@yhong91/vibetime 0.1.49 → 0.1.50

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 +242 -79
  2. package/package.json +1 -1
package/bin/vibetime.mjs CHANGED
@@ -2047,7 +2047,7 @@ function claudeStyleFileMetrics(tool, input) {
2047
2047
  }
2048
2048
 
2049
2049
  // src/lib/constants.ts
2050
- var PACKAGE_VERSION = true ? "0.1.49" : "0.1.1";
2050
+ var PACKAGE_VERSION = true ? "0.1.50" : "0.1.1";
2051
2051
  var DEFAULT_API_URL = "http://121.196.224.82:3001";
2052
2052
  var DEFAULT_BACKFILL_BATCH_SIZE = 50;
2053
2053
  var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
@@ -8094,27 +8094,98 @@ import path17 from "node:path";
8094
8094
  import { access } from "node:fs/promises";
8095
8095
  import os7 from "node:os";
8096
8096
  import path16 from "node:path";
8097
+ function takeQoderDbModelCall(calls, requestId, blockStart) {
8098
+ if (requestId) {
8099
+ const call = calls.byRequestId.get(requestId)?.shift();
8100
+ if (call) {
8101
+ const index = calls.ordered.indexOf(call);
8102
+ if (index !== -1) {
8103
+ calls.ordered.splice(index, 1);
8104
+ }
8105
+ }
8106
+ return call;
8107
+ }
8108
+ if (!blockStart) {
8109
+ return void 0;
8110
+ }
8111
+ return calls.ordered.shift();
8112
+ }
8113
+ function appDataRoot(appDirName, home = os7.homedir()) {
8114
+ if (process.platform === "darwin") {
8115
+ return path16.join(home, "Library", "Application Support", appDirName);
8116
+ }
8117
+ if (process.platform === "win32") {
8118
+ return path16.join(process.env.APPDATA || path16.join(home, "AppData", "Roaming"), appDirName);
8119
+ }
8120
+ return path16.join(home, ".config", appDirName);
8121
+ }
8097
8122
  function qoderLocalDbCandidates(appDirName) {
8098
8123
  const candidates = [];
8099
8124
  const envPath = process.env.QODER_LOCAL_DB_PATH;
8100
8125
  if (envPath) {
8101
8126
  candidates.push(envPath);
8102
8127
  }
8103
- const home = os7.homedir();
8104
- let configRoot;
8105
- if (process.platform === "darwin") {
8106
- configRoot = path16.join(home, "Library", "Application Support", appDirName);
8107
- } else if (process.platform === "win32") {
8108
- configRoot = path16.join(process.env.APPDATA || path16.join(home, "AppData", "Roaming"), appDirName);
8109
- } else {
8110
- configRoot = path16.join(home, ".config", appDirName);
8111
- }
8128
+ const configRoot = appDataRoot(appDirName);
8112
8129
  candidates.push(
8113
8130
  path16.join(configRoot, "SharedClientCache", "cache", "db", "local.db"),
8114
8131
  path16.join(configRoot, "SharedClientCache", "db", "local.db")
8115
8132
  );
8116
8133
  return candidates;
8117
8134
  }
8135
+ async function loadQoderIdeModelCatalog(appDirName, home) {
8136
+ const map = {};
8137
+ try {
8138
+ const { DatabaseSync } = await import("node:sqlite");
8139
+ const db = new DatabaseSync(
8140
+ path16.join(appDataRoot(appDirName, home), "User", "globalStorage", "state.vscdb"),
8141
+ { readOnly: true }
8142
+ );
8143
+ try {
8144
+ const rows = db.prepare(
8145
+ `select key, value from ItemTable where key like 'aicoding.modelConfigs.cache.%' or key = 'aicoding.customModels'`
8146
+ ).all();
8147
+ const customIds = [];
8148
+ for (const row of rows) {
8149
+ const key = stringField(row, "key");
8150
+ const value = stringField(row, "value");
8151
+ if (!key || !value) {
8152
+ continue;
8153
+ }
8154
+ let entries;
8155
+ try {
8156
+ entries = JSON.parse(value);
8157
+ } catch {
8158
+ continue;
8159
+ }
8160
+ for (const entry of entries) {
8161
+ const displayName = stringField(entry, "displayName");
8162
+ if (key === "aicoding.customModels") {
8163
+ const id = stringField(entry, "id");
8164
+ if (id && displayName) {
8165
+ map[`custom:${id}`] = displayName;
8166
+ customIds.push(id);
8167
+ }
8168
+ } else {
8169
+ const name = stringField(entry, "name");
8170
+ if (name && displayName) {
8171
+ map[name] = displayName;
8172
+ }
8173
+ }
8174
+ }
8175
+ }
8176
+ if (customIds.length === 1) {
8177
+ const displayName = map[`custom:${customIds[0]}`];
8178
+ if (displayName) {
8179
+ map.custom_model = displayName;
8180
+ }
8181
+ }
8182
+ } finally {
8183
+ db.close();
8184
+ }
8185
+ } catch {
8186
+ }
8187
+ return map;
8188
+ }
8118
8189
  async function loadQoderDbModelCalls(appDirName, sessionId, modelMap) {
8119
8190
  const calls = { byRequestId: /* @__PURE__ */ new Map(), ordered: [] };
8120
8191
  if (!sessionId) {
@@ -8266,7 +8337,7 @@ async function parseModelNamesFromDynamicTexts(dynamicTextsPath) {
8266
8337
  return {};
8267
8338
  }
8268
8339
  }
8269
- async function loadQoderCnModelNames(configDir2) {
8340
+ async function loadQoderCnModelNames(configDir2, home) {
8270
8341
  const map = await parseModelNamesFromDynamicTexts(path17.join(configDir2, ".auth", "dynamic-texts.json"));
8271
8342
  const siblingConfigDir = configDir2.replace(/\.qoder-cn$/, ".qoder");
8272
8343
  if (siblingConfigDir !== configDir2) {
@@ -8277,6 +8348,14 @@ async function loadQoderCnModelNames(configDir2) {
8277
8348
  }
8278
8349
  }
8279
8350
  }
8351
+ for (const appDirName of ["QoderCN", "Qoder"]) {
8352
+ const ideMap = await loadQoderIdeModelCatalog(appDirName, home);
8353
+ for (const [key, val] of Object.entries(ideMap)) {
8354
+ if (!(key in map)) {
8355
+ map[key] = val;
8356
+ }
8357
+ }
8358
+ }
8280
8359
  return map;
8281
8360
  }
8282
8361
  async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
@@ -8310,7 +8389,8 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
8310
8389
  inputTokens: numberField(data, "input_tokens") || 0,
8311
8390
  outputTokens: numberField(data, "output_tokens") || 0,
8312
8391
  cacheCreationInputTokens: numberField(data, "cache_creation_input_tokens") || 0,
8313
- cacheReadInputTokens: numberField(data, "cache_read_input_tokens") || 0
8392
+ cacheReadInputTokens: numberField(data, "cache_read_input_tokens") || 0,
8393
+ stopReason: stringField(data, "stop_reason") || void 0
8314
8394
  });
8315
8395
  }
8316
8396
  }
@@ -8333,20 +8413,15 @@ async function parseQoderCnSessionFile(filePath, options) {
8333
8413
  let cwd;
8334
8414
  let project = projectContext.project;
8335
8415
  let model;
8336
- const modelMap = await loadQoderCnModelNames(configDir2);
8416
+ const home = path17.resolve(stringOption(options.home) || os8.homedir());
8417
+ const modelMap = await loadQoderCnModelNames(configDir2, home);
8337
8418
  const isSubagentSession = filePath.includes("subagents");
8338
8419
  const segmentModelCalls = await loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap);
8339
8420
  let modelCallIndex = 0;
8340
8421
  let dbModelCalls;
8341
8422
  const nextDbModelCall = async (requestId, blockStart) => {
8342
8423
  dbModelCalls ??= await loadQoderDbModelCalls("QoderCN", sessionId, modelMap);
8343
- if (requestId) {
8344
- return dbModelCalls.byRequestId.get(requestId)?.shift();
8345
- }
8346
- if (!blockStart) {
8347
- return void 0;
8348
- }
8349
- return dbModelCalls.ordered.shift();
8424
+ return takeQoderDbModelCall(dbModelCalls, requestId, blockStart);
8350
8425
  };
8351
8426
  const state = new SessionParserState(filePath, options, (event) => baseQoderCnEvent({ ...event, cwd, project, model }));
8352
8427
  state.sessionId = sessionId;
@@ -8532,6 +8607,20 @@ async function parseQoderCnSessionFile(filePath, options) {
8532
8607
  modelCalls: 1
8533
8608
  };
8534
8609
  model = call.model || model;
8610
+ if (!usage.tokensTotal && !usage.tokensCachedInput) {
8611
+ const dbCall = await nextDbModelCall(requestId, isBlockStart);
8612
+ if (dbCall && (dbCall.inputTokens || dbCall.outputTokens || dbCall.cachedTokens)) {
8613
+ usage = {
8614
+ tokensInput: dbCall.inputTokens || void 0,
8615
+ tokensCachedInput: dbCall.cachedTokens || void 0,
8616
+ tokensCacheReadInput: dbCall.cachedTokens || void 0,
8617
+ tokensOutput: dbCall.outputTokens || void 0,
8618
+ tokensTotal: dbCall.inputTokens + dbCall.outputTokens || void 0,
8619
+ modelCalls: 1
8620
+ };
8621
+ model = dbCall.model || model;
8622
+ }
8623
+ }
8535
8624
  } else if (shouldEmitUsage) {
8536
8625
  const dbCall = await nextDbModelCall(requestId, isBlockStart);
8537
8626
  if (dbCall) {
@@ -8982,6 +9071,7 @@ function createQoderCnAdapter() {
8982
9071
  }
8983
9072
 
8984
9073
  // src/adapters/qoder.ts
9074
+ import { existsSync } from "node:fs";
8985
9075
  import { readdir as readdir8, readFile as readFile11, stat as stat9 } from "node:fs/promises";
8986
9076
  import os9 from "node:os";
8987
9077
  import path18 from "node:path";
@@ -9044,7 +9134,7 @@ async function parseModelNamesFromDynamicTexts2(dynamicTextsPath) {
9044
9134
  return {};
9045
9135
  }
9046
9136
  }
9047
- async function loadQoderModelNames(configDir2) {
9137
+ async function loadQoderModelNames(configDir2, home) {
9048
9138
  const map = await parseModelNamesFromDynamicTexts2(path18.join(configDir2, ".auth", "dynamic-texts.json"));
9049
9139
  const siblingConfigDir = configDir2.replace(/\.qoder$/, ".qoder-cn");
9050
9140
  if (siblingConfigDir !== configDir2) {
@@ -9055,8 +9145,38 @@ async function loadQoderModelNames(configDir2) {
9055
9145
  }
9056
9146
  }
9057
9147
  }
9148
+ if (isQwenworkConfigRoot(configDir2)) {
9149
+ for (const dir of [path18.join(home, ".qoder"), path18.join(home, ".qoder-cn")]) {
9150
+ if (path18.resolve(dir) === path18.resolve(configDir2)) {
9151
+ continue;
9152
+ }
9153
+ const fallbackMap = await parseModelNamesFromDynamicTexts2(path18.join(dir, ".auth", "dynamic-texts.json"));
9154
+ for (const [key, val] of Object.entries(fallbackMap)) {
9155
+ if (!(key in map)) {
9156
+ map[key] = val;
9157
+ }
9158
+ }
9159
+ }
9160
+ }
9161
+ for (const appDirName of ["Qoder", "QoderCN"]) {
9162
+ const ideMap = await loadQoderIdeModelCatalog(appDirName, home);
9163
+ for (const [key, val] of Object.entries(ideMap)) {
9164
+ if (!(key in map)) {
9165
+ map[key] = val;
9166
+ }
9167
+ }
9168
+ }
9058
9169
  return map;
9059
9170
  }
9171
+ function isQwenworkConfigRoot(configDir2) {
9172
+ const name = path18.basename(path18.resolve(configDir2));
9173
+ if (name === ".qwenworkcn" || name === ".qwenwork") {
9174
+ return true;
9175
+ }
9176
+ const override = process.env.QWENWORK_CONFIG_DIR;
9177
+ return Boolean(override && override.trim() && path18.basename(path18.resolve(override)) === name);
9178
+ }
9179
+ var FAILED_SEGMENT_STOP_REASONS = /* @__PURE__ */ new Set(["cancelled", "canceled", "error", "failed", "refusal"]);
9060
9180
  async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
9061
9181
  const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
9062
9182
  const segmentsPath = path18.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
@@ -9088,7 +9208,8 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
9088
9208
  inputTokens: numberField(data, "input_tokens") || 0,
9089
9209
  outputTokens: numberField(data, "output_tokens") || 0,
9090
9210
  cacheCreationInputTokens: numberField(data, "cache_creation_input_tokens") || 0,
9091
- cacheReadInputTokens: numberField(data, "cache_read_input_tokens") || 0
9211
+ cacheReadInputTokens: numberField(data, "cache_read_input_tokens") || 0,
9212
+ stopReason: stringField(data, "stop_reason") || void 0
9092
9213
  });
9093
9214
  }
9094
9215
  }
@@ -9111,20 +9232,16 @@ async function parseQoderSessionFile(filePath, options) {
9111
9232
  let cwd;
9112
9233
  let project = projectContext.project;
9113
9234
  let model;
9114
- const modelMap = await loadQoderModelNames(configDir2);
9235
+ const home = path18.resolve(stringOption(options.home) || os9.homedir());
9236
+ const modelMap = await loadQoderModelNames(configDir2, home);
9237
+ const qwenworkRoot = isQwenworkConfigRoot(configDir2);
9115
9238
  const isSubagentSession = filePath.includes("subagents");
9116
9239
  const segmentModelCalls = await loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap);
9117
9240
  let modelCallIndex = 0;
9118
9241
  let dbModelCalls;
9119
9242
  const nextDbModelCall = async (requestId, blockStart) => {
9120
9243
  dbModelCalls ??= await loadQoderDbModelCalls("Qoder", sessionId, modelMap);
9121
- if (requestId) {
9122
- return dbModelCalls.byRequestId.get(requestId)?.shift();
9123
- }
9124
- if (!blockStart) {
9125
- return void 0;
9126
- }
9127
- return dbModelCalls.ordered.shift();
9244
+ return takeQoderDbModelCall(dbModelCalls, requestId, blockStart);
9128
9245
  };
9129
9246
  const state = new SessionParserState(filePath, options, (event) => baseQoderEvent({ ...event, cwd, project, model }));
9130
9247
  state.sessionId = sessionId;
@@ -9292,39 +9409,28 @@ async function parseQoderSessionFile(filePath, options) {
9292
9409
  seenUsageKeys.add(usageKey);
9293
9410
  }
9294
9411
  let usage;
9412
+ let keepZeroTokenUsage = false;
9295
9413
  if (shouldEmitUsage && modelCallIndex < segmentModelCalls.length) {
9296
9414
  const call = segmentModelCalls[modelCallIndex++];
9297
- const inputTokens = call.inputTokens;
9298
- const cacheCreationInputTokens = call.cacheCreationInputTokens;
9299
- const cacheReadInputTokens = call.cacheReadInputTokens;
9300
- const outputTokens = call.outputTokens;
9301
- const cachedInputTokens = cacheCreationInputTokens + cacheReadInputTokens;
9302
- const totalInputTokens = inputTokens;
9303
- usage = {
9304
- tokensInput: totalInputTokens || void 0,
9305
- tokensCachedInput: cachedInputTokens || void 0,
9306
- tokensCacheCreationInput: cacheCreationInputTokens || void 0,
9307
- tokensCacheReadInput: cacheReadInputTokens || void 0,
9308
- tokensOutput: outputTokens || void 0,
9309
- tokensTotal: totalInputTokens + outputTokens || void 0,
9310
- modelCalls: 1
9311
- };
9415
+ usage = qoderSegmentUsage(call);
9312
9416
  model = call.model || model;
9417
+ if (!usage.tokensTotal && !usage.tokensCachedInput) {
9418
+ const dbCall = await nextDbModelCall(requestId, isBlockStart);
9419
+ if (dbCall && (dbCall.inputTokens || dbCall.outputTokens || dbCall.cachedTokens)) {
9420
+ usage = qoderDbUsage(dbCall);
9421
+ model = dbCall.model || model;
9422
+ } else if (qwenworkRoot && (!call.stopReason || !FAILED_SEGMENT_STOP_REASONS.has(call.stopReason))) {
9423
+ keepZeroTokenUsage = true;
9424
+ }
9425
+ }
9313
9426
  } else if (shouldEmitUsage) {
9314
9427
  const dbCall = await nextDbModelCall(requestId, isBlockStart);
9315
9428
  if (dbCall) {
9316
- usage = {
9317
- tokensInput: dbCall.inputTokens || void 0,
9318
- tokensCachedInput: dbCall.cachedTokens || void 0,
9319
- tokensCacheReadInput: dbCall.cachedTokens || void 0,
9320
- tokensOutput: dbCall.outputTokens || void 0,
9321
- tokensTotal: dbCall.inputTokens + dbCall.outputTokens || void 0,
9322
- modelCalls: 1
9323
- };
9429
+ usage = qoderDbUsage(dbCall);
9324
9430
  model = dbCall.model || model;
9325
9431
  }
9326
9432
  }
9327
- if (usage && (usage.tokensTotal || usage.tokensCachedInput)) {
9433
+ if (usage && (usage.tokensTotal || usage.tokensCachedInput || keepZeroTokenUsage)) {
9328
9434
  const speed = stringField(objectField(message, "usage"), "speed");
9329
9435
  const usageModel = speed === "fast" && model ? `${model}-fast` : model;
9330
9436
  push(baseQoderEvent({
@@ -9451,6 +9557,28 @@ async function parseQoderSessionFile(filePath, options) {
9451
9557
  }
9452
9558
  return validEvents;
9453
9559
  }
9560
+ function qoderSegmentUsage(call) {
9561
+ const cachedInputTokens = call.cacheCreationInputTokens + call.cacheReadInputTokens;
9562
+ return {
9563
+ tokensInput: call.inputTokens || void 0,
9564
+ tokensCachedInput: cachedInputTokens || void 0,
9565
+ tokensCacheCreationInput: call.cacheCreationInputTokens || void 0,
9566
+ tokensCacheReadInput: call.cacheReadInputTokens || void 0,
9567
+ tokensOutput: call.outputTokens || void 0,
9568
+ tokensTotal: call.inputTokens + call.outputTokens || void 0,
9569
+ modelCalls: 1
9570
+ };
9571
+ }
9572
+ function qoderDbUsage(dbCall) {
9573
+ return {
9574
+ tokensInput: dbCall.inputTokens || void 0,
9575
+ tokensCachedInput: dbCall.cachedTokens || void 0,
9576
+ tokensCacheReadInput: dbCall.cachedTokens || void 0,
9577
+ tokensOutput: dbCall.outputTokens || void 0,
9578
+ tokensTotal: dbCall.inputTokens + dbCall.outputTokens || void 0,
9579
+ modelCalls: 1
9580
+ };
9581
+ }
9454
9582
  function baseQoderEvent(event) {
9455
9583
  return {
9456
9584
  schemaVersion: AGENT_TIME_SCHEMA_VERSION,
@@ -9534,12 +9662,20 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
9534
9662
  const isSubagent = filePath.includes(`${path18.sep}subagents${path18.sep}`);
9535
9663
  const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
9536
9664
  let cwds = [];
9665
+ const workspaceDirs = [];
9537
9666
  for (const line of lines) {
9538
9667
  const raw = parseJsonLine(line);
9539
9668
  const cwd = raw ? stringField(raw, "cwd") : void 0;
9540
9669
  if (cwd && path18.isAbsolute(cwd)) {
9541
9670
  cwds.push(cwd);
9542
9671
  }
9672
+ if (raw && stringField(raw, "type") === "workspace-directories") {
9673
+ for (const dir of arrayField5(raw, "directories")) {
9674
+ if (typeof dir === "string" && path18.isAbsolute(dir)) {
9675
+ workspaceDirs.push(dir);
9676
+ }
9677
+ }
9678
+ }
9543
9679
  }
9544
9680
  if (isSubagent) {
9545
9681
  if (inherited?.cwd && path18.isAbsolute(inherited.cwd)) {
@@ -9555,6 +9691,13 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
9555
9691
  if (cwd && path18.isAbsolute(cwd)) {
9556
9692
  parentCwds.push(cwd);
9557
9693
  }
9694
+ if (workspaceDirs.length === 0 && raw && stringField(raw, "type") === "workspace-directories") {
9695
+ for (const dir of arrayField5(raw, "directories")) {
9696
+ if (typeof dir === "string" && path18.isAbsolute(dir)) {
9697
+ workspaceDirs.push(dir);
9698
+ }
9699
+ }
9700
+ }
9558
9701
  }
9559
9702
  if (parentCwds.length > 0) {
9560
9703
  cwds = parentCwds;
@@ -9563,6 +9706,12 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
9563
9706
  }
9564
9707
  }
9565
9708
  }
9709
+ if (cwds.length > 0 && cwds.every((cwd) => pathInsideDir(cwd, configDir2))) {
9710
+ const external = workspaceDirs.filter((dir) => !pathInsideDir(dir, configDir2));
9711
+ if (external.length > 0) {
9712
+ cwds = external;
9713
+ }
9714
+ }
9566
9715
  const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
9567
9716
  const project = inherited?.project || (cwds.length > 0 ? path18.basename(cwds[0]) : root ? path18.basename(root) : await qoderProjectFromFilePath(filePath, options));
9568
9717
  return {
@@ -9570,6 +9719,11 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
9570
9719
  workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
9571
9720
  };
9572
9721
  }
9722
+ function pathInsideDir(candidate, dir) {
9723
+ const resolvedDir = path18.resolve(dir);
9724
+ const resolved = path18.resolve(candidate);
9725
+ return resolved === resolvedDir || resolved.startsWith(`${resolvedDir}${path18.sep}`);
9726
+ }
9573
9727
  async function gitRootFromCwds3(cwds) {
9574
9728
  const seen = /* @__PURE__ */ new Set();
9575
9729
  for (const cwd of cwds) {
@@ -9594,7 +9748,7 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
9594
9748
  for (const cwd of cwds) {
9595
9749
  let current = path18.resolve(cwd);
9596
9750
  while (true) {
9597
- if (encodeQoderProjectPath(current) === projectDir) {
9751
+ if (qoderEncodedVariants(current).includes(projectDir)) {
9598
9752
  return current;
9599
9753
  }
9600
9754
  const parent = path18.dirname(current);
@@ -9606,21 +9760,23 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
9606
9760
  }
9607
9761
  return void 0;
9608
9762
  }
9609
- function encodeQoderProjectPath(value) {
9610
- return path18.resolve(value).split(path18.sep).join("-").replaceAll("_", "-");
9611
- }
9612
9763
  function rawQoderProjectPath(value) {
9613
9764
  return path18.resolve(value).split(path18.sep).join("-");
9614
9765
  }
9615
9766
  function qoderEncodedVariants(value) {
9616
9767
  const raw = rawQoderProjectPath(value);
9617
- const normalized = raw.replaceAll("_", "-");
9618
- return raw === normalized ? [raw] : [raw, normalized];
9768
+ const variants = /* @__PURE__ */ new Set([
9769
+ raw,
9770
+ raw.replaceAll("_", "-"),
9771
+ raw.replaceAll(".", "-"),
9772
+ raw.replaceAll("_", "-").replaceAll(".", "-")
9773
+ ]);
9774
+ return [...variants];
9619
9775
  }
9620
9776
  function qoderEncodedProjectSuffix(projectDir, home) {
9621
9777
  for (const prefix of qoderEncodedVariants(home).map((value) => `${value}-`)) {
9622
9778
  if (projectDir.startsWith(prefix)) {
9623
- return projectDir.slice(prefix.length) || void 0;
9779
+ return projectDir.slice(prefix.length).replace(/^-+/, "") || void 0;
9624
9780
  }
9625
9781
  }
9626
9782
  return void 0;
@@ -9705,6 +9861,16 @@ function qoderConfigDir(home, env) {
9705
9861
  }
9706
9862
  return path18.join(home, ".qoder");
9707
9863
  }
9864
+ function qwenworkConfigDir(home, env) {
9865
+ const override = env?.QWENWORK_CONFIG_DIR;
9866
+ if (override && override.trim()) {
9867
+ return path18.resolve(override);
9868
+ }
9869
+ return path18.join(home, ".qwenworkcn");
9870
+ }
9871
+ function qoderConfigDirs(home, env) {
9872
+ return [...new Set([qoderConfigDir(home, env), qwenworkConfigDir(home, env)].map((dir) => path18.resolve(dir)))];
9873
+ }
9708
9874
  function createQoderAdapter() {
9709
9875
  return {
9710
9876
  id: "qoder",
@@ -9724,19 +9890,22 @@ function createQoderAdapter() {
9724
9890
  );
9725
9891
  },
9726
9892
  installEntries(home, env) {
9727
- return [{
9893
+ const [primary, ...variants] = qoderConfigDirs(home, env);
9894
+ const targets = [primary, ...variants.filter((dir) => existsSync(dir))];
9895
+ return targets.map((base) => ({
9728
9896
  kind: "hooks-json",
9729
- path: path18.join(qoderConfigDir(home, env), "settings.json"),
9897
+ path: path18.join(base, "settings.json"),
9730
9898
  content: hookConfig7()
9731
- }];
9899
+ }));
9732
9900
  },
9733
9901
  sourcePaths(home, env) {
9902
+ const paths = qoderConfigDirs(home, env).map((base2) => path18.join(base2, "projects"));
9734
9903
  const base = qoderConfigDir(home, env);
9735
- return [
9736
- path18.join(base, "projects"),
9904
+ paths.push(
9737
9905
  path18.join(base, ".qoder.json"),
9738
9906
  path18.join(home, ".qoder.json")
9739
- ];
9907
+ );
9908
+ return paths;
9740
9909
  },
9741
9910
  parseSessionFile: parseQoderSessionFile
9742
9911
  };
@@ -11171,13 +11340,7 @@ function createZedAdapter() {
11171
11340
  }
11172
11341
 
11173
11342
  // src/lib/pricing.ts
11174
- function estimateEventCostUsd(event) {
11175
- if (event.type !== "model.usage") {
11176
- return 0;
11177
- }
11178
- if (typeof event.metrics?.costUsd === "number" && event.metrics.costUsd > 0) {
11179
- return event.metrics.costUsd;
11180
- }
11343
+ function estimateEventCostUsd(_event) {
11181
11344
  return 0;
11182
11345
  }
11183
11346
 
@@ -11640,7 +11803,7 @@ function hookCommandFromGroup(group) {
11640
11803
 
11641
11804
  // src/lib/config.ts
11642
11805
  import { randomUUID } from "node:crypto";
11643
- import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
11806
+ import { existsSync as existsSync2, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
11644
11807
  import { homedir, hostname } from "node:os";
11645
11808
  import path22 from "node:path";
11646
11809
  function configDir(home = homedir()) {
@@ -11654,7 +11817,7 @@ function machineIdPath(home = homedir()) {
11654
11817
  }
11655
11818
  function readConfig(home = homedir()) {
11656
11819
  const file = configPath(home);
11657
- if (!existsSync(file)) {
11820
+ if (!existsSync2(file)) {
11658
11821
  return {};
11659
11822
  }
11660
11823
  try {
@@ -11666,7 +11829,7 @@ function readConfig(home = homedir()) {
11666
11829
  }
11667
11830
  function writeConfig(config, home = homedir()) {
11668
11831
  const dir = configDir(home);
11669
- if (!existsSync(dir)) {
11832
+ if (!existsSync2(dir)) {
11670
11833
  mkdirSync(dir, { recursive: true });
11671
11834
  }
11672
11835
  writeFileSync(configPath(home), `${JSON.stringify(config, null, 2)}
@@ -11674,7 +11837,7 @@ function writeConfig(config, home = homedir()) {
11674
11837
  }
11675
11838
  function ensureLocalMachineId(home = homedir()) {
11676
11839
  const file = machineIdPath(home);
11677
- if (existsSync(file)) {
11840
+ if (existsSync2(file)) {
11678
11841
  const value = readFileSync(file, "utf8").trim();
11679
11842
  if (value.length > 0) {
11680
11843
  return value;
@@ -11682,7 +11845,7 @@ function ensureLocalMachineId(home = homedir()) {
11682
11845
  }
11683
11846
  const id = randomUUID();
11684
11847
  const dir = configDir(home);
11685
- if (!existsSync(dir)) {
11848
+ if (!existsSync2(dir)) {
11686
11849
  mkdirSync(dir, { recursive: true });
11687
11850
  }
11688
11851
  writeFileSync(file, `${id}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yhong91/vibetime",
3
3
  "type": "module",
4
- "version": "0.1.49",
4
+ "version": "0.1.50",
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": {