@yhong91/vibetime 0.1.53 → 0.1.54
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 +181 -50
- package/package.json +1 -1
package/bin/vibetime.mjs
CHANGED
|
@@ -884,8 +884,8 @@ var init_esm = __esm({
|
|
|
884
884
|
|
|
885
885
|
// src/cli.ts
|
|
886
886
|
import { spawn as spawn2, spawnSync } from "node:child_process";
|
|
887
|
-
import { mkdir as mkdir5, open, rm, stat as
|
|
888
|
-
import
|
|
887
|
+
import { mkdir as mkdir5, open, rm, stat as stat14, writeFile as writeFile4 } from "node:fs/promises";
|
|
888
|
+
import os12 from "node:os";
|
|
889
889
|
import path25 from "node:path";
|
|
890
890
|
import { fileURLToPath } from "node:url";
|
|
891
891
|
|
|
@@ -2047,7 +2047,7 @@ function claudeStyleFileMetrics(tool, input) {
|
|
|
2047
2047
|
}
|
|
2048
2048
|
|
|
2049
2049
|
// src/lib/constants.ts
|
|
2050
|
-
var PACKAGE_VERSION = true ? "0.1.
|
|
2050
|
+
var PACKAGE_VERSION = true ? "0.1.54" : "0.1.1";
|
|
2051
2051
|
var GENERATED_MARKER = "Generated by vibetime.";
|
|
2052
2052
|
var DEFAULT_API_URL = "http://121.196.224.82:3001";
|
|
2053
2053
|
var DEFAULT_BACKFILL_BATCH_SIZE = 50;
|
|
@@ -3331,6 +3331,9 @@ function isTurnIdle(lastEventAt) {
|
|
|
3331
3331
|
}
|
|
3332
3332
|
return Date.now() - lastMs > TURN_IDLE_MS;
|
|
3333
3333
|
}
|
|
3334
|
+
function withoutSubagentTurnEvents(events) {
|
|
3335
|
+
return events.filter((event) => event.type !== "turn.started" && event.type !== "turn.completed");
|
|
3336
|
+
}
|
|
3334
3337
|
function sessionIdFromFilePath(filePath, prefix) {
|
|
3335
3338
|
const match = path6.basename(filePath).match(/([0-9a-f]{8}-[0-9a-f-]{27,})/);
|
|
3336
3339
|
return match?.[1] || `${prefix}_${createStableHash(filePath).slice(0, 24)}`;
|
|
@@ -4253,7 +4256,8 @@ async function parseClaudeCoworkSessionFile(filePath, options) {
|
|
|
4253
4256
|
const parentSourcePathHash = subagentInfo ? `sha256:${createStableHash(subagentInfo.mainTranscriptPath)}` : void 0;
|
|
4254
4257
|
const parentSessionId = subagentInfo ? prefixCoworkId(subagentInfo.cliSessionId) : void 0;
|
|
4255
4258
|
const events = await parser(filePath, options);
|
|
4256
|
-
|
|
4259
|
+
const foldable = subagentInfo ? withoutSubagentTurnEvents(events).map((event) => ({ ...event, turnId: void 0 })) : events;
|
|
4260
|
+
return foldable.map((event) => {
|
|
4257
4261
|
const sessionId = parentSessionId || prefixCoworkId(event.sessionId);
|
|
4258
4262
|
const turnId = prefixCoworkId(event.turnId);
|
|
4259
4263
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
@@ -5007,8 +5011,8 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
5007
5011
|
}
|
|
5008
5012
|
const filePath = path9.join(traceDir, entry);
|
|
5009
5013
|
try {
|
|
5010
|
-
const
|
|
5011
|
-
files.push({ path: filePath, modifiedAt:
|
|
5014
|
+
const stat15 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
|
|
5015
|
+
files.push({ path: filePath, modifiedAt: stat15.mtime.toISOString(), groupId: pidDir.name });
|
|
5012
5016
|
} catch {
|
|
5013
5017
|
}
|
|
5014
5018
|
}
|
|
@@ -7635,6 +7639,8 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
7635
7639
|
for (const session of sessions) {
|
|
7636
7640
|
const rawSessionId = session.id;
|
|
7637
7641
|
const sessionId = rootIdByRawId.get(rawSessionId) || rawSessionId;
|
|
7642
|
+
const isSubagent = sessionId !== rawSessionId;
|
|
7643
|
+
const sessionEventStart = events.length;
|
|
7638
7644
|
const cwd = session.directory || session.path || void 0;
|
|
7639
7645
|
const project = cwd ? path15.basename(cwd) : void 0;
|
|
7640
7646
|
const sessionTs = msToIso(session.time_created);
|
|
@@ -7951,6 +7957,9 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
7951
7957
|
operation: "session end"
|
|
7952
7958
|
}));
|
|
7953
7959
|
}
|
|
7960
|
+
if (isSubagent) {
|
|
7961
|
+
events.push(...withoutSubagentTurnEvents(events.splice(sessionEventStart)).map((event) => ({ ...event, turnId: void 0 })));
|
|
7962
|
+
}
|
|
7954
7963
|
}
|
|
7955
7964
|
} finally {
|
|
7956
7965
|
db.close();
|
|
@@ -8029,19 +8038,19 @@ function opencodeDataCandidates(home, env) {
|
|
|
8029
8038
|
return [primary, path15.join(home, ".opencode", "opencode.db")];
|
|
8030
8039
|
}
|
|
8031
8040
|
async function opencodeBackfillFiles(sourceRoot, home = os6.homedir(), env) {
|
|
8032
|
-
const { stat:
|
|
8041
|
+
const { stat: stat15 } = await import("node:fs/promises");
|
|
8033
8042
|
if (sourceRoot) {
|
|
8034
8043
|
if (!sourceRoot.endsWith(".db")) {
|
|
8035
8044
|
return [];
|
|
8036
8045
|
}
|
|
8037
|
-
const info = await
|
|
8046
|
+
const info = await stat15(sourceRoot).catch(() => null);
|
|
8038
8047
|
if (!info) {
|
|
8039
8048
|
return [];
|
|
8040
8049
|
}
|
|
8041
8050
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
8042
8051
|
}
|
|
8043
8052
|
for (const candidatePath of opencodeDataCandidates(home, env)) {
|
|
8044
|
-
const info = await
|
|
8053
|
+
const info = await stat15(candidatePath).catch(() => null);
|
|
8045
8054
|
if (info) {
|
|
8046
8055
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
8047
8056
|
}
|
|
@@ -8141,8 +8150,10 @@ function createOpenCodeAdapter() {
|
|
|
8141
8150
|
}
|
|
8142
8151
|
|
|
8143
8152
|
// src/adapters/pi.ts
|
|
8144
|
-
import { readFile as readFile10 } from "node:fs/promises";
|
|
8153
|
+
import { readdir as readdir7, readFile as readFile10, stat as stat8 } from "node:fs/promises";
|
|
8154
|
+
import os7 from "node:os";
|
|
8145
8155
|
import path16 from "node:path";
|
|
8156
|
+
init_fs();
|
|
8146
8157
|
function parsePiSubagentLink(filePath, headerParentSession) {
|
|
8147
8158
|
if (headerParentSession) {
|
|
8148
8159
|
const parentFile = path16.isAbsolute(headerParentSession) ? headerParentSession : void 0;
|
|
@@ -8187,11 +8198,15 @@ async function resolveParentContext(link, options) {
|
|
|
8187
8198
|
return void 0;
|
|
8188
8199
|
}
|
|
8189
8200
|
function foldEventsIntoParent(events, link) {
|
|
8190
|
-
const
|
|
8191
|
-
|
|
8201
|
+
const folded = withoutSubagentTurnEvents(events);
|
|
8202
|
+
const childSessionId = folded.find((event) => event.sessionId)?.sessionId;
|
|
8203
|
+
return folded.map((event) => {
|
|
8192
8204
|
const rewritten = {
|
|
8193
8205
|
...event,
|
|
8194
|
-
sessionId: link.parentSessionId
|
|
8206
|
+
sessionId: link.parentSessionId,
|
|
8207
|
+
// Subagent turns don't exist in the host session; drop the reference so
|
|
8208
|
+
// buildSessionRollups doesn't synthesize phantom turn rollups.
|
|
8209
|
+
turnId: void 0
|
|
8195
8210
|
};
|
|
8196
8211
|
if (childSessionId && childSessionId !== link.parentSessionId) {
|
|
8197
8212
|
rewritten.refs = {
|
|
@@ -8447,6 +8462,100 @@ async function parsePiSessionFile(filePath, options) {
|
|
|
8447
8462
|
}
|
|
8448
8463
|
return state.events.filter((event) => matchesBackfillFilters(event, options));
|
|
8449
8464
|
}
|
|
8465
|
+
async function parsePiFile(filePath, options) {
|
|
8466
|
+
if (filePath.endsWith(".json")) {
|
|
8467
|
+
return parsePiWorkflowRunFile(filePath, options);
|
|
8468
|
+
}
|
|
8469
|
+
return parsePiSessionFile(filePath, options);
|
|
8470
|
+
}
|
|
8471
|
+
async function parsePiWorkflowRunFile(filePath, options) {
|
|
8472
|
+
let raw;
|
|
8473
|
+
try {
|
|
8474
|
+
raw = JSON.parse(await readFile10(filePath, "utf8"));
|
|
8475
|
+
} catch {
|
|
8476
|
+
return [];
|
|
8477
|
+
}
|
|
8478
|
+
if (!isPlainObject(raw)) {
|
|
8479
|
+
return [];
|
|
8480
|
+
}
|
|
8481
|
+
const sessionId = stringField(raw, "sessionId");
|
|
8482
|
+
const agents = Array.isArray(raw.agents) ? raw.agents.filter((agent) => isPlainObject(agent)) : [];
|
|
8483
|
+
if (!sessionId || agents.length === 0) {
|
|
8484
|
+
return [];
|
|
8485
|
+
}
|
|
8486
|
+
const runUpdatedAt = timestampFrom(raw.updatedAt);
|
|
8487
|
+
const parentSessionFile = await findPiSessionFileById(sessionId, options);
|
|
8488
|
+
const host = await resolveParentContext(
|
|
8489
|
+
{ parentSessionId: sessionId, parentSessionFile, explicit: true },
|
|
8490
|
+
options
|
|
8491
|
+
);
|
|
8492
|
+
const cwd = host?.cwd;
|
|
8493
|
+
const project = host?.project;
|
|
8494
|
+
const state = new SessionParserState(filePath, options, (event) => basePiEvent({ ...event, cwd, project, model: event.model }));
|
|
8495
|
+
const push = (event, ln) => {
|
|
8496
|
+
state.push(
|
|
8497
|
+
{ ...event, workspaceId: event.workspaceId || createWorkspaceId({ projectName: project, repoRoot: cwd }) },
|
|
8498
|
+
ln,
|
|
8499
|
+
"workflow-run",
|
|
8500
|
+
event.type
|
|
8501
|
+
);
|
|
8502
|
+
};
|
|
8503
|
+
for (const [index, agent] of agents.entries()) {
|
|
8504
|
+
const lineNumber = index + 1;
|
|
8505
|
+
const usage = objectField(agent, "tokenUsage");
|
|
8506
|
+
const input = numberField(usage, "input") || 0;
|
|
8507
|
+
const output = numberField(usage, "output") || 0;
|
|
8508
|
+
const cacheRead = numberField(usage, "cacheRead") || 0;
|
|
8509
|
+
const cacheWrite = numberField(usage, "cacheWrite") || 0;
|
|
8510
|
+
const breakdown = input + output + cacheRead + cacheWrite;
|
|
8511
|
+
const total = numberField(usage, "total") || breakdown || numberField(agent, "tokens") || 0;
|
|
8512
|
+
if (total <= 0) {
|
|
8513
|
+
continue;
|
|
8514
|
+
}
|
|
8515
|
+
const model = stringField(agent, "model")?.replace(/:(off|minimal|low|medium|high|xhigh|max)$/, "");
|
|
8516
|
+
const ts = timestampFrom(agent.endedAt) || timestampFrom(agent.startedAt) || runUpdatedAt || (/* @__PURE__ */ new Date()).toISOString();
|
|
8517
|
+
push(basePiEvent({
|
|
8518
|
+
ts,
|
|
8519
|
+
type: "model.usage",
|
|
8520
|
+
sessionId,
|
|
8521
|
+
cwd,
|
|
8522
|
+
project,
|
|
8523
|
+
model,
|
|
8524
|
+
confidence: breakdown > 0 ? "exact" : "derived",
|
|
8525
|
+
metrics: {
|
|
8526
|
+
tokensInput: breakdown > 0 ? input + cacheRead + cacheWrite || void 0 : void 0,
|
|
8527
|
+
tokensOutput: breakdown > 0 ? output || void 0 : void 0,
|
|
8528
|
+
tokensCachedInput: breakdown > 0 ? cacheRead + cacheWrite || void 0 : void 0,
|
|
8529
|
+
tokensCacheReadInput: breakdown > 0 ? cacheRead || void 0 : void 0,
|
|
8530
|
+
tokensCacheCreationInput: breakdown > 0 ? cacheWrite || void 0 : void 0,
|
|
8531
|
+
tokensTotal: total,
|
|
8532
|
+
costUsd: numberField(usage, "cost") || void 0
|
|
8533
|
+
},
|
|
8534
|
+
refs: stringRefs({
|
|
8535
|
+
sourceId: stringField(agent, "callId") || stringField(agent, "label")
|
|
8536
|
+
})
|
|
8537
|
+
}), lineNumber);
|
|
8538
|
+
}
|
|
8539
|
+
return state.events.filter((event) => matchesBackfillFilters(event, options));
|
|
8540
|
+
}
|
|
8541
|
+
async function findPiSessionFileById(sessionId, options) {
|
|
8542
|
+
const sessionsDir = piSessionDir(path16.resolve(stringOption(options.home) || os7.homedir()));
|
|
8543
|
+
try {
|
|
8544
|
+
const projectDirs = await readdir7(sessionsDir, { withFileTypes: true });
|
|
8545
|
+
for (const dir of projectDirs) {
|
|
8546
|
+
if (!dir.isDirectory()) {
|
|
8547
|
+
continue;
|
|
8548
|
+
}
|
|
8549
|
+
const names = await readdir7(path16.join(sessionsDir, dir.name));
|
|
8550
|
+
const hit = names.find((name) => name.endsWith(`_${sessionId}.jsonl`));
|
|
8551
|
+
if (hit) {
|
|
8552
|
+
return path16.join(sessionsDir, dir.name, hit);
|
|
8553
|
+
}
|
|
8554
|
+
}
|
|
8555
|
+
} catch {
|
|
8556
|
+
}
|
|
8557
|
+
return void 0;
|
|
8558
|
+
}
|
|
8450
8559
|
function basePiEvent(event) {
|
|
8451
8560
|
return {
|
|
8452
8561
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
@@ -8693,6 +8802,20 @@ function piSessionDir(home, env) {
|
|
|
8693
8802
|
}
|
|
8694
8803
|
return path16.join(piAgentDir(home, env), "sessions");
|
|
8695
8804
|
}
|
|
8805
|
+
function piWorkflowProjectsDir(home) {
|
|
8806
|
+
return path16.join(home, ".pi", "workflows", "projects");
|
|
8807
|
+
}
|
|
8808
|
+
async function piBackfillFiles(sourceRoot, home = os7.homedir(), env) {
|
|
8809
|
+
const lists = sourceRoot ? [await listFilesByExtensions(sourceRoot, [".jsonl", ".json"])] : await Promise.all([
|
|
8810
|
+
listFilesByExtensions(piSessionDir(home, env), [".jsonl"]),
|
|
8811
|
+
listFilesByExtensions(piWorkflowProjectsDir(home), [".json"])
|
|
8812
|
+
]);
|
|
8813
|
+
const files = lists.flat().sort();
|
|
8814
|
+
return Promise.all(files.map(async (filePath) => {
|
|
8815
|
+
const info = await stat8(filePath);
|
|
8816
|
+
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
8817
|
+
}));
|
|
8818
|
+
}
|
|
8696
8819
|
function createPiAdapter() {
|
|
8697
8820
|
return {
|
|
8698
8821
|
id: "pi",
|
|
@@ -8721,20 +8844,20 @@ function createPiAdapter() {
|
|
|
8721
8844
|
}];
|
|
8722
8845
|
},
|
|
8723
8846
|
sourcePaths(home, env) {
|
|
8724
|
-
return [piSessionDir(home, env)];
|
|
8847
|
+
return [piSessionDir(home, env), piWorkflowProjectsDir(home)];
|
|
8725
8848
|
},
|
|
8726
|
-
parseSessionFile:
|
|
8849
|
+
parseSessionFile: parsePiFile
|
|
8727
8850
|
};
|
|
8728
8851
|
}
|
|
8729
8852
|
|
|
8730
8853
|
// src/adapters/qoder-cn.ts
|
|
8731
|
-
import { readdir as
|
|
8732
|
-
import
|
|
8854
|
+
import { readdir as readdir8, readFile as readFile11, stat as stat9 } from "node:fs/promises";
|
|
8855
|
+
import os9 from "node:os";
|
|
8733
8856
|
import path18 from "node:path";
|
|
8734
8857
|
|
|
8735
8858
|
// src/adapters/qoder-local-db.ts
|
|
8736
8859
|
import { access } from "node:fs/promises";
|
|
8737
|
-
import
|
|
8860
|
+
import os8 from "node:os";
|
|
8738
8861
|
import path17 from "node:path";
|
|
8739
8862
|
function takeQoderDbModelCall(calls, requestId, blockStart) {
|
|
8740
8863
|
if (requestId) {
|
|
@@ -8752,7 +8875,7 @@ function takeQoderDbModelCall(calls, requestId, blockStart) {
|
|
|
8752
8875
|
}
|
|
8753
8876
|
return calls.ordered.shift();
|
|
8754
8877
|
}
|
|
8755
|
-
function appDataRoot(appDirName, home =
|
|
8878
|
+
function appDataRoot(appDirName, home = os8.homedir()) {
|
|
8756
8879
|
if (process.platform === "darwin") {
|
|
8757
8880
|
return path17.join(home, "Library", "Application Support", appDirName);
|
|
8758
8881
|
}
|
|
@@ -9005,7 +9128,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
|
|
|
9005
9128
|
const segmentsPath = path18.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
9006
9129
|
const modelCalls = [];
|
|
9007
9130
|
try {
|
|
9008
|
-
const files = await
|
|
9131
|
+
const files = await readdir8(segmentsPath);
|
|
9009
9132
|
for (const file of files) {
|
|
9010
9133
|
if (!file.endsWith(".jsonl")) {
|
|
9011
9134
|
continue;
|
|
@@ -9055,7 +9178,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
9055
9178
|
let cwd;
|
|
9056
9179
|
let project = projectContext.project;
|
|
9057
9180
|
let model;
|
|
9058
|
-
const home = path18.resolve(stringOption(options.home) ||
|
|
9181
|
+
const home = path18.resolve(stringOption(options.home) || os9.homedir());
|
|
9059
9182
|
const modelMap = await loadQoderCnModelNames(configDir2, home);
|
|
9060
9183
|
const isSubagentSession = filePath.includes("subagents");
|
|
9061
9184
|
const segmentModelCalls = await loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap);
|
|
@@ -9623,7 +9746,7 @@ async function gitRootFromCwds2(cwds) {
|
|
|
9623
9746
|
while (!seen.has(current)) {
|
|
9624
9747
|
seen.add(current);
|
|
9625
9748
|
try {
|
|
9626
|
-
await
|
|
9749
|
+
await stat9(path18.join(current, ".git"));
|
|
9627
9750
|
return current;
|
|
9628
9751
|
} catch {
|
|
9629
9752
|
}
|
|
@@ -9657,7 +9780,7 @@ function encodeQoderCnProjectPath(value) {
|
|
|
9657
9780
|
}
|
|
9658
9781
|
async function qoderCnProjectFromFilePath(filePath, options) {
|
|
9659
9782
|
const projectDir = path18.basename(path18.dirname(filePath));
|
|
9660
|
-
const home = options ? path18.resolve(stringOption(options.home) ||
|
|
9783
|
+
const home = options ? path18.resolve(stringOption(options.home) || os9.homedir()) : os9.homedir();
|
|
9661
9784
|
const resolved = await resolveQoderCnProjectPath(projectDir, home);
|
|
9662
9785
|
if (resolved) {
|
|
9663
9786
|
return path18.basename(resolved);
|
|
@@ -9680,7 +9803,7 @@ async function resolveQoderCnProjectPath(projectDir, home) {
|
|
|
9680
9803
|
while (projectDir.startsWith(`${currentEncoded}-`)) {
|
|
9681
9804
|
let matchedChild;
|
|
9682
9805
|
try {
|
|
9683
|
-
const entries = await
|
|
9806
|
+
const entries = await readdir8(current, { withFileTypes: true });
|
|
9684
9807
|
for (const entry of entries) {
|
|
9685
9808
|
if (!entry.isDirectory()) {
|
|
9686
9809
|
continue;
|
|
@@ -9773,8 +9896,8 @@ function createQoderCnAdapter() {
|
|
|
9773
9896
|
|
|
9774
9897
|
// src/adapters/qoder.ts
|
|
9775
9898
|
import { existsSync } from "node:fs";
|
|
9776
|
-
import { readdir as
|
|
9777
|
-
import
|
|
9899
|
+
import { readdir as readdir9, readFile as readFile12, stat as stat10 } from "node:fs/promises";
|
|
9900
|
+
import os10 from "node:os";
|
|
9778
9901
|
import path19 from "node:path";
|
|
9779
9902
|
function parseQoderPaths(filePath) {
|
|
9780
9903
|
const parts = filePath.split(path19.sep);
|
|
@@ -9883,7 +10006,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
|
|
|
9883
10006
|
const segmentsPath = path19.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
9884
10007
|
const modelCalls = [];
|
|
9885
10008
|
try {
|
|
9886
|
-
const files = await
|
|
10009
|
+
const files = await readdir9(segmentsPath);
|
|
9887
10010
|
for (const file of files) {
|
|
9888
10011
|
if (!file.endsWith(".jsonl")) {
|
|
9889
10012
|
continue;
|
|
@@ -9933,7 +10056,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
9933
10056
|
let cwd;
|
|
9934
10057
|
let project = projectContext.project;
|
|
9935
10058
|
let model;
|
|
9936
|
-
const home = path19.resolve(stringOption(options.home) ||
|
|
10059
|
+
const home = path19.resolve(stringOption(options.home) || os10.homedir());
|
|
9937
10060
|
const modelMap = await loadQoderModelNames(configDir2, home);
|
|
9938
10061
|
const qwenworkRoot = isQwenworkConfigRoot(configDir2);
|
|
9939
10062
|
const isSubagentSession = filePath.includes("subagents");
|
|
@@ -10467,7 +10590,7 @@ async function gitRootFromCwds3(cwds) {
|
|
|
10467
10590
|
while (!seen.has(current)) {
|
|
10468
10591
|
seen.add(current);
|
|
10469
10592
|
try {
|
|
10470
|
-
await
|
|
10593
|
+
await stat10(path19.join(current, ".git"));
|
|
10471
10594
|
return current;
|
|
10472
10595
|
} catch {
|
|
10473
10596
|
}
|
|
@@ -10519,7 +10642,7 @@ function qoderEncodedProjectSuffix(projectDir, home) {
|
|
|
10519
10642
|
}
|
|
10520
10643
|
async function qoderProjectFromFilePath(filePath, options) {
|
|
10521
10644
|
const projectDir = path19.basename(path19.dirname(filePath));
|
|
10522
|
-
const home = options ? path19.resolve(stringOption(options.home) ||
|
|
10645
|
+
const home = options ? path19.resolve(stringOption(options.home) || os10.homedir()) : os10.homedir();
|
|
10523
10646
|
const resolved = await resolveQoderProjectPath(projectDir, home);
|
|
10524
10647
|
if (resolved) {
|
|
10525
10648
|
return path19.basename(resolved);
|
|
@@ -10543,7 +10666,7 @@ async function resolveQoderProjectPath(projectDir, home) {
|
|
|
10543
10666
|
while (currentEncodedVariants.some((prefix) => projectDir.startsWith(`${prefix}-`))) {
|
|
10544
10667
|
let matchedChild;
|
|
10545
10668
|
try {
|
|
10546
|
-
const entries = await
|
|
10669
|
+
const entries = await readdir9(current, { withFileTypes: true });
|
|
10547
10670
|
for (const entry of entries) {
|
|
10548
10671
|
if (!entry.isDirectory()) {
|
|
10549
10672
|
continue;
|
|
@@ -10675,7 +10798,7 @@ function normalizeId(id) {
|
|
|
10675
10798
|
}
|
|
10676
10799
|
|
|
10677
10800
|
// src/adapters/workbuddy.ts
|
|
10678
|
-
import { readdir as
|
|
10801
|
+
import { readdir as readdir10, readFile as readFile13, stat as stat11 } from "node:fs/promises";
|
|
10679
10802
|
import path20 from "node:path";
|
|
10680
10803
|
function workbuddyProjectsDir(home, env) {
|
|
10681
10804
|
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
@@ -11118,17 +11241,17 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
11118
11241
|
const base = sourceRoot || workbuddyProjectsDir(home, env);
|
|
11119
11242
|
const files = [];
|
|
11120
11243
|
try {
|
|
11121
|
-
const projects = await
|
|
11244
|
+
const projects = await readdir10(base, { withFileTypes: true });
|
|
11122
11245
|
for (const project of projects) {
|
|
11123
11246
|
if (!project.isDirectory()) {
|
|
11124
11247
|
continue;
|
|
11125
11248
|
}
|
|
11126
11249
|
const projectDir = path20.join(base, project.name);
|
|
11127
|
-
const entries = await
|
|
11250
|
+
const entries = await readdir10(projectDir, { withFileTypes: true });
|
|
11128
11251
|
for (const entry of entries) {
|
|
11129
11252
|
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
11130
11253
|
const filePath = path20.join(projectDir, entry.name);
|
|
11131
|
-
const info = await
|
|
11254
|
+
const info = await stat11(filePath);
|
|
11132
11255
|
files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
|
|
11133
11256
|
}
|
|
11134
11257
|
}
|
|
@@ -11189,7 +11312,7 @@ function createWorkbuddyAdapter() {
|
|
|
11189
11312
|
|
|
11190
11313
|
// src/adapters/zcode.ts
|
|
11191
11314
|
import { execFile } from "node:child_process";
|
|
11192
|
-
import { readFile as readFile14, stat as
|
|
11315
|
+
import { readFile as readFile14, stat as stat12 } from "node:fs/promises";
|
|
11193
11316
|
import path21 from "node:path";
|
|
11194
11317
|
import { promisify as promisify2 } from "node:util";
|
|
11195
11318
|
init_fs();
|
|
@@ -11208,7 +11331,7 @@ var providerNameCache = null;
|
|
|
11208
11331
|
async function loadProviderNames(configPath2) {
|
|
11209
11332
|
let fileMtime = 0;
|
|
11210
11333
|
try {
|
|
11211
|
-
const info = await
|
|
11334
|
+
const info = await stat12(configPath2);
|
|
11212
11335
|
fileMtime = info.mtimeMs;
|
|
11213
11336
|
} catch {
|
|
11214
11337
|
return /* @__PURE__ */ new Map();
|
|
@@ -11408,6 +11531,7 @@ function sessionContext(row, sessions) {
|
|
|
11408
11531
|
return {
|
|
11409
11532
|
rawSessionId: sessionId,
|
|
11410
11533
|
sessionId: `zcode:${rootSessionId}`,
|
|
11534
|
+
isSubagent: rootSessionId !== sessionId,
|
|
11411
11535
|
cwd,
|
|
11412
11536
|
project,
|
|
11413
11537
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: cwd }),
|
|
@@ -11424,7 +11548,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
11424
11548
|
for (let i = 0; i < 12; i++) {
|
|
11425
11549
|
const probe = path21.join(candidate, ".zcode", "v2", "config.json");
|
|
11426
11550
|
try {
|
|
11427
|
-
await
|
|
11551
|
+
await stat12(probe);
|
|
11428
11552
|
configPath2 = probe;
|
|
11429
11553
|
break;
|
|
11430
11554
|
} catch {
|
|
@@ -11499,6 +11623,9 @@ async function parseZCodeDb(filePath, options) {
|
|
|
11499
11623
|
return;
|
|
11500
11624
|
}
|
|
11501
11625
|
const ctx = sessionContext(row, sessions);
|
|
11626
|
+
if (ctx.isSubagent) {
|
|
11627
|
+
return;
|
|
11628
|
+
}
|
|
11502
11629
|
const turnId = `zcode:${rawTurnId}`;
|
|
11503
11630
|
const started = makeEvent2({
|
|
11504
11631
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
@@ -11559,7 +11686,8 @@ async function parseZCodeDb(filePath, options) {
|
|
|
11559
11686
|
project: ctx.project,
|
|
11560
11687
|
cwd: ctx.cwd,
|
|
11561
11688
|
sessionId: ctx.sessionId,
|
|
11562
|
-
|
|
11689
|
+
// Subagent turns are dropped; keep their events out of turn rollups.
|
|
11690
|
+
turnId: !ctx.isSubagent && stringField(row, "turn_id") ? `zcode:${stringField(row, "turn_id")}` : void 0,
|
|
11563
11691
|
agent: stringField(row, "agent") || "zcode",
|
|
11564
11692
|
provider: nameMap.get(stringField(row, "provider_id") || "") || stringField(row, "provider_id"),
|
|
11565
11693
|
model: modelId,
|
|
@@ -11585,7 +11713,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
11585
11713
|
return;
|
|
11586
11714
|
}
|
|
11587
11715
|
const ctx = sessionContext(row, sessions);
|
|
11588
|
-
const turnId = stringField(row, "turn_id") ? `zcode:${stringField(row, "turn_id")}` : void 0;
|
|
11716
|
+
const turnId = !ctx.isSubagent && stringField(row, "turn_id") ? `zcode:${stringField(row, "turn_id")}` : void 0;
|
|
11589
11717
|
const spanId = `${ctx.sessionId}:tool:${toolCallId}`;
|
|
11590
11718
|
const started = makeEvent2({
|
|
11591
11719
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
@@ -11646,7 +11774,7 @@ async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
|
11646
11774
|
const candidate = sourceRoot || zcodeDbPath(home, env);
|
|
11647
11775
|
const filePath = candidate.endsWith(".sqlite") ? candidate : path21.join(candidate, "db", "db.sqlite");
|
|
11648
11776
|
try {
|
|
11649
|
-
const info = await
|
|
11777
|
+
const info = await stat12(filePath);
|
|
11650
11778
|
return [{ path: filePath, modifiedAt: info.mtime.toISOString() }];
|
|
11651
11779
|
} catch {
|
|
11652
11780
|
return [];
|
|
@@ -11678,7 +11806,7 @@ function createZCodeAdapter() {
|
|
|
11678
11806
|
}
|
|
11679
11807
|
|
|
11680
11808
|
// src/adapters/zed.ts
|
|
11681
|
-
import
|
|
11809
|
+
import os11 from "node:os";
|
|
11682
11810
|
import path22 from "node:path";
|
|
11683
11811
|
function zedThreadsCandidates(home, env) {
|
|
11684
11812
|
const candidates = [];
|
|
@@ -12030,20 +12158,20 @@ async function parseZedSessionFile(dbPath, options) {
|
|
|
12030
12158
|
}
|
|
12031
12159
|
return events.filter((event) => matchesBackfillFilters(event, options));
|
|
12032
12160
|
}
|
|
12033
|
-
async function zedBackfillFiles(sourceRoot, home =
|
|
12034
|
-
const { stat:
|
|
12161
|
+
async function zedBackfillFiles(sourceRoot, home = os11.homedir(), env) {
|
|
12162
|
+
const { stat: stat15 } = await import("node:fs/promises");
|
|
12035
12163
|
if (sourceRoot) {
|
|
12036
12164
|
if (!sourceRoot.endsWith(".db")) {
|
|
12037
12165
|
return [];
|
|
12038
12166
|
}
|
|
12039
|
-
const info = await
|
|
12167
|
+
const info = await stat15(sourceRoot).catch(() => null);
|
|
12040
12168
|
if (!info) {
|
|
12041
12169
|
return [];
|
|
12042
12170
|
}
|
|
12043
12171
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
12044
12172
|
}
|
|
12045
12173
|
for (const candidatePath of zedThreadsCandidates(home, env)) {
|
|
12046
|
-
const info = await
|
|
12174
|
+
const info = await stat15(candidatePath).catch(() => null);
|
|
12047
12175
|
if (info) {
|
|
12048
12176
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
12049
12177
|
}
|
|
@@ -12823,7 +12951,7 @@ function defaultMachineName() {
|
|
|
12823
12951
|
init_fs();
|
|
12824
12952
|
|
|
12825
12953
|
// src/lib/logger.ts
|
|
12826
|
-
import { appendFile, mkdir as mkdir4, rename, stat as
|
|
12954
|
+
import { appendFile, mkdir as mkdir4, rename, stat as stat13 } from "node:fs/promises";
|
|
12827
12955
|
import { homedir as homedir2 } from "node:os";
|
|
12828
12956
|
import path24 from "node:path";
|
|
12829
12957
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
@@ -12841,7 +12969,7 @@ function serializeError(error) {
|
|
|
12841
12969
|
}
|
|
12842
12970
|
async function rotateIfNeeded(file) {
|
|
12843
12971
|
try {
|
|
12844
|
-
const info = await
|
|
12972
|
+
const info = await stat13(file);
|
|
12845
12973
|
if (info.size > MAX_BYTES) {
|
|
12846
12974
|
await rename(file, `${file}.1`).catch(() => {
|
|
12847
12975
|
});
|
|
@@ -13660,11 +13788,14 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
13660
13788
|
if (source.id === "zed") {
|
|
13661
13789
|
return zedBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
13662
13790
|
}
|
|
13791
|
+
if (source.id === "pi") {
|
|
13792
|
+
return piBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
13793
|
+
}
|
|
13663
13794
|
const roots = stringOption(options["source-root"]) ? [requiredOption(options, "source-root")] : source.paths;
|
|
13664
13795
|
const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
|
|
13665
13796
|
const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
|
|
13666
13797
|
return Promise.all(files.map(async (filePath) => {
|
|
13667
|
-
const info = await
|
|
13798
|
+
const info = await stat14(filePath);
|
|
13668
13799
|
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
13669
13800
|
}));
|
|
13670
13801
|
}
|
|
@@ -14252,7 +14383,7 @@ function syncLocalRunnerEntryArgs(cliPath) {
|
|
|
14252
14383
|
return [path25.resolve(path25.dirname(cliPath), "../bin/vibetime.mjs")];
|
|
14253
14384
|
}
|
|
14254
14385
|
function resolveHome3(options, ctx) {
|
|
14255
|
-
return path25.resolve(stringOption(options.home) || ctx.env.HOME ||
|
|
14386
|
+
return path25.resolve(stringOption(options.home) || ctx.env.HOME || os12.homedir());
|
|
14256
14387
|
}
|
|
14257
14388
|
function requestedTargets(options) {
|
|
14258
14389
|
const value = options.target || options.targets;
|
package/package.json
CHANGED