mobbdev 1.0.177 → 1.0.178

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +547 -155
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -32,7 +32,7 @@ var init_env = __esm({
32
32
  });
33
33
 
34
34
  // src/mcp/core/configs.ts
35
- var MCP_DEFAULT_API_URL, MCP_API_KEY_HEADER_NAME, MCP_LOGIN_MAX_WAIT, MCP_LOGIN_CHECK_DELAY, MCP_VUL_REPORT_DIGEST_TIMEOUT_MS, MCP_MAX_FILE_SIZE, MCP_PERIODIC_CHECK_INTERVAL, MCP_DEFAULT_MAX_FILES_TO_SCAN, MCP_REPORT_ID_EXPIRATION_MS, MCP_TOOLS_BROWSER_COOLDOWN_MS, MCP_DEFAULT_LIMIT, isAutoScan, MVS_AUTO_FIX_OVERRIDE, MCP_AUTO_FIX_DEBUG_MODE;
35
+ var MCP_DEFAULT_API_URL, MCP_API_KEY_HEADER_NAME, MCP_LOGIN_MAX_WAIT, MCP_LOGIN_CHECK_DELAY, MCP_VUL_REPORT_DIGEST_TIMEOUT_MS, MCP_MAX_FILE_SIZE, MCP_PERIODIC_CHECK_INTERVAL, MCP_DEFAULT_MAX_FILES_TO_SCAN, MCP_REPORT_ID_EXPIRATION_MS, MCP_TOOLS_BROWSER_COOLDOWN_MS, MCP_DEFAULT_LIMIT, isAutoScan, MVS_AUTO_FIX_OVERRIDE, MCP_AUTO_FIX_DEBUG_MODE, MCP_PERIODIC_TRACK_INTERVAL, MCP_DEFAULT_REST_API_URL;
36
36
  var init_configs = __esm({
37
37
  "src/mcp/core/configs.ts"() {
38
38
  "use strict";
@@ -51,6 +51,8 @@ var init_configs = __esm({
51
51
  isAutoScan = process.env["AUTO_SCAN"] !== "false";
52
52
  MVS_AUTO_FIX_OVERRIDE = process.env["MVS_AUTO_FIX"];
53
53
  MCP_AUTO_FIX_DEBUG_MODE = true;
54
+ MCP_PERIODIC_TRACK_INTERVAL = 60 * 60 * 1e3;
55
+ MCP_DEFAULT_REST_API_URL = "https://api.mobb.ai/api/rest/mcp/track";
54
56
  }
55
57
  });
56
58
 
@@ -6373,7 +6375,7 @@ async function getAdoSdk(params) {
6373
6375
  const url = new URL(repoUrl);
6374
6376
  const origin2 = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
6375
6377
  const params2 = `path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
6376
- const path15 = [
6378
+ const path16 = [
6377
6379
  prefixPath,
6378
6380
  owner,
6379
6381
  projectName,
@@ -6384,7 +6386,7 @@ async function getAdoSdk(params) {
6384
6386
  "items",
6385
6387
  "items"
6386
6388
  ].filter(Boolean).join("/");
6387
- return new URL(`${path15}?${params2}`, origin2).toString();
6389
+ return new URL(`${path16}?${params2}`, origin2).toString();
6388
6390
  },
6389
6391
  async getAdoBranchList({ repoUrl }) {
6390
6392
  try {
@@ -7839,14 +7841,14 @@ function getGithubSdk(params = {}) {
7839
7841
  };
7840
7842
  },
7841
7843
  async getGithubBlameRanges(params2) {
7842
- const { ref, gitHubUrl, path: path15 } = params2;
7844
+ const { ref, gitHubUrl, path: path16 } = params2;
7843
7845
  const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
7844
7846
  const res = await octokit.graphql(
7845
7847
  GET_BLAME_DOCUMENT,
7846
7848
  {
7847
7849
  owner,
7848
7850
  repo,
7849
- path: path15,
7851
+ path: path16,
7850
7852
  ref
7851
7853
  }
7852
7854
  );
@@ -8153,11 +8155,11 @@ var GithubSCMLib = class extends SCMLib {
8153
8155
  markdownComment: comment
8154
8156
  });
8155
8157
  }
8156
- async getRepoBlameRanges(ref, path15) {
8158
+ async getRepoBlameRanges(ref, path16) {
8157
8159
  this._validateUrl();
8158
8160
  return await this.githubSdk.getGithubBlameRanges({
8159
8161
  ref,
8160
- path: path15,
8162
+ path: path16,
8161
8163
  gitHubUrl: this.url
8162
8164
  });
8163
8165
  }
@@ -8571,13 +8573,13 @@ function parseGitlabOwnerAndRepo(gitlabUrl) {
8571
8573
  const { organization, repoName, projectPath } = parsingResult;
8572
8574
  return { owner: organization, repo: repoName, projectPath };
8573
8575
  }
8574
- async function getGitlabBlameRanges({ ref, gitlabUrl, path: path15 }, options) {
8576
+ async function getGitlabBlameRanges({ ref, gitlabUrl, path: path16 }, options) {
8575
8577
  const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
8576
8578
  const api2 = getGitBeaker({
8577
8579
  url: gitlabUrl,
8578
8580
  gitlabAuthToken: options?.gitlabAuthToken
8579
8581
  });
8580
- const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path15, ref);
8582
+ const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path16, ref);
8581
8583
  let lineNumber = 1;
8582
8584
  return resp.filter((range) => range.lines).map((range) => {
8583
8585
  const oldLineNumber = lineNumber;
@@ -8753,10 +8755,10 @@ var GitlabSCMLib = class extends SCMLib {
8753
8755
  markdownComment: comment
8754
8756
  });
8755
8757
  }
8756
- async getRepoBlameRanges(ref, path15) {
8758
+ async getRepoBlameRanges(ref, path16) {
8757
8759
  this._validateUrl();
8758
8760
  return await getGitlabBlameRanges(
8759
- { ref, path: path15, gitlabUrl: this.url },
8761
+ { ref, path: path16, gitlabUrl: this.url },
8760
8762
  {
8761
8763
  url: this.url,
8762
8764
  gitlabAuthToken: this.accessToken
@@ -9834,7 +9836,7 @@ async function postIssueComment(params) {
9834
9836
  fpDescription
9835
9837
  } = params;
9836
9838
  const {
9837
- path: path15,
9839
+ path: path16,
9838
9840
  startLine,
9839
9841
  vulnerabilityReportIssue: {
9840
9842
  vulnerabilityReportIssueTags,
@@ -9849,7 +9851,7 @@ async function postIssueComment(params) {
9849
9851
  Refresh the page in order to see the changes.`,
9850
9852
  pull_number: pullRequest,
9851
9853
  commit_id: commitSha,
9852
- path: path15,
9854
+ path: path16,
9853
9855
  line: startLine
9854
9856
  });
9855
9857
  const commentId = commentRes.data.id;
@@ -9883,7 +9885,7 @@ async function postFixComment(params) {
9883
9885
  scanner
9884
9886
  } = params;
9885
9887
  const {
9886
- path: path15,
9888
+ path: path16,
9887
9889
  startLine,
9888
9890
  vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
9889
9891
  vulnerabilityReportIssueId
@@ -9901,7 +9903,7 @@ async function postFixComment(params) {
9901
9903
  Refresh the page in order to see the changes.`,
9902
9904
  pull_number: pullRequest,
9903
9905
  commit_id: commitSha,
9904
- path: path15,
9906
+ path: path16,
9905
9907
  line: startLine
9906
9908
  });
9907
9909
  const commentId = commentRes.data.id;
@@ -10198,10 +10200,10 @@ async function getGitInfo(srcDirPath) {
10198
10200
  repoUrl: void 0
10199
10201
  };
10200
10202
  }
10201
- const gitInfo = await gitService.getGitInfo();
10203
+ const gitInfo2 = await gitService.getGitInfo();
10202
10204
  return {
10203
10205
  success: true,
10204
- ...gitInfo
10206
+ ...gitInfo2
10205
10207
  };
10206
10208
  } catch (e) {
10207
10209
  if (e instanceof Error) {
@@ -10995,8 +10997,8 @@ import path8 from "path";
10995
10997
  var debug15 = Debug15("mobbdev:checkmarx");
10996
10998
  var require2 = createRequire(import.meta.url);
10997
10999
  var getCheckmarxPath = () => {
10998
- const os3 = type();
10999
- const cxFileName = os3 === "Windows_NT" ? "cx.exe" : "cx";
11000
+ const os5 = type();
11001
+ const cxFileName = os5 === "Windows_NT" ? "cx.exe" : "cx";
11000
11002
  try {
11001
11003
  return require2.resolve(`.bin/${cxFileName}`);
11002
11004
  } catch (e) {
@@ -11671,7 +11673,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
11671
11673
  text: "\u{1F4C1} Uploading Report successful!"
11672
11674
  });
11673
11675
  }
11674
- let gitInfo = { success: false };
11676
+ let gitInfo2 = { success: false };
11675
11677
  if (reportPath) {
11676
11678
  const vulnFiles = await _digestReport({
11677
11679
  gqlClient,
@@ -11687,7 +11689,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
11687
11689
  repoUploadInfo,
11688
11690
  isIncludeAllFiles: false
11689
11691
  });
11690
- gitInfo = res.gitInfo;
11692
+ gitInfo2 = res.gitInfo;
11691
11693
  } else {
11692
11694
  const res = await _zipAndUploadRepo({
11693
11695
  srcPath,
@@ -11695,7 +11697,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
11695
11697
  repoUploadInfo,
11696
11698
  isIncludeAllFiles: true
11697
11699
  });
11698
- gitInfo = res.gitInfo;
11700
+ gitInfo2 = res.gitInfo;
11699
11701
  await _digestReport({
11700
11702
  gqlClient,
11701
11703
  fixReportId: reportUploadInfo.fixReportId,
@@ -11713,9 +11715,9 @@ async function _scan(params, { skipPrompts = false } = {}) {
11713
11715
  submitVulnerabilityReportVariables: {
11714
11716
  fixReportId: reportUploadInfo.fixReportId,
11715
11717
  projectId,
11716
- repoUrl: repo || gitInfo.repoUrl || getTopLevelDirName(srcPath),
11717
- reference: ref || gitInfo.reference || "no-branch",
11718
- sha: commitHash || gitInfo.hash || "0123456789abcdef",
11718
+ repoUrl: repo || gitInfo2.repoUrl || getTopLevelDirName(srcPath),
11719
+ reference: ref || gitInfo2.reference || "no-branch",
11720
+ sha: commitHash || gitInfo2.hash || "0123456789abcdef",
11719
11721
  scanSource: _getScanSource(command, ci),
11720
11722
  pullRequest: params.pullRequest,
11721
11723
  experimentalEnabled: !!experimentalEnabled,
@@ -11761,11 +11763,11 @@ async function _zipAndUploadRepo({
11761
11763
  const srcFileStatus = await fsPromises2.lstat(srcPath);
11762
11764
  const zippingSpinner = createSpinner4("\u{1F4E6} Zipping repo").start();
11763
11765
  let zipBuffer;
11764
- let gitInfo = { success: false };
11766
+ let gitInfo2 = { success: false };
11765
11767
  if (srcFileStatus.isFile() && path9.extname(srcPath).toLowerCase() === ".fpr") {
11766
11768
  zipBuffer = await repackFpr(srcPath);
11767
11769
  } else {
11768
- gitInfo = await getGitInfo(srcPath);
11770
+ gitInfo2 = await getGitInfo(srcPath);
11769
11771
  zipBuffer = await pack(srcPath, vulnFiles, isIncludeAllFiles);
11770
11772
  }
11771
11773
  zippingSpinner.success({ text: "\u{1F4E6} Zipping repo successful!" });
@@ -11782,7 +11784,7 @@ async function _zipAndUploadRepo({
11782
11784
  throw e;
11783
11785
  }
11784
11786
  uploadRepoSpinner.success({ text: "\u{1F4C1} Uploading Repo successful!" });
11785
- return { gitInfo };
11787
+ return { gitInfo: gitInfo2 };
11786
11788
  }
11787
11789
  async function _digestReport({
11788
11790
  gqlClient,
@@ -12283,6 +12285,29 @@ var logWarn = (message, data) => logger.log(message, "warn", data);
12283
12285
  var logDebug = (message, data) => logger.log(message, "debug", data);
12284
12286
  var log = logger.log.bind(logger);
12285
12287
 
12288
+ // src/mcp/services/ConfigStoreService.ts
12289
+ init_configs();
12290
+ import Configstore4 from "configstore";
12291
+ function createConfigStore(defaultValues = { apiToken: "" }) {
12292
+ const API_URL2 = process.env["API_URL"] || MCP_DEFAULT_API_URL;
12293
+ let domain = "";
12294
+ try {
12295
+ const url = new URL(API_URL2);
12296
+ domain = url.hostname;
12297
+ } catch (e) {
12298
+ domain = API_URL2.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/:\d+$/, "");
12299
+ }
12300
+ const sanitizedDomain = domain.replace(/\./g, "_");
12301
+ return new Configstore4(
12302
+ `${packageJson.name}-${sanitizedDomain}`,
12303
+ defaultValues
12304
+ );
12305
+ }
12306
+ function getConfigStore() {
12307
+ return createConfigStore();
12308
+ }
12309
+ var configStore = getConfigStore();
12310
+
12286
12311
  // src/mcp/services/McpGQLClient.ts
12287
12312
  import crypto3 from "crypto";
12288
12313
  import { GraphQLClient as GraphQLClient2 } from "graphql-request";
@@ -12415,29 +12440,6 @@ var GetLatestReportByRepoUrlResponseSchema = z31.object({
12415
12440
  expiredReport: z31.array(ExpiredReportSchema)
12416
12441
  });
12417
12442
 
12418
- // src/mcp/services/ConfigStoreService.ts
12419
- init_configs();
12420
- import Configstore4 from "configstore";
12421
- function createConfigStore(defaultValues = { apiToken: "" }) {
12422
- const API_URL2 = process.env["API_URL"] || MCP_DEFAULT_API_URL;
12423
- let domain = "";
12424
- try {
12425
- const url = new URL(API_URL2);
12426
- domain = url.hostname;
12427
- } catch (e) {
12428
- domain = API_URL2.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/:\d+$/, "");
12429
- }
12430
- const sanitizedDomain = domain.replace(/\./g, "_");
12431
- return new Configstore4(
12432
- `${packageJson.name}-${sanitizedDomain}`,
12433
- defaultValues
12434
- );
12435
- }
12436
- function getConfigStore() {
12437
- return createConfigStore();
12438
- }
12439
- var configStore = getConfigStore();
12440
-
12441
12443
  // src/mcp/services/McpAuthService.ts
12442
12444
  import crypto2 from "crypto";
12443
12445
  import os2 from "os";
@@ -13119,6 +13121,366 @@ async function createAuthenticatedMcpGQLClient({
13119
13121
  return new McpGQLClient({ apiKey: newApiToken, type: "apiKey" });
13120
13122
  }
13121
13123
 
13124
+ // src/mcp/services/McpUsageService.ts
13125
+ init_configs();
13126
+ import fetch5 from "node-fetch";
13127
+ import os4 from "os";
13128
+ import { v4 as uuidv43, v5 as uuidv5 } from "uuid";
13129
+
13130
+ // src/mcp/core/host.ts
13131
+ import { execSync } from "child_process";
13132
+ import fs10 from "fs";
13133
+ import os3 from "os";
13134
+ import path11 from "path";
13135
+ var IDEs = ["cursor", "windsurf", "webstorm", "vscode"];
13136
+ var runCommand = (cmd) => {
13137
+ try {
13138
+ return execSync(cmd, { encoding: "utf8" }).trim();
13139
+ } catch {
13140
+ return "";
13141
+ }
13142
+ };
13143
+ var gitInfo = {
13144
+ name: runCommand("git config user.name"),
13145
+ email: runCommand("git config user.email")
13146
+ };
13147
+ var getMCPConfigPath = (hostName) => {
13148
+ const home = os3.homedir();
13149
+ switch (hostName.toLowerCase()) {
13150
+ case "cursor":
13151
+ return path11.join(home, ".cursor", "mcp.json");
13152
+ case "windsurf":
13153
+ return path11.join(home, ".codeium", "windsurf", "mcp_config.json");
13154
+ case "webstorm":
13155
+ return "";
13156
+ case "visualstudiocode":
13157
+ case "vscode":
13158
+ return process.platform === "win32" ? path11.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path11.join(
13159
+ home,
13160
+ "Library",
13161
+ "Application Support",
13162
+ "Code",
13163
+ "User",
13164
+ "mcp.json"
13165
+ );
13166
+ default:
13167
+ throw new Error(`Unknown hostName: ${hostName}`);
13168
+ }
13169
+ };
13170
+ var readMCPConfig = (hostName) => {
13171
+ const filePath = getMCPConfigPath(hostName);
13172
+ if (!fs10.existsSync(filePath)) return null;
13173
+ return JSON.parse(fs10.readFileSync(filePath, "utf8"));
13174
+ };
13175
+ var getRunningProcesses = () => {
13176
+ try {
13177
+ return os3.platform() === "win32" ? execSync("tasklist", { encoding: "utf8" }) : execSync("ps aux", { encoding: "utf8" });
13178
+ } catch {
13179
+ return "";
13180
+ }
13181
+ };
13182
+ var knownHosts = {
13183
+ webstorm: "WebStorm",
13184
+ cursor: "Cursor",
13185
+ windsurf: "Windsurf",
13186
+ code: "Vscode"
13187
+ };
13188
+ var versionCommands = {
13189
+ WebStorm: {
13190
+ darwin: [
13191
+ `grep -m1 '"version"' /Applications/WebStorm.app/Contents/Resources/product-info.json | cut -d'"' -f4`
13192
+ ],
13193
+ win32: []
13194
+ },
13195
+ Cursor: {
13196
+ darwin: [
13197
+ "grep -A1 CFBundleVersion /Applications/Cursor.app/Contents/Info.plist | grep '<string>' | sed -E 's/.*<string>(.*)<\\/string>.*/\\1/'",
13198
+ "cursor --version"
13199
+ ],
13200
+ win32: [
13201
+ '(Get-Item "$env:LOCALAPPDATA\\Programs\\cursor\\Cursor.exe").VersionInfo.ProductVersion'
13202
+ ]
13203
+ },
13204
+ Windsurf: {
13205
+ darwin: [
13206
+ "grep -A1 CFBundleVersion /Applications/Windsurf.app/Contents/Info.plist | grep '<string>' | sed -E 's/.*<string>(.*)<\\/string>.*/\\1/'",
13207
+ "windsurf --version"
13208
+ ],
13209
+ win32: [
13210
+ `(Get-Item "$env:LOCALAPPDATA\\Programs\\Windsurf\\Windsurf.exe").VersionInfo.ProductVersion`
13211
+ ]
13212
+ },
13213
+ Vscode: {
13214
+ darwin: [
13215
+ `grep -A1 CFBundleVersion "/Applications/Visual Studio Code.app/Contents/Info.plist" | grep '<string>' | sed -E 's/.*<string>(.*)<\\/string>.*/\\1/'`,
13216
+ process.env["TERM_PROGRAM_VERSION"] || "Unknown"
13217
+ ],
13218
+ win32: [
13219
+ `(Get-Item "$env:LOCALAPPDATA\\Programs\\Microsoft VS Code\\Code.exe").VersionInfo.ProductVersion`
13220
+ ]
13221
+ }
13222
+ };
13223
+ var getProcessInfo = (pid) => {
13224
+ const platform = os3.platform();
13225
+ try {
13226
+ if (platform === "linux" || platform === "darwin") {
13227
+ const output = execSync(`ps -o pid=,ppid=,comm= -p ${pid}`, {
13228
+ stdio: ["pipe", "pipe", "ignore"]
13229
+ }).toString().trim();
13230
+ if (!output) return null;
13231
+ const [pidStr, ppid, ...cmd] = output.trim().split(/\s+/);
13232
+ return { pid: pidStr ?? "", ppid: ppid ?? "", cmd: cmd.join(" ") };
13233
+ } else if (platform === "win32") {
13234
+ const output = execSync(
13235
+ `powershell -Command "Get-CimInstance Win32_Process -Filter 'ProcessId=${pid}' | Select-Object ProcessId,ParentProcessId,Name | Format-Table -HideTableHeaders"`,
13236
+ { stdio: ["pipe", "pipe", "ignore"] }
13237
+ ).toString().trim();
13238
+ if (!output) return null;
13239
+ const parts = output.split(/\s+/);
13240
+ const pidStr = parts[0];
13241
+ const ppid = parts[1];
13242
+ const cmd = parts.slice(2).join(" ");
13243
+ return { pid: pidStr ?? "", ppid: ppid ?? "", cmd };
13244
+ } else {
13245
+ logWarn(`Unsupported platform: ${platform}`);
13246
+ return null;
13247
+ }
13248
+ } catch {
13249
+ return null;
13250
+ }
13251
+ };
13252
+ var getHostInfo = () => {
13253
+ const runningProcesses = getRunningProcesses().toLowerCase();
13254
+ const results = [];
13255
+ const allConfigs = {};
13256
+ for (const ide of IDEs) {
13257
+ const cfg = readMCPConfig(ide);
13258
+ if (cfg) allConfigs[ide] = cfg;
13259
+ }
13260
+ const servers = [];
13261
+ for (const [ide, cfg] of Object.entries(allConfigs)) {
13262
+ for (const [name, server] of Object.entries(
13263
+ cfg.mcpServers || cfg.servers || {}
13264
+ )) {
13265
+ servers.push({
13266
+ ide,
13267
+ name,
13268
+ command: server.command || "",
13269
+ isRunning: false
13270
+ });
13271
+ }
13272
+ }
13273
+ const runningLines = runningProcesses.split("\n");
13274
+ for (const line of runningLines) {
13275
+ if (line.includes("mcp")) {
13276
+ const cmdLower = line.toLowerCase();
13277
+ const existingServer = servers.find(
13278
+ (s) => s.command && cmdLower.includes(s.command.toLowerCase())
13279
+ );
13280
+ if (existingServer) {
13281
+ existingServer.isRunning = true;
13282
+ } else {
13283
+ let ideName = "Unknown";
13284
+ const foundHostKey = Object.keys(knownHosts).find(
13285
+ (key) => cmdLower.includes(key)
13286
+ );
13287
+ if (foundHostKey) {
13288
+ ideName = knownHosts[foundHostKey] || "Unknown";
13289
+ } else {
13290
+ const pidMatch = line.trim().split(/\s+/)[1];
13291
+ const pid = parseInt(String(pidMatch), 10);
13292
+ if (!isNaN(pid)) {
13293
+ let currentPid = pid;
13294
+ while (currentPid && currentPid !== 0) {
13295
+ const proc = getProcessInfo(currentPid);
13296
+ if (!proc) break;
13297
+ const cmdProc = proc.cmd.toLowerCase();
13298
+ const found = Object.keys(knownHosts).find(
13299
+ (key) => cmdProc.includes(key)
13300
+ );
13301
+ if (found) {
13302
+ ideName = knownHosts[found] || "Unknown";
13303
+ break;
13304
+ }
13305
+ currentPid = parseInt(proc.ppid, 10);
13306
+ }
13307
+ }
13308
+ }
13309
+ servers.push({
13310
+ ide: ideName.toLowerCase(),
13311
+ name: "unknown",
13312
+ command: line.trim(),
13313
+ isRunning: true
13314
+ });
13315
+ }
13316
+ }
13317
+ }
13318
+ for (const { ide, name, command, isRunning } of servers) {
13319
+ const config4 = allConfigs[ide] || null;
13320
+ const ideName = ide.charAt(0).toUpperCase() + ide.slice(1) || "Unknown";
13321
+ let ideVersion = "Unknown";
13322
+ const platform = os3.platform();
13323
+ const cmds = versionCommands[ideName]?.[platform] ?? [];
13324
+ for (const cmd of cmds) {
13325
+ try {
13326
+ const versionOutput = cmd.includes("grep") || cmd.includes("--version") || cmd.includes("sed") ? execSync(cmd, { stdio: ["pipe", "pipe", "ignore"] }).toString().split("\n")[0] ?? "" : cmd;
13327
+ if (versionOutput && versionOutput !== "Unknown") {
13328
+ ideVersion = versionOutput;
13329
+ break;
13330
+ }
13331
+ } catch {
13332
+ continue;
13333
+ }
13334
+ }
13335
+ let mcpConfigObj = {};
13336
+ if (config4) {
13337
+ const allServers = config4.mcpServers || config4.servers || {};
13338
+ if (name in allServers && allServers[name]) {
13339
+ mcpConfigObj = allServers[name];
13340
+ }
13341
+ }
13342
+ results.push({
13343
+ mcpName: name || command,
13344
+ mcpConfiguration: JSON.stringify(mcpConfigObj),
13345
+ ideName: ideName || "Unknown",
13346
+ ideVersion: ideVersion || "Unknown",
13347
+ isRunning
13348
+ });
13349
+ }
13350
+ return { mcps: results, user: gitInfo };
13351
+ };
13352
+
13353
+ // src/mcp/services/McpUsageService.ts
13354
+ var McpUsageService = class {
13355
+ constructor() {
13356
+ __publicField(this, "configKey", "mcpUsage");
13357
+ __publicField(this, "intervalId", null);
13358
+ __publicField(this, "REST_API_URL", MCP_DEFAULT_REST_API_URL);
13359
+ this.startPeriodicTracking();
13360
+ if (process.env["API_URL"]) {
13361
+ const url = new URL(process.env["API_URL"]);
13362
+ const domain = `${url.protocol}//${url.host}`;
13363
+ this.REST_API_URL = `${domain}/api/rest/mcp/track`;
13364
+ }
13365
+ }
13366
+ startPeriodicTracking() {
13367
+ const scanContext = ScanContext.BACKGROUND_PERIODIC;
13368
+ logDebug(`[${scanContext}] Starting periodic tracking for mcps`, {});
13369
+ this.intervalId = setInterval(async () => {
13370
+ logDebug(`[${scanContext}] Triggering periodic security scan`, {
13371
+ MCP_PERIODIC_TRACK_INTERVAL
13372
+ });
13373
+ await mcpUsageService.trackServerStart();
13374
+ }, 1e4);
13375
+ }
13376
+ generateHostId() {
13377
+ const stored = configStore.get(this.configKey);
13378
+ if (stored?.mcpHostId) return stored.mcpHostId;
13379
+ const interfaces = os4.networkInterfaces();
13380
+ const macs = [];
13381
+ for (const iface of Object.values(interfaces)) {
13382
+ if (!iface) continue;
13383
+ for (const net of iface) {
13384
+ if (net.mac && net.mac !== "00:00:00:00:00:00") macs.push(net.mac);
13385
+ }
13386
+ }
13387
+ const macString = macs.length ? macs.sort().join(",") : `${os4.hostname()}-${uuidv43()}`;
13388
+ const hostId = uuidv5(macString, uuidv5.DNS);
13389
+ logDebug("Generated new host ID", { hostId });
13390
+ return hostId;
13391
+ }
13392
+ getOrganizationId() {
13393
+ const organizationId = configStore.get("GOV-ORG-ID") || "";
13394
+ if (organizationId) {
13395
+ logDebug("Using stored organization ID", {
13396
+ organizationId
13397
+ });
13398
+ return organizationId;
13399
+ }
13400
+ return "";
13401
+ }
13402
+ createUsageData(mcpHostId, organizationId, status) {
13403
+ const { user, mcps } = getHostInfo();
13404
+ return {
13405
+ mcpHostId,
13406
+ organizationId,
13407
+ mcpVersion: packageJson.version,
13408
+ mcpOsName: os4.platform(),
13409
+ mcps: JSON.stringify(mcps),
13410
+ status,
13411
+ userName: user.name,
13412
+ userEmail: user.email,
13413
+ date: String((/* @__PURE__ */ new Date()).toISOString().split("T")[0])
13414
+ // it's used to make sure we track the mcp usage daily
13415
+ };
13416
+ }
13417
+ async trackUsage(status) {
13418
+ try {
13419
+ const hostId = this.generateHostId();
13420
+ const organizationId = this.getOrganizationId();
13421
+ if (!organizationId) {
13422
+ logError("Cannot track MCP usage - organization ID not available");
13423
+ return;
13424
+ }
13425
+ const usageData = this.createUsageData(hostId, organizationId, status);
13426
+ const stored = configStore.get(this.configKey);
13427
+ const hasChanges = !stored || Object.keys(usageData).some(
13428
+ (key) => usageData[key] !== stored[key]
13429
+ );
13430
+ if (!hasChanges) {
13431
+ logDebug(`Skipping ${status} usage tracking - no changes`);
13432
+ return;
13433
+ }
13434
+ logDebug("Before", { usageData });
13435
+ try {
13436
+ const res = await fetch5(this.REST_API_URL, {
13437
+ method: "POST",
13438
+ headers: {
13439
+ Accept: "application/json"
13440
+ },
13441
+ body: JSON.stringify({
13442
+ organizationId,
13443
+ mcps: usageData.mcps,
13444
+ status,
13445
+ osName: usageData.mcpOsName,
13446
+ userFullName: usageData.userName,
13447
+ userEmail: usageData.userEmail
13448
+ })
13449
+ });
13450
+ const authResult = await res.json();
13451
+ logDebug("Success usage data", { authResult });
13452
+ } catch (err) {
13453
+ logDebug("Error usage data", { err });
13454
+ }
13455
+ logDebug("Saving usage data", { usageData });
13456
+ configStore.set(this.configKey, usageData);
13457
+ logInfo(
13458
+ `MCP server ${status === "ACTIVE" ? "start" : "stop"} tracked successfully`
13459
+ );
13460
+ } catch (error) {
13461
+ configStore.set(this.configKey, { status: "FAILED" });
13462
+ logError(
13463
+ `Failed to track MCP server ${status === "ACTIVE" ? "start" : "stop"}`,
13464
+ { error }
13465
+ );
13466
+ }
13467
+ }
13468
+ async trackServerStart() {
13469
+ await this.trackUsage("ACTIVE");
13470
+ }
13471
+ async trackServerStop() {
13472
+ await this.trackUsage("INACTIVE");
13473
+ }
13474
+ reset() {
13475
+ if (!this.intervalId) {
13476
+ return;
13477
+ }
13478
+ clearInterval(this.intervalId);
13479
+ this.intervalId = null;
13480
+ }
13481
+ };
13482
+ var mcpUsageService = new McpUsageService();
13483
+
13122
13484
  // src/mcp/tools/toolNames.ts
13123
13485
  var MCP_TOOL_CHECK_FOR_NEW_AVAILABLE_FIXES = "check_for_new_available_fixes";
13124
13486
  var MCP_TOOL_FETCH_AVAILABLE_FIXES = "fetch_available_fixes";
@@ -13185,7 +13547,23 @@ var McpServer = class {
13185
13547
  logInfo("MCP server instance created");
13186
13548
  logDebug("MCP server instance config", { config: config4 });
13187
13549
  }
13188
- handleProcessSignal({
13550
+ async trackServerUsage(action, signalOrError) {
13551
+ try {
13552
+ if (action === "start") {
13553
+ await mcpUsageService.trackServerStart();
13554
+ }
13555
+ if (action === "stop") {
13556
+ await mcpUsageService.trackServerStop();
13557
+ mcpUsageService.reset();
13558
+ }
13559
+ } catch (usageError) {
13560
+ logWarn(`Failed to track MCP server ${action}`, {
13561
+ error: usageError,
13562
+ signalOrError
13563
+ });
13564
+ }
13565
+ }
13566
+ async handleProcessSignal({
13189
13567
  signal,
13190
13568
  error
13191
13569
  }) {
@@ -13223,9 +13601,11 @@ var McpServer = class {
13223
13601
  logDebug(message, { signal });
13224
13602
  }
13225
13603
  if (signal === "SIGINT" || signal === "SIGTERM") {
13604
+ await this.trackServerUsage("stop", signal);
13226
13605
  process.exit(0);
13227
13606
  }
13228
13607
  if (signal === "uncaughtException") {
13608
+ await this.trackServerUsage("stop", signal);
13229
13609
  process.exit(1);
13230
13610
  }
13231
13611
  }
@@ -13243,8 +13623,8 @@ var McpServer = class {
13243
13623
  "warning"
13244
13624
  ];
13245
13625
  signals.forEach((signal) => {
13246
- const handler = (error) => {
13247
- this.handleProcessSignal({ signal, error });
13626
+ const handler = async (error) => {
13627
+ await this.handleProcessSignal({ signal, error });
13248
13628
  };
13249
13629
  this.eventHandlers.set(signal, handler);
13250
13630
  process.on(signal, handler);
@@ -13303,6 +13683,12 @@ var McpServer = class {
13303
13683
  }
13304
13684
  }
13305
13685
  async handleListToolsRequest(request) {
13686
+ const govOrgId = configStore.get("GOV-ORG-ID") || "";
13687
+ if (govOrgId) {
13688
+ return {
13689
+ tools: []
13690
+ };
13691
+ }
13306
13692
  logInfo("Received list_tools request");
13307
13693
  logDebug("list_tools request", {
13308
13694
  request: JSON.parse(JSON.stringify(request))
@@ -13390,6 +13776,7 @@ var McpServer = class {
13390
13776
  const transport = new StdioServerTransport();
13391
13777
  await this.server.connect(transport);
13392
13778
  logDebug("MCP server is running on stdin/stdout");
13779
+ await this.trackServerUsage("start");
13393
13780
  process.stdin.resume();
13394
13781
  await this.createShutdownPromise();
13395
13782
  await this.stop();
@@ -13400,6 +13787,7 @@ var McpServer = class {
13400
13787
  }
13401
13788
  async stop() {
13402
13789
  logDebug("MCP server shutting down");
13790
+ await this.trackServerUsage("stop");
13403
13791
  this.eventHandlers.forEach((handler, signal) => {
13404
13792
  process.removeListener(signal, handler);
13405
13793
  });
@@ -13413,8 +13801,8 @@ var McpServer = class {
13413
13801
  import { z as z34 } from "zod";
13414
13802
 
13415
13803
  // src/mcp/services/PathValidation.ts
13416
- import fs10 from "fs";
13417
- import path11 from "path";
13804
+ import fs11 from "fs";
13805
+ import path12 from "path";
13418
13806
  async function validatePath(inputPath) {
13419
13807
  logDebug("Validating MCP path", { inputPath });
13420
13808
  if (/^\/[a-zA-Z]:\//.test(inputPath)) {
@@ -13441,7 +13829,7 @@ async function validatePath(inputPath) {
13441
13829
  logError(error);
13442
13830
  return { isValid: false, error, path: inputPath };
13443
13831
  }
13444
- const normalizedPath = path11.normalize(inputPath);
13832
+ const normalizedPath = path12.normalize(inputPath);
13445
13833
  if (normalizedPath.includes("..")) {
13446
13834
  const error = `Normalized path contains path traversal patterns: ${inputPath}`;
13447
13835
  logError(error);
@@ -13468,7 +13856,7 @@ async function validatePath(inputPath) {
13468
13856
  logDebug("Path validation successful", { inputPath });
13469
13857
  logDebug("Checking path existence", { inputPath });
13470
13858
  try {
13471
- await fs10.promises.access(inputPath);
13859
+ await fs11.promises.access(inputPath);
13472
13860
  logDebug("Path exists and is accessible", { inputPath });
13473
13861
  return { isValid: true, path: inputPath };
13474
13862
  } catch (error) {
@@ -14030,26 +14418,26 @@ ${whatHappensNextSection}`;
14030
14418
  init_FileUtils();
14031
14419
  init_GitService();
14032
14420
  init_configs();
14033
- import fs11 from "fs/promises";
14421
+ import fs12 from "fs/promises";
14034
14422
  import nodePath from "path";
14035
14423
  var getLocalFiles = async ({
14036
- path: path15,
14424
+ path: path16,
14037
14425
  maxFileSize = MCP_MAX_FILE_SIZE,
14038
14426
  maxFiles,
14039
14427
  isAllFilesScan,
14040
14428
  scanContext
14041
14429
  }) => {
14042
14430
  logDebug(`[${scanContext}] Starting getLocalFiles`, {
14043
- path: path15,
14431
+ path: path16,
14044
14432
  maxFileSize,
14045
14433
  maxFiles,
14046
14434
  isAllFilesScan
14047
14435
  });
14048
14436
  try {
14049
- const resolvedRepoPath = await fs11.realpath(path15);
14437
+ const resolvedRepoPath = await fs12.realpath(path16);
14050
14438
  logDebug(`[${scanContext}] Resolved repository path`, {
14051
14439
  resolvedRepoPath,
14052
- originalPath: path15
14440
+ originalPath: path16
14053
14441
  });
14054
14442
  const gitService = new GitService(resolvedRepoPath, log);
14055
14443
  const gitValidation = await gitService.validateRepository();
@@ -14062,7 +14450,7 @@ var getLocalFiles = async ({
14062
14450
  if (!gitValidation.isValid || isAllFilesScan) {
14063
14451
  try {
14064
14452
  files = await FileUtils.getLastChangedFiles({
14065
- dir: path15,
14453
+ dir: path16,
14066
14454
  maxFileSize,
14067
14455
  maxFiles,
14068
14456
  isAllFilesScan
@@ -14126,7 +14514,7 @@ var getLocalFiles = async ({
14126
14514
  absoluteFilePath
14127
14515
  );
14128
14516
  try {
14129
- const fileStat = await fs11.stat(absoluteFilePath);
14517
+ const fileStat = await fs12.stat(absoluteFilePath);
14130
14518
  return {
14131
14519
  filename: nodePath.basename(absoluteFilePath),
14132
14520
  relativePath,
@@ -14154,15 +14542,15 @@ var getLocalFiles = async ({
14154
14542
  logError(`${scanContext}Unexpected error in getLocalFiles`, {
14155
14543
  error: error instanceof Error ? error.message : String(error),
14156
14544
  stack: error instanceof Error ? error.stack : void 0,
14157
- path: path15
14545
+ path: path16
14158
14546
  });
14159
14547
  throw error;
14160
14548
  }
14161
14549
  };
14162
14550
 
14163
14551
  // src/mcp/services/LocalMobbFolderService.ts
14164
- import fs12 from "fs";
14165
- import path12 from "path";
14552
+ import fs13 from "fs";
14553
+ import path13 from "path";
14166
14554
  import { z as z33 } from "zod";
14167
14555
  init_GitService();
14168
14556
  function extractPathFromPatch(patch) {
@@ -14249,19 +14637,19 @@ var LocalMobbFolderService = class {
14249
14637
  "[LocalMobbFolderService] Non-git repository detected, skipping .gitignore operations"
14250
14638
  );
14251
14639
  }
14252
- const mobbFolderPath = path12.join(
14640
+ const mobbFolderPath = path13.join(
14253
14641
  this.repoPath,
14254
14642
  this.defaultMobbFolderName
14255
14643
  );
14256
- if (!fs12.existsSync(mobbFolderPath)) {
14644
+ if (!fs13.existsSync(mobbFolderPath)) {
14257
14645
  logInfo("[LocalMobbFolderService] Creating .mobb folder", {
14258
14646
  mobbFolderPath
14259
14647
  });
14260
- fs12.mkdirSync(mobbFolderPath, { recursive: true });
14648
+ fs13.mkdirSync(mobbFolderPath, { recursive: true });
14261
14649
  } else {
14262
14650
  logDebug("[LocalMobbFolderService] .mobb folder already exists");
14263
14651
  }
14264
- const stats = fs12.statSync(mobbFolderPath);
14652
+ const stats = fs13.statSync(mobbFolderPath);
14265
14653
  if (!stats.isDirectory()) {
14266
14654
  throw new Error(`Path exists but is not a directory: ${mobbFolderPath}`);
14267
14655
  }
@@ -14302,13 +14690,13 @@ var LocalMobbFolderService = class {
14302
14690
  logDebug("[LocalMobbFolderService] Git repository validated successfully");
14303
14691
  } else {
14304
14692
  try {
14305
- const stats = fs12.statSync(this.repoPath);
14693
+ const stats = fs13.statSync(this.repoPath);
14306
14694
  if (!stats.isDirectory()) {
14307
14695
  throw new Error(
14308
14696
  `Path exists but is not a directory: ${this.repoPath}`
14309
14697
  );
14310
14698
  }
14311
- fs12.accessSync(this.repoPath, fs12.constants.R_OK | fs12.constants.W_OK);
14699
+ fs13.accessSync(this.repoPath, fs13.constants.R_OK | fs13.constants.W_OK);
14312
14700
  logDebug(
14313
14701
  "[LocalMobbFolderService] Non-git directory validated successfully"
14314
14702
  );
@@ -14421,8 +14809,8 @@ var LocalMobbFolderService = class {
14421
14809
  mobbFolderPath,
14422
14810
  baseFileName
14423
14811
  );
14424
- const filePath = path12.join(mobbFolderPath, uniqueFileName);
14425
- await fs12.promises.writeFile(filePath, patch, "utf8");
14812
+ const filePath = path13.join(mobbFolderPath, uniqueFileName);
14813
+ await fs13.promises.writeFile(filePath, patch, "utf8");
14426
14814
  logInfo("[LocalMobbFolderService] Patch saved successfully", {
14427
14815
  filePath,
14428
14816
  fileName: uniqueFileName,
@@ -14479,11 +14867,11 @@ var LocalMobbFolderService = class {
14479
14867
  * @returns Unique filename that doesn't conflict with existing files
14480
14868
  */
14481
14869
  getUniqueFileName(folderPath, baseFileName) {
14482
- const baseName = path12.parse(baseFileName).name;
14483
- const extension = path12.parse(baseFileName).ext;
14870
+ const baseName = path13.parse(baseFileName).name;
14871
+ const extension = path13.parse(baseFileName).ext;
14484
14872
  let uniqueFileName = baseFileName;
14485
14873
  let index = 1;
14486
- while (fs12.existsSync(path12.join(folderPath, uniqueFileName))) {
14874
+ while (fs13.existsSync(path13.join(folderPath, uniqueFileName))) {
14487
14875
  uniqueFileName = `${baseName}-${index}${extension}`;
14488
14876
  index++;
14489
14877
  if (index > 1e3) {
@@ -14514,18 +14902,18 @@ var LocalMobbFolderService = class {
14514
14902
  logDebug("[LocalMobbFolderService] Logging patch info", { fixId: fix.id });
14515
14903
  try {
14516
14904
  const mobbFolderPath = await this.getFolder();
14517
- const patchInfoPath = path12.join(mobbFolderPath, "patchInfo.md");
14905
+ const patchInfoPath = path13.join(mobbFolderPath, "patchInfo.md");
14518
14906
  const markdownContent = this.generateFixMarkdown(fix, savedPatchFileName);
14519
14907
  let existingContent = "";
14520
- if (fs12.existsSync(patchInfoPath)) {
14521
- existingContent = await fs12.promises.readFile(patchInfoPath, "utf8");
14908
+ if (fs13.existsSync(patchInfoPath)) {
14909
+ existingContent = await fs13.promises.readFile(patchInfoPath, "utf8");
14522
14910
  logDebug("[LocalMobbFolderService] Existing patchInfo.md found");
14523
14911
  } else {
14524
14912
  logDebug("[LocalMobbFolderService] Creating new patchInfo.md file");
14525
14913
  }
14526
14914
  const separator = existingContent ? "\n\n================================================================================\n\n" : "";
14527
14915
  const updatedContent = `${markdownContent}${separator}${existingContent}`;
14528
- await fs12.promises.writeFile(patchInfoPath, updatedContent, "utf8");
14916
+ await fs13.promises.writeFile(patchInfoPath, updatedContent, "utf8");
14529
14917
  logInfo("[LocalMobbFolderService] Patch info logged successfully", {
14530
14918
  patchInfoPath,
14531
14919
  fixId: fix.id,
@@ -14556,7 +14944,7 @@ var LocalMobbFolderService = class {
14556
14944
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
14557
14945
  const patch = this.extractPatchFromFix(fix);
14558
14946
  const relativePatchedFilePath = patch ? extractPathFromPatch(patch) : null;
14559
- const patchedFilePath = relativePatchedFilePath ? path12.resolve(this.repoPath, relativePatchedFilePath) : null;
14947
+ const patchedFilePath = relativePatchedFilePath ? path13.resolve(this.repoPath, relativePatchedFilePath) : null;
14560
14948
  const fixIdentifier = savedPatchFileName ? savedPatchFileName.replace(".patch", "") : fix.id;
14561
14949
  let markdown = `# Fix ${fixIdentifier}
14562
14950
 
@@ -14898,16 +15286,16 @@ import {
14898
15286
  unlinkSync,
14899
15287
  writeFileSync
14900
15288
  } from "fs";
14901
- import fs13 from "fs/promises";
15289
+ import fs14 from "fs/promises";
14902
15290
  import parseDiff2 from "parse-diff";
14903
- import path13 from "path";
15291
+ import path14 from "path";
14904
15292
  var PatchApplicationService = class {
14905
15293
  /**
14906
15294
  * Gets the appropriate comment syntax for a file based on its extension
14907
15295
  */
14908
15296
  static getCommentSyntax(filePath) {
14909
- const ext = path13.extname(filePath).toLowerCase();
14910
- const basename2 = path13.basename(filePath);
15297
+ const ext = path14.extname(filePath).toLowerCase();
15298
+ const basename2 = path14.basename(filePath);
14911
15299
  const commentMap = {
14912
15300
  // C-style languages (single line comments)
14913
15301
  ".js": "//",
@@ -15117,7 +15505,7 @@ var PatchApplicationService = class {
15117
15505
  }
15118
15506
  );
15119
15507
  }
15120
- const dirPath = path13.dirname(filePath);
15508
+ const dirPath = path14.dirname(filePath);
15121
15509
  mkdirSync(dirPath, { recursive: true });
15122
15510
  writeFileSync(filePath, finalContent, "utf8");
15123
15511
  return filePath;
@@ -15401,9 +15789,9 @@ var PatchApplicationService = class {
15401
15789
  continue;
15402
15790
  }
15403
15791
  try {
15404
- const absolutePath = path13.resolve(repositoryPath, targetFile);
15792
+ const absolutePath = path14.resolve(repositoryPath, targetFile);
15405
15793
  if (existsSync2(absolutePath)) {
15406
- const stats = await fs13.stat(absolutePath);
15794
+ const stats = await fs14.stat(absolutePath);
15407
15795
  const fileModTime = stats.mtime.getTime();
15408
15796
  if (fileModTime > scanStartTime) {
15409
15797
  logError(
@@ -15444,7 +15832,7 @@ var PatchApplicationService = class {
15444
15832
  const appliedFixes = [];
15445
15833
  const failedFixes = [];
15446
15834
  const skippedFixes = [];
15447
- const resolvedRepoPath = await fs13.realpath(repositoryPath);
15835
+ const resolvedRepoPath = await fs14.realpath(repositoryPath);
15448
15836
  logInfo(
15449
15837
  `[${scanContext}] Starting patch application for ${fixes.length} fixes`,
15450
15838
  {
@@ -15592,11 +15980,11 @@ var PatchApplicationService = class {
15592
15980
  }) {
15593
15981
  const sanitizedRepoPath = String(repositoryPath || "").replace("\0", "").replace(/^(\.\.(\/|\\))+/, "");
15594
15982
  const sanitizedTargetFile = String(targetFile || "").replace("\0", "").replace(/^(\.\.(\/|\\))+/, "");
15595
- const absoluteFilePath = path13.resolve(
15983
+ const absoluteFilePath = path14.resolve(
15596
15984
  sanitizedRepoPath,
15597
15985
  sanitizedTargetFile
15598
15986
  );
15599
- const relativePath = path13.relative(sanitizedRepoPath, absoluteFilePath);
15987
+ const relativePath = path14.relative(sanitizedRepoPath, absoluteFilePath);
15600
15988
  if (relativePath.startsWith("..")) {
15601
15989
  throw new Error(
15602
15990
  `Security violation: target file ${targetFile} resolves outside repository`
@@ -15630,7 +16018,7 @@ var PatchApplicationService = class {
15630
16018
  fix,
15631
16019
  scanContext
15632
16020
  });
15633
- appliedFiles.push(path13.relative(repositoryPath, actualPath));
16021
+ appliedFiles.push(path14.relative(repositoryPath, actualPath));
15634
16022
  logDebug(`[${scanContext}] Created new file: ${relativePath}`);
15635
16023
  }
15636
16024
  /**
@@ -15678,7 +16066,7 @@ var PatchApplicationService = class {
15678
16066
  fix,
15679
16067
  scanContext
15680
16068
  });
15681
- appliedFiles.push(path13.relative(repositoryPath, actualPath));
16069
+ appliedFiles.push(path14.relative(repositoryPath, actualPath));
15682
16070
  logDebug(`[${scanContext}] Modified file: ${relativePath}`);
15683
16071
  }
15684
16072
  }
@@ -15873,8 +16261,8 @@ init_configs();
15873
16261
 
15874
16262
  // src/mcp/services/FileOperations.ts
15875
16263
  init_FileUtils();
15876
- import fs14 from "fs";
15877
- import path14 from "path";
16264
+ import fs15 from "fs";
16265
+ import path15 from "path";
15878
16266
  import AdmZip2 from "adm-zip";
15879
16267
  var FileOperations = class {
15880
16268
  /**
@@ -15894,10 +16282,10 @@ var FileOperations = class {
15894
16282
  let packedFilesCount = 0;
15895
16283
  const packedFiles = [];
15896
16284
  const excludedFiles = [];
15897
- const resolvedRepoPath = path14.resolve(repositoryPath);
16285
+ const resolvedRepoPath = path15.resolve(repositoryPath);
15898
16286
  for (const filepath of fileList) {
15899
- const absoluteFilepath = path14.join(repositoryPath, filepath);
15900
- const resolvedFilePath = path14.resolve(absoluteFilepath);
16287
+ const absoluteFilepath = path15.join(repositoryPath, filepath);
16288
+ const resolvedFilePath = path15.resolve(absoluteFilepath);
15901
16289
  if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
15902
16290
  const reason = "potential path traversal security risk";
15903
16291
  logDebug(`[FileOperations] Skipping ${filepath} due to ${reason}`);
@@ -15944,11 +16332,11 @@ var FileOperations = class {
15944
16332
  fileList,
15945
16333
  repositoryPath
15946
16334
  }) {
15947
- const resolvedRepoPath = path14.resolve(repositoryPath);
16335
+ const resolvedRepoPath = path15.resolve(repositoryPath);
15948
16336
  const validatedPaths = [];
15949
16337
  for (const filepath of fileList) {
15950
- const absoluteFilepath = path14.join(repositoryPath, filepath);
15951
- const resolvedFilePath = path14.resolve(absoluteFilepath);
16338
+ const absoluteFilepath = path15.join(repositoryPath, filepath);
16339
+ const resolvedFilePath = path15.resolve(absoluteFilepath);
15952
16340
  if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
15953
16341
  logDebug(
15954
16342
  `[FileOperations] Rejecting ${filepath} - path traversal attempt detected`
@@ -15956,7 +16344,7 @@ var FileOperations = class {
15956
16344
  continue;
15957
16345
  }
15958
16346
  try {
15959
- await fs14.promises.access(absoluteFilepath, fs14.constants.R_OK);
16347
+ await fs15.promises.access(absoluteFilepath, fs15.constants.R_OK);
15960
16348
  validatedPaths.push(filepath);
15961
16349
  } catch (error) {
15962
16350
  logDebug(
@@ -15975,8 +16363,8 @@ var FileOperations = class {
15975
16363
  const fileDataArray = [];
15976
16364
  for (const absolutePath of filePaths) {
15977
16365
  try {
15978
- const content = await fs14.promises.readFile(absolutePath);
15979
- const relativePath = path14.basename(absolutePath);
16366
+ const content = await fs15.promises.readFile(absolutePath);
16367
+ const relativePath = path15.basename(absolutePath);
15980
16368
  fileDataArray.push({
15981
16369
  relativePath,
15982
16370
  absolutePath,
@@ -16001,7 +16389,7 @@ var FileOperations = class {
16001
16389
  relativeFilepath
16002
16390
  }) {
16003
16391
  try {
16004
- return await fs14.promises.readFile(absoluteFilepath);
16392
+ return await fs15.promises.readFile(absoluteFilepath);
16005
16393
  } catch (fsError) {
16006
16394
  logError(
16007
16395
  `[FileOperations] Failed to read ${relativeFilepath} from filesystem: ${fsError}`
@@ -16288,14 +16676,14 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
16288
16676
  * since the last scan.
16289
16677
  */
16290
16678
  async scanForSecurityVulnerabilities({
16291
- path: path15,
16679
+ path: path16,
16292
16680
  isAllDetectionRulesScan,
16293
16681
  isAllFilesScan,
16294
16682
  scanContext
16295
16683
  }) {
16296
16684
  this.hasAuthenticationFailed = false;
16297
16685
  logDebug(`[${scanContext}] Scanning for new security vulnerabilities`, {
16298
- path: path15
16686
+ path: path16
16299
16687
  });
16300
16688
  if (!this.gqlClient) {
16301
16689
  logInfo(`[${scanContext}] No GQL client found, skipping scan`);
@@ -16311,10 +16699,10 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
16311
16699
  }
16312
16700
  logDebug(
16313
16701
  `[${scanContext}] Connected to the API, assembling list of files to scan`,
16314
- { path: path15 }
16702
+ { path: path16 }
16315
16703
  );
16316
16704
  const files = await getLocalFiles({
16317
- path: path15,
16705
+ path: path16,
16318
16706
  isAllFilesScan,
16319
16707
  scanContext
16320
16708
  });
@@ -16339,13 +16727,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
16339
16727
  });
16340
16728
  const { fixReportId, projectId } = await scanFiles({
16341
16729
  fileList: filesToScan.map((file) => file.relativePath),
16342
- repositoryPath: path15,
16730
+ repositoryPath: path16,
16343
16731
  gqlClient: this.gqlClient,
16344
16732
  isAllDetectionRulesScan,
16345
16733
  scanContext
16346
16734
  });
16347
16735
  logInfo(
16348
- `[${scanContext}] Security scan completed for ${path15} reportId: ${fixReportId} projectId: ${projectId}`
16736
+ `[${scanContext}] Security scan completed for ${path16} reportId: ${fixReportId} projectId: ${projectId}`
16349
16737
  );
16350
16738
  if (isAllFilesScan) {
16351
16739
  return;
@@ -16639,13 +17027,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
16639
17027
  });
16640
17028
  return scannedFiles.some((file) => file.relativePath === fixFile);
16641
17029
  }
16642
- async getFreshFixes({ path: path15 }) {
17030
+ async getFreshFixes({ path: path16 }) {
16643
17031
  const scanContext = ScanContext.USER_REQUEST;
16644
- logDebug(`[${scanContext}] Getting fresh fixes`, { path: path15 });
16645
- if (this.path !== path15) {
16646
- this.path = path15;
17032
+ logDebug(`[${scanContext}] Getting fresh fixes`, { path: path16 });
17033
+ if (this.path !== path16) {
17034
+ this.path = path16;
16647
17035
  this.reset();
16648
- logInfo(`[${scanContext}] Reset service state for new path`, { path: path15 });
17036
+ logInfo(`[${scanContext}] Reset service state for new path`, { path: path16 });
16649
17037
  }
16650
17038
  try {
16651
17039
  this.gqlClient = await createAuthenticatedMcpGQLClient();
@@ -16663,7 +17051,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
16663
17051
  }
16664
17052
  throw error;
16665
17053
  }
16666
- this.triggerScan({ path: path15, gqlClient: this.gqlClient });
17054
+ this.triggerScan({ path: path16, gqlClient: this.gqlClient });
16667
17055
  let isMvsAutoFixEnabled = null;
16668
17056
  try {
16669
17057
  isMvsAutoFixEnabled = await this.gqlClient.getMvsAutoFixSettings();
@@ -16697,33 +17085,33 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
16697
17085
  return noFreshFixesPrompt;
16698
17086
  }
16699
17087
  triggerScan({
16700
- path: path15,
17088
+ path: path16,
16701
17089
  gqlClient
16702
17090
  }) {
16703
- if (this.path !== path15) {
16704
- this.path = path15;
17091
+ if (this.path !== path16) {
17092
+ this.path = path16;
16705
17093
  this.reset();
16706
- logInfo(`Reset service state for new path in triggerScan`, { path: path15 });
17094
+ logInfo(`Reset service state for new path in triggerScan`, { path: path16 });
16707
17095
  }
16708
17096
  this.gqlClient = gqlClient;
16709
17097
  if (!this.intervalId) {
16710
- this.startPeriodicScanning(path15);
16711
- this.executeInitialScan(path15);
16712
- void this.executeInitialFullScan(path15);
17098
+ this.startPeriodicScanning(path16);
17099
+ this.executeInitialScan(path16);
17100
+ void this.executeInitialFullScan(path16);
16713
17101
  }
16714
17102
  }
16715
- startPeriodicScanning(path15) {
17103
+ startPeriodicScanning(path16) {
16716
17104
  const scanContext = ScanContext.BACKGROUND_PERIODIC;
16717
17105
  logDebug(
16718
17106
  `[${scanContext}] Starting periodic scan for new security vulnerabilities`,
16719
17107
  {
16720
- path: path15
17108
+ path: path16
16721
17109
  }
16722
17110
  );
16723
17111
  this.intervalId = setInterval(() => {
16724
- logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path15 });
17112
+ logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path16 });
16725
17113
  this.scanForSecurityVulnerabilities({
16726
- path: path15,
17114
+ path: path16,
16727
17115
  scanContext
16728
17116
  }).catch((error) => {
16729
17117
  logError(`[${scanContext}] Error during periodic security scan`, {
@@ -16732,45 +17120,45 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
16732
17120
  });
16733
17121
  }, MCP_PERIODIC_CHECK_INTERVAL);
16734
17122
  }
16735
- async executeInitialFullScan(path15) {
17123
+ async executeInitialFullScan(path16) {
16736
17124
  const scanContext = ScanContext.FULL_SCAN;
16737
- logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path15 });
17125
+ logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path16 });
16738
17126
  logDebug(`[${scanContext}] Full scan paths scanned`, {
16739
17127
  fullScanPathsScanned: this.fullScanPathsScanned
16740
17128
  });
16741
- if (this.fullScanPathsScanned.includes(path15)) {
17129
+ if (this.fullScanPathsScanned.includes(path16)) {
16742
17130
  logDebug(`[${scanContext}] Full scan already executed for this path`, {
16743
- path: path15
17131
+ path: path16
16744
17132
  });
16745
17133
  return;
16746
17134
  }
16747
17135
  configStore.set("fullScanPathsScanned", [
16748
17136
  ...this.fullScanPathsScanned,
16749
- path15
17137
+ path16
16750
17138
  ]);
16751
17139
  try {
16752
17140
  await this.scanForSecurityVulnerabilities({
16753
- path: path15,
17141
+ path: path16,
16754
17142
  isAllFilesScan: true,
16755
17143
  isAllDetectionRulesScan: true,
16756
17144
  scanContext: ScanContext.FULL_SCAN
16757
17145
  });
16758
- if (!this.fullScanPathsScanned.includes(path15)) {
16759
- this.fullScanPathsScanned.push(path15);
17146
+ if (!this.fullScanPathsScanned.includes(path16)) {
17147
+ this.fullScanPathsScanned.push(path16);
16760
17148
  configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
16761
17149
  }
16762
- logInfo(`[${scanContext}] Full scan completed`, { path: path15 });
17150
+ logInfo(`[${scanContext}] Full scan completed`, { path: path16 });
16763
17151
  } catch (error) {
16764
17152
  logError(`[${scanContext}] Error during initial full security scan`, {
16765
17153
  error
16766
17154
  });
16767
17155
  }
16768
17156
  }
16769
- executeInitialScan(path15) {
17157
+ executeInitialScan(path16) {
16770
17158
  const scanContext = ScanContext.BACKGROUND_INITIAL;
16771
- logDebug(`[${scanContext}] Triggering initial security scan`, { path: path15 });
17159
+ logDebug(`[${scanContext}] Triggering initial security scan`, { path: path16 });
16772
17160
  this.scanForSecurityVulnerabilities({
16773
- path: path15,
17161
+ path: path16,
16774
17162
  scanContext: ScanContext.BACKGROUND_INITIAL
16775
17163
  }).catch((error) => {
16776
17164
  logError(`[${scanContext}] Error during initial security scan`, { error });
@@ -16866,9 +17254,9 @@ Example payload:
16866
17254
  `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
16867
17255
  );
16868
17256
  }
16869
- const path15 = pathValidationResult.path;
17257
+ const path16 = pathValidationResult.path;
16870
17258
  const resultText = await this.newFixesService.getFreshFixes({
16871
- path: path15
17259
+ path: path16
16872
17260
  });
16873
17261
  logInfo("CheckForNewAvailableFixesTool execution completed", {
16874
17262
  resultText
@@ -17016,8 +17404,8 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
17016
17404
  `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
17017
17405
  );
17018
17406
  }
17019
- const path15 = pathValidationResult.path;
17020
- const gitService = new GitService(path15, log);
17407
+ const path16 = pathValidationResult.path;
17408
+ const gitService = new GitService(path16, log);
17021
17409
  const gitValidation = await gitService.validateRepository();
17022
17410
  if (!gitValidation.isValid) {
17023
17411
  throw new Error(`Invalid git repository: ${gitValidation.error}`);
@@ -17283,9 +17671,9 @@ Example payload:
17283
17671
  `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
17284
17672
  );
17285
17673
  }
17286
- const path15 = pathValidationResult.path;
17674
+ const path16 = pathValidationResult.path;
17287
17675
  const files = await getLocalFiles({
17288
- path: path15,
17676
+ path: path16,
17289
17677
  maxFileSize: MCP_MAX_FILE_SIZE,
17290
17678
  maxFiles: args.maxFiles,
17291
17679
  scanContext: ScanContext.USER_REQUEST
@@ -17304,7 +17692,7 @@ Example payload:
17304
17692
  try {
17305
17693
  const fixResult = await this.vulnerabilityFixService.processVulnerabilities({
17306
17694
  fileList: files.map((file) => file.relativePath),
17307
- repositoryPath: path15,
17695
+ repositoryPath: path16,
17308
17696
  offset: args.offset,
17309
17697
  limit: args.limit,
17310
17698
  isRescan: args.rescan || !!args.maxFiles
@@ -17355,9 +17743,12 @@ function createMcpServer() {
17355
17743
  logInfo("MCP server created and configured");
17356
17744
  return server;
17357
17745
  }
17358
- async function startMcpServer() {
17746
+ async function startMcpServer({
17747
+ govOrgId = ""
17748
+ }) {
17359
17749
  try {
17360
17750
  logDebug("Initializing MCP server");
17751
+ configStore.set("GOV-ORG-ID", govOrgId);
17361
17752
  const server = createMcpServer();
17362
17753
  await server.start();
17363
17754
  } catch (error) {
@@ -17368,7 +17759,7 @@ async function startMcpServer() {
17368
17759
 
17369
17760
  // src/args/commands/mcp.ts
17370
17761
  var mcpBuilder = (yargs2) => {
17371
- return yargs2.example("$0 mcp", "Launch the MCP server").option("debug", {
17762
+ return yargs2.example("$0 mcp", "Launch the MCP server").option("gov-org-id", organizationIdOptions).option("debug", {
17372
17763
  alias: "d",
17373
17764
  type: "boolean",
17374
17765
  description: "Run in debug mode with communication logging",
@@ -17377,7 +17768,8 @@ var mcpBuilder = (yargs2) => {
17377
17768
  };
17378
17769
  var mcpHandler = async (_args) => {
17379
17770
  try {
17380
- await startMcpServer();
17771
+ validateOrganizationId(_args.govOrgId);
17772
+ await startMcpServer({ govOrgId: _args.govOrgId });
17381
17773
  } catch (error) {
17382
17774
  console.error("Failed to start MCP server:", error);
17383
17775
  process.exit(1);
@@ -17385,7 +17777,7 @@ var mcpHandler = async (_args) => {
17385
17777
  };
17386
17778
 
17387
17779
  // src/args/commands/review.ts
17388
- import fs15 from "fs";
17780
+ import fs16 from "fs";
17389
17781
  import chalk9 from "chalk";
17390
17782
  function reviewBuilder(yargs2) {
17391
17783
  return yargs2.option("f", {
@@ -17422,7 +17814,7 @@ function reviewBuilder(yargs2) {
17422
17814
  ).help();
17423
17815
  }
17424
17816
  function validateReviewOptions(argv) {
17425
- if (!fs15.existsSync(argv.f)) {
17817
+ if (!fs16.existsSync(argv.f)) {
17426
17818
  throw new CliError(`
17427
17819
  Can't access ${chalk9.bold(argv.f)}`);
17428
17820
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "1.0.177",
3
+ "version": "1.0.178",
4
4
  "description": "Automated secure code remediation tool",
5
5
  "repository": "git+https://github.com/mobb-dev/bugsy.git",
6
6
  "main": "dist/index.mjs",