mobbdev 1.2.53 → 1.2.55

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/dist/index.mjs CHANGED
@@ -9918,7 +9918,7 @@ var _contextLogger = null;
9918
9918
  var createContextLogger = async () => {
9919
9919
  if (_contextLogger) return _contextLogger;
9920
9920
  try {
9921
- let logger2;
9921
+ let logger3;
9922
9922
  try {
9923
9923
  let module;
9924
9924
  try {
@@ -9928,15 +9928,15 @@ var createContextLogger = async () => {
9928
9928
  const sourcePath = "../../../../../tscommon/backend/src/utils/logger";
9929
9929
  module = await import(sourcePath);
9930
9930
  }
9931
- logger2 = module.logger;
9931
+ logger3 = module.logger;
9932
9932
  } catch {
9933
9933
  }
9934
- if (logger2) {
9934
+ if (logger3) {
9935
9935
  _contextLogger = {
9936
- info: (message, data) => data ? logger2.info(data, message) : logger2.info(message),
9937
- warn: (message, data) => data ? logger2.warn(data, message) : logger2.warn(message),
9938
- debug: (message, data) => data ? logger2.debug(data, message) : logger2.debug(message),
9939
- error: (message, data) => data ? logger2.error(data, message) : logger2.error(message)
9936
+ info: (message, data) => data ? logger3.info(data, message) : logger3.info(message),
9937
+ warn: (message, data) => data ? logger3.warn(data, message) : logger3.warn(message),
9938
+ debug: (message, data) => data ? logger3.debug(data, message) : logger3.debug(message),
9939
+ error: (message, data) => data ? logger3.error(data, message) : logger3.error(message)
9940
9940
  };
9941
9941
  return _contextLogger;
9942
9942
  }
@@ -9952,20 +9952,20 @@ var createContextLogger = async () => {
9952
9952
  };
9953
9953
  var contextLogger = {
9954
9954
  info: async (message, data) => {
9955
- const logger2 = await createContextLogger();
9956
- return logger2.info(message, data);
9955
+ const logger3 = await createContextLogger();
9956
+ return logger3.info(message, data);
9957
9957
  },
9958
9958
  debug: async (message, data) => {
9959
- const logger2 = await createContextLogger();
9960
- return logger2.debug(message, data);
9959
+ const logger3 = await createContextLogger();
9960
+ return logger3.debug(message, data);
9961
9961
  },
9962
9962
  warn: async (message, data) => {
9963
- const logger2 = await createContextLogger();
9964
- return logger2.warn(message, data);
9963
+ const logger3 = await createContextLogger();
9964
+ return logger3.warn(message, data);
9965
9965
  },
9966
9966
  error: async (message, data) => {
9967
- const logger2 = await createContextLogger();
9968
- return logger2.error(message, data);
9967
+ const logger3 = await createContextLogger();
9968
+ return logger3.error(message, data);
9969
9969
  }
9970
9970
  };
9971
9971
 
@@ -11313,12 +11313,12 @@ var defaultLogger = {
11313
11313
  }
11314
11314
  }
11315
11315
  };
11316
- function createGitWithLogging(dirName, logger2 = defaultLogger) {
11316
+ function createGitWithLogging(dirName, logger3 = defaultLogger) {
11317
11317
  return simpleGit2(dirName, {
11318
11318
  maxConcurrentProcesses: 6
11319
11319
  }).outputHandler((bin, stdout2, stderr2) => {
11320
11320
  const callID = Math.random();
11321
- logger2.info({ callID, bin }, "Start git CLI call");
11321
+ logger3.info({ callID, bin }, "Start git CLI call");
11322
11322
  let errChunks = [];
11323
11323
  let outChunks = [];
11324
11324
  let isStdoutDone = false;
@@ -11339,25 +11339,25 @@ function createGitWithLogging(dirName, logger2 = defaultLogger) {
11339
11339
  err: `${errChunks.join("").slice(0, 200)}...`,
11340
11340
  out: `${outChunks.join("").slice(0, 200)}...`
11341
11341
  };
11342
- logger2.info(logObj, "git log output");
11342
+ logger3.info(logObj, "git log output");
11343
11343
  stderr2.removeListener("data", onStderrData);
11344
11344
  stdout2.removeListener("data", onStdoutData);
11345
11345
  errChunks = [];
11346
11346
  outChunks = [];
11347
11347
  }
11348
- function markDone(stream) {
11349
- if (stream === "stderr") isStderrDone = true;
11348
+ function markDone(stream3) {
11349
+ if (stream3 === "stderr") isStderrDone = true;
11350
11350
  else isStdoutDone = true;
11351
11351
  finalizeAndCleanup();
11352
11352
  }
11353
11353
  stderr2.on("close", () => markDone("stderr"));
11354
11354
  stdout2.on("close", () => markDone("stdout"));
11355
11355
  stderr2.on("error", (error) => {
11356
- logger2.info({ callID, error: String(error) }, "git stderr stream error");
11356
+ logger3.info({ callID, error: String(error) }, "git stderr stream error");
11357
11357
  markDone("stderr");
11358
11358
  });
11359
11359
  stdout2.on("error", (error) => {
11360
- logger2.info({ callID, error: String(error) }, "git stdout stream error");
11360
+ logger3.info({ callID, error: String(error) }, "git stdout stream error");
11361
11361
  markDone("stdout");
11362
11362
  });
11363
11363
  });
@@ -13014,9 +13014,9 @@ async function uploadFile({
13014
13014
  url,
13015
13015
  uploadKey,
13016
13016
  uploadFields,
13017
- logger: logger2
13017
+ logger: logger3
13018
13018
  }) {
13019
- const logInfo2 = logger2 || ((_message, _data) => {
13019
+ const logInfo2 = logger3 || ((_message, _data) => {
13020
13020
  });
13021
13021
  logInfo2(`FileUpload: upload file start ${url}`);
13022
13022
  logInfo2(`FileUpload: upload fields`, uploadFields);
@@ -13059,22 +13059,27 @@ import os from "os";
13059
13059
 
13060
13060
  // src/utils/ConfigStoreService.ts
13061
13061
  import Configstore from "configstore";
13062
- function createConfigStore(defaultValues = { apiToken: "" }) {
13062
+ function getSanitizedDomain() {
13063
13063
  const API_URL2 = process.env["API_URL"] || DEFAULT_API_URL;
13064
13064
  let domain = "";
13065
13065
  try {
13066
13066
  const url = new URL(API_URL2);
13067
13067
  domain = url.hostname;
13068
- } catch (e) {
13068
+ } catch {
13069
13069
  domain = API_URL2.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/:\d+$/, "");
13070
13070
  }
13071
- const sanitizedDomain = domain.replace(/\./g, "_");
13072
- return new Configstore(`mobbdev-${sanitizedDomain}`, defaultValues);
13071
+ return domain.replace(/\./g, "_");
13072
+ }
13073
+ function createConfigStore(defaultValues = { apiToken: "" }) {
13074
+ return new Configstore(`mobbdev-${getSanitizedDomain()}`, defaultValues);
13073
13075
  }
13074
- function getConfigStore() {
13075
- return createConfigStore();
13076
+ function createSessionConfigStore(sessionId) {
13077
+ return new Configstore(`mobbdev-${getSanitizedDomain()}-session-${sessionId}`);
13076
13078
  }
13077
- var configStore = getConfigStore();
13079
+ function getSessionFilePrefix() {
13080
+ return `mobbdev-${getSanitizedDomain()}-session-`;
13081
+ }
13082
+ var configStore = createConfigStore();
13078
13083
 
13079
13084
  // src/utils/computerName.ts
13080
13085
  var STABLE_COMPUTER_NAME_CONFIG_KEY = "stableComputerName";
@@ -13305,6 +13310,10 @@ async function sanitizeDataWithCounts(obj) {
13305
13310
  const sanitizedData = await sanitizeRecursive(obj);
13306
13311
  return { sanitizedData, counts };
13307
13312
  }
13313
+ async function sanitizeData(obj) {
13314
+ const result = await sanitizeDataWithCounts(obj);
13315
+ return result.sanitizedData;
13316
+ }
13308
13317
 
13309
13318
  // src/args/commands/upload_ai_blame.ts
13310
13319
  var defaultLogger2 = {
@@ -13358,9 +13367,9 @@ var PromptItemZ = z27.object({
13358
13367
  }).optional()
13359
13368
  });
13360
13369
  var PromptItemArrayZ = z27.array(PromptItemZ);
13361
- async function getRepositoryUrl() {
13370
+ async function getRepositoryUrl(workingDir) {
13362
13371
  try {
13363
- const gitService = new GitService(process.cwd());
13372
+ const gitService = new GitService(workingDir ?? process.cwd());
13364
13373
  const isRepo = await gitService.isGitRepository();
13365
13374
  if (!isRepo) {
13366
13375
  return null;
@@ -13421,6 +13430,7 @@ function uploadAiBlameBuilder(args) {
13421
13430
  }).strict();
13422
13431
  }
13423
13432
  async function uploadAiBlameHandlerFromExtension(args) {
13433
+ const shouldSanitize = args.sanitize ?? true;
13424
13434
  const uploadArgs = {
13425
13435
  prompt: [],
13426
13436
  inference: [],
@@ -13434,28 +13444,50 @@ async function uploadAiBlameHandlerFromExtension(args) {
13434
13444
  let inferenceCounts;
13435
13445
  let promptsUUID;
13436
13446
  let inferenceUUID;
13447
+ const zeroCounts = {
13448
+ detections: { total: 0, high: 0, medium: 0, low: 0 }
13449
+ };
13450
+ let sanitizationDurationMs;
13437
13451
  await withFile(async (promptFile) => {
13438
- const promptsResult = await sanitizeDataWithCounts(args.prompts);
13439
- promptsCounts = promptsResult.counts;
13440
13452
  promptsUUID = path7.basename(promptFile.path, path7.extname(promptFile.path));
13441
- await fsPromises2.writeFile(
13442
- promptFile.path,
13443
- JSON.stringify(promptsResult.sanitizedData, null, 2),
13444
- "utf-8"
13445
- );
13453
+ if (shouldSanitize) {
13454
+ const sanitizeStart = performance.now();
13455
+ const promptsResult = await sanitizeDataWithCounts(args.prompts);
13456
+ promptsCounts = promptsResult.counts;
13457
+ await fsPromises2.writeFile(
13458
+ promptFile.path,
13459
+ JSON.stringify(promptsResult.sanitizedData, null, 2),
13460
+ "utf-8"
13461
+ );
13462
+ sanitizationDurationMs = performance.now() - sanitizeStart;
13463
+ } else {
13464
+ promptsCounts = zeroCounts;
13465
+ await fsPromises2.writeFile(
13466
+ promptFile.path,
13467
+ JSON.stringify(args.prompts, null, 2),
13468
+ "utf-8"
13469
+ );
13470
+ }
13446
13471
  uploadArgs.prompt.push(promptFile.path);
13447
13472
  await withFile(async (inferenceFile) => {
13448
- const inferenceResult = await sanitizeDataWithCounts(args.inference);
13449
- inferenceCounts = inferenceResult.counts;
13450
13473
  inferenceUUID = path7.basename(
13451
13474
  inferenceFile.path,
13452
13475
  path7.extname(inferenceFile.path)
13453
13476
  );
13454
- await fsPromises2.writeFile(
13455
- inferenceFile.path,
13456
- inferenceResult.sanitizedData,
13457
- "utf-8"
13458
- );
13477
+ if (shouldSanitize) {
13478
+ const inferenceStart = performance.now();
13479
+ const inferenceResult = await sanitizeDataWithCounts(args.inference);
13480
+ inferenceCounts = inferenceResult.counts;
13481
+ await fsPromises2.writeFile(
13482
+ inferenceFile.path,
13483
+ inferenceResult.sanitizedData,
13484
+ "utf-8"
13485
+ );
13486
+ sanitizationDurationMs = (sanitizationDurationMs ?? 0) + (performance.now() - inferenceStart);
13487
+ } else {
13488
+ inferenceCounts = zeroCounts;
13489
+ await fsPromises2.writeFile(inferenceFile.path, args.inference, "utf-8");
13490
+ }
13459
13491
  uploadArgs.inference.push(inferenceFile.path);
13460
13492
  uploadArgs.model.push(args.model);
13461
13493
  uploadArgs.toolName.push(args.tool);
@@ -13477,7 +13509,8 @@ async function uploadAiBlameHandlerFromExtension(args) {
13477
13509
  promptsCounts,
13478
13510
  inferenceCounts,
13479
13511
  promptsUUID,
13480
- inferenceUUID
13512
+ inferenceUUID,
13513
+ sanitizationDurationMs
13481
13514
  };
13482
13515
  }
13483
13516
  async function uploadAiBlameHandler(options) {
@@ -13486,7 +13519,7 @@ async function uploadAiBlameHandler(options) {
13486
13519
  exitOnError = true,
13487
13520
  apiUrl,
13488
13521
  webAppUrl,
13489
- logger: logger2 = defaultLogger2
13522
+ logger: logger3 = defaultLogger2
13490
13523
  } = options;
13491
13524
  const prompts = args.prompt || [];
13492
13525
  const inferences = args.inference || [];
@@ -13497,7 +13530,7 @@ async function uploadAiBlameHandler(options) {
13497
13530
  const sessionIds = args.sessionId || args["session-id"] || [];
13498
13531
  if (prompts.length !== inferences.length) {
13499
13532
  const errorMsg = "prompt and inference must have the same number of entries";
13500
- logger2.error(chalk4.red(errorMsg));
13533
+ logger3.error(chalk4.red(errorMsg));
13501
13534
  if (exitOnError) {
13502
13535
  process.exit(1);
13503
13536
  }
@@ -13517,7 +13550,7 @@ async function uploadAiBlameHandler(options) {
13517
13550
  ]);
13518
13551
  } catch {
13519
13552
  const errorMsg = `File not found for session ${i + 1}`;
13520
- logger2.error(chalk4.red(errorMsg));
13553
+ logger3.error(chalk4.red(errorMsg));
13521
13554
  if (exitOnError) {
13522
13555
  process.exit(1);
13523
13556
  }
@@ -13550,7 +13583,7 @@ async function uploadAiBlameHandler(options) {
13550
13583
  const uploadSessions = initRes.uploadAIBlameInferencesInit?.uploadSessions ?? [];
13551
13584
  if (uploadSessions.length !== sessions.length) {
13552
13585
  const errorMsg = "Init failed to return expected number of sessions";
13553
- logger2.error(chalk4.red(errorMsg));
13586
+ logger3.error(chalk4.red(errorMsg));
13554
13587
  if (exitOnError) {
13555
13588
  process.exit(1);
13556
13589
  }
@@ -13594,7 +13627,7 @@ async function uploadAiBlameHandler(options) {
13594
13627
  };
13595
13628
  });
13596
13629
  try {
13597
- logger2.info(
13630
+ logger3.info(
13598
13631
  `[UPLOAD] Calling finalizeAIBlameInferencesUploadRaw with ${finalizeSessions.length} sessions`
13599
13632
  );
13600
13633
  const finRes = await authenticatedClient.finalizeAIBlameInferencesUploadRaw(
@@ -13602,11 +13635,11 @@ async function uploadAiBlameHandler(options) {
13602
13635
  sessions: finalizeSessions
13603
13636
  }
13604
13637
  );
13605
- logger2.info("[UPLOAD] Finalize response:", JSON.stringify(finRes, null, 2));
13638
+ logger3.info("[UPLOAD] Finalize response:", JSON.stringify(finRes, null, 2));
13606
13639
  const status = finRes?.finalizeAIBlameInferencesUpload?.status;
13607
13640
  if (status !== "OK") {
13608
13641
  const errorMsg = finRes?.finalizeAIBlameInferencesUpload?.error || "unknown error";
13609
- logger2.error(
13642
+ logger3.error(
13610
13643
  chalk4.red(
13611
13644
  `[UPLOAD] Finalize failed with status: ${status}, error: ${errorMsg}`
13612
13645
  )
@@ -13616,9 +13649,9 @@ async function uploadAiBlameHandler(options) {
13616
13649
  }
13617
13650
  throw new Error(errorMsg);
13618
13651
  }
13619
- logger2.info(chalk4.green("[UPLOAD] AI Blame uploads finalized successfully"));
13652
+ logger3.info(chalk4.green("[UPLOAD] AI Blame uploads finalized successfully"));
13620
13653
  } catch (error) {
13621
- logger2.error("[UPLOAD] Finalize threw error:", error);
13654
+ logger3.error("[UPLOAD] Finalize threw error:", error);
13622
13655
  throw error;
13623
13656
  }
13624
13657
  }
@@ -13628,6 +13661,110 @@ async function uploadAiBlameCommandHandler(args) {
13628
13661
 
13629
13662
  // src/features/analysis/graphql/tracy-batch-upload.ts
13630
13663
  var debug10 = Debug9("mobbdev:tracy-batch-upload");
13664
+ async function sanitizeRawData(rawData) {
13665
+ try {
13666
+ const sanitized = await sanitizeData(rawData);
13667
+ return JSON.stringify(sanitized);
13668
+ } catch (err) {
13669
+ console.warn(
13670
+ "[tracy] sanitizeRawData failed, falling back to unsanitized:",
13671
+ err.message
13672
+ );
13673
+ return JSON.stringify(rawData);
13674
+ }
13675
+ }
13676
+ async function prepareAndSendTracyRecords(client, rawRecords, workingDir) {
13677
+ const repositoryUrl = await getRepositoryUrl(workingDir);
13678
+ const { computerName, userName } = getSystemInfo();
13679
+ const clientVersion = packageJson.version;
13680
+ const serializedRawDataByIndex = /* @__PURE__ */ new Map();
13681
+ const records = await Promise.all(
13682
+ rawRecords.map(async (record, index) => {
13683
+ if (record.rawData != null) {
13684
+ const serialized = await sanitizeRawData(record.rawData);
13685
+ serializedRawDataByIndex.set(index, serialized);
13686
+ }
13687
+ const { rawData: _rawData, ...rest } = record;
13688
+ return {
13689
+ ...rest,
13690
+ repositoryUrl: repositoryUrl ?? void 0,
13691
+ computerName,
13692
+ userName,
13693
+ clientVersion
13694
+ };
13695
+ })
13696
+ );
13697
+ const recordsWithRawData = rawRecords.map((r, i) => ({ recordId: r.recordId, index: i })).filter((entry) => serializedRawDataByIndex.has(entry.index));
13698
+ if (recordsWithRawData.length > 0) {
13699
+ debug10("Uploading %d rawData files to S3...", recordsWithRawData.length);
13700
+ const uploadUrlResult = await client.getTracyRawDataUploadUrl();
13701
+ const { url, uploadFieldsJSON, keyPrefix } = uploadUrlResult.getTracyRawDataUploadUrl;
13702
+ if (!url || !uploadFieldsJSON || !keyPrefix) {
13703
+ return {
13704
+ ok: false,
13705
+ errors: ["Failed to get S3 upload URL for rawData"]
13706
+ };
13707
+ }
13708
+ let uploadFields;
13709
+ try {
13710
+ uploadFields = JSON.parse(uploadFieldsJSON);
13711
+ } catch {
13712
+ return { ok: false, errors: ["Malformed uploadFieldsJSON from server"] };
13713
+ }
13714
+ const uploadResults = await Promise.allSettled(
13715
+ recordsWithRawData.map(async (entry) => {
13716
+ const rawDataJson = serializedRawDataByIndex.get(entry.index);
13717
+ if (!rawDataJson) {
13718
+ debug10("No serialized rawData for recordId=%s", entry.recordId);
13719
+ return;
13720
+ }
13721
+ const uploadKey = `${keyPrefix}${entry.recordId}.json`;
13722
+ await uploadFile({
13723
+ file: Buffer.from(rawDataJson, "utf-8"),
13724
+ url,
13725
+ uploadKey,
13726
+ uploadFields
13727
+ });
13728
+ records[entry.index].rawDataS3Key = uploadKey;
13729
+ })
13730
+ );
13731
+ const uploadErrors = uploadResults.filter((r) => r.status === "rejected").map((r) => r.reason.message);
13732
+ if (uploadErrors.length > 0) {
13733
+ debug10("S3 upload errors: %O", uploadErrors);
13734
+ }
13735
+ const missingS3Keys = recordsWithRawData.filter(
13736
+ (entry) => !records[entry.index].rawDataS3Key
13737
+ );
13738
+ if (missingS3Keys.length > 0) {
13739
+ const missingIds = missingS3Keys.map((e) => e.recordId);
13740
+ debug10("Records missing S3 keys after upload: %O", missingIds);
13741
+ return {
13742
+ ok: false,
13743
+ errors: [
13744
+ `Failed to upload rawData to S3 for ${missingS3Keys.length} record(s): ${missingIds.join(", ")}`,
13745
+ ...uploadErrors
13746
+ ]
13747
+ };
13748
+ }
13749
+ debug10("S3 uploads complete");
13750
+ }
13751
+ try {
13752
+ const result = await client.uploadTracyRecords({ records });
13753
+ if (result.uploadTracyRecords.status !== "OK") {
13754
+ return {
13755
+ ok: false,
13756
+ errors: [result.uploadTracyRecords.error ?? "Unknown server error"]
13757
+ };
13758
+ }
13759
+ } catch (err) {
13760
+ debug10("Upload failed: %s", err.message);
13761
+ return {
13762
+ ok: false,
13763
+ errors: [err.message]
13764
+ };
13765
+ }
13766
+ return { ok: true, errors: null };
13767
+ }
13631
13768
 
13632
13769
  // src/mcp/services/types.ts
13633
13770
  function detectIDE() {
@@ -14845,8 +14982,8 @@ if (typeof __filename !== "undefined") {
14845
14982
  }
14846
14983
  var costumeRequire = createRequire(moduleUrl);
14847
14984
  var getCheckmarxPath = () => {
14848
- const os13 = type();
14849
- const cxFileName = os13 === "Windows_NT" ? "cx.exe" : "cx";
14985
+ const os14 = type();
14986
+ const cxFileName = os14 === "Windows_NT" ? "cx.exe" : "cx";
14850
14987
  try {
14851
14988
  return costumeRequire.resolve(`.bin/${cxFileName}`);
14852
14989
  } catch (e) {
@@ -16159,229 +16296,383 @@ async function analyzeHandler(args) {
16159
16296
  }
16160
16297
 
16161
16298
  // src/features/claude_code/data_collector.ts
16299
+ import { createHash as createHash2 } from "crypto";
16300
+ import { open as open4, readdir, readFile, unlink } from "fs/promises";
16301
+ import path13 from "path";
16162
16302
  import { z as z33 } from "zod";
16163
16303
  init_client_generates();
16164
- init_GitService();
16165
- init_urlParser2();
16166
16304
 
16167
- // src/utils/computeGitDiffAdditions.ts
16168
- import { mkdtemp, rm, writeFile } from "fs/promises";
16169
- import { tmpdir } from "os";
16170
- import path13 from "path";
16171
- import { simpleGit as simpleGit4 } from "simple-git";
16172
- async function computeGitDiffAdditions(oldStr, newStr) {
16173
- const tmpDir = await mkdtemp(path13.join(tmpdir(), "diff-"));
16174
- const oldFile = path13.join(tmpDir, "old");
16175
- const newFile = path13.join(tmpDir, "new");
16176
- try {
16177
- await writeFile(oldFile, oldStr);
16178
- await writeFile(newFile, newStr);
16179
- const git = simpleGit4();
16180
- let result;
16305
+ // src/utils/shared-logger/create-logger.ts
16306
+ import Configstore2 from "configstore";
16307
+ import pino from "pino";
16308
+
16309
+ // src/utils/shared-logger/configstore-stream.ts
16310
+ import { writeFileSync } from "fs";
16311
+ import * as stream from "stream";
16312
+ var DEFAULT_MAX_LOGS = 1e3;
16313
+ var DEFAULT_MAX_HEARTBEAT = 100;
16314
+ var LOGS_KEY = "logs";
16315
+ var HEARTBEAT_KEY = "heartbeat";
16316
+ function createConfigstoreStream(store, opts) {
16317
+ const maxLogs = opts.maxLogs ?? DEFAULT_MAX_LOGS;
16318
+ const maxHeartbeat = opts.maxHeartbeat ?? DEFAULT_MAX_HEARTBEAT;
16319
+ const buffer = [];
16320
+ const heartbeatBuffer = [];
16321
+ let scopePath = opts.scopePath;
16322
+ function storeKey(base) {
16323
+ return scopePath ? `${base}:${scopePath}` : base;
16324
+ }
16325
+ function writeToDisk(entries, key, max) {
16181
16326
  try {
16182
- result = await git.raw([
16183
- "diff",
16184
- "--no-index",
16185
- "--unified=0",
16186
- oldFile,
16187
- newFile
16188
- ]);
16189
- } catch (err) {
16190
- if (err instanceof Error && "stdOut" in err) {
16191
- result = err.stdOut;
16192
- } else {
16193
- throw err;
16327
+ const existing = store.get(key) ?? [];
16328
+ existing.push(...entries);
16329
+ const trimmed = existing.length > max ? existing.slice(-max) : existing;
16330
+ store.set(key, trimmed);
16331
+ } catch {
16332
+ try {
16333
+ const lines = `${entries.map((e) => JSON.stringify(e)).join("\n")}
16334
+ `;
16335
+ writeFileSync(`${store.path}.fallback`, lines, { flag: "a" });
16336
+ } catch {
16194
16337
  }
16195
16338
  }
16196
- const additions = [];
16197
- for (const line of result.split("\n")) {
16198
- if (line.startsWith("+") && !line.startsWith("+++")) {
16199
- additions.push(line.slice(1));
16339
+ }
16340
+ const writable = new stream.Writable({
16341
+ write(chunk, _encoding, callback) {
16342
+ callback();
16343
+ try {
16344
+ const parsed = JSON.parse(chunk.toString());
16345
+ const entry = {
16346
+ timestamp: parsed.time ? new Date(parsed.time).toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
16347
+ level: parsed.level ?? "info",
16348
+ message: parsed.msg ?? "",
16349
+ ...parsed.durationMs !== void 0 && {
16350
+ durationMs: parsed.durationMs
16351
+ },
16352
+ ...parsed.data !== void 0 && { data: parsed.data }
16353
+ };
16354
+ const isHeartbeat = parsed.heartbeat === true;
16355
+ if (opts.buffered) {
16356
+ if (isHeartbeat) {
16357
+ heartbeatBuffer.push(entry);
16358
+ } else {
16359
+ buffer.push(entry);
16360
+ }
16361
+ } else {
16362
+ if (isHeartbeat) {
16363
+ writeToDisk([entry], storeKey(HEARTBEAT_KEY), maxHeartbeat);
16364
+ } else {
16365
+ writeToDisk([entry], storeKey(LOGS_KEY), maxLogs);
16366
+ }
16367
+ }
16368
+ } catch {
16200
16369
  }
16201
16370
  }
16202
- return additions.join("\n");
16203
- } finally {
16204
- await rm(tmpDir, { recursive: true, force: true });
16371
+ });
16372
+ function flush() {
16373
+ if (buffer.length > 0) {
16374
+ writeToDisk(buffer, storeKey(LOGS_KEY), maxLogs);
16375
+ buffer.length = 0;
16376
+ }
16377
+ if (heartbeatBuffer.length > 0) {
16378
+ writeToDisk(heartbeatBuffer, storeKey(HEARTBEAT_KEY), maxHeartbeat);
16379
+ heartbeatBuffer.length = 0;
16380
+ }
16381
+ }
16382
+ function setScopePath(path27) {
16383
+ scopePath = path27;
16384
+ }
16385
+ return { writable, flush, setScopePath };
16386
+ }
16387
+
16388
+ // src/utils/shared-logger/dd-batch.ts
16389
+ import * as stream2 from "stream";
16390
+ import * as util from "util";
16391
+ import fetch5 from "cross-fetch";
16392
+ var DD_BATCH_INTERVAL_MS = 5e3;
16393
+ var DD_BATCH_MAX_SIZE = 50;
16394
+ function createDdBatch(config2) {
16395
+ let batch = [];
16396
+ let flushTimer = null;
16397
+ let pendingFlush = null;
16398
+ let errorLogged = false;
16399
+ function flush() {
16400
+ if (batch.length === 0) return;
16401
+ const toSend = batch;
16402
+ batch = [];
16403
+ pendingFlush = fetch5("https://http-intake.logs.datadoghq.com/api/v2/logs", {
16404
+ method: "POST",
16405
+ headers: {
16406
+ "Content-Type": "application/json",
16407
+ "DD-API-KEY": config2.apiKey
16408
+ },
16409
+ body: JSON.stringify(toSend)
16410
+ }).then(() => void 0).catch((error) => {
16411
+ if (!errorLogged) {
16412
+ errorLogged = true;
16413
+ config2.onError?.(
16414
+ `Error sending log to Datadog (further errors suppressed): ${util.inspect(error)}`
16415
+ );
16416
+ }
16417
+ });
16418
+ }
16419
+ function enqueue(message) {
16420
+ if (!config2.apiKey) return;
16421
+ batch.push({
16422
+ hostname: config2.hostname,
16423
+ ddsource: config2.ddsource,
16424
+ service: config2.service,
16425
+ ddtags: config2.ddtags,
16426
+ message
16427
+ });
16428
+ if (!flushTimer) {
16429
+ flushTimer = setInterval(flush, DD_BATCH_INTERVAL_MS);
16430
+ if (config2.unrefTimer) {
16431
+ flushTimer.unref();
16432
+ }
16433
+ }
16434
+ if (batch.length >= DD_BATCH_MAX_SIZE) {
16435
+ flush();
16436
+ }
16437
+ }
16438
+ async function flushAsync() {
16439
+ flush();
16440
+ await pendingFlush;
16205
16441
  }
16442
+ function dispose() {
16443
+ flush();
16444
+ if (flushTimer) {
16445
+ clearInterval(flushTimer);
16446
+ flushTimer = null;
16447
+ }
16448
+ }
16449
+ function createPinoStream() {
16450
+ return new stream2.Writable({
16451
+ write(chunk, _encoding, callback) {
16452
+ callback();
16453
+ enqueue(chunk.toString());
16454
+ }
16455
+ });
16456
+ }
16457
+ return { enqueue, flush, flushAsync, dispose, createPinoStream };
16206
16458
  }
16207
16459
 
16208
- // src/features/claude_code/transcript_parser.ts
16209
- import fsPromises4 from "fs/promises";
16210
- function processTranscriptLine(entry) {
16211
- const prompts = [];
16212
- let model;
16213
- let inputTokens = 0;
16214
- let outputTokens = 0;
16215
- let date;
16216
- if (entry.message?.model) {
16217
- model = entry.message.model;
16218
- }
16219
- if (entry.message?.usage) {
16220
- inputTokens = entry.message.usage.input_tokens || 0;
16221
- outputTokens = entry.message.usage.output_tokens || 0;
16222
- }
16223
- if (entry.timestamp) {
16224
- date = new Date(entry.timestamp);
16225
- }
16226
- if (entry.type === "user" && entry.message?.role === "user") {
16227
- if (typeof entry.message.content === "string") {
16228
- prompts.push({
16229
- type: "USER_PROMPT",
16230
- text: entry.message.content,
16231
- date: date || /* @__PURE__ */ new Date(),
16232
- tokens: inputTokens > 0 ? {
16233
- inputCount: inputTokens,
16234
- outputCount: 0
16235
- } : void 0
16236
- });
16237
- }
16238
- } else if (entry.type === "assistant" && entry.message?.role === "assistant") {
16239
- if (Array.isArray(entry.message.content)) {
16240
- for (const item of entry.message.content) {
16241
- if (item.type === "text" && item.text) {
16242
- prompts.push({
16243
- type: "AI_RESPONSE",
16244
- text: item.text,
16245
- date: date || /* @__PURE__ */ new Date(),
16246
- tokens: outputTokens > 0 ? {
16247
- inputCount: 0,
16248
- outputCount: outputTokens
16249
- } : void 0
16250
- });
16251
- } else if (item.type === "thinking" && item.thinking) {
16252
- prompts.push({
16253
- type: "AI_THINKING",
16254
- text: item.thinking,
16255
- date: date || /* @__PURE__ */ new Date()
16256
- });
16257
- }
16460
+ // src/utils/shared-logger/hostname.ts
16461
+ import { createHash } from "crypto";
16462
+ import os4 from "os";
16463
+ function hashString(input) {
16464
+ return createHash("sha256").update(input).digest("hex").slice(0, 16);
16465
+ }
16466
+ function getPlainHostname() {
16467
+ try {
16468
+ return `${os4.userInfo().username}@${os4.hostname()}`;
16469
+ } catch {
16470
+ return `unknown@${os4.hostname()}`;
16471
+ }
16472
+ }
16473
+ function getHashedHostname() {
16474
+ try {
16475
+ return `${hashString(os4.userInfo().username)}@${hashString(os4.hostname())}`;
16476
+ } catch {
16477
+ return `unknown@${hashString(os4.hostname())}`;
16478
+ }
16479
+ }
16480
+
16481
+ // src/utils/shared-logger/create-logger.ts
16482
+ function createLogger(config2) {
16483
+ const {
16484
+ namespace,
16485
+ scopePath,
16486
+ buffered = true,
16487
+ maxLogs,
16488
+ maxHeartbeat,
16489
+ dd,
16490
+ additionalStreams = []
16491
+ } = config2;
16492
+ const store = new Configstore2(namespace, {});
16493
+ const csStream = createConfigstoreStream(store, {
16494
+ buffered,
16495
+ scopePath,
16496
+ maxLogs,
16497
+ maxHeartbeat
16498
+ });
16499
+ let ddBatch = null;
16500
+ if (dd) {
16501
+ const hostname = dd.hostnameMode === "hashed" ? getHashedHostname() : getPlainHostname();
16502
+ const ddConfig = {
16503
+ apiKey: dd.apiKey,
16504
+ ddsource: dd.ddsource,
16505
+ service: dd.service,
16506
+ ddtags: dd.ddtags,
16507
+ hostname,
16508
+ unrefTimer: dd.unrefTimer,
16509
+ onError: dd.onError
16510
+ };
16511
+ ddBatch = createDdBatch(ddConfig);
16512
+ }
16513
+ const streams = [
16514
+ { stream: csStream.writable, level: "info" }
16515
+ ];
16516
+ if (ddBatch) {
16517
+ streams.push({ stream: ddBatch.createPinoStream(), level: "info" });
16518
+ }
16519
+ for (const extra of additionalStreams) {
16520
+ streams.push({
16521
+ stream: extra.stream,
16522
+ level: extra.level
16523
+ });
16524
+ }
16525
+ const pinoLogger = pino(
16526
+ {
16527
+ formatters: {
16528
+ level: (label) => ({ level: label })
16258
16529
  }
16530
+ },
16531
+ pino.multistream(streams)
16532
+ );
16533
+ const info = pinoLogger.info.bind(pinoLogger);
16534
+ const warn = pinoLogger.warn.bind(pinoLogger);
16535
+ const error = pinoLogger.error.bind(pinoLogger);
16536
+ const debug23 = pinoLogger.debug.bind(pinoLogger);
16537
+ function heartbeat(message, data) {
16538
+ pinoLogger.info({ data, heartbeat: true }, message);
16539
+ }
16540
+ async function timed(label, fn) {
16541
+ const start = Date.now();
16542
+ try {
16543
+ const result = await fn();
16544
+ pinoLogger.info({ durationMs: Date.now() - start }, label);
16545
+ return result;
16546
+ } catch (err) {
16547
+ pinoLogger.error(
16548
+ {
16549
+ durationMs: Date.now() - start,
16550
+ data: err instanceof Error ? err.message : String(err)
16551
+ },
16552
+ `${label} [FAILED]`
16553
+ );
16554
+ throw err;
16259
16555
  }
16260
16556
  }
16261
- return {
16262
- prompts,
16263
- model,
16264
- inputTokens,
16265
- outputTokens,
16266
- date
16267
- };
16268
- }
16269
- async function parseTranscriptAndCreateTrace(transcriptPath, hookData, inference) {
16270
- const content = await fsPromises4.readFile(transcriptPath, "utf-8");
16271
- const lines = content.trim().split("\n");
16272
- let currentToolIndex = -1;
16273
- for (let i = lines.length - 1; i >= 0; i--) {
16274
- const line = lines[i]?.trim() ?? "";
16275
- if (!line.includes('"type":"tool_use"')) continue;
16276
- const isEditTool = line.includes('"name":"Edit"');
16277
- const isWriteTool = line.includes('"name":"Write"');
16278
- if (isEditTool || isWriteTool) {
16279
- currentToolIndex = i;
16280
- break;
16557
+ function flushLogs2() {
16558
+ csStream.flush();
16559
+ }
16560
+ async function flushDdAsync() {
16561
+ if (ddBatch) {
16562
+ await ddBatch.flushAsync();
16281
16563
  }
16282
16564
  }
16283
- const startIndex = 0;
16284
- const endIndex = currentToolIndex === -1 ? lines.length - 1 : currentToolIndex - 1;
16285
- const prompts = [];
16286
- let model;
16287
- let latestDate;
16288
- for (let i = startIndex; i <= endIndex; i++) {
16289
- const line = lines[i]?.trim() ?? "";
16290
- const entry = JSON.parse(line);
16291
- const lineResult = processTranscriptLine(entry);
16292
- prompts.push(...lineResult.prompts);
16293
- if (lineResult.model && !model) {
16294
- model = lineResult.model;
16295
- }
16296
- if (lineResult.date) {
16297
- if (!latestDate || lineResult.date > latestDate) {
16298
- latestDate = lineResult.date;
16299
- }
16300
- }
16301
- }
16302
- prompts.push({
16303
- type: "TOOL_EXECUTION",
16304
- date: latestDate || /* @__PURE__ */ new Date(),
16305
- tool: {
16306
- name: hookData.tool_name,
16307
- parameters: JSON.stringify(hookData.tool_input, null, 2),
16308
- result: JSON.stringify(hookData.tool_response, null, 2),
16309
- rawArguments: JSON.stringify(hookData.tool_input),
16310
- accepted: true
16565
+ function disposeDd() {
16566
+ if (ddBatch) {
16567
+ ddBatch.dispose();
16311
16568
  }
16312
- });
16569
+ }
16313
16570
  return {
16314
- prompts,
16315
- inference,
16316
- model: model || "claude-sonnet-4",
16317
- // Use extracted model or fallback
16318
- tool: "Claude Code",
16319
- responseTime: (latestDate || /* @__PURE__ */ new Date()).toISOString()
16571
+ info,
16572
+ warn,
16573
+ error,
16574
+ debug: debug23,
16575
+ heartbeat,
16576
+ timed,
16577
+ flushLogs: flushLogs2,
16578
+ flushDdAsync,
16579
+ disposeDd,
16580
+ setScopePath: csStream.setScopePath
16320
16581
  };
16321
16582
  }
16322
16583
 
16584
+ // src/features/claude_code/hook_logger.ts
16585
+ var DD_RUM_TOKEN = true ? "" : "";
16586
+ var CLI_VERSION = true ? "1.2.55" : "unknown";
16587
+ var NAMESPACE = "mobbdev-claude-code-hook-logs";
16588
+ function createHookLogger(scopePath) {
16589
+ return createLogger({
16590
+ namespace: NAMESPACE,
16591
+ scopePath,
16592
+ dd: {
16593
+ apiKey: DD_RUM_TOKEN,
16594
+ ddsource: "mobbdev-cli",
16595
+ service: "mobbdev-cli-hook",
16596
+ ddtags: `version:${CLI_VERSION}`,
16597
+ hostnameMode: "hashed",
16598
+ unrefTimer: true
16599
+ }
16600
+ });
16601
+ }
16602
+ var logger = createHookLogger();
16603
+ var activeScopedLoggers = [];
16604
+ var hookLog = logger;
16605
+ function flushLogs() {
16606
+ logger.flushLogs();
16607
+ for (const scoped of activeScopedLoggers) {
16608
+ scoped.flushLogs();
16609
+ }
16610
+ activeScopedLoggers.length = 0;
16611
+ }
16612
+ async function flushDdLogs() {
16613
+ await logger.flushDdAsync();
16614
+ for (const scoped of activeScopedLoggers) {
16615
+ await scoped.flushDdAsync();
16616
+ }
16617
+ }
16618
+ function createScopedHookLog(scopePath) {
16619
+ const scoped = createHookLogger(scopePath);
16620
+ activeScopedLoggers.push(scoped);
16621
+ return scoped;
16622
+ }
16623
+
16323
16624
  // src/features/claude_code/data_collector.ts
16324
- var StructuredPatchItemSchema = z33.object({
16325
- oldStart: z33.number(),
16326
- oldLines: z33.number(),
16327
- newStart: z33.number(),
16328
- newLines: z33.number(),
16329
- lines: z33.array(z33.string())
16330
- });
16331
- var EditToolInputSchema = z33.object({
16332
- file_path: z33.string(),
16333
- old_string: z33.string(),
16334
- new_string: z33.string()
16335
- });
16336
- var WriteToolInputSchema = z33.object({
16337
- file_path: z33.string(),
16338
- content: z33.string()
16339
- });
16340
- var EditToolResponseSchema = z33.object({
16341
- filePath: z33.string(),
16342
- oldString: z33.string().optional(),
16343
- newString: z33.string().optional(),
16344
- originalFile: z33.string().optional(),
16345
- structuredPatch: z33.array(StructuredPatchItemSchema),
16346
- userModified: z33.boolean().optional(),
16347
- replaceAll: z33.boolean().optional()
16348
- });
16349
- var WriteToolResponseSchema = z33.object({
16350
- type: z33.string().optional(),
16351
- filePath: z33.string(),
16352
- content: z33.string().optional(),
16353
- structuredPatch: z33.array(z33.any()).optional()
16354
- });
16625
+ var HOOK_COOLDOWN_MS = 1e4;
16626
+ var STALE_KEY_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
16627
+ var CLEANUP_INTERVAL_MS = 24 * 60 * 60 * 1e3;
16628
+ var COOLDOWN_KEY = "lastHookRunAt";
16355
16629
  var HookDataSchema = z33.object({
16356
16630
  session_id: z33.string(),
16357
16631
  transcript_path: z33.string(),
16358
16632
  cwd: z33.string(),
16359
- permission_mode: z33.string().optional(),
16360
- hook_event_name: z33.literal("PostToolUse"),
16361
- tool_name: z33.enum(["Edit", "Write"]),
16362
- tool_input: z33.union([EditToolInputSchema, WriteToolInputSchema]),
16363
- tool_response: z33.union([EditToolResponseSchema, WriteToolResponseSchema])
16633
+ hook_event_name: z33.string(),
16634
+ tool_name: z33.string(),
16635
+ tool_input: z33.unknown(),
16636
+ tool_response: z33.unknown()
16364
16637
  });
16638
+ var STDIN_TIMEOUT_MS = 1e4;
16365
16639
  async function readStdinData() {
16640
+ hookLog.debug("Reading stdin data");
16366
16641
  return new Promise((resolve, reject) => {
16367
16642
  let inputData = "";
16643
+ let settled = false;
16644
+ const timer = setTimeout(() => {
16645
+ if (!settled) {
16646
+ settled = true;
16647
+ process.stdin.destroy();
16648
+ reject(new Error("Timed out reading from stdin"));
16649
+ }
16650
+ }, STDIN_TIMEOUT_MS);
16368
16651
  process.stdin.setEncoding("utf-8");
16369
16652
  process.stdin.on("data", (chunk) => {
16370
16653
  inputData += chunk;
16371
16654
  });
16372
16655
  process.stdin.on("end", () => {
16656
+ if (settled) return;
16657
+ settled = true;
16658
+ clearTimeout(timer);
16373
16659
  try {
16374
16660
  const parsedData = JSON.parse(inputData);
16661
+ hookLog.debug("Parsed stdin data", {
16662
+ keys: Object.keys(parsedData)
16663
+ });
16375
16664
  resolve(parsedData);
16376
16665
  } catch (error) {
16377
- reject(
16378
- new Error(
16379
- `Failed to parse JSON from stdin: ${error.message}`
16380
- )
16381
- );
16666
+ const msg = `Failed to parse JSON from stdin: ${error.message}`;
16667
+ hookLog.error(msg);
16668
+ reject(new Error(msg));
16382
16669
  }
16383
16670
  });
16384
16671
  process.stdin.on("error", (error) => {
16672
+ if (settled) return;
16673
+ settled = true;
16674
+ clearTimeout(timer);
16675
+ hookLog.error("Error reading from stdin", { error: error.message });
16385
16676
  reject(new Error(`Error reading from stdin: ${error.message}`));
16386
16677
  });
16387
16678
  });
@@ -16389,144 +16680,329 @@ async function readStdinData() {
16389
16680
  function validateHookData(data) {
16390
16681
  return HookDataSchema.parse(data);
16391
16682
  }
16392
- function extractStructuredPatchAdditions(hookData) {
16393
- const editResponse = hookData.tool_response;
16394
- const additions = [];
16395
- for (const patch of editResponse.structuredPatch) {
16396
- for (const line of patch.lines) {
16397
- if (line.startsWith("+")) {
16398
- additions.push(line.slice(1));
16399
- }
16400
- }
16401
- }
16402
- return additions.join("\n");
16403
- }
16404
- async function extractInference(hookData) {
16405
- if (hookData.tool_name === "Write") {
16406
- const writeInput = hookData.tool_input;
16407
- return writeInput.content || "";
16408
- }
16409
- if (hookData.tool_name === "Edit") {
16410
- const editInput = hookData.tool_input;
16683
+ function generateSyntheticId(sessionId, timestamp, type2, lineIndex) {
16684
+ const input = `${sessionId ?? ""}:${timestamp ?? ""}:${type2 ?? ""}:${lineIndex}`;
16685
+ const hash = createHash2("sha256").update(input).digest("hex").slice(0, 16);
16686
+ return `synth:${hash}`;
16687
+ }
16688
+ function getCursorKey(transcriptPath) {
16689
+ const hash = createHash2("sha256").update(transcriptPath).digest("hex").slice(0, 12);
16690
+ return `cursor.${hash}`;
16691
+ }
16692
+ async function readNewTranscriptEntries(transcriptPath, sessionId, sessionStore) {
16693
+ const cursor = sessionStore.get(getCursorKey(transcriptPath));
16694
+ let content;
16695
+ let fileSize;
16696
+ let lineIndexOffset;
16697
+ if (cursor?.byteOffset) {
16698
+ const fh = await open4(transcriptPath, "r");
16411
16699
  try {
16412
- return await computeGitDiffAdditions(
16413
- editInput.old_string,
16414
- editInput.new_string
16700
+ const stat = await fh.stat();
16701
+ fileSize = stat.size;
16702
+ if (cursor.byteOffset >= stat.size) {
16703
+ hookLog.info("No new data in transcript file", { sessionId });
16704
+ return { entries: [], fileSize };
16705
+ }
16706
+ const buf = Buffer.alloc(stat.size - cursor.byteOffset);
16707
+ await fh.read(buf, 0, buf.length, cursor.byteOffset);
16708
+ content = buf.toString("utf-8");
16709
+ } finally {
16710
+ await fh.close();
16711
+ }
16712
+ lineIndexOffset = cursor.byteOffset;
16713
+ hookLog.debug("Read transcript file from offset", {
16714
+ transcriptPath,
16715
+ byteOffset: cursor.byteOffset,
16716
+ bytesRead: content.length
16717
+ });
16718
+ } else {
16719
+ content = await readFile(transcriptPath, "utf-8");
16720
+ fileSize = Buffer.byteLength(content, "utf-8");
16721
+ lineIndexOffset = 0;
16722
+ hookLog.debug("Read full transcript file", {
16723
+ transcriptPath,
16724
+ totalBytes: fileSize
16725
+ });
16726
+ }
16727
+ const lines = content.split("\n").filter((line) => line.trim().length > 0);
16728
+ const parsed = [];
16729
+ let malformedLines = 0;
16730
+ for (let i = 0; i < lines.length; i++) {
16731
+ try {
16732
+ const entry = JSON.parse(lines[i]);
16733
+ const recordId = entry.uuid ?? generateSyntheticId(
16734
+ entry.sessionId,
16735
+ entry.timestamp,
16736
+ entry.type,
16737
+ lineIndexOffset + i
16415
16738
  );
16739
+ parsed.push({ ...entry, _recordId: recordId });
16416
16740
  } catch {
16417
- return extractStructuredPatchAdditions(hookData);
16741
+ malformedLines++;
16418
16742
  }
16419
16743
  }
16420
- return "";
16744
+ if (malformedLines > 0) {
16745
+ hookLog.warn("Skipped malformed lines", { malformedLines, transcriptPath });
16746
+ }
16747
+ if (!cursor) {
16748
+ hookLog.info("First invocation for session \u2014 uploading all entries", {
16749
+ sessionId,
16750
+ totalEntries: parsed.length
16751
+ });
16752
+ } else {
16753
+ hookLog.info("Resuming from byte offset", {
16754
+ sessionId,
16755
+ byteOffset: cursor.byteOffset,
16756
+ newEntries: parsed.length
16757
+ });
16758
+ }
16759
+ return { entries: parsed, fileSize };
16760
+ }
16761
+ var FILTERED_PROGRESS_SUBTYPES = /* @__PURE__ */ new Set([
16762
+ // Incremental streaming output from running bash commands, emitted every
16763
+ // ~1 second. The final complete output is already captured in the "user"
16764
+ // tool_result entry when the command finishes.
16765
+ "bash_progress",
16766
+ // Records that the hook itself fired. Pure meta-noise — the hook
16767
+ // recording the fact that the hook ran.
16768
+ "hook_progress",
16769
+ // UI-only "waiting" indicator for background tasks (TaskOutput polling).
16770
+ // Contains only a task description and type — no session-relevant data.
16771
+ "waiting_for_task",
16772
+ // MCP tool start/completed timing events. Only unique data is elapsedTimeMs
16773
+ // which can be derived from tool_use/tool_result timestamps.
16774
+ "mcp_progress"
16775
+ ]);
16776
+ var FILTERED_ENTRY_TYPES = /* @__PURE__ */ new Set([
16777
+ // Claude Code's internal undo/restore bookkeeping — tracks which files
16778
+ // have backups. No sessionId, no message, no model or tool data.
16779
+ "file-history-snapshot",
16780
+ // Internal task queue management (enqueue/remove/popAll). Duplicates data
16781
+ // already captured in user messages, agent_progress, and Task tool_use entries.
16782
+ "queue-operation",
16783
+ // Records the last user prompt text before a compaction or session restart.
16784
+ // Redundant — the actual user prompt is already captured in the 'user' entry.
16785
+ "last-prompt"
16786
+ ]);
16787
+ var FILTERED_ASSISTANT_TOOLS = /* @__PURE__ */ new Set([
16788
+ // Polls for a sub-agent result. The input is just task_id + boilerplate
16789
+ // (block, timeout). The actual result is captured in the user:tool_result.
16790
+ "TaskOutput",
16791
+ // Discovers available deferred/MCP tools. The input is just a search query.
16792
+ // The discovered tools are captured in the user:tool_result.
16793
+ "ToolSearch"
16794
+ ]);
16795
+ function filterEntries(entries) {
16796
+ const filtered = entries.filter((entry) => {
16797
+ const entryType = entry.type ?? "";
16798
+ if (FILTERED_ENTRY_TYPES.has(entryType)) {
16799
+ return false;
16800
+ }
16801
+ if (entryType === "progress") {
16802
+ const data = entry["data"];
16803
+ const subtype = typeof data?.["type"] === "string" ? data["type"] : "";
16804
+ return !FILTERED_PROGRESS_SUBTYPES.has(subtype);
16805
+ }
16806
+ if (entryType === "assistant") {
16807
+ const message = entry["message"];
16808
+ const content = message?.["content"];
16809
+ if (Array.isArray(content) && content.length > 0) {
16810
+ const block = content[0];
16811
+ if (block["type"] === "tool_use" && typeof block["name"] === "string" && FILTERED_ASSISTANT_TOOLS.has(block["name"])) {
16812
+ return false;
16813
+ }
16814
+ }
16815
+ }
16816
+ return true;
16817
+ });
16818
+ return { filtered, filteredOut: entries.length - filtered.length };
16421
16819
  }
16422
- async function collectHookData() {
16423
- const rawData = await readStdinData();
16424
- const hookData = validateHookData(rawData);
16425
- const inference = await extractInference(hookData);
16426
- let tracePayload;
16820
+ async function cleanupStaleSessions(sessionStore) {
16821
+ const lastCleanup = configStore.get("claudeCode.lastCleanupAt");
16822
+ if (lastCleanup && Date.now() - lastCleanup < CLEANUP_INTERVAL_MS) {
16823
+ return;
16824
+ }
16825
+ const now = Date.now();
16826
+ const prefix = getSessionFilePrefix();
16827
+ const configDir = path13.dirname(sessionStore.path);
16427
16828
  try {
16428
- tracePayload = await parseTranscriptAndCreateTrace(
16429
- hookData.transcript_path,
16430
- hookData,
16431
- inference
16432
- );
16433
- } catch (error) {
16434
- console.warn(
16435
- "Warning: Could not parse transcript:",
16436
- error.message
16437
- );
16438
- tracePayload = {
16439
- prompts: [
16440
- {
16441
- type: "TOOL_EXECUTION",
16442
- date: /* @__PURE__ */ new Date(),
16443
- tool: {
16444
- name: hookData.tool_name,
16445
- parameters: JSON.stringify(hookData.tool_input, null, 2),
16446
- result: JSON.stringify(hookData.tool_response, null, 2),
16447
- rawArguments: JSON.stringify(hookData.tool_input),
16448
- accepted: true
16829
+ const files = await readdir(configDir);
16830
+ let deletedCount = 0;
16831
+ for (const file of files) {
16832
+ if (!file.startsWith(prefix) || !file.endsWith(".json")) continue;
16833
+ const filePath = path13.join(configDir, file);
16834
+ try {
16835
+ const content = JSON.parse(await readFile(filePath, "utf-8"));
16836
+ let newest = 0;
16837
+ const cooldown = content[COOLDOWN_KEY];
16838
+ if (cooldown && cooldown > newest) newest = cooldown;
16839
+ const cursors = content["cursor"];
16840
+ if (cursors && typeof cursors === "object") {
16841
+ for (const val of Object.values(cursors)) {
16842
+ const c = val;
16843
+ if (c?.updatedAt && c.updatedAt > newest) newest = c.updatedAt;
16449
16844
  }
16450
16845
  }
16451
- ],
16452
- inference,
16453
- model: "claude-sonnet-4",
16454
- tool: "Claude Code",
16455
- responseTime: (/* @__PURE__ */ new Date()).toISOString()
16456
- };
16457
- }
16458
- return {
16459
- hookData,
16460
- inference,
16461
- tracePayload
16462
- };
16463
- }
16464
- async function getRepositoryUrl2(cwd) {
16465
- try {
16466
- const gitService = new GitService(cwd);
16467
- const isRepo = await gitService.isGitRepository();
16468
- if (!isRepo) {
16469
- return null;
16846
+ if (newest > 0 && now - newest > STALE_KEY_MAX_AGE_MS) {
16847
+ await unlink(filePath);
16848
+ deletedCount++;
16849
+ }
16850
+ } catch {
16851
+ }
16852
+ }
16853
+ if (deletedCount > 0) {
16854
+ hookLog.info("Cleaned up stale session files", { deletedCount });
16470
16855
  }
16471
- const remoteUrl = await gitService.getRemoteUrl();
16472
- const parsed = parseScmURL(remoteUrl);
16473
- return parsed?.scmType === "GitHub" /* GitHub */ || parsed?.scmType === "GitLab" /* GitLab */ ? remoteUrl : null;
16474
16856
  } catch {
16475
- return null;
16476
16857
  }
16858
+ configStore.set("claudeCode.lastCleanupAt", now);
16477
16859
  }
16478
- async function processAndUploadHookData() {
16479
- const result = await collectHookData();
16480
- const repositoryUrl = await getRepositoryUrl2(result.hookData.cwd);
16481
- let uploadSuccess;
16860
+ async function processAndUploadTranscriptEntries() {
16861
+ hookLog.info("Hook invoked");
16862
+ const rawData = await readStdinData();
16863
+ const hookData = validateHookData(rawData);
16864
+ const sessionStore = createSessionConfigStore(hookData.session_id);
16865
+ await cleanupStaleSessions(sessionStore);
16866
+ const lastRunAt = sessionStore.get(COOLDOWN_KEY);
16867
+ if (lastRunAt && Date.now() - lastRunAt < HOOK_COOLDOWN_MS) {
16868
+ return { entriesUploaded: 0, entriesSkipped: 0, errors: 0 };
16869
+ }
16870
+ sessionStore.set(COOLDOWN_KEY, Date.now());
16871
+ const log2 = createScopedHookLog(hookData.cwd);
16872
+ log2.info("Hook data validated", {
16873
+ sessionId: hookData.session_id,
16874
+ toolName: hookData.tool_name,
16875
+ hookEvent: hookData.hook_event_name,
16876
+ cwd: hookData.cwd
16877
+ });
16482
16878
  try {
16483
- await uploadAiBlameHandlerFromExtension({
16484
- prompts: result.tracePayload.prompts,
16485
- inference: result.tracePayload.inference,
16486
- model: result.tracePayload.model,
16487
- tool: result.tracePayload.tool,
16488
- responseTime: result.tracePayload.responseTime,
16879
+ return await processTranscript(hookData, sessionStore, log2);
16880
+ } finally {
16881
+ log2.flushLogs();
16882
+ }
16883
+ }
16884
+ async function processTranscript(hookData, sessionStore, log2) {
16885
+ const cursorKey = getCursorKey(hookData.transcript_path);
16886
+ const { entries: rawEntries, fileSize } = await readNewTranscriptEntries(
16887
+ hookData.transcript_path,
16888
+ hookData.session_id,
16889
+ sessionStore
16890
+ );
16891
+ if (rawEntries.length === 0) {
16892
+ log2.info("No new entries to upload");
16893
+ return { entriesUploaded: 0, entriesSkipped: 0, errors: 0 };
16894
+ }
16895
+ const { filtered: entries, filteredOut } = filterEntries(rawEntries);
16896
+ if (filteredOut > 0) {
16897
+ log2.info("Filtered out noise entries", {
16898
+ filteredOut,
16899
+ remaining: entries.length
16900
+ });
16901
+ }
16902
+ if (entries.length === 0) {
16903
+ log2.info("All entries filtered out, nothing to upload");
16904
+ const lastEntry = rawEntries[rawEntries.length - 1];
16905
+ const prevCursor = sessionStore.get(cursorKey);
16906
+ const cursor = {
16907
+ id: lastEntry._recordId,
16908
+ byteOffset: fileSize,
16909
+ updatedAt: Date.now(),
16910
+ lastModel: prevCursor?.lastModel
16911
+ };
16912
+ sessionStore.set(cursorKey, cursor);
16913
+ return {
16914
+ entriesUploaded: 0,
16915
+ entriesSkipped: filteredOut,
16916
+ errors: 0
16917
+ };
16918
+ }
16919
+ const gqlClient = await log2.timed(
16920
+ "GQL auth",
16921
+ () => getAuthenticatedGQLClient({ isSkipPrompts: true })
16922
+ );
16923
+ const cursorForModel = sessionStore.get(cursorKey);
16924
+ let lastSeenModel = cursorForModel?.lastModel ?? null;
16925
+ const records = entries.map((entry) => {
16926
+ const { _recordId, ...rawEntry } = entry;
16927
+ const message = rawEntry["message"];
16928
+ const currentModel = message?.["model"] ?? null;
16929
+ if (currentModel && currentModel !== "<synthetic>") {
16930
+ lastSeenModel = currentModel;
16931
+ } else if (lastSeenModel && !currentModel) {
16932
+ if (message) {
16933
+ message["model"] = lastSeenModel;
16934
+ } else {
16935
+ rawEntry["message"] = { model: lastSeenModel };
16936
+ }
16937
+ }
16938
+ return {
16939
+ platform: "CLAUDE_CODE" /* ClaudeCode */,
16940
+ recordId: _recordId,
16941
+ recordTimestamp: entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
16489
16942
  blameType: "CHAT" /* Chat */,
16490
- sessionId: result.hookData.session_id,
16491
- repositoryUrl
16943
+ rawData: rawEntry
16944
+ };
16945
+ });
16946
+ log2.info("Uploading batch", {
16947
+ count: records.length,
16948
+ skipped: filteredOut,
16949
+ firstRecordId: records[0]?.recordId,
16950
+ lastRecordId: records[records.length - 1]?.recordId
16951
+ });
16952
+ const result = await log2.timed(
16953
+ "Batch upload",
16954
+ () => prepareAndSendTracyRecords(gqlClient, records, hookData.cwd)
16955
+ );
16956
+ if (result.ok) {
16957
+ const lastRawEntry = rawEntries[rawEntries.length - 1];
16958
+ const cursor = {
16959
+ id: lastRawEntry._recordId,
16960
+ byteOffset: fileSize,
16961
+ updatedAt: Date.now(),
16962
+ lastModel: lastSeenModel ?? void 0
16963
+ };
16964
+ sessionStore.set(cursorKey, cursor);
16965
+ log2.heartbeat("Upload ok", {
16966
+ entriesUploaded: entries.length,
16967
+ entriesSkipped: filteredOut
16492
16968
  });
16493
- uploadSuccess = true;
16494
- } catch (error) {
16495
- console.warn(
16496
- "Warning: Failed to upload trace data:",
16497
- error.message
16498
- );
16499
- uploadSuccess = false;
16969
+ return {
16970
+ entriesUploaded: entries.length,
16971
+ entriesSkipped: filteredOut,
16972
+ errors: 0
16973
+ };
16500
16974
  }
16975
+ log2.error("Batch upload had errors", { errors: result.errors });
16501
16976
  return {
16502
- ...result,
16503
- uploadSuccess
16977
+ entriesUploaded: 0,
16978
+ entriesSkipped: filteredOut,
16979
+ errors: entries.length
16504
16980
  };
16505
16981
  }
16506
16982
 
16507
16983
  // src/features/claude_code/install_hook.ts
16508
- import fsPromises5 from "fs/promises";
16509
- import os4 from "os";
16984
+ import fsPromises4 from "fs/promises";
16985
+ import os5 from "os";
16510
16986
  import path14 from "path";
16511
16987
  import chalk11 from "chalk";
16512
- var CLAUDE_SETTINGS_PATH = path14.join(os4.homedir(), ".claude", "settings.json");
16988
+ var CLAUDE_SETTINGS_PATH = path14.join(os5.homedir(), ".claude", "settings.json");
16513
16989
  async function claudeSettingsExists() {
16514
16990
  try {
16515
- await fsPromises5.access(CLAUDE_SETTINGS_PATH);
16991
+ await fsPromises4.access(CLAUDE_SETTINGS_PATH);
16516
16992
  return true;
16517
16993
  } catch {
16518
16994
  return false;
16519
16995
  }
16520
16996
  }
16521
16997
  async function readClaudeSettings() {
16522
- const settingsContent = await fsPromises5.readFile(
16998
+ const settingsContent = await fsPromises4.readFile(
16523
16999
  CLAUDE_SETTINGS_PATH,
16524
17000
  "utf-8"
16525
17001
  );
16526
17002
  return JSON.parse(settingsContent);
16527
17003
  }
16528
17004
  async function writeClaudeSettings(settings) {
16529
- await fsPromises5.writeFile(
17005
+ await fsPromises4.writeFile(
16530
17006
  CLAUDE_SETTINGS_PATH,
16531
17007
  JSON.stringify(settings, null, 2),
16532
17008
  "utf-8"
@@ -16569,7 +17045,8 @@ async function installMobbHooks(options = {}) {
16569
17045
  }
16570
17046
  }
16571
17047
  const mobbHookConfig = {
16572
- matcher: "Edit|Write",
17048
+ // Empty matcher = match all tools (Claude Code hook spec: empty string matches every PostToolUse event)
17049
+ matcher: "",
16573
17050
  hooks: [
16574
17051
  {
16575
17052
  type: "command",
@@ -16578,7 +17055,7 @@ async function installMobbHooks(options = {}) {
16578
17055
  ]
16579
17056
  };
16580
17057
  const existingHookIndex = settings.hooks.PostToolUse.findIndex(
16581
- (hook) => hook.matcher === "Edit|Write" && hook.hooks.some(
17058
+ (hook) => hook.hooks.some(
16582
17059
  (h) => h.command?.includes("mobbdev@latest claude-code-process-hook")
16583
17060
  )
16584
17061
  );
@@ -16628,51 +17105,45 @@ var claudeCodeInstallHookHandler = async (argv) => {
16628
17105
  }
16629
17106
  };
16630
17107
  var claudeCodeProcessHookHandler = async () => {
16631
- try {
16632
- const { hookData, inference, tracePayload, uploadSuccess } = await processAndUploadHookData();
16633
- console.log("Successfully processed Claude Code hook:");
16634
- console.log("Session ID:", hookData.session_id);
16635
- console.log("Tool:", hookData.tool_name);
16636
- console.log("Transcript path:", hookData.transcript_path);
16637
- console.log("Inference length:", inference.length);
16638
- const userPrompts = tracePayload.prompts.filter(
16639
- (p) => p.type === "USER_PROMPT"
16640
- );
16641
- const assistantResponses = tracePayload.prompts.filter(
16642
- (p) => p.type === "AI_RESPONSE"
16643
- );
16644
- const aiThinking = tracePayload.prompts.filter(
16645
- (p) => p.type === "AI_THINKING"
16646
- );
16647
- console.log("Conversation context extracted:");
16648
- console.log("- User prompts:", userPrompts.length);
16649
- console.log("- Assistant responses:", assistantResponses.length);
16650
- console.log("- AI thinking entries:", aiThinking.length);
16651
- console.log("- Model:", tracePayload.model);
16652
- const totalInputTokens = tracePayload.prompts.reduce(
16653
- (sum, p) => sum + (p.tokens?.inputCount || 0),
16654
- 0
16655
- );
16656
- const totalOutputTokens = tracePayload.prompts.reduce(
16657
- (sum, p) => sum + (p.tokens?.outputCount || 0),
16658
- 0
16659
- );
16660
- console.log("- Input tokens:", totalInputTokens);
16661
- console.log("- Output tokens:", totalOutputTokens);
16662
- console.log("Trace data formatted:");
16663
- console.log("- Prompt items:", tracePayload.prompts.length);
16664
- console.log("- Model:", tracePayload.model);
16665
- console.log("- Tool:", tracePayload.tool);
16666
- console.log("- Response time:", tracePayload.responseTime);
16667
- console.log("- Upload success:", uploadSuccess ? "\u2705" : "\u274C");
16668
- if (uploadSuccess) {
16669
- console.log("\u2705 Claude Code trace uploaded successfully to Mobb backend");
17108
+ async function flushAndExit(code) {
17109
+ try {
17110
+ flushLogs();
17111
+ await flushDdLogs();
17112
+ } catch {
17113
+ } finally {
17114
+ process.exit(code);
16670
17115
  }
16671
- process.exit(0);
17116
+ }
17117
+ process.on("uncaughtException", (error) => {
17118
+ hookLog.error("Uncaught exception in hook", {
17119
+ error: String(error),
17120
+ stack: error.stack
17121
+ });
17122
+ void flushAndExit(1);
17123
+ });
17124
+ process.on("unhandledRejection", (reason) => {
17125
+ hookLog.error("Unhandled rejection in hook", {
17126
+ error: String(reason),
17127
+ stack: reason instanceof Error ? reason.stack : void 0
17128
+ });
17129
+ void flushAndExit(1);
17130
+ });
17131
+ let exitCode = 0;
17132
+ try {
17133
+ const result = await processAndUploadTranscriptEntries();
17134
+ hookLog.info("Claude Code upload complete", {
17135
+ entriesUploaded: result.entriesUploaded,
17136
+ entriesSkipped: result.entriesSkipped,
17137
+ errors: result.errors
17138
+ });
16672
17139
  } catch (error) {
16673
- console.error("Failed to process Claude Code hook data:", error);
16674
- process.exit(1);
17140
+ exitCode = 1;
17141
+ hookLog.error("Failed to process Claude Code hook", {
17142
+ error: String(error),
17143
+ stack: error instanceof Error ? error.stack : void 0
17144
+ });
16675
17145
  }
17146
+ await flushAndExit(exitCode);
16676
17147
  };
16677
17148
 
16678
17149
  // src/mcp/core/McpServer.ts
@@ -16686,7 +17157,7 @@ import {
16686
17157
  } from "@modelcontextprotocol/sdk/types.js";
16687
17158
 
16688
17159
  // src/mcp/Logger.ts
16689
- import Configstore2 from "configstore";
17160
+ import Configstore3 from "configstore";
16690
17161
 
16691
17162
  // src/mcp/services/WorkspaceService.ts
16692
17163
  var WorkspaceService = class {
@@ -16772,7 +17243,7 @@ var Logger = class {
16772
17243
  __publicField(this, "lastKnownPath", null);
16773
17244
  this.host = WorkspaceService.getHost();
16774
17245
  this.unknownPathSuffix = Math.floor(1e3 + Math.random() * 9e3).toString();
16775
- this.mobbConfigStore = new Configstore2("mobb-logs", {});
17246
+ this.mobbConfigStore = new Configstore3("mobb-logs", {});
16776
17247
  this.mobbConfigStore.set("version", packageJson.version);
16777
17248
  }
16778
17249
  /**
@@ -16828,12 +17299,12 @@ var Logger = class {
16828
17299
  this.mobbConfigStore.set(currentPath, [...logs, logMessage]);
16829
17300
  }
16830
17301
  };
16831
- var logger = new Logger();
16832
- var logInfo = (message, data) => logger.log(message, "info", data);
16833
- var logError = (message, data) => logger.log(message, "error", data);
16834
- var logWarn = (message, data) => logger.log(message, "warn", data);
16835
- var logDebug = (message, data) => logger.log(message, "debug", data);
16836
- var log = logger.log.bind(logger);
17302
+ var logger2 = new Logger();
17303
+ var logInfo = (message, data) => logger2.log(message, "info", data);
17304
+ var logError = (message, data) => logger2.log(message, "error", data);
17305
+ var logWarn = (message, data) => logger2.log(message, "warn", data);
17306
+ var logDebug = (message, data) => logger2.log(message, "debug", data);
17307
+ var log = logger2.log.bind(logger2);
16837
17308
 
16838
17309
  // src/mcp/services/McpGQLClient.ts
16839
17310
  import crypto2 from "crypto";
@@ -17555,7 +18026,7 @@ async function createAuthenticatedMcpGQLClient({
17555
18026
  // src/mcp/services/McpUsageService/host.ts
17556
18027
  import { execSync as execSync2 } from "child_process";
17557
18028
  import fs13 from "fs";
17558
- import os5 from "os";
18029
+ import os6 from "os";
17559
18030
  import path15 from "path";
17560
18031
  var IDEs = ["cursor", "windsurf", "webstorm", "vscode", "claude"];
17561
18032
  var runCommand = (cmd) => {
@@ -17570,7 +18041,7 @@ var gitInfo = {
17570
18041
  email: runCommand("git config user.email")
17571
18042
  };
17572
18043
  var getClaudeWorkspacePaths = () => {
17573
- const home = os5.homedir();
18044
+ const home = os6.homedir();
17574
18045
  const claudeIdePath = path15.join(home, ".claude", "ide");
17575
18046
  const workspacePaths = [];
17576
18047
  if (!fs13.existsSync(claudeIdePath)) {
@@ -17599,7 +18070,7 @@ var getClaudeWorkspacePaths = () => {
17599
18070
  return workspacePaths;
17600
18071
  };
17601
18072
  var getMCPConfigPaths = (hostName) => {
17602
- const home = os5.homedir();
18073
+ const home = os6.homedir();
17603
18074
  const currentDir = process.env["WORKSPACE_FOLDER_PATHS"] || process.env["PWD"] || process.cwd();
17604
18075
  switch (hostName.toLowerCase()) {
17605
18076
  case "cursor":
@@ -17689,7 +18160,7 @@ var readMCPConfig = (hostName) => {
17689
18160
  };
17690
18161
  var getRunningProcesses = () => {
17691
18162
  try {
17692
- return os5.platform() === "win32" ? execSync2("tasklist", { encoding: "utf8" }) : execSync2("ps aux", { encoding: "utf8" });
18163
+ return os6.platform() === "win32" ? execSync2("tasklist", { encoding: "utf8" }) : execSync2("ps aux", { encoding: "utf8" });
17693
18164
  } catch {
17694
18165
  return "";
17695
18166
  }
@@ -17764,7 +18235,7 @@ var versionCommands = {
17764
18235
  }
17765
18236
  };
17766
18237
  var getProcessInfo = (pid) => {
17767
- const platform2 = os5.platform();
18238
+ const platform2 = os6.platform();
17768
18239
  try {
17769
18240
  if (platform2 === "linux" || platform2 === "darwin") {
17770
18241
  const output = execSync2(`ps -o pid=,ppid=,comm= -p ${pid}`, {
@@ -17883,7 +18354,7 @@ var getHostInfo = (additionalMcpList) => {
17883
18354
  const config2 = allConfigs[ide] || null;
17884
18355
  const ideName = ide.charAt(0).toUpperCase() + ide.slice(1) || "Unknown";
17885
18356
  let ideVersion = "Unknown";
17886
- const platform2 = os5.platform();
18357
+ const platform2 = os6.platform();
17887
18358
  const cmds = versionCommands[ideName]?.[platform2] ?? [];
17888
18359
  for (const cmd of cmds) {
17889
18360
  try {
@@ -17915,15 +18386,15 @@ var getHostInfo = (additionalMcpList) => {
17915
18386
  };
17916
18387
 
17917
18388
  // src/mcp/services/McpUsageService/McpUsageService.ts
17918
- import fetch5 from "node-fetch";
17919
- import os7 from "os";
18389
+ import fetch6 from "node-fetch";
18390
+ import os8 from "os";
17920
18391
  import { v4 as uuidv42, v5 as uuidv5 } from "uuid";
17921
18392
  init_configs();
17922
18393
 
17923
18394
  // src/mcp/services/McpUsageService/system.ts
17924
18395
  init_configs();
17925
18396
  import fs14 from "fs";
17926
- import os6 from "os";
18397
+ import os7 from "os";
17927
18398
  import path16 from "path";
17928
18399
  var MAX_DEPTH = 2;
17929
18400
  var patterns = ["mcp", "claude"];
@@ -17958,8 +18429,8 @@ var searchDir = async (dir, depth = 0) => {
17958
18429
  };
17959
18430
  var findSystemMCPConfigs = async () => {
17960
18431
  try {
17961
- const home = os6.homedir();
17962
- const platform2 = os6.platform();
18432
+ const home = os7.homedir();
18433
+ const platform2 = os7.platform();
17963
18434
  const knownDirs = platform2 === "win32" ? [
17964
18435
  path16.join(home, ".cursor"),
17965
18436
  path16.join(home, "Documents"),
@@ -18031,7 +18502,7 @@ var McpUsageService = class {
18031
18502
  generateHostId() {
18032
18503
  const stored = configStore.get(this.configKey);
18033
18504
  if (stored?.mcpHostId) return stored.mcpHostId;
18034
- const interfaces = os7.networkInterfaces();
18505
+ const interfaces = os8.networkInterfaces();
18035
18506
  const macs = [];
18036
18507
  for (const iface of Object.values(interfaces)) {
18037
18508
  if (!iface) continue;
@@ -18039,7 +18510,7 @@ var McpUsageService = class {
18039
18510
  if (net.mac && net.mac !== "00:00:00:00:00:00") macs.push(net.mac);
18040
18511
  }
18041
18512
  }
18042
- const macString = macs.length ? macs.sort().join(",") : `${os7.hostname()}-${uuidv42()}`;
18513
+ const macString = macs.length ? macs.sort().join(",") : `${os8.hostname()}-${uuidv42()}`;
18043
18514
  const hostId = uuidv5(macString, uuidv5.DNS);
18044
18515
  logDebug("[UsageService] Generated new host ID", { hostId });
18045
18516
  return hostId;
@@ -18062,7 +18533,7 @@ var McpUsageService = class {
18062
18533
  mcpHostId,
18063
18534
  organizationId,
18064
18535
  mcpVersion: packageJson.version,
18065
- mcpOsName: os7.platform(),
18536
+ mcpOsName: os8.platform(),
18066
18537
  mcps: JSON.stringify(mcps),
18067
18538
  status,
18068
18539
  userName: user.name,
@@ -18102,7 +18573,7 @@ var McpUsageService = class {
18102
18573
  }
18103
18574
  logDebug("[UsageService] Before", { usageData });
18104
18575
  try {
18105
- const res = await fetch5(this.REST_API_URL, {
18576
+ const res = await fetch6(this.REST_API_URL, {
18106
18577
  method: "POST",
18107
18578
  headers: {
18108
18579
  Accept: "application/json"
@@ -20383,22 +20854,22 @@ For a complete security audit workflow, use the \`full-security-audit\` prompt.
20383
20854
 
20384
20855
  // src/mcp/services/McpDetectionService/CursorMcpDetectionService.ts
20385
20856
  import * as fs17 from "fs";
20386
- import * as os9 from "os";
20857
+ import * as os10 from "os";
20387
20858
  import * as path18 from "path";
20388
20859
 
20389
20860
  // src/mcp/services/McpDetectionService/BaseMcpDetectionService.ts
20390
20861
  init_configs();
20391
20862
  import * as fs16 from "fs";
20392
- import fetch6 from "node-fetch";
20863
+ import fetch7 from "node-fetch";
20393
20864
  import * as path17 from "path";
20394
20865
 
20395
20866
  // src/mcp/services/McpDetectionService/McpDetectionServiceUtils.ts
20396
20867
  import * as fs15 from "fs";
20397
- import * as os8 from "os";
20868
+ import * as os9 from "os";
20398
20869
 
20399
20870
  // src/mcp/services/McpDetectionService/VscodeMcpDetectionService.ts
20400
20871
  import * as fs18 from "fs";
20401
- import * as os10 from "os";
20872
+ import * as os11 from "os";
20402
20873
  import * as path19 from "path";
20403
20874
 
20404
20875
  // src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesTool.ts
@@ -21956,7 +22427,7 @@ import {
21956
22427
  mkdirSync,
21957
22428
  readFileSync as readFileSync3,
21958
22429
  unlinkSync,
21959
- writeFileSync
22430
+ writeFileSync as writeFileSync2
21960
22431
  } from "fs";
21961
22432
  import fs22 from "fs/promises";
21962
22433
  import parseDiff2 from "parse-diff";
@@ -22177,7 +22648,7 @@ var PatchApplicationService = class {
22177
22648
  }
22178
22649
  const dirPath = path22.dirname(normalizedFilePath);
22179
22650
  mkdirSync(dirPath, { recursive: true });
22180
- writeFileSync(normalizedFilePath, finalContent, "utf8");
22651
+ writeFileSync2(normalizedFilePath, finalContent, "utf8");
22181
22652
  return normalizedFilePath;
22182
22653
  }
22183
22654
  static resolvePathWithinRepo({
@@ -24843,18 +25314,18 @@ async function getGrpcClient(port, csrf3) {
24843
25314
 
24844
25315
  // src/features/codeium_intellij/parse_intellij_logs.ts
24845
25316
  import fs25 from "fs";
24846
- import os11 from "os";
25317
+ import os12 from "os";
24847
25318
  import path25 from "path";
24848
25319
  function getLogsDir() {
24849
25320
  if (process.platform === "darwin") {
24850
- return path25.join(os11.homedir(), "Library/Logs/JetBrains");
25321
+ return path25.join(os12.homedir(), "Library/Logs/JetBrains");
24851
25322
  } else if (process.platform === "win32") {
24852
25323
  return path25.join(
24853
- process.env["LOCALAPPDATA"] || path25.join(os11.homedir(), "AppData/Local"),
25324
+ process.env["LOCALAPPDATA"] || path25.join(os12.homedir(), "AppData/Local"),
24854
25325
  "JetBrains"
24855
25326
  );
24856
25327
  } else {
24857
- return path25.join(os11.homedir(), ".cache/JetBrains");
25328
+ return path25.join(os12.homedir(), ".cache/JetBrains");
24858
25329
  }
24859
25330
  }
24860
25331
  function parseIdeLogDir(ideLogDir) {
@@ -24912,7 +25383,7 @@ function findRunningCodeiumLanguageServers() {
24912
25383
  var HookDataSchema2 = z47.object({
24913
25384
  trajectory_id: z47.string()
24914
25385
  });
24915
- async function processAndUploadHookData2() {
25386
+ async function processAndUploadHookData() {
24916
25387
  const tracePayload = await getTraceDataForHook();
24917
25388
  if (!tracePayload) {
24918
25389
  console.warn("Warning: Failed to retrieve chat data.");
@@ -25076,17 +25547,17 @@ function processChatStepCodeAction(step) {
25076
25547
  }
25077
25548
 
25078
25549
  // src/features/codeium_intellij/install_hook.ts
25079
- import fsPromises6 from "fs/promises";
25080
- import os12 from "os";
25550
+ import fsPromises5 from "fs/promises";
25551
+ import os13 from "os";
25081
25552
  import path26 from "path";
25082
25553
  import chalk14 from "chalk";
25083
25554
  function getCodeiumHooksPath() {
25084
- return path26.join(os12.homedir(), ".codeium", "hooks.json");
25555
+ return path26.join(os13.homedir(), ".codeium", "hooks.json");
25085
25556
  }
25086
25557
  async function readCodeiumHooks() {
25087
25558
  const hooksPath = getCodeiumHooksPath();
25088
25559
  try {
25089
- const content = await fsPromises6.readFile(hooksPath, "utf-8");
25560
+ const content = await fsPromises5.readFile(hooksPath, "utf-8");
25090
25561
  return JSON.parse(content);
25091
25562
  } catch {
25092
25563
  return {};
@@ -25095,8 +25566,8 @@ async function readCodeiumHooks() {
25095
25566
  async function writeCodeiumHooks(config2) {
25096
25567
  const hooksPath = getCodeiumHooksPath();
25097
25568
  const dir = path26.dirname(hooksPath);
25098
- await fsPromises6.mkdir(dir, { recursive: true });
25099
- await fsPromises6.writeFile(
25569
+ await fsPromises5.mkdir(dir, { recursive: true });
25570
+ await fsPromises5.writeFile(
25100
25571
  hooksPath,
25101
25572
  JSON.stringify(config2, null, 2),
25102
25573
  "utf-8"
@@ -25184,7 +25655,7 @@ var windsurfIntellijInstallHookHandler = async (argv) => {
25184
25655
  };
25185
25656
  var windsurfIntellijProcessHookHandler = async () => {
25186
25657
  try {
25187
- await processAndUploadHookData2();
25658
+ await processAndUploadHookData();
25188
25659
  process.exit(0);
25189
25660
  } catch (error) {
25190
25661
  console.error("Failed to process Windsurf IntelliJ hook data:", error);