mobbdev 1.2.8 → 1.2.21

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
@@ -120,10 +120,13 @@ function getSdk(client, withWrapper = defaultWrapper) {
120
120
  },
121
121
  streamCommitBlameRequests(variables, requestHeaders, signal) {
122
122
  return withWrapper((wrappedRequestHeaders) => client.request({ document: StreamCommitBlameRequestsDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "streamCommitBlameRequests", "subscription", variables);
123
+ },
124
+ ScanSkill(variables, requestHeaders, signal) {
125
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: ScanSkillDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "ScanSkill", "mutation", variables);
123
126
  }
124
127
  };
125
128
  }
126
- var AiBlameInferenceType, FixQuestionInputType, Language, ManifestAction, Effort_To_Apply_Fix_Enum, Fix_Rating_Tag_Enum, Fix_Report_State_Enum, Fix_State_Enum, IssueLanguage_Enum, IssueType_Enum, Pr_Status_Enum, Project_Role_Type_Enum, Vulnerability_Report_Issue_Category_Enum, Vulnerability_Report_Issue_State_Enum, Vulnerability_Report_Issue_Tag_Enum, Vulnerability_Report_Vendor_Enum, Vulnerability_Severity_Enum, FixDetailsFragmentDoc, FixReportSummaryFieldsFragmentDoc, MeDocument, GetLastOrgAndNamedProjectDocument, GetLastOrgDocument, GetEncryptedApiTokenDocument, FixReportStateDocument, GetVulnerabilityReportPathsDocument, GetAnalysisSubscriptionDocument, GetAnalysisDocument, GetFixesDocument, GetVulByNodesMetadataDocument, GetFalsePositiveDocument, UpdateScmTokenDocument, UploadS3BucketInfoDocument, GetTracyDiffUploadUrlDocument, AnalyzeCommitForExtensionAiBlameDocument, GetAiBlameInferenceDocument, GetAiBlameAttributionPromptDocument, GetPromptSummaryDocument, UploadAiBlameInferencesInitDocument, FinalizeAiBlameInferencesUploadDocument, DigestVulnerabilityReportDocument, SubmitVulnerabilityReportDocument, CreateCommunityUserDocument, CreateCliLoginDocument, PerformCliLoginDocument, CreateProjectDocument, ValidateRepoUrlDocument, GitReferenceDocument, AutoPrAnalysisDocument, GetFixReportsByRepoUrlDocument, GetReportFixesDocument, GetLatestReportByRepoUrlDocument, UpdateDownloadedFixDataDocument, GetUserMvsAutoFixDocument, StreamBlameAiAnalysisRequestsDocument, StreamCommitBlameRequestsDocument, defaultWrapper;
129
+ var AiBlameInferenceType, FixQuestionInputType, Language, ManifestAction, Effort_To_Apply_Fix_Enum, Fix_Rating_Tag_Enum, Fix_Report_State_Enum, Fix_State_Enum, IssueLanguage_Enum, IssueType_Enum, Pr_Status_Enum, Project_Role_Type_Enum, Vulnerability_Report_Issue_Category_Enum, Vulnerability_Report_Issue_State_Enum, Vulnerability_Report_Issue_Tag_Enum, Vulnerability_Report_Vendor_Enum, Vulnerability_Severity_Enum, FixDetailsFragmentDoc, FixReportSummaryFieldsFragmentDoc, MeDocument, GetLastOrgAndNamedProjectDocument, GetLastOrgDocument, GetEncryptedApiTokenDocument, FixReportStateDocument, GetVulnerabilityReportPathsDocument, GetAnalysisSubscriptionDocument, GetAnalysisDocument, GetFixesDocument, GetVulByNodesMetadataDocument, GetFalsePositiveDocument, UpdateScmTokenDocument, UploadS3BucketInfoDocument, GetTracyDiffUploadUrlDocument, AnalyzeCommitForExtensionAiBlameDocument, GetAiBlameInferenceDocument, GetAiBlameAttributionPromptDocument, GetPromptSummaryDocument, UploadAiBlameInferencesInitDocument, FinalizeAiBlameInferencesUploadDocument, DigestVulnerabilityReportDocument, SubmitVulnerabilityReportDocument, CreateCommunityUserDocument, CreateCliLoginDocument, PerformCliLoginDocument, CreateProjectDocument, ValidateRepoUrlDocument, GitReferenceDocument, AutoPrAnalysisDocument, GetFixReportsByRepoUrlDocument, GetReportFixesDocument, GetLatestReportByRepoUrlDocument, UpdateDownloadedFixDataDocument, GetUserMvsAutoFixDocument, StreamBlameAiAnalysisRequestsDocument, StreamCommitBlameRequestsDocument, ScanSkillDocument, defaultWrapper;
127
130
  var init_client_generates = __esm({
128
131
  "src/features/analysis/scm/generates/client_generates.ts"() {
129
132
  "use strict";
@@ -277,6 +280,7 @@ var init_client_generates = __esm({
277
280
  IssueType_Enum2["MissingTemplateStringIndicator"] = "MISSING_TEMPLATE_STRING_INDICATOR";
278
281
  IssueType_Enum2["MissingUser"] = "MISSING_USER";
279
282
  IssueType_Enum2["MissingWhitespace"] = "MISSING_WHITESPACE";
283
+ IssueType_Enum2["MissingWorkflowPermissions"] = "MISSING_WORKFLOW_PERMISSIONS";
280
284
  IssueType_Enum2["ModifiedDefaultParam"] = "MODIFIED_DEFAULT_PARAM";
281
285
  IssueType_Enum2["NonFinalPublicStaticField"] = "NON_FINAL_PUBLIC_STATIC_FIELD";
282
286
  IssueType_Enum2["NonReadonlyField"] = "NON_READONLY_FIELD";
@@ -1196,6 +1200,32 @@ var init_client_generates = __esm({
1196
1200
  completedOn
1197
1201
  error
1198
1202
  }
1203
+ }
1204
+ `;
1205
+ ScanSkillDocument = `
1206
+ mutation ScanSkill($skillUrl: String!) {
1207
+ scanSkill(skillUrl: $skillUrl) {
1208
+ skillName
1209
+ skillHash
1210
+ skillVersion
1211
+ verdict
1212
+ findingsCount
1213
+ findings {
1214
+ category
1215
+ severity
1216
+ ruleId
1217
+ explanation
1218
+ evidence
1219
+ filePath
1220
+ lineNumber
1221
+ confidence
1222
+ layer
1223
+ }
1224
+ scanDurationMs
1225
+ layersExecuted
1226
+ cached
1227
+ summary
1228
+ }
1199
1229
  }
1200
1230
  `;
1201
1231
  defaultWrapper = (action, _operationName, _operationType, _variables) => action();
@@ -1380,7 +1410,8 @@ var init_getIssueType = __esm({
1380
1410
  ["RETURN_IN_INIT" /* ReturnInInit */]: "Return in Init",
1381
1411
  ["ACTION_NOT_PINNED_TO_COMMIT_SHA" /* ActionNotPinnedToCommitSha */]: "Action Not Pinned to Commit Sha",
1382
1412
  ["DJANGO_BLANK_FIELD_NEEDS_NULL_OR_DEFAULT" /* DjangoBlankFieldNeedsNullOrDefault */]: "Django Blank Field Needs Null or Default",
1383
- ["REDUNDANT_NIL_ERROR_CHECK" /* RedundantNilErrorCheck */]: "Redundant Nil Error Check"
1413
+ ["REDUNDANT_NIL_ERROR_CHECK" /* RedundantNilErrorCheck */]: "Redundant Nil Error Check",
1414
+ ["MISSING_WORKFLOW_PERMISSIONS" /* MissingWorkflowPermissions */]: "Missing Workflow Permissions"
1384
1415
  };
1385
1416
  issueTypeZ = z.nativeEnum(IssueType_Enum);
1386
1417
  getIssueTypeFriendlyString = (issueType) => {
@@ -1507,6 +1538,7 @@ var init_fix = __esm({
1507
1538
  });
1508
1539
  IssueSharedStateZ = z7.object({
1509
1540
  id: z7.string(),
1541
+ createdAt: z7.string(),
1510
1542
  isArchived: z7.boolean(),
1511
1543
  ticketIntegrationId: z7.string().nullable(),
1512
1544
  ticketIntegrations: z7.array(
@@ -3801,7 +3833,7 @@ ${rootContent}`;
3801
3833
  }
3802
3834
  }
3803
3835
  /**
3804
- * Gets local commit data including diff, timestamp, and parent commits.
3836
+ * Gets local commit data including diff and timestamp.
3805
3837
  * Used by Tracy extension to send commit data directly without requiring SCM token.
3806
3838
  * @param commitSha The commit SHA to get data for
3807
3839
  * @param maxDiffSizeBytes Maximum diff size in bytes (default 3MB). Returns null if exceeded.
@@ -3813,7 +3845,7 @@ ${rootContent}`;
3813
3845
  const DIFF_DELIMITER = "---MOBB_DIFF_START---";
3814
3846
  const output = await this.git.show([
3815
3847
  commitSha,
3816
- `--format=%cI%n%P%n${DIFF_DELIMITER}`,
3848
+ `--format=%cI%n${DIFF_DELIMITER}`,
3817
3849
  "--patch"
3818
3850
  ]);
3819
3851
  const delimiterIndex = output.indexOf(DIFF_DELIMITER);
@@ -3868,7 +3900,7 @@ import Debug19 from "debug";
3868
3900
  import { hideBin } from "yargs/helpers";
3869
3901
 
3870
3902
  // src/args/yargs.ts
3871
- import chalk13 from "chalk";
3903
+ import chalk15 from "chalk";
3872
3904
  import yargs from "yargs/yargs";
3873
3905
 
3874
3906
  // src/args/commands/convert_to_sarif.ts
@@ -4241,7 +4273,8 @@ var fixDetailsData = {
4241
4273
  ["RETURN_IN_INIT" /* ReturnInInit */]: void 0,
4242
4274
  ["ACTION_NOT_PINNED_TO_COMMIT_SHA" /* ActionNotPinnedToCommitSha */]: void 0,
4243
4275
  ["DJANGO_BLANK_FIELD_NEEDS_NULL_OR_DEFAULT" /* DjangoBlankFieldNeedsNullOrDefault */]: void 0,
4244
- ["REDUNDANT_NIL_ERROR_CHECK" /* RedundantNilErrorCheck */]: void 0
4276
+ ["REDUNDANT_NIL_ERROR_CHECK" /* RedundantNilErrorCheck */]: void 0,
4277
+ ["MISSING_WORKFLOW_PERMISSIONS" /* MissingWorkflowPermissions */]: void 0
4245
4278
  };
4246
4279
 
4247
4280
  // src/features/analysis/scm/shared/src/commitDescriptionMarkup.ts
@@ -6763,7 +6796,7 @@ async function getAdoSdk(params) {
6763
6796
  const url = new URL(repoUrl);
6764
6797
  const origin2 = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
6765
6798
  const params2 = `path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
6766
- const path25 = [
6799
+ const path26 = [
6767
6800
  prefixPath,
6768
6801
  owner,
6769
6802
  projectName,
@@ -6774,7 +6807,7 @@ async function getAdoSdk(params) {
6774
6807
  "items",
6775
6808
  "items"
6776
6809
  ].filter(Boolean).join("/");
6777
- return new URL(`${path25}?${params2}`, origin2).toString();
6810
+ return new URL(`${path26}?${params2}`, origin2).toString();
6778
6811
  },
6779
6812
  async getAdoBranchList({ repoUrl }) {
6780
6813
  try {
@@ -8318,7 +8351,7 @@ function getGithubSdk(params = {}) {
8318
8351
  if (res.status === 204) {
8319
8352
  return true;
8320
8353
  }
8321
- } catch (collaboratorError) {
8354
+ } catch (_collaboratorError) {
8322
8355
  try {
8323
8356
  const permissionRes = await octokit.rest.repos.getCollaboratorPermissionLevel({
8324
8357
  owner,
@@ -8328,16 +8361,16 @@ function getGithubSdk(params = {}) {
8328
8361
  if (permissionRes.data.permission !== "none") {
8329
8362
  return true;
8330
8363
  }
8331
- } catch (permissionError) {
8364
+ } catch (_permissionError) {
8332
8365
  try {
8333
8366
  await octokit.rest.repos.get({ owner, repo });
8334
8367
  return true;
8335
- } catch (repoError) {
8368
+ } catch (_repoError) {
8336
8369
  return false;
8337
8370
  }
8338
8371
  }
8339
8372
  }
8340
- } catch (e) {
8373
+ } catch (_e) {
8341
8374
  return false;
8342
8375
  }
8343
8376
  return false;
@@ -8378,7 +8411,7 @@ function getGithubSdk(params = {}) {
8378
8411
  branch
8379
8412
  });
8380
8413
  return branch === res.data.name;
8381
- } catch (e) {
8414
+ } catch (_e) {
8382
8415
  return false;
8383
8416
  }
8384
8417
  },
@@ -8573,7 +8606,7 @@ function getGithubSdk(params = {}) {
8573
8606
  const sourceFileContentResponse = await octokit.rest.repos.getContent({
8574
8607
  owner: sourceOwner,
8575
8608
  repo: sourceRepo,
8576
- path: "/" + sourceFilePath
8609
+ path: `/${sourceFilePath}`
8577
8610
  });
8578
8611
  const { data: repository } = await octokit.rest.repos.get({ owner, repo });
8579
8612
  const defaultBranch = repository.default_branch;
@@ -8601,7 +8634,7 @@ function getGithubSdk(params = {}) {
8601
8634
  const secondFileContentResponse = await octokit.rest.repos.getContent({
8602
8635
  owner: sourceOwner,
8603
8636
  repo: sourceRepo,
8604
- path: "/" + secondFilePath
8637
+ path: `/${secondFilePath}`
8605
8638
  });
8606
8639
  const secondDecodedContent = Buffer.from(
8607
8640
  // Check if file content exists and handle different response types
@@ -10369,6 +10402,7 @@ async function getGitlabMergeRequestDiff({
10369
10402
  title: mr.title,
10370
10403
  description: mr.description || void 0,
10371
10404
  commits,
10405
+ headCommitSha: mr.sha,
10372
10406
  diffLines
10373
10407
  };
10374
10408
  }
@@ -11741,7 +11775,8 @@ var mobbCliCommand = {
11741
11775
  claudeCodeInstallHook: "claude-code-install-hook",
11742
11776
  claudeCodeProcessHook: "claude-code-process-hook",
11743
11777
  windsurfIntellijInstallHook: "windsurf-intellij-install-hook",
11744
- windsurfIntellijProcessHook: "windsurf-intellij-process-hook"
11778
+ windsurfIntellijProcessHook: "windsurf-intellij-process-hook",
11779
+ scanSkill: "scan-skill"
11745
11780
  };
11746
11781
  var ScanContext = {
11747
11782
  FULL_SCAN: "FULL_SCAN",
@@ -11752,10 +11787,11 @@ var ScanContext = {
11752
11787
  };
11753
11788
 
11754
11789
  // src/args/commands/analyze.ts
11755
- import fs11 from "fs";
11756
- import chalk8 from "chalk";
11790
+ import fs12 from "fs";
11791
+ import chalk9 from "chalk";
11757
11792
 
11758
11793
  // src/commands/index.ts
11794
+ import chalk7 from "chalk";
11759
11795
  import chalkAnimation from "chalk-animation";
11760
11796
 
11761
11797
  // src/features/analysis/index.ts
@@ -12541,6 +12577,9 @@ var GQLClient = class {
12541
12577
  async getTracyDiffUploadUrl(variables) {
12542
12578
  return await this._clientSdk.GetTracyDiffUploadUrl(variables);
12543
12579
  }
12580
+ async scanSkill(variables) {
12581
+ return await this._clientSdk.ScanSkill(variables);
12582
+ }
12544
12583
  };
12545
12584
 
12546
12585
  // src/mcp/services/types.ts
@@ -13146,7 +13185,7 @@ async function postIssueComment(params) {
13146
13185
  fpDescription
13147
13186
  } = params;
13148
13187
  const {
13149
- path: path25,
13188
+ path: path26,
13150
13189
  startLine,
13151
13190
  vulnerabilityReportIssue: {
13152
13191
  vulnerabilityReportIssueTags,
@@ -13161,7 +13200,7 @@ async function postIssueComment(params) {
13161
13200
  Refresh the page in order to see the changes.`,
13162
13201
  pull_number: pullRequest,
13163
13202
  commit_id: commitSha,
13164
- path: path25,
13203
+ path: path26,
13165
13204
  line: startLine
13166
13205
  });
13167
13206
  const commentId = commentRes.data.id;
@@ -13195,7 +13234,7 @@ async function postFixComment(params) {
13195
13234
  scanner
13196
13235
  } = params;
13197
13236
  const {
13198
- path: path25,
13237
+ path: path26,
13199
13238
  startLine,
13200
13239
  vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
13201
13240
  vulnerabilityReportIssueId
@@ -13213,7 +13252,7 @@ async function postFixComment(params) {
13213
13252
  Refresh the page in order to see the changes.`,
13214
13253
  pull_number: pullRequest,
13215
13254
  commit_id: commitSha,
13216
- path: path25,
13255
+ path: path26,
13217
13256
  line: startLine
13218
13257
  });
13219
13258
  const commentId = commentRes.data.id;
@@ -14776,6 +14815,85 @@ async function waitForAnaysisAndReviewPr({
14776
14815
  }
14777
14816
  }
14778
14817
 
14818
+ // src/commands/scan_skill_input.ts
14819
+ import fs11 from "fs";
14820
+ import path10 from "path";
14821
+ import AdmZip2 from "adm-zip";
14822
+ var LOCAL_SKILL_ZIP_DATA_URL_PREFIX = "data:application/zip;base64,";
14823
+ var MAX_LOCAL_SKILL_ARCHIVE_BYTES = 2 * 1024 * 1024;
14824
+ async function resolveSkillScanInput(skillInput) {
14825
+ const resolvedPath = path10.resolve(skillInput);
14826
+ if (!fs11.existsSync(resolvedPath)) {
14827
+ return skillInput;
14828
+ }
14829
+ const stat = fs11.statSync(resolvedPath);
14830
+ if (!stat.isDirectory()) {
14831
+ throw new CliError(
14832
+ "Local skill input must be a directory containing SKILL.md"
14833
+ );
14834
+ }
14835
+ return packageLocalSkillDirectory(resolvedPath);
14836
+ }
14837
+ function packageLocalSkillDirectory(directoryPath) {
14838
+ const zip = new AdmZip2();
14839
+ const rootPath = path10.resolve(directoryPath);
14840
+ const filePaths = listDirectoryFiles(rootPath);
14841
+ let hasSkillMd = false;
14842
+ for (const relativePath of filePaths) {
14843
+ const fullPath = path10.join(rootPath, relativePath);
14844
+ const normalizedFullPath = path10.resolve(fullPath);
14845
+ if (normalizedFullPath !== rootPath && !normalizedFullPath.startsWith(rootPath + path10.sep)) {
14846
+ continue;
14847
+ }
14848
+ const fileContent = fs11.readFileSync(normalizedFullPath);
14849
+ zip.addFile(relativePath, fileContent);
14850
+ if (path10.basename(relativePath).toLowerCase() === "skill.md") {
14851
+ hasSkillMd = true;
14852
+ }
14853
+ }
14854
+ if (!hasSkillMd) {
14855
+ throw new CliError("Local skill directory must contain a SKILL.md file");
14856
+ }
14857
+ const zipBuffer = zip.toBuffer();
14858
+ if (zipBuffer.length > MAX_LOCAL_SKILL_ARCHIVE_BYTES) {
14859
+ throw new CliError(
14860
+ `Local skill directory is too large to scan via CLI (${zipBuffer.length} bytes > ${MAX_LOCAL_SKILL_ARCHIVE_BYTES} bytes)`
14861
+ );
14862
+ }
14863
+ return `${LOCAL_SKILL_ZIP_DATA_URL_PREFIX}${zipBuffer.toString("base64")}`;
14864
+ }
14865
+ function listDirectoryFiles(rootPath) {
14866
+ const files = [];
14867
+ function walk(relativeDir) {
14868
+ const absoluteDir = path10.join(rootPath, relativeDir);
14869
+ const entries = fs11.readdirSync(absoluteDir, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
14870
+ for (const entry of entries) {
14871
+ const safeEntryName = path10.basename(entry.name).replace(/\0/g, "");
14872
+ if (!safeEntryName) {
14873
+ continue;
14874
+ }
14875
+ const relativePath = relativeDir ? path10.posix.join(relativeDir, safeEntryName) : safeEntryName;
14876
+ const absolutePath = path10.join(rootPath, relativePath);
14877
+ const normalizedAbsolutePath = path10.resolve(absolutePath);
14878
+ if (normalizedAbsolutePath !== rootPath && !normalizedAbsolutePath.startsWith(rootPath + path10.sep)) {
14879
+ continue;
14880
+ }
14881
+ if (entry.isSymbolicLink()) {
14882
+ continue;
14883
+ }
14884
+ if (entry.isDirectory()) {
14885
+ walk(relativePath);
14886
+ continue;
14887
+ }
14888
+ if (entry.isFile()) {
14889
+ files.push(relativePath);
14890
+ }
14891
+ }
14892
+ }
14893
+ walk("");
14894
+ return files;
14895
+ }
14896
+
14779
14897
  // src/commands/index.ts
14780
14898
  async function review(params, { skipPrompts = true } = {}) {
14781
14899
  const {
@@ -14901,10 +15019,80 @@ async function showWelcomeMessage(skipPrompts = false) {
14901
15019
  skipPrompts ? await sleep(100) : await sleep(2e3);
14902
15020
  welcome.stop();
14903
15021
  }
15022
+ var VERDICT_COLORS = {
15023
+ BENIGN: "green",
15024
+ WARNING: "yellow",
15025
+ SUSPICIOUS: "magenta",
15026
+ MALICIOUS: "red"
15027
+ };
15028
+ var SEVERITY_COLORS = {
15029
+ CRITICAL: "red",
15030
+ HIGH: "magenta",
15031
+ MEDIUM: "yellow",
15032
+ LOW: "cyan"
15033
+ };
15034
+ async function scanSkill(options) {
15035
+ const { url, apiKey, ci } = options;
15036
+ const gqlClient = await getAuthenticatedGQLClient({
15037
+ inputApiKey: apiKey,
15038
+ isSkipPrompts: ci
15039
+ });
15040
+ console.log(chalk7.dim(`Scanning skill: ${url}`));
15041
+ console.log();
15042
+ const skillUrl = await resolveSkillScanInput(url);
15043
+ const result = await gqlClient.scanSkill({ skillUrl });
15044
+ const scan2 = result.scanSkill;
15045
+ const verdictColor = VERDICT_COLORS[scan2.verdict] ?? "white";
15046
+ console.log(
15047
+ chalk7.bold(`Verdict: `) + chalk7[verdictColor](
15048
+ scan2.verdict
15049
+ )
15050
+ );
15051
+ console.log(`Skill: ${scan2.skillName}`);
15052
+ if (scan2.skillVersion) {
15053
+ console.log(`Version: ${scan2.skillVersion}`);
15054
+ }
15055
+ console.log(`Hash: ${scan2.skillHash ?? "N/A"}`);
15056
+ console.log(`Findings: ${scan2.findingsCount}`);
15057
+ console.log(`Duration: ${scan2.scanDurationMs}ms`);
15058
+ if (scan2.cached) {
15059
+ console.log(chalk7.dim("(cached result)"));
15060
+ }
15061
+ console.log();
15062
+ if (scan2.findings.length > 0) {
15063
+ console.log(chalk7.bold("Findings:"));
15064
+ console.log();
15065
+ for (const f of scan2.findings) {
15066
+ const sevColor = SEVERITY_COLORS[f.severity] ?? "white";
15067
+ const location = [f.filePath, f.lineNumber].filter(Boolean).join(":");
15068
+ console.log(
15069
+ ` ${chalk7[sevColor](f.severity)} [${f.layer}] ${f.category}${f.ruleId ? ` (${f.ruleId})` : ""}`
15070
+ );
15071
+ if (location) {
15072
+ console.log(` ${chalk7.dim(location)}`);
15073
+ }
15074
+ console.log(` ${f.explanation}`);
15075
+ if (f.evidence) {
15076
+ console.log(
15077
+ ` ${String(chalk7.dim("Evidence: " + f.evidence.slice(0, 120))).replace(/\n|\r/g, "")}`
15078
+ );
15079
+ }
15080
+ console.log();
15081
+ }
15082
+ }
15083
+ if (scan2.summary) {
15084
+ console.log(chalk7.bold("Analysis:"));
15085
+ console.log(` ${scan2.summary}`);
15086
+ console.log();
15087
+ }
15088
+ if (scan2.verdict === "MALICIOUS" || scan2.verdict === "SUSPICIOUS") {
15089
+ process.exit(2);
15090
+ }
15091
+ }
14904
15092
 
14905
15093
  // src/args/validation.ts
14906
- import chalk7 from "chalk";
14907
- import path10 from "path";
15094
+ import chalk8 from "chalk";
15095
+ import path11 from "path";
14908
15096
  import { z as z30 } from "zod";
14909
15097
  function throwRepoUrlErrorMessage({
14910
15098
  error,
@@ -14913,11 +15101,11 @@ function throwRepoUrlErrorMessage({
14913
15101
  }) {
14914
15102
  const errorMessage = error.issues[error.issues.length - 1]?.message;
14915
15103
  const formattedErrorMessage = `
14916
- Error: ${chalk7.bold(
15104
+ Error: ${chalk8.bold(
14917
15105
  repoUrl
14918
15106
  )} is ${errorMessage}
14919
15107
  Example:
14920
- mobbdev ${command} -r ${chalk7.bold(
15108
+ mobbdev ${command} -r ${chalk8.bold(
14921
15109
  "https://github.com/WebGoat/WebGoat"
14922
15110
  )}`;
14923
15111
  throw new CliError(formattedErrorMessage);
@@ -14948,12 +15136,12 @@ function validateRepoUrl(args) {
14948
15136
  }
14949
15137
  var supportExtensions = [".json", ".xml", ".fpr", ".sarif", ".zip"];
14950
15138
  function validateReportFileFormat(reportFile) {
14951
- if (!supportExtensions.includes(path10.extname(reportFile))) {
15139
+ if (!supportExtensions.includes(path11.extname(reportFile))) {
14952
15140
  throw new CliError(
14953
15141
  `
14954
- ${chalk7.bold(
15142
+ ${chalk8.bold(
14955
15143
  reportFile
14956
- )} is not a supported file extension. Supported extensions are: ${chalk7.bold(
15144
+ )} is not a supported file extension. Supported extensions are: ${chalk8.bold(
14957
15145
  supportExtensions.join(", ")
14958
15146
  )}
14959
15147
  `
@@ -14966,22 +15154,22 @@ function analyzeBuilder(yargs2) {
14966
15154
  return yargs2.option("f", {
14967
15155
  alias: "scan-file",
14968
15156
  type: "string",
14969
- describe: chalk8.bold(
15157
+ describe: chalk9.bold(
14970
15158
  "Select the vulnerability report to analyze (Checkmarx, Snyk, Fortify, CodeQL, Sonarqube, Semgrep, Datadog)"
14971
15159
  )
14972
15160
  }).option("repo", repoOption).option("p", {
14973
15161
  alias: "src-path",
14974
- describe: chalk8.bold(
15162
+ describe: chalk9.bold(
14975
15163
  "Path to the repository folder with the source code; alternatively, you can specify the Fortify FPR file to extract source code out of it"
14976
15164
  ),
14977
15165
  type: "string"
14978
15166
  }).option("ref", refOption).option("ch", {
14979
15167
  alias: "commit-hash",
14980
- describe: chalk8.bold("Hash of the commit"),
15168
+ describe: chalk9.bold("Hash of the commit"),
14981
15169
  type: "string"
14982
15170
  }).option("mobb-project-name", mobbProjectNameOption).option("y", yesOption).option("ci", ciOption).option("org", organizationIdOptions).option("api-key", apiKeyOption).option("commit-hash", commitHashOption).option("auto-pr", autoPrOption).option("create-one-pr", createOnePrOption).option("commit-directly", commitDirectlyOption).option("pull-request", {
14983
15171
  alias: ["pr", "pr-number", "pr-id"],
14984
- describe: chalk8.bold("Number of the pull request"),
15172
+ describe: chalk9.bold("Number of the pull request"),
14985
15173
  type: "number",
14986
15174
  demandOption: false
14987
15175
  }).option("polling", pollingOption).example(
@@ -14990,9 +15178,9 @@ function analyzeBuilder(yargs2) {
14990
15178
  ).help();
14991
15179
  }
14992
15180
  function validateAnalyzeOptions(argv) {
14993
- if (argv.f && !fs11.existsSync(argv.f)) {
15181
+ if (argv.f && !fs12.existsSync(argv.f)) {
14994
15182
  throw new CliError(`
14995
- Can't access ${chalk8.bold(argv.f)}`);
15183
+ Can't access ${chalk9.bold(argv.f)}`);
14996
15184
  }
14997
15185
  validateOrganizationId(argv.organizationId);
14998
15186
  if (!argv.srcPath && !argv.repo) {
@@ -15039,8 +15227,8 @@ import { z as z32 } from "zod";
15039
15227
  // src/args/commands/upload_ai_blame.ts
15040
15228
  import fsPromises3 from "fs/promises";
15041
15229
  import * as os3 from "os";
15042
- import path11 from "path";
15043
- import chalk9 from "chalk";
15230
+ import path12 from "path";
15231
+ import chalk10 from "chalk";
15044
15232
  import { withFile } from "tmp-promise";
15045
15233
  import z31 from "zod";
15046
15234
  init_client_generates();
@@ -15360,33 +15548,33 @@ function uploadAiBlameBuilder(args) {
15360
15548
  type: "string",
15361
15549
  array: true,
15362
15550
  demandOption: true,
15363
- describe: chalk9.bold("Path(s) to prompt artifact(s) (one per session)")
15551
+ describe: chalk10.bold("Path(s) to prompt artifact(s) (one per session)")
15364
15552
  }).option("inference", {
15365
15553
  type: "string",
15366
15554
  array: true,
15367
15555
  demandOption: true,
15368
- describe: chalk9.bold(
15556
+ describe: chalk10.bold(
15369
15557
  "Path(s) to inference artifact(s) (one per session)"
15370
15558
  )
15371
15559
  }).option("ai-response-at", {
15372
15560
  type: "string",
15373
15561
  array: true,
15374
- describe: chalk9.bold(
15562
+ describe: chalk10.bold(
15375
15563
  "ISO timestamp(s) for AI response (one per session, defaults to now)"
15376
15564
  )
15377
15565
  }).option("model", {
15378
15566
  type: "string",
15379
15567
  array: true,
15380
- describe: chalk9.bold("AI model name(s) (optional, one per session)")
15568
+ describe: chalk10.bold("AI model name(s) (optional, one per session)")
15381
15569
  }).option("tool-name", {
15382
15570
  type: "string",
15383
15571
  array: true,
15384
- describe: chalk9.bold("Tool/IDE name(s) (optional, one per session)")
15572
+ describe: chalk10.bold("Tool/IDE name(s) (optional, one per session)")
15385
15573
  }).option("blame-type", {
15386
15574
  type: "string",
15387
15575
  array: true,
15388
15576
  choices: Object.values(AiBlameInferenceType),
15389
- describe: chalk9.bold(
15577
+ describe: chalk10.bold(
15390
15578
  "Blame type(s) (optional, one per session, defaults to CHAT)"
15391
15579
  )
15392
15580
  }).strict();
@@ -15408,7 +15596,7 @@ async function uploadAiBlameHandlerFromExtension(args) {
15408
15596
  await withFile(async (promptFile) => {
15409
15597
  const promptsResult = await sanitizeDataWithCounts(args.prompts);
15410
15598
  promptsCounts = promptsResult.counts;
15411
- promptsUUID = path11.basename(promptFile.path, path11.extname(promptFile.path));
15599
+ promptsUUID = path12.basename(promptFile.path, path12.extname(promptFile.path));
15412
15600
  await fsPromises3.writeFile(
15413
15601
  promptFile.path,
15414
15602
  JSON.stringify(promptsResult.sanitizedData, null, 2),
@@ -15418,9 +15606,9 @@ async function uploadAiBlameHandlerFromExtension(args) {
15418
15606
  await withFile(async (inferenceFile) => {
15419
15607
  const inferenceResult = await sanitizeDataWithCounts(args.inference);
15420
15608
  inferenceCounts = inferenceResult.counts;
15421
- inferenceUUID = path11.basename(
15609
+ inferenceUUID = path12.basename(
15422
15610
  inferenceFile.path,
15423
- path11.extname(inferenceFile.path)
15611
+ path12.extname(inferenceFile.path)
15424
15612
  );
15425
15613
  await fsPromises3.writeFile(
15426
15614
  inferenceFile.path,
@@ -15468,7 +15656,7 @@ async function uploadAiBlameHandler(options) {
15468
15656
  const sessionIds = args.sessionId || args["session-id"] || [];
15469
15657
  if (prompts.length !== inferences.length) {
15470
15658
  const errorMsg = "prompt and inference must have the same number of entries";
15471
- logger2.error(chalk9.red(errorMsg));
15659
+ logger2.error(chalk10.red(errorMsg));
15472
15660
  if (exitOnError) {
15473
15661
  process.exit(1);
15474
15662
  }
@@ -15488,15 +15676,15 @@ async function uploadAiBlameHandler(options) {
15488
15676
  ]);
15489
15677
  } catch {
15490
15678
  const errorMsg = `File not found for session ${i + 1}`;
15491
- logger2.error(chalk9.red(errorMsg));
15679
+ logger2.error(chalk10.red(errorMsg));
15492
15680
  if (exitOnError) {
15493
15681
  process.exit(1);
15494
15682
  }
15495
15683
  throw new Error(errorMsg);
15496
15684
  }
15497
15685
  sessions.push({
15498
- promptFileName: path11.basename(promptPath),
15499
- inferenceFileName: path11.basename(inferencePath),
15686
+ promptFileName: path12.basename(promptPath),
15687
+ inferenceFileName: path12.basename(inferencePath),
15500
15688
  aiResponseAt: responseTimes[i] || nowIso,
15501
15689
  model: models[i],
15502
15690
  toolName: tools[i],
@@ -15521,7 +15709,7 @@ async function uploadAiBlameHandler(options) {
15521
15709
  const uploadSessions = initRes.uploadAIBlameInferencesInit?.uploadSessions ?? [];
15522
15710
  if (uploadSessions.length !== sessions.length) {
15523
15711
  const errorMsg = "Init failed to return expected number of sessions";
15524
- logger2.error(chalk9.red(errorMsg));
15712
+ logger2.error(chalk10.red(errorMsg));
15525
15713
  if (exitOnError) {
15526
15714
  process.exit(1);
15527
15715
  }
@@ -15578,7 +15766,7 @@ async function uploadAiBlameHandler(options) {
15578
15766
  if (status !== "OK") {
15579
15767
  const errorMsg = finRes?.finalizeAIBlameInferencesUpload?.error || "unknown error";
15580
15768
  logger2.error(
15581
- chalk9.red(
15769
+ chalk10.red(
15582
15770
  `[UPLOAD] Finalize failed with status: ${status}, error: ${errorMsg}`
15583
15771
  )
15584
15772
  );
@@ -15587,7 +15775,7 @@ async function uploadAiBlameHandler(options) {
15587
15775
  }
15588
15776
  throw new Error(errorMsg);
15589
15777
  }
15590
- logger2.info(chalk9.green("[UPLOAD] AI Blame uploads finalized successfully"));
15778
+ logger2.info(chalk10.green("[UPLOAD] AI Blame uploads finalized successfully"));
15591
15779
  } catch (error) {
15592
15780
  logger2.error("[UPLOAD] Finalize threw error:", error);
15593
15781
  throw error;
@@ -15599,6 +15787,8 @@ async function uploadAiBlameCommandHandler(args) {
15599
15787
 
15600
15788
  // src/features/claude_code/data_collector.ts
15601
15789
  init_client_generates();
15790
+ init_GitService();
15791
+ init_urlParser2();
15602
15792
 
15603
15793
  // src/features/claude_code/transcript_parser.ts
15604
15794
  import fsPromises4 from "fs/promises";
@@ -15845,8 +16035,23 @@ async function collectHookData() {
15845
16035
  tracePayload
15846
16036
  };
15847
16037
  }
16038
+ async function getRepositoryUrl2(cwd) {
16039
+ try {
16040
+ const gitService = new GitService(cwd);
16041
+ const isRepo = await gitService.isGitRepository();
16042
+ if (!isRepo) {
16043
+ return null;
16044
+ }
16045
+ const remoteUrl = await gitService.getRemoteUrl();
16046
+ const parsed = parseScmURL(remoteUrl);
16047
+ return parsed?.scmType === "GitHub" /* GitHub */ || parsed?.scmType === "GitLab" /* GitLab */ ? remoteUrl : null;
16048
+ } catch {
16049
+ return null;
16050
+ }
16051
+ }
15848
16052
  async function processAndUploadHookData() {
15849
16053
  const result = await collectHookData();
16054
+ const repositoryUrl = await getRepositoryUrl2(result.hookData.cwd);
15850
16055
  let uploadSuccess;
15851
16056
  try {
15852
16057
  await uploadAiBlameHandlerFromExtension({
@@ -15856,7 +16061,8 @@ async function processAndUploadHookData() {
15856
16061
  tool: result.tracePayload.tool,
15857
16062
  responseTime: result.tracePayload.responseTime,
15858
16063
  blameType: "CHAT" /* Chat */,
15859
- sessionId: result.hookData.session_id
16064
+ sessionId: result.hookData.session_id,
16065
+ repositoryUrl
15860
16066
  });
15861
16067
  uploadSuccess = true;
15862
16068
  } catch (error) {
@@ -15875,9 +16081,9 @@ async function processAndUploadHookData() {
15875
16081
  // src/features/claude_code/install_hook.ts
15876
16082
  import fsPromises5 from "fs/promises";
15877
16083
  import os4 from "os";
15878
- import path12 from "path";
15879
- import chalk10 from "chalk";
15880
- var CLAUDE_SETTINGS_PATH = path12.join(os4.homedir(), ".claude", "settings.json");
16084
+ import path13 from "path";
16085
+ import chalk11 from "chalk";
16086
+ var CLAUDE_SETTINGS_PATH = path13.join(os4.homedir(), ".claude", "settings.json");
15881
16087
  async function claudeSettingsExists() {
15882
16088
  try {
15883
16089
  await fsPromises5.access(CLAUDE_SETTINGS_PATH);
@@ -15901,12 +16107,12 @@ async function writeClaudeSettings(settings) {
15901
16107
  );
15902
16108
  }
15903
16109
  async function installMobbHooks(options = {}) {
15904
- console.log(chalk10.blue("Installing Mobb hooks in Claude Code settings..."));
16110
+ console.log(chalk11.blue("Installing Mobb hooks in Claude Code settings..."));
15905
16111
  if (!await claudeSettingsExists()) {
15906
- console.log(chalk10.red("\u274C Claude Code settings file not found"));
15907
- console.log(chalk10.yellow(`Expected location: ${CLAUDE_SETTINGS_PATH}`));
15908
- console.log(chalk10.yellow("Is Claude Code installed on your system?"));
15909
- console.log(chalk10.yellow("Please install Claude Code and try again."));
16112
+ console.log(chalk11.red("\u274C Claude Code settings file not found"));
16113
+ console.log(chalk11.yellow(`Expected location: ${CLAUDE_SETTINGS_PATH}`));
16114
+ console.log(chalk11.yellow("Is Claude Code installed on your system?"));
16115
+ console.log(chalk11.yellow("Please install Claude Code and try again."));
15910
16116
  throw new Error(
15911
16117
  "Claude Code settings file not found. Is Claude Code installed?"
15912
16118
  );
@@ -15930,7 +16136,7 @@ async function installMobbHooks(options = {}) {
15930
16136
  if (envVars.length > 0) {
15931
16137
  command = `${envVars.join(" ")} ${command}`;
15932
16138
  console.log(
15933
- chalk10.blue(
16139
+ chalk11.blue(
15934
16140
  `Adding environment variables to hook command: ${envVars.join(", ")}`
15935
16141
  )
15936
16142
  );
@@ -15951,15 +16157,15 @@ async function installMobbHooks(options = {}) {
15951
16157
  )
15952
16158
  );
15953
16159
  if (existingHookIndex >= 0) {
15954
- console.log(chalk10.yellow("Mobb hook already exists, updating..."));
16160
+ console.log(chalk11.yellow("Mobb hook already exists, updating..."));
15955
16161
  settings.hooks.PostToolUse[existingHookIndex] = mobbHookConfig;
15956
16162
  } else {
15957
- console.log(chalk10.green("Adding new Mobb hook..."));
16163
+ console.log(chalk11.green("Adding new Mobb hook..."));
15958
16164
  settings.hooks.PostToolUse.push(mobbHookConfig);
15959
16165
  }
15960
16166
  await writeClaudeSettings(settings);
15961
16167
  console.log(
15962
- chalk10.green(
16168
+ chalk11.green(
15963
16169
  `\u2705 Mobb hooks ${options.saveEnv ? "and environment variables " : ""}installed successfully in ${CLAUDE_SETTINGS_PATH}`
15964
16170
  )
15965
16171
  );
@@ -16062,8 +16268,8 @@ var WorkspaceService = class {
16062
16268
  * Sets a known workspace path that was discovered through successful validation
16063
16269
  * @param path The validated workspace path to store
16064
16270
  */
16065
- static setKnownWorkspacePath(path25) {
16066
- this.knownWorkspacePath = path25;
16271
+ static setKnownWorkspacePath(path26) {
16272
+ this.knownWorkspacePath = path26;
16067
16273
  }
16068
16274
  /**
16069
16275
  * Gets the known workspace path that was previously validated
@@ -17093,9 +17299,9 @@ async function createAuthenticatedMcpGQLClient({
17093
17299
 
17094
17300
  // src/mcp/services/McpUsageService/host.ts
17095
17301
  import { execSync as execSync2 } from "child_process";
17096
- import fs12 from "fs";
17302
+ import fs13 from "fs";
17097
17303
  import os6 from "os";
17098
- import path13 from "path";
17304
+ import path14 from "path";
17099
17305
  var IDEs = ["cursor", "windsurf", "webstorm", "vscode", "claude"];
17100
17306
  var runCommand = (cmd) => {
17101
17307
  try {
@@ -17110,17 +17316,17 @@ var gitInfo = {
17110
17316
  };
17111
17317
  var getClaudeWorkspacePaths = () => {
17112
17318
  const home = os6.homedir();
17113
- const claudeIdePath = path13.join(home, ".claude", "ide");
17319
+ const claudeIdePath = path14.join(home, ".claude", "ide");
17114
17320
  const workspacePaths = [];
17115
- if (!fs12.existsSync(claudeIdePath)) {
17321
+ if (!fs13.existsSync(claudeIdePath)) {
17116
17322
  return workspacePaths;
17117
17323
  }
17118
17324
  try {
17119
- const lockFiles = fs12.readdirSync(claudeIdePath).filter((file) => file.endsWith(".lock"));
17325
+ const lockFiles = fs13.readdirSync(claudeIdePath).filter((file) => file.endsWith(".lock"));
17120
17326
  for (const lockFile of lockFiles) {
17121
- const lockFilePath = path13.join(claudeIdePath, lockFile);
17327
+ const lockFilePath = path14.join(claudeIdePath, lockFile);
17122
17328
  try {
17123
- const lockContent = JSON.parse(fs12.readFileSync(lockFilePath, "utf8"));
17329
+ const lockContent = JSON.parse(fs13.readFileSync(lockFilePath, "utf8"));
17124
17330
  if (lockContent.workspaceFolders && Array.isArray(lockContent.workspaceFolders)) {
17125
17331
  workspacePaths.push(...lockContent.workspaceFolders);
17126
17332
  }
@@ -17143,24 +17349,24 @@ var getMCPConfigPaths = (hostName) => {
17143
17349
  switch (hostName.toLowerCase()) {
17144
17350
  case "cursor":
17145
17351
  return [
17146
- path13.join(currentDir, ".cursor", "mcp.json"),
17352
+ path14.join(currentDir, ".cursor", "mcp.json"),
17147
17353
  // local first
17148
- path13.join(home, ".cursor", "mcp.json")
17354
+ path14.join(home, ".cursor", "mcp.json")
17149
17355
  ];
17150
17356
  case "windsurf":
17151
17357
  return [
17152
- path13.join(currentDir, ".codeium", "mcp_config.json"),
17358
+ path14.join(currentDir, ".codeium", "mcp_config.json"),
17153
17359
  // local first
17154
- path13.join(home, ".codeium", "windsurf", "mcp_config.json")
17360
+ path14.join(home, ".codeium", "windsurf", "mcp_config.json")
17155
17361
  ];
17156
17362
  case "webstorm":
17157
17363
  return [];
17158
17364
  case "visualstudiocode":
17159
17365
  case "vscode":
17160
17366
  return [
17161
- path13.join(currentDir, ".vscode", "mcp.json"),
17367
+ path14.join(currentDir, ".vscode", "mcp.json"),
17162
17368
  // local first
17163
- process.platform === "win32" ? path13.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path13.join(
17369
+ process.platform === "win32" ? path14.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path14.join(
17164
17370
  home,
17165
17371
  "Library",
17166
17372
  "Application Support",
@@ -17171,13 +17377,13 @@ var getMCPConfigPaths = (hostName) => {
17171
17377
  ];
17172
17378
  case "claude": {
17173
17379
  const claudePaths = [
17174
- path13.join(currentDir, ".claude.json"),
17380
+ path14.join(currentDir, ".claude.json"),
17175
17381
  // local first
17176
- path13.join(home, ".claude.json")
17382
+ path14.join(home, ".claude.json")
17177
17383
  ];
17178
17384
  const workspacePaths = getClaudeWorkspacePaths();
17179
17385
  for (const workspacePath of workspacePaths) {
17180
- claudePaths.push(path13.join(workspacePath, ".mcp.json"));
17386
+ claudePaths.push(path14.join(workspacePath, ".mcp.json"));
17181
17387
  }
17182
17388
  return claudePaths;
17183
17389
  }
@@ -17186,9 +17392,9 @@ var getMCPConfigPaths = (hostName) => {
17186
17392
  }
17187
17393
  };
17188
17394
  var readConfigFile = (filePath) => {
17189
- if (!fs12.existsSync(filePath)) return null;
17395
+ if (!fs13.existsSync(filePath)) return null;
17190
17396
  try {
17191
- return JSON.parse(fs12.readFileSync(filePath, "utf8"));
17397
+ return JSON.parse(fs13.readFileSync(filePath, "utf8"));
17192
17398
  } catch (error) {
17193
17399
  logWarn(`[UsageService] Failed to read MCP config: ${filePath}`);
17194
17400
  return null;
@@ -17338,10 +17544,10 @@ var getHostInfo = (additionalMcpList) => {
17338
17544
  const ideConfigPaths = /* @__PURE__ */ new Set();
17339
17545
  for (const ide of IDEs) {
17340
17546
  const configPaths = getMCPConfigPaths(ide);
17341
- configPaths.forEach((path25) => ideConfigPaths.add(path25));
17547
+ configPaths.forEach((path26) => ideConfigPaths.add(path26));
17342
17548
  }
17343
17549
  const uniqueAdditionalPaths = additionalMcpList.filter(
17344
- (path25) => !ideConfigPaths.has(path25)
17550
+ (path26) => !ideConfigPaths.has(path26)
17345
17551
  );
17346
17552
  for (const ide of IDEs) {
17347
17553
  const cfg = readMCPConfig(ide);
@@ -17461,9 +17667,9 @@ init_configs();
17461
17667
 
17462
17668
  // src/mcp/services/McpUsageService/system.ts
17463
17669
  init_configs();
17464
- import fs13 from "fs";
17670
+ import fs14 from "fs";
17465
17671
  import os7 from "os";
17466
- import path14 from "path";
17672
+ import path15 from "path";
17467
17673
  var MAX_DEPTH = 2;
17468
17674
  var patterns = ["mcp", "claude"];
17469
17675
  var isFileMatch = (fileName) => {
@@ -17472,7 +17678,7 @@ var isFileMatch = (fileName) => {
17472
17678
  };
17473
17679
  var safeAccess = async (filePath) => {
17474
17680
  try {
17475
- await fs13.promises.access(filePath, fs13.constants.R_OK);
17681
+ await fs14.promises.access(filePath, fs14.constants.R_OK);
17476
17682
  return true;
17477
17683
  } catch {
17478
17684
  return false;
@@ -17481,9 +17687,9 @@ var safeAccess = async (filePath) => {
17481
17687
  var searchDir = async (dir, depth = 0) => {
17482
17688
  const results = [];
17483
17689
  if (depth > MAX_DEPTH) return results;
17484
- const entries = await fs13.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
17690
+ const entries = await fs14.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
17485
17691
  for (const entry of entries) {
17486
- const fullPath = path14.join(dir, entry.name);
17692
+ const fullPath = path15.join(dir, entry.name);
17487
17693
  if (entry.isFile() && isFileMatch(entry.name)) {
17488
17694
  results.push(fullPath);
17489
17695
  } else if (entry.isDirectory()) {
@@ -17500,14 +17706,14 @@ var findSystemMCPConfigs = async () => {
17500
17706
  const home = os7.homedir();
17501
17707
  const platform2 = os7.platform();
17502
17708
  const knownDirs = platform2 === "win32" ? [
17503
- path14.join(home, ".cursor"),
17504
- path14.join(home, "Documents"),
17505
- path14.join(home, "Downloads")
17709
+ path15.join(home, ".cursor"),
17710
+ path15.join(home, "Documents"),
17711
+ path15.join(home, "Downloads")
17506
17712
  ] : [
17507
- path14.join(home, ".cursor"),
17508
- process.env["XDG_CONFIG_HOME"] || path14.join(home, ".config"),
17509
- path14.join(home, "Documents"),
17510
- path14.join(home, "Downloads")
17713
+ path15.join(home, ".cursor"),
17714
+ process.env["XDG_CONFIG_HOME"] || path15.join(home, ".config"),
17715
+ path15.join(home, "Documents"),
17716
+ path15.join(home, "Downloads")
17511
17717
  ];
17512
17718
  const timeoutPromise = new Promise(
17513
17719
  (resolve) => setTimeout(() => {
@@ -17519,7 +17725,7 @@ var findSystemMCPConfigs = async () => {
17519
17725
  );
17520
17726
  const searchPromise = Promise.all(
17521
17727
  knownDirs.map(
17522
- (dir) => fs13.existsSync(dir) ? searchDir(dir) : Promise.resolve([])
17728
+ (dir) => fs14.existsSync(dir) ? searchDir(dir) : Promise.resolve([])
17523
17729
  )
17524
17730
  ).then((results) => results.flat());
17525
17731
  return await Promise.race([timeoutPromise, searchPromise]);
@@ -19921,31 +20127,31 @@ For a complete security audit workflow, use the \`full-security-audit\` prompt.
19921
20127
  };
19922
20128
 
19923
20129
  // src/mcp/services/McpDetectionService/CursorMcpDetectionService.ts
19924
- import * as fs16 from "fs";
20130
+ import * as fs17 from "fs";
19925
20131
  import * as os10 from "os";
19926
- import * as path16 from "path";
20132
+ import * as path17 from "path";
19927
20133
 
19928
20134
  // src/mcp/services/McpDetectionService/BaseMcpDetectionService.ts
19929
20135
  init_configs();
19930
- import * as fs15 from "fs";
20136
+ import * as fs16 from "fs";
19931
20137
  import fetch6 from "node-fetch";
19932
- import * as path15 from "path";
20138
+ import * as path16 from "path";
19933
20139
 
19934
20140
  // src/mcp/services/McpDetectionService/McpDetectionServiceUtils.ts
19935
- import * as fs14 from "fs";
20141
+ import * as fs15 from "fs";
19936
20142
  import * as os9 from "os";
19937
20143
 
19938
20144
  // src/mcp/services/McpDetectionService/VscodeMcpDetectionService.ts
19939
- import * as fs17 from "fs";
20145
+ import * as fs18 from "fs";
19940
20146
  import * as os11 from "os";
19941
- import * as path17 from "path";
20147
+ import * as path18 from "path";
19942
20148
 
19943
20149
  // src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesTool.ts
19944
20150
  import { z as z42 } from "zod";
19945
20151
 
19946
20152
  // src/mcp/services/PathValidation.ts
19947
- import fs18 from "fs";
19948
- import path18 from "path";
20153
+ import fs19 from "fs";
20154
+ import path19 from "path";
19949
20155
  async function validatePath(inputPath) {
19950
20156
  logDebug("Validating MCP path", { inputPath });
19951
20157
  if (/^\/[a-zA-Z]:\//.test(inputPath)) {
@@ -19977,7 +20183,7 @@ async function validatePath(inputPath) {
19977
20183
  logError(error);
19978
20184
  return { isValid: false, error, path: inputPath };
19979
20185
  }
19980
- const normalizedPath = path18.normalize(inputPath);
20186
+ const normalizedPath = path19.normalize(inputPath);
19981
20187
  if (normalizedPath.includes("..")) {
19982
20188
  const error = `Normalized path contains path traversal patterns: ${inputPath}`;
19983
20189
  logError(error);
@@ -20004,7 +20210,7 @@ async function validatePath(inputPath) {
20004
20210
  logDebug("Path validation successful", { inputPath });
20005
20211
  logDebug("Checking path existence", { inputPath });
20006
20212
  try {
20007
- await fs18.promises.access(inputPath);
20213
+ await fs19.promises.access(inputPath);
20008
20214
  logDebug("Path exists and is accessible", { inputPath });
20009
20215
  WorkspaceService.setKnownWorkspacePath(inputPath);
20010
20216
  logDebug("Stored validated path in WorkspaceService", { inputPath });
@@ -20632,10 +20838,10 @@ If you wish to scan files that were recently changed in your git history call th
20632
20838
  init_FileUtils();
20633
20839
  init_GitService();
20634
20840
  init_configs();
20635
- import fs19 from "fs/promises";
20841
+ import fs20 from "fs/promises";
20636
20842
  import nodePath from "path";
20637
20843
  var getLocalFiles = async ({
20638
- path: path25,
20844
+ path: path26,
20639
20845
  maxFileSize = MCP_MAX_FILE_SIZE,
20640
20846
  maxFiles,
20641
20847
  isAllFilesScan,
@@ -20643,17 +20849,17 @@ var getLocalFiles = async ({
20643
20849
  scanRecentlyChangedFiles
20644
20850
  }) => {
20645
20851
  logDebug(`[${scanContext}] Starting getLocalFiles`, {
20646
- path: path25,
20852
+ path: path26,
20647
20853
  maxFileSize,
20648
20854
  maxFiles,
20649
20855
  isAllFilesScan,
20650
20856
  scanRecentlyChangedFiles
20651
20857
  });
20652
20858
  try {
20653
- const resolvedRepoPath = await fs19.realpath(path25);
20859
+ const resolvedRepoPath = await fs20.realpath(path26);
20654
20860
  logDebug(`[${scanContext}] Resolved repository path`, {
20655
20861
  resolvedRepoPath,
20656
- originalPath: path25
20862
+ originalPath: path26
20657
20863
  });
20658
20864
  const gitService = new GitService(resolvedRepoPath, log);
20659
20865
  const gitValidation = await gitService.validateRepository();
@@ -20666,7 +20872,7 @@ var getLocalFiles = async ({
20666
20872
  if (!gitValidation.isValid || isAllFilesScan) {
20667
20873
  try {
20668
20874
  files = await FileUtils.getLastChangedFiles({
20669
- dir: path25,
20875
+ dir: path26,
20670
20876
  maxFileSize,
20671
20877
  maxFiles,
20672
20878
  isAllFilesScan
@@ -20730,7 +20936,7 @@ var getLocalFiles = async ({
20730
20936
  absoluteFilePath
20731
20937
  );
20732
20938
  try {
20733
- const fileStat = await fs19.stat(absoluteFilePath);
20939
+ const fileStat = await fs20.stat(absoluteFilePath);
20734
20940
  return {
20735
20941
  filename: nodePath.basename(absoluteFilePath),
20736
20942
  relativePath,
@@ -20758,7 +20964,7 @@ var getLocalFiles = async ({
20758
20964
  logError(`${scanContext}Unexpected error in getLocalFiles`, {
20759
20965
  error: error instanceof Error ? error.message : String(error),
20760
20966
  stack: error instanceof Error ? error.stack : void 0,
20761
- path: path25
20967
+ path: path26
20762
20968
  });
20763
20969
  throw error;
20764
20970
  }
@@ -20767,8 +20973,8 @@ var getLocalFiles = async ({
20767
20973
  // src/mcp/services/LocalMobbFolderService.ts
20768
20974
  init_client_generates();
20769
20975
  init_GitService();
20770
- import fs20 from "fs";
20771
- import path19 from "path";
20976
+ import fs21 from "fs";
20977
+ import path20 from "path";
20772
20978
  import { z as z41 } from "zod";
20773
20979
  function extractPathFromPatch(patch) {
20774
20980
  const match = patch?.match(/diff --git a\/([^\s]+) b\//);
@@ -20854,19 +21060,19 @@ var LocalMobbFolderService = class {
20854
21060
  "[LocalMobbFolderService] Non-git repository detected, skipping .gitignore operations"
20855
21061
  );
20856
21062
  }
20857
- const mobbFolderPath = path19.join(
21063
+ const mobbFolderPath = path20.join(
20858
21064
  this.repoPath,
20859
21065
  this.defaultMobbFolderName
20860
21066
  );
20861
- if (!fs20.existsSync(mobbFolderPath)) {
21067
+ if (!fs21.existsSync(mobbFolderPath)) {
20862
21068
  logInfo("[LocalMobbFolderService] Creating .mobb folder", {
20863
21069
  mobbFolderPath
20864
21070
  });
20865
- fs20.mkdirSync(mobbFolderPath, { recursive: true });
21071
+ fs21.mkdirSync(mobbFolderPath, { recursive: true });
20866
21072
  } else {
20867
21073
  logDebug("[LocalMobbFolderService] .mobb folder already exists");
20868
21074
  }
20869
- const stats = fs20.statSync(mobbFolderPath);
21075
+ const stats = fs21.statSync(mobbFolderPath);
20870
21076
  if (!stats.isDirectory()) {
20871
21077
  throw new Error(`Path exists but is not a directory: ${mobbFolderPath}`);
20872
21078
  }
@@ -20907,13 +21113,13 @@ var LocalMobbFolderService = class {
20907
21113
  logDebug("[LocalMobbFolderService] Git repository validated successfully");
20908
21114
  } else {
20909
21115
  try {
20910
- const stats = fs20.statSync(this.repoPath);
21116
+ const stats = fs21.statSync(this.repoPath);
20911
21117
  if (!stats.isDirectory()) {
20912
21118
  throw new Error(
20913
21119
  `Path exists but is not a directory: ${this.repoPath}`
20914
21120
  );
20915
21121
  }
20916
- fs20.accessSync(this.repoPath, fs20.constants.R_OK | fs20.constants.W_OK);
21122
+ fs21.accessSync(this.repoPath, fs21.constants.R_OK | fs21.constants.W_OK);
20917
21123
  logDebug(
20918
21124
  "[LocalMobbFolderService] Non-git directory validated successfully"
20919
21125
  );
@@ -21026,8 +21232,8 @@ var LocalMobbFolderService = class {
21026
21232
  mobbFolderPath,
21027
21233
  baseFileName
21028
21234
  );
21029
- const filePath = path19.join(mobbFolderPath, uniqueFileName);
21030
- await fs20.promises.writeFile(filePath, patch, "utf8");
21235
+ const filePath = path20.join(mobbFolderPath, uniqueFileName);
21236
+ await fs21.promises.writeFile(filePath, patch, "utf8");
21031
21237
  logInfo("[LocalMobbFolderService] Patch saved successfully", {
21032
21238
  filePath,
21033
21239
  fileName: uniqueFileName,
@@ -21084,11 +21290,11 @@ var LocalMobbFolderService = class {
21084
21290
  * @returns Unique filename that doesn't conflict with existing files
21085
21291
  */
21086
21292
  getUniqueFileName(folderPath, baseFileName) {
21087
- const baseName = path19.parse(baseFileName).name;
21088
- const extension = path19.parse(baseFileName).ext;
21293
+ const baseName = path20.parse(baseFileName).name;
21294
+ const extension = path20.parse(baseFileName).ext;
21089
21295
  let uniqueFileName = baseFileName;
21090
21296
  let index = 1;
21091
- while (fs20.existsSync(path19.join(folderPath, uniqueFileName))) {
21297
+ while (fs21.existsSync(path20.join(folderPath, uniqueFileName))) {
21092
21298
  uniqueFileName = `${baseName}-${index}${extension}`;
21093
21299
  index++;
21094
21300
  if (index > 1e3) {
@@ -21119,18 +21325,18 @@ var LocalMobbFolderService = class {
21119
21325
  logDebug("[LocalMobbFolderService] Logging patch info", { fixId: fix.id });
21120
21326
  try {
21121
21327
  const mobbFolderPath = await this.getFolder();
21122
- const patchInfoPath = path19.join(mobbFolderPath, "patchInfo.md");
21328
+ const patchInfoPath = path20.join(mobbFolderPath, "patchInfo.md");
21123
21329
  const markdownContent = this.generateFixMarkdown(fix, savedPatchFileName);
21124
21330
  let existingContent = "";
21125
- if (fs20.existsSync(patchInfoPath)) {
21126
- existingContent = await fs20.promises.readFile(patchInfoPath, "utf8");
21331
+ if (fs21.existsSync(patchInfoPath)) {
21332
+ existingContent = await fs21.promises.readFile(patchInfoPath, "utf8");
21127
21333
  logDebug("[LocalMobbFolderService] Existing patchInfo.md found");
21128
21334
  } else {
21129
21335
  logDebug("[LocalMobbFolderService] Creating new patchInfo.md file");
21130
21336
  }
21131
21337
  const separator = existingContent ? "\n\n================================================================================\n\n" : "";
21132
21338
  const updatedContent = `${markdownContent}${separator}${existingContent}`;
21133
- await fs20.promises.writeFile(patchInfoPath, updatedContent, "utf8");
21339
+ await fs21.promises.writeFile(patchInfoPath, updatedContent, "utf8");
21134
21340
  logInfo("[LocalMobbFolderService] Patch info logged successfully", {
21135
21341
  patchInfoPath,
21136
21342
  fixId: fix.id,
@@ -21161,7 +21367,7 @@ var LocalMobbFolderService = class {
21161
21367
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
21162
21368
  const patch = this.extractPatchFromFix(fix);
21163
21369
  const relativePatchedFilePath = patch ? extractPathFromPatch(patch) : null;
21164
- const patchedFilePath = relativePatchedFilePath ? path19.resolve(this.repoPath, relativePatchedFilePath) : null;
21370
+ const patchedFilePath = relativePatchedFilePath ? path20.resolve(this.repoPath, relativePatchedFilePath) : null;
21165
21371
  const fixIdentifier = savedPatchFileName ? savedPatchFileName.replace(".patch", "") : fix.id;
21166
21372
  let markdown = `# Fix ${fixIdentifier}
21167
21373
 
@@ -21503,16 +21709,16 @@ import {
21503
21709
  unlinkSync,
21504
21710
  writeFileSync
21505
21711
  } from "fs";
21506
- import fs21 from "fs/promises";
21712
+ import fs22 from "fs/promises";
21507
21713
  import parseDiff3 from "parse-diff";
21508
- import path20 from "path";
21714
+ import path21 from "path";
21509
21715
  var PatchApplicationService = class {
21510
21716
  /**
21511
21717
  * Gets the appropriate comment syntax for a file based on its extension
21512
21718
  */
21513
21719
  static getCommentSyntax(filePath) {
21514
- const ext = path20.extname(filePath).toLowerCase();
21515
- const basename2 = path20.basename(filePath);
21720
+ const ext = path21.extname(filePath).toLowerCase();
21721
+ const basename2 = path21.basename(filePath);
21516
21722
  const commentMap = {
21517
21723
  // C-style languages (single line comments)
21518
21724
  ".js": "//",
@@ -21720,7 +21926,7 @@ var PatchApplicationService = class {
21720
21926
  }
21721
21927
  );
21722
21928
  }
21723
- const dirPath = path20.dirname(normalizedFilePath);
21929
+ const dirPath = path21.dirname(normalizedFilePath);
21724
21930
  mkdirSync(dirPath, { recursive: true });
21725
21931
  writeFileSync(normalizedFilePath, finalContent, "utf8");
21726
21932
  return normalizedFilePath;
@@ -21729,9 +21935,9 @@ var PatchApplicationService = class {
21729
21935
  repositoryPath,
21730
21936
  targetPath
21731
21937
  }) {
21732
- const repoRoot = path20.resolve(repositoryPath);
21733
- const normalizedPath = path20.resolve(repoRoot, targetPath);
21734
- const repoRootWithSep = repoRoot.endsWith(path20.sep) ? repoRoot : `${repoRoot}${path20.sep}`;
21938
+ const repoRoot = path21.resolve(repositoryPath);
21939
+ const normalizedPath = path21.resolve(repoRoot, targetPath);
21940
+ const repoRootWithSep = repoRoot.endsWith(path21.sep) ? repoRoot : `${repoRoot}${path21.sep}`;
21735
21941
  if (normalizedPath !== repoRoot && !normalizedPath.startsWith(repoRootWithSep)) {
21736
21942
  throw new Error(
21737
21943
  `Security violation: target path ${targetPath} resolves outside repository`
@@ -21740,7 +21946,7 @@ var PatchApplicationService = class {
21740
21946
  return {
21741
21947
  repoRoot,
21742
21948
  normalizedPath,
21743
- relativePath: path20.relative(repoRoot, normalizedPath)
21949
+ relativePath: path21.relative(repoRoot, normalizedPath)
21744
21950
  };
21745
21951
  }
21746
21952
  /**
@@ -22022,9 +22228,9 @@ var PatchApplicationService = class {
22022
22228
  continue;
22023
22229
  }
22024
22230
  try {
22025
- const absolutePath = path20.resolve(repositoryPath, targetFile);
22231
+ const absolutePath = path21.resolve(repositoryPath, targetFile);
22026
22232
  if (existsSync6(absolutePath)) {
22027
- const stats = await fs21.stat(absolutePath);
22233
+ const stats = await fs22.stat(absolutePath);
22028
22234
  const fileModTime = stats.mtime.getTime();
22029
22235
  if (fileModTime > scanStartTime) {
22030
22236
  logError(
@@ -22065,7 +22271,7 @@ var PatchApplicationService = class {
22065
22271
  const appliedFixes = [];
22066
22272
  const failedFixes = [];
22067
22273
  const skippedFixes = [];
22068
- const resolvedRepoPath = await fs21.realpath(repositoryPath);
22274
+ const resolvedRepoPath = await fs22.realpath(repositoryPath);
22069
22275
  logInfo(
22070
22276
  `[${scanContext}] Starting patch application for ${fixes.length} fixes`,
22071
22277
  {
@@ -22248,7 +22454,7 @@ var PatchApplicationService = class {
22248
22454
  fix,
22249
22455
  scanContext
22250
22456
  });
22251
- appliedFiles.push(path20.relative(repositoryPath, actualPath));
22457
+ appliedFiles.push(path21.relative(repositoryPath, actualPath));
22252
22458
  logDebug(`[${scanContext}] Created new file: ${relativePath}`);
22253
22459
  }
22254
22460
  /**
@@ -22297,7 +22503,7 @@ var PatchApplicationService = class {
22297
22503
  fix,
22298
22504
  scanContext
22299
22505
  });
22300
- appliedFiles.push(path20.relative(repositoryPath, actualPath));
22506
+ appliedFiles.push(path21.relative(repositoryPath, actualPath));
22301
22507
  logDebug(`[${scanContext}] Modified file: ${relativePath}`);
22302
22508
  }
22303
22509
  }
@@ -22493,9 +22699,9 @@ init_configs();
22493
22699
 
22494
22700
  // src/mcp/services/FileOperations.ts
22495
22701
  init_FileUtils();
22496
- import fs22 from "fs";
22497
- import path21 from "path";
22498
- import AdmZip2 from "adm-zip";
22702
+ import fs23 from "fs";
22703
+ import path22 from "path";
22704
+ import AdmZip3 from "adm-zip";
22499
22705
  var FileOperations = class {
22500
22706
  /**
22501
22707
  * Creates a ZIP archive containing the specified source files
@@ -22510,14 +22716,14 @@ var FileOperations = class {
22510
22716
  maxFileSize
22511
22717
  }) {
22512
22718
  logDebug("[FileOperations] Packing files");
22513
- const zip = new AdmZip2();
22719
+ const zip = new AdmZip3();
22514
22720
  let packedFilesCount = 0;
22515
22721
  const packedFiles = [];
22516
22722
  const excludedFiles = [];
22517
- const resolvedRepoPath = path21.resolve(repositoryPath);
22723
+ const resolvedRepoPath = path22.resolve(repositoryPath);
22518
22724
  for (const filepath of fileList) {
22519
- const absoluteFilepath = path21.join(repositoryPath, filepath);
22520
- const resolvedFilePath = path21.resolve(absoluteFilepath);
22725
+ const absoluteFilepath = path22.join(repositoryPath, filepath);
22726
+ const resolvedFilePath = path22.resolve(absoluteFilepath);
22521
22727
  if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
22522
22728
  const reason = "potential path traversal security risk";
22523
22729
  logDebug(`[FileOperations] Skipping ${filepath} due to ${reason}`);
@@ -22564,11 +22770,11 @@ var FileOperations = class {
22564
22770
  fileList,
22565
22771
  repositoryPath
22566
22772
  }) {
22567
- const resolvedRepoPath = path21.resolve(repositoryPath);
22773
+ const resolvedRepoPath = path22.resolve(repositoryPath);
22568
22774
  const validatedPaths = [];
22569
22775
  for (const filepath of fileList) {
22570
- const absoluteFilepath = path21.join(repositoryPath, filepath);
22571
- const resolvedFilePath = path21.resolve(absoluteFilepath);
22776
+ const absoluteFilepath = path22.join(repositoryPath, filepath);
22777
+ const resolvedFilePath = path22.resolve(absoluteFilepath);
22572
22778
  if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
22573
22779
  logDebug(
22574
22780
  `[FileOperations] Rejecting ${filepath} - path traversal attempt detected`
@@ -22576,7 +22782,7 @@ var FileOperations = class {
22576
22782
  continue;
22577
22783
  }
22578
22784
  try {
22579
- await fs22.promises.access(absoluteFilepath, fs22.constants.R_OK);
22785
+ await fs23.promises.access(absoluteFilepath, fs23.constants.R_OK);
22580
22786
  validatedPaths.push(filepath);
22581
22787
  } catch (error) {
22582
22788
  logDebug(
@@ -22595,8 +22801,8 @@ var FileOperations = class {
22595
22801
  const fileDataArray = [];
22596
22802
  for (const absolutePath of filePaths) {
22597
22803
  try {
22598
- const content = await fs22.promises.readFile(absolutePath);
22599
- const relativePath = path21.basename(absolutePath);
22804
+ const content = await fs23.promises.readFile(absolutePath);
22805
+ const relativePath = path22.basename(absolutePath);
22600
22806
  fileDataArray.push({
22601
22807
  relativePath,
22602
22808
  absolutePath,
@@ -22621,7 +22827,7 @@ var FileOperations = class {
22621
22827
  relativeFilepath
22622
22828
  }) {
22623
22829
  try {
22624
- return await fs22.promises.readFile(absoluteFilepath);
22830
+ return await fs23.promises.readFile(absoluteFilepath);
22625
22831
  } catch (fsError) {
22626
22832
  logError(
22627
22833
  `[FileOperations] Failed to read ${relativeFilepath} from filesystem: ${fsError}`
@@ -22908,14 +23114,14 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
22908
23114
  * since the last scan.
22909
23115
  */
22910
23116
  async scanForSecurityVulnerabilities({
22911
- path: path25,
23117
+ path: path26,
22912
23118
  isAllDetectionRulesScan,
22913
23119
  isAllFilesScan,
22914
23120
  scanContext
22915
23121
  }) {
22916
23122
  this.hasAuthenticationFailed = false;
22917
23123
  logDebug(`[${scanContext}] Scanning for new security vulnerabilities`, {
22918
- path: path25
23124
+ path: path26
22919
23125
  });
22920
23126
  if (!this.gqlClient) {
22921
23127
  logInfo(`[${scanContext}] No GQL client found, skipping scan`);
@@ -22931,11 +23137,11 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
22931
23137
  }
22932
23138
  logDebug(
22933
23139
  `[${scanContext}] Connected to the API, assembling list of files to scan`,
22934
- { path: path25 }
23140
+ { path: path26 }
22935
23141
  );
22936
23142
  const isBackgroundScan = scanContext === ScanContext.BACKGROUND_INITIAL || scanContext === ScanContext.BACKGROUND_PERIODIC;
22937
23143
  const files = await getLocalFiles({
22938
- path: path25,
23144
+ path: path26,
22939
23145
  isAllFilesScan,
22940
23146
  scanContext,
22941
23147
  scanRecentlyChangedFiles: !isBackgroundScan
@@ -22961,13 +23167,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
22961
23167
  });
22962
23168
  const { fixReportId, projectId } = await scanFiles({
22963
23169
  fileList: filesToScan.map((file) => file.relativePath),
22964
- repositoryPath: path25,
23170
+ repositoryPath: path26,
22965
23171
  gqlClient: this.gqlClient,
22966
23172
  isAllDetectionRulesScan,
22967
23173
  scanContext
22968
23174
  });
22969
23175
  logInfo(
22970
- `[${scanContext}] Security scan completed for ${path25} reportId: ${fixReportId} projectId: ${projectId}`
23176
+ `[${scanContext}] Security scan completed for ${path26} reportId: ${fixReportId} projectId: ${projectId}`
22971
23177
  );
22972
23178
  if (isAllFilesScan) {
22973
23179
  return;
@@ -23261,13 +23467,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
23261
23467
  });
23262
23468
  return scannedFiles.some((file) => file.relativePath === fixFile);
23263
23469
  }
23264
- async getFreshFixes({ path: path25 }) {
23470
+ async getFreshFixes({ path: path26 }) {
23265
23471
  const scanContext = ScanContext.USER_REQUEST;
23266
- logDebug(`[${scanContext}] Getting fresh fixes`, { path: path25 });
23267
- if (this.path !== path25) {
23268
- this.path = path25;
23472
+ logDebug(`[${scanContext}] Getting fresh fixes`, { path: path26 });
23473
+ if (this.path !== path26) {
23474
+ this.path = path26;
23269
23475
  this.reset();
23270
- logInfo(`[${scanContext}] Reset service state for new path`, { path: path25 });
23476
+ logInfo(`[${scanContext}] Reset service state for new path`, { path: path26 });
23271
23477
  }
23272
23478
  try {
23273
23479
  const loginContext = createMcpLoginContext("check_new_fixes");
@@ -23286,7 +23492,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
23286
23492
  }
23287
23493
  throw error;
23288
23494
  }
23289
- this.triggerScan({ path: path25, gqlClient: this.gqlClient });
23495
+ this.triggerScan({ path: path26, gqlClient: this.gqlClient });
23290
23496
  let isMvsAutoFixEnabled = null;
23291
23497
  try {
23292
23498
  isMvsAutoFixEnabled = await this.gqlClient.getMvsAutoFixSettings();
@@ -23320,33 +23526,33 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
23320
23526
  return noFreshFixesPrompt;
23321
23527
  }
23322
23528
  triggerScan({
23323
- path: path25,
23529
+ path: path26,
23324
23530
  gqlClient
23325
23531
  }) {
23326
- if (this.path !== path25) {
23327
- this.path = path25;
23532
+ if (this.path !== path26) {
23533
+ this.path = path26;
23328
23534
  this.reset();
23329
- logInfo(`Reset service state for new path in triggerScan`, { path: path25 });
23535
+ logInfo(`Reset service state for new path in triggerScan`, { path: path26 });
23330
23536
  }
23331
23537
  this.gqlClient = gqlClient;
23332
23538
  if (!this.intervalId) {
23333
- this.startPeriodicScanning(path25);
23334
- this.executeInitialScan(path25);
23335
- void this.executeInitialFullScan(path25);
23539
+ this.startPeriodicScanning(path26);
23540
+ this.executeInitialScan(path26);
23541
+ void this.executeInitialFullScan(path26);
23336
23542
  }
23337
23543
  }
23338
- startPeriodicScanning(path25) {
23544
+ startPeriodicScanning(path26) {
23339
23545
  const scanContext = ScanContext.BACKGROUND_PERIODIC;
23340
23546
  logDebug(
23341
23547
  `[${scanContext}] Starting periodic scan for new security vulnerabilities`,
23342
23548
  {
23343
- path: path25
23549
+ path: path26
23344
23550
  }
23345
23551
  );
23346
23552
  this.intervalId = setInterval(() => {
23347
- logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path25 });
23553
+ logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path26 });
23348
23554
  this.scanForSecurityVulnerabilities({
23349
- path: path25,
23555
+ path: path26,
23350
23556
  scanContext
23351
23557
  }).catch((error) => {
23352
23558
  logError(`[${scanContext}] Error during periodic security scan`, {
@@ -23355,45 +23561,45 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
23355
23561
  });
23356
23562
  }, MCP_PERIODIC_CHECK_INTERVAL);
23357
23563
  }
23358
- async executeInitialFullScan(path25) {
23564
+ async executeInitialFullScan(path26) {
23359
23565
  const scanContext = ScanContext.FULL_SCAN;
23360
- logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path25 });
23566
+ logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path26 });
23361
23567
  logDebug(`[${scanContext}] Full scan paths scanned`, {
23362
23568
  fullScanPathsScanned: this.fullScanPathsScanned
23363
23569
  });
23364
- if (this.fullScanPathsScanned.includes(path25)) {
23570
+ if (this.fullScanPathsScanned.includes(path26)) {
23365
23571
  logDebug(`[${scanContext}] Full scan already executed for this path`, {
23366
- path: path25
23572
+ path: path26
23367
23573
  });
23368
23574
  return;
23369
23575
  }
23370
23576
  configStore.set("fullScanPathsScanned", [
23371
23577
  ...this.fullScanPathsScanned,
23372
- path25
23578
+ path26
23373
23579
  ]);
23374
23580
  try {
23375
23581
  await this.scanForSecurityVulnerabilities({
23376
- path: path25,
23582
+ path: path26,
23377
23583
  isAllFilesScan: true,
23378
23584
  isAllDetectionRulesScan: true,
23379
23585
  scanContext: ScanContext.FULL_SCAN
23380
23586
  });
23381
- if (!this.fullScanPathsScanned.includes(path25)) {
23382
- this.fullScanPathsScanned.push(path25);
23587
+ if (!this.fullScanPathsScanned.includes(path26)) {
23588
+ this.fullScanPathsScanned.push(path26);
23383
23589
  configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
23384
23590
  }
23385
- logInfo(`[${scanContext}] Full scan completed`, { path: path25 });
23591
+ logInfo(`[${scanContext}] Full scan completed`, { path: path26 });
23386
23592
  } catch (error) {
23387
23593
  logError(`[${scanContext}] Error during initial full security scan`, {
23388
23594
  error
23389
23595
  });
23390
23596
  }
23391
23597
  }
23392
- executeInitialScan(path25) {
23598
+ executeInitialScan(path26) {
23393
23599
  const scanContext = ScanContext.BACKGROUND_INITIAL;
23394
- logDebug(`[${scanContext}] Triggering initial security scan`, { path: path25 });
23600
+ logDebug(`[${scanContext}] Triggering initial security scan`, { path: path26 });
23395
23601
  this.scanForSecurityVulnerabilities({
23396
- path: path25,
23602
+ path: path26,
23397
23603
  scanContext: ScanContext.BACKGROUND_INITIAL
23398
23604
  }).catch((error) => {
23399
23605
  logError(`[${scanContext}] Error during initial security scan`, { error });
@@ -23490,9 +23696,9 @@ Example payload:
23490
23696
  `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
23491
23697
  );
23492
23698
  }
23493
- const path25 = pathValidationResult.path;
23699
+ const path26 = pathValidationResult.path;
23494
23700
  const resultText = await this.newFixesService.getFreshFixes({
23495
- path: path25
23701
+ path: path26
23496
23702
  });
23497
23703
  logInfo("CheckForNewAvailableFixesTool execution completed", {
23498
23704
  resultText
@@ -23670,8 +23876,8 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
23670
23876
  `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
23671
23877
  );
23672
23878
  }
23673
- const path25 = pathValidationResult.path;
23674
- const gitService = new GitService(path25, log);
23879
+ const path26 = pathValidationResult.path;
23880
+ const gitService = new GitService(path26, log);
23675
23881
  const gitValidation = await gitService.validateRepository();
23676
23882
  if (!gitValidation.isValid) {
23677
23883
  throw new Error(`Invalid git repository: ${gitValidation.error}`);
@@ -24056,9 +24262,9 @@ Example payload:
24056
24262
  `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
24057
24263
  );
24058
24264
  }
24059
- const path25 = pathValidationResult.path;
24265
+ const path26 = pathValidationResult.path;
24060
24266
  const files = await getLocalFiles({
24061
- path: path25,
24267
+ path: path26,
24062
24268
  maxFileSize: MCP_MAX_FILE_SIZE,
24063
24269
  maxFiles: args.maxFiles,
24064
24270
  scanContext: ScanContext.USER_REQUEST,
@@ -24078,7 +24284,7 @@ Example payload:
24078
24284
  try {
24079
24285
  const fixResult = await this.vulnerabilityFixService.processVulnerabilities({
24080
24286
  fileList: files.map((file) => file.relativePath),
24081
- repositoryPath: path25,
24287
+ repositoryPath: path26,
24082
24288
  offset: args.offset,
24083
24289
  limit: args.limit,
24084
24290
  isRescan: args.rescan || !!args.maxFiles
@@ -24182,33 +24388,33 @@ var mcpHandler = async (_args) => {
24182
24388
  };
24183
24389
 
24184
24390
  // src/args/commands/review.ts
24185
- import fs23 from "fs";
24186
- import chalk11 from "chalk";
24391
+ import fs24 from "fs";
24392
+ import chalk12 from "chalk";
24187
24393
  function reviewBuilder(yargs2) {
24188
24394
  return yargs2.option("f", {
24189
24395
  alias: "scan-file",
24190
24396
  demandOption: true,
24191
24397
  type: "string",
24192
- describe: chalk11.bold(
24398
+ describe: chalk12.bold(
24193
24399
  "Select the vulnerability report to analyze (Checkmarx, Snyk, Fortify, CodeQL, Sonarqube, Semgrep)"
24194
24400
  )
24195
24401
  }).option("repo", { ...repoOption, demandOption: true }).option("scanner", { ...scannerOptions, demandOption: true }).option("ref", { ...refOption, demandOption: true }).option("ch", {
24196
24402
  alias: "commit-hash",
24197
- describe: chalk11.bold("Hash of the commit"),
24403
+ describe: chalk12.bold("Hash of the commit"),
24198
24404
  type: "string",
24199
24405
  demandOption: true
24200
24406
  }).option("mobb-project-name", mobbProjectNameOption).option("api-key", { ...apiKeyOption, demandOption: true }).option("commit-hash", { ...commitHashOption, demandOption: true }).option("github-token", {
24201
- describe: chalk11.bold("Github action token"),
24407
+ describe: chalk12.bold("Github action token"),
24202
24408
  type: "string",
24203
24409
  demandOption: true
24204
24410
  }).option("pull-request", {
24205
24411
  alias: ["pr", "pr-number", "pr-id"],
24206
- describe: chalk11.bold("Number of the pull request"),
24412
+ describe: chalk12.bold("Number of the pull request"),
24207
24413
  type: "number",
24208
24414
  demandOption: true
24209
24415
  }).option("p", {
24210
24416
  alias: "src-path",
24211
- describe: chalk11.bold(
24417
+ describe: chalk12.bold(
24212
24418
  "Path to the repository folder with the source code"
24213
24419
  ),
24214
24420
  type: "string",
@@ -24219,9 +24425,9 @@ function reviewBuilder(yargs2) {
24219
24425
  ).help();
24220
24426
  }
24221
24427
  function validateReviewOptions(argv) {
24222
- if (!fs23.existsSync(argv.f)) {
24428
+ if (!fs24.existsSync(argv.f)) {
24223
24429
  throw new CliError(`
24224
- Can't access ${chalk11.bold(argv.f)}`);
24430
+ Can't access ${chalk12.bold(argv.f)}`);
24225
24431
  }
24226
24432
  validateRepoUrl(argv);
24227
24433
  validateReportFileFormat(argv.f);
@@ -24256,6 +24462,27 @@ async function scanHandler(args) {
24256
24462
  await scan(args, { skipPrompts: args.yes });
24257
24463
  }
24258
24464
 
24465
+ // src/args/commands/scan_skill.ts
24466
+ import chalk13 from "chalk";
24467
+ function scanSkillBuilder(args) {
24468
+ return args.option("url", {
24469
+ demandOption: true,
24470
+ type: "string",
24471
+ describe: chalk13.bold(
24472
+ "URL or local directory of the skill to scan (GitHub repo, ZIP archive, raw SKILL.md, or folder containing SKILL.md)"
24473
+ )
24474
+ }).option("api-key", apiKeyOption).option("ci", ciOption).example(
24475
+ "npx mobbdev@latest scan-skill --url https://github.com/user/my-skill",
24476
+ "Scan an OpenClaw/ClawHub skill for security threats"
24477
+ ).example(
24478
+ "npx mobbdev@latest scan-skill --url ./my-skill-folder",
24479
+ "Scan a local skill directory that contains SKILL.md"
24480
+ ).help();
24481
+ }
24482
+ async function scanSkillHandler(args) {
24483
+ await scanSkill(args);
24484
+ }
24485
+
24259
24486
  // src/args/commands/token.ts
24260
24487
  function addScmTokenBuilder(args) {
24261
24488
  return args.option("scm-type", scmTypeOption).option("url", urlOption).option("token", scmTokenOption).option("organization", scmOrgOption).option("refresh-token", scmRefreshTokenOption).option("api-key", apiKeyOption).option("ci", ciOption).example(
@@ -24297,10 +24524,10 @@ init_client_generates();
24297
24524
  init_urlParser2();
24298
24525
 
24299
24526
  // src/features/codeium_intellij/codeium_language_server_grpc_client.ts
24300
- import path22 from "path";
24527
+ import path23 from "path";
24301
24528
  import * as grpc from "@grpc/grpc-js";
24302
24529
  import * as protoLoader from "@grpc/proto-loader";
24303
- var PROTO_PATH = path22.join(
24530
+ var PROTO_PATH = path23.join(
24304
24531
  getModuleRootDir(),
24305
24532
  "src/features/codeium_intellij/proto/exa/language_server_pb/language_server.proto"
24306
24533
  );
@@ -24312,7 +24539,7 @@ function loadProto() {
24312
24539
  defaults: true,
24313
24540
  oneofs: true,
24314
24541
  includeDirs: [
24315
- path22.join(getModuleRootDir(), "src/features/codeium_intellij/proto")
24542
+ path23.join(getModuleRootDir(), "src/features/codeium_intellij/proto")
24316
24543
  ]
24317
24544
  });
24318
24545
  return grpc.loadPackageDefinition(
@@ -24366,30 +24593,30 @@ async function getGrpcClient(port, csrf3) {
24366
24593
  }
24367
24594
 
24368
24595
  // src/features/codeium_intellij/parse_intellij_logs.ts
24369
- import fs24 from "fs";
24596
+ import fs25 from "fs";
24370
24597
  import os12 from "os";
24371
- import path23 from "path";
24598
+ import path24 from "path";
24372
24599
  function getLogsDir() {
24373
24600
  if (process.platform === "darwin") {
24374
- return path23.join(os12.homedir(), "Library/Logs/JetBrains");
24601
+ return path24.join(os12.homedir(), "Library/Logs/JetBrains");
24375
24602
  } else if (process.platform === "win32") {
24376
- return path23.join(
24377
- process.env["LOCALAPPDATA"] || path23.join(os12.homedir(), "AppData/Local"),
24603
+ return path24.join(
24604
+ process.env["LOCALAPPDATA"] || path24.join(os12.homedir(), "AppData/Local"),
24378
24605
  "JetBrains"
24379
24606
  );
24380
24607
  } else {
24381
- return path23.join(os12.homedir(), ".cache/JetBrains");
24608
+ return path24.join(os12.homedir(), ".cache/JetBrains");
24382
24609
  }
24383
24610
  }
24384
24611
  function parseIdeLogDir(ideLogDir) {
24385
- const logFiles = fs24.readdirSync(ideLogDir).filter((f) => /^idea(\.\d+)?\.log$/.test(f)).map((f) => ({
24612
+ const logFiles = fs25.readdirSync(ideLogDir).filter((f) => /^idea(\.\d+)?\.log$/.test(f)).map((f) => ({
24386
24613
  name: f,
24387
- mtime: fs24.statSync(path23.join(ideLogDir, f)).mtimeMs
24614
+ mtime: fs25.statSync(path24.join(ideLogDir, f)).mtimeMs
24388
24615
  })).sort((a, b) => a.mtime - b.mtime).map((f) => f.name);
24389
24616
  let latestCsrf = null;
24390
24617
  let latestPort = null;
24391
24618
  for (const logFile of logFiles) {
24392
- const lines = fs24.readFileSync(path23.join(ideLogDir, logFile), "utf-8").split("\n");
24619
+ const lines = fs25.readFileSync(path24.join(ideLogDir, logFile), "utf-8").split("\n");
24393
24620
  for (const line of lines) {
24394
24621
  if (!line.includes(
24395
24622
  "com.codeium.intellij.language_server.LanguageServerProcessHandler"
@@ -24415,13 +24642,13 @@ function parseIdeLogDir(ideLogDir) {
24415
24642
  function findRunningCodeiumLanguageServers() {
24416
24643
  const results = [];
24417
24644
  const logsDir = getLogsDir();
24418
- if (!fs24.existsSync(logsDir)) return results;
24419
- for (const ide of fs24.readdirSync(logsDir)) {
24420
- let ideLogDir = path23.join(logsDir, ide);
24645
+ if (!fs25.existsSync(logsDir)) return results;
24646
+ for (const ide of fs25.readdirSync(logsDir)) {
24647
+ let ideLogDir = path24.join(logsDir, ide);
24421
24648
  if (process.platform !== "darwin") {
24422
- ideLogDir = path23.join(ideLogDir, "log");
24649
+ ideLogDir = path24.join(ideLogDir, "log");
24423
24650
  }
24424
- if (!fs24.existsSync(ideLogDir) || !fs24.statSync(ideLogDir).isDirectory()) {
24651
+ if (!fs25.existsSync(ideLogDir) || !fs25.statSync(ideLogDir).isDirectory()) {
24425
24652
  continue;
24426
24653
  }
24427
24654
  const result = parseIdeLogDir(ideLogDir);
@@ -24602,10 +24829,10 @@ function processChatStepCodeAction(step) {
24602
24829
  // src/features/codeium_intellij/install_hook.ts
24603
24830
  import fsPromises6 from "fs/promises";
24604
24831
  import os13 from "os";
24605
- import path24 from "path";
24606
- import chalk12 from "chalk";
24832
+ import path25 from "path";
24833
+ import chalk14 from "chalk";
24607
24834
  function getCodeiumHooksPath() {
24608
- return path24.join(os13.homedir(), ".codeium", "hooks.json");
24835
+ return path25.join(os13.homedir(), ".codeium", "hooks.json");
24609
24836
  }
24610
24837
  async function readCodeiumHooks() {
24611
24838
  const hooksPath = getCodeiumHooksPath();
@@ -24618,7 +24845,7 @@ async function readCodeiumHooks() {
24618
24845
  }
24619
24846
  async function writeCodeiumHooks(config2) {
24620
24847
  const hooksPath = getCodeiumHooksPath();
24621
- const dir = path24.dirname(hooksPath);
24848
+ const dir = path25.dirname(hooksPath);
24622
24849
  await fsPromises6.mkdir(dir, { recursive: true });
24623
24850
  await fsPromises6.writeFile(
24624
24851
  hooksPath,
@@ -24628,7 +24855,7 @@ async function writeCodeiumHooks(config2) {
24628
24855
  }
24629
24856
  async function installWindsurfHooks(options = {}) {
24630
24857
  const hooksPath = getCodeiumHooksPath();
24631
- console.log(chalk12.blue("Installing Mobb hooks in Windsurf IntelliJ..."));
24858
+ console.log(chalk14.blue("Installing Mobb hooks in Windsurf IntelliJ..."));
24632
24859
  const config2 = await readCodeiumHooks();
24633
24860
  if (!config2.hooks) {
24634
24861
  config2.hooks = {};
@@ -24648,7 +24875,7 @@ async function installWindsurfHooks(options = {}) {
24648
24875
  if (envVars.length > 0) {
24649
24876
  command = `${envVars.join(" ")} ${command}`;
24650
24877
  console.log(
24651
- chalk12.blue(
24878
+ chalk14.blue(
24652
24879
  `Adding environment variables to hook command: ${envVars.join(", ")}`
24653
24880
  )
24654
24881
  );
@@ -24662,15 +24889,15 @@ async function installWindsurfHooks(options = {}) {
24662
24889
  (hook) => hook.command?.includes("mobbdev@latest windsurf-intellij-process-hook")
24663
24890
  );
24664
24891
  if (existingHookIndex >= 0) {
24665
- console.log(chalk12.yellow("Mobb hook already exists, updating..."));
24892
+ console.log(chalk14.yellow("Mobb hook already exists, updating..."));
24666
24893
  config2.hooks.post_write_code[existingHookIndex] = mobbHook;
24667
24894
  } else {
24668
- console.log(chalk12.green("Adding new Mobb hook..."));
24895
+ console.log(chalk14.green("Adding new Mobb hook..."));
24669
24896
  config2.hooks.post_write_code.push(mobbHook);
24670
24897
  }
24671
24898
  await writeCodeiumHooks(config2);
24672
24899
  console.log(
24673
- chalk12.green(
24900
+ chalk14.green(
24674
24901
  `\u2705 Mobb hooks ${options.saveEnv ? "and environment variables " : ""}installed successfully in ${hooksPath}`
24675
24902
  )
24676
24903
  );
@@ -24720,81 +24947,86 @@ var windsurfIntellijProcessHookHandler = async () => {
24720
24947
  var parseArgs = async (args) => {
24721
24948
  const yargsInstance = yargs(args);
24722
24949
  return yargsInstance.updateStrings({
24723
- "Commands:": chalk13.yellow.underline.bold("Commands:"),
24724
- "Options:": chalk13.yellow.underline.bold("Options:"),
24725
- "Examples:": chalk13.yellow.underline.bold("Examples:"),
24726
- "Show help": chalk13.bold("Show help")
24950
+ "Commands:": chalk15.yellow.underline.bold("Commands:"),
24951
+ "Options:": chalk15.yellow.underline.bold("Options:"),
24952
+ "Examples:": chalk15.yellow.underline.bold("Examples:"),
24953
+ "Show help": chalk15.bold("Show help")
24727
24954
  }).usage(
24728
- `${chalk13.bold(
24955
+ `${chalk15.bold(
24729
24956
  "\n Bugsy - Trusted, Automatic Vulnerability Fixer \u{1F575}\uFE0F\u200D\u2642\uFE0F\n\n"
24730
- )} ${chalk13.yellow.underline.bold("Usage:")}
24731
- $0 ${chalk13.green(
24957
+ )} ${chalk15.yellow.underline.bold("Usage:")}
24958
+ $0 ${chalk15.green(
24732
24959
  "<command>"
24733
- )} ${chalk13.dim("[options]")}
24960
+ )} ${chalk15.dim("[options]")}
24734
24961
  `
24735
24962
  ).version(false).command(
24736
24963
  mobbCliCommand.scan,
24737
- chalk13.bold(
24964
+ chalk15.bold(
24738
24965
  "Scan your code for vulnerabilities, get automated fixes right away."
24739
24966
  ),
24740
24967
  scanBuilder,
24741
24968
  scanHandler
24742
24969
  ).command(
24743
24970
  mobbCliCommand.analyze,
24744
- chalk13.bold(
24971
+ chalk15.bold(
24745
24972
  "Provide a code repository, get automated fixes right away. You can also provide a vulnerability report to analyze or have Mobb scan the code for you."
24746
24973
  ),
24747
24974
  analyzeBuilder,
24748
24975
  analyzeHandler
24749
24976
  ).command(
24750
24977
  mobbCliCommand.review,
24751
- chalk13.bold(
24978
+ chalk15.bold(
24752
24979
  "Mobb will review your github pull requests and provide comments with fixes "
24753
24980
  ),
24754
24981
  reviewBuilder,
24755
24982
  reviewHandler
24756
24983
  ).command(
24757
24984
  mobbCliCommand.addScmToken,
24758
- chalk13.bold(
24985
+ chalk15.bold(
24759
24986
  "Add your SCM (Github, Gitlab, Azure DevOps) token to Mobb to enable automated fixes."
24760
24987
  ),
24761
24988
  addScmTokenBuilder,
24762
24989
  addScmTokenHandler
24990
+ ).command(
24991
+ mobbCliCommand.scanSkill,
24992
+ chalk15.bold("Scan an OpenClaw/ClawHub skill for security threats."),
24993
+ scanSkillBuilder,
24994
+ scanSkillHandler
24763
24995
  ).command(
24764
24996
  mobbCliCommand.convertToSarif,
24765
- chalk13.bold("Convert an existing SAST report to SARIF format."),
24997
+ chalk15.bold("Convert an existing SAST report to SARIF format."),
24766
24998
  convertToSarifBuilder,
24767
24999
  convertToSarifHandler
24768
25000
  ).command(
24769
25001
  mobbCliCommand.mcp,
24770
- chalk13.bold("Launch the MCP (Model Context Protocol) server."),
25002
+ chalk15.bold("Launch the MCP (Model Context Protocol) server."),
24771
25003
  mcpBuilder,
24772
25004
  mcpHandler
24773
25005
  ).command(
24774
25006
  mobbCliCommand.uploadAiBlame,
24775
- chalk13.bold(
25007
+ chalk15.bold(
24776
25008
  "Upload AI Blame inference artifacts (prompt + inference) and finalize them."
24777
25009
  ),
24778
25010
  uploadAiBlameBuilder,
24779
25011
  uploadAiBlameCommandHandler
24780
25012
  ).command(
24781
25013
  mobbCliCommand.claudeCodeInstallHook,
24782
- chalk13.bold("Install Claude Code hooks for data collection."),
25014
+ chalk15.bold("Install Claude Code hooks for data collection."),
24783
25015
  claudeCodeInstallHookBuilder,
24784
25016
  claudeCodeInstallHookHandler
24785
25017
  ).command(
24786
25018
  mobbCliCommand.claudeCodeProcessHook,
24787
- chalk13.bold("Process Claude Code hook data and upload to backend."),
25019
+ chalk15.bold("Process Claude Code hook data and upload to backend."),
24788
25020
  claudeCodeProcessHookBuilder,
24789
25021
  claudeCodeProcessHookHandler
24790
25022
  ).command(
24791
25023
  mobbCliCommand.windsurfIntellijInstallHook,
24792
- chalk13.bold("Install Windsurf IntelliJ hooks for data collection."),
25024
+ chalk15.bold("Install Windsurf IntelliJ hooks for data collection."),
24793
25025
  windsurfIntellijInstallHookBuilder,
24794
25026
  windsurfIntellijInstallHookHandler
24795
25027
  ).command(
24796
25028
  mobbCliCommand.windsurfIntellijProcessHook,
24797
- chalk13.bold("Process Windsurf IntelliJ hook data and upload to backend."),
25029
+ chalk15.bold("Process Windsurf IntelliJ hook data and upload to backend."),
24798
25030
  windsurfIntellijProcessHookBuilder,
24799
25031
  windsurfIntellijProcessHookHandler
24800
25032
  ).example(
@@ -24805,7 +25037,7 @@ var parseArgs = async (args) => {
24805
25037
  handler() {
24806
25038
  yargsInstance.showHelp();
24807
25039
  }
24808
- }).strictOptions().help("h").alias("h", "help").epilog(chalk13.bgBlue("Made with \u2764\uFE0F by Mobb")).showHelpOnFail(true).wrap(Math.min(120, yargsInstance.terminalWidth())).parse();
25040
+ }).strictOptions().help("h").alias("h", "help").epilog(chalk15.bgBlue("Made with \u2764\uFE0F by Mobb")).showHelpOnFail(true).wrap(Math.min(120, yargsInstance.terminalWidth())).parse();
24809
25041
  };
24810
25042
 
24811
25043
  // src/index.ts