mobbdev 1.0.184 → 1.0.186

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 +165 -57
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1692,6 +1692,7 @@ var IssueType_Enum = /* @__PURE__ */ ((IssueType_Enum2) => {
1692
1692
  IssueType_Enum2["DeclareVariableExplicitly"] = "DECLARE_VARIABLE_EXPLICITLY";
1693
1693
  IssueType_Enum2["DefaultRightsInObjDefinition"] = "DEFAULT_RIGHTS_IN_OBJ_DEFINITION";
1694
1694
  IssueType_Enum2["DeprecatedFunction"] = "DEPRECATED_FUNCTION";
1695
+ IssueType_Enum2["DjangoBlankFieldNeedsNullOrDefault"] = "DJANGO_BLANK_FIELD_NEEDS_NULL_OR_DEFAULT";
1695
1696
  IssueType_Enum2["DosStringBuilder"] = "DOS_STRING_BUILDER";
1696
1697
  IssueType_Enum2["DoNotRaiseException"] = "DO_NOT_RAISE_EXCEPTION";
1697
1698
  IssueType_Enum2["DoNotThrowGenericException"] = "DO_NOT_THROW_GENERIC_EXCEPTION";
@@ -2916,7 +2917,8 @@ var fixDetailsData = {
2916
2917
  ["FUNCTION_CALL_WITHOUT_PARENTHESES" /* FunctionCallWithoutParentheses */]: void 0,
2917
2918
  ["SPRING_DEFAULT_PERMIT" /* SpringDefaultPermit */]: void 0,
2918
2919
  ["RETURN_IN_INIT" /* ReturnInInit */]: void 0,
2919
- ["ACTION_NOT_PINNED_TO_COMMIT_SHA" /* ActionNotPinnedToCommitSha */]: void 0
2920
+ ["ACTION_NOT_PINNED_TO_COMMIT_SHA" /* ActionNotPinnedToCommitSha */]: void 0,
2921
+ ["DJANGO_BLANK_FIELD_NEEDS_NULL_OR_DEFAULT" /* DjangoBlankFieldNeedsNullOrDefault */]: void 0
2920
2922
  };
2921
2923
 
2922
2924
  // src/features/analysis/scm/shared/src/getIssueType.ts
@@ -3054,7 +3056,8 @@ var issueTypeMap = {
3054
3056
  ["FUNCTION_CALL_WITHOUT_PARENTHESES" /* FunctionCallWithoutParentheses */]: "Function Call Without Parentheses",
3055
3057
  ["SPRING_DEFAULT_PERMIT" /* SpringDefaultPermit */]: "Spring Default Permit",
3056
3058
  ["RETURN_IN_INIT" /* ReturnInInit */]: "Return in Init",
3057
- ["ACTION_NOT_PINNED_TO_COMMIT_SHA" /* ActionNotPinnedToCommitSha */]: "Action Not Pinned to Commit Sha"
3059
+ ["ACTION_NOT_PINNED_TO_COMMIT_SHA" /* ActionNotPinnedToCommitSha */]: "Action Not Pinned to Commit Sha",
3060
+ ["DJANGO_BLANK_FIELD_NEEDS_NULL_OR_DEFAULT" /* DjangoBlankFieldNeedsNullOrDefault */]: "Django Blank Field Needs Null or Default"
3058
3061
  };
3059
3062
  var issueTypeZ = z.nativeEnum(IssueType_Enum);
3060
3063
  var getIssueTypeFriendlyString = (issueType) => {
@@ -12373,6 +12376,12 @@ var WorkspaceService = class {
12373
12376
  static getKnownWorkspacePath() {
12374
12377
  return this.knownWorkspacePath;
12375
12378
  }
12379
+ /**
12380
+ * Clears the known workspace path cache
12381
+ */
12382
+ static clearKnownWorkspacePath() {
12383
+ this.knownWorkspacePath = void 0;
12384
+ }
12376
12385
  /**
12377
12386
  * Gets the workspace folder path from known path or environment variables
12378
12387
  * @returns The workspace folder path or undefined if none found
@@ -13357,52 +13366,119 @@ var gitInfo = {
13357
13366
  name: runCommand("git config user.name"),
13358
13367
  email: runCommand("git config user.email")
13359
13368
  };
13360
- var getMCPConfigPath = (hostName) => {
13369
+ var getClaudeWorkspacePaths = () => {
13370
+ const home = os3.homedir();
13371
+ const claudeIdePath = path11.join(home, ".claude", "ide");
13372
+ const workspacePaths = [];
13373
+ if (!fs10.existsSync(claudeIdePath)) {
13374
+ return workspacePaths;
13375
+ }
13376
+ try {
13377
+ const lockFiles = fs10.readdirSync(claudeIdePath).filter((file) => file.endsWith(".lock"));
13378
+ for (const lockFile of lockFiles) {
13379
+ const lockFilePath = path11.join(claudeIdePath, lockFile);
13380
+ try {
13381
+ const lockContent = JSON.parse(fs10.readFileSync(lockFilePath, "utf8"));
13382
+ if (lockContent.workspaceFolders && Array.isArray(lockContent.workspaceFolders)) {
13383
+ workspacePaths.push(...lockContent.workspaceFolders);
13384
+ }
13385
+ } catch (error) {
13386
+ logWarn(
13387
+ `[UsageService] Failed to read Claude lock file: ${lockFilePath}`
13388
+ );
13389
+ }
13390
+ }
13391
+ } catch (error) {
13392
+ logWarn(
13393
+ `[UsageService] Failed to read Claude IDE directory: ${claudeIdePath}`
13394
+ );
13395
+ }
13396
+ return workspacePaths;
13397
+ };
13398
+ var getMCPConfigPaths = (hostName) => {
13361
13399
  const home = os3.homedir();
13400
+ const currentDir = process.env["WORKSPACE_FOLDER_PATHS"] || process.env["PWD"] || process.cwd();
13362
13401
  switch (hostName.toLowerCase()) {
13363
13402
  case "cursor":
13364
- return path11.join(home, ".cursor", "mcp.json");
13403
+ return [
13404
+ path11.join(currentDir, ".cursor", "mcp.json"),
13405
+ // local first
13406
+ path11.join(home, ".cursor", "mcp.json")
13407
+ ];
13365
13408
  case "windsurf":
13366
- return path11.join(home, ".codeium", "windsurf", "mcp_config.json");
13409
+ return [
13410
+ path11.join(currentDir, ".codeium", "mcp_config.json"),
13411
+ // local first
13412
+ path11.join(home, ".codeium", "windsurf", "mcp_config.json")
13413
+ ];
13367
13414
  case "webstorm":
13368
- return "";
13415
+ return [];
13369
13416
  case "visualstudiocode":
13370
13417
  case "vscode":
13371
- return process.platform === "win32" ? path11.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path11.join(
13372
- home,
13373
- "Library",
13374
- "Application Support",
13375
- "Code",
13376
- "User",
13377
- "mcp.json"
13378
- );
13379
- case "claude":
13380
- return path11.join(home, ".claude.json");
13418
+ return [
13419
+ path11.join(currentDir, ".vscode", "mcp.json"),
13420
+ // local first
13421
+ process.platform === "win32" ? path11.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path11.join(
13422
+ home,
13423
+ "Library",
13424
+ "Application Support",
13425
+ "Code",
13426
+ "User",
13427
+ "mcp.json"
13428
+ )
13429
+ ];
13430
+ case "claude": {
13431
+ const claudePaths = [
13432
+ path11.join(currentDir, ".claude.json"),
13433
+ // local first
13434
+ path11.join(home, ".claude.json")
13435
+ ];
13436
+ const workspacePaths = getClaudeWorkspacePaths();
13437
+ for (const workspacePath of workspacePaths) {
13438
+ claudePaths.push(path11.join(workspacePath, ".mcp.json"));
13439
+ }
13440
+ return claudePaths;
13441
+ }
13381
13442
  default:
13382
13443
  throw new Error(`Unknown hostName: ${hostName}`);
13383
13444
  }
13384
13445
  };
13385
- var readMCPConfig = (hostName) => {
13386
- const filePath = getMCPConfigPath(hostName);
13446
+ var readConfigFile = (filePath) => {
13387
13447
  if (!fs10.existsSync(filePath)) return null;
13388
- const config4 = JSON.parse(fs10.readFileSync(filePath, "utf8"));
13389
- if (hostName === "claude" && config4.projects) {
13390
- const allMcpServers = {};
13391
- for (const projectPath in config4.projects) {
13392
- const project = config4.projects[projectPath];
13393
- if (project?.mcpServers) {
13394
- for (const [serverName, serverConfig] of Object.entries(
13395
- project.mcpServers
13396
- )) {
13397
- allMcpServers[serverName] = serverConfig;
13448
+ try {
13449
+ return JSON.parse(fs10.readFileSync(filePath, "utf8"));
13450
+ } catch (error) {
13451
+ logWarn(`[UsageService] Failed to read MCP config: ${filePath}`);
13452
+ return null;
13453
+ }
13454
+ };
13455
+ var readMCPConfig = (hostName) => {
13456
+ const configPaths = getMCPConfigPaths(hostName);
13457
+ const mergedConfig = {};
13458
+ for (const configPath of configPaths) {
13459
+ const config4 = readConfigFile(configPath);
13460
+ if (hostName === "claude" && config4?.projects) {
13461
+ const allMcpServers = {};
13462
+ for (const projectPath in config4.projects) {
13463
+ const project = config4.projects[projectPath];
13464
+ if (project?.mcpServers) {
13465
+ Object.assign(allMcpServers, project.mcpServers);
13398
13466
  }
13399
13467
  }
13468
+ mergedConfig.mcpServers = { ...mergedConfig.mcpServers, ...allMcpServers };
13469
+ continue;
13470
+ }
13471
+ if (config4?.mcpServers) {
13472
+ mergedConfig.mcpServers = {
13473
+ ...mergedConfig.mcpServers,
13474
+ ...config4.mcpServers
13475
+ };
13476
+ }
13477
+ if (config4?.servers) {
13478
+ mergedConfig.servers = { ...mergedConfig.servers, ...config4.servers };
13400
13479
  }
13401
- return {
13402
- mcpServers: allMcpServers
13403
- };
13404
13480
  }
13405
- return config4;
13481
+ return Object.keys(mergedConfig).length > 0 ? mergedConfig : null;
13406
13482
  };
13407
13483
  var getRunningProcesses = () => {
13408
13484
  try {
@@ -13816,6 +13892,7 @@ var McpServer = class {
13816
13892
  __publicField(this, "eventHandlers", /* @__PURE__ */ new Map());
13817
13893
  __publicField(this, "parentProcessCheckInterval");
13818
13894
  __publicField(this, "parentPid");
13895
+ __publicField(this, "socketEventHandlers", /* @__PURE__ */ new Map());
13819
13896
  __publicField(this, "mcpUsageService");
13820
13897
  this.parentPid = process.ppid;
13821
13898
  this.mcpUsageService = govOrgId ? new McpUsageService(govOrgId) : null;
@@ -13936,31 +14013,43 @@ var McpServer = class {
13936
14013
  logInfo("Setting up parent process monitoring", {
13937
14014
  parentPid: this.parentPid
13938
14015
  });
13939
- process.stdin.on("close", async () => {
14016
+ const stdinCloseHandler = async () => {
13940
14017
  logDebug("stdin closed - parent likely terminated");
13941
14018
  await this.handleParentProcessDeath("stdin-close");
13942
- });
13943
- process.stdin.on("end", async () => {
14019
+ };
14020
+ const stdinEndHandler = async () => {
13944
14021
  logDebug("stdin ended - parent likely terminated");
13945
14022
  await this.handleParentProcessDeath("stdin-end");
13946
- });
13947
- process.stdout.on("error", async (error) => {
14023
+ };
14024
+ const stdoutErrorHandler = async (...args) => {
14025
+ const error = args[0];
13948
14026
  logWarn("stdout error - parent may have terminated", { error });
13949
14027
  if (error.message.includes("EPIPE") || error.message.includes("ECONNRESET")) {
13950
14028
  await this.handleParentProcessDeath("stdout-error");
13951
14029
  }
13952
- });
13953
- process.stderr.on("error", async (error) => {
14030
+ };
14031
+ const stderrErrorHandler = async (...args) => {
14032
+ const error = args[0];
13954
14033
  logWarn("stderr error - parent may have terminated", { error });
13955
14034
  if (error.message.includes("EPIPE") || error.message.includes("ECONNRESET")) {
13956
14035
  await this.handleParentProcessDeath("stderr-error");
13957
14036
  }
13958
- });
14037
+ };
14038
+ const disconnectHandler = async () => {
14039
+ logDebug("IPC disconnected - parent terminated");
14040
+ await this.handleParentProcessDeath("ipc-disconnect");
14041
+ };
14042
+ this.socketEventHandlers.set("stdin-close", stdinCloseHandler);
14043
+ this.socketEventHandlers.set("stdin-end", stdinEndHandler);
14044
+ this.socketEventHandlers.set("stdout-error", stdoutErrorHandler);
14045
+ this.socketEventHandlers.set("stderr-error", stderrErrorHandler);
14046
+ this.socketEventHandlers.set("disconnect", disconnectHandler);
14047
+ process.stdin.on("close", stdinCloseHandler);
14048
+ process.stdin.on("end", stdinEndHandler);
14049
+ process.stdout.on("error", stdoutErrorHandler);
14050
+ process.stderr.on("error", stderrErrorHandler);
13959
14051
  if (process.send) {
13960
- process.on("disconnect", async () => {
13961
- logDebug("IPC disconnected - parent terminated");
13962
- await this.handleParentProcessDeath("ipc-disconnect");
13963
- });
14052
+ process.on("disconnect", disconnectHandler);
13964
14053
  logDebug("IPC monitoring enabled");
13965
14054
  } else {
13966
14055
  logDebug("IPC not available - skipping IPC monitoring");
@@ -14027,6 +14116,7 @@ var McpServer = class {
14027
14116
  logError("Failed to connect to the API, skipping background scan");
14028
14117
  return;
14029
14118
  }
14119
+ WorkspaceService.clearKnownWorkspacePath();
14030
14120
  const workspacePath = WorkspaceService.getWorkspaceFolderPath();
14031
14121
  if (workspacePath) {
14032
14122
  try {
@@ -14183,6 +14273,31 @@ var McpServer = class {
14183
14273
  this.parentProcessCheckInterval = void 0;
14184
14274
  logDebug("Parent process check interval cleared");
14185
14275
  }
14276
+ this.socketEventHandlers.forEach((handler, eventType) => {
14277
+ try {
14278
+ switch (eventType) {
14279
+ case "stdin-close":
14280
+ process.stdin.removeListener("close", handler);
14281
+ break;
14282
+ case "stdin-end":
14283
+ process.stdin.removeListener("end", handler);
14284
+ break;
14285
+ case "stdout-error":
14286
+ process.stdout.removeListener("error", handler);
14287
+ break;
14288
+ case "stderr-error":
14289
+ process.stderr.removeListener("error", handler);
14290
+ break;
14291
+ case "disconnect":
14292
+ process.removeListener("disconnect", handler);
14293
+ break;
14294
+ }
14295
+ } catch (error) {
14296
+ logWarn(`Failed to remove ${eventType} listener`, { error });
14297
+ }
14298
+ });
14299
+ this.socketEventHandlers.clear();
14300
+ logDebug("Socket event handlers cleaned up");
14186
14301
  this.eventHandlers.forEach((handler, signal) => {
14187
14302
  process.removeListener(signal, handler);
14188
14303
  });
@@ -15901,28 +16016,21 @@ var PatchApplicationService = class {
15901
16016
  let finalContent = content;
15902
16017
  if (MCP_AUTO_FIX_DEBUG_MODE) {
15903
16018
  const fixType = fix.safeIssueType || "Security Issue";
15904
- let fixLink;
15905
- if (fix.fixUrl) {
15906
- fixLink = fix.fixUrl;
15907
- } else {
15908
- const apiUrl = process.env["API_URL"] || MCP_DEFAULT_API_URL;
15909
- const appBaseUrl = apiUrl.replace("/v1/graphql", "").replace("api.", "");
15910
- fixLink = `${appBaseUrl}/fixes/${fix.id}`;
15911
- }
15912
16019
  const commentPrefix = this.getCommentSyntax(filePath);
15913
16020
  const lines = content.split("\n");
15914
16021
  const lastLine = lines[lines.length - 1]?.trim() || "";
15915
16022
  const isMobbComment = lastLine.includes("Mobb security fix applied:");
15916
16023
  const spacing = isMobbComment ? "\n" : "\n\n";
16024
+ const fixComment = `Mobb security fix applied: ${fixType} ${fix.fixUrl || ""}`;
15917
16025
  let comment;
15918
16026
  if (commentPrefix === "<!--") {
15919
- comment = `${spacing}<!-- Mobb security fix applied: ${fixType} ${fixLink} -->`;
16027
+ comment = `${spacing}<!-- ${fixComment} -->`;
15920
16028
  } else if (commentPrefix === "/*") {
15921
- comment = `${spacing}/* Mobb security fix applied: ${fixType} ${fixLink} */`;
16029
+ comment = `${spacing}/* ${fixComment} */`;
15922
16030
  } else if (commentPrefix === "(*") {
15923
- comment = `${spacing}(* Mobb security fix applied: ${fixType} ${fixLink} *)`;
16031
+ comment = `${spacing}(* ${fixComment} *)`;
15924
16032
  } else {
15925
- comment = `${spacing}${commentPrefix} Mobb security fix applied: ${fixType} ${fixLink}`;
16033
+ comment = `${spacing}${commentPrefix} ${fixComment}`;
15926
16034
  }
15927
16035
  finalContent = content + comment;
15928
16036
  logInfo(
@@ -15930,7 +16038,7 @@ var PatchApplicationService = class {
15930
16038
  {
15931
16039
  fixId: fix.id,
15932
16040
  fixType,
15933
- fixLink,
16041
+ fixLink: fix.fixUrl,
15934
16042
  commentSyntax: commentPrefix,
15935
16043
  spacing: isMobbComment ? "single line" : "empty line above"
15936
16044
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "1.0.184",
3
+ "version": "1.0.186",
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",