mobbdev 1.4.48 → 1.4.49

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
@@ -5227,7 +5227,7 @@ async function getAdoSdk(params) {
5227
5227
  const url = new URL(repoUrl);
5228
5228
  const origin = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
5229
5229
  const params2 = `path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
5230
- const path37 = [
5230
+ const path38 = [
5231
5231
  prefixPath,
5232
5232
  owner,
5233
5233
  projectName,
@@ -5238,7 +5238,7 @@ async function getAdoSdk(params) {
5238
5238
  "items",
5239
5239
  "items"
5240
5240
  ].filter(Boolean).join("/");
5241
- return new URL(`${path37}?${params2}`, origin).toString();
5241
+ return new URL(`${path38}?${params2}`, origin).toString();
5242
5242
  },
5243
5243
  async getAdoBranchList({ repoUrl }) {
5244
5244
  try {
@@ -5327,8 +5327,8 @@ async function getAdoSdk(params) {
5327
5327
  const changeType = entry.changeType;
5328
5328
  return changeType !== 16 && entry.item?.path;
5329
5329
  }).map((entry) => {
5330
- const path37 = entry.item.path;
5331
- return path37.startsWith("/") ? path37.slice(1) : path37;
5330
+ const path38 = entry.item.path;
5331
+ return path38.startsWith("/") ? path38.slice(1) : path38;
5332
5332
  });
5333
5333
  },
5334
5334
  async searchAdoPullRequests({
@@ -6265,7 +6265,6 @@ var AdoSCMLib = class extends SCMLib {
6265
6265
  // src/features/analysis/scm/bitbucket/bitbucket.ts
6266
6266
  import querystring2 from "querystring";
6267
6267
  import * as bitbucketPkgNode from "bitbucket";
6268
- import bitbucketPkg from "bitbucket";
6269
6268
  import Debug2 from "debug";
6270
6269
  import { z as z16 } from "zod";
6271
6270
 
@@ -6278,6 +6277,7 @@ var BitbucketAuthResultZ = z15.object({
6278
6277
  });
6279
6278
 
6280
6279
  // src/features/analysis/scm/bitbucket/bitbucket.ts
6280
+ var bitbucketPkg = bitbucketPkgNode.default;
6281
6281
  var debug3 = Debug2("scm:bitbucket");
6282
6282
  function isBitbucketPermissionDenied(e) {
6283
6283
  const status = e?.status;
@@ -10417,6 +10417,7 @@ __export(utils_exports, {
10417
10417
  getDirName: () => getDirName,
10418
10418
  getModuleRootDir: () => getModuleRootDir,
10419
10419
  getTopLevelDirName: () => getTopLevelDirName,
10420
+ isStandaloneBinary: () => isStandaloneBinary,
10420
10421
  keypress: () => keypress,
10421
10422
  packageJson: () => packageJson,
10422
10423
  sleep: () => sleep
@@ -10427,6 +10428,10 @@ import fs3 from "fs";
10427
10428
  import path3 from "path";
10428
10429
  import { fileURLToPath } from "url";
10429
10430
  function getModuleRootDir() {
10431
+ const seaRoot = process.env["MOBBDEV_MODULE_ROOT"];
10432
+ if (seaRoot) {
10433
+ return seaRoot;
10434
+ }
10430
10435
  let manifestDir = getDirName();
10431
10436
  for (let i = 0; i < 10; i++) {
10432
10437
  const manifestPath = path3.join(manifestDir, "package.json");
@@ -10523,6 +10528,16 @@ function Spinner({ ci = false } = {}) {
10523
10528
  };
10524
10529
  }
10525
10530
 
10531
+ // src/utils/standalone_binary.ts
10532
+ function isStandaloneBinary() {
10533
+ try {
10534
+ const getBuiltin = process.getBuiltinModule;
10535
+ return Boolean(getBuiltin?.("node:sea")?.isSea());
10536
+ } catch {
10537
+ return false;
10538
+ }
10539
+ }
10540
+
10526
10541
  // src/utils/check_node_version.ts
10527
10542
  import fs4 from "fs";
10528
10543
  import path4 from "path";
@@ -11306,7 +11321,7 @@ var ScanContext = {
11306
11321
  };
11307
11322
 
11308
11323
  // src/args/commands/analyze.ts
11309
- import fs12 from "fs";
11324
+ import fs13 from "fs";
11310
11325
  import chalk10 from "chalk";
11311
11326
 
11312
11327
  // src/commands/index.ts
@@ -11314,11 +11329,11 @@ import chalk8 from "chalk";
11314
11329
  import chalkAnimation from "chalk-animation";
11315
11330
 
11316
11331
  // src/features/analysis/index.ts
11317
- import fs10 from "fs";
11332
+ import fs11 from "fs";
11318
11333
  import fsPromises3 from "fs/promises";
11319
- import path10 from "path";
11334
+ import path11 from "path";
11320
11335
  import { env as env2 } from "process";
11321
- import { pipeline } from "stream/promises";
11336
+ import { pipeline as pipeline2 } from "stream/promises";
11322
11337
  import chalk7 from "chalk";
11323
11338
  import Debug22 from "debug";
11324
11339
  import extract from "extract-zip";
@@ -14019,7 +14034,7 @@ async function postIssueComment(params) {
14019
14034
  fpDescription
14020
14035
  } = params;
14021
14036
  const {
14022
- path: path37,
14037
+ path: path38,
14023
14038
  startLine,
14024
14039
  vulnerabilityReportIssue: {
14025
14040
  vulnerabilityReportIssueTags,
@@ -14034,7 +14049,7 @@ async function postIssueComment(params) {
14034
14049
  Refresh the page in order to see the changes.`,
14035
14050
  pull_number: pullRequest,
14036
14051
  commit_id: commitSha,
14037
- path: path37,
14052
+ path: path38,
14038
14053
  line: startLine
14039
14054
  });
14040
14055
  const commentId = commentRes.data.id;
@@ -14068,7 +14083,7 @@ async function postFixComment(params) {
14068
14083
  scanner
14069
14084
  } = params;
14070
14085
  const {
14071
- path: path37,
14086
+ path: path38,
14072
14087
  startLine,
14073
14088
  vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
14074
14089
  vulnerabilityReportIssueId
@@ -14086,7 +14101,7 @@ async function postFixComment(params) {
14086
14101
  Refresh the page in order to see the changes.`,
14087
14102
  pull_number: pullRequest,
14088
14103
  commit_id: commitSha,
14089
- path: path37,
14104
+ path: path38,
14090
14105
  line: startLine
14091
14106
  });
14092
14107
  const commentId = commentRes.data.id;
@@ -14636,7 +14651,7 @@ function createFork({ args, processPath, name }, options) {
14636
14651
  }
14637
14652
  function createSpawn({ args, processPath, name, cwd, env: env3 }, options) {
14638
14653
  const child = cp.spawn(processPath, args, {
14639
- stdio: ["inherit", "pipe", "pipe", "ipc"],
14654
+ stdio: ["inherit", "pipe", "pipe"],
14640
14655
  env: { ...process2.env, ...env3 },
14641
14656
  cwd
14642
14657
  });
@@ -14694,11 +14709,16 @@ if (typeof __filename !== "undefined") {
14694
14709
  }
14695
14710
  var costumeRequire = createRequire(moduleUrl);
14696
14711
  var getCheckmarxPath = () => {
14697
- const os19 = type();
14698
- const cxFileName = os19 === "Windows_NT" ? "cx.exe" : "cx";
14712
+ const os20 = type();
14713
+ const cxFileName = os20 === "Windows_NT" ? "cx.exe" : "cx";
14699
14714
  try {
14700
14715
  return costumeRequire.resolve(`.bin/${cxFileName}`);
14701
14716
  } catch (e) {
14717
+ if (isStandaloneBinary()) {
14718
+ throw new CliError(
14719
+ "The Checkmarx scanner is not available in the standalone mobbdev binary yet. Use the npm package instead: npx mobbdev@latest"
14720
+ );
14721
+ }
14702
14722
  throw new CliError(cxOperatingSystemSupportMessage);
14703
14723
  }
14704
14724
  };
@@ -14805,7 +14825,13 @@ async function validateCheckamxCredentials() {
14805
14825
  }
14806
14826
 
14807
14827
  // src/features/analysis/scanners/snyk.ts
14828
+ import crypto2 from "crypto";
14829
+ import fs10 from "fs";
14808
14830
  import { createRequire as createRequire2 } from "module";
14831
+ import os4 from "os";
14832
+ import path10 from "path";
14833
+ import { Readable } from "stream";
14834
+ import { pipeline } from "stream/promises";
14809
14835
  import chalk6 from "chalk";
14810
14836
  import Debug21 from "debug";
14811
14837
  import { createSpinner as createSpinner3 } from "nanospinner";
@@ -14830,31 +14856,130 @@ if (typeof __filename !== "undefined") {
14830
14856
  }
14831
14857
  }
14832
14858
  var costumeRequire2 = createRequire2(moduleUrl2);
14833
- var SNYK_PATH = costumeRequire2.resolve("snyk/bin/snyk");
14834
14859
  var SNYK_ARTICLE_URL = "https://docs.snyk.io/scan-using-snyk/snyk-code/configure-snyk-code#enable-snyk-code";
14835
- debug21("snyk executable path %s", SNYK_PATH);
14860
+ var SNYK_VERSION = packageJson.dependencies.snyk;
14861
+ var SNYK_DOWNLOAD_BASE = process.env["MOBB_SNYK_DOWNLOAD_BASE"] || "https://downloads.snyk.io/cli";
14862
+ var SNYK_BINARY_ASSETS = {
14863
+ "darwin-x64": "snyk-macos",
14864
+ "darwin-arm64": "snyk-macos-arm64",
14865
+ "linux-x64": "snyk-linux",
14866
+ "linux-arm64": "snyk-linux-arm64",
14867
+ "win32-x64": "snyk-win.exe"
14868
+ };
14869
+ async function downloadSnykBinary(asset, dest) {
14870
+ if (!/^\d+\.\d+\.\d+$/.test(SNYK_VERSION)) {
14871
+ throw new CliError(
14872
+ `Cannot build the Snyk CLI download URL: expected an exact version in the "snyk" dependency of package.json, got "${SNYK_VERSION}".`
14873
+ );
14874
+ }
14875
+ const url = `${SNYK_DOWNLOAD_BASE}/v${SNYK_VERSION}/${asset}`;
14876
+ const tmpPath = `${dest}.download.${process.pid}`;
14877
+ const spinner = createSpinner3(
14878
+ `\u2B07\uFE0F Downloading Snyk CLI v${SNYK_VERSION}`
14879
+ ).start();
14880
+ try {
14881
+ fs10.mkdirSync(path10.dirname(dest), { recursive: true });
14882
+ const timeout = () => AbortSignal.timeout(10 * 60 * 1e3);
14883
+ const [binRes, shaRes] = await Promise.all([
14884
+ fetchWithProxy(url, { signal: timeout() }),
14885
+ fetchWithProxy(`${url}.sha256`, { signal: timeout() })
14886
+ ]);
14887
+ if (!binRes.ok || !shaRes.ok || !binRes.body) {
14888
+ throw new CliError(
14889
+ `Snyk CLI download failed with HTTP ${binRes.ok ? shaRes.status : binRes.status}: ${url}
14890
+ If downloads.snyk.io is unreachable from this network, point MOBB_SNYK_DOWNLOAD_BASE at a mirror.`
14891
+ );
14892
+ }
14893
+ const hash = crypto2.createHash("sha256");
14894
+ await pipeline(
14895
+ Readable.fromWeb(binRes.body),
14896
+ async function* (source) {
14897
+ for await (const chunk of source) {
14898
+ hash.update(chunk);
14899
+ yield chunk;
14900
+ }
14901
+ },
14902
+ fs10.createWriteStream(tmpPath, { mode: 493 })
14903
+ );
14904
+ const expected = (await shaRes.text()).trim().split(/\s+/)[0];
14905
+ const actual = hash.digest("hex");
14906
+ if (actual !== expected) {
14907
+ throw new CliError(
14908
+ `Snyk CLI download checksum mismatch (expected ${expected}, got ${actual}) \u2014 refusing to install it. Please try again.`
14909
+ );
14910
+ }
14911
+ fs10.renameSync(tmpPath, dest);
14912
+ spinner.success({ text: `\u2B07\uFE0F Snyk CLI v${SNYK_VERSION} installed` });
14913
+ } catch (e) {
14914
+ fs10.rmSync(tmpPath, { force: true });
14915
+ spinner.error({ text: "\u2B07\uFE0F Snyk CLI download failed" });
14916
+ throw e;
14917
+ }
14918
+ }
14919
+ async function getSnykExecutable() {
14920
+ try {
14921
+ return {
14922
+ processPath: costumeRequire2.resolve("snyk/bin/snyk"),
14923
+ isNodeScript: true
14924
+ };
14925
+ } catch (e) {
14926
+ if (!isStandaloneBinary()) {
14927
+ throw e;
14928
+ }
14929
+ debug21("running as standalone binary, using standalone snyk binary");
14930
+ }
14931
+ const asset = SNYK_BINARY_ASSETS[`${process.platform}-${process.arch}`];
14932
+ if (!asset) {
14933
+ throw new CliError(
14934
+ `Snyk scan is not supported on this platform (${process.platform}-${process.arch}) when running the standalone mobbdev binary. Use the npm package instead: npx mobbdev@latest`
14935
+ );
14936
+ }
14937
+ const dest = path10.join(
14938
+ os4.homedir(),
14939
+ ".mobb",
14940
+ "tools",
14941
+ "snyk",
14942
+ `v${SNYK_VERSION}`,
14943
+ asset
14944
+ );
14945
+ if (!fs10.existsSync(dest)) {
14946
+ await downloadSnykBinary(asset, dest);
14947
+ }
14948
+ return { processPath: dest, isNodeScript: false };
14949
+ }
14836
14950
  async function forkSnyk(args, { display }) {
14837
14951
  debug21("fork snyk with args %o %s", args, display);
14838
- return createFork({ args, processPath: SNYK_PATH, name: "snyk" }, { display });
14952
+ const { processPath, isNodeScript } = await getSnykExecutable();
14953
+ const create = isNodeScript ? createFork : createSpawn;
14954
+ return create({ args, processPath, name: "snyk" }, { display });
14839
14955
  }
14840
14956
  async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
14841
14957
  debug21("get snyk report start %s %s", reportPath, repoRoot);
14842
14958
  const config2 = await forkSnyk(["config"], { display: false });
14843
14959
  const { message: configMessage } = config2;
14844
- if (!configMessage.includes("api: ")) {
14845
- const snykLoginSpinner = createSpinner3().start();
14846
- if (!skipPrompts) {
14960
+ const hasStoredCredential = configMessage.includes("api: ") || configMessage.includes("INTERNAL_OAUTH_TOKEN_STORAGE");
14961
+ if (!hasStoredCredential) {
14962
+ const hasSnykToken = !!process.env["SNYK_TOKEN"];
14963
+ if (skipPrompts) {
14964
+ if (!hasSnykToken) {
14965
+ throw new CliError(
14966
+ "Snyk authentication is required. In CI / non-interactive mode, set the SNYK_TOKEN environment variable (Snyk API token). Interactive `snyk auth` (browser) is not available with --ci."
14967
+ );
14968
+ }
14969
+ debug21("skipPrompts: using SNYK_TOKEN for snyk authentication");
14970
+ } else {
14971
+ const snykLoginSpinner = createSpinner3().start();
14847
14972
  snykLoginSpinner.update({
14848
14973
  text: "\u{1F513} Login to Snyk is required, press any key to continue"
14849
14974
  });
14850
14975
  await keypress();
14976
+ snykLoginSpinner.update({
14977
+ text: "\u{1F513} Waiting for Snyk login to complete"
14978
+ });
14979
+ debug21("no token in the config %s", config2);
14980
+ await forkSnyk(["auth"], { display: true });
14981
+ snykLoginSpinner.success({ text: "\u{1F513} Login to Snyk Successful" });
14851
14982
  }
14852
- snykLoginSpinner.update({
14853
- text: "\u{1F513} Waiting for Snyk login to complete"
14854
- });
14855
- debug21("no token in the config %s", config2);
14856
- await forkSnyk(["auth"], { display: true });
14857
- snykLoginSpinner.success({ text: "\u{1F513} Login to Snyk Successful" });
14858
14983
  }
14859
14984
  const snykSpinner = createSpinner3("\u{1F50D} Scanning your repo with Snyk ").start();
14860
14985
  const { message: scanOutput } = await forkSnyk(
@@ -14916,7 +15041,7 @@ async function downloadRepo({
14916
15041
  const { createSpinner: createSpinner5 } = Spinner2({ ci });
14917
15042
  const repoSpinner = createSpinner5("\u{1F4BE} Downloading Repo").start();
14918
15043
  debug22("download repo %s %s %s", repoUrl, dirname);
14919
- const zipFilePath = path10.join(dirname, "repo.zip");
15044
+ const zipFilePath = path11.join(dirname, "repo.zip");
14920
15045
  debug22("download URL: %s auth headers: %o", downloadUrl, authHeaders);
14921
15046
  const response = await fetch4(downloadUrl, {
14922
15047
  method: "GET",
@@ -14929,19 +15054,19 @@ async function downloadRepo({
14929
15054
  repoSpinner.error({ text: "\u{1F4BE} Repo download failed" });
14930
15055
  throw new Error(`Can't access ${chalk7.bold(repoUrl)}`);
14931
15056
  }
14932
- const fileWriterStream = fs10.createWriteStream(zipFilePath);
15057
+ const fileWriterStream = fs11.createWriteStream(zipFilePath);
14933
15058
  if (!response.body) {
14934
15059
  throw new Error("Response body is empty");
14935
15060
  }
14936
- await pipeline(response.body, fileWriterStream);
15061
+ await pipeline2(response.body, fileWriterStream);
14937
15062
  await extract(zipFilePath, { dir: dirname });
14938
- const repoRoot = fs10.readdirSync(dirname, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name)[0];
15063
+ const repoRoot = fs11.readdirSync(dirname, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name)[0];
14939
15064
  if (!repoRoot) {
14940
15065
  throw new Error("Repo root not found");
14941
15066
  }
14942
15067
  debug22("repo root %s", repoRoot);
14943
15068
  repoSpinner.success({ text: "\u{1F4BE} Repo downloaded successfully" });
14944
- return path10.join(dirname, repoRoot);
15069
+ return path11.join(dirname, repoRoot);
14945
15070
  }
14946
15071
  var getReportUrl = ({
14947
15072
  organizationId,
@@ -15049,7 +15174,7 @@ async function getReport(params, { skipPrompts }) {
15049
15174
  authHeaders: scm.getAuthHeaders(),
15050
15175
  downloadUrl
15051
15176
  });
15052
- const reportPath = path10.join(dirname, REPORT_DEFAULT_FILE_NAME);
15177
+ const reportPath = path11.join(dirname, REPORT_DEFAULT_FILE_NAME);
15053
15178
  switch (scanner) {
15054
15179
  case "snyk":
15055
15180
  await getSnykReport(reportPath, repositoryRoot, { skipPrompts });
@@ -15461,7 +15586,7 @@ async function _zipAndUploadRepo({
15461
15586
  const zippingSpinner = createSpinner4("\u{1F4E6} Zipping repo").start();
15462
15587
  let zipBuffer;
15463
15588
  let gitInfo2 = { success: false };
15464
- if (srcFileStatus.isFile() && path10.extname(srcPath).toLowerCase() === ".fpr") {
15589
+ if (srcFileStatus.isFile() && path11.extname(srcPath).toLowerCase() === ".fpr") {
15465
15590
  zipBuffer = await repackFpr(srcPath);
15466
15591
  } else {
15467
15592
  gitInfo2 = await getGitInfo(srcPath);
@@ -15634,17 +15759,17 @@ async function waitForAnaysisAndReviewPr({
15634
15759
  }
15635
15760
 
15636
15761
  // src/commands/scan_skill_input.ts
15637
- import fs11 from "fs";
15638
- import path11 from "path";
15762
+ import fs12 from "fs";
15763
+ import path12 from "path";
15639
15764
  import AdmZip2 from "adm-zip";
15640
15765
  var LOCAL_SKILL_ZIP_DATA_URL_PREFIX = "data:application/zip;base64,";
15641
15766
  var MAX_LOCAL_SKILL_ARCHIVE_BYTES = 2 * 1024 * 1024;
15642
15767
  async function resolveSkillScanInput(skillInput) {
15643
- const resolvedPath = path11.resolve(skillInput);
15644
- if (!fs11.existsSync(resolvedPath)) {
15768
+ const resolvedPath = path12.resolve(skillInput);
15769
+ if (!fs12.existsSync(resolvedPath)) {
15645
15770
  return skillInput;
15646
15771
  }
15647
- const stat5 = fs11.statSync(resolvedPath);
15772
+ const stat5 = fs12.statSync(resolvedPath);
15648
15773
  if (!stat5.isDirectory()) {
15649
15774
  throw new CliError(
15650
15775
  "Local skill input must be a directory containing SKILL.md"
@@ -15654,18 +15779,18 @@ async function resolveSkillScanInput(skillInput) {
15654
15779
  }
15655
15780
  function packageLocalSkillDirectory(directoryPath) {
15656
15781
  const zip = new AdmZip2();
15657
- const rootPath = path11.resolve(directoryPath);
15782
+ const rootPath = path12.resolve(directoryPath);
15658
15783
  const filePaths = listDirectoryFiles(rootPath);
15659
15784
  let hasSkillMd = false;
15660
15785
  for (const relativePath of filePaths) {
15661
- const fullPath = path11.join(rootPath, relativePath);
15662
- const normalizedFullPath = path11.resolve(fullPath);
15663
- if (normalizedFullPath !== rootPath && !normalizedFullPath.startsWith(rootPath + path11.sep)) {
15786
+ const fullPath = path12.join(rootPath, relativePath);
15787
+ const normalizedFullPath = path12.resolve(fullPath);
15788
+ if (normalizedFullPath !== rootPath && !normalizedFullPath.startsWith(rootPath + path12.sep)) {
15664
15789
  continue;
15665
15790
  }
15666
- const fileContent = fs11.readFileSync(normalizedFullPath);
15791
+ const fileContent = fs12.readFileSync(normalizedFullPath);
15667
15792
  zip.addFile(relativePath, fileContent);
15668
- if (path11.basename(relativePath).toLowerCase() === "skill.md") {
15793
+ if (path12.basename(relativePath).toLowerCase() === "skill.md") {
15669
15794
  hasSkillMd = true;
15670
15795
  }
15671
15796
  }
@@ -15683,17 +15808,17 @@ function packageLocalSkillDirectory(directoryPath) {
15683
15808
  function listDirectoryFiles(rootPath) {
15684
15809
  const files = [];
15685
15810
  function walk(relativeDir) {
15686
- const absoluteDir = path11.join(rootPath, relativeDir);
15687
- const entries = fs11.readdirSync(absoluteDir, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
15811
+ const absoluteDir = path12.join(rootPath, relativeDir);
15812
+ const entries = fs12.readdirSync(absoluteDir, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
15688
15813
  for (const entry of entries) {
15689
- const safeEntryName = path11.basename(entry.name).replace(/\0/g, "");
15814
+ const safeEntryName = path12.basename(entry.name).replace(/\0/g, "");
15690
15815
  if (!safeEntryName) {
15691
15816
  continue;
15692
15817
  }
15693
- const relativePath = relativeDir ? path11.posix.join(relativeDir, safeEntryName) : safeEntryName;
15694
- const absolutePath = path11.join(rootPath, relativePath);
15695
- const normalizedAbsolutePath = path11.resolve(absolutePath);
15696
- if (normalizedAbsolutePath !== rootPath && !normalizedAbsolutePath.startsWith(rootPath + path11.sep)) {
15818
+ const relativePath = relativeDir ? path12.posix.join(relativeDir, safeEntryName) : safeEntryName;
15819
+ const absolutePath = path12.join(rootPath, relativePath);
15820
+ const normalizedAbsolutePath = path12.resolve(absolutePath);
15821
+ if (normalizedAbsolutePath !== rootPath && !normalizedAbsolutePath.startsWith(rootPath + path12.sep)) {
15697
15822
  continue;
15698
15823
  }
15699
15824
  if (entry.isSymbolicLink()) {
@@ -15914,7 +16039,7 @@ async function scanSkill(options) {
15914
16039
 
15915
16040
  // src/args/validation.ts
15916
16041
  import chalk9 from "chalk";
15917
- import path12 from "path";
16042
+ import path13 from "path";
15918
16043
  import { z as z28 } from "zod";
15919
16044
  function throwRepoUrlErrorMessage({
15920
16045
  error,
@@ -15958,7 +16083,7 @@ function validateRepoUrl(args) {
15958
16083
  }
15959
16084
  var supportExtensions = [".json", ".xml", ".fpr", ".sarif", ".zip"];
15960
16085
  function validateReportFileFormat(reportFile) {
15961
- if (!supportExtensions.includes(path12.extname(reportFile))) {
16086
+ if (!supportExtensions.includes(path13.extname(reportFile))) {
15962
16087
  throw new CliError(
15963
16088
  `
15964
16089
  ${chalk9.bold(
@@ -16006,7 +16131,7 @@ function analyzeBuilder(yargs2) {
16006
16131
  ).help();
16007
16132
  }
16008
16133
  function validateAnalyzeOptions(argv) {
16009
- if (argv.f && !fs12.existsSync(argv.f)) {
16134
+ if (argv.f && !fs13.existsSync(argv.f)) {
16010
16135
  throw new CliError(`
16011
16136
  Can't access ${chalk10.bold(argv.f)}`);
16012
16137
  }
@@ -16054,8 +16179,8 @@ import { spawn } from "child_process";
16054
16179
 
16055
16180
  // src/features/claude_code/daemon.ts
16056
16181
  import { readFileSync, writeFileSync as writeFileSync2 } from "fs";
16057
- import * as os8 from "os";
16058
- import path24 from "path";
16182
+ import * as os9 from "os";
16183
+ import path25 from "path";
16059
16184
  import { setTimeout as sleep4 } from "timers/promises";
16060
16185
  import Configstore4 from "configstore";
16061
16186
 
@@ -16234,7 +16359,7 @@ function loadBreaker(store) {
16234
16359
  // src/features/analysis/skill_quarantine/runQuarantineCheck.ts
16235
16360
  import { stat as stat3 } from "fs/promises";
16236
16361
  import { homedir as homedir4 } from "os";
16237
- import path19 from "path";
16362
+ import path20 from "path";
16238
16363
 
16239
16364
  // src/features/analysis/skill_quarantine/constants.ts
16240
16365
  var HEARTBEAT_DEBOUNCE_MS = (() => {
@@ -16249,11 +16374,11 @@ var STUB_MARKER = "\u26D4 QUARANTINED BY TRACY";
16249
16374
 
16250
16375
  // src/features/analysis/skill_quarantine/enumerateInstalledSkills.ts
16251
16376
  import { homedir as homedir2 } from "os";
16252
- import path15 from "path";
16377
+ import path16 from "path";
16253
16378
 
16254
16379
  // src/features/analysis/context_file_processor.ts
16255
16380
  import { createHash } from "crypto";
16256
- import path13 from "path";
16381
+ import path14 from "path";
16257
16382
  import AdmZip3 from "adm-zip";
16258
16383
  import pLimit5 from "p-limit";
16259
16384
  var SANITIZE_CONCURRENCY = 5;
@@ -16287,7 +16412,7 @@ async function processContextFiles(regularFiles, skillGroups) {
16287
16412
  );
16288
16413
  for (const file of sortedFiles) {
16289
16414
  const sanitizedContent = await sanitizeFileContent(file.content);
16290
- const zipEntryName = group.isFolder ? path13.relative(group.skillPath, file.path).replace(/\\/g, "/") : path13.basename(file.path);
16415
+ const zipEntryName = group.isFolder ? path14.relative(group.skillPath, file.path).replace(/\\/g, "/") : path14.basename(file.path);
16291
16416
  zip.addFile(zipEntryName, Buffer.from(sanitizedContent, "utf-8"));
16292
16417
  const entry = zip.getEntry(zipEntryName);
16293
16418
  if (entry) {
@@ -16306,7 +16431,7 @@ async function processContextFiles(regularFiles, skillGroups) {
16306
16431
  // src/features/analysis/context_file_scanner.ts
16307
16432
  import { lstat, readdir, readFile, realpath, stat } from "fs/promises";
16308
16433
  import { homedir } from "os";
16309
- import path14 from "path";
16434
+ import path15 from "path";
16310
16435
  import { globby as globby2 } from "globby";
16311
16436
  import { parse as parseJsoncLib } from "jsonc-parser";
16312
16437
 
@@ -16638,25 +16763,25 @@ function resolveCustomLocationPath(raw, workspaceRoot, home) {
16638
16763
  return null;
16639
16764
  }
16640
16765
  if (s.startsWith("~/") || s === "~") {
16641
- s = path14.join(home, s.slice(1));
16766
+ s = path15.join(home, s.slice(1));
16642
16767
  }
16643
- if (!path14.isAbsolute(s)) {
16644
- s = path14.resolve(workspaceRoot, s);
16768
+ if (!path15.isAbsolute(s)) {
16769
+ s = path15.resolve(workspaceRoot, s);
16645
16770
  }
16646
- const resolved = path14.normalize(s);
16771
+ const resolved = path15.normalize(s);
16647
16772
  if (resolved === "/" || resolved === home) {
16648
16773
  return null;
16649
16774
  }
16650
16775
  for (const sub of SENSITIVE_HOME_SUBDIRS) {
16651
- const sensitive = path14.join(home, sub);
16652
- if (resolved === sensitive || resolved.startsWith(`${sensitive}${path14.sep}`)) {
16776
+ const sensitive = path15.join(home, sub);
16777
+ if (resolved === sensitive || resolved.startsWith(`${sensitive}${path15.sep}`)) {
16653
16778
  return null;
16654
16779
  }
16655
16780
  }
16656
- const relWorkspace = path14.relative(workspaceRoot, resolved);
16657
- const relHome = path14.relative(home, resolved);
16658
- const escapesWorkspace = relWorkspace.startsWith("..") || path14.isAbsolute(relWorkspace);
16659
- const escapesHome = relHome.startsWith("..") || path14.isAbsolute(relHome);
16781
+ const relWorkspace = path15.relative(workspaceRoot, resolved);
16782
+ const relHome = path15.relative(home, resolved);
16783
+ const escapesWorkspace = relWorkspace.startsWith("..") || path15.isAbsolute(relWorkspace);
16784
+ const escapesHome = relHome.startsWith("..") || path15.isAbsolute(relHome);
16660
16785
  if (escapesWorkspace && escapesHome) {
16661
16786
  return null;
16662
16787
  }
@@ -16707,15 +16832,15 @@ async function readJsoncSettings(settingsPath) {
16707
16832
  putSettingsCache(settingsPath, { mtimeMs, parsed: payload });
16708
16833
  return payload;
16709
16834
  }
16710
- function putSettingsCache(path37, entry) {
16711
- if (!settingsCache.has(path37) && settingsCache.size >= MAX_SETTINGS_CACHE_SIZE) {
16835
+ function putSettingsCache(path38, entry) {
16836
+ if (!settingsCache.has(path38) && settingsCache.size >= MAX_SETTINGS_CACHE_SIZE) {
16712
16837
  settingsCache.delete(settingsCache.keys().next().value);
16713
16838
  }
16714
- settingsCache.set(path37, entry);
16839
+ settingsCache.set(path38, entry);
16715
16840
  }
16716
16841
  async function readCopilotCustomLocations(workspaceRoot) {
16717
16842
  const parsed = await readJsoncSettings(
16718
- path14.join(workspaceRoot, ".vscode", "settings.json")
16843
+ path15.join(workspaceRoot, ".vscode", "settings.json")
16719
16844
  );
16720
16845
  if (!parsed) {
16721
16846
  return [];
@@ -16762,7 +16887,7 @@ async function readCopilotCustomLocations(workspaceRoot) {
16762
16887
  async function readClaudeCodeCustomLocations() {
16763
16888
  const home = homedir();
16764
16889
  const parsed = await readJsoncSettings(
16765
- path14.join(home, ".claude", "settings.json")
16890
+ path15.join(home, ".claude", "settings.json")
16766
16891
  );
16767
16892
  if (!parsed) {
16768
16893
  return [];
@@ -16804,7 +16929,7 @@ function groupSkills(files, root, baseDir) {
16804
16929
  const folderMap = /* @__PURE__ */ new Map();
16805
16930
  const standalone = [];
16806
16931
  for (const f of skillFiles) {
16807
- const rel = path14.relative(baseDir, f.path).replace(/\\/g, "/");
16932
+ const rel = path15.relative(baseDir, f.path).replace(/\\/g, "/");
16808
16933
  const skillsMarker = "skills/";
16809
16934
  const skillsIdx = rel.indexOf(skillsMarker);
16810
16935
  if (skillsIdx === -1) {
@@ -16831,8 +16956,8 @@ function groupSkills(files, root, baseDir) {
16831
16956
  }
16832
16957
  const groups = [];
16833
16958
  for (const f of standalone) {
16834
- const name = path14.basename(f.path, path14.extname(f.path));
16835
- const standaloneRel = path14.relative(baseDir, f.path).replace(/\\/g, "/");
16959
+ const name = path15.basename(f.path, path15.extname(f.path));
16960
+ const standaloneRel = path15.relative(baseDir, f.path).replace(/\\/g, "/");
16836
16961
  const sessionKey = `skill:${root}:${standaloneRel}`;
16837
16962
  groups.push({
16838
16963
  name,
@@ -16846,7 +16971,7 @@ function groupSkills(files, root, baseDir) {
16846
16971
  }
16847
16972
  for (const [folderKey, { folderName, files: folderFiles }] of folderMap) {
16848
16973
  const maxMtimeMs = Math.max(...folderFiles.map((f) => f.mtimeMs));
16849
- const skillPath = path14.join(baseDir, folderKey);
16974
+ const skillPath = path15.join(baseDir, folderKey);
16850
16975
  const sessionKey = `skill:${root}:${folderKey}`;
16851
16976
  groups.push({
16852
16977
  name: folderName,
@@ -16967,10 +17092,10 @@ async function enumerateGlob(pattern, cwd, category, isDynamic) {
16967
17092
  } catch {
16968
17093
  return [];
16969
17094
  }
16970
- return files.map((path37) => ({ path: path37, category }));
17095
+ return files.map((path38) => ({ path: path38, category }));
16971
17096
  }
16972
17097
  async function enumerateSkillBundle(baseDir, skillsRoot) {
16973
- const skillsDir = path14.resolve(baseDir, skillsRoot);
17098
+ const skillsDir = path15.resolve(baseDir, skillsRoot);
16974
17099
  let manifests;
16975
17100
  try {
16976
17101
  manifests = await globby2("*/SKILL.md", {
@@ -16986,7 +17111,7 @@ async function enumerateSkillBundle(baseDir, skillsRoot) {
16986
17111
  }
16987
17112
  const perSkillResults = await Promise.all(
16988
17113
  manifests.map(async (manifest) => {
16989
- const skillDir = path14.dirname(manifest);
17114
+ const skillDir = path15.dirname(manifest);
16990
17115
  try {
16991
17116
  return await globby2("**/*", {
16992
17117
  cwd: skillDir,
@@ -17035,11 +17160,11 @@ async function enumerateSymlinkedSkills(skillsDir) {
17035
17160
  const results = [];
17036
17161
  for (const entry of dirEntries) {
17037
17162
  if (!entry.isSymbolicLink()) continue;
17038
- const entryPath = path14.join(skillsDir, entry.name);
17163
+ const entryPath = path15.join(skillsDir, entry.name);
17039
17164
  try {
17040
17165
  const st = await stat(entryPath);
17041
17166
  if (st.isDirectory()) {
17042
- const hasManifest = await stat(path14.join(entryPath, "SKILL.md")).then(() => true).catch(() => false);
17167
+ const hasManifest = await stat(path15.join(entryPath, "SKILL.md")).then(() => true).catch(() => false);
17043
17168
  if (!hasManifest) continue;
17044
17169
  const realDir = await realpath(entryPath);
17045
17170
  const realFiles = await globby2("**/*", {
@@ -17052,7 +17177,7 @@ async function enumerateSymlinkedSkills(skillsDir) {
17052
17177
  }).catch(() => []);
17053
17178
  for (const f of realFiles) {
17054
17179
  results.push({
17055
- path: path14.join(entryPath, path14.relative(realDir, f)),
17180
+ path: path15.join(entryPath, path15.relative(realDir, f)),
17056
17181
  category: "skill"
17057
17182
  });
17058
17183
  }
@@ -17084,11 +17209,11 @@ function scopeForRoot(root) {
17084
17209
  return void 0;
17085
17210
  }
17086
17211
  function deriveIdentifier(filePath, baseDir) {
17087
- const relative2 = path14.relative(baseDir, filePath);
17212
+ const relative2 = path15.relative(baseDir, filePath);
17088
17213
  if (!relative2.startsWith("..")) {
17089
17214
  return relative2.replace(/\\/g, "/");
17090
17215
  }
17091
- return path14.basename(filePath);
17216
+ return path15.basename(filePath);
17092
17217
  }
17093
17218
 
17094
17219
  // src/features/analysis/skill_quarantine/enumerateInstalledSkills.ts
@@ -17100,8 +17225,8 @@ async function enumerateInstalledSkills(workspaceRoot) {
17100
17225
  );
17101
17226
  const home = homedir2();
17102
17227
  const agentGroups = regularFiles.filter((f) => f.category === "agent-config").map((f) => ({
17103
- name: path15.basename(f.path, path15.extname(f.path)),
17104
- root: f.path.startsWith(home + path15.sep) ? "home" : "workspace",
17228
+ name: path16.basename(f.path, path16.extname(f.path)),
17229
+ root: f.path.startsWith(home + path16.sep) ? "home" : "workspace",
17105
17230
  skillPath: f.path,
17106
17231
  files: [f],
17107
17232
  isFolder: false,
@@ -17185,32 +17310,32 @@ import {
17185
17310
  unlink,
17186
17311
  writeFile
17187
17312
  } from "fs/promises";
17188
- import path18 from "path";
17313
+ import path19 from "path";
17189
17314
  import AdmZip4 from "adm-zip";
17190
17315
 
17191
17316
  // src/features/analysis/skill_quarantine/paths.ts
17192
17317
  import { homedir as homedir3 } from "os";
17193
- import path16 from "path";
17318
+ import path17 from "path";
17194
17319
  function getQuarantineRoot() {
17195
- return path16.join(homedir3(), ".tracy", "quarantine", "claude", "skills");
17320
+ return path17.join(homedir3(), ".tracy", "quarantine", "claude", "skills");
17196
17321
  }
17197
17322
  function getQuarantineZipPath(md5) {
17198
- return path16.join(getQuarantineRoot(), `${md5}.zip`);
17323
+ return path17.join(getQuarantineRoot(), `${md5}.zip`);
17199
17324
  }
17200
17325
  function getTmpZipPath(md5, uuid) {
17201
- return path16.join(getQuarantineRoot(), `${md5}_tmp_${uuid}.zip`);
17326
+ return path17.join(getQuarantineRoot(), `${md5}_tmp_${uuid}.zip`);
17202
17327
  }
17203
17328
  var TMP_ZIP_REGEX = /^([0-9a-f]{32})_tmp_[0-9a-f-]+\.zip$/;
17204
17329
  var COMMITTED_ZIP_REGEX = /^([0-9a-f]{32})\.zip$/;
17205
17330
 
17206
17331
  // src/features/analysis/skill_quarantine/stubTemplate.ts
17207
- import path17 from "path";
17332
+ import path18 from "path";
17208
17333
  import { quote } from "shell-quote";
17209
17334
  var LEGACY_SUMMARY_FALLBACK = "not available (scan predates current schema)";
17210
17335
  function renderStub(params) {
17211
17336
  const folderOrFile = params.isFolder ? "skill folder" : "skill file";
17212
17337
  const reason = params.summary ?? LEGACY_SUMMARY_FALLBACK;
17213
- const extractParent = path17.dirname(params.origPath);
17338
+ const extractParent = path18.dirname(params.origPath);
17214
17339
  const recoverCommand = `rm -rf ${quote([params.origPath])} && unzip -o ${quote([params.quarantinedZipPath])} -d ${quote([extractParent])}`;
17215
17340
  return `# ${STUB_MARKER}
17216
17341
 
@@ -17324,7 +17449,7 @@ async function quarantineSkill(params) {
17324
17449
  }
17325
17450
  async function preregisterStubMd5(params) {
17326
17451
  const { skillPath, isFolder, origName, log: log2 } = params;
17327
- const stubFilePath = isFolder ? path18.join(skillPath, "SKILL.md") : skillPath;
17452
+ const stubFilePath = isFolder ? path19.join(skillPath, "SKILL.md") : skillPath;
17328
17453
  const stubEntryName = isFolder ? `${origName}/SKILL.md` : origName;
17329
17454
  const content = await readFile2(stubFilePath, "utf-8");
17330
17455
  const fileStat = await stat2(stubFilePath);
@@ -17337,7 +17462,7 @@ async function preregisterStubMd5(params) {
17337
17462
  mtimeMs: fileStat.mtimeMs
17338
17463
  };
17339
17464
  const stubGroup = {
17340
- name: isFolder ? origName : path18.basename(skillPath, path18.extname(skillPath)),
17465
+ name: isFolder ? origName : path19.basename(skillPath, path19.extname(skillPath)),
17341
17466
  root: "workspace",
17342
17467
  // unused by md5 computation
17343
17468
  skillPath,
@@ -17384,7 +17509,7 @@ async function writeStub(params) {
17384
17509
  if (isFolder) {
17385
17510
  await rm(skillPath, { recursive: true, force: true });
17386
17511
  await mkdir(skillPath, { recursive: true });
17387
- await writeFile(path18.join(skillPath, "SKILL.md"), stubContent, "utf8");
17512
+ await writeFile(path19.join(skillPath, "SKILL.md"), stubContent, "utf8");
17388
17513
  } else {
17389
17514
  await writeFile(skillPath, stubContent, "utf8");
17390
17515
  }
@@ -17406,7 +17531,7 @@ async function reconcileAndSweep(log2) {
17406
17531
  for (const entry of entries) {
17407
17532
  const md5 = TMP_ZIP_REGEX.exec(entry)?.[1];
17408
17533
  if (md5 === void 0) continue;
17409
- const full = path18.join(root, entry);
17534
+ const full = path19.join(root, entry);
17410
17535
  if (committed.has(md5)) {
17411
17536
  await unlink(full).catch(
17412
17537
  (err) => log2.warn(
@@ -17466,8 +17591,8 @@ async function addFolderAsync(zip, root, prefix) {
17466
17591
  async function walk(dir, relPrefix) {
17467
17592
  const entries = await readdir2(dir, { withFileTypes: true });
17468
17593
  for (const e of entries) {
17469
- const full = path18.join(dir, e.name);
17470
- const rel = path18.posix.join(relPrefix, e.name);
17594
+ const full = path19.join(dir, e.name);
17595
+ const rel = path19.posix.join(relPrefix, e.name);
17471
17596
  if (e.isDirectory()) await walk(full, rel);
17472
17597
  else if (e.isFile()) zip.addFile(rel, await readFile2(full));
17473
17598
  }
@@ -17513,8 +17638,8 @@ var SKILL_PARENT_DIRS = [
17513
17638
  async function getSkillDirsMtimeMs(cwd) {
17514
17639
  const home = homedir4();
17515
17640
  const dirs = SKILL_PARENT_DIRS.flatMap((d) => [
17516
- path19.join(cwd, d),
17517
- path19.join(home, d)
17641
+ path20.join(cwd, d),
17642
+ path20.join(home, d)
17518
17643
  ]);
17519
17644
  let max = 0;
17520
17645
  for (const dir of dirs) {
@@ -17627,9 +17752,9 @@ async function runQuarantineCheckIfNeeded(opts) {
17627
17752
  }
17628
17753
 
17629
17754
  // src/features/claude_code/daemon_pid_file.ts
17630
- import fs13 from "fs";
17631
- import os4 from "os";
17632
- import path20 from "path";
17755
+ import fs14 from "fs";
17756
+ import os5 from "os";
17757
+ import path21 from "path";
17633
17758
 
17634
17759
  // src/features/claude_code/data_collector_constants.ts
17635
17760
  var CC_VERSION_CACHE_KEY = "claudeCode.detectedCCVersion";
@@ -17655,26 +17780,26 @@ var DAEMON_SHUTDOWN_DRAIN_MS = 6e3;
17655
17780
 
17656
17781
  // src/features/claude_code/daemon_pid_file.ts
17657
17782
  function getMobbdevDir() {
17658
- return path20.join(os4.homedir(), ".mobbdev");
17783
+ return path21.join(os5.homedir(), ".mobbdev");
17659
17784
  }
17660
17785
  function getDaemonCheckScriptPath() {
17661
- return path20.join(getMobbdevDir(), "daemon-check.js");
17786
+ return path21.join(getMobbdevDir(), "daemon-check.js");
17662
17787
  }
17663
17788
  var DaemonPidFile = class {
17664
17789
  constructor() {
17665
17790
  __publicField(this, "data", null);
17666
17791
  }
17667
17792
  get filePath() {
17668
- return path20.join(getMobbdevDir(), "daemon.pid");
17793
+ return path21.join(getMobbdevDir(), "daemon.pid");
17669
17794
  }
17670
17795
  /** Ensure ~/.mobbdev/ directory exists. */
17671
17796
  ensureDir() {
17672
- fs13.mkdirSync(getMobbdevDir(), { recursive: true });
17797
+ fs14.mkdirSync(getMobbdevDir(), { recursive: true });
17673
17798
  }
17674
17799
  /** Read the PID file from disk. Returns the parsed data or null. */
17675
17800
  read() {
17676
17801
  try {
17677
- const raw = fs13.readFileSync(this.filePath, "utf8");
17802
+ const raw = fs14.readFileSync(this.filePath, "utf8");
17678
17803
  const parsed = JSON.parse(raw);
17679
17804
  if (typeof parsed.pid !== "number" || typeof parsed.startedAt !== "number" || typeof parsed.heartbeat !== "number") {
17680
17805
  this.data = null;
@@ -17694,14 +17819,14 @@ var DaemonPidFile = class {
17694
17819
  heartbeat: Date.now(),
17695
17820
  version
17696
17821
  };
17697
- fs13.writeFileSync(this.filePath, JSON.stringify(this.data), "utf8");
17822
+ fs14.writeFileSync(this.filePath, JSON.stringify(this.data), "utf8");
17698
17823
  }
17699
17824
  /** Update the heartbeat timestamp of the current PID file. */
17700
17825
  updateHeartbeat() {
17701
17826
  if (!this.data) this.read();
17702
17827
  if (!this.data) return;
17703
17828
  this.data.heartbeat = Date.now();
17704
- fs13.writeFileSync(this.filePath, JSON.stringify(this.data), "utf8");
17829
+ fs14.writeFileSync(this.filePath, JSON.stringify(this.data), "utf8");
17705
17830
  }
17706
17831
  /** Check whether the previously read PID data represents a live daemon. */
17707
17832
  isAlive() {
@@ -17718,7 +17843,7 @@ var DaemonPidFile = class {
17718
17843
  remove() {
17719
17844
  this.data = null;
17720
17845
  try {
17721
- fs13.unlinkSync(this.filePath);
17846
+ fs14.unlinkSync(this.filePath);
17722
17847
  } catch {
17723
17848
  }
17724
17849
  }
@@ -17728,7 +17853,7 @@ var DaemonPidFile = class {
17728
17853
  import { execFile } from "child_process";
17729
17854
  import { createHash as createHash3 } from "crypto";
17730
17855
  import { access as access2, open as open4, readdir as readdir3, readFile as readFile3, unlink as unlink2 } from "fs/promises";
17731
- import path21 from "path";
17856
+ import path22 from "path";
17732
17857
  import { promisify } from "util";
17733
17858
 
17734
17859
  // src/features/analysis/context_file_uploader.ts
@@ -18092,8 +18217,8 @@ function createConfigstoreStream(store, opts) {
18092
18217
  heartbeatBuffer.length = 0;
18093
18218
  }
18094
18219
  }
18095
- function setScopePath(path37) {
18096
- scopePath = path37;
18220
+ function setScopePath(path38) {
18221
+ scopePath = path38;
18097
18222
  }
18098
18223
  return { writable, flush, setScopePath };
18099
18224
  }
@@ -18175,22 +18300,22 @@ function createDdBatch(config2) {
18175
18300
 
18176
18301
  // src/utils/shared-logger/hostname.ts
18177
18302
  import { createHash as createHash2 } from "crypto";
18178
- import os5 from "os";
18303
+ import os6 from "os";
18179
18304
  function hashString(input) {
18180
18305
  return createHash2("sha256").update(input).digest("hex").slice(0, 16);
18181
18306
  }
18182
18307
  function getPlainHostname() {
18183
18308
  try {
18184
- return `${os5.userInfo().username}@${os5.hostname()}`;
18309
+ return `${os6.userInfo().username}@${os6.hostname()}`;
18185
18310
  } catch {
18186
- return `unknown@${os5.hostname()}`;
18311
+ return `unknown@${os6.hostname()}`;
18187
18312
  }
18188
18313
  }
18189
18314
  function getHashedHostname() {
18190
18315
  try {
18191
- return `${hashString(os5.userInfo().username)}@${hashString(os5.hostname())}`;
18316
+ return `${hashString(os6.userInfo().username)}@${hashString(os6.hostname())}`;
18192
18317
  } catch {
18193
- return `unknown@${hashString(os5.hostname())}`;
18318
+ return `unknown@${hashString(os6.hostname())}`;
18194
18319
  }
18195
18320
  }
18196
18321
 
@@ -18317,7 +18442,7 @@ function createLogger(config2) {
18317
18442
 
18318
18443
  // src/features/claude_code/hook_logger.ts
18319
18444
  var DD_RUM_TOKEN = true ? "pubf59c0182545bfb4c299175119f1abf9b" : "";
18320
- var CLI_VERSION = true ? "1.4.48" : "unknown";
18445
+ var CLI_VERSION = true ? "1.4.49" : "unknown";
18321
18446
  var NAMESPACE = "mobbdev-claude-code-hook-logs";
18322
18447
  var claudeCodeVersion;
18323
18448
  function buildDdTags() {
@@ -18434,12 +18559,12 @@ async function resolveTranscriptPath(transcriptPath, sessionId) {
18434
18559
  return transcriptPath;
18435
18560
  } catch {
18436
18561
  }
18437
- const filename = path21.basename(transcriptPath);
18438
- const dirName = path21.basename(path21.dirname(transcriptPath));
18439
- const projectsDir = path21.dirname(path21.dirname(transcriptPath));
18562
+ const filename = path22.basename(transcriptPath);
18563
+ const dirName = path22.basename(path22.dirname(transcriptPath));
18564
+ const projectsDir = path22.dirname(path22.dirname(transcriptPath));
18440
18565
  const baseDirName = dirName.replace(/[-.]claude-worktrees-.+$/, "");
18441
18566
  if (baseDirName !== dirName) {
18442
- const candidate = path21.join(projectsDir, baseDirName, filename);
18567
+ const candidate = path22.join(projectsDir, baseDirName, filename);
18443
18568
  try {
18444
18569
  await access2(candidate);
18445
18570
  hookLog.info(
@@ -18461,7 +18586,7 @@ async function resolveTranscriptPath(transcriptPath, sessionId) {
18461
18586
  const dirs = await readdir3(projectsDir);
18462
18587
  for (const dir of dirs) {
18463
18588
  if (dir === dirName) continue;
18464
- const candidate = path21.join(projectsDir, dir, filename);
18589
+ const candidate = path22.join(projectsDir, dir, filename);
18465
18590
  try {
18466
18591
  await access2(candidate);
18467
18592
  hookLog.info(
@@ -18683,7 +18808,7 @@ async function cleanupStaleSessions(configDir) {
18683
18808
  );
18684
18809
  let deletedCount = 0;
18685
18810
  for (const file of sessionFiles) {
18686
- const filePath = path21.join(configDir, file);
18811
+ const filePath = path22.join(configDir, file);
18687
18812
  try {
18688
18813
  const content = JSON.parse(await readFile3(filePath, "utf-8"));
18689
18814
  let newest = 0;
@@ -18980,17 +19105,17 @@ function summarizeUploadErrTypes(errs) {
18980
19105
  }
18981
19106
 
18982
19107
  // src/features/claude_code/install_hook.ts
18983
- import fs14 from "fs";
19108
+ import fs15 from "fs";
18984
19109
  import fsPromises4 from "fs/promises";
18985
- import os6 from "os";
18986
- import path22 from "path";
19110
+ import os7 from "os";
19111
+ import path23 from "path";
18987
19112
  import chalk11 from "chalk";
18988
19113
 
18989
19114
  // src/features/claude_code/daemon-check-shim.tmpl.js
18990
19115
  var daemon_check_shim_tmpl_default = "// Mobb daemon shim \u2014 checks if daemon is alive, spawns if dead.\n// Auto-generated by mobbdev CLI. Do not edit.\nvar fs = require('fs')\nvar spawn = require('child_process').spawn\nvar path = require('path')\nvar os = require('os')\n\nvar pidFile = path.join(os.homedir(), '.mobbdev', 'daemon.pid')\nvar HEARTBEAT_STALE_MS = __HEARTBEAT_STALE_MS__\n\ntry {\n var data = JSON.parse(fs.readFileSync(pidFile, 'utf8'))\n if (Date.now() - data.heartbeat > HEARTBEAT_STALE_MS) throw new Error('stale')\n process.kill(data.pid, 0) // throws ESRCH if the process is gone\n} catch (e) {\n var localCli = process.env.MOBBDEV_LOCAL_CLI\n var child = localCli\n ? spawn('node', [localCli, 'claude-code-daemon'], { detached: true, stdio: 'ignore', windowsHide: true })\n : spawn('npx', ['--yes', 'mobbdev@latest', 'claude-code-daemon'], { detached: true, stdio: 'ignore', shell: true, windowsHide: true })\n child.unref()\n}\n";
18991
19116
 
18992
19117
  // src/features/claude_code/install_hook.ts
18993
- var CLAUDE_SETTINGS_PATH = path22.join(os6.homedir(), ".claude", "settings.json");
19118
+ var CLAUDE_SETTINGS_PATH = path23.join(os7.homedir(), ".claude", "settings.json");
18994
19119
  var RECOMMENDED_MATCHER = "*";
18995
19120
  async function claudeSettingsExists() {
18996
19121
  try {
@@ -19025,8 +19150,8 @@ function getDaemonCheckScript() {
19025
19150
  );
19026
19151
  }
19027
19152
  function writeDaemonCheckScript() {
19028
- fs14.mkdirSync(getMobbdevDir(), { recursive: true });
19029
- fs14.writeFileSync(getDaemonCheckScriptPath(), getDaemonCheckScript(), "utf8");
19153
+ fs15.mkdirSync(getMobbdevDir(), { recursive: true });
19154
+ fs15.writeFileSync(getDaemonCheckScriptPath(), getDaemonCheckScript(), "utf8");
19030
19155
  }
19031
19156
  function buildHookCommand(envPrefix) {
19032
19157
  const nodeBin = process.execPath || "node";
@@ -19137,17 +19262,17 @@ async function installMobbHooks(options = {}) {
19137
19262
 
19138
19263
  // src/features/claude_code/transcript_scanner.ts
19139
19264
  import { lstat as lstat2, open as open5, readdir as readdir4, stat as stat4 } from "fs/promises";
19140
- import os7 from "os";
19141
- import path23 from "path";
19265
+ import os8 from "os";
19266
+ import path24 from "path";
19142
19267
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
19143
19268
  function getClaudeProjectsDirs() {
19144
19269
  const dirs = [];
19145
19270
  const configDir = process.env["CLAUDE_CONFIG_DIR"];
19146
19271
  if (configDir) {
19147
- dirs.push(path23.join(configDir, "projects"));
19272
+ dirs.push(path24.join(configDir, "projects"));
19148
19273
  }
19149
- dirs.push(path23.join(os7.homedir(), ".config", "claude", "projects"));
19150
- dirs.push(path23.join(os7.homedir(), ".claude", "projects"));
19274
+ dirs.push(path24.join(os8.homedir(), ".config", "claude", "projects"));
19275
+ dirs.push(path24.join(os8.homedir(), ".claude", "projects"));
19151
19276
  return dirs;
19152
19277
  }
19153
19278
  var META_MAX_BYTES = 4096;
@@ -19203,7 +19328,7 @@ async function collectJsonlFiles(files, dir, projectDir, seen, now, results, ove
19203
19328
  sessionId = basename2;
19204
19329
  isSubagent = false;
19205
19330
  }
19206
- const filePath = path23.join(dir, file);
19331
+ const filePath = path24.join(dir, file);
19207
19332
  if (seen.has(filePath)) continue;
19208
19333
  seen.add(filePath);
19209
19334
  let fileStat;
@@ -19237,7 +19362,7 @@ async function scanForTranscripts(projectsDirs = getClaudeProjectsDirs()) {
19237
19362
  continue;
19238
19363
  }
19239
19364
  for (const projName of projectDirs) {
19240
- const projPath = path23.join(projectsDir, projName);
19365
+ const projPath = path24.join(projectsDir, projName);
19241
19366
  let projStat;
19242
19367
  try {
19243
19368
  projStat = await stat4(projPath);
@@ -19254,7 +19379,7 @@ async function scanForTranscripts(projectsDirs = getClaudeProjectsDirs()) {
19254
19379
  await collectJsonlFiles(files, projPath, projPath, seen, now, results);
19255
19380
  for (const entry of files) {
19256
19381
  if (!UUID_RE.test(entry)) continue;
19257
- const subagentsDir = path23.join(projPath, entry, "subagents");
19382
+ const subagentsDir = path24.join(projPath, entry, "subagents");
19258
19383
  if (knownAbsentSubagentDirs.has(subagentsDir)) continue;
19259
19384
  try {
19260
19385
  const s = await stat4(subagentsDir);
@@ -19360,8 +19485,8 @@ async function startDaemon() {
19360
19485
  const sessionCwdCache = /* @__PURE__ */ new Map();
19361
19486
  let lastContextScanMs = 0;
19362
19487
  const machineContext = {
19363
- cpuCount: os8.cpus().length,
19364
- totalMemGB: Math.round(os8.totalmem() / 1024 ** 3),
19488
+ cpuCount: os9.cpus().length,
19489
+ totalMemGB: Math.round(os9.totalmem() / 1024 ** 3),
19365
19490
  nodeVersion: process.version
19366
19491
  };
19367
19492
  while (true) {
@@ -19384,7 +19509,7 @@ async function startDaemon() {
19384
19509
  for (const transcript of changed) {
19385
19510
  const sessionStore = createSessionConfigStore(transcript.sessionId);
19386
19511
  if (!cleanupConfigDir) {
19387
- cleanupConfigDir = path24.dirname(sessionStore.path);
19512
+ cleanupConfigDir = path25.dirname(sessionStore.path);
19388
19513
  }
19389
19514
  pidFile.updateHeartbeat();
19390
19515
  const drainStart = Date.now();
@@ -19672,6 +19797,12 @@ var claudeCodeDaemonBuilder = (yargs2) => {
19672
19797
  ).strict();
19673
19798
  };
19674
19799
  var claudeCodeInstallHookHandler = async (argv) => {
19800
+ if (isStandaloneBinary()) {
19801
+ console.error(
19802
+ "Claude Code hooks are not available in the standalone mobbdev binary (they need a Node.js runtime). Install them with the npm package instead: npx mobbdev@latest claude-code-install-hook"
19803
+ );
19804
+ process.exit(1);
19805
+ }
19675
19806
  try {
19676
19807
  await getAuthenticatedGQLClient({ isSkipPrompts: false });
19677
19808
  await installMobbHooks({ saveEnv: argv["save-env"] });
@@ -19740,8 +19871,8 @@ var WorkspaceService = class {
19740
19871
  * Sets a known workspace path that was discovered through successful validation
19741
19872
  * @param path The validated workspace path to store
19742
19873
  */
19743
- static setKnownWorkspacePath(path37) {
19744
- this.knownWorkspacePath = path37;
19874
+ static setKnownWorkspacePath(path38) {
19875
+ this.knownWorkspacePath = path38;
19745
19876
  }
19746
19877
  /**
19747
19878
  * Gets the known workspace path that was previously validated
@@ -19882,7 +20013,7 @@ var logDebug = (message, data) => logger2.log(message, "debug", data);
19882
20013
  var log = logger2.log.bind(logger2);
19883
20014
 
19884
20015
  // src/mcp/services/McpGQLClient.ts
19885
- import os9 from "os";
20016
+ import os10 from "os";
19886
20017
  init_client_generates();
19887
20018
  init_configs();
19888
20019
 
@@ -20393,7 +20524,7 @@ var McpGQLClient = class extends GQLClient {
20393
20524
  projectId: params.projectId ?? null,
20394
20525
  repoUrl: params.repoUrl ?? null,
20395
20526
  riskCount: params.riskCount ?? null,
20396
- computerName: os9.hostname(),
20527
+ computerName: os10.hostname(),
20397
20528
  computerUser: getComputerUser() ?? null,
20398
20529
  clientVersion: packageJson.version
20399
20530
  });
@@ -20676,9 +20807,9 @@ async function createAuthenticatedMcpGQLClient({
20676
20807
 
20677
20808
  // src/mcp/services/McpUsageService/host.ts
20678
20809
  import { execSync as execSync2 } from "child_process";
20679
- import fs15 from "fs";
20680
- import os10 from "os";
20681
- import path25 from "path";
20810
+ import fs16 from "fs";
20811
+ import os11 from "os";
20812
+ import path26 from "path";
20682
20813
  var IDEs = ["cursor", "windsurf", "webstorm", "vscode", "claude"];
20683
20814
  var runCommand = (cmd) => {
20684
20815
  try {
@@ -20692,18 +20823,18 @@ var gitInfo = {
20692
20823
  email: runCommand("git config user.email")
20693
20824
  };
20694
20825
  var getClaudeWorkspacePaths = () => {
20695
- const home = os10.homedir();
20696
- const claudeIdePath = path25.join(home, ".claude", "ide");
20826
+ const home = os11.homedir();
20827
+ const claudeIdePath = path26.join(home, ".claude", "ide");
20697
20828
  const workspacePaths = [];
20698
- if (!fs15.existsSync(claudeIdePath)) {
20829
+ if (!fs16.existsSync(claudeIdePath)) {
20699
20830
  return workspacePaths;
20700
20831
  }
20701
20832
  try {
20702
- const lockFiles = fs15.readdirSync(claudeIdePath).filter((file) => file.endsWith(".lock"));
20833
+ const lockFiles = fs16.readdirSync(claudeIdePath).filter((file) => file.endsWith(".lock"));
20703
20834
  for (const lockFile of lockFiles) {
20704
- const lockFilePath = path25.join(claudeIdePath, lockFile);
20835
+ const lockFilePath = path26.join(claudeIdePath, lockFile);
20705
20836
  try {
20706
- const lockContent = JSON.parse(fs15.readFileSync(lockFilePath, "utf8"));
20837
+ const lockContent = JSON.parse(fs16.readFileSync(lockFilePath, "utf8"));
20707
20838
  if (lockContent.workspaceFolders && Array.isArray(lockContent.workspaceFolders)) {
20708
20839
  workspacePaths.push(...lockContent.workspaceFolders);
20709
20840
  }
@@ -20721,29 +20852,29 @@ var getClaudeWorkspacePaths = () => {
20721
20852
  return workspacePaths;
20722
20853
  };
20723
20854
  var getMCPConfigPaths = (hostName) => {
20724
- const home = os10.homedir();
20855
+ const home = os11.homedir();
20725
20856
  const currentDir = process.env["WORKSPACE_FOLDER_PATHS"] || process.env["PWD"] || process.cwd();
20726
20857
  switch (hostName.toLowerCase()) {
20727
20858
  case "cursor":
20728
20859
  return [
20729
- path25.join(currentDir, ".cursor", "mcp.json"),
20860
+ path26.join(currentDir, ".cursor", "mcp.json"),
20730
20861
  // local first
20731
- path25.join(home, ".cursor", "mcp.json")
20862
+ path26.join(home, ".cursor", "mcp.json")
20732
20863
  ];
20733
20864
  case "windsurf":
20734
20865
  return [
20735
- path25.join(currentDir, ".codeium", "mcp_config.json"),
20866
+ path26.join(currentDir, ".codeium", "mcp_config.json"),
20736
20867
  // local first
20737
- path25.join(home, ".codeium", "windsurf", "mcp_config.json")
20868
+ path26.join(home, ".codeium", "windsurf", "mcp_config.json")
20738
20869
  ];
20739
20870
  case "webstorm":
20740
20871
  return [];
20741
20872
  case "visualstudiocode":
20742
20873
  case "vscode":
20743
20874
  return [
20744
- path25.join(currentDir, ".vscode", "mcp.json"),
20875
+ path26.join(currentDir, ".vscode", "mcp.json"),
20745
20876
  // local first
20746
- process.platform === "win32" ? path25.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path25.join(
20877
+ process.platform === "win32" ? path26.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path26.join(
20747
20878
  home,
20748
20879
  "Library",
20749
20880
  "Application Support",
@@ -20754,13 +20885,13 @@ var getMCPConfigPaths = (hostName) => {
20754
20885
  ];
20755
20886
  case "claude": {
20756
20887
  const claudePaths = [
20757
- path25.join(currentDir, ".claude.json"),
20888
+ path26.join(currentDir, ".claude.json"),
20758
20889
  // local first
20759
- path25.join(home, ".claude.json")
20890
+ path26.join(home, ".claude.json")
20760
20891
  ];
20761
20892
  const workspacePaths = getClaudeWorkspacePaths();
20762
20893
  for (const workspacePath of workspacePaths) {
20763
- claudePaths.push(path25.join(workspacePath, ".mcp.json"));
20894
+ claudePaths.push(path26.join(workspacePath, ".mcp.json"));
20764
20895
  }
20765
20896
  return claudePaths;
20766
20897
  }
@@ -20769,9 +20900,9 @@ var getMCPConfigPaths = (hostName) => {
20769
20900
  }
20770
20901
  };
20771
20902
  var readConfigFile = (filePath) => {
20772
- if (!fs15.existsSync(filePath)) return null;
20903
+ if (!fs16.existsSync(filePath)) return null;
20773
20904
  try {
20774
- return JSON.parse(fs15.readFileSync(filePath, "utf8"));
20905
+ return JSON.parse(fs16.readFileSync(filePath, "utf8"));
20775
20906
  } catch (error) {
20776
20907
  logWarn(`[UsageService] Failed to read MCP config: ${filePath}`);
20777
20908
  return null;
@@ -20811,7 +20942,7 @@ var readMCPConfig = (hostName) => {
20811
20942
  };
20812
20943
  var getRunningProcesses = () => {
20813
20944
  try {
20814
- return os10.platform() === "win32" ? execSync2("tasklist", { encoding: "utf8" }) : execSync2("ps aux", { encoding: "utf8" });
20945
+ return os11.platform() === "win32" ? execSync2("tasklist", { encoding: "utf8" }) : execSync2("ps aux", { encoding: "utf8" });
20815
20946
  } catch {
20816
20947
  return "";
20817
20948
  }
@@ -20886,7 +21017,7 @@ var versionCommands = {
20886
21017
  }
20887
21018
  };
20888
21019
  var getProcessInfo = (pid) => {
20889
- const platform2 = os10.platform();
21020
+ const platform2 = os11.platform();
20890
21021
  try {
20891
21022
  if (platform2 === "linux" || platform2 === "darwin") {
20892
21023
  const output = execSync2(`ps -o pid=,ppid=,comm= -p ${pid}`, {
@@ -20921,10 +21052,10 @@ var getHostInfo = (additionalMcpList) => {
20921
21052
  const ideConfigPaths = /* @__PURE__ */ new Set();
20922
21053
  for (const ide of IDEs) {
20923
21054
  const configPaths = getMCPConfigPaths(ide);
20924
- configPaths.forEach((path37) => ideConfigPaths.add(path37));
21055
+ configPaths.forEach((path38) => ideConfigPaths.add(path38));
20925
21056
  }
20926
21057
  const uniqueAdditionalPaths = additionalMcpList.filter(
20927
- (path37) => !ideConfigPaths.has(path37)
21058
+ (path38) => !ideConfigPaths.has(path38)
20928
21059
  );
20929
21060
  for (const ide of IDEs) {
20930
21061
  const cfg = readMCPConfig(ide);
@@ -21005,7 +21136,7 @@ var getHostInfo = (additionalMcpList) => {
21005
21136
  const config2 = allConfigs[ide] || null;
21006
21137
  const ideName = ide.charAt(0).toUpperCase() + ide.slice(1) || "Unknown";
21007
21138
  let ideVersion = "Unknown";
21008
- const platform2 = os10.platform();
21139
+ const platform2 = os11.platform();
21009
21140
  const cmds = versionCommands[ideName]?.[platform2] ?? [];
21010
21141
  for (const cmd of cmds) {
21011
21142
  try {
@@ -21038,15 +21169,15 @@ var getHostInfo = (additionalMcpList) => {
21038
21169
 
21039
21170
  // src/mcp/services/McpUsageService/McpUsageService.ts
21040
21171
  import fetch6 from "node-fetch";
21041
- import os12 from "os";
21172
+ import os13 from "os";
21042
21173
  import { v4 as uuidv42, v5 as uuidv5 } from "uuid";
21043
21174
  init_configs();
21044
21175
 
21045
21176
  // src/mcp/services/McpUsageService/system.ts
21046
21177
  init_configs();
21047
- import fs16 from "fs";
21048
- import os11 from "os";
21049
- import path26 from "path";
21178
+ import fs17 from "fs";
21179
+ import os12 from "os";
21180
+ import path27 from "path";
21050
21181
  var MAX_DEPTH = 2;
21051
21182
  var patterns = ["mcp", "claude"];
21052
21183
  var isFileMatch = (fileName) => {
@@ -21055,7 +21186,7 @@ var isFileMatch = (fileName) => {
21055
21186
  };
21056
21187
  var safeAccess = async (filePath) => {
21057
21188
  try {
21058
- await fs16.promises.access(filePath, fs16.constants.R_OK);
21189
+ await fs17.promises.access(filePath, fs17.constants.R_OK);
21059
21190
  return true;
21060
21191
  } catch {
21061
21192
  return false;
@@ -21064,9 +21195,9 @@ var safeAccess = async (filePath) => {
21064
21195
  var searchDir = async (dir, depth = 0) => {
21065
21196
  const results = [];
21066
21197
  if (depth > MAX_DEPTH) return results;
21067
- const entries = await fs16.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
21198
+ const entries = await fs17.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
21068
21199
  for (const entry of entries) {
21069
- const fullPath = path26.join(dir, entry.name);
21200
+ const fullPath = path27.join(dir, entry.name);
21070
21201
  if (entry.isFile() && isFileMatch(entry.name)) {
21071
21202
  results.push(fullPath);
21072
21203
  } else if (entry.isDirectory()) {
@@ -21080,17 +21211,17 @@ var searchDir = async (dir, depth = 0) => {
21080
21211
  };
21081
21212
  var findSystemMCPConfigs = async () => {
21082
21213
  try {
21083
- const home = os11.homedir();
21084
- const platform2 = os11.platform();
21214
+ const home = os12.homedir();
21215
+ const platform2 = os12.platform();
21085
21216
  const knownDirs = platform2 === "win32" ? [
21086
- path26.join(home, ".cursor"),
21087
- path26.join(home, "Documents"),
21088
- path26.join(home, "Downloads")
21217
+ path27.join(home, ".cursor"),
21218
+ path27.join(home, "Documents"),
21219
+ path27.join(home, "Downloads")
21089
21220
  ] : [
21090
- path26.join(home, ".cursor"),
21091
- process.env["XDG_CONFIG_HOME"] || path26.join(home, ".config"),
21092
- path26.join(home, "Documents"),
21093
- path26.join(home, "Downloads")
21221
+ path27.join(home, ".cursor"),
21222
+ process.env["XDG_CONFIG_HOME"] || path27.join(home, ".config"),
21223
+ path27.join(home, "Documents"),
21224
+ path27.join(home, "Downloads")
21094
21225
  ];
21095
21226
  const timeoutPromise = new Promise(
21096
21227
  (resolve) => setTimeout(() => {
@@ -21102,7 +21233,7 @@ var findSystemMCPConfigs = async () => {
21102
21233
  );
21103
21234
  const searchPromise = Promise.all(
21104
21235
  knownDirs.map(
21105
- (dir) => fs16.existsSync(dir) ? searchDir(dir) : Promise.resolve([])
21236
+ (dir) => fs17.existsSync(dir) ? searchDir(dir) : Promise.resolve([])
21106
21237
  )
21107
21238
  ).then((results) => results.flat());
21108
21239
  return await Promise.race([timeoutPromise, searchPromise]);
@@ -21153,7 +21284,7 @@ var McpUsageService = class {
21153
21284
  generateHostId() {
21154
21285
  const stored = configStore.get(this.configKey);
21155
21286
  if (stored?.mcpHostId) return stored.mcpHostId;
21156
- const interfaces = os12.networkInterfaces();
21287
+ const interfaces = os13.networkInterfaces();
21157
21288
  const macs = [];
21158
21289
  for (const iface of Object.values(interfaces)) {
21159
21290
  if (!iface) continue;
@@ -21161,7 +21292,7 @@ var McpUsageService = class {
21161
21292
  if (net.mac && net.mac !== "00:00:00:00:00:00") macs.push(net.mac);
21162
21293
  }
21163
21294
  }
21164
- const macString = macs.length ? macs.sort().join(",") : `${os12.hostname()}-${uuidv42()}`;
21295
+ const macString = macs.length ? macs.sort().join(",") : `${os13.hostname()}-${uuidv42()}`;
21165
21296
  const hostId = uuidv5(macString, uuidv5.DNS);
21166
21297
  logDebug("[UsageService] Generated new host ID", { hostId });
21167
21298
  return hostId;
@@ -21184,7 +21315,7 @@ var McpUsageService = class {
21184
21315
  mcpHostId,
21185
21316
  organizationId,
21186
21317
  mcpVersion: packageJson.version,
21187
- mcpOsName: os12.platform(),
21318
+ mcpOsName: os13.platform(),
21188
21319
  mcps: JSON.stringify(mcps),
21189
21320
  status,
21190
21321
  userName: user.name,
@@ -23505,31 +23636,31 @@ For a complete security audit workflow, use the \`full-security-audit\` prompt.
23505
23636
  };
23506
23637
 
23507
23638
  // src/mcp/services/McpDetectionService/CursorMcpDetectionService.ts
23508
- import * as fs19 from "fs";
23509
- import * as os14 from "os";
23510
- import * as path28 from "path";
23639
+ import * as fs20 from "fs";
23640
+ import * as os15 from "os";
23641
+ import * as path29 from "path";
23511
23642
 
23512
23643
  // src/mcp/services/McpDetectionService/BaseMcpDetectionService.ts
23513
23644
  init_configs();
23514
- import * as fs18 from "fs";
23645
+ import * as fs19 from "fs";
23515
23646
  import fetch7 from "node-fetch";
23516
- import * as path27 from "path";
23647
+ import * as path28 from "path";
23517
23648
 
23518
23649
  // src/mcp/services/McpDetectionService/McpDetectionServiceUtils.ts
23519
- import * as fs17 from "fs";
23520
- import * as os13 from "os";
23650
+ import * as fs18 from "fs";
23651
+ import * as os14 from "os";
23521
23652
 
23522
23653
  // src/mcp/services/McpDetectionService/VscodeMcpDetectionService.ts
23523
- import * as fs20 from "fs";
23524
- import * as os15 from "os";
23525
- import * as path29 from "path";
23654
+ import * as fs21 from "fs";
23655
+ import * as os16 from "os";
23656
+ import * as path30 from "path";
23526
23657
 
23527
23658
  // src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesTool.ts
23528
23659
  import { z as z37 } from "zod";
23529
23660
 
23530
23661
  // src/mcp/services/PathValidation.ts
23531
- import fs21 from "fs";
23532
- import path30 from "path";
23662
+ import fs22 from "fs";
23663
+ import path31 from "path";
23533
23664
  async function validatePath(inputPath) {
23534
23665
  logDebug("Validating MCP path", { inputPath });
23535
23666
  if (/^\/[a-zA-Z]:\//.test(inputPath)) {
@@ -23561,7 +23692,7 @@ async function validatePath(inputPath) {
23561
23692
  logError(error);
23562
23693
  return { isValid: false, error, path: inputPath };
23563
23694
  }
23564
- const normalizedPath = path30.normalize(inputPath);
23695
+ const normalizedPath = path31.normalize(inputPath);
23565
23696
  if (normalizedPath.includes("..")) {
23566
23697
  const error = `Normalized path contains path traversal patterns: ${inputPath}`;
23567
23698
  logError(error);
@@ -23588,7 +23719,7 @@ async function validatePath(inputPath) {
23588
23719
  logDebug("Path validation successful", { inputPath });
23589
23720
  logDebug("Checking path existence", { inputPath });
23590
23721
  try {
23591
- await fs21.promises.access(inputPath);
23722
+ await fs22.promises.access(inputPath);
23592
23723
  logDebug("Path exists and is accessible", { inputPath });
23593
23724
  WorkspaceService.setKnownWorkspacePath(inputPath);
23594
23725
  logDebug("Stored validated path in WorkspaceService", { inputPath });
@@ -24342,10 +24473,10 @@ If you wish to scan files that were recently changed in your git history call th
24342
24473
  init_FileUtils();
24343
24474
  init_GitService();
24344
24475
  init_configs();
24345
- import fs22 from "fs/promises";
24476
+ import fs23 from "fs/promises";
24346
24477
  import nodePath from "path";
24347
24478
  var getLocalFiles = async ({
24348
- path: path37,
24479
+ path: path38,
24349
24480
  maxFileSize = MCP_MAX_FILE_SIZE,
24350
24481
  maxFiles,
24351
24482
  isAllFilesScan,
@@ -24353,17 +24484,17 @@ var getLocalFiles = async ({
24353
24484
  scanRecentlyChangedFiles
24354
24485
  }) => {
24355
24486
  logDebug(`[${scanContext}] Starting getLocalFiles`, {
24356
- path: path37,
24487
+ path: path38,
24357
24488
  maxFileSize,
24358
24489
  maxFiles,
24359
24490
  isAllFilesScan,
24360
24491
  scanRecentlyChangedFiles
24361
24492
  });
24362
24493
  try {
24363
- const resolvedRepoPath = await fs22.realpath(path37);
24494
+ const resolvedRepoPath = await fs23.realpath(path38);
24364
24495
  logDebug(`[${scanContext}] Resolved repository path`, {
24365
24496
  resolvedRepoPath,
24366
- originalPath: path37
24497
+ originalPath: path38
24367
24498
  });
24368
24499
  const gitService = new GitService(resolvedRepoPath, log);
24369
24500
  const gitValidation = await gitService.validateRepository();
@@ -24376,7 +24507,7 @@ var getLocalFiles = async ({
24376
24507
  if (!gitValidation.isValid || isAllFilesScan) {
24377
24508
  try {
24378
24509
  files = await FileUtils.getLastChangedFiles({
24379
- dir: path37,
24510
+ dir: path38,
24380
24511
  maxFileSize,
24381
24512
  maxFiles,
24382
24513
  isAllFilesScan
@@ -24440,7 +24571,7 @@ var getLocalFiles = async ({
24440
24571
  absoluteFilePath
24441
24572
  );
24442
24573
  try {
24443
- const fileStat = await fs22.stat(absoluteFilePath);
24574
+ const fileStat = await fs23.stat(absoluteFilePath);
24444
24575
  return {
24445
24576
  filename: nodePath.basename(absoluteFilePath),
24446
24577
  relativePath,
@@ -24468,7 +24599,7 @@ var getLocalFiles = async ({
24468
24599
  logError(`${scanContext}Unexpected error in getLocalFiles`, {
24469
24600
  error: error instanceof Error ? error.message : String(error),
24470
24601
  stack: error instanceof Error ? error.stack : void 0,
24471
- path: path37
24602
+ path: path38
24472
24603
  });
24473
24604
  throw error;
24474
24605
  }
@@ -24477,8 +24608,8 @@ var getLocalFiles = async ({
24477
24608
  // src/mcp/services/LocalMobbFolderService.ts
24478
24609
  init_GitService();
24479
24610
  init_issueTypeCatalog();
24480
- import fs23 from "fs";
24481
- import path31 from "path";
24611
+ import fs24 from "fs";
24612
+ import path32 from "path";
24482
24613
  function extractPathFromPatch(patch) {
24483
24614
  const match = patch?.match(/diff --git a\/([^\s]+) b\//);
24484
24615
  return match?.[1] ?? null;
@@ -24560,19 +24691,19 @@ var LocalMobbFolderService = class {
24560
24691
  "[LocalMobbFolderService] Non-git repository detected, skipping .gitignore operations"
24561
24692
  );
24562
24693
  }
24563
- const mobbFolderPath = path31.join(
24694
+ const mobbFolderPath = path32.join(
24564
24695
  this.repoPath,
24565
24696
  this.defaultMobbFolderName
24566
24697
  );
24567
- if (!fs23.existsSync(mobbFolderPath)) {
24698
+ if (!fs24.existsSync(mobbFolderPath)) {
24568
24699
  logInfo("[LocalMobbFolderService] Creating .mobb folder", {
24569
24700
  mobbFolderPath
24570
24701
  });
24571
- fs23.mkdirSync(mobbFolderPath, { recursive: true });
24702
+ fs24.mkdirSync(mobbFolderPath, { recursive: true });
24572
24703
  } else {
24573
24704
  logDebug("[LocalMobbFolderService] .mobb folder already exists");
24574
24705
  }
24575
- const stats = fs23.statSync(mobbFolderPath);
24706
+ const stats = fs24.statSync(mobbFolderPath);
24576
24707
  if (!stats.isDirectory()) {
24577
24708
  throw new Error(`Path exists but is not a directory: ${mobbFolderPath}`);
24578
24709
  }
@@ -24613,13 +24744,13 @@ var LocalMobbFolderService = class {
24613
24744
  logDebug("[LocalMobbFolderService] Git repository validated successfully");
24614
24745
  } else {
24615
24746
  try {
24616
- const stats = fs23.statSync(this.repoPath);
24747
+ const stats = fs24.statSync(this.repoPath);
24617
24748
  if (!stats.isDirectory()) {
24618
24749
  throw new Error(
24619
24750
  `Path exists but is not a directory: ${this.repoPath}`
24620
24751
  );
24621
24752
  }
24622
- fs23.accessSync(this.repoPath, fs23.constants.R_OK | fs23.constants.W_OK);
24753
+ fs24.accessSync(this.repoPath, fs24.constants.R_OK | fs24.constants.W_OK);
24623
24754
  logDebug(
24624
24755
  "[LocalMobbFolderService] Non-git directory validated successfully"
24625
24756
  );
@@ -24732,8 +24863,8 @@ var LocalMobbFolderService = class {
24732
24863
  mobbFolderPath,
24733
24864
  baseFileName
24734
24865
  );
24735
- const filePath = path31.join(mobbFolderPath, uniqueFileName);
24736
- await fs23.promises.writeFile(filePath, patch, "utf8");
24866
+ const filePath = path32.join(mobbFolderPath, uniqueFileName);
24867
+ await fs24.promises.writeFile(filePath, patch, "utf8");
24737
24868
  logInfo("[LocalMobbFolderService] Patch saved successfully", {
24738
24869
  filePath,
24739
24870
  fileName: uniqueFileName,
@@ -24790,11 +24921,11 @@ var LocalMobbFolderService = class {
24790
24921
  * @returns Unique filename that doesn't conflict with existing files
24791
24922
  */
24792
24923
  getUniqueFileName(folderPath, baseFileName) {
24793
- const baseName = path31.parse(baseFileName).name;
24794
- const extension = path31.parse(baseFileName).ext;
24924
+ const baseName = path32.parse(baseFileName).name;
24925
+ const extension = path32.parse(baseFileName).ext;
24795
24926
  let uniqueFileName = baseFileName;
24796
24927
  let index = 1;
24797
- while (fs23.existsSync(path31.join(folderPath, uniqueFileName))) {
24928
+ while (fs24.existsSync(path32.join(folderPath, uniqueFileName))) {
24798
24929
  uniqueFileName = `${baseName}-${index}${extension}`;
24799
24930
  index++;
24800
24931
  if (index > 1e3) {
@@ -24825,18 +24956,18 @@ var LocalMobbFolderService = class {
24825
24956
  logDebug("[LocalMobbFolderService] Logging patch info", { fixId: fix.id });
24826
24957
  try {
24827
24958
  const mobbFolderPath = await this.getFolder();
24828
- const patchInfoPath = path31.join(mobbFolderPath, "patchInfo.md");
24959
+ const patchInfoPath = path32.join(mobbFolderPath, "patchInfo.md");
24829
24960
  const markdownContent = this.generateFixMarkdown(fix, savedPatchFileName);
24830
24961
  let existingContent = "";
24831
- if (fs23.existsSync(patchInfoPath)) {
24832
- existingContent = await fs23.promises.readFile(patchInfoPath, "utf8");
24962
+ if (fs24.existsSync(patchInfoPath)) {
24963
+ existingContent = await fs24.promises.readFile(patchInfoPath, "utf8");
24833
24964
  logDebug("[LocalMobbFolderService] Existing patchInfo.md found");
24834
24965
  } else {
24835
24966
  logDebug("[LocalMobbFolderService] Creating new patchInfo.md file");
24836
24967
  }
24837
24968
  const separator = existingContent ? "\n\n================================================================================\n\n" : "";
24838
24969
  const updatedContent = `${markdownContent}${separator}${existingContent}`;
24839
- await fs23.promises.writeFile(patchInfoPath, updatedContent, "utf8");
24970
+ await fs24.promises.writeFile(patchInfoPath, updatedContent, "utf8");
24840
24971
  logInfo("[LocalMobbFolderService] Patch info logged successfully", {
24841
24972
  patchInfoPath,
24842
24973
  fixId: fix.id,
@@ -24867,7 +24998,7 @@ var LocalMobbFolderService = class {
24867
24998
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
24868
24999
  const patch = this.extractPatchFromFix(fix);
24869
25000
  const relativePatchedFilePath = patch ? extractPathFromPatch(patch) : null;
24870
- const patchedFilePath = relativePatchedFilePath ? path31.resolve(this.repoPath, relativePatchedFilePath) : null;
25001
+ const patchedFilePath = relativePatchedFilePath ? path32.resolve(this.repoPath, relativePatchedFilePath) : null;
24871
25002
  const fixIdentifier = savedPatchFileName ? savedPatchFileName.replace(".patch", "") : fix.id;
24872
25003
  let markdown = `# Fix ${fixIdentifier}
24873
25004
 
@@ -25209,16 +25340,16 @@ import {
25209
25340
  unlinkSync,
25210
25341
  writeFileSync as writeFileSync3
25211
25342
  } from "fs";
25212
- import fs24 from "fs/promises";
25343
+ import fs25 from "fs/promises";
25213
25344
  import parseDiff2 from "parse-diff";
25214
- import path32 from "path";
25345
+ import path33 from "path";
25215
25346
  var PatchApplicationService = class {
25216
25347
  /**
25217
25348
  * Gets the appropriate comment syntax for a file based on its extension
25218
25349
  */
25219
25350
  static getCommentSyntax(filePath) {
25220
- const ext = path32.extname(filePath).toLowerCase();
25221
- const basename2 = path32.basename(filePath);
25351
+ const ext = path33.extname(filePath).toLowerCase();
25352
+ const basename2 = path33.basename(filePath);
25222
25353
  const commentMap = {
25223
25354
  // C-style languages (single line comments)
25224
25355
  ".js": "//",
@@ -25426,7 +25557,7 @@ var PatchApplicationService = class {
25426
25557
  }
25427
25558
  );
25428
25559
  }
25429
- const dirPath = path32.dirname(normalizedFilePath);
25560
+ const dirPath = path33.dirname(normalizedFilePath);
25430
25561
  mkdirSync(dirPath, { recursive: true });
25431
25562
  writeFileSync3(normalizedFilePath, finalContent, "utf8");
25432
25563
  return normalizedFilePath;
@@ -25435,9 +25566,9 @@ var PatchApplicationService = class {
25435
25566
  repositoryPath,
25436
25567
  targetPath
25437
25568
  }) {
25438
- const repoRoot = path32.resolve(repositoryPath);
25439
- const normalizedPath = path32.resolve(repoRoot, targetPath);
25440
- const repoRootWithSep = repoRoot.endsWith(path32.sep) ? repoRoot : `${repoRoot}${path32.sep}`;
25569
+ const repoRoot = path33.resolve(repositoryPath);
25570
+ const normalizedPath = path33.resolve(repoRoot, targetPath);
25571
+ const repoRootWithSep = repoRoot.endsWith(path33.sep) ? repoRoot : `${repoRoot}${path33.sep}`;
25441
25572
  if (normalizedPath !== repoRoot && !normalizedPath.startsWith(repoRootWithSep)) {
25442
25573
  throw new Error(
25443
25574
  `Security violation: target path ${targetPath} resolves outside repository`
@@ -25446,7 +25577,7 @@ var PatchApplicationService = class {
25446
25577
  return {
25447
25578
  repoRoot,
25448
25579
  normalizedPath,
25449
- relativePath: path32.relative(repoRoot, normalizedPath)
25580
+ relativePath: path33.relative(repoRoot, normalizedPath)
25450
25581
  };
25451
25582
  }
25452
25583
  /**
@@ -25728,9 +25859,9 @@ var PatchApplicationService = class {
25728
25859
  continue;
25729
25860
  }
25730
25861
  try {
25731
- const absolutePath = path32.resolve(repositoryPath, targetFile);
25862
+ const absolutePath = path33.resolve(repositoryPath, targetFile);
25732
25863
  if (existsSync6(absolutePath)) {
25733
- const stats = await fs24.stat(absolutePath);
25864
+ const stats = await fs25.stat(absolutePath);
25734
25865
  const fileModTime = stats.mtime.getTime();
25735
25866
  if (fileModTime > scanStartTime) {
25736
25867
  logError(
@@ -25772,7 +25903,7 @@ var PatchApplicationService = class {
25772
25903
  const appliedFixes = [];
25773
25904
  const failedFixes = [];
25774
25905
  const skippedFixes = [];
25775
- const resolvedRepoPath = await fs24.realpath(repositoryPath);
25906
+ const resolvedRepoPath = await fs25.realpath(repositoryPath);
25776
25907
  logInfo(
25777
25908
  `[${scanContext}] Starting patch application for ${fixes.length} fixes`,
25778
25909
  {
@@ -25961,7 +26092,7 @@ var PatchApplicationService = class {
25961
26092
  fix,
25962
26093
  scanContext
25963
26094
  });
25964
- appliedFiles.push(path32.relative(repositoryPath, actualPath));
26095
+ appliedFiles.push(path33.relative(repositoryPath, actualPath));
25965
26096
  logDebug(`[${scanContext}] Created new file: ${relativePath}`);
25966
26097
  }
25967
26098
  /**
@@ -26010,7 +26141,7 @@ var PatchApplicationService = class {
26010
26141
  fix,
26011
26142
  scanContext
26012
26143
  });
26013
- appliedFiles.push(path32.relative(repositoryPath, actualPath));
26144
+ appliedFiles.push(path33.relative(repositoryPath, actualPath));
26014
26145
  logDebug(`[${scanContext}] Modified file: ${relativePath}`);
26015
26146
  }
26016
26147
  }
@@ -26202,13 +26333,13 @@ var PatchApplicationService = class {
26202
26333
  // src/mcp/services/ScanFiles.ts
26203
26334
  init_client_generates();
26204
26335
  init_GitService();
26205
- import os16 from "os";
26336
+ import os17 from "os";
26206
26337
  init_configs();
26207
26338
 
26208
26339
  // src/mcp/services/FileOperations.ts
26209
26340
  init_FileUtils();
26210
- import fs25 from "fs";
26211
- import path33 from "path";
26341
+ import fs26 from "fs";
26342
+ import path34 from "path";
26212
26343
  import AdmZip5 from "adm-zip";
26213
26344
  var FileOperations = class {
26214
26345
  /**
@@ -26228,10 +26359,10 @@ var FileOperations = class {
26228
26359
  let packedFilesCount = 0;
26229
26360
  const packedFiles = [];
26230
26361
  const excludedFiles = [];
26231
- const resolvedRepoPath = path33.resolve(repositoryPath);
26362
+ const resolvedRepoPath = path34.resolve(repositoryPath);
26232
26363
  for (const filepath of fileList) {
26233
- const absoluteFilepath = path33.join(repositoryPath, filepath);
26234
- const resolvedFilePath = path33.resolve(absoluteFilepath);
26364
+ const absoluteFilepath = path34.join(repositoryPath, filepath);
26365
+ const resolvedFilePath = path34.resolve(absoluteFilepath);
26235
26366
  if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
26236
26367
  const reason = "potential path traversal security risk";
26237
26368
  logDebug(`[FileOperations] Skipping ${filepath} due to ${reason}`);
@@ -26278,11 +26409,11 @@ var FileOperations = class {
26278
26409
  fileList,
26279
26410
  repositoryPath
26280
26411
  }) {
26281
- const resolvedRepoPath = path33.resolve(repositoryPath);
26412
+ const resolvedRepoPath = path34.resolve(repositoryPath);
26282
26413
  const validatedPaths = [];
26283
26414
  for (const filepath of fileList) {
26284
- const absoluteFilepath = path33.join(repositoryPath, filepath);
26285
- const resolvedFilePath = path33.resolve(absoluteFilepath);
26415
+ const absoluteFilepath = path34.join(repositoryPath, filepath);
26416
+ const resolvedFilePath = path34.resolve(absoluteFilepath);
26286
26417
  if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
26287
26418
  logDebug(
26288
26419
  `[FileOperations] Rejecting ${filepath} - path traversal attempt detected`
@@ -26290,7 +26421,7 @@ var FileOperations = class {
26290
26421
  continue;
26291
26422
  }
26292
26423
  try {
26293
- await fs25.promises.access(absoluteFilepath, fs25.constants.R_OK);
26424
+ await fs26.promises.access(absoluteFilepath, fs26.constants.R_OK);
26294
26425
  validatedPaths.push(filepath);
26295
26426
  } catch (error) {
26296
26427
  logDebug(
@@ -26309,8 +26440,8 @@ var FileOperations = class {
26309
26440
  const fileDataArray = [];
26310
26441
  for (const absolutePath of filePaths) {
26311
26442
  try {
26312
- const content = await fs25.promises.readFile(absolutePath);
26313
- const relativePath = path33.basename(absolutePath);
26443
+ const content = await fs26.promises.readFile(absolutePath);
26444
+ const relativePath = path34.basename(absolutePath);
26314
26445
  fileDataArray.push({
26315
26446
  relativePath,
26316
26447
  absolutePath,
@@ -26335,7 +26466,7 @@ var FileOperations = class {
26335
26466
  relativeFilepath
26336
26467
  }) {
26337
26468
  try {
26338
- return await fs25.promises.readFile(absoluteFilepath);
26469
+ return await fs26.promises.readFile(absoluteFilepath);
26339
26470
  } catch (fsError) {
26340
26471
  logError(
26341
26472
  `[FileOperations] Failed to read ${relativeFilepath} from filesystem: ${fsError}`
@@ -26479,7 +26610,7 @@ var executeSecurityScan = async ({
26479
26610
  fileCount,
26480
26611
  // MVS device attribution: a developer appears in the MVS Developers grid
26481
26612
  // from scanning alone (no fresh login needed).
26482
- computerName: os16.hostname(),
26613
+ computerName: os17.hostname(),
26483
26614
  computerUser: getComputerUser(),
26484
26615
  clientVersion: packageJson.version
26485
26616
  };
@@ -26629,14 +26760,14 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
26629
26760
  * since the last scan.
26630
26761
  */
26631
26762
  async scanForSecurityVulnerabilities({
26632
- path: path37,
26763
+ path: path38,
26633
26764
  isAllDetectionRulesScan,
26634
26765
  isAllFilesScan,
26635
26766
  scanContext
26636
26767
  }) {
26637
26768
  this.hasAuthenticationFailed = false;
26638
26769
  logDebug(`[${scanContext}] Scanning for new security vulnerabilities`, {
26639
- path: path37
26770
+ path: path38
26640
26771
  });
26641
26772
  if (!this.gqlClient) {
26642
26773
  logInfo(`[${scanContext}] No GQL client found, skipping scan`);
@@ -26652,11 +26783,11 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
26652
26783
  }
26653
26784
  logDebug(
26654
26785
  `[${scanContext}] Connected to the API, assembling list of files to scan`,
26655
- { path: path37 }
26786
+ { path: path38 }
26656
26787
  );
26657
26788
  const isBackgroundScan = scanContext === ScanContext.BACKGROUND_INITIAL || scanContext === ScanContext.BACKGROUND_PERIODIC;
26658
26789
  const files = await getLocalFiles({
26659
- path: path37,
26790
+ path: path38,
26660
26791
  isAllFilesScan,
26661
26792
  scanContext,
26662
26793
  scanRecentlyChangedFiles: !isBackgroundScan
@@ -26682,13 +26813,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
26682
26813
  });
26683
26814
  const { fixReportId, projectId } = await scanFiles({
26684
26815
  fileList: filesToScan.map((file) => file.relativePath),
26685
- repositoryPath: path37,
26816
+ repositoryPath: path38,
26686
26817
  gqlClient: this.gqlClient,
26687
26818
  isAllDetectionRulesScan,
26688
26819
  scanContext
26689
26820
  });
26690
26821
  logInfo(
26691
- `[${scanContext}] Security scan completed for ${path37} reportId: ${fixReportId} projectId: ${projectId}`
26822
+ `[${scanContext}] Security scan completed for ${path38} reportId: ${fixReportId} projectId: ${projectId}`
26692
26823
  );
26693
26824
  if (isAllFilesScan) {
26694
26825
  return;
@@ -26992,13 +27123,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
26992
27123
  });
26993
27124
  return scannedFiles.some((file) => file.relativePath === fixFile);
26994
27125
  }
26995
- async getFreshFixes({ path: path37 }) {
27126
+ async getFreshFixes({ path: path38 }) {
26996
27127
  const scanContext = ScanContext.USER_REQUEST;
26997
- logDebug(`[${scanContext}] Getting fresh fixes`, { path: path37 });
26998
- if (this.path !== path37) {
26999
- this.path = path37;
27128
+ logDebug(`[${scanContext}] Getting fresh fixes`, { path: path38 });
27129
+ if (this.path !== path38) {
27130
+ this.path = path38;
27000
27131
  this.reset();
27001
- logInfo(`[${scanContext}] Reset service state for new path`, { path: path37 });
27132
+ logInfo(`[${scanContext}] Reset service state for new path`, { path: path38 });
27002
27133
  }
27003
27134
  try {
27004
27135
  const loginContext = createMcpLoginContext("check_new_fixes");
@@ -27017,7 +27148,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
27017
27148
  }
27018
27149
  throw error;
27019
27150
  }
27020
- this.triggerScan({ path: path37, gqlClient: this.gqlClient });
27151
+ this.triggerScan({ path: path38, gqlClient: this.gqlClient });
27021
27152
  let isMvsAutoFixEnabled = null;
27022
27153
  try {
27023
27154
  isMvsAutoFixEnabled = await this.gqlClient.getMvsAutoFixSettings();
@@ -27051,33 +27182,33 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
27051
27182
  return noFreshFixesPrompt;
27052
27183
  }
27053
27184
  triggerScan({
27054
- path: path37,
27185
+ path: path38,
27055
27186
  gqlClient
27056
27187
  }) {
27057
- if (this.path !== path37) {
27058
- this.path = path37;
27188
+ if (this.path !== path38) {
27189
+ this.path = path38;
27059
27190
  this.reset();
27060
- logInfo(`Reset service state for new path in triggerScan`, { path: path37 });
27191
+ logInfo(`Reset service state for new path in triggerScan`, { path: path38 });
27061
27192
  }
27062
27193
  this.gqlClient = gqlClient;
27063
27194
  if (!this.intervalId) {
27064
- this.startPeriodicScanning(path37);
27065
- this.executeInitialScan(path37);
27066
- void this.executeInitialFullScan(path37);
27195
+ this.startPeriodicScanning(path38);
27196
+ this.executeInitialScan(path38);
27197
+ void this.executeInitialFullScan(path38);
27067
27198
  }
27068
27199
  }
27069
- startPeriodicScanning(path37) {
27200
+ startPeriodicScanning(path38) {
27070
27201
  const scanContext = ScanContext.BACKGROUND_PERIODIC;
27071
27202
  logDebug(
27072
27203
  `[${scanContext}] Starting periodic scan for new security vulnerabilities`,
27073
27204
  {
27074
- path: path37
27205
+ path: path38
27075
27206
  }
27076
27207
  );
27077
27208
  this.intervalId = setInterval(() => {
27078
- logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path37 });
27209
+ logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path38 });
27079
27210
  this.scanForSecurityVulnerabilities({
27080
- path: path37,
27211
+ path: path38,
27081
27212
  scanContext
27082
27213
  }).catch((error) => {
27083
27214
  logError(`[${scanContext}] Error during periodic security scan`, {
@@ -27086,45 +27217,45 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
27086
27217
  });
27087
27218
  }, MCP_PERIODIC_CHECK_INTERVAL);
27088
27219
  }
27089
- async executeInitialFullScan(path37) {
27220
+ async executeInitialFullScan(path38) {
27090
27221
  const scanContext = ScanContext.FULL_SCAN;
27091
- logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path37 });
27222
+ logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path38 });
27092
27223
  logDebug(`[${scanContext}] Full scan paths scanned`, {
27093
27224
  fullScanPathsScanned: this.fullScanPathsScanned
27094
27225
  });
27095
- if (this.fullScanPathsScanned.includes(path37)) {
27226
+ if (this.fullScanPathsScanned.includes(path38)) {
27096
27227
  logDebug(`[${scanContext}] Full scan already executed for this path`, {
27097
- path: path37
27228
+ path: path38
27098
27229
  });
27099
27230
  return;
27100
27231
  }
27101
27232
  configStore.set("fullScanPathsScanned", [
27102
27233
  ...this.fullScanPathsScanned,
27103
- path37
27234
+ path38
27104
27235
  ]);
27105
27236
  try {
27106
27237
  await this.scanForSecurityVulnerabilities({
27107
- path: path37,
27238
+ path: path38,
27108
27239
  isAllFilesScan: true,
27109
27240
  isAllDetectionRulesScan: true,
27110
27241
  scanContext: ScanContext.FULL_SCAN
27111
27242
  });
27112
- if (!this.fullScanPathsScanned.includes(path37)) {
27113
- this.fullScanPathsScanned.push(path37);
27243
+ if (!this.fullScanPathsScanned.includes(path38)) {
27244
+ this.fullScanPathsScanned.push(path38);
27114
27245
  configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
27115
27246
  }
27116
- logInfo(`[${scanContext}] Full scan completed`, { path: path37 });
27247
+ logInfo(`[${scanContext}] Full scan completed`, { path: path38 });
27117
27248
  } catch (error) {
27118
27249
  logError(`[${scanContext}] Error during initial full security scan`, {
27119
27250
  error
27120
27251
  });
27121
27252
  }
27122
27253
  }
27123
- executeInitialScan(path37) {
27254
+ executeInitialScan(path38) {
27124
27255
  const scanContext = ScanContext.BACKGROUND_INITIAL;
27125
- logDebug(`[${scanContext}] Triggering initial security scan`, { path: path37 });
27256
+ logDebug(`[${scanContext}] Triggering initial security scan`, { path: path38 });
27126
27257
  this.scanForSecurityVulnerabilities({
27127
- path: path37,
27258
+ path: path38,
27128
27259
  scanContext: ScanContext.BACKGROUND_INITIAL
27129
27260
  }).catch((error) => {
27130
27261
  logError(`[${scanContext}] Error during initial security scan`, { error });
@@ -27225,9 +27356,9 @@ Example payload:
27225
27356
  `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
27226
27357
  );
27227
27358
  }
27228
- const path37 = pathValidationResult.path;
27359
+ const path38 = pathValidationResult.path;
27229
27360
  const resultText = await this.newFixesService.getFreshFixes({
27230
- path: path37
27361
+ path: path38
27231
27362
  });
27232
27363
  logInfo("CheckForNewAvailableFixesTool execution completed", {
27233
27364
  resultText
@@ -27408,8 +27539,8 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
27408
27539
  `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
27409
27540
  );
27410
27541
  }
27411
- const path37 = pathValidationResult.path;
27412
- const gitService = new GitService(path37, log);
27542
+ const path38 = pathValidationResult.path;
27543
+ const gitService = new GitService(path38, log);
27413
27544
  const gitValidation = await gitService.validateRepository();
27414
27545
  if (!gitValidation.isValid) {
27415
27546
  throw new Error(`Invalid git repository: ${gitValidation.error}`);
@@ -27446,7 +27577,7 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
27446
27577
  }
27447
27578
  const fixResult = await this.availableFixesService.checkForAvailableFixes({
27448
27579
  repoUrl: originUrl,
27449
- repositoryPath: path37,
27580
+ repositoryPath: path38,
27450
27581
  limit: args.limit,
27451
27582
  offset: args.offset,
27452
27583
  fileFilter: actualFileFilter
@@ -28031,7 +28162,7 @@ Example payload (Mode B \u2014 abstain from every interactive fix, no rescan):
28031
28162
  `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
28032
28163
  );
28033
28164
  }
28034
- const path37 = pathValidationResult.path;
28165
+ const path38 = pathValidationResult.path;
28035
28166
  if (args.interactiveAnswers !== void 0) {
28036
28167
  if (args.interactiveAnswers.length === 0) {
28037
28168
  return this.createSuccessResponse(
@@ -28041,7 +28172,7 @@ Example payload (Mode B \u2014 abstain from every interactive fix, no rescan):
28041
28172
  try {
28042
28173
  const result = await this.vulnerabilityFixService.applyInteractiveAnswers({
28043
28174
  interactiveAnswers: args.interactiveAnswers,
28044
- repositoryPath: path37
28175
+ repositoryPath: path38
28045
28176
  });
28046
28177
  return this.createSuccessResponse(result);
28047
28178
  } catch (error) {
@@ -28053,7 +28184,7 @@ Example payload (Mode B \u2014 abstain from every interactive fix, no rescan):
28053
28184
  }
28054
28185
  }
28055
28186
  const files = await getLocalFiles({
28056
- path: path37,
28187
+ path: path38,
28057
28188
  maxFileSize: MCP_MAX_FILE_SIZE,
28058
28189
  maxFiles: args.maxFiles,
28059
28190
  scanContext: ScanContext.USER_REQUEST,
@@ -28073,7 +28204,7 @@ Example payload (Mode B \u2014 abstain from every interactive fix, no rescan):
28073
28204
  try {
28074
28205
  const fixResult = await this.vulnerabilityFixService.processVulnerabilities({
28075
28206
  fileList: files.map((file) => file.relativePath),
28076
- repositoryPath: path37,
28207
+ repositoryPath: path38,
28077
28208
  offset: args.offset,
28078
28209
  limit: args.limit,
28079
28210
  isRescan: args.rescan || !!args.maxFiles
@@ -28177,7 +28308,7 @@ var mcpHandler = async (_args) => {
28177
28308
  };
28178
28309
 
28179
28310
  // src/args/commands/review.ts
28180
- import fs26 from "fs";
28311
+ import fs27 from "fs";
28181
28312
  import chalk12 from "chalk";
28182
28313
  function reviewBuilder(yargs2) {
28183
28314
  return yargs2.option("f", {
@@ -28214,7 +28345,7 @@ function reviewBuilder(yargs2) {
28214
28345
  ).help();
28215
28346
  }
28216
28347
  function validateReviewOptions(argv) {
28217
- if (!fs26.existsSync(argv.f)) {
28348
+ if (!fs27.existsSync(argv.f)) {
28218
28349
  throw new CliError(`
28219
28350
  Can't access ${chalk12.bold(argv.f)}`);
28220
28351
  }
@@ -28374,10 +28505,10 @@ init_client_generates();
28374
28505
  init_urlParser2();
28375
28506
 
28376
28507
  // src/features/codeium_intellij/codeium_language_server_grpc_client.ts
28377
- import path34 from "path";
28508
+ import path35 from "path";
28378
28509
  import * as grpc from "@grpc/grpc-js";
28379
28510
  import * as protoLoader from "@grpc/proto-loader";
28380
- var PROTO_PATH = path34.join(
28511
+ var PROTO_PATH = path35.join(
28381
28512
  getModuleRootDir(),
28382
28513
  "src/features/codeium_intellij/proto/exa/language_server_pb/language_server.proto"
28383
28514
  );
@@ -28389,7 +28520,7 @@ function loadProto() {
28389
28520
  defaults: true,
28390
28521
  oneofs: true,
28391
28522
  includeDirs: [
28392
- path34.join(getModuleRootDir(), "src/features/codeium_intellij/proto")
28523
+ path35.join(getModuleRootDir(), "src/features/codeium_intellij/proto")
28393
28524
  ]
28394
28525
  });
28395
28526
  return grpc.loadPackageDefinition(
@@ -28443,30 +28574,30 @@ async function getGrpcClient(port, csrf) {
28443
28574
  }
28444
28575
 
28445
28576
  // src/features/codeium_intellij/parse_intellij_logs.ts
28446
- import fs27 from "fs";
28447
- import os17 from "os";
28448
- import path35 from "path";
28577
+ import fs28 from "fs";
28578
+ import os18 from "os";
28579
+ import path36 from "path";
28449
28580
  function getLogsDir() {
28450
28581
  if (process.platform === "darwin") {
28451
- return path35.join(os17.homedir(), "Library/Logs/JetBrains");
28582
+ return path36.join(os18.homedir(), "Library/Logs/JetBrains");
28452
28583
  } else if (process.platform === "win32") {
28453
- return path35.join(
28454
- process.env["LOCALAPPDATA"] || path35.join(os17.homedir(), "AppData/Local"),
28584
+ return path36.join(
28585
+ process.env["LOCALAPPDATA"] || path36.join(os18.homedir(), "AppData/Local"),
28455
28586
  "JetBrains"
28456
28587
  );
28457
28588
  } else {
28458
- return path35.join(os17.homedir(), ".cache/JetBrains");
28589
+ return path36.join(os18.homedir(), ".cache/JetBrains");
28459
28590
  }
28460
28591
  }
28461
28592
  function parseIdeLogDir(ideLogDir) {
28462
- const logFiles = fs27.readdirSync(ideLogDir).filter((f) => /^idea(\.\d+)?\.log$/.test(f)).map((f) => ({
28593
+ const logFiles = fs28.readdirSync(ideLogDir).filter((f) => /^idea(\.\d+)?\.log$/.test(f)).map((f) => ({
28463
28594
  name: f,
28464
- mtime: fs27.statSync(path35.join(ideLogDir, f)).mtimeMs
28595
+ mtime: fs28.statSync(path36.join(ideLogDir, f)).mtimeMs
28465
28596
  })).sort((a, b) => a.mtime - b.mtime).map((f) => f.name);
28466
28597
  let latestCsrf = null;
28467
28598
  let latestPort = null;
28468
28599
  for (const logFile of logFiles) {
28469
- const lines = fs27.readFileSync(path35.join(ideLogDir, logFile), "utf-8").split("\n");
28600
+ const lines = fs28.readFileSync(path36.join(ideLogDir, logFile), "utf-8").split("\n");
28470
28601
  for (const line of lines) {
28471
28602
  if (!line.includes(
28472
28603
  "com.codeium.intellij.language_server.LanguageServerProcessHandler"
@@ -28492,13 +28623,13 @@ function parseIdeLogDir(ideLogDir) {
28492
28623
  function findRunningCodeiumLanguageServers() {
28493
28624
  const results = [];
28494
28625
  const logsDir = getLogsDir();
28495
- if (!fs27.existsSync(logsDir)) return results;
28496
- for (const ide of fs27.readdirSync(logsDir)) {
28497
- let ideLogDir = path35.join(logsDir, ide);
28626
+ if (!fs28.existsSync(logsDir)) return results;
28627
+ for (const ide of fs28.readdirSync(logsDir)) {
28628
+ let ideLogDir = path36.join(logsDir, ide);
28498
28629
  if (process.platform !== "darwin") {
28499
- ideLogDir = path35.join(ideLogDir, "log");
28630
+ ideLogDir = path36.join(ideLogDir, "log");
28500
28631
  }
28501
- if (!fs27.existsSync(ideLogDir) || !fs27.statSync(ideLogDir).isDirectory()) {
28632
+ if (!fs28.existsSync(ideLogDir) || !fs28.statSync(ideLogDir).isDirectory()) {
28502
28633
  continue;
28503
28634
  }
28504
28635
  const result = parseIdeLogDir(ideLogDir);
@@ -28678,11 +28809,11 @@ function processChatStepCodeAction(step) {
28678
28809
 
28679
28810
  // src/features/codeium_intellij/install_hook.ts
28680
28811
  import fsPromises5 from "fs/promises";
28681
- import os18 from "os";
28682
- import path36 from "path";
28812
+ import os19 from "os";
28813
+ import path37 from "path";
28683
28814
  import chalk14 from "chalk";
28684
28815
  function getCodeiumHooksPath() {
28685
- return path36.join(os18.homedir(), ".codeium", "hooks.json");
28816
+ return path37.join(os19.homedir(), ".codeium", "hooks.json");
28686
28817
  }
28687
28818
  async function readCodeiumHooks() {
28688
28819
  const hooksPath = getCodeiumHooksPath();
@@ -28695,7 +28826,7 @@ async function readCodeiumHooks() {
28695
28826
  }
28696
28827
  async function writeCodeiumHooks(config2) {
28697
28828
  const hooksPath = getCodeiumHooksPath();
28698
- const dir = path36.dirname(hooksPath);
28829
+ const dir = path37.dirname(hooksPath);
28699
28830
  await fsPromises5.mkdir(dir, { recursive: true });
28700
28831
  await fsPromises5.writeFile(
28701
28832
  hooksPath,