mobbdev 1.2.54 → 1.2.56

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;
@@ -13510,7 +13519,7 @@ async function uploadAiBlameHandler(options) {
13510
13519
  exitOnError = true,
13511
13520
  apiUrl,
13512
13521
  webAppUrl,
13513
- logger: logger2 = defaultLogger2
13522
+ logger: logger3 = defaultLogger2
13514
13523
  } = options;
13515
13524
  const prompts = args.prompt || [];
13516
13525
  const inferences = args.inference || [];
@@ -13521,7 +13530,7 @@ async function uploadAiBlameHandler(options) {
13521
13530
  const sessionIds = args.sessionId || args["session-id"] || [];
13522
13531
  if (prompts.length !== inferences.length) {
13523
13532
  const errorMsg = "prompt and inference must have the same number of entries";
13524
- logger2.error(chalk4.red(errorMsg));
13533
+ logger3.error(chalk4.red(errorMsg));
13525
13534
  if (exitOnError) {
13526
13535
  process.exit(1);
13527
13536
  }
@@ -13541,7 +13550,7 @@ async function uploadAiBlameHandler(options) {
13541
13550
  ]);
13542
13551
  } catch {
13543
13552
  const errorMsg = `File not found for session ${i + 1}`;
13544
- logger2.error(chalk4.red(errorMsg));
13553
+ logger3.error(chalk4.red(errorMsg));
13545
13554
  if (exitOnError) {
13546
13555
  process.exit(1);
13547
13556
  }
@@ -13574,7 +13583,7 @@ async function uploadAiBlameHandler(options) {
13574
13583
  const uploadSessions = initRes.uploadAIBlameInferencesInit?.uploadSessions ?? [];
13575
13584
  if (uploadSessions.length !== sessions.length) {
13576
13585
  const errorMsg = "Init failed to return expected number of sessions";
13577
- logger2.error(chalk4.red(errorMsg));
13586
+ logger3.error(chalk4.red(errorMsg));
13578
13587
  if (exitOnError) {
13579
13588
  process.exit(1);
13580
13589
  }
@@ -13618,7 +13627,7 @@ async function uploadAiBlameHandler(options) {
13618
13627
  };
13619
13628
  });
13620
13629
  try {
13621
- logger2.info(
13630
+ logger3.info(
13622
13631
  `[UPLOAD] Calling finalizeAIBlameInferencesUploadRaw with ${finalizeSessions.length} sessions`
13623
13632
  );
13624
13633
  const finRes = await authenticatedClient.finalizeAIBlameInferencesUploadRaw(
@@ -13626,11 +13635,11 @@ async function uploadAiBlameHandler(options) {
13626
13635
  sessions: finalizeSessions
13627
13636
  }
13628
13637
  );
13629
- logger2.info("[UPLOAD] Finalize response:", JSON.stringify(finRes, null, 2));
13638
+ logger3.info("[UPLOAD] Finalize response:", JSON.stringify(finRes, null, 2));
13630
13639
  const status = finRes?.finalizeAIBlameInferencesUpload?.status;
13631
13640
  if (status !== "OK") {
13632
13641
  const errorMsg = finRes?.finalizeAIBlameInferencesUpload?.error || "unknown error";
13633
- logger2.error(
13642
+ logger3.error(
13634
13643
  chalk4.red(
13635
13644
  `[UPLOAD] Finalize failed with status: ${status}, error: ${errorMsg}`
13636
13645
  )
@@ -13640,9 +13649,9 @@ async function uploadAiBlameHandler(options) {
13640
13649
  }
13641
13650
  throw new Error(errorMsg);
13642
13651
  }
13643
- logger2.info(chalk4.green("[UPLOAD] AI Blame uploads finalized successfully"));
13652
+ logger3.info(chalk4.green("[UPLOAD] AI Blame uploads finalized successfully"));
13644
13653
  } catch (error) {
13645
- logger2.error("[UPLOAD] Finalize threw error:", error);
13654
+ logger3.error("[UPLOAD] Finalize threw error:", error);
13646
13655
  throw error;
13647
13656
  }
13648
13657
  }
@@ -13652,6 +13661,110 @@ async function uploadAiBlameCommandHandler(args) {
13652
13661
 
13653
13662
  // src/features/analysis/graphql/tracy-batch-upload.ts
13654
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
+ }
13655
13768
 
13656
13769
  // src/mcp/services/types.ts
13657
13770
  function detectIDE() {
@@ -14869,8 +14982,8 @@ if (typeof __filename !== "undefined") {
14869
14982
  }
14870
14983
  var costumeRequire = createRequire(moduleUrl);
14871
14984
  var getCheckmarxPath = () => {
14872
- const os13 = type();
14873
- const cxFileName = os13 === "Windows_NT" ? "cx.exe" : "cx";
14985
+ const os14 = type();
14986
+ const cxFileName = os14 === "Windows_NT" ? "cx.exe" : "cx";
14874
14987
  try {
14875
14988
  return costumeRequire.resolve(`.bin/${cxFileName}`);
14876
14989
  } catch (e) {
@@ -16183,229 +16296,383 @@ async function analyzeHandler(args) {
16183
16296
  }
16184
16297
 
16185
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";
16186
16302
  import { z as z33 } from "zod";
16187
16303
  init_client_generates();
16188
- init_GitService();
16189
- init_urlParser2();
16190
16304
 
16191
- // src/utils/computeGitDiffAdditions.ts
16192
- import { mkdtemp, rm, writeFile } from "fs/promises";
16193
- import { tmpdir } from "os";
16194
- import path13 from "path";
16195
- import { simpleGit as simpleGit4 } from "simple-git";
16196
- async function computeGitDiffAdditions(oldStr, newStr) {
16197
- const tmpDir = await mkdtemp(path13.join(tmpdir(), "diff-"));
16198
- const oldFile = path13.join(tmpDir, "old");
16199
- const newFile = path13.join(tmpDir, "new");
16200
- try {
16201
- await writeFile(oldFile, oldStr);
16202
- await writeFile(newFile, newStr);
16203
- const git = simpleGit4();
16204
- 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) {
16205
16326
  try {
16206
- result = await git.raw([
16207
- "diff",
16208
- "--no-index",
16209
- "--unified=0",
16210
- oldFile,
16211
- newFile
16212
- ]);
16213
- } catch (err) {
16214
- if (err instanceof Error && "stdOut" in err) {
16215
- result = err.stdOut;
16216
- } else {
16217
- 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 {
16337
+ }
16338
+ }
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 {
16218
16369
  }
16219
16370
  }
16220
- const additions = [];
16221
- for (const line of result.split("\n")) {
16222
- if (line.startsWith("+") && !line.startsWith("+++")) {
16223
- additions.push(line.slice(1));
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();
16224
16432
  }
16225
16433
  }
16226
- return additions.join("\n");
16227
- } finally {
16228
- await rm(tmpDir, { recursive: true, force: true });
16434
+ if (batch.length >= DD_BATCH_MAX_SIZE) {
16435
+ flush();
16436
+ }
16229
16437
  }
16438
+ async function flushAsync() {
16439
+ flush();
16440
+ await pendingFlush;
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 };
16230
16458
  }
16231
16459
 
16232
- // src/features/claude_code/transcript_parser.ts
16233
- import fsPromises4 from "fs/promises";
16234
- function processTranscriptLine(entry) {
16235
- const prompts = [];
16236
- let model;
16237
- let inputTokens = 0;
16238
- let outputTokens = 0;
16239
- let date;
16240
- if (entry.message?.model) {
16241
- model = entry.message.model;
16242
- }
16243
- if (entry.message?.usage) {
16244
- inputTokens = entry.message.usage.input_tokens || 0;
16245
- outputTokens = entry.message.usage.output_tokens || 0;
16246
- }
16247
- if (entry.timestamp) {
16248
- date = new Date(entry.timestamp);
16249
- }
16250
- if (entry.type === "user" && entry.message?.role === "user") {
16251
- if (typeof entry.message.content === "string") {
16252
- prompts.push({
16253
- type: "USER_PROMPT",
16254
- text: entry.message.content,
16255
- date: date || /* @__PURE__ */ new Date(),
16256
- tokens: inputTokens > 0 ? {
16257
- inputCount: inputTokens,
16258
- outputCount: 0
16259
- } : void 0
16260
- });
16261
- }
16262
- } else if (entry.type === "assistant" && entry.message?.role === "assistant") {
16263
- if (Array.isArray(entry.message.content)) {
16264
- for (const item of entry.message.content) {
16265
- if (item.type === "text" && item.text) {
16266
- prompts.push({
16267
- type: "AI_RESPONSE",
16268
- text: item.text,
16269
- date: date || /* @__PURE__ */ new Date(),
16270
- tokens: outputTokens > 0 ? {
16271
- inputCount: 0,
16272
- outputCount: outputTokens
16273
- } : void 0
16274
- });
16275
- } else if (item.type === "thinking" && item.thinking) {
16276
- prompts.push({
16277
- type: "AI_THINKING",
16278
- text: item.thinking,
16279
- date: date || /* @__PURE__ */ new Date()
16280
- });
16281
- }
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 })
16282
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;
16283
16555
  }
16284
16556
  }
16285
- return {
16286
- prompts,
16287
- model,
16288
- inputTokens,
16289
- outputTokens,
16290
- date
16291
- };
16292
- }
16293
- async function parseTranscriptAndCreateTrace(transcriptPath, hookData, inference) {
16294
- const content = await fsPromises4.readFile(transcriptPath, "utf-8");
16295
- const lines = content.trim().split("\n");
16296
- let currentToolIndex = -1;
16297
- for (let i = lines.length - 1; i >= 0; i--) {
16298
- const line = lines[i]?.trim() ?? "";
16299
- if (!line.includes('"type":"tool_use"')) continue;
16300
- const isEditTool = line.includes('"name":"Edit"');
16301
- const isWriteTool = line.includes('"name":"Write"');
16302
- if (isEditTool || isWriteTool) {
16303
- currentToolIndex = i;
16304
- break;
16557
+ function flushLogs2() {
16558
+ csStream.flush();
16559
+ }
16560
+ async function flushDdAsync() {
16561
+ if (ddBatch) {
16562
+ await ddBatch.flushAsync();
16305
16563
  }
16306
16564
  }
16307
- const startIndex = 0;
16308
- const endIndex = currentToolIndex === -1 ? lines.length - 1 : currentToolIndex - 1;
16309
- const prompts = [];
16310
- let model;
16311
- let latestDate;
16312
- for (let i = startIndex; i <= endIndex; i++) {
16313
- const line = lines[i]?.trim() ?? "";
16314
- const entry = JSON.parse(line);
16315
- const lineResult = processTranscriptLine(entry);
16316
- prompts.push(...lineResult.prompts);
16317
- if (lineResult.model && !model) {
16318
- model = lineResult.model;
16319
- }
16320
- if (lineResult.date) {
16321
- if (!latestDate || lineResult.date > latestDate) {
16322
- latestDate = lineResult.date;
16323
- }
16324
- }
16325
- }
16326
- prompts.push({
16327
- type: "TOOL_EXECUTION",
16328
- date: latestDate || /* @__PURE__ */ new Date(),
16329
- tool: {
16330
- name: hookData.tool_name,
16331
- parameters: JSON.stringify(hookData.tool_input, null, 2),
16332
- result: JSON.stringify(hookData.tool_response, null, 2),
16333
- rawArguments: JSON.stringify(hookData.tool_input),
16334
- accepted: true
16565
+ function disposeDd() {
16566
+ if (ddBatch) {
16567
+ ddBatch.dispose();
16335
16568
  }
16336
- });
16569
+ }
16337
16570
  return {
16338
- prompts,
16339
- inference,
16340
- model: model || "claude-sonnet-4",
16341
- // Use extracted model or fallback
16342
- tool: "Claude Code",
16343
- 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
16344
16581
  };
16345
16582
  }
16346
16583
 
16584
+ // src/features/claude_code/hook_logger.ts
16585
+ var DD_RUM_TOKEN = true ? "pubf59c0182545bfb4c299175119f1abf9b" : "";
16586
+ var CLI_VERSION = true ? "1.2.56" : "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
+
16347
16624
  // src/features/claude_code/data_collector.ts
16348
- var StructuredPatchItemSchema = z33.object({
16349
- oldStart: z33.number(),
16350
- oldLines: z33.number(),
16351
- newStart: z33.number(),
16352
- newLines: z33.number(),
16353
- lines: z33.array(z33.string())
16354
- });
16355
- var EditToolInputSchema = z33.object({
16356
- file_path: z33.string(),
16357
- old_string: z33.string(),
16358
- new_string: z33.string()
16359
- });
16360
- var WriteToolInputSchema = z33.object({
16361
- file_path: z33.string(),
16362
- content: z33.string()
16363
- });
16364
- var EditToolResponseSchema = z33.object({
16365
- filePath: z33.string(),
16366
- oldString: z33.string().optional(),
16367
- newString: z33.string().optional(),
16368
- originalFile: z33.string().optional(),
16369
- structuredPatch: z33.array(StructuredPatchItemSchema),
16370
- userModified: z33.boolean().optional(),
16371
- replaceAll: z33.boolean().optional()
16372
- });
16373
- var WriteToolResponseSchema = z33.object({
16374
- type: z33.string().optional(),
16375
- filePath: z33.string(),
16376
- content: z33.string().optional(),
16377
- structuredPatch: z33.array(z33.any()).optional()
16378
- });
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";
16379
16629
  var HookDataSchema = z33.object({
16380
16630
  session_id: z33.string(),
16381
16631
  transcript_path: z33.string(),
16382
16632
  cwd: z33.string(),
16383
- permission_mode: z33.string().optional(),
16384
- hook_event_name: z33.literal("PostToolUse"),
16385
- tool_name: z33.enum(["Edit", "Write"]),
16386
- tool_input: z33.union([EditToolInputSchema, WriteToolInputSchema]),
16387
- 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()
16388
16637
  });
16638
+ var STDIN_TIMEOUT_MS = 1e4;
16389
16639
  async function readStdinData() {
16640
+ hookLog.debug("Reading stdin data");
16390
16641
  return new Promise((resolve, reject) => {
16391
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);
16392
16651
  process.stdin.setEncoding("utf-8");
16393
16652
  process.stdin.on("data", (chunk) => {
16394
16653
  inputData += chunk;
16395
16654
  });
16396
16655
  process.stdin.on("end", () => {
16656
+ if (settled) return;
16657
+ settled = true;
16658
+ clearTimeout(timer);
16397
16659
  try {
16398
16660
  const parsedData = JSON.parse(inputData);
16661
+ hookLog.debug("Parsed stdin data", {
16662
+ keys: Object.keys(parsedData)
16663
+ });
16399
16664
  resolve(parsedData);
16400
16665
  } catch (error) {
16401
- reject(
16402
- new Error(
16403
- `Failed to parse JSON from stdin: ${error.message}`
16404
- )
16405
- );
16666
+ const msg = `Failed to parse JSON from stdin: ${error.message}`;
16667
+ hookLog.error(msg);
16668
+ reject(new Error(msg));
16406
16669
  }
16407
16670
  });
16408
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 });
16409
16676
  reject(new Error(`Error reading from stdin: ${error.message}`));
16410
16677
  });
16411
16678
  });
@@ -16413,144 +16680,329 @@ async function readStdinData() {
16413
16680
  function validateHookData(data) {
16414
16681
  return HookDataSchema.parse(data);
16415
16682
  }
16416
- function extractStructuredPatchAdditions(hookData) {
16417
- const editResponse = hookData.tool_response;
16418
- const additions = [];
16419
- for (const patch of editResponse.structuredPatch) {
16420
- for (const line of patch.lines) {
16421
- if (line.startsWith("+")) {
16422
- additions.push(line.slice(1));
16423
- }
16424
- }
16425
- }
16426
- return additions.join("\n");
16427
- }
16428
- async function extractInference(hookData) {
16429
- if (hookData.tool_name === "Write") {
16430
- const writeInput = hookData.tool_input;
16431
- return writeInput.content || "";
16432
- }
16433
- if (hookData.tool_name === "Edit") {
16434
- 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");
16435
16699
  try {
16436
- return await computeGitDiffAdditions(
16437
- editInput.old_string,
16438
- 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
16439
16738
  );
16739
+ parsed.push({ ...entry, _recordId: recordId });
16440
16740
  } catch {
16441
- return extractStructuredPatchAdditions(hookData);
16741
+ malformedLines++;
16442
16742
  }
16443
16743
  }
16444
- 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 };
16445
16819
  }
16446
- async function collectHookData() {
16447
- const rawData = await readStdinData();
16448
- const hookData = validateHookData(rawData);
16449
- const inference = await extractInference(hookData);
16450
- 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);
16451
16828
  try {
16452
- tracePayload = await parseTranscriptAndCreateTrace(
16453
- hookData.transcript_path,
16454
- hookData,
16455
- inference
16456
- );
16457
- } catch (error) {
16458
- console.warn(
16459
- "Warning: Could not parse transcript:",
16460
- error.message
16461
- );
16462
- tracePayload = {
16463
- prompts: [
16464
- {
16465
- type: "TOOL_EXECUTION",
16466
- date: /* @__PURE__ */ new Date(),
16467
- tool: {
16468
- name: hookData.tool_name,
16469
- parameters: JSON.stringify(hookData.tool_input, null, 2),
16470
- result: JSON.stringify(hookData.tool_response, null, 2),
16471
- rawArguments: JSON.stringify(hookData.tool_input),
16472
- 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;
16473
16844
  }
16474
16845
  }
16475
- ],
16476
- inference,
16477
- model: "claude-sonnet-4",
16478
- tool: "Claude Code",
16479
- responseTime: (/* @__PURE__ */ new Date()).toISOString()
16480
- };
16481
- }
16482
- return {
16483
- hookData,
16484
- inference,
16485
- tracePayload
16486
- };
16487
- }
16488
- async function getRepositoryUrl2(cwd) {
16489
- try {
16490
- const gitService = new GitService(cwd);
16491
- const isRepo = await gitService.isGitRepository();
16492
- if (!isRepo) {
16493
- 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 });
16494
16855
  }
16495
- const remoteUrl = await gitService.getRemoteUrl();
16496
- const parsed = parseScmURL(remoteUrl);
16497
- return parsed?.scmType === "GitHub" /* GitHub */ || parsed?.scmType === "GitLab" /* GitLab */ ? remoteUrl : null;
16498
16856
  } catch {
16499
- return null;
16500
16857
  }
16858
+ configStore.set("claudeCode.lastCleanupAt", now);
16501
16859
  }
16502
- async function processAndUploadHookData() {
16503
- const result = await collectHookData();
16504
- const repositoryUrl = await getRepositoryUrl2(result.hookData.cwd);
16505
- 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
+ });
16506
16878
  try {
16507
- await uploadAiBlameHandlerFromExtension({
16508
- prompts: result.tracePayload.prompts,
16509
- inference: result.tracePayload.inference,
16510
- model: result.tracePayload.model,
16511
- tool: result.tracePayload.tool,
16512
- 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(),
16513
16942
  blameType: "CHAT" /* Chat */,
16514
- sessionId: result.hookData.session_id,
16515
- 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
16516
16968
  });
16517
- uploadSuccess = true;
16518
- } catch (error) {
16519
- console.warn(
16520
- "Warning: Failed to upload trace data:",
16521
- error.message
16522
- );
16523
- uploadSuccess = false;
16969
+ return {
16970
+ entriesUploaded: entries.length,
16971
+ entriesSkipped: filteredOut,
16972
+ errors: 0
16973
+ };
16524
16974
  }
16975
+ log2.error("Batch upload had errors", { errors: result.errors });
16525
16976
  return {
16526
- ...result,
16527
- uploadSuccess
16977
+ entriesUploaded: 0,
16978
+ entriesSkipped: filteredOut,
16979
+ errors: entries.length
16528
16980
  };
16529
16981
  }
16530
16982
 
16531
16983
  // src/features/claude_code/install_hook.ts
16532
- import fsPromises5 from "fs/promises";
16533
- import os4 from "os";
16984
+ import fsPromises4 from "fs/promises";
16985
+ import os5 from "os";
16534
16986
  import path14 from "path";
16535
16987
  import chalk11 from "chalk";
16536
- var CLAUDE_SETTINGS_PATH = path14.join(os4.homedir(), ".claude", "settings.json");
16988
+ var CLAUDE_SETTINGS_PATH = path14.join(os5.homedir(), ".claude", "settings.json");
16537
16989
  async function claudeSettingsExists() {
16538
16990
  try {
16539
- await fsPromises5.access(CLAUDE_SETTINGS_PATH);
16991
+ await fsPromises4.access(CLAUDE_SETTINGS_PATH);
16540
16992
  return true;
16541
16993
  } catch {
16542
16994
  return false;
16543
16995
  }
16544
16996
  }
16545
16997
  async function readClaudeSettings() {
16546
- const settingsContent = await fsPromises5.readFile(
16998
+ const settingsContent = await fsPromises4.readFile(
16547
16999
  CLAUDE_SETTINGS_PATH,
16548
17000
  "utf-8"
16549
17001
  );
16550
17002
  return JSON.parse(settingsContent);
16551
17003
  }
16552
17004
  async function writeClaudeSettings(settings) {
16553
- await fsPromises5.writeFile(
17005
+ await fsPromises4.writeFile(
16554
17006
  CLAUDE_SETTINGS_PATH,
16555
17007
  JSON.stringify(settings, null, 2),
16556
17008
  "utf-8"
@@ -16593,7 +17045,8 @@ async function installMobbHooks(options = {}) {
16593
17045
  }
16594
17046
  }
16595
17047
  const mobbHookConfig = {
16596
- matcher: "Edit|Write",
17048
+ // Empty matcher = match all tools (Claude Code hook spec: empty string matches every PostToolUse event)
17049
+ matcher: "",
16597
17050
  hooks: [
16598
17051
  {
16599
17052
  type: "command",
@@ -16602,7 +17055,7 @@ async function installMobbHooks(options = {}) {
16602
17055
  ]
16603
17056
  };
16604
17057
  const existingHookIndex = settings.hooks.PostToolUse.findIndex(
16605
- (hook) => hook.matcher === "Edit|Write" && hook.hooks.some(
17058
+ (hook) => hook.hooks.some(
16606
17059
  (h) => h.command?.includes("mobbdev@latest claude-code-process-hook")
16607
17060
  )
16608
17061
  );
@@ -16652,51 +17105,45 @@ var claudeCodeInstallHookHandler = async (argv) => {
16652
17105
  }
16653
17106
  };
16654
17107
  var claudeCodeProcessHookHandler = async () => {
16655
- try {
16656
- const { hookData, inference, tracePayload, uploadSuccess } = await processAndUploadHookData();
16657
- console.log("Successfully processed Claude Code hook:");
16658
- console.log("Session ID:", hookData.session_id);
16659
- console.log("Tool:", hookData.tool_name);
16660
- console.log("Transcript path:", hookData.transcript_path);
16661
- console.log("Inference length:", inference.length);
16662
- const userPrompts = tracePayload.prompts.filter(
16663
- (p) => p.type === "USER_PROMPT"
16664
- );
16665
- const assistantResponses = tracePayload.prompts.filter(
16666
- (p) => p.type === "AI_RESPONSE"
16667
- );
16668
- const aiThinking = tracePayload.prompts.filter(
16669
- (p) => p.type === "AI_THINKING"
16670
- );
16671
- console.log("Conversation context extracted:");
16672
- console.log("- User prompts:", userPrompts.length);
16673
- console.log("- Assistant responses:", assistantResponses.length);
16674
- console.log("- AI thinking entries:", aiThinking.length);
16675
- console.log("- Model:", tracePayload.model);
16676
- const totalInputTokens = tracePayload.prompts.reduce(
16677
- (sum, p) => sum + (p.tokens?.inputCount || 0),
16678
- 0
16679
- );
16680
- const totalOutputTokens = tracePayload.prompts.reduce(
16681
- (sum, p) => sum + (p.tokens?.outputCount || 0),
16682
- 0
16683
- );
16684
- console.log("- Input tokens:", totalInputTokens);
16685
- console.log("- Output tokens:", totalOutputTokens);
16686
- console.log("Trace data formatted:");
16687
- console.log("- Prompt items:", tracePayload.prompts.length);
16688
- console.log("- Model:", tracePayload.model);
16689
- console.log("- Tool:", tracePayload.tool);
16690
- console.log("- Response time:", tracePayload.responseTime);
16691
- console.log("- Upload success:", uploadSuccess ? "\u2705" : "\u274C");
16692
- if (uploadSuccess) {
16693
- 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);
16694
17115
  }
16695
- 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
+ });
16696
17139
  } catch (error) {
16697
- console.error("Failed to process Claude Code hook data:", error);
16698
- 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
+ });
16699
17145
  }
17146
+ await flushAndExit(exitCode);
16700
17147
  };
16701
17148
 
16702
17149
  // src/mcp/core/McpServer.ts
@@ -16710,7 +17157,7 @@ import {
16710
17157
  } from "@modelcontextprotocol/sdk/types.js";
16711
17158
 
16712
17159
  // src/mcp/Logger.ts
16713
- import Configstore2 from "configstore";
17160
+ import Configstore3 from "configstore";
16714
17161
 
16715
17162
  // src/mcp/services/WorkspaceService.ts
16716
17163
  var WorkspaceService = class {
@@ -16796,7 +17243,7 @@ var Logger = class {
16796
17243
  __publicField(this, "lastKnownPath", null);
16797
17244
  this.host = WorkspaceService.getHost();
16798
17245
  this.unknownPathSuffix = Math.floor(1e3 + Math.random() * 9e3).toString();
16799
- this.mobbConfigStore = new Configstore2("mobb-logs", {});
17246
+ this.mobbConfigStore = new Configstore3("mobb-logs", {});
16800
17247
  this.mobbConfigStore.set("version", packageJson.version);
16801
17248
  }
16802
17249
  /**
@@ -16852,12 +17299,12 @@ var Logger = class {
16852
17299
  this.mobbConfigStore.set(currentPath, [...logs, logMessage]);
16853
17300
  }
16854
17301
  };
16855
- var logger = new Logger();
16856
- var logInfo = (message, data) => logger.log(message, "info", data);
16857
- var logError = (message, data) => logger.log(message, "error", data);
16858
- var logWarn = (message, data) => logger.log(message, "warn", data);
16859
- var logDebug = (message, data) => logger.log(message, "debug", data);
16860
- 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);
16861
17308
 
16862
17309
  // src/mcp/services/McpGQLClient.ts
16863
17310
  import crypto2 from "crypto";
@@ -17579,7 +18026,7 @@ async function createAuthenticatedMcpGQLClient({
17579
18026
  // src/mcp/services/McpUsageService/host.ts
17580
18027
  import { execSync as execSync2 } from "child_process";
17581
18028
  import fs13 from "fs";
17582
- import os5 from "os";
18029
+ import os6 from "os";
17583
18030
  import path15 from "path";
17584
18031
  var IDEs = ["cursor", "windsurf", "webstorm", "vscode", "claude"];
17585
18032
  var runCommand = (cmd) => {
@@ -17594,7 +18041,7 @@ var gitInfo = {
17594
18041
  email: runCommand("git config user.email")
17595
18042
  };
17596
18043
  var getClaudeWorkspacePaths = () => {
17597
- const home = os5.homedir();
18044
+ const home = os6.homedir();
17598
18045
  const claudeIdePath = path15.join(home, ".claude", "ide");
17599
18046
  const workspacePaths = [];
17600
18047
  if (!fs13.existsSync(claudeIdePath)) {
@@ -17623,7 +18070,7 @@ var getClaudeWorkspacePaths = () => {
17623
18070
  return workspacePaths;
17624
18071
  };
17625
18072
  var getMCPConfigPaths = (hostName) => {
17626
- const home = os5.homedir();
18073
+ const home = os6.homedir();
17627
18074
  const currentDir = process.env["WORKSPACE_FOLDER_PATHS"] || process.env["PWD"] || process.cwd();
17628
18075
  switch (hostName.toLowerCase()) {
17629
18076
  case "cursor":
@@ -17713,7 +18160,7 @@ var readMCPConfig = (hostName) => {
17713
18160
  };
17714
18161
  var getRunningProcesses = () => {
17715
18162
  try {
17716
- 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" });
17717
18164
  } catch {
17718
18165
  return "";
17719
18166
  }
@@ -17788,7 +18235,7 @@ var versionCommands = {
17788
18235
  }
17789
18236
  };
17790
18237
  var getProcessInfo = (pid) => {
17791
- const platform2 = os5.platform();
18238
+ const platform2 = os6.platform();
17792
18239
  try {
17793
18240
  if (platform2 === "linux" || platform2 === "darwin") {
17794
18241
  const output = execSync2(`ps -o pid=,ppid=,comm= -p ${pid}`, {
@@ -17907,7 +18354,7 @@ var getHostInfo = (additionalMcpList) => {
17907
18354
  const config2 = allConfigs[ide] || null;
17908
18355
  const ideName = ide.charAt(0).toUpperCase() + ide.slice(1) || "Unknown";
17909
18356
  let ideVersion = "Unknown";
17910
- const platform2 = os5.platform();
18357
+ const platform2 = os6.platform();
17911
18358
  const cmds = versionCommands[ideName]?.[platform2] ?? [];
17912
18359
  for (const cmd of cmds) {
17913
18360
  try {
@@ -17939,15 +18386,15 @@ var getHostInfo = (additionalMcpList) => {
17939
18386
  };
17940
18387
 
17941
18388
  // src/mcp/services/McpUsageService/McpUsageService.ts
17942
- import fetch5 from "node-fetch";
17943
- import os7 from "os";
18389
+ import fetch6 from "node-fetch";
18390
+ import os8 from "os";
17944
18391
  import { v4 as uuidv42, v5 as uuidv5 } from "uuid";
17945
18392
  init_configs();
17946
18393
 
17947
18394
  // src/mcp/services/McpUsageService/system.ts
17948
18395
  init_configs();
17949
18396
  import fs14 from "fs";
17950
- import os6 from "os";
18397
+ import os7 from "os";
17951
18398
  import path16 from "path";
17952
18399
  var MAX_DEPTH = 2;
17953
18400
  var patterns = ["mcp", "claude"];
@@ -17982,8 +18429,8 @@ var searchDir = async (dir, depth = 0) => {
17982
18429
  };
17983
18430
  var findSystemMCPConfigs = async () => {
17984
18431
  try {
17985
- const home = os6.homedir();
17986
- const platform2 = os6.platform();
18432
+ const home = os7.homedir();
18433
+ const platform2 = os7.platform();
17987
18434
  const knownDirs = platform2 === "win32" ? [
17988
18435
  path16.join(home, ".cursor"),
17989
18436
  path16.join(home, "Documents"),
@@ -18055,7 +18502,7 @@ var McpUsageService = class {
18055
18502
  generateHostId() {
18056
18503
  const stored = configStore.get(this.configKey);
18057
18504
  if (stored?.mcpHostId) return stored.mcpHostId;
18058
- const interfaces = os7.networkInterfaces();
18505
+ const interfaces = os8.networkInterfaces();
18059
18506
  const macs = [];
18060
18507
  for (const iface of Object.values(interfaces)) {
18061
18508
  if (!iface) continue;
@@ -18063,7 +18510,7 @@ var McpUsageService = class {
18063
18510
  if (net.mac && net.mac !== "00:00:00:00:00:00") macs.push(net.mac);
18064
18511
  }
18065
18512
  }
18066
- const macString = macs.length ? macs.sort().join(",") : `${os7.hostname()}-${uuidv42()}`;
18513
+ const macString = macs.length ? macs.sort().join(",") : `${os8.hostname()}-${uuidv42()}`;
18067
18514
  const hostId = uuidv5(macString, uuidv5.DNS);
18068
18515
  logDebug("[UsageService] Generated new host ID", { hostId });
18069
18516
  return hostId;
@@ -18086,7 +18533,7 @@ var McpUsageService = class {
18086
18533
  mcpHostId,
18087
18534
  organizationId,
18088
18535
  mcpVersion: packageJson.version,
18089
- mcpOsName: os7.platform(),
18536
+ mcpOsName: os8.platform(),
18090
18537
  mcps: JSON.stringify(mcps),
18091
18538
  status,
18092
18539
  userName: user.name,
@@ -18126,7 +18573,7 @@ var McpUsageService = class {
18126
18573
  }
18127
18574
  logDebug("[UsageService] Before", { usageData });
18128
18575
  try {
18129
- const res = await fetch5(this.REST_API_URL, {
18576
+ const res = await fetch6(this.REST_API_URL, {
18130
18577
  method: "POST",
18131
18578
  headers: {
18132
18579
  Accept: "application/json"
@@ -20407,22 +20854,22 @@ For a complete security audit workflow, use the \`full-security-audit\` prompt.
20407
20854
 
20408
20855
  // src/mcp/services/McpDetectionService/CursorMcpDetectionService.ts
20409
20856
  import * as fs17 from "fs";
20410
- import * as os9 from "os";
20857
+ import * as os10 from "os";
20411
20858
  import * as path18 from "path";
20412
20859
 
20413
20860
  // src/mcp/services/McpDetectionService/BaseMcpDetectionService.ts
20414
20861
  init_configs();
20415
20862
  import * as fs16 from "fs";
20416
- import fetch6 from "node-fetch";
20863
+ import fetch7 from "node-fetch";
20417
20864
  import * as path17 from "path";
20418
20865
 
20419
20866
  // src/mcp/services/McpDetectionService/McpDetectionServiceUtils.ts
20420
20867
  import * as fs15 from "fs";
20421
- import * as os8 from "os";
20868
+ import * as os9 from "os";
20422
20869
 
20423
20870
  // src/mcp/services/McpDetectionService/VscodeMcpDetectionService.ts
20424
20871
  import * as fs18 from "fs";
20425
- import * as os10 from "os";
20872
+ import * as os11 from "os";
20426
20873
  import * as path19 from "path";
20427
20874
 
20428
20875
  // src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesTool.ts
@@ -21980,7 +22427,7 @@ import {
21980
22427
  mkdirSync,
21981
22428
  readFileSync as readFileSync3,
21982
22429
  unlinkSync,
21983
- writeFileSync
22430
+ writeFileSync as writeFileSync2
21984
22431
  } from "fs";
21985
22432
  import fs22 from "fs/promises";
21986
22433
  import parseDiff2 from "parse-diff";
@@ -22201,7 +22648,7 @@ var PatchApplicationService = class {
22201
22648
  }
22202
22649
  const dirPath = path22.dirname(normalizedFilePath);
22203
22650
  mkdirSync(dirPath, { recursive: true });
22204
- writeFileSync(normalizedFilePath, finalContent, "utf8");
22651
+ writeFileSync2(normalizedFilePath, finalContent, "utf8");
22205
22652
  return normalizedFilePath;
22206
22653
  }
22207
22654
  static resolvePathWithinRepo({
@@ -24867,18 +25314,18 @@ async function getGrpcClient(port, csrf3) {
24867
25314
 
24868
25315
  // src/features/codeium_intellij/parse_intellij_logs.ts
24869
25316
  import fs25 from "fs";
24870
- import os11 from "os";
25317
+ import os12 from "os";
24871
25318
  import path25 from "path";
24872
25319
  function getLogsDir() {
24873
25320
  if (process.platform === "darwin") {
24874
- return path25.join(os11.homedir(), "Library/Logs/JetBrains");
25321
+ return path25.join(os12.homedir(), "Library/Logs/JetBrains");
24875
25322
  } else if (process.platform === "win32") {
24876
25323
  return path25.join(
24877
- process.env["LOCALAPPDATA"] || path25.join(os11.homedir(), "AppData/Local"),
25324
+ process.env["LOCALAPPDATA"] || path25.join(os12.homedir(), "AppData/Local"),
24878
25325
  "JetBrains"
24879
25326
  );
24880
25327
  } else {
24881
- return path25.join(os11.homedir(), ".cache/JetBrains");
25328
+ return path25.join(os12.homedir(), ".cache/JetBrains");
24882
25329
  }
24883
25330
  }
24884
25331
  function parseIdeLogDir(ideLogDir) {
@@ -24936,7 +25383,7 @@ function findRunningCodeiumLanguageServers() {
24936
25383
  var HookDataSchema2 = z47.object({
24937
25384
  trajectory_id: z47.string()
24938
25385
  });
24939
- async function processAndUploadHookData2() {
25386
+ async function processAndUploadHookData() {
24940
25387
  const tracePayload = await getTraceDataForHook();
24941
25388
  if (!tracePayload) {
24942
25389
  console.warn("Warning: Failed to retrieve chat data.");
@@ -25100,17 +25547,17 @@ function processChatStepCodeAction(step) {
25100
25547
  }
25101
25548
 
25102
25549
  // src/features/codeium_intellij/install_hook.ts
25103
- import fsPromises6 from "fs/promises";
25104
- import os12 from "os";
25550
+ import fsPromises5 from "fs/promises";
25551
+ import os13 from "os";
25105
25552
  import path26 from "path";
25106
25553
  import chalk14 from "chalk";
25107
25554
  function getCodeiumHooksPath() {
25108
- return path26.join(os12.homedir(), ".codeium", "hooks.json");
25555
+ return path26.join(os13.homedir(), ".codeium", "hooks.json");
25109
25556
  }
25110
25557
  async function readCodeiumHooks() {
25111
25558
  const hooksPath = getCodeiumHooksPath();
25112
25559
  try {
25113
- const content = await fsPromises6.readFile(hooksPath, "utf-8");
25560
+ const content = await fsPromises5.readFile(hooksPath, "utf-8");
25114
25561
  return JSON.parse(content);
25115
25562
  } catch {
25116
25563
  return {};
@@ -25119,8 +25566,8 @@ async function readCodeiumHooks() {
25119
25566
  async function writeCodeiumHooks(config2) {
25120
25567
  const hooksPath = getCodeiumHooksPath();
25121
25568
  const dir = path26.dirname(hooksPath);
25122
- await fsPromises6.mkdir(dir, { recursive: true });
25123
- await fsPromises6.writeFile(
25569
+ await fsPromises5.mkdir(dir, { recursive: true });
25570
+ await fsPromises5.writeFile(
25124
25571
  hooksPath,
25125
25572
  JSON.stringify(config2, null, 2),
25126
25573
  "utf-8"
@@ -25208,7 +25655,7 @@ var windsurfIntellijInstallHookHandler = async (argv) => {
25208
25655
  };
25209
25656
  var windsurfIntellijProcessHookHandler = async () => {
25210
25657
  try {
25211
- await processAndUploadHookData2();
25658
+ await processAndUploadHookData();
25212
25659
  process.exit(0);
25213
25660
  } catch (error) {
25214
25661
  console.error("Failed to process Windsurf IntelliJ hook data:", error);