@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.
Files changed (2) hide show
  1. package/bin/vibetime.mjs +322 -131
  2. 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 os10 from "node:os";
889
- import path23 from "node:path";
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.30" : "0.1.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-cn.ts
7384
- import { readdir as readdir7, readFile as readFile10, stat as stat8 } from "node:fs/promises";
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(path16.sep);
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(path16.sep);
7399
- mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path16.sep);
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 = path16.basename(filename, ".jsonl");
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(path16.sep);
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 = path16.join(configDir2, ".auth", "dynamic-texts.json");
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 = path16.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
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(path16.join(segmentsPath, file), "utf8");
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 ? path16.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
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(`${path16.sep}subagents${path16.sep}`);
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 && path16.isAbsolute(cwd)) {
8123
+ if (cwd && path17.isAbsolute(cwd)) {
7966
8124
  cwds.push(cwd);
7967
8125
  }
7968
8126
  }
7969
8127
  if (isSubagent) {
7970
- if (inherited?.cwd && path16.isAbsolute(inherited.cwd)) {
8128
+ if (inherited?.cwd && path17.isAbsolute(inherited.cwd)) {
7971
8129
  cwds = [inherited.cwd];
7972
8130
  } else {
7973
- const parentSessionPath = path16.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
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 && path16.isAbsolute(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 ? path16.basename(cwds[0]) : root ? path16.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
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 = path16.resolve(cwd);
8159
+ let current = path17.resolve(cwd);
8002
8160
  while (!seen.has(current)) {
8003
8161
  seen.add(current);
8004
8162
  try {
8005
- await stat8(path16.join(current, ".git"));
8163
+ await stat8(path17.join(current, ".git"));
8006
8164
  return current;
8007
8165
  } catch {
8008
8166
  }
8009
- const parent = path16.dirname(current);
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 = path16.resolve(cwd);
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 = path16.dirname(current);
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 path16.resolve(value).split(path16.sep).join("-").replace(/_/g, "-");
8193
+ return path17.resolve(value).split(path17.sep).join("-").replace(/_/g, "-");
8036
8194
  }
8037
8195
  async function qoderCnProjectFromFilePath(filePath, options) {
8038
- const projectDir = path16.basename(path16.dirname(filePath));
8039
- const home = options ? path16.resolve(stringOption(options.home) || os7.homedir()) : os7.homedir();
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 path16.basename(resolved);
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 = path16.join(current, entry.name);
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 path16.resolve(override);
8270
+ return path17.resolve(override);
8113
8271
  }
8114
- return path16.join(home, ".qoder-cn");
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 path16.join(qoderCnConfigDir(home, env), "settings.json");
8284
+ return path17.join(qoderCnConfigDir(home, env), "settings.json");
8127
8285
  },
8128
8286
  async isInstalled(home, env) {
8129
8287
  return isHooksJsonInstalled(
8130
- path16.join(qoderCnConfigDir(home, env), "settings.json"),
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: path16.join(qoderCnConfigDir(home, env), "settings.json"),
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
- path16.join(base, "projects"),
8145
- path16.join(base, ".qoder.json"),
8146
- path16.join(home, ".qoder.json")
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 os8 from "node:os";
8156
- import path17 from "node:path";
8313
+ import os9 from "node:os";
8314
+ import path18 from "node:path";
8157
8315
  function parseQoderPaths(filePath) {
8158
- const parts = filePath.split(path17.sep);
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(path17.sep);
8169
- mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path17.sep);
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 = path17.basename(filename, ".jsonl");
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(path17.sep);
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 = path17.join(configDir2, ".auth", "dynamic-texts.json");
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 = path17.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
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(path17.join(segmentsPath, file), "utf8");
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 ? path17.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
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(`${path17.sep}subagents${path17.sep}`);
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 && path17.isAbsolute(cwd)) {
8892
+ if (cwd && path18.isAbsolute(cwd)) {
8702
8893
  cwds.push(cwd);
8703
8894
  }
8704
8895
  }
8705
8896
  if (isSubagent) {
8706
- if (inherited?.cwd && path17.isAbsolute(inherited.cwd)) {
8897
+ if (inherited?.cwd && path18.isAbsolute(inherited.cwd)) {
8707
8898
  cwds = [inherited.cwd];
8708
8899
  } else {
8709
- const parentSessionPath = path17.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
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 && path17.isAbsolute(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 ? path17.basename(cwds[0]) : root ? path17.basename(root) : await qoderProjectFromFilePath(filePath, options));
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 = path17.resolve(cwd);
8928
+ let current = path18.resolve(cwd);
8738
8929
  while (!seen.has(current)) {
8739
8930
  seen.add(current);
8740
8931
  try {
8741
- await stat9(path17.join(current, ".git"));
8932
+ await stat9(path18.join(current, ".git"));
8742
8933
  return current;
8743
8934
  } catch {
8744
8935
  }
8745
- const parent = path17.dirname(current);
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 = path17.resolve(cwd);
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 = path17.dirname(current);
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 path17.resolve(value).split(path17.sep).join("-").replace(/_/g, "-");
8962
+ return path18.resolve(value).split(path18.sep).join("-").replace(/_/g, "-");
8772
8963
  }
8773
8964
  function rawQoderProjectPath(value) {
8774
- return path17.resolve(value).split(path17.sep).join("-");
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 = path17.basename(path17.dirname(filePath));
8791
- const home = options ? path17.resolve(stringOption(options.home) || os8.homedir()) : os8.homedir();
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 path17.basename(resolved);
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 = path17.join(current, entry.name);
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 path17.resolve(override);
9056
+ return path18.resolve(override);
8866
9057
  }
8867
- return path17.join(home, ".qoder");
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 path17.join(qoderConfigDir(home, env), "settings.json");
9070
+ return path18.join(qoderConfigDir(home, env), "settings.json");
8880
9071
  },
8881
9072
  async isInstalled(home, env) {
8882
9073
  return isHooksJsonInstalled(
8883
- path17.join(qoderConfigDir(home, env), "settings.json"),
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: path17.join(qoderConfigDir(home, env), "settings.json"),
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
- path17.join(base, "projects"),
8898
- path17.join(base, ".qoder.json"),
8899
- path17.join(home, ".qoder.json")
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 path18 from "node:path";
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 path18.resolve(override, override.endsWith("projects") ? "" : "projects");
9131
+ return path19.resolve(override, override.endsWith("projects") ? "" : "projects");
8941
9132
  }
8942
- return path18.join(home, ".workbuddy", "projects");
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 path18.basename(cwd) || fallback;
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") || path18.basename(filePath, ".jsonl");
9052
- const fallbackProject = path18.basename(path18.dirname(filePath));
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 = path18.join(base, project.name);
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 = path18.join(projectDir, entry.name);
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 path19 from "node:path";
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 path19.resolve(override, override.endsWith("cli") ? "" : "cli");
9467
+ return path20.resolve(override, override.endsWith("cli") ? "" : "cli");
9277
9468
  }
9278
- return path19.join(home, ".zcode", "cli");
9469
+ return path20.join(home, ".zcode", "cli");
9279
9470
  }
9280
9471
  function zcodeDbPath(home, env) {
9281
- return path19.join(zcodeCliDir(home, env), "db", "db.sqlite");
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 ? path19.basename(directory) || "zcode" : "zcode";
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 = path19.resolve(filePath);
9689
+ let candidate = path20.resolve(filePath);
9499
9690
  let configPath2 = "";
9500
9691
  for (let i = 0; i < 12; i++) {
9501
- const probe = path19.join(candidate, ".zcode", "v2", "config.json");
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 = path19.dirname(candidate);
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 : path19.join(candidate, "db", "db.sqlite");
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 os9 from "node:os";
9758
- import path20 from "node:path";
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(path20.join(home, "Library", "Application Support", "Zed", "threads", "threads.db"));
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(path20.join(path20.resolve(appdata), "Zed", "threads", "threads.db"));
9958
+ candidates.push(path21.join(path21.resolve(appdata), "Zed", "threads", "threads.db"));
9768
9959
  }
9769
- candidates.push(path20.join(home, "AppData", "Roaming", "Zed", "threads", "threads.db"));
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(path20.join(path20.resolve(xdgData), "zed", "threads", "threads.db"));
9964
+ candidates.push(path21.join(path21.resolve(xdgData), "zed", "threads", "threads.db"));
9774
9965
  }
9775
- candidates.push(path20.join(home, ".local", "share", "zed", "threads", "threads.db"));
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(path20.join(path20.resolve(xdgConfig), "zed", "threads", "threads.db"));
9969
+ candidates.push(path21.join(path21.resolve(xdgConfig), "zed", "threads", "threads.db"));
9779
9970
  }
9780
- candidates.push(path20.join(home, ".config", "zed", "threads", "threads.db"));
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 path20.join(home, "Library", "Application Support", "Zed");
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 path20.join(path20.resolve(appdata), "Zed");
9983
+ return path21.join(path21.resolve(appdata), "Zed");
9793
9984
  }
9794
- return path20.join(home, "AppData", "Roaming", "Zed");
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 path20.join(path20.resolve(xdgConfig), "zed");
9989
+ return path21.join(path21.resolve(xdgConfig), "zed");
9799
9990
  }
9800
- return path20.join(home, ".config", "zed");
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 ? path20.basename(cwd) : row.summary ? row.summary.slice(0, 40) : void 0;
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 = os9.homedir(), env) {
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 path20.join(zedConfigDir(home, env), "vibetime-marker");
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 path21 from "node:path";
10789
+ import path22 from "node:path";
10599
10790
  function configDir(home = homedir()) {
10600
- return path21.join(home, ".vibetime");
10791
+ return path22.join(home, ".vibetime");
10601
10792
  }
10602
10793
  function configPath(home = homedir()) {
10603
- return path21.join(configDir(home), "config.json");
10794
+ return path22.join(configDir(home), "config.json");
10604
10795
  }
10605
10796
  function machineIdPath(home = homedir()) {
10606
- return path21.join(configDir(home), "machine-id");
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 path22 from "node:path";
10846
+ import path23 from "node:path";
10656
10847
  var MAX_BYTES = 1 * 1024 * 1024;
10657
10848
  function logDir(home = homedir2()) {
10658
- return path22.join(home, ".vibetime", "logs");
10849
+ return path23.join(home, ".vibetime", "logs");
10659
10850
  }
10660
10851
  function logPath(home = homedir2(), name = "cli.log") {
10661
- return path22.join(logDir(home), name);
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, path24) {
10837
- return new URL(path24, base.endsWith("/") ? base : `${base}/`).toString();
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 path23.join(home, ".vibetime", "backfill-state.json");
11947
+ return path24.join(home, ".vibetime", "backfill-state.json");
11757
11948
  }
11758
11949
  function syncLocalTriggerStatePath(home) {
11759
- return path23.join(home, ".vibetime", "sync-local-trigger.json");
11950
+ return path24.join(home, ".vibetime", "sync-local-trigger.json");
11760
11951
  }
11761
11952
  function syncLocalTriggerLockPath(home) {
11762
- return path23.join(home, ".vibetime", "sync-local-trigger.lock");
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(path23.dirname(statePath), { recursive: true });
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(path23.dirname(statePath), { recursive: true });
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(path23.dirname(lockPath), { recursive: true });
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(path23.dirname(lockPath), { recursive: true });
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 [path23.resolve(path23.dirname(cliPath), "../bin/vibetime.mjs")];
12164
+ return [path24.resolve(path24.dirname(cliPath), "../bin/vibetime.mjs")];
11974
12165
  }
11975
12166
  function resolveHome3(options, ctx) {
11976
- return path23.resolve(stringOption(options.home) || ctx.env.HOME || os10.homedir());
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yhong91/vibetime",
3
3
  "type": "module",
4
- "version": "0.1.30",
4
+ "version": "0.1.32",
5
5
  "description": "vibetime CLI — install AI-agent hooks (Claude Code, Codex, OpenCode, Pi) and report activity to vibetime.",
6
6
  "license": "MIT",
7
7
  "publishConfig": {