@yhong91/vibetime 0.1.30 → 0.1.32
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 +322 -131
- package/package.json +1 -1
package/bin/vibetime.mjs
CHANGED
|
@@ -885,8 +885,8 @@ var init_esm = __esm({
|
|
|
885
885
|
// src/cli.ts
|
|
886
886
|
import { spawn as spawn2, spawnSync } from "node:child_process";
|
|
887
887
|
import { mkdir as mkdir5, open, rm, stat as stat13, writeFile as writeFile4 } from "node:fs/promises";
|
|
888
|
-
import
|
|
889
|
-
import
|
|
888
|
+
import os11 from "node:os";
|
|
889
|
+
import path24 from "node:path";
|
|
890
890
|
import { fileURLToPath } from "node:url";
|
|
891
891
|
|
|
892
892
|
// ../shared/src/index.ts
|
|
@@ -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.32" : "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;
|
|
@@ -4913,8 +4913,10 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
4913
4913
|
let lastTurnIdForComplete;
|
|
4914
4914
|
let turnIdAtLastUserMessage;
|
|
4915
4915
|
let sessionMetaLocked = false;
|
|
4916
|
+
let forkedSession = false;
|
|
4916
4917
|
let lastTotalTokenUsage;
|
|
4917
4918
|
let lastPerCallUsageKey;
|
|
4919
|
+
let compactionPending = false;
|
|
4918
4920
|
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
4919
4921
|
for (const [index, line] of lines.entries()) {
|
|
4920
4922
|
const lineNumber = index + 1;
|
|
@@ -4932,6 +4934,7 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
4932
4934
|
}
|
|
4933
4935
|
sessionMetaLocked = true;
|
|
4934
4936
|
const forkedFromId = stringField(payload, "forked_from_id");
|
|
4937
|
+
forkedSession = Boolean(forkedFromId);
|
|
4935
4938
|
const inherited = forkedFromId ? await readPersistedSessionContextFromOptions(options, forkedFromId) : void 0;
|
|
4936
4939
|
sessionId = stringField(payload, "id") || sessionId;
|
|
4937
4940
|
cwd = inherited?.cwd || stringField(payload, "cwd") || cwd;
|
|
@@ -4953,6 +4956,10 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
4953
4956
|
sessionStartEmitted = true;
|
|
4954
4957
|
continue;
|
|
4955
4958
|
}
|
|
4959
|
+
if (topType === "compacted") {
|
|
4960
|
+
compactionPending = true;
|
|
4961
|
+
continue;
|
|
4962
|
+
}
|
|
4956
4963
|
if (topType === "turn_context") {
|
|
4957
4964
|
currentTurnId = stringField(payload, "turn_id") || currentTurnId;
|
|
4958
4965
|
cwd = stringField(payload, "cwd") || cwd;
|
|
@@ -5080,12 +5087,32 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
5080
5087
|
project,
|
|
5081
5088
|
model: rewriteCodexModelForTier(model, serviceTier),
|
|
5082
5089
|
confidence: "partial",
|
|
5083
|
-
metrics: usage
|
|
5090
|
+
metrics: excludeForkInheritedCache(usage, forkedSession)
|
|
5084
5091
|
}), { filePath, sourcePathHash, lineNumber, topType, payloadType, options }));
|
|
5085
5092
|
lastPerCallUsageKey = usageKey;
|
|
5086
5093
|
}
|
|
5087
5094
|
break;
|
|
5088
5095
|
}
|
|
5096
|
+
if (compactionPending && lastTotalTokenUsage && total < lastTotalTokenUsage.total) {
|
|
5097
|
+
const lastUsage = lastTokenUsageFromPayload(payload);
|
|
5098
|
+
if (lastUsage) {
|
|
5099
|
+
events.push(withBackfillRefs(baseCodexEvent({
|
|
5100
|
+
ts,
|
|
5101
|
+
type: "model.usage",
|
|
5102
|
+
sessionId,
|
|
5103
|
+
turnId: currentTurnId,
|
|
5104
|
+
cwd,
|
|
5105
|
+
project,
|
|
5106
|
+
model: rewriteCodexModelForTier(model, serviceTier),
|
|
5107
|
+
confidence: "partial",
|
|
5108
|
+
metrics: excludeForkInheritedCache({ ...lastUsage, reasoningEffort }, forkedSession)
|
|
5109
|
+
}), { filePath, sourcePathHash, lineNumber, topType, payloadType, options }));
|
|
5110
|
+
}
|
|
5111
|
+
lastTotalTokenUsage = { input, cached, output, reasoning, total };
|
|
5112
|
+
compactionPending = false;
|
|
5113
|
+
break;
|
|
5114
|
+
}
|
|
5115
|
+
compactionPending = false;
|
|
5089
5116
|
if (lastTotalTokenUsage && total >= lastTotalTokenUsage.total) {
|
|
5090
5117
|
const deltaInput = input - lastTotalTokenUsage.input;
|
|
5091
5118
|
const deltaCached = cached - lastTotalTokenUsage.cached;
|
|
@@ -5102,7 +5129,7 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
5102
5129
|
project,
|
|
5103
5130
|
model: rewriteCodexModelForTier(model, serviceTier),
|
|
5104
5131
|
confidence: "partial",
|
|
5105
|
-
metrics: {
|
|
5132
|
+
metrics: excludeForkInheritedCache({
|
|
5106
5133
|
tokensInput: deltaInput > 0 ? deltaInput : void 0,
|
|
5107
5134
|
tokensCachedInput: deltaCached > 0 ? deltaCached : void 0,
|
|
5108
5135
|
tokensOutput: deltaOutput > 0 ? deltaOutput : void 0,
|
|
@@ -5110,7 +5137,7 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
5110
5137
|
tokensTotal: deltaTotal > 0 ? deltaTotal : void 0,
|
|
5111
5138
|
modelContextWindow: usage.modelContextWindow,
|
|
5112
5139
|
reasoningEffort
|
|
5113
|
-
}
|
|
5140
|
+
}, forkedSession)
|
|
5114
5141
|
}), { filePath, sourcePathHash, lineNumber, topType, payloadType, options }));
|
|
5115
5142
|
}
|
|
5116
5143
|
} else {
|
|
@@ -5123,7 +5150,7 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
5123
5150
|
project,
|
|
5124
5151
|
model: rewriteCodexModelForTier(model, serviceTier),
|
|
5125
5152
|
confidence: "partial",
|
|
5126
|
-
metrics: {
|
|
5153
|
+
metrics: excludeForkInheritedCache({
|
|
5127
5154
|
tokensInput: input,
|
|
5128
5155
|
tokensCachedInput: cached,
|
|
5129
5156
|
tokensOutput: output,
|
|
@@ -5131,7 +5158,7 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
5131
5158
|
tokensTotal: total,
|
|
5132
5159
|
modelContextWindow: usage.modelContextWindow,
|
|
5133
5160
|
reasoningEffort
|
|
5134
|
-
}
|
|
5161
|
+
}, forkedSession)
|
|
5135
5162
|
}), { filePath, sourcePathHash, lineNumber, topType, payloadType, options }));
|
|
5136
5163
|
}
|
|
5137
5164
|
lastTotalTokenUsage = { input, cached, output, reasoning, total };
|
|
@@ -5389,6 +5416,13 @@ function tokenUsageFromPayload(payload) {
|
|
|
5389
5416
|
const info = objectField(payload, "info");
|
|
5390
5417
|
const totalUsage = objectField(info, "total_token_usage");
|
|
5391
5418
|
const usage = Object.keys(totalUsage).length > 0 ? totalUsage : objectField(info, "last_token_usage");
|
|
5419
|
+
return tokenUsageFromRecord(usage, info);
|
|
5420
|
+
}
|
|
5421
|
+
function lastTokenUsageFromPayload(payload) {
|
|
5422
|
+
const info = objectField(payload, "info");
|
|
5423
|
+
return tokenUsageFromRecord(objectField(info, "last_token_usage"), info);
|
|
5424
|
+
}
|
|
5425
|
+
function tokenUsageFromRecord(usage, info) {
|
|
5392
5426
|
if (Object.keys(usage).length === 0) {
|
|
5393
5427
|
return;
|
|
5394
5428
|
}
|
|
@@ -5410,6 +5444,18 @@ function tokenUsageFromPayload(payload) {
|
|
|
5410
5444
|
modelContextWindow: numberField(info, "model_context_window")
|
|
5411
5445
|
};
|
|
5412
5446
|
}
|
|
5447
|
+
function excludeForkInheritedCache(usage, forked) {
|
|
5448
|
+
if (!forked || !usage) {
|
|
5449
|
+
return usage;
|
|
5450
|
+
}
|
|
5451
|
+
const cached = usage.tokensCachedInput ?? 0;
|
|
5452
|
+
return {
|
|
5453
|
+
...usage,
|
|
5454
|
+
tokensInput: Math.max(0, (usage.tokensInput ?? 0) - cached) || void 0,
|
|
5455
|
+
tokensCachedInput: void 0,
|
|
5456
|
+
tokensTotal: Math.max(0, (usage.tokensTotal ?? 0) - cached) || void 0
|
|
5457
|
+
};
|
|
5458
|
+
}
|
|
5413
5459
|
function toolNameFromPayload(payload, payloadType) {
|
|
5414
5460
|
if (payloadType === "web_search_call") {
|
|
5415
5461
|
return "web_search";
|
|
@@ -7380,12 +7426,91 @@ function createPiAdapter() {
|
|
|
7380
7426
|
};
|
|
7381
7427
|
}
|
|
7382
7428
|
|
|
7383
|
-
// src/adapters/qoder-
|
|
7384
|
-
import {
|
|
7429
|
+
// src/adapters/qoder-local-db.ts
|
|
7430
|
+
import { access } from "node:fs/promises";
|
|
7385
7431
|
import os7 from "node:os";
|
|
7386
7432
|
import path16 from "node:path";
|
|
7433
|
+
function qoderLocalDbCandidates(appDirName) {
|
|
7434
|
+
const candidates = [];
|
|
7435
|
+
const envPath = process.env.QODER_LOCAL_DB_PATH;
|
|
7436
|
+
if (envPath) {
|
|
7437
|
+
candidates.push(envPath);
|
|
7438
|
+
}
|
|
7439
|
+
const home = os7.homedir();
|
|
7440
|
+
let configRoot;
|
|
7441
|
+
if (process.platform === "darwin") {
|
|
7442
|
+
configRoot = path16.join(home, "Library", "Application Support", appDirName);
|
|
7443
|
+
} else if (process.platform === "win32") {
|
|
7444
|
+
configRoot = path16.join(process.env.APPDATA || path16.join(home, "AppData", "Roaming"), appDirName);
|
|
7445
|
+
} else {
|
|
7446
|
+
configRoot = path16.join(home, ".config", appDirName);
|
|
7447
|
+
}
|
|
7448
|
+
candidates.push(
|
|
7449
|
+
path16.join(configRoot, "SharedClientCache", "cache", "db", "local.db"),
|
|
7450
|
+
path16.join(configRoot, "SharedClientCache", "db", "local.db")
|
|
7451
|
+
);
|
|
7452
|
+
return candidates;
|
|
7453
|
+
}
|
|
7454
|
+
async function loadQoderDbModelCalls(appDirName, sessionId, modelMap) {
|
|
7455
|
+
const calls = { byRequestId: /* @__PURE__ */ new Map(), ordered: [] };
|
|
7456
|
+
if (!sessionId) {
|
|
7457
|
+
return calls;
|
|
7458
|
+
}
|
|
7459
|
+
try {
|
|
7460
|
+
const { DatabaseSync } = await import("node:sqlite");
|
|
7461
|
+
let dbPath;
|
|
7462
|
+
for (const candidate of qoderLocalDbCandidates(appDirName)) {
|
|
7463
|
+
try {
|
|
7464
|
+
await access(candidate);
|
|
7465
|
+
dbPath = candidate;
|
|
7466
|
+
break;
|
|
7467
|
+
} catch {
|
|
7468
|
+
}
|
|
7469
|
+
}
|
|
7470
|
+
if (!dbPath) {
|
|
7471
|
+
return calls;
|
|
7472
|
+
}
|
|
7473
|
+
const db = new DatabaseSync(dbPath, { readOnly: true });
|
|
7474
|
+
try {
|
|
7475
|
+
const rows = db.prepare(
|
|
7476
|
+
`select request_id, token_info, model_info from chat_message where session_id = ? and role = 'assistant' and token_info != '' order by gmt_create asc`
|
|
7477
|
+
).all(sessionId);
|
|
7478
|
+
for (const row of rows) {
|
|
7479
|
+
const usage = parseJsonLine(stringField(row, "token_info") || "") || {};
|
|
7480
|
+
const modelInfo = parseJsonLine(stringField(row, "model_info") || "") || {};
|
|
7481
|
+
const modelKey = stringField(modelInfo, "model_key");
|
|
7482
|
+
const call = {
|
|
7483
|
+
model: modelKey ? modelMap[modelKey] || modelKey : void 0,
|
|
7484
|
+
inputTokens: numberField(usage, "prompt_tokens") || 0,
|
|
7485
|
+
outputTokens: numberField(usage, "completion_tokens") || 0,
|
|
7486
|
+
cachedTokens: numberField(usage, "cached_tokens") || 0
|
|
7487
|
+
};
|
|
7488
|
+
calls.ordered.push(call);
|
|
7489
|
+
const requestId = stringField(row, "request_id");
|
|
7490
|
+
if (!requestId) {
|
|
7491
|
+
continue;
|
|
7492
|
+
}
|
|
7493
|
+
const queue = calls.byRequestId.get(requestId);
|
|
7494
|
+
if (queue) {
|
|
7495
|
+
queue.push(call);
|
|
7496
|
+
} else {
|
|
7497
|
+
calls.byRequestId.set(requestId, [call]);
|
|
7498
|
+
}
|
|
7499
|
+
}
|
|
7500
|
+
} finally {
|
|
7501
|
+
db.close();
|
|
7502
|
+
}
|
|
7503
|
+
} catch {
|
|
7504
|
+
}
|
|
7505
|
+
return calls;
|
|
7506
|
+
}
|
|
7507
|
+
|
|
7508
|
+
// src/adapters/qoder-cn.ts
|
|
7509
|
+
import { readdir as readdir7, readFile as readFile10, stat as stat8 } from "node:fs/promises";
|
|
7510
|
+
import os8 from "node:os";
|
|
7511
|
+
import path17 from "node:path";
|
|
7387
7512
|
function parseQoderCnPaths(filePath) {
|
|
7388
|
-
const parts = filePath.split(
|
|
7513
|
+
const parts = filePath.split(path17.sep);
|
|
7389
7514
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
7390
7515
|
let sessionId = "";
|
|
7391
7516
|
let projectName = "";
|
|
@@ -7395,14 +7520,17 @@ function parseQoderCnPaths(filePath) {
|
|
|
7395
7520
|
sessionId = parts[subagentsIdx - 1];
|
|
7396
7521
|
projectName = parts[subagentsIdx - 2];
|
|
7397
7522
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
7398
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
7399
|
-
mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(
|
|
7523
|
+
configDir2 = parts.slice(0, projectsIdx).join(path17.sep);
|
|
7524
|
+
mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path17.sep);
|
|
7400
7525
|
} else {
|
|
7401
7526
|
const filename = parts.at(-1) || "";
|
|
7402
|
-
sessionId =
|
|
7527
|
+
sessionId = path17.basename(filename, ".jsonl");
|
|
7403
7528
|
projectName = parts.at(-2) || "";
|
|
7529
|
+
if (projectName === "transcript") {
|
|
7530
|
+
projectName = parts.at(-3) || "";
|
|
7531
|
+
}
|
|
7404
7532
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
7405
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
7533
|
+
configDir2 = parts.slice(0, projectsIdx).join(path17.sep);
|
|
7406
7534
|
}
|
|
7407
7535
|
return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
|
|
7408
7536
|
}
|
|
@@ -7425,7 +7553,7 @@ function rebuildEventIdentity2(event) {
|
|
|
7425
7553
|
}
|
|
7426
7554
|
async function loadQoderCnModelNames(configDir2) {
|
|
7427
7555
|
try {
|
|
7428
|
-
const dynamicTextsPath =
|
|
7556
|
+
const dynamicTextsPath = path17.join(configDir2, ".auth", "dynamic-texts.json");
|
|
7429
7557
|
const content = await readFile10(dynamicTextsPath, "utf8");
|
|
7430
7558
|
const json = JSON.parse(content);
|
|
7431
7559
|
const texts = json.texts || {};
|
|
@@ -7443,7 +7571,7 @@ async function loadQoderCnModelNames(configDir2) {
|
|
|
7443
7571
|
}
|
|
7444
7572
|
async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
7445
7573
|
const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
|
|
7446
|
-
const segmentsPath =
|
|
7574
|
+
const segmentsPath = path17.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
7447
7575
|
const modelCalls = [];
|
|
7448
7576
|
try {
|
|
7449
7577
|
const files = await readdir7(segmentsPath);
|
|
@@ -7451,7 +7579,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
|
|
|
7451
7579
|
if (!file.endsWith(".jsonl")) {
|
|
7452
7580
|
continue;
|
|
7453
7581
|
}
|
|
7454
|
-
const content = await readFile10(
|
|
7582
|
+
const content = await readFile10(path17.join(segmentsPath, file), "utf8");
|
|
7455
7583
|
let currentTurnIsSubagent = false;
|
|
7456
7584
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
7457
7585
|
const raw = parseJsonLine(line);
|
|
@@ -7498,6 +7626,17 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
7498
7626
|
const isSubagentSession = filePath.includes("subagents");
|
|
7499
7627
|
const segmentModelCalls = await loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap);
|
|
7500
7628
|
let modelCallIndex = 0;
|
|
7629
|
+
let dbModelCalls;
|
|
7630
|
+
const nextDbModelCall = async (requestId, blockStart) => {
|
|
7631
|
+
dbModelCalls ??= await loadQoderDbModelCalls("QoderCN", sessionId, modelMap);
|
|
7632
|
+
if (requestId) {
|
|
7633
|
+
return dbModelCalls.byRequestId.get(requestId)?.shift();
|
|
7634
|
+
}
|
|
7635
|
+
if (!blockStart) {
|
|
7636
|
+
return void 0;
|
|
7637
|
+
}
|
|
7638
|
+
return dbModelCalls.ordered.shift();
|
|
7639
|
+
};
|
|
7501
7640
|
const state = new SessionParserState(filePath, options, (event) => baseQoderCnEvent({ ...event, cwd, project, model }));
|
|
7502
7641
|
state.sessionId = sessionId;
|
|
7503
7642
|
const push = (event, ln, topType, payloadType) => {
|
|
@@ -7508,6 +7647,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
7508
7647
|
payloadType
|
|
7509
7648
|
);
|
|
7510
7649
|
};
|
|
7650
|
+
let assistantBlockOpen = false;
|
|
7511
7651
|
for (const [index, line] of lines.entries()) {
|
|
7512
7652
|
const lineNumber = index + 1;
|
|
7513
7653
|
const raw = parseJsonLine(line);
|
|
@@ -7515,11 +7655,14 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
7515
7655
|
continue;
|
|
7516
7656
|
}
|
|
7517
7657
|
const topType = stringField(raw, "type");
|
|
7658
|
+
if (topType !== "assistant") {
|
|
7659
|
+
assistantBlockOpen = false;
|
|
7660
|
+
}
|
|
7518
7661
|
const ts = timestampFrom(raw.timestamp);
|
|
7519
7662
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
7520
7663
|
state.sessionId = sessionId;
|
|
7521
7664
|
cwd = stringField(raw, "cwd") || cwd;
|
|
7522
|
-
project = projectContext.project || (cwd ?
|
|
7665
|
+
project = projectContext.project || (cwd ? path17.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
|
|
7523
7666
|
if (!ts) {
|
|
7524
7667
|
continue;
|
|
7525
7668
|
}
|
|
@@ -7652,6 +7795,8 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
7652
7795
|
model = rawModel ? modelMap[rawModel] || rawModel : void 0;
|
|
7653
7796
|
const messageId = stringField(message, "id");
|
|
7654
7797
|
const requestId = stringField(raw, "requestId");
|
|
7798
|
+
const isBlockStart = !assistantBlockOpen;
|
|
7799
|
+
assistantBlockOpen = true;
|
|
7655
7800
|
const usageKey = messageId ? `${messageId}:${requestId}` : null;
|
|
7656
7801
|
const shouldEmitUsage = usageKey == null || !seenUsageKeys.has(usageKey);
|
|
7657
7802
|
if (usageKey != null) {
|
|
@@ -7676,6 +7821,19 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
7676
7821
|
modelCalls: 1
|
|
7677
7822
|
};
|
|
7678
7823
|
model = call.model || model;
|
|
7824
|
+
} else if (shouldEmitUsage) {
|
|
7825
|
+
const dbCall = await nextDbModelCall(requestId, isBlockStart);
|
|
7826
|
+
if (dbCall) {
|
|
7827
|
+
usage = {
|
|
7828
|
+
tokensInput: dbCall.inputTokens || void 0,
|
|
7829
|
+
tokensCachedInput: dbCall.cachedTokens || void 0,
|
|
7830
|
+
tokensCacheReadInput: dbCall.cachedTokens || void 0,
|
|
7831
|
+
tokensOutput: dbCall.outputTokens || void 0,
|
|
7832
|
+
tokensTotal: dbCall.inputTokens + dbCall.outputTokens || void 0,
|
|
7833
|
+
modelCalls: 1
|
|
7834
|
+
};
|
|
7835
|
+
model = dbCall.model || model;
|
|
7836
|
+
}
|
|
7679
7837
|
}
|
|
7680
7838
|
if (usage) {
|
|
7681
7839
|
const speed = stringField(objectField(message, "usage"), "speed");
|
|
@@ -7956,28 +8114,28 @@ function isNoisePrompt(text) {
|
|
|
7956
8114
|
}
|
|
7957
8115
|
async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
7958
8116
|
const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
|
|
7959
|
-
const isSubagent = filePath.includes(`${
|
|
8117
|
+
const isSubagent = filePath.includes(`${path17.sep}subagents${path17.sep}`);
|
|
7960
8118
|
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
7961
8119
|
let cwds = [];
|
|
7962
8120
|
for (const line of lines) {
|
|
7963
8121
|
const raw = parseJsonLine(line);
|
|
7964
8122
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
7965
|
-
if (cwd &&
|
|
8123
|
+
if (cwd && path17.isAbsolute(cwd)) {
|
|
7966
8124
|
cwds.push(cwd);
|
|
7967
8125
|
}
|
|
7968
8126
|
}
|
|
7969
8127
|
if (isSubagent) {
|
|
7970
|
-
if (inherited?.cwd &&
|
|
8128
|
+
if (inherited?.cwd && path17.isAbsolute(inherited.cwd)) {
|
|
7971
8129
|
cwds = [inherited.cwd];
|
|
7972
8130
|
} else {
|
|
7973
|
-
const parentSessionPath =
|
|
8131
|
+
const parentSessionPath = path17.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
7974
8132
|
try {
|
|
7975
8133
|
const parentText = await readFile10(parentSessionPath, "utf8");
|
|
7976
8134
|
const parentCwds = [];
|
|
7977
8135
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
7978
8136
|
const raw = parseJsonLine(line);
|
|
7979
8137
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
7980
|
-
if (cwd &&
|
|
8138
|
+
if (cwd && path17.isAbsolute(cwd)) {
|
|
7981
8139
|
parentCwds.push(cwd);
|
|
7982
8140
|
}
|
|
7983
8141
|
}
|
|
@@ -7989,7 +8147,7 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
7989
8147
|
}
|
|
7990
8148
|
}
|
|
7991
8149
|
const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
|
|
7992
|
-
const project = inherited?.project || (cwds.length > 0 ?
|
|
8150
|
+
const project = inherited?.project || (cwds.length > 0 ? path17.basename(cwds[0]) : root ? path17.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
|
|
7993
8151
|
return {
|
|
7994
8152
|
project,
|
|
7995
8153
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -7998,15 +8156,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
7998
8156
|
async function gitRootFromCwds2(cwds) {
|
|
7999
8157
|
const seen = /* @__PURE__ */ new Set();
|
|
8000
8158
|
for (const cwd of cwds) {
|
|
8001
|
-
let current =
|
|
8159
|
+
let current = path17.resolve(cwd);
|
|
8002
8160
|
while (!seen.has(current)) {
|
|
8003
8161
|
seen.add(current);
|
|
8004
8162
|
try {
|
|
8005
|
-
await stat8(
|
|
8163
|
+
await stat8(path17.join(current, ".git"));
|
|
8006
8164
|
return current;
|
|
8007
8165
|
} catch {
|
|
8008
8166
|
}
|
|
8009
|
-
const parent =
|
|
8167
|
+
const parent = path17.dirname(current);
|
|
8010
8168
|
if (parent === current) {
|
|
8011
8169
|
break;
|
|
8012
8170
|
}
|
|
@@ -8017,12 +8175,12 @@ async function gitRootFromCwds2(cwds) {
|
|
|
8017
8175
|
}
|
|
8018
8176
|
function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
8019
8177
|
for (const cwd of cwds) {
|
|
8020
|
-
let current =
|
|
8178
|
+
let current = path17.resolve(cwd);
|
|
8021
8179
|
while (true) {
|
|
8022
8180
|
if (encodeQoderCnProjectPath(current) === projectDir) {
|
|
8023
8181
|
return current;
|
|
8024
8182
|
}
|
|
8025
|
-
const parent =
|
|
8183
|
+
const parent = path17.dirname(current);
|
|
8026
8184
|
if (parent === current) {
|
|
8027
8185
|
break;
|
|
8028
8186
|
}
|
|
@@ -8032,14 +8190,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
|
8032
8190
|
return void 0;
|
|
8033
8191
|
}
|
|
8034
8192
|
function encodeQoderCnProjectPath(value) {
|
|
8035
|
-
return
|
|
8193
|
+
return path17.resolve(value).split(path17.sep).join("-").replace(/_/g, "-");
|
|
8036
8194
|
}
|
|
8037
8195
|
async function qoderCnProjectFromFilePath(filePath, options) {
|
|
8038
|
-
const projectDir =
|
|
8039
|
-
const home = options ?
|
|
8196
|
+
const projectDir = path17.basename(path17.dirname(filePath));
|
|
8197
|
+
const home = options ? path17.resolve(stringOption(options.home) || os8.homedir()) : os8.homedir();
|
|
8040
8198
|
const resolved = await resolveQoderCnProjectPath(projectDir, home);
|
|
8041
8199
|
if (resolved) {
|
|
8042
|
-
return
|
|
8200
|
+
return path17.basename(resolved);
|
|
8043
8201
|
}
|
|
8044
8202
|
const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
|
|
8045
8203
|
if (projectDir.startsWith(homePrefix)) {
|
|
@@ -8064,7 +8222,7 @@ async function resolveQoderCnProjectPath(projectDir, home) {
|
|
|
8064
8222
|
if (!entry.isDirectory()) {
|
|
8065
8223
|
continue;
|
|
8066
8224
|
}
|
|
8067
|
-
const candidate =
|
|
8225
|
+
const candidate = path17.join(current, entry.name);
|
|
8068
8226
|
const encoded = encodeQoderCnProjectPath(candidate);
|
|
8069
8227
|
if (encoded === projectDir) {
|
|
8070
8228
|
return candidate;
|
|
@@ -8109,9 +8267,9 @@ function hookConfig6() {
|
|
|
8109
8267
|
function qoderCnConfigDir(home, env) {
|
|
8110
8268
|
const override = env?.QODER_CN_CONFIG_DIR;
|
|
8111
8269
|
if (override && override.trim()) {
|
|
8112
|
-
return
|
|
8270
|
+
return path17.resolve(override);
|
|
8113
8271
|
}
|
|
8114
|
-
return
|
|
8272
|
+
return path17.join(home, ".qoder-cn");
|
|
8115
8273
|
}
|
|
8116
8274
|
function createQoderCnAdapter() {
|
|
8117
8275
|
return {
|
|
@@ -8123,27 +8281,27 @@ function createQoderCnAdapter() {
|
|
|
8123
8281
|
return qoderCnConfigDir(home, env);
|
|
8124
8282
|
},
|
|
8125
8283
|
installedPath(home, env) {
|
|
8126
|
-
return
|
|
8284
|
+
return path17.join(qoderCnConfigDir(home, env), "settings.json");
|
|
8127
8285
|
},
|
|
8128
8286
|
async isInstalled(home, env) {
|
|
8129
8287
|
return isHooksJsonInstalled(
|
|
8130
|
-
|
|
8288
|
+
path17.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
8131
8289
|
"vibetime hook --agent qoder-cn"
|
|
8132
8290
|
);
|
|
8133
8291
|
},
|
|
8134
8292
|
installEntries(home, env) {
|
|
8135
8293
|
return [{
|
|
8136
8294
|
kind: "hooks-json",
|
|
8137
|
-
path:
|
|
8295
|
+
path: path17.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
8138
8296
|
content: hookConfig6()
|
|
8139
8297
|
}];
|
|
8140
8298
|
},
|
|
8141
8299
|
sourcePaths(home, env) {
|
|
8142
8300
|
const base = qoderCnConfigDir(home, env);
|
|
8143
8301
|
return [
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8302
|
+
path17.join(base, "projects"),
|
|
8303
|
+
path17.join(base, ".qoder.json"),
|
|
8304
|
+
path17.join(home, ".qoder.json")
|
|
8147
8305
|
];
|
|
8148
8306
|
},
|
|
8149
8307
|
parseSessionFile: parseQoderCnSessionFile
|
|
@@ -8152,10 +8310,10 @@ function createQoderCnAdapter() {
|
|
|
8152
8310
|
|
|
8153
8311
|
// src/adapters/qoder.ts
|
|
8154
8312
|
import { readdir as readdir8, readFile as readFile11, stat as stat9 } from "node:fs/promises";
|
|
8155
|
-
import
|
|
8156
|
-
import
|
|
8313
|
+
import os9 from "node:os";
|
|
8314
|
+
import path18 from "node:path";
|
|
8157
8315
|
function parseQoderPaths(filePath) {
|
|
8158
|
-
const parts = filePath.split(
|
|
8316
|
+
const parts = filePath.split(path18.sep);
|
|
8159
8317
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
8160
8318
|
let sessionId = "";
|
|
8161
8319
|
let projectName = "";
|
|
@@ -8165,14 +8323,17 @@ function parseQoderPaths(filePath) {
|
|
|
8165
8323
|
sessionId = parts[subagentsIdx - 1];
|
|
8166
8324
|
projectName = parts[subagentsIdx - 2];
|
|
8167
8325
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
8168
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
8169
|
-
mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(
|
|
8326
|
+
configDir2 = parts.slice(0, projectsIdx).join(path18.sep);
|
|
8327
|
+
mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path18.sep);
|
|
8170
8328
|
} else {
|
|
8171
8329
|
const filename = parts.at(-1) || "";
|
|
8172
|
-
sessionId =
|
|
8330
|
+
sessionId = path18.basename(filename, ".jsonl");
|
|
8173
8331
|
projectName = parts.at(-2) || "";
|
|
8332
|
+
if (projectName === "transcript") {
|
|
8333
|
+
projectName = parts.at(-3) || "";
|
|
8334
|
+
}
|
|
8174
8335
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
8175
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
8336
|
+
configDir2 = parts.slice(0, projectsIdx).join(path18.sep);
|
|
8176
8337
|
}
|
|
8177
8338
|
return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
|
|
8178
8339
|
}
|
|
@@ -8195,7 +8356,7 @@ function rebuildEventIdentity3(event) {
|
|
|
8195
8356
|
}
|
|
8196
8357
|
async function loadQoderModelNames(configDir2) {
|
|
8197
8358
|
try {
|
|
8198
|
-
const dynamicTextsPath =
|
|
8359
|
+
const dynamicTextsPath = path18.join(configDir2, ".auth", "dynamic-texts.json");
|
|
8199
8360
|
const content = await readFile11(dynamicTextsPath, "utf8");
|
|
8200
8361
|
const json = JSON.parse(content);
|
|
8201
8362
|
const texts = json.texts || {};
|
|
@@ -8213,7 +8374,7 @@ async function loadQoderModelNames(configDir2) {
|
|
|
8213
8374
|
}
|
|
8214
8375
|
async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
8215
8376
|
const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
|
|
8216
|
-
const segmentsPath =
|
|
8377
|
+
const segmentsPath = path18.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
8217
8378
|
const modelCalls = [];
|
|
8218
8379
|
try {
|
|
8219
8380
|
const files = await readdir8(segmentsPath);
|
|
@@ -8221,7 +8382,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
|
|
|
8221
8382
|
if (!file.endsWith(".jsonl")) {
|
|
8222
8383
|
continue;
|
|
8223
8384
|
}
|
|
8224
|
-
const content = await readFile11(
|
|
8385
|
+
const content = await readFile11(path18.join(segmentsPath, file), "utf8");
|
|
8225
8386
|
let currentTurnIsSubagent = false;
|
|
8226
8387
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
8227
8388
|
const raw = parseJsonLine(line);
|
|
@@ -8268,6 +8429,17 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
8268
8429
|
const isSubagentSession = filePath.includes("subagents");
|
|
8269
8430
|
const segmentModelCalls = await loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap);
|
|
8270
8431
|
let modelCallIndex = 0;
|
|
8432
|
+
let dbModelCalls;
|
|
8433
|
+
const nextDbModelCall = async (requestId, blockStart) => {
|
|
8434
|
+
dbModelCalls ??= await loadQoderDbModelCalls("Qoder", sessionId, modelMap);
|
|
8435
|
+
if (requestId) {
|
|
8436
|
+
return dbModelCalls.byRequestId.get(requestId)?.shift();
|
|
8437
|
+
}
|
|
8438
|
+
if (!blockStart) {
|
|
8439
|
+
return void 0;
|
|
8440
|
+
}
|
|
8441
|
+
return dbModelCalls.ordered.shift();
|
|
8442
|
+
};
|
|
8271
8443
|
const state = new SessionParserState(filePath, options, (event) => baseQoderEvent({ ...event, cwd, project, model }));
|
|
8272
8444
|
state.sessionId = sessionId;
|
|
8273
8445
|
const push = (event, ln, topType, payloadType) => {
|
|
@@ -8278,6 +8450,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
8278
8450
|
payloadType
|
|
8279
8451
|
);
|
|
8280
8452
|
};
|
|
8453
|
+
let assistantBlockOpen = false;
|
|
8281
8454
|
for (const [index, line] of lines.entries()) {
|
|
8282
8455
|
const lineNumber = index + 1;
|
|
8283
8456
|
const raw = parseJsonLine(line);
|
|
@@ -8285,11 +8458,14 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
8285
8458
|
continue;
|
|
8286
8459
|
}
|
|
8287
8460
|
const topType = stringField(raw, "type");
|
|
8461
|
+
if (topType !== "assistant") {
|
|
8462
|
+
assistantBlockOpen = false;
|
|
8463
|
+
}
|
|
8288
8464
|
const ts = timestampFrom(raw.timestamp);
|
|
8289
8465
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
8290
8466
|
state.sessionId = sessionId;
|
|
8291
8467
|
cwd = stringField(raw, "cwd") || cwd;
|
|
8292
|
-
project = projectContext.project || (cwd ?
|
|
8468
|
+
project = projectContext.project || (cwd ? path18.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
|
|
8293
8469
|
if (!ts) {
|
|
8294
8470
|
continue;
|
|
8295
8471
|
}
|
|
@@ -8422,6 +8598,8 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
8422
8598
|
model = rawModel ? modelMap[rawModel] || rawModel : void 0;
|
|
8423
8599
|
const messageId = stringField(message, "id");
|
|
8424
8600
|
const requestId = stringField(raw, "requestId");
|
|
8601
|
+
const isBlockStart = !assistantBlockOpen;
|
|
8602
|
+
assistantBlockOpen = true;
|
|
8425
8603
|
const usageKey = messageId ? `${messageId}:${requestId}` : null;
|
|
8426
8604
|
const shouldEmitUsage = usageKey == null || !seenUsageKeys.has(usageKey);
|
|
8427
8605
|
if (usageKey != null) {
|
|
@@ -8446,6 +8624,19 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
8446
8624
|
modelCalls: 1
|
|
8447
8625
|
};
|
|
8448
8626
|
model = call.model || model;
|
|
8627
|
+
} else if (shouldEmitUsage) {
|
|
8628
|
+
const dbCall = await nextDbModelCall(requestId, isBlockStart);
|
|
8629
|
+
if (dbCall) {
|
|
8630
|
+
usage = {
|
|
8631
|
+
tokensInput: dbCall.inputTokens || void 0,
|
|
8632
|
+
tokensCachedInput: dbCall.cachedTokens || void 0,
|
|
8633
|
+
tokensCacheReadInput: dbCall.cachedTokens || void 0,
|
|
8634
|
+
tokensOutput: dbCall.outputTokens || void 0,
|
|
8635
|
+
tokensTotal: dbCall.inputTokens + dbCall.outputTokens || void 0,
|
|
8636
|
+
modelCalls: 1
|
|
8637
|
+
};
|
|
8638
|
+
model = dbCall.model || model;
|
|
8639
|
+
}
|
|
8449
8640
|
}
|
|
8450
8641
|
if (usage) {
|
|
8451
8642
|
const speed = stringField(objectField(message, "usage"), "speed");
|
|
@@ -8692,28 +8883,28 @@ function qoderExtractText(value) {
|
|
|
8692
8883
|
}
|
|
8693
8884
|
async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
8694
8885
|
const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
|
|
8695
|
-
const isSubagent = filePath.includes(`${
|
|
8886
|
+
const isSubagent = filePath.includes(`${path18.sep}subagents${path18.sep}`);
|
|
8696
8887
|
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
8697
8888
|
let cwds = [];
|
|
8698
8889
|
for (const line of lines) {
|
|
8699
8890
|
const raw = parseJsonLine(line);
|
|
8700
8891
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
8701
|
-
if (cwd &&
|
|
8892
|
+
if (cwd && path18.isAbsolute(cwd)) {
|
|
8702
8893
|
cwds.push(cwd);
|
|
8703
8894
|
}
|
|
8704
8895
|
}
|
|
8705
8896
|
if (isSubagent) {
|
|
8706
|
-
if (inherited?.cwd &&
|
|
8897
|
+
if (inherited?.cwd && path18.isAbsolute(inherited.cwd)) {
|
|
8707
8898
|
cwds = [inherited.cwd];
|
|
8708
8899
|
} else {
|
|
8709
|
-
const parentSessionPath =
|
|
8900
|
+
const parentSessionPath = path18.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
8710
8901
|
try {
|
|
8711
8902
|
const parentText = await readFile11(parentSessionPath, "utf8");
|
|
8712
8903
|
const parentCwds = [];
|
|
8713
8904
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
8714
8905
|
const raw = parseJsonLine(line);
|
|
8715
8906
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
8716
|
-
if (cwd &&
|
|
8907
|
+
if (cwd && path18.isAbsolute(cwd)) {
|
|
8717
8908
|
parentCwds.push(cwd);
|
|
8718
8909
|
}
|
|
8719
8910
|
}
|
|
@@ -8725,7 +8916,7 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
8725
8916
|
}
|
|
8726
8917
|
}
|
|
8727
8918
|
const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
|
|
8728
|
-
const project = inherited?.project || (cwds.length > 0 ?
|
|
8919
|
+
const project = inherited?.project || (cwds.length > 0 ? path18.basename(cwds[0]) : root ? path18.basename(root) : await qoderProjectFromFilePath(filePath, options));
|
|
8729
8920
|
return {
|
|
8730
8921
|
project,
|
|
8731
8922
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -8734,15 +8925,15 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
8734
8925
|
async function gitRootFromCwds3(cwds) {
|
|
8735
8926
|
const seen = /* @__PURE__ */ new Set();
|
|
8736
8927
|
for (const cwd of cwds) {
|
|
8737
|
-
let current =
|
|
8928
|
+
let current = path18.resolve(cwd);
|
|
8738
8929
|
while (!seen.has(current)) {
|
|
8739
8930
|
seen.add(current);
|
|
8740
8931
|
try {
|
|
8741
|
-
await stat9(
|
|
8932
|
+
await stat9(path18.join(current, ".git"));
|
|
8742
8933
|
return current;
|
|
8743
8934
|
} catch {
|
|
8744
8935
|
}
|
|
8745
|
-
const parent =
|
|
8936
|
+
const parent = path18.dirname(current);
|
|
8746
8937
|
if (parent === current) {
|
|
8747
8938
|
break;
|
|
8748
8939
|
}
|
|
@@ -8753,12 +8944,12 @@ async function gitRootFromCwds3(cwds) {
|
|
|
8753
8944
|
}
|
|
8754
8945
|
function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
8755
8946
|
for (const cwd of cwds) {
|
|
8756
|
-
let current =
|
|
8947
|
+
let current = path18.resolve(cwd);
|
|
8757
8948
|
while (true) {
|
|
8758
8949
|
if (encodeQoderProjectPath(current) === projectDir) {
|
|
8759
8950
|
return current;
|
|
8760
8951
|
}
|
|
8761
|
-
const parent =
|
|
8952
|
+
const parent = path18.dirname(current);
|
|
8762
8953
|
if (parent === current) {
|
|
8763
8954
|
break;
|
|
8764
8955
|
}
|
|
@@ -8768,10 +8959,10 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
|
8768
8959
|
return void 0;
|
|
8769
8960
|
}
|
|
8770
8961
|
function encodeQoderProjectPath(value) {
|
|
8771
|
-
return
|
|
8962
|
+
return path18.resolve(value).split(path18.sep).join("-").replace(/_/g, "-");
|
|
8772
8963
|
}
|
|
8773
8964
|
function rawQoderProjectPath(value) {
|
|
8774
|
-
return
|
|
8965
|
+
return path18.resolve(value).split(path18.sep).join("-");
|
|
8775
8966
|
}
|
|
8776
8967
|
function qoderEncodedVariants(value) {
|
|
8777
8968
|
const raw = rawQoderProjectPath(value);
|
|
@@ -8787,11 +8978,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
|
|
|
8787
8978
|
return void 0;
|
|
8788
8979
|
}
|
|
8789
8980
|
async function qoderProjectFromFilePath(filePath, options) {
|
|
8790
|
-
const projectDir =
|
|
8791
|
-
const home = options ?
|
|
8981
|
+
const projectDir = path18.basename(path18.dirname(filePath));
|
|
8982
|
+
const home = options ? path18.resolve(stringOption(options.home) || os9.homedir()) : os9.homedir();
|
|
8792
8983
|
const resolved = await resolveQoderProjectPath(projectDir, home);
|
|
8793
8984
|
if (resolved) {
|
|
8794
|
-
return
|
|
8985
|
+
return path18.basename(resolved);
|
|
8795
8986
|
}
|
|
8796
8987
|
const suffix = qoderEncodedProjectSuffix(projectDir, home);
|
|
8797
8988
|
if (suffix) {
|
|
@@ -8817,7 +9008,7 @@ async function resolveQoderProjectPath(projectDir, home) {
|
|
|
8817
9008
|
if (!entry.isDirectory()) {
|
|
8818
9009
|
continue;
|
|
8819
9010
|
}
|
|
8820
|
-
const candidate =
|
|
9011
|
+
const candidate = path18.join(current, entry.name);
|
|
8821
9012
|
const candidateVariants = qoderEncodedVariants(candidate);
|
|
8822
9013
|
if (candidateVariants.includes(projectDir)) {
|
|
8823
9014
|
return candidate;
|
|
@@ -8862,9 +9053,9 @@ function hookConfig7() {
|
|
|
8862
9053
|
function qoderConfigDir(home, env) {
|
|
8863
9054
|
const override = env?.QODER_CONFIG_DIR;
|
|
8864
9055
|
if (override && override.trim()) {
|
|
8865
|
-
return
|
|
9056
|
+
return path18.resolve(override);
|
|
8866
9057
|
}
|
|
8867
|
-
return
|
|
9058
|
+
return path18.join(home, ".qoder");
|
|
8868
9059
|
}
|
|
8869
9060
|
function createQoderAdapter() {
|
|
8870
9061
|
return {
|
|
@@ -8876,27 +9067,27 @@ function createQoderAdapter() {
|
|
|
8876
9067
|
return qoderConfigDir(home, env);
|
|
8877
9068
|
},
|
|
8878
9069
|
installedPath(home, env) {
|
|
8879
|
-
return
|
|
9070
|
+
return path18.join(qoderConfigDir(home, env), "settings.json");
|
|
8880
9071
|
},
|
|
8881
9072
|
async isInstalled(home, env) {
|
|
8882
9073
|
return isHooksJsonInstalled(
|
|
8883
|
-
|
|
9074
|
+
path18.join(qoderConfigDir(home, env), "settings.json"),
|
|
8884
9075
|
"vibetime hook --agent qoder"
|
|
8885
9076
|
);
|
|
8886
9077
|
},
|
|
8887
9078
|
installEntries(home, env) {
|
|
8888
9079
|
return [{
|
|
8889
9080
|
kind: "hooks-json",
|
|
8890
|
-
path:
|
|
9081
|
+
path: path18.join(qoderConfigDir(home, env), "settings.json"),
|
|
8891
9082
|
content: hookConfig7()
|
|
8892
9083
|
}];
|
|
8893
9084
|
},
|
|
8894
9085
|
sourcePaths(home, env) {
|
|
8895
9086
|
const base = qoderConfigDir(home, env);
|
|
8896
9087
|
return [
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
9088
|
+
path18.join(base, "projects"),
|
|
9089
|
+
path18.join(base, ".qoder.json"),
|
|
9090
|
+
path18.join(home, ".qoder.json")
|
|
8900
9091
|
];
|
|
8901
9092
|
},
|
|
8902
9093
|
parseSessionFile: parseQoderSessionFile
|
|
@@ -8932,20 +9123,20 @@ function normalizeId(id) {
|
|
|
8932
9123
|
|
|
8933
9124
|
// src/adapters/workbuddy.ts
|
|
8934
9125
|
import { readFile as readFile12, readdir as readdir9, stat as stat10 } from "node:fs/promises";
|
|
8935
|
-
import
|
|
9126
|
+
import path19 from "node:path";
|
|
8936
9127
|
init_fs();
|
|
8937
9128
|
function workbuddyProjectsDir(home, env) {
|
|
8938
9129
|
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
8939
9130
|
if (override && override.trim()) {
|
|
8940
|
-
return
|
|
9131
|
+
return path19.resolve(override, override.endsWith("projects") ? "" : "projects");
|
|
8941
9132
|
}
|
|
8942
|
-
return
|
|
9133
|
+
return path19.join(home, ".workbuddy", "projects");
|
|
8943
9134
|
}
|
|
8944
9135
|
function projectFromCwd(cwd, fallback) {
|
|
8945
9136
|
if (!cwd) {
|
|
8946
9137
|
return fallback;
|
|
8947
9138
|
}
|
|
8948
|
-
return
|
|
9139
|
+
return path19.basename(cwd) || fallback;
|
|
8949
9140
|
}
|
|
8950
9141
|
function sourceHash(filePath) {
|
|
8951
9142
|
return `sha256:${createStableHash(filePath)}`;
|
|
@@ -9048,8 +9239,8 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
9048
9239
|
}
|
|
9049
9240
|
const events = [];
|
|
9050
9241
|
const first = lines[0].record;
|
|
9051
|
-
const sessionId = stringField(first, "sessionId") ||
|
|
9052
|
-
const fallbackProject =
|
|
9242
|
+
const sessionId = stringField(first, "sessionId") || path19.basename(filePath, ".jsonl");
|
|
9243
|
+
const fallbackProject = path19.basename(path19.dirname(filePath));
|
|
9053
9244
|
const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
|
|
9054
9245
|
const project = projectFromCwd(cwd, fallbackProject);
|
|
9055
9246
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
@@ -9223,11 +9414,11 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
9223
9414
|
if (!project.isDirectory()) {
|
|
9224
9415
|
continue;
|
|
9225
9416
|
}
|
|
9226
|
-
const projectDir =
|
|
9417
|
+
const projectDir = path19.join(base, project.name);
|
|
9227
9418
|
const entries = await readdir9(projectDir, { withFileTypes: true });
|
|
9228
9419
|
for (const entry of entries) {
|
|
9229
9420
|
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
9230
|
-
const filePath =
|
|
9421
|
+
const filePath = path19.join(projectDir, entry.name);
|
|
9231
9422
|
const info = await stat10(filePath);
|
|
9232
9423
|
files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
|
|
9233
9424
|
}
|
|
@@ -9266,19 +9457,19 @@ function createWorkbuddyAdapter() {
|
|
|
9266
9457
|
// src/adapters/zcode.ts
|
|
9267
9458
|
import { execFile } from "node:child_process";
|
|
9268
9459
|
import { readFile as readFile13, stat as stat11 } from "node:fs/promises";
|
|
9269
|
-
import
|
|
9460
|
+
import path20 from "node:path";
|
|
9270
9461
|
import { promisify as promisify2 } from "node:util";
|
|
9271
9462
|
init_fs();
|
|
9272
9463
|
var execFileAsync = promisify2(execFile);
|
|
9273
9464
|
function zcodeCliDir(home, env) {
|
|
9274
9465
|
const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
|
|
9275
9466
|
if (override && override.trim()) {
|
|
9276
|
-
return
|
|
9467
|
+
return path20.resolve(override, override.endsWith("cli") ? "" : "cli");
|
|
9277
9468
|
}
|
|
9278
|
-
return
|
|
9469
|
+
return path20.join(home, ".zcode", "cli");
|
|
9279
9470
|
}
|
|
9280
9471
|
function zcodeDbPath(home, env) {
|
|
9281
|
-
return
|
|
9472
|
+
return path20.join(zcodeCliDir(home, env), "db", "db.sqlite");
|
|
9282
9473
|
}
|
|
9283
9474
|
var providerNameCache = null;
|
|
9284
9475
|
async function loadProviderNames(configPath2) {
|
|
@@ -9312,7 +9503,7 @@ function sourceHash2(filePath) {
|
|
|
9312
9503
|
return `sha256:${createStableHash(filePath)}`;
|
|
9313
9504
|
}
|
|
9314
9505
|
function projectFromDirectory(directory) {
|
|
9315
|
-
return directory ?
|
|
9506
|
+
return directory ? path20.basename(directory) || "zcode" : "zcode";
|
|
9316
9507
|
}
|
|
9317
9508
|
function isoFromMs(value) {
|
|
9318
9509
|
return timestampFrom(typeof value === "number" ? value : Number(value));
|
|
@@ -9495,16 +9686,16 @@ async function parseZCodeDb(filePath, options) {
|
|
|
9495
9686
|
if (rows.length === 0) {
|
|
9496
9687
|
return [];
|
|
9497
9688
|
}
|
|
9498
|
-
let candidate =
|
|
9689
|
+
let candidate = path20.resolve(filePath);
|
|
9499
9690
|
let configPath2 = "";
|
|
9500
9691
|
for (let i = 0; i < 12; i++) {
|
|
9501
|
-
const probe =
|
|
9692
|
+
const probe = path20.join(candidate, ".zcode", "v2", "config.json");
|
|
9502
9693
|
try {
|
|
9503
9694
|
await stat11(probe);
|
|
9504
9695
|
configPath2 = probe;
|
|
9505
9696
|
break;
|
|
9506
9697
|
} catch {
|
|
9507
|
-
const parent =
|
|
9698
|
+
const parent = path20.dirname(candidate);
|
|
9508
9699
|
if (parent === candidate) break;
|
|
9509
9700
|
candidate = parent;
|
|
9510
9701
|
}
|
|
@@ -9720,7 +9911,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
9720
9911
|
}
|
|
9721
9912
|
async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
9722
9913
|
const candidate = sourceRoot || zcodeDbPath(home, env);
|
|
9723
|
-
const filePath = candidate.endsWith(".sqlite") ? candidate :
|
|
9914
|
+
const filePath = candidate.endsWith(".sqlite") ? candidate : path20.join(candidate, "db", "db.sqlite");
|
|
9724
9915
|
try {
|
|
9725
9916
|
const info = await stat11(filePath);
|
|
9726
9917
|
return [{ path: filePath, modifiedAt: info.mtime.toISOString() }];
|
|
@@ -9754,50 +9945,50 @@ function createZCodeAdapter() {
|
|
|
9754
9945
|
}
|
|
9755
9946
|
|
|
9756
9947
|
// src/adapters/zed.ts
|
|
9757
|
-
import
|
|
9758
|
-
import
|
|
9948
|
+
import os10 from "node:os";
|
|
9949
|
+
import path21 from "node:path";
|
|
9759
9950
|
function zedThreadsCandidates(home, env) {
|
|
9760
9951
|
const candidates = [];
|
|
9761
9952
|
const platform2 = process.platform;
|
|
9762
9953
|
if (platform2 === "darwin") {
|
|
9763
|
-
candidates.push(
|
|
9954
|
+
candidates.push(path21.join(home, "Library", "Application Support", "Zed", "threads", "threads.db"));
|
|
9764
9955
|
} else if (platform2 === "win32") {
|
|
9765
9956
|
const appdata = env?.APPDATA;
|
|
9766
9957
|
if (appdata && appdata.trim()) {
|
|
9767
|
-
candidates.push(
|
|
9958
|
+
candidates.push(path21.join(path21.resolve(appdata), "Zed", "threads", "threads.db"));
|
|
9768
9959
|
}
|
|
9769
|
-
candidates.push(
|
|
9960
|
+
candidates.push(path21.join(home, "AppData", "Roaming", "Zed", "threads", "threads.db"));
|
|
9770
9961
|
} else {
|
|
9771
9962
|
const xdgData = env?.XDG_DATA_HOME;
|
|
9772
9963
|
if (xdgData && xdgData.trim()) {
|
|
9773
|
-
candidates.push(
|
|
9964
|
+
candidates.push(path21.join(path21.resolve(xdgData), "zed", "threads", "threads.db"));
|
|
9774
9965
|
}
|
|
9775
|
-
candidates.push(
|
|
9966
|
+
candidates.push(path21.join(home, ".local", "share", "zed", "threads", "threads.db"));
|
|
9776
9967
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
9777
9968
|
if (xdgConfig && xdgConfig.trim()) {
|
|
9778
|
-
candidates.push(
|
|
9969
|
+
candidates.push(path21.join(path21.resolve(xdgConfig), "zed", "threads", "threads.db"));
|
|
9779
9970
|
}
|
|
9780
|
-
candidates.push(
|
|
9971
|
+
candidates.push(path21.join(home, ".config", "zed", "threads", "threads.db"));
|
|
9781
9972
|
}
|
|
9782
9973
|
return candidates;
|
|
9783
9974
|
}
|
|
9784
9975
|
function zedConfigDir(home, env) {
|
|
9785
9976
|
const platform2 = process.platform;
|
|
9786
9977
|
if (platform2 === "darwin") {
|
|
9787
|
-
return
|
|
9978
|
+
return path21.join(home, "Library", "Application Support", "Zed");
|
|
9788
9979
|
}
|
|
9789
9980
|
if (platform2 === "win32") {
|
|
9790
9981
|
const appdata = env?.APPDATA;
|
|
9791
9982
|
if (appdata && appdata.trim()) {
|
|
9792
|
-
return
|
|
9983
|
+
return path21.join(path21.resolve(appdata), "Zed");
|
|
9793
9984
|
}
|
|
9794
|
-
return
|
|
9985
|
+
return path21.join(home, "AppData", "Roaming", "Zed");
|
|
9795
9986
|
}
|
|
9796
9987
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
9797
9988
|
if (xdgConfig && xdgConfig.trim()) {
|
|
9798
|
-
return
|
|
9989
|
+
return path21.join(path21.resolve(xdgConfig), "zed");
|
|
9799
9990
|
}
|
|
9800
|
-
return
|
|
9991
|
+
return path21.join(home, ".config", "zed");
|
|
9801
9992
|
}
|
|
9802
9993
|
function baseZedEvent(event) {
|
|
9803
9994
|
return {
|
|
@@ -9861,7 +10052,7 @@ async function parseZedSessionFile(dbPath, options) {
|
|
|
9861
10052
|
const folderRaw = row.folder_paths || "";
|
|
9862
10053
|
const folder = folderRaw.split(/[\n,]/).map((s) => s.trim()).find(Boolean);
|
|
9863
10054
|
const cwd = folder || void 0;
|
|
9864
|
-
const project = cwd ?
|
|
10055
|
+
const project = cwd ? path21.basename(cwd) : row.summary ? row.summary.slice(0, 40) : void 0;
|
|
9865
10056
|
let json;
|
|
9866
10057
|
try {
|
|
9867
10058
|
const bytes = row.data_type === "zstd" ? decompress2(new Uint8Array(row.data)) : new Uint8Array(row.data);
|
|
@@ -10106,7 +10297,7 @@ async function parseZedSessionFile(dbPath, options) {
|
|
|
10106
10297
|
}
|
|
10107
10298
|
return events.filter((event) => matchesBackfillFilters(event, options));
|
|
10108
10299
|
}
|
|
10109
|
-
async function zedBackfillFiles(sourceRoot, home =
|
|
10300
|
+
async function zedBackfillFiles(sourceRoot, home = os10.homedir(), env) {
|
|
10110
10301
|
const { stat: stat14 } = await import("node:fs/promises");
|
|
10111
10302
|
if (sourceRoot) {
|
|
10112
10303
|
if (!sourceRoot.endsWith(".db")) {
|
|
@@ -10136,7 +10327,7 @@ function createZedAdapter() {
|
|
|
10136
10327
|
return zedConfigDir(home, env);
|
|
10137
10328
|
},
|
|
10138
10329
|
installedPath(home, env) {
|
|
10139
|
-
return
|
|
10330
|
+
return path21.join(zedConfigDir(home, env), "vibetime-marker");
|
|
10140
10331
|
},
|
|
10141
10332
|
async isInstalled() {
|
|
10142
10333
|
return false;
|
|
@@ -10595,15 +10786,15 @@ function hookCommandFromGroup(group) {
|
|
|
10595
10786
|
import { randomUUID } from "node:crypto";
|
|
10596
10787
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
10597
10788
|
import { homedir, hostname } from "node:os";
|
|
10598
|
-
import
|
|
10789
|
+
import path22 from "node:path";
|
|
10599
10790
|
function configDir(home = homedir()) {
|
|
10600
|
-
return
|
|
10791
|
+
return path22.join(home, ".vibetime");
|
|
10601
10792
|
}
|
|
10602
10793
|
function configPath(home = homedir()) {
|
|
10603
|
-
return
|
|
10794
|
+
return path22.join(configDir(home), "config.json");
|
|
10604
10795
|
}
|
|
10605
10796
|
function machineIdPath(home = homedir()) {
|
|
10606
|
-
return
|
|
10797
|
+
return path22.join(configDir(home), "machine-id");
|
|
10607
10798
|
}
|
|
10608
10799
|
function readConfig(home = homedir()) {
|
|
10609
10800
|
const file = configPath(home);
|
|
@@ -10652,13 +10843,13 @@ init_fs();
|
|
|
10652
10843
|
// src/lib/logger.ts
|
|
10653
10844
|
import { appendFile, mkdir as mkdir4, rename, stat as stat12 } from "node:fs/promises";
|
|
10654
10845
|
import { homedir as homedir2 } from "node:os";
|
|
10655
|
-
import
|
|
10846
|
+
import path23 from "node:path";
|
|
10656
10847
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
10657
10848
|
function logDir(home = homedir2()) {
|
|
10658
|
-
return
|
|
10849
|
+
return path23.join(home, ".vibetime", "logs");
|
|
10659
10850
|
}
|
|
10660
10851
|
function logPath(home = homedir2(), name = "cli.log") {
|
|
10661
|
-
return
|
|
10852
|
+
return path23.join(logDir(home), name);
|
|
10662
10853
|
}
|
|
10663
10854
|
function serializeError(error) {
|
|
10664
10855
|
if (error instanceof Error) {
|
|
@@ -10833,8 +11024,8 @@ function buildHeaders(token, machine) {
|
|
|
10833
11024
|
...machine?.platform ? { "x-machine-platform": machine.platform } : {}
|
|
10834
11025
|
};
|
|
10835
11026
|
}
|
|
10836
|
-
function joinUrl(base,
|
|
10837
|
-
return new URL(
|
|
11027
|
+
function joinUrl(base, path25) {
|
|
11028
|
+
return new URL(path25, base.endsWith("/") ? base : `${base}/`).toString();
|
|
10838
11029
|
}
|
|
10839
11030
|
async function postRollupBatch(remote, rollups, options = {}) {
|
|
10840
11031
|
const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
|
|
@@ -11753,13 +11944,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
|
|
|
11753
11944
|
});
|
|
11754
11945
|
}
|
|
11755
11946
|
function backfillIncrementalStatePath(home) {
|
|
11756
|
-
return
|
|
11947
|
+
return path24.join(home, ".vibetime", "backfill-state.json");
|
|
11757
11948
|
}
|
|
11758
11949
|
function syncLocalTriggerStatePath(home) {
|
|
11759
|
-
return
|
|
11950
|
+
return path24.join(home, ".vibetime", "sync-local-trigger.json");
|
|
11760
11951
|
}
|
|
11761
11952
|
function syncLocalTriggerLockPath(home) {
|
|
11762
|
-
return
|
|
11953
|
+
return path24.join(home, ".vibetime", "sync-local-trigger.lock");
|
|
11763
11954
|
}
|
|
11764
11955
|
function backfillRemoteKey(baseUrl) {
|
|
11765
11956
|
try {
|
|
@@ -11821,7 +12012,7 @@ async function readBackfillIncrementalStateFile(home, ctx) {
|
|
|
11821
12012
|
}
|
|
11822
12013
|
async function writeBackfillIncrementalStateFile(home, file) {
|
|
11823
12014
|
const statePath = backfillIncrementalStatePath(home);
|
|
11824
|
-
await mkdir5(
|
|
12015
|
+
await mkdir5(path24.dirname(statePath), { recursive: true });
|
|
11825
12016
|
await writeFile4(statePath, `${JSON.stringify(file, null, 2)}
|
|
11826
12017
|
`, "utf8");
|
|
11827
12018
|
}
|
|
@@ -11870,7 +12061,7 @@ async function readSyncLocalTriggerState(statePath) {
|
|
|
11870
12061
|
return nextState;
|
|
11871
12062
|
}
|
|
11872
12063
|
async function writeSyncLocalTriggerState(statePath, state) {
|
|
11873
|
-
await mkdir5(
|
|
12064
|
+
await mkdir5(path24.dirname(statePath), { recursive: true });
|
|
11874
12065
|
await writeFile4(statePath, `${JSON.stringify(state, null, 2)}
|
|
11875
12066
|
`, "utf8");
|
|
11876
12067
|
}
|
|
@@ -11885,12 +12076,12 @@ async function readSyncLocalLock(lockPath) {
|
|
|
11885
12076
|
return { pid: lock.pid, startedAt: lock.startedAt };
|
|
11886
12077
|
}
|
|
11887
12078
|
async function writeSyncLocalLock(lockPath, lock) {
|
|
11888
|
-
await mkdir5(
|
|
12079
|
+
await mkdir5(path24.dirname(lockPath), { recursive: true });
|
|
11889
12080
|
await writeFile4(lockPath, `${JSON.stringify(lock, null, 2)}
|
|
11890
12081
|
`, "utf8");
|
|
11891
12082
|
}
|
|
11892
12083
|
async function acquireSyncLocalLock(lockPath, lock) {
|
|
11893
|
-
await mkdir5(
|
|
12084
|
+
await mkdir5(path24.dirname(lockPath), { recursive: true });
|
|
11894
12085
|
try {
|
|
11895
12086
|
const handle = await open(lockPath, "wx");
|
|
11896
12087
|
try {
|
|
@@ -11970,10 +12161,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
|
|
|
11970
12161
|
if (cliPath.endsWith(".ts")) {
|
|
11971
12162
|
return ["--import", "tsx", cliPath];
|
|
11972
12163
|
}
|
|
11973
|
-
return [
|
|
12164
|
+
return [path24.resolve(path24.dirname(cliPath), "../bin/vibetime.mjs")];
|
|
11974
12165
|
}
|
|
11975
12166
|
function resolveHome3(options, ctx) {
|
|
11976
|
-
return
|
|
12167
|
+
return path24.resolve(stringOption(options.home) || ctx.env.HOME || os11.homedir());
|
|
11977
12168
|
}
|
|
11978
12169
|
function requestedTargets(options) {
|
|
11979
12170
|
const value = options.target || options.targets;
|
package/package.json
CHANGED