mobbdev 1.2.19 → 1.2.22
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/args/commands/upload_ai_blame.mjs +35 -3
- package/dist/index.mjs +489 -261
- package/package.json +1 -1
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";
|
|
@@ -1197,6 +1200,32 @@ var init_client_generates = __esm({
|
|
|
1197
1200
|
completedOn
|
|
1198
1201
|
error
|
|
1199
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
|
+
}
|
|
1200
1229
|
}
|
|
1201
1230
|
`;
|
|
1202
1231
|
defaultWrapper = (action, _operationName, _operationType, _variables) => action();
|
|
@@ -3804,7 +3833,7 @@ ${rootContent}`;
|
|
|
3804
3833
|
}
|
|
3805
3834
|
}
|
|
3806
3835
|
/**
|
|
3807
|
-
* Gets local commit data including diff
|
|
3836
|
+
* Gets local commit data including diff and timestamp.
|
|
3808
3837
|
* Used by Tracy extension to send commit data directly without requiring SCM token.
|
|
3809
3838
|
* @param commitSha The commit SHA to get data for
|
|
3810
3839
|
* @param maxDiffSizeBytes Maximum diff size in bytes (default 3MB). Returns null if exceeded.
|
|
@@ -3816,7 +3845,7 @@ ${rootContent}`;
|
|
|
3816
3845
|
const DIFF_DELIMITER = "---MOBB_DIFF_START---";
|
|
3817
3846
|
const output = await this.git.show([
|
|
3818
3847
|
commitSha,
|
|
3819
|
-
`--format=%cI%n
|
|
3848
|
+
`--format=%cI%n${DIFF_DELIMITER}`,
|
|
3820
3849
|
"--patch"
|
|
3821
3850
|
]);
|
|
3822
3851
|
const delimiterIndex = output.indexOf(DIFF_DELIMITER);
|
|
@@ -3871,7 +3900,7 @@ import Debug19 from "debug";
|
|
|
3871
3900
|
import { hideBin } from "yargs/helpers";
|
|
3872
3901
|
|
|
3873
3902
|
// src/args/yargs.ts
|
|
3874
|
-
import
|
|
3903
|
+
import chalk15 from "chalk";
|
|
3875
3904
|
import yargs from "yargs/yargs";
|
|
3876
3905
|
|
|
3877
3906
|
// src/args/commands/convert_to_sarif.ts
|
|
@@ -6767,7 +6796,7 @@ async function getAdoSdk(params) {
|
|
|
6767
6796
|
const url = new URL(repoUrl);
|
|
6768
6797
|
const origin2 = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
|
|
6769
6798
|
const params2 = `path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
|
|
6770
|
-
const
|
|
6799
|
+
const path26 = [
|
|
6771
6800
|
prefixPath,
|
|
6772
6801
|
owner,
|
|
6773
6802
|
projectName,
|
|
@@ -6778,7 +6807,7 @@ async function getAdoSdk(params) {
|
|
|
6778
6807
|
"items",
|
|
6779
6808
|
"items"
|
|
6780
6809
|
].filter(Boolean).join("/");
|
|
6781
|
-
return new URL(`${
|
|
6810
|
+
return new URL(`${path26}?${params2}`, origin2).toString();
|
|
6782
6811
|
},
|
|
6783
6812
|
async getAdoBranchList({ repoUrl }) {
|
|
6784
6813
|
try {
|
|
@@ -8322,7 +8351,7 @@ function getGithubSdk(params = {}) {
|
|
|
8322
8351
|
if (res.status === 204) {
|
|
8323
8352
|
return true;
|
|
8324
8353
|
}
|
|
8325
|
-
} catch (
|
|
8354
|
+
} catch (_collaboratorError) {
|
|
8326
8355
|
try {
|
|
8327
8356
|
const permissionRes = await octokit.rest.repos.getCollaboratorPermissionLevel({
|
|
8328
8357
|
owner,
|
|
@@ -8332,16 +8361,16 @@ function getGithubSdk(params = {}) {
|
|
|
8332
8361
|
if (permissionRes.data.permission !== "none") {
|
|
8333
8362
|
return true;
|
|
8334
8363
|
}
|
|
8335
|
-
} catch (
|
|
8364
|
+
} catch (_permissionError) {
|
|
8336
8365
|
try {
|
|
8337
8366
|
await octokit.rest.repos.get({ owner, repo });
|
|
8338
8367
|
return true;
|
|
8339
|
-
} catch (
|
|
8368
|
+
} catch (_repoError) {
|
|
8340
8369
|
return false;
|
|
8341
8370
|
}
|
|
8342
8371
|
}
|
|
8343
8372
|
}
|
|
8344
|
-
} catch (
|
|
8373
|
+
} catch (_e) {
|
|
8345
8374
|
return false;
|
|
8346
8375
|
}
|
|
8347
8376
|
return false;
|
|
@@ -8382,7 +8411,7 @@ function getGithubSdk(params = {}) {
|
|
|
8382
8411
|
branch
|
|
8383
8412
|
});
|
|
8384
8413
|
return branch === res.data.name;
|
|
8385
|
-
} catch (
|
|
8414
|
+
} catch (_e) {
|
|
8386
8415
|
return false;
|
|
8387
8416
|
}
|
|
8388
8417
|
},
|
|
@@ -8577,7 +8606,7 @@ function getGithubSdk(params = {}) {
|
|
|
8577
8606
|
const sourceFileContentResponse = await octokit.rest.repos.getContent({
|
|
8578
8607
|
owner: sourceOwner,
|
|
8579
8608
|
repo: sourceRepo,
|
|
8580
|
-
path:
|
|
8609
|
+
path: `/${sourceFilePath}`
|
|
8581
8610
|
});
|
|
8582
8611
|
const { data: repository } = await octokit.rest.repos.get({ owner, repo });
|
|
8583
8612
|
const defaultBranch = repository.default_branch;
|
|
@@ -8605,7 +8634,7 @@ function getGithubSdk(params = {}) {
|
|
|
8605
8634
|
const secondFileContentResponse = await octokit.rest.repos.getContent({
|
|
8606
8635
|
owner: sourceOwner,
|
|
8607
8636
|
repo: sourceRepo,
|
|
8608
|
-
path:
|
|
8637
|
+
path: `/${secondFilePath}`
|
|
8609
8638
|
});
|
|
8610
8639
|
const secondDecodedContent = Buffer.from(
|
|
8611
8640
|
// Check if file content exists and handle different response types
|
|
@@ -10373,6 +10402,7 @@ async function getGitlabMergeRequestDiff({
|
|
|
10373
10402
|
title: mr.title,
|
|
10374
10403
|
description: mr.description || void 0,
|
|
10375
10404
|
commits,
|
|
10405
|
+
headCommitSha: mr.sha,
|
|
10376
10406
|
diffLines
|
|
10377
10407
|
};
|
|
10378
10408
|
}
|
|
@@ -11745,7 +11775,8 @@ var mobbCliCommand = {
|
|
|
11745
11775
|
claudeCodeInstallHook: "claude-code-install-hook",
|
|
11746
11776
|
claudeCodeProcessHook: "claude-code-process-hook",
|
|
11747
11777
|
windsurfIntellijInstallHook: "windsurf-intellij-install-hook",
|
|
11748
|
-
windsurfIntellijProcessHook: "windsurf-intellij-process-hook"
|
|
11778
|
+
windsurfIntellijProcessHook: "windsurf-intellij-process-hook",
|
|
11779
|
+
scanSkill: "scan-skill"
|
|
11749
11780
|
};
|
|
11750
11781
|
var ScanContext = {
|
|
11751
11782
|
FULL_SCAN: "FULL_SCAN",
|
|
@@ -11756,10 +11787,11 @@ var ScanContext = {
|
|
|
11756
11787
|
};
|
|
11757
11788
|
|
|
11758
11789
|
// src/args/commands/analyze.ts
|
|
11759
|
-
import
|
|
11760
|
-
import
|
|
11790
|
+
import fs12 from "fs";
|
|
11791
|
+
import chalk9 from "chalk";
|
|
11761
11792
|
|
|
11762
11793
|
// src/commands/index.ts
|
|
11794
|
+
import chalk7 from "chalk";
|
|
11763
11795
|
import chalkAnimation from "chalk-animation";
|
|
11764
11796
|
|
|
11765
11797
|
// src/features/analysis/index.ts
|
|
@@ -12545,6 +12577,9 @@ var GQLClient = class {
|
|
|
12545
12577
|
async getTracyDiffUploadUrl(variables) {
|
|
12546
12578
|
return await this._clientSdk.GetTracyDiffUploadUrl(variables);
|
|
12547
12579
|
}
|
|
12580
|
+
async scanSkill(variables) {
|
|
12581
|
+
return await this._clientSdk.ScanSkill(variables);
|
|
12582
|
+
}
|
|
12548
12583
|
};
|
|
12549
12584
|
|
|
12550
12585
|
// src/mcp/services/types.ts
|
|
@@ -13150,7 +13185,7 @@ async function postIssueComment(params) {
|
|
|
13150
13185
|
fpDescription
|
|
13151
13186
|
} = params;
|
|
13152
13187
|
const {
|
|
13153
|
-
path:
|
|
13188
|
+
path: path26,
|
|
13154
13189
|
startLine,
|
|
13155
13190
|
vulnerabilityReportIssue: {
|
|
13156
13191
|
vulnerabilityReportIssueTags,
|
|
@@ -13165,7 +13200,7 @@ async function postIssueComment(params) {
|
|
|
13165
13200
|
Refresh the page in order to see the changes.`,
|
|
13166
13201
|
pull_number: pullRequest,
|
|
13167
13202
|
commit_id: commitSha,
|
|
13168
|
-
path:
|
|
13203
|
+
path: path26,
|
|
13169
13204
|
line: startLine
|
|
13170
13205
|
});
|
|
13171
13206
|
const commentId = commentRes.data.id;
|
|
@@ -13199,7 +13234,7 @@ async function postFixComment(params) {
|
|
|
13199
13234
|
scanner
|
|
13200
13235
|
} = params;
|
|
13201
13236
|
const {
|
|
13202
|
-
path:
|
|
13237
|
+
path: path26,
|
|
13203
13238
|
startLine,
|
|
13204
13239
|
vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
|
|
13205
13240
|
vulnerabilityReportIssueId
|
|
@@ -13217,7 +13252,7 @@ async function postFixComment(params) {
|
|
|
13217
13252
|
Refresh the page in order to see the changes.`,
|
|
13218
13253
|
pull_number: pullRequest,
|
|
13219
13254
|
commit_id: commitSha,
|
|
13220
|
-
path:
|
|
13255
|
+
path: path26,
|
|
13221
13256
|
line: startLine
|
|
13222
13257
|
});
|
|
13223
13258
|
const commentId = commentRes.data.id;
|
|
@@ -14780,6 +14815,85 @@ async function waitForAnaysisAndReviewPr({
|
|
|
14780
14815
|
}
|
|
14781
14816
|
}
|
|
14782
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
|
+
|
|
14783
14897
|
// src/commands/index.ts
|
|
14784
14898
|
async function review(params, { skipPrompts = true } = {}) {
|
|
14785
14899
|
const {
|
|
@@ -14905,10 +15019,80 @@ async function showWelcomeMessage(skipPrompts = false) {
|
|
|
14905
15019
|
skipPrompts ? await sleep(100) : await sleep(2e3);
|
|
14906
15020
|
welcome.stop();
|
|
14907
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
|
+
}
|
|
14908
15092
|
|
|
14909
15093
|
// src/args/validation.ts
|
|
14910
|
-
import
|
|
14911
|
-
import
|
|
15094
|
+
import chalk8 from "chalk";
|
|
15095
|
+
import path11 from "path";
|
|
14912
15096
|
import { z as z30 } from "zod";
|
|
14913
15097
|
function throwRepoUrlErrorMessage({
|
|
14914
15098
|
error,
|
|
@@ -14917,11 +15101,11 @@ function throwRepoUrlErrorMessage({
|
|
|
14917
15101
|
}) {
|
|
14918
15102
|
const errorMessage = error.issues[error.issues.length - 1]?.message;
|
|
14919
15103
|
const formattedErrorMessage = `
|
|
14920
|
-
Error: ${
|
|
15104
|
+
Error: ${chalk8.bold(
|
|
14921
15105
|
repoUrl
|
|
14922
15106
|
)} is ${errorMessage}
|
|
14923
15107
|
Example:
|
|
14924
|
-
mobbdev ${command} -r ${
|
|
15108
|
+
mobbdev ${command} -r ${chalk8.bold(
|
|
14925
15109
|
"https://github.com/WebGoat/WebGoat"
|
|
14926
15110
|
)}`;
|
|
14927
15111
|
throw new CliError(formattedErrorMessage);
|
|
@@ -14952,12 +15136,12 @@ function validateRepoUrl(args) {
|
|
|
14952
15136
|
}
|
|
14953
15137
|
var supportExtensions = [".json", ".xml", ".fpr", ".sarif", ".zip"];
|
|
14954
15138
|
function validateReportFileFormat(reportFile) {
|
|
14955
|
-
if (!supportExtensions.includes(
|
|
15139
|
+
if (!supportExtensions.includes(path11.extname(reportFile))) {
|
|
14956
15140
|
throw new CliError(
|
|
14957
15141
|
`
|
|
14958
|
-
${
|
|
15142
|
+
${chalk8.bold(
|
|
14959
15143
|
reportFile
|
|
14960
|
-
)} is not a supported file extension. Supported extensions are: ${
|
|
15144
|
+
)} is not a supported file extension. Supported extensions are: ${chalk8.bold(
|
|
14961
15145
|
supportExtensions.join(", ")
|
|
14962
15146
|
)}
|
|
14963
15147
|
`
|
|
@@ -14970,22 +15154,22 @@ function analyzeBuilder(yargs2) {
|
|
|
14970
15154
|
return yargs2.option("f", {
|
|
14971
15155
|
alias: "scan-file",
|
|
14972
15156
|
type: "string",
|
|
14973
|
-
describe:
|
|
15157
|
+
describe: chalk9.bold(
|
|
14974
15158
|
"Select the vulnerability report to analyze (Checkmarx, Snyk, Fortify, CodeQL, Sonarqube, Semgrep, Datadog)"
|
|
14975
15159
|
)
|
|
14976
15160
|
}).option("repo", repoOption).option("p", {
|
|
14977
15161
|
alias: "src-path",
|
|
14978
|
-
describe:
|
|
15162
|
+
describe: chalk9.bold(
|
|
14979
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"
|
|
14980
15164
|
),
|
|
14981
15165
|
type: "string"
|
|
14982
15166
|
}).option("ref", refOption).option("ch", {
|
|
14983
15167
|
alias: "commit-hash",
|
|
14984
|
-
describe:
|
|
15168
|
+
describe: chalk9.bold("Hash of the commit"),
|
|
14985
15169
|
type: "string"
|
|
14986
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", {
|
|
14987
15171
|
alias: ["pr", "pr-number", "pr-id"],
|
|
14988
|
-
describe:
|
|
15172
|
+
describe: chalk9.bold("Number of the pull request"),
|
|
14989
15173
|
type: "number",
|
|
14990
15174
|
demandOption: false
|
|
14991
15175
|
}).option("polling", pollingOption).example(
|
|
@@ -14994,9 +15178,9 @@ function analyzeBuilder(yargs2) {
|
|
|
14994
15178
|
).help();
|
|
14995
15179
|
}
|
|
14996
15180
|
function validateAnalyzeOptions(argv) {
|
|
14997
|
-
if (argv.f && !
|
|
15181
|
+
if (argv.f && !fs12.existsSync(argv.f)) {
|
|
14998
15182
|
throw new CliError(`
|
|
14999
|
-
Can't access ${
|
|
15183
|
+
Can't access ${chalk9.bold(argv.f)}`);
|
|
15000
15184
|
}
|
|
15001
15185
|
validateOrganizationId(argv.organizationId);
|
|
15002
15186
|
if (!argv.srcPath && !argv.repo) {
|
|
@@ -15043,8 +15227,8 @@ import { z as z32 } from "zod";
|
|
|
15043
15227
|
// src/args/commands/upload_ai_blame.ts
|
|
15044
15228
|
import fsPromises3 from "fs/promises";
|
|
15045
15229
|
import * as os3 from "os";
|
|
15046
|
-
import
|
|
15047
|
-
import
|
|
15230
|
+
import path12 from "path";
|
|
15231
|
+
import chalk10 from "chalk";
|
|
15048
15232
|
import { withFile } from "tmp-promise";
|
|
15049
15233
|
import z31 from "zod";
|
|
15050
15234
|
init_client_generates();
|
|
@@ -15364,33 +15548,33 @@ function uploadAiBlameBuilder(args) {
|
|
|
15364
15548
|
type: "string",
|
|
15365
15549
|
array: true,
|
|
15366
15550
|
demandOption: true,
|
|
15367
|
-
describe:
|
|
15551
|
+
describe: chalk10.bold("Path(s) to prompt artifact(s) (one per session)")
|
|
15368
15552
|
}).option("inference", {
|
|
15369
15553
|
type: "string",
|
|
15370
15554
|
array: true,
|
|
15371
15555
|
demandOption: true,
|
|
15372
|
-
describe:
|
|
15556
|
+
describe: chalk10.bold(
|
|
15373
15557
|
"Path(s) to inference artifact(s) (one per session)"
|
|
15374
15558
|
)
|
|
15375
15559
|
}).option("ai-response-at", {
|
|
15376
15560
|
type: "string",
|
|
15377
15561
|
array: true,
|
|
15378
|
-
describe:
|
|
15562
|
+
describe: chalk10.bold(
|
|
15379
15563
|
"ISO timestamp(s) for AI response (one per session, defaults to now)"
|
|
15380
15564
|
)
|
|
15381
15565
|
}).option("model", {
|
|
15382
15566
|
type: "string",
|
|
15383
15567
|
array: true,
|
|
15384
|
-
describe:
|
|
15568
|
+
describe: chalk10.bold("AI model name(s) (optional, one per session)")
|
|
15385
15569
|
}).option("tool-name", {
|
|
15386
15570
|
type: "string",
|
|
15387
15571
|
array: true,
|
|
15388
|
-
describe:
|
|
15572
|
+
describe: chalk10.bold("Tool/IDE name(s) (optional, one per session)")
|
|
15389
15573
|
}).option("blame-type", {
|
|
15390
15574
|
type: "string",
|
|
15391
15575
|
array: true,
|
|
15392
15576
|
choices: Object.values(AiBlameInferenceType),
|
|
15393
|
-
describe:
|
|
15577
|
+
describe: chalk10.bold(
|
|
15394
15578
|
"Blame type(s) (optional, one per session, defaults to CHAT)"
|
|
15395
15579
|
)
|
|
15396
15580
|
}).strict();
|
|
@@ -15412,7 +15596,7 @@ async function uploadAiBlameHandlerFromExtension(args) {
|
|
|
15412
15596
|
await withFile(async (promptFile) => {
|
|
15413
15597
|
const promptsResult = await sanitizeDataWithCounts(args.prompts);
|
|
15414
15598
|
promptsCounts = promptsResult.counts;
|
|
15415
|
-
promptsUUID =
|
|
15599
|
+
promptsUUID = path12.basename(promptFile.path, path12.extname(promptFile.path));
|
|
15416
15600
|
await fsPromises3.writeFile(
|
|
15417
15601
|
promptFile.path,
|
|
15418
15602
|
JSON.stringify(promptsResult.sanitizedData, null, 2),
|
|
@@ -15422,9 +15606,9 @@ async function uploadAiBlameHandlerFromExtension(args) {
|
|
|
15422
15606
|
await withFile(async (inferenceFile) => {
|
|
15423
15607
|
const inferenceResult = await sanitizeDataWithCounts(args.inference);
|
|
15424
15608
|
inferenceCounts = inferenceResult.counts;
|
|
15425
|
-
inferenceUUID =
|
|
15609
|
+
inferenceUUID = path12.basename(
|
|
15426
15610
|
inferenceFile.path,
|
|
15427
|
-
|
|
15611
|
+
path12.extname(inferenceFile.path)
|
|
15428
15612
|
);
|
|
15429
15613
|
await fsPromises3.writeFile(
|
|
15430
15614
|
inferenceFile.path,
|
|
@@ -15472,7 +15656,7 @@ async function uploadAiBlameHandler(options) {
|
|
|
15472
15656
|
const sessionIds = args.sessionId || args["session-id"] || [];
|
|
15473
15657
|
if (prompts.length !== inferences.length) {
|
|
15474
15658
|
const errorMsg = "prompt and inference must have the same number of entries";
|
|
15475
|
-
logger2.error(
|
|
15659
|
+
logger2.error(chalk10.red(errorMsg));
|
|
15476
15660
|
if (exitOnError) {
|
|
15477
15661
|
process.exit(1);
|
|
15478
15662
|
}
|
|
@@ -15492,15 +15676,15 @@ async function uploadAiBlameHandler(options) {
|
|
|
15492
15676
|
]);
|
|
15493
15677
|
} catch {
|
|
15494
15678
|
const errorMsg = `File not found for session ${i + 1}`;
|
|
15495
|
-
logger2.error(
|
|
15679
|
+
logger2.error(chalk10.red(errorMsg));
|
|
15496
15680
|
if (exitOnError) {
|
|
15497
15681
|
process.exit(1);
|
|
15498
15682
|
}
|
|
15499
15683
|
throw new Error(errorMsg);
|
|
15500
15684
|
}
|
|
15501
15685
|
sessions.push({
|
|
15502
|
-
promptFileName:
|
|
15503
|
-
inferenceFileName:
|
|
15686
|
+
promptFileName: path12.basename(promptPath),
|
|
15687
|
+
inferenceFileName: path12.basename(inferencePath),
|
|
15504
15688
|
aiResponseAt: responseTimes[i] || nowIso,
|
|
15505
15689
|
model: models[i],
|
|
15506
15690
|
toolName: tools[i],
|
|
@@ -15525,7 +15709,7 @@ async function uploadAiBlameHandler(options) {
|
|
|
15525
15709
|
const uploadSessions = initRes.uploadAIBlameInferencesInit?.uploadSessions ?? [];
|
|
15526
15710
|
if (uploadSessions.length !== sessions.length) {
|
|
15527
15711
|
const errorMsg = "Init failed to return expected number of sessions";
|
|
15528
|
-
logger2.error(
|
|
15712
|
+
logger2.error(chalk10.red(errorMsg));
|
|
15529
15713
|
if (exitOnError) {
|
|
15530
15714
|
process.exit(1);
|
|
15531
15715
|
}
|
|
@@ -15582,7 +15766,7 @@ async function uploadAiBlameHandler(options) {
|
|
|
15582
15766
|
if (status !== "OK") {
|
|
15583
15767
|
const errorMsg = finRes?.finalizeAIBlameInferencesUpload?.error || "unknown error";
|
|
15584
15768
|
logger2.error(
|
|
15585
|
-
|
|
15769
|
+
chalk10.red(
|
|
15586
15770
|
`[UPLOAD] Finalize failed with status: ${status}, error: ${errorMsg}`
|
|
15587
15771
|
)
|
|
15588
15772
|
);
|
|
@@ -15591,7 +15775,7 @@ async function uploadAiBlameHandler(options) {
|
|
|
15591
15775
|
}
|
|
15592
15776
|
throw new Error(errorMsg);
|
|
15593
15777
|
}
|
|
15594
|
-
logger2.info(
|
|
15778
|
+
logger2.info(chalk10.green("[UPLOAD] AI Blame uploads finalized successfully"));
|
|
15595
15779
|
} catch (error) {
|
|
15596
15780
|
logger2.error("[UPLOAD] Finalize threw error:", error);
|
|
15597
15781
|
throw error;
|
|
@@ -15603,6 +15787,8 @@ async function uploadAiBlameCommandHandler(args) {
|
|
|
15603
15787
|
|
|
15604
15788
|
// src/features/claude_code/data_collector.ts
|
|
15605
15789
|
init_client_generates();
|
|
15790
|
+
init_GitService();
|
|
15791
|
+
init_urlParser2();
|
|
15606
15792
|
|
|
15607
15793
|
// src/features/claude_code/transcript_parser.ts
|
|
15608
15794
|
import fsPromises4 from "fs/promises";
|
|
@@ -15849,8 +16035,23 @@ async function collectHookData() {
|
|
|
15849
16035
|
tracePayload
|
|
15850
16036
|
};
|
|
15851
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
|
+
}
|
|
15852
16052
|
async function processAndUploadHookData() {
|
|
15853
16053
|
const result = await collectHookData();
|
|
16054
|
+
const repositoryUrl = await getRepositoryUrl2(result.hookData.cwd);
|
|
15854
16055
|
let uploadSuccess;
|
|
15855
16056
|
try {
|
|
15856
16057
|
await uploadAiBlameHandlerFromExtension({
|
|
@@ -15860,7 +16061,8 @@ async function processAndUploadHookData() {
|
|
|
15860
16061
|
tool: result.tracePayload.tool,
|
|
15861
16062
|
responseTime: result.tracePayload.responseTime,
|
|
15862
16063
|
blameType: "CHAT" /* Chat */,
|
|
15863
|
-
sessionId: result.hookData.session_id
|
|
16064
|
+
sessionId: result.hookData.session_id,
|
|
16065
|
+
repositoryUrl
|
|
15864
16066
|
});
|
|
15865
16067
|
uploadSuccess = true;
|
|
15866
16068
|
} catch (error) {
|
|
@@ -15879,9 +16081,9 @@ async function processAndUploadHookData() {
|
|
|
15879
16081
|
// src/features/claude_code/install_hook.ts
|
|
15880
16082
|
import fsPromises5 from "fs/promises";
|
|
15881
16083
|
import os4 from "os";
|
|
15882
|
-
import
|
|
15883
|
-
import
|
|
15884
|
-
var CLAUDE_SETTINGS_PATH =
|
|
16084
|
+
import path13 from "path";
|
|
16085
|
+
import chalk11 from "chalk";
|
|
16086
|
+
var CLAUDE_SETTINGS_PATH = path13.join(os4.homedir(), ".claude", "settings.json");
|
|
15885
16087
|
async function claudeSettingsExists() {
|
|
15886
16088
|
try {
|
|
15887
16089
|
await fsPromises5.access(CLAUDE_SETTINGS_PATH);
|
|
@@ -15905,12 +16107,12 @@ async function writeClaudeSettings(settings) {
|
|
|
15905
16107
|
);
|
|
15906
16108
|
}
|
|
15907
16109
|
async function installMobbHooks(options = {}) {
|
|
15908
|
-
console.log(
|
|
16110
|
+
console.log(chalk11.blue("Installing Mobb hooks in Claude Code settings..."));
|
|
15909
16111
|
if (!await claudeSettingsExists()) {
|
|
15910
|
-
console.log(
|
|
15911
|
-
console.log(
|
|
15912
|
-
console.log(
|
|
15913
|
-
console.log(
|
|
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."));
|
|
15914
16116
|
throw new Error(
|
|
15915
16117
|
"Claude Code settings file not found. Is Claude Code installed?"
|
|
15916
16118
|
);
|
|
@@ -15934,7 +16136,7 @@ async function installMobbHooks(options = {}) {
|
|
|
15934
16136
|
if (envVars.length > 0) {
|
|
15935
16137
|
command = `${envVars.join(" ")} ${command}`;
|
|
15936
16138
|
console.log(
|
|
15937
|
-
|
|
16139
|
+
chalk11.blue(
|
|
15938
16140
|
`Adding environment variables to hook command: ${envVars.join(", ")}`
|
|
15939
16141
|
)
|
|
15940
16142
|
);
|
|
@@ -15955,15 +16157,15 @@ async function installMobbHooks(options = {}) {
|
|
|
15955
16157
|
)
|
|
15956
16158
|
);
|
|
15957
16159
|
if (existingHookIndex >= 0) {
|
|
15958
|
-
console.log(
|
|
16160
|
+
console.log(chalk11.yellow("Mobb hook already exists, updating..."));
|
|
15959
16161
|
settings.hooks.PostToolUse[existingHookIndex] = mobbHookConfig;
|
|
15960
16162
|
} else {
|
|
15961
|
-
console.log(
|
|
16163
|
+
console.log(chalk11.green("Adding new Mobb hook..."));
|
|
15962
16164
|
settings.hooks.PostToolUse.push(mobbHookConfig);
|
|
15963
16165
|
}
|
|
15964
16166
|
await writeClaudeSettings(settings);
|
|
15965
16167
|
console.log(
|
|
15966
|
-
|
|
16168
|
+
chalk11.green(
|
|
15967
16169
|
`\u2705 Mobb hooks ${options.saveEnv ? "and environment variables " : ""}installed successfully in ${CLAUDE_SETTINGS_PATH}`
|
|
15968
16170
|
)
|
|
15969
16171
|
);
|
|
@@ -16066,8 +16268,8 @@ var WorkspaceService = class {
|
|
|
16066
16268
|
* Sets a known workspace path that was discovered through successful validation
|
|
16067
16269
|
* @param path The validated workspace path to store
|
|
16068
16270
|
*/
|
|
16069
|
-
static setKnownWorkspacePath(
|
|
16070
|
-
this.knownWorkspacePath =
|
|
16271
|
+
static setKnownWorkspacePath(path26) {
|
|
16272
|
+
this.knownWorkspacePath = path26;
|
|
16071
16273
|
}
|
|
16072
16274
|
/**
|
|
16073
16275
|
* Gets the known workspace path that was previously validated
|
|
@@ -17097,9 +17299,9 @@ async function createAuthenticatedMcpGQLClient({
|
|
|
17097
17299
|
|
|
17098
17300
|
// src/mcp/services/McpUsageService/host.ts
|
|
17099
17301
|
import { execSync as execSync2 } from "child_process";
|
|
17100
|
-
import
|
|
17302
|
+
import fs13 from "fs";
|
|
17101
17303
|
import os6 from "os";
|
|
17102
|
-
import
|
|
17304
|
+
import path14 from "path";
|
|
17103
17305
|
var IDEs = ["cursor", "windsurf", "webstorm", "vscode", "claude"];
|
|
17104
17306
|
var runCommand = (cmd) => {
|
|
17105
17307
|
try {
|
|
@@ -17114,17 +17316,17 @@ var gitInfo = {
|
|
|
17114
17316
|
};
|
|
17115
17317
|
var getClaudeWorkspacePaths = () => {
|
|
17116
17318
|
const home = os6.homedir();
|
|
17117
|
-
const claudeIdePath =
|
|
17319
|
+
const claudeIdePath = path14.join(home, ".claude", "ide");
|
|
17118
17320
|
const workspacePaths = [];
|
|
17119
|
-
if (!
|
|
17321
|
+
if (!fs13.existsSync(claudeIdePath)) {
|
|
17120
17322
|
return workspacePaths;
|
|
17121
17323
|
}
|
|
17122
17324
|
try {
|
|
17123
|
-
const lockFiles =
|
|
17325
|
+
const lockFiles = fs13.readdirSync(claudeIdePath).filter((file) => file.endsWith(".lock"));
|
|
17124
17326
|
for (const lockFile of lockFiles) {
|
|
17125
|
-
const lockFilePath =
|
|
17327
|
+
const lockFilePath = path14.join(claudeIdePath, lockFile);
|
|
17126
17328
|
try {
|
|
17127
|
-
const lockContent = JSON.parse(
|
|
17329
|
+
const lockContent = JSON.parse(fs13.readFileSync(lockFilePath, "utf8"));
|
|
17128
17330
|
if (lockContent.workspaceFolders && Array.isArray(lockContent.workspaceFolders)) {
|
|
17129
17331
|
workspacePaths.push(...lockContent.workspaceFolders);
|
|
17130
17332
|
}
|
|
@@ -17147,24 +17349,24 @@ var getMCPConfigPaths = (hostName) => {
|
|
|
17147
17349
|
switch (hostName.toLowerCase()) {
|
|
17148
17350
|
case "cursor":
|
|
17149
17351
|
return [
|
|
17150
|
-
|
|
17352
|
+
path14.join(currentDir, ".cursor", "mcp.json"),
|
|
17151
17353
|
// local first
|
|
17152
|
-
|
|
17354
|
+
path14.join(home, ".cursor", "mcp.json")
|
|
17153
17355
|
];
|
|
17154
17356
|
case "windsurf":
|
|
17155
17357
|
return [
|
|
17156
|
-
|
|
17358
|
+
path14.join(currentDir, ".codeium", "mcp_config.json"),
|
|
17157
17359
|
// local first
|
|
17158
|
-
|
|
17360
|
+
path14.join(home, ".codeium", "windsurf", "mcp_config.json")
|
|
17159
17361
|
];
|
|
17160
17362
|
case "webstorm":
|
|
17161
17363
|
return [];
|
|
17162
17364
|
case "visualstudiocode":
|
|
17163
17365
|
case "vscode":
|
|
17164
17366
|
return [
|
|
17165
|
-
|
|
17367
|
+
path14.join(currentDir, ".vscode", "mcp.json"),
|
|
17166
17368
|
// local first
|
|
17167
|
-
process.platform === "win32" ?
|
|
17369
|
+
process.platform === "win32" ? path14.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path14.join(
|
|
17168
17370
|
home,
|
|
17169
17371
|
"Library",
|
|
17170
17372
|
"Application Support",
|
|
@@ -17175,13 +17377,13 @@ var getMCPConfigPaths = (hostName) => {
|
|
|
17175
17377
|
];
|
|
17176
17378
|
case "claude": {
|
|
17177
17379
|
const claudePaths = [
|
|
17178
|
-
|
|
17380
|
+
path14.join(currentDir, ".claude.json"),
|
|
17179
17381
|
// local first
|
|
17180
|
-
|
|
17382
|
+
path14.join(home, ".claude.json")
|
|
17181
17383
|
];
|
|
17182
17384
|
const workspacePaths = getClaudeWorkspacePaths();
|
|
17183
17385
|
for (const workspacePath of workspacePaths) {
|
|
17184
|
-
claudePaths.push(
|
|
17386
|
+
claudePaths.push(path14.join(workspacePath, ".mcp.json"));
|
|
17185
17387
|
}
|
|
17186
17388
|
return claudePaths;
|
|
17187
17389
|
}
|
|
@@ -17190,9 +17392,9 @@ var getMCPConfigPaths = (hostName) => {
|
|
|
17190
17392
|
}
|
|
17191
17393
|
};
|
|
17192
17394
|
var readConfigFile = (filePath) => {
|
|
17193
|
-
if (!
|
|
17395
|
+
if (!fs13.existsSync(filePath)) return null;
|
|
17194
17396
|
try {
|
|
17195
|
-
return JSON.parse(
|
|
17397
|
+
return JSON.parse(fs13.readFileSync(filePath, "utf8"));
|
|
17196
17398
|
} catch (error) {
|
|
17197
17399
|
logWarn(`[UsageService] Failed to read MCP config: ${filePath}`);
|
|
17198
17400
|
return null;
|
|
@@ -17342,10 +17544,10 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
17342
17544
|
const ideConfigPaths = /* @__PURE__ */ new Set();
|
|
17343
17545
|
for (const ide of IDEs) {
|
|
17344
17546
|
const configPaths = getMCPConfigPaths(ide);
|
|
17345
|
-
configPaths.forEach((
|
|
17547
|
+
configPaths.forEach((path26) => ideConfigPaths.add(path26));
|
|
17346
17548
|
}
|
|
17347
17549
|
const uniqueAdditionalPaths = additionalMcpList.filter(
|
|
17348
|
-
(
|
|
17550
|
+
(path26) => !ideConfigPaths.has(path26)
|
|
17349
17551
|
);
|
|
17350
17552
|
for (const ide of IDEs) {
|
|
17351
17553
|
const cfg = readMCPConfig(ide);
|
|
@@ -17465,9 +17667,9 @@ init_configs();
|
|
|
17465
17667
|
|
|
17466
17668
|
// src/mcp/services/McpUsageService/system.ts
|
|
17467
17669
|
init_configs();
|
|
17468
|
-
import
|
|
17670
|
+
import fs14 from "fs";
|
|
17469
17671
|
import os7 from "os";
|
|
17470
|
-
import
|
|
17672
|
+
import path15 from "path";
|
|
17471
17673
|
var MAX_DEPTH = 2;
|
|
17472
17674
|
var patterns = ["mcp", "claude"];
|
|
17473
17675
|
var isFileMatch = (fileName) => {
|
|
@@ -17476,7 +17678,7 @@ var isFileMatch = (fileName) => {
|
|
|
17476
17678
|
};
|
|
17477
17679
|
var safeAccess = async (filePath) => {
|
|
17478
17680
|
try {
|
|
17479
|
-
await
|
|
17681
|
+
await fs14.promises.access(filePath, fs14.constants.R_OK);
|
|
17480
17682
|
return true;
|
|
17481
17683
|
} catch {
|
|
17482
17684
|
return false;
|
|
@@ -17485,9 +17687,9 @@ var safeAccess = async (filePath) => {
|
|
|
17485
17687
|
var searchDir = async (dir, depth = 0) => {
|
|
17486
17688
|
const results = [];
|
|
17487
17689
|
if (depth > MAX_DEPTH) return results;
|
|
17488
|
-
const entries = await
|
|
17690
|
+
const entries = await fs14.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
17489
17691
|
for (const entry of entries) {
|
|
17490
|
-
const fullPath =
|
|
17692
|
+
const fullPath = path15.join(dir, entry.name);
|
|
17491
17693
|
if (entry.isFile() && isFileMatch(entry.name)) {
|
|
17492
17694
|
results.push(fullPath);
|
|
17493
17695
|
} else if (entry.isDirectory()) {
|
|
@@ -17504,14 +17706,14 @@ var findSystemMCPConfigs = async () => {
|
|
|
17504
17706
|
const home = os7.homedir();
|
|
17505
17707
|
const platform2 = os7.platform();
|
|
17506
17708
|
const knownDirs = platform2 === "win32" ? [
|
|
17507
|
-
|
|
17508
|
-
|
|
17509
|
-
|
|
17709
|
+
path15.join(home, ".cursor"),
|
|
17710
|
+
path15.join(home, "Documents"),
|
|
17711
|
+
path15.join(home, "Downloads")
|
|
17510
17712
|
] : [
|
|
17511
|
-
|
|
17512
|
-
process.env["XDG_CONFIG_HOME"] ||
|
|
17513
|
-
|
|
17514
|
-
|
|
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")
|
|
17515
17717
|
];
|
|
17516
17718
|
const timeoutPromise = new Promise(
|
|
17517
17719
|
(resolve) => setTimeout(() => {
|
|
@@ -17523,7 +17725,7 @@ var findSystemMCPConfigs = async () => {
|
|
|
17523
17725
|
);
|
|
17524
17726
|
const searchPromise = Promise.all(
|
|
17525
17727
|
knownDirs.map(
|
|
17526
|
-
(dir) =>
|
|
17728
|
+
(dir) => fs14.existsSync(dir) ? searchDir(dir) : Promise.resolve([])
|
|
17527
17729
|
)
|
|
17528
17730
|
).then((results) => results.flat());
|
|
17529
17731
|
return await Promise.race([timeoutPromise, searchPromise]);
|
|
@@ -19925,31 +20127,31 @@ For a complete security audit workflow, use the \`full-security-audit\` prompt.
|
|
|
19925
20127
|
};
|
|
19926
20128
|
|
|
19927
20129
|
// src/mcp/services/McpDetectionService/CursorMcpDetectionService.ts
|
|
19928
|
-
import * as
|
|
20130
|
+
import * as fs17 from "fs";
|
|
19929
20131
|
import * as os10 from "os";
|
|
19930
|
-
import * as
|
|
20132
|
+
import * as path17 from "path";
|
|
19931
20133
|
|
|
19932
20134
|
// src/mcp/services/McpDetectionService/BaseMcpDetectionService.ts
|
|
19933
20135
|
init_configs();
|
|
19934
|
-
import * as
|
|
20136
|
+
import * as fs16 from "fs";
|
|
19935
20137
|
import fetch6 from "node-fetch";
|
|
19936
|
-
import * as
|
|
20138
|
+
import * as path16 from "path";
|
|
19937
20139
|
|
|
19938
20140
|
// src/mcp/services/McpDetectionService/McpDetectionServiceUtils.ts
|
|
19939
|
-
import * as
|
|
20141
|
+
import * as fs15 from "fs";
|
|
19940
20142
|
import * as os9 from "os";
|
|
19941
20143
|
|
|
19942
20144
|
// src/mcp/services/McpDetectionService/VscodeMcpDetectionService.ts
|
|
19943
|
-
import * as
|
|
20145
|
+
import * as fs18 from "fs";
|
|
19944
20146
|
import * as os11 from "os";
|
|
19945
|
-
import * as
|
|
20147
|
+
import * as path18 from "path";
|
|
19946
20148
|
|
|
19947
20149
|
// src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesTool.ts
|
|
19948
20150
|
import { z as z42 } from "zod";
|
|
19949
20151
|
|
|
19950
20152
|
// src/mcp/services/PathValidation.ts
|
|
19951
|
-
import
|
|
19952
|
-
import
|
|
20153
|
+
import fs19 from "fs";
|
|
20154
|
+
import path19 from "path";
|
|
19953
20155
|
async function validatePath(inputPath) {
|
|
19954
20156
|
logDebug("Validating MCP path", { inputPath });
|
|
19955
20157
|
if (/^\/[a-zA-Z]:\//.test(inputPath)) {
|
|
@@ -19981,7 +20183,7 @@ async function validatePath(inputPath) {
|
|
|
19981
20183
|
logError(error);
|
|
19982
20184
|
return { isValid: false, error, path: inputPath };
|
|
19983
20185
|
}
|
|
19984
|
-
const normalizedPath =
|
|
20186
|
+
const normalizedPath = path19.normalize(inputPath);
|
|
19985
20187
|
if (normalizedPath.includes("..")) {
|
|
19986
20188
|
const error = `Normalized path contains path traversal patterns: ${inputPath}`;
|
|
19987
20189
|
logError(error);
|
|
@@ -20008,7 +20210,7 @@ async function validatePath(inputPath) {
|
|
|
20008
20210
|
logDebug("Path validation successful", { inputPath });
|
|
20009
20211
|
logDebug("Checking path existence", { inputPath });
|
|
20010
20212
|
try {
|
|
20011
|
-
await
|
|
20213
|
+
await fs19.promises.access(inputPath);
|
|
20012
20214
|
logDebug("Path exists and is accessible", { inputPath });
|
|
20013
20215
|
WorkspaceService.setKnownWorkspacePath(inputPath);
|
|
20014
20216
|
logDebug("Stored validated path in WorkspaceService", { inputPath });
|
|
@@ -20636,10 +20838,10 @@ If you wish to scan files that were recently changed in your git history call th
|
|
|
20636
20838
|
init_FileUtils();
|
|
20637
20839
|
init_GitService();
|
|
20638
20840
|
init_configs();
|
|
20639
|
-
import
|
|
20841
|
+
import fs20 from "fs/promises";
|
|
20640
20842
|
import nodePath from "path";
|
|
20641
20843
|
var getLocalFiles = async ({
|
|
20642
|
-
path:
|
|
20844
|
+
path: path26,
|
|
20643
20845
|
maxFileSize = MCP_MAX_FILE_SIZE,
|
|
20644
20846
|
maxFiles,
|
|
20645
20847
|
isAllFilesScan,
|
|
@@ -20647,17 +20849,17 @@ var getLocalFiles = async ({
|
|
|
20647
20849
|
scanRecentlyChangedFiles
|
|
20648
20850
|
}) => {
|
|
20649
20851
|
logDebug(`[${scanContext}] Starting getLocalFiles`, {
|
|
20650
|
-
path:
|
|
20852
|
+
path: path26,
|
|
20651
20853
|
maxFileSize,
|
|
20652
20854
|
maxFiles,
|
|
20653
20855
|
isAllFilesScan,
|
|
20654
20856
|
scanRecentlyChangedFiles
|
|
20655
20857
|
});
|
|
20656
20858
|
try {
|
|
20657
|
-
const resolvedRepoPath = await
|
|
20859
|
+
const resolvedRepoPath = await fs20.realpath(path26);
|
|
20658
20860
|
logDebug(`[${scanContext}] Resolved repository path`, {
|
|
20659
20861
|
resolvedRepoPath,
|
|
20660
|
-
originalPath:
|
|
20862
|
+
originalPath: path26
|
|
20661
20863
|
});
|
|
20662
20864
|
const gitService = new GitService(resolvedRepoPath, log);
|
|
20663
20865
|
const gitValidation = await gitService.validateRepository();
|
|
@@ -20670,7 +20872,7 @@ var getLocalFiles = async ({
|
|
|
20670
20872
|
if (!gitValidation.isValid || isAllFilesScan) {
|
|
20671
20873
|
try {
|
|
20672
20874
|
files = await FileUtils.getLastChangedFiles({
|
|
20673
|
-
dir:
|
|
20875
|
+
dir: path26,
|
|
20674
20876
|
maxFileSize,
|
|
20675
20877
|
maxFiles,
|
|
20676
20878
|
isAllFilesScan
|
|
@@ -20734,7 +20936,7 @@ var getLocalFiles = async ({
|
|
|
20734
20936
|
absoluteFilePath
|
|
20735
20937
|
);
|
|
20736
20938
|
try {
|
|
20737
|
-
const fileStat = await
|
|
20939
|
+
const fileStat = await fs20.stat(absoluteFilePath);
|
|
20738
20940
|
return {
|
|
20739
20941
|
filename: nodePath.basename(absoluteFilePath),
|
|
20740
20942
|
relativePath,
|
|
@@ -20762,7 +20964,7 @@ var getLocalFiles = async ({
|
|
|
20762
20964
|
logError(`${scanContext}Unexpected error in getLocalFiles`, {
|
|
20763
20965
|
error: error instanceof Error ? error.message : String(error),
|
|
20764
20966
|
stack: error instanceof Error ? error.stack : void 0,
|
|
20765
|
-
path:
|
|
20967
|
+
path: path26
|
|
20766
20968
|
});
|
|
20767
20969
|
throw error;
|
|
20768
20970
|
}
|
|
@@ -20771,8 +20973,8 @@ var getLocalFiles = async ({
|
|
|
20771
20973
|
// src/mcp/services/LocalMobbFolderService.ts
|
|
20772
20974
|
init_client_generates();
|
|
20773
20975
|
init_GitService();
|
|
20774
|
-
import
|
|
20775
|
-
import
|
|
20976
|
+
import fs21 from "fs";
|
|
20977
|
+
import path20 from "path";
|
|
20776
20978
|
import { z as z41 } from "zod";
|
|
20777
20979
|
function extractPathFromPatch(patch) {
|
|
20778
20980
|
const match = patch?.match(/diff --git a\/([^\s]+) b\//);
|
|
@@ -20858,19 +21060,19 @@ var LocalMobbFolderService = class {
|
|
|
20858
21060
|
"[LocalMobbFolderService] Non-git repository detected, skipping .gitignore operations"
|
|
20859
21061
|
);
|
|
20860
21062
|
}
|
|
20861
|
-
const mobbFolderPath =
|
|
21063
|
+
const mobbFolderPath = path20.join(
|
|
20862
21064
|
this.repoPath,
|
|
20863
21065
|
this.defaultMobbFolderName
|
|
20864
21066
|
);
|
|
20865
|
-
if (!
|
|
21067
|
+
if (!fs21.existsSync(mobbFolderPath)) {
|
|
20866
21068
|
logInfo("[LocalMobbFolderService] Creating .mobb folder", {
|
|
20867
21069
|
mobbFolderPath
|
|
20868
21070
|
});
|
|
20869
|
-
|
|
21071
|
+
fs21.mkdirSync(mobbFolderPath, { recursive: true });
|
|
20870
21072
|
} else {
|
|
20871
21073
|
logDebug("[LocalMobbFolderService] .mobb folder already exists");
|
|
20872
21074
|
}
|
|
20873
|
-
const stats =
|
|
21075
|
+
const stats = fs21.statSync(mobbFolderPath);
|
|
20874
21076
|
if (!stats.isDirectory()) {
|
|
20875
21077
|
throw new Error(`Path exists but is not a directory: ${mobbFolderPath}`);
|
|
20876
21078
|
}
|
|
@@ -20911,13 +21113,13 @@ var LocalMobbFolderService = class {
|
|
|
20911
21113
|
logDebug("[LocalMobbFolderService] Git repository validated successfully");
|
|
20912
21114
|
} else {
|
|
20913
21115
|
try {
|
|
20914
|
-
const stats =
|
|
21116
|
+
const stats = fs21.statSync(this.repoPath);
|
|
20915
21117
|
if (!stats.isDirectory()) {
|
|
20916
21118
|
throw new Error(
|
|
20917
21119
|
`Path exists but is not a directory: ${this.repoPath}`
|
|
20918
21120
|
);
|
|
20919
21121
|
}
|
|
20920
|
-
|
|
21122
|
+
fs21.accessSync(this.repoPath, fs21.constants.R_OK | fs21.constants.W_OK);
|
|
20921
21123
|
logDebug(
|
|
20922
21124
|
"[LocalMobbFolderService] Non-git directory validated successfully"
|
|
20923
21125
|
);
|
|
@@ -21030,8 +21232,8 @@ var LocalMobbFolderService = class {
|
|
|
21030
21232
|
mobbFolderPath,
|
|
21031
21233
|
baseFileName
|
|
21032
21234
|
);
|
|
21033
|
-
const filePath =
|
|
21034
|
-
await
|
|
21235
|
+
const filePath = path20.join(mobbFolderPath, uniqueFileName);
|
|
21236
|
+
await fs21.promises.writeFile(filePath, patch, "utf8");
|
|
21035
21237
|
logInfo("[LocalMobbFolderService] Patch saved successfully", {
|
|
21036
21238
|
filePath,
|
|
21037
21239
|
fileName: uniqueFileName,
|
|
@@ -21088,11 +21290,11 @@ var LocalMobbFolderService = class {
|
|
|
21088
21290
|
* @returns Unique filename that doesn't conflict with existing files
|
|
21089
21291
|
*/
|
|
21090
21292
|
getUniqueFileName(folderPath, baseFileName) {
|
|
21091
|
-
const baseName =
|
|
21092
|
-
const extension =
|
|
21293
|
+
const baseName = path20.parse(baseFileName).name;
|
|
21294
|
+
const extension = path20.parse(baseFileName).ext;
|
|
21093
21295
|
let uniqueFileName = baseFileName;
|
|
21094
21296
|
let index = 1;
|
|
21095
|
-
while (
|
|
21297
|
+
while (fs21.existsSync(path20.join(folderPath, uniqueFileName))) {
|
|
21096
21298
|
uniqueFileName = `${baseName}-${index}${extension}`;
|
|
21097
21299
|
index++;
|
|
21098
21300
|
if (index > 1e3) {
|
|
@@ -21123,18 +21325,18 @@ var LocalMobbFolderService = class {
|
|
|
21123
21325
|
logDebug("[LocalMobbFolderService] Logging patch info", { fixId: fix.id });
|
|
21124
21326
|
try {
|
|
21125
21327
|
const mobbFolderPath = await this.getFolder();
|
|
21126
|
-
const patchInfoPath =
|
|
21328
|
+
const patchInfoPath = path20.join(mobbFolderPath, "patchInfo.md");
|
|
21127
21329
|
const markdownContent = this.generateFixMarkdown(fix, savedPatchFileName);
|
|
21128
21330
|
let existingContent = "";
|
|
21129
|
-
if (
|
|
21130
|
-
existingContent = await
|
|
21331
|
+
if (fs21.existsSync(patchInfoPath)) {
|
|
21332
|
+
existingContent = await fs21.promises.readFile(patchInfoPath, "utf8");
|
|
21131
21333
|
logDebug("[LocalMobbFolderService] Existing patchInfo.md found");
|
|
21132
21334
|
} else {
|
|
21133
21335
|
logDebug("[LocalMobbFolderService] Creating new patchInfo.md file");
|
|
21134
21336
|
}
|
|
21135
21337
|
const separator = existingContent ? "\n\n================================================================================\n\n" : "";
|
|
21136
21338
|
const updatedContent = `${markdownContent}${separator}${existingContent}`;
|
|
21137
|
-
await
|
|
21339
|
+
await fs21.promises.writeFile(patchInfoPath, updatedContent, "utf8");
|
|
21138
21340
|
logInfo("[LocalMobbFolderService] Patch info logged successfully", {
|
|
21139
21341
|
patchInfoPath,
|
|
21140
21342
|
fixId: fix.id,
|
|
@@ -21165,7 +21367,7 @@ var LocalMobbFolderService = class {
|
|
|
21165
21367
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
21166
21368
|
const patch = this.extractPatchFromFix(fix);
|
|
21167
21369
|
const relativePatchedFilePath = patch ? extractPathFromPatch(patch) : null;
|
|
21168
|
-
const patchedFilePath = relativePatchedFilePath ?
|
|
21370
|
+
const patchedFilePath = relativePatchedFilePath ? path20.resolve(this.repoPath, relativePatchedFilePath) : null;
|
|
21169
21371
|
const fixIdentifier = savedPatchFileName ? savedPatchFileName.replace(".patch", "") : fix.id;
|
|
21170
21372
|
let markdown = `# Fix ${fixIdentifier}
|
|
21171
21373
|
|
|
@@ -21507,16 +21709,16 @@ import {
|
|
|
21507
21709
|
unlinkSync,
|
|
21508
21710
|
writeFileSync
|
|
21509
21711
|
} from "fs";
|
|
21510
|
-
import
|
|
21712
|
+
import fs22 from "fs/promises";
|
|
21511
21713
|
import parseDiff3 from "parse-diff";
|
|
21512
|
-
import
|
|
21714
|
+
import path21 from "path";
|
|
21513
21715
|
var PatchApplicationService = class {
|
|
21514
21716
|
/**
|
|
21515
21717
|
* Gets the appropriate comment syntax for a file based on its extension
|
|
21516
21718
|
*/
|
|
21517
21719
|
static getCommentSyntax(filePath) {
|
|
21518
|
-
const ext =
|
|
21519
|
-
const basename2 =
|
|
21720
|
+
const ext = path21.extname(filePath).toLowerCase();
|
|
21721
|
+
const basename2 = path21.basename(filePath);
|
|
21520
21722
|
const commentMap = {
|
|
21521
21723
|
// C-style languages (single line comments)
|
|
21522
21724
|
".js": "//",
|
|
@@ -21724,7 +21926,7 @@ var PatchApplicationService = class {
|
|
|
21724
21926
|
}
|
|
21725
21927
|
);
|
|
21726
21928
|
}
|
|
21727
|
-
const dirPath =
|
|
21929
|
+
const dirPath = path21.dirname(normalizedFilePath);
|
|
21728
21930
|
mkdirSync(dirPath, { recursive: true });
|
|
21729
21931
|
writeFileSync(normalizedFilePath, finalContent, "utf8");
|
|
21730
21932
|
return normalizedFilePath;
|
|
@@ -21733,9 +21935,9 @@ var PatchApplicationService = class {
|
|
|
21733
21935
|
repositoryPath,
|
|
21734
21936
|
targetPath
|
|
21735
21937
|
}) {
|
|
21736
|
-
const repoRoot =
|
|
21737
|
-
const normalizedPath =
|
|
21738
|
-
const repoRootWithSep = repoRoot.endsWith(
|
|
21938
|
+
const repoRoot = path21.resolve(repositoryPath);
|
|
21939
|
+
const normalizedPath = path21.resolve(repoRoot, targetPath);
|
|
21940
|
+
const repoRootWithSep = repoRoot.endsWith(path21.sep) ? repoRoot : `${repoRoot}${path21.sep}`;
|
|
21739
21941
|
if (normalizedPath !== repoRoot && !normalizedPath.startsWith(repoRootWithSep)) {
|
|
21740
21942
|
throw new Error(
|
|
21741
21943
|
`Security violation: target path ${targetPath} resolves outside repository`
|
|
@@ -21744,7 +21946,7 @@ var PatchApplicationService = class {
|
|
|
21744
21946
|
return {
|
|
21745
21947
|
repoRoot,
|
|
21746
21948
|
normalizedPath,
|
|
21747
|
-
relativePath:
|
|
21949
|
+
relativePath: path21.relative(repoRoot, normalizedPath)
|
|
21748
21950
|
};
|
|
21749
21951
|
}
|
|
21750
21952
|
/**
|
|
@@ -22026,9 +22228,9 @@ var PatchApplicationService = class {
|
|
|
22026
22228
|
continue;
|
|
22027
22229
|
}
|
|
22028
22230
|
try {
|
|
22029
|
-
const absolutePath =
|
|
22231
|
+
const absolutePath = path21.resolve(repositoryPath, targetFile);
|
|
22030
22232
|
if (existsSync6(absolutePath)) {
|
|
22031
|
-
const stats = await
|
|
22233
|
+
const stats = await fs22.stat(absolutePath);
|
|
22032
22234
|
const fileModTime = stats.mtime.getTime();
|
|
22033
22235
|
if (fileModTime > scanStartTime) {
|
|
22034
22236
|
logError(
|
|
@@ -22069,7 +22271,7 @@ var PatchApplicationService = class {
|
|
|
22069
22271
|
const appliedFixes = [];
|
|
22070
22272
|
const failedFixes = [];
|
|
22071
22273
|
const skippedFixes = [];
|
|
22072
|
-
const resolvedRepoPath = await
|
|
22274
|
+
const resolvedRepoPath = await fs22.realpath(repositoryPath);
|
|
22073
22275
|
logInfo(
|
|
22074
22276
|
`[${scanContext}] Starting patch application for ${fixes.length} fixes`,
|
|
22075
22277
|
{
|
|
@@ -22252,7 +22454,7 @@ var PatchApplicationService = class {
|
|
|
22252
22454
|
fix,
|
|
22253
22455
|
scanContext
|
|
22254
22456
|
});
|
|
22255
|
-
appliedFiles.push(
|
|
22457
|
+
appliedFiles.push(path21.relative(repositoryPath, actualPath));
|
|
22256
22458
|
logDebug(`[${scanContext}] Created new file: ${relativePath}`);
|
|
22257
22459
|
}
|
|
22258
22460
|
/**
|
|
@@ -22301,7 +22503,7 @@ var PatchApplicationService = class {
|
|
|
22301
22503
|
fix,
|
|
22302
22504
|
scanContext
|
|
22303
22505
|
});
|
|
22304
|
-
appliedFiles.push(
|
|
22506
|
+
appliedFiles.push(path21.relative(repositoryPath, actualPath));
|
|
22305
22507
|
logDebug(`[${scanContext}] Modified file: ${relativePath}`);
|
|
22306
22508
|
}
|
|
22307
22509
|
}
|
|
@@ -22497,9 +22699,9 @@ init_configs();
|
|
|
22497
22699
|
|
|
22498
22700
|
// src/mcp/services/FileOperations.ts
|
|
22499
22701
|
init_FileUtils();
|
|
22500
|
-
import
|
|
22501
|
-
import
|
|
22502
|
-
import
|
|
22702
|
+
import fs23 from "fs";
|
|
22703
|
+
import path22 from "path";
|
|
22704
|
+
import AdmZip3 from "adm-zip";
|
|
22503
22705
|
var FileOperations = class {
|
|
22504
22706
|
/**
|
|
22505
22707
|
* Creates a ZIP archive containing the specified source files
|
|
@@ -22514,14 +22716,14 @@ var FileOperations = class {
|
|
|
22514
22716
|
maxFileSize
|
|
22515
22717
|
}) {
|
|
22516
22718
|
logDebug("[FileOperations] Packing files");
|
|
22517
|
-
const zip = new
|
|
22719
|
+
const zip = new AdmZip3();
|
|
22518
22720
|
let packedFilesCount = 0;
|
|
22519
22721
|
const packedFiles = [];
|
|
22520
22722
|
const excludedFiles = [];
|
|
22521
|
-
const resolvedRepoPath =
|
|
22723
|
+
const resolvedRepoPath = path22.resolve(repositoryPath);
|
|
22522
22724
|
for (const filepath of fileList) {
|
|
22523
|
-
const absoluteFilepath =
|
|
22524
|
-
const resolvedFilePath =
|
|
22725
|
+
const absoluteFilepath = path22.join(repositoryPath, filepath);
|
|
22726
|
+
const resolvedFilePath = path22.resolve(absoluteFilepath);
|
|
22525
22727
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
22526
22728
|
const reason = "potential path traversal security risk";
|
|
22527
22729
|
logDebug(`[FileOperations] Skipping ${filepath} due to ${reason}`);
|
|
@@ -22568,11 +22770,11 @@ var FileOperations = class {
|
|
|
22568
22770
|
fileList,
|
|
22569
22771
|
repositoryPath
|
|
22570
22772
|
}) {
|
|
22571
|
-
const resolvedRepoPath =
|
|
22773
|
+
const resolvedRepoPath = path22.resolve(repositoryPath);
|
|
22572
22774
|
const validatedPaths = [];
|
|
22573
22775
|
for (const filepath of fileList) {
|
|
22574
|
-
const absoluteFilepath =
|
|
22575
|
-
const resolvedFilePath =
|
|
22776
|
+
const absoluteFilepath = path22.join(repositoryPath, filepath);
|
|
22777
|
+
const resolvedFilePath = path22.resolve(absoluteFilepath);
|
|
22576
22778
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
22577
22779
|
logDebug(
|
|
22578
22780
|
`[FileOperations] Rejecting ${filepath} - path traversal attempt detected`
|
|
@@ -22580,7 +22782,7 @@ var FileOperations = class {
|
|
|
22580
22782
|
continue;
|
|
22581
22783
|
}
|
|
22582
22784
|
try {
|
|
22583
|
-
await
|
|
22785
|
+
await fs23.promises.access(absoluteFilepath, fs23.constants.R_OK);
|
|
22584
22786
|
validatedPaths.push(filepath);
|
|
22585
22787
|
} catch (error) {
|
|
22586
22788
|
logDebug(
|
|
@@ -22599,8 +22801,8 @@ var FileOperations = class {
|
|
|
22599
22801
|
const fileDataArray = [];
|
|
22600
22802
|
for (const absolutePath of filePaths) {
|
|
22601
22803
|
try {
|
|
22602
|
-
const content = await
|
|
22603
|
-
const relativePath =
|
|
22804
|
+
const content = await fs23.promises.readFile(absolutePath);
|
|
22805
|
+
const relativePath = path22.basename(absolutePath);
|
|
22604
22806
|
fileDataArray.push({
|
|
22605
22807
|
relativePath,
|
|
22606
22808
|
absolutePath,
|
|
@@ -22625,7 +22827,7 @@ var FileOperations = class {
|
|
|
22625
22827
|
relativeFilepath
|
|
22626
22828
|
}) {
|
|
22627
22829
|
try {
|
|
22628
|
-
return await
|
|
22830
|
+
return await fs23.promises.readFile(absoluteFilepath);
|
|
22629
22831
|
} catch (fsError) {
|
|
22630
22832
|
logError(
|
|
22631
22833
|
`[FileOperations] Failed to read ${relativeFilepath} from filesystem: ${fsError}`
|
|
@@ -22912,14 +23114,14 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
22912
23114
|
* since the last scan.
|
|
22913
23115
|
*/
|
|
22914
23116
|
async scanForSecurityVulnerabilities({
|
|
22915
|
-
path:
|
|
23117
|
+
path: path26,
|
|
22916
23118
|
isAllDetectionRulesScan,
|
|
22917
23119
|
isAllFilesScan,
|
|
22918
23120
|
scanContext
|
|
22919
23121
|
}) {
|
|
22920
23122
|
this.hasAuthenticationFailed = false;
|
|
22921
23123
|
logDebug(`[${scanContext}] Scanning for new security vulnerabilities`, {
|
|
22922
|
-
path:
|
|
23124
|
+
path: path26
|
|
22923
23125
|
});
|
|
22924
23126
|
if (!this.gqlClient) {
|
|
22925
23127
|
logInfo(`[${scanContext}] No GQL client found, skipping scan`);
|
|
@@ -22935,11 +23137,11 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
22935
23137
|
}
|
|
22936
23138
|
logDebug(
|
|
22937
23139
|
`[${scanContext}] Connected to the API, assembling list of files to scan`,
|
|
22938
|
-
{ path:
|
|
23140
|
+
{ path: path26 }
|
|
22939
23141
|
);
|
|
22940
23142
|
const isBackgroundScan = scanContext === ScanContext.BACKGROUND_INITIAL || scanContext === ScanContext.BACKGROUND_PERIODIC;
|
|
22941
23143
|
const files = await getLocalFiles({
|
|
22942
|
-
path:
|
|
23144
|
+
path: path26,
|
|
22943
23145
|
isAllFilesScan,
|
|
22944
23146
|
scanContext,
|
|
22945
23147
|
scanRecentlyChangedFiles: !isBackgroundScan
|
|
@@ -22965,13 +23167,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
22965
23167
|
});
|
|
22966
23168
|
const { fixReportId, projectId } = await scanFiles({
|
|
22967
23169
|
fileList: filesToScan.map((file) => file.relativePath),
|
|
22968
|
-
repositoryPath:
|
|
23170
|
+
repositoryPath: path26,
|
|
22969
23171
|
gqlClient: this.gqlClient,
|
|
22970
23172
|
isAllDetectionRulesScan,
|
|
22971
23173
|
scanContext
|
|
22972
23174
|
});
|
|
22973
23175
|
logInfo(
|
|
22974
|
-
`[${scanContext}] Security scan completed for ${
|
|
23176
|
+
`[${scanContext}] Security scan completed for ${path26} reportId: ${fixReportId} projectId: ${projectId}`
|
|
22975
23177
|
);
|
|
22976
23178
|
if (isAllFilesScan) {
|
|
22977
23179
|
return;
|
|
@@ -23265,13 +23467,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
23265
23467
|
});
|
|
23266
23468
|
return scannedFiles.some((file) => file.relativePath === fixFile);
|
|
23267
23469
|
}
|
|
23268
|
-
async getFreshFixes({ path:
|
|
23470
|
+
async getFreshFixes({ path: path26 }) {
|
|
23269
23471
|
const scanContext = ScanContext.USER_REQUEST;
|
|
23270
|
-
logDebug(`[${scanContext}] Getting fresh fixes`, { path:
|
|
23271
|
-
if (this.path !==
|
|
23272
|
-
this.path =
|
|
23472
|
+
logDebug(`[${scanContext}] Getting fresh fixes`, { path: path26 });
|
|
23473
|
+
if (this.path !== path26) {
|
|
23474
|
+
this.path = path26;
|
|
23273
23475
|
this.reset();
|
|
23274
|
-
logInfo(`[${scanContext}] Reset service state for new path`, { path:
|
|
23476
|
+
logInfo(`[${scanContext}] Reset service state for new path`, { path: path26 });
|
|
23275
23477
|
}
|
|
23276
23478
|
try {
|
|
23277
23479
|
const loginContext = createMcpLoginContext("check_new_fixes");
|
|
@@ -23290,7 +23492,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
23290
23492
|
}
|
|
23291
23493
|
throw error;
|
|
23292
23494
|
}
|
|
23293
|
-
this.triggerScan({ path:
|
|
23495
|
+
this.triggerScan({ path: path26, gqlClient: this.gqlClient });
|
|
23294
23496
|
let isMvsAutoFixEnabled = null;
|
|
23295
23497
|
try {
|
|
23296
23498
|
isMvsAutoFixEnabled = await this.gqlClient.getMvsAutoFixSettings();
|
|
@@ -23324,33 +23526,33 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
23324
23526
|
return noFreshFixesPrompt;
|
|
23325
23527
|
}
|
|
23326
23528
|
triggerScan({
|
|
23327
|
-
path:
|
|
23529
|
+
path: path26,
|
|
23328
23530
|
gqlClient
|
|
23329
23531
|
}) {
|
|
23330
|
-
if (this.path !==
|
|
23331
|
-
this.path =
|
|
23532
|
+
if (this.path !== path26) {
|
|
23533
|
+
this.path = path26;
|
|
23332
23534
|
this.reset();
|
|
23333
|
-
logInfo(`Reset service state for new path in triggerScan`, { path:
|
|
23535
|
+
logInfo(`Reset service state for new path in triggerScan`, { path: path26 });
|
|
23334
23536
|
}
|
|
23335
23537
|
this.gqlClient = gqlClient;
|
|
23336
23538
|
if (!this.intervalId) {
|
|
23337
|
-
this.startPeriodicScanning(
|
|
23338
|
-
this.executeInitialScan(
|
|
23339
|
-
void this.executeInitialFullScan(
|
|
23539
|
+
this.startPeriodicScanning(path26);
|
|
23540
|
+
this.executeInitialScan(path26);
|
|
23541
|
+
void this.executeInitialFullScan(path26);
|
|
23340
23542
|
}
|
|
23341
23543
|
}
|
|
23342
|
-
startPeriodicScanning(
|
|
23544
|
+
startPeriodicScanning(path26) {
|
|
23343
23545
|
const scanContext = ScanContext.BACKGROUND_PERIODIC;
|
|
23344
23546
|
logDebug(
|
|
23345
23547
|
`[${scanContext}] Starting periodic scan for new security vulnerabilities`,
|
|
23346
23548
|
{
|
|
23347
|
-
path:
|
|
23549
|
+
path: path26
|
|
23348
23550
|
}
|
|
23349
23551
|
);
|
|
23350
23552
|
this.intervalId = setInterval(() => {
|
|
23351
|
-
logDebug(`[${scanContext}] Triggering periodic security scan`, { path:
|
|
23553
|
+
logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path26 });
|
|
23352
23554
|
this.scanForSecurityVulnerabilities({
|
|
23353
|
-
path:
|
|
23555
|
+
path: path26,
|
|
23354
23556
|
scanContext
|
|
23355
23557
|
}).catch((error) => {
|
|
23356
23558
|
logError(`[${scanContext}] Error during periodic security scan`, {
|
|
@@ -23359,45 +23561,45 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
23359
23561
|
});
|
|
23360
23562
|
}, MCP_PERIODIC_CHECK_INTERVAL);
|
|
23361
23563
|
}
|
|
23362
|
-
async executeInitialFullScan(
|
|
23564
|
+
async executeInitialFullScan(path26) {
|
|
23363
23565
|
const scanContext = ScanContext.FULL_SCAN;
|
|
23364
|
-
logDebug(`[${scanContext}] Triggering initial full security scan`, { path:
|
|
23566
|
+
logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path26 });
|
|
23365
23567
|
logDebug(`[${scanContext}] Full scan paths scanned`, {
|
|
23366
23568
|
fullScanPathsScanned: this.fullScanPathsScanned
|
|
23367
23569
|
});
|
|
23368
|
-
if (this.fullScanPathsScanned.includes(
|
|
23570
|
+
if (this.fullScanPathsScanned.includes(path26)) {
|
|
23369
23571
|
logDebug(`[${scanContext}] Full scan already executed for this path`, {
|
|
23370
|
-
path:
|
|
23572
|
+
path: path26
|
|
23371
23573
|
});
|
|
23372
23574
|
return;
|
|
23373
23575
|
}
|
|
23374
23576
|
configStore.set("fullScanPathsScanned", [
|
|
23375
23577
|
...this.fullScanPathsScanned,
|
|
23376
|
-
|
|
23578
|
+
path26
|
|
23377
23579
|
]);
|
|
23378
23580
|
try {
|
|
23379
23581
|
await this.scanForSecurityVulnerabilities({
|
|
23380
|
-
path:
|
|
23582
|
+
path: path26,
|
|
23381
23583
|
isAllFilesScan: true,
|
|
23382
23584
|
isAllDetectionRulesScan: true,
|
|
23383
23585
|
scanContext: ScanContext.FULL_SCAN
|
|
23384
23586
|
});
|
|
23385
|
-
if (!this.fullScanPathsScanned.includes(
|
|
23386
|
-
this.fullScanPathsScanned.push(
|
|
23587
|
+
if (!this.fullScanPathsScanned.includes(path26)) {
|
|
23588
|
+
this.fullScanPathsScanned.push(path26);
|
|
23387
23589
|
configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
|
|
23388
23590
|
}
|
|
23389
|
-
logInfo(`[${scanContext}] Full scan completed`, { path:
|
|
23591
|
+
logInfo(`[${scanContext}] Full scan completed`, { path: path26 });
|
|
23390
23592
|
} catch (error) {
|
|
23391
23593
|
logError(`[${scanContext}] Error during initial full security scan`, {
|
|
23392
23594
|
error
|
|
23393
23595
|
});
|
|
23394
23596
|
}
|
|
23395
23597
|
}
|
|
23396
|
-
executeInitialScan(
|
|
23598
|
+
executeInitialScan(path26) {
|
|
23397
23599
|
const scanContext = ScanContext.BACKGROUND_INITIAL;
|
|
23398
|
-
logDebug(`[${scanContext}] Triggering initial security scan`, { path:
|
|
23600
|
+
logDebug(`[${scanContext}] Triggering initial security scan`, { path: path26 });
|
|
23399
23601
|
this.scanForSecurityVulnerabilities({
|
|
23400
|
-
path:
|
|
23602
|
+
path: path26,
|
|
23401
23603
|
scanContext: ScanContext.BACKGROUND_INITIAL
|
|
23402
23604
|
}).catch((error) => {
|
|
23403
23605
|
logError(`[${scanContext}] Error during initial security scan`, { error });
|
|
@@ -23494,9 +23696,9 @@ Example payload:
|
|
|
23494
23696
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
23495
23697
|
);
|
|
23496
23698
|
}
|
|
23497
|
-
const
|
|
23699
|
+
const path26 = pathValidationResult.path;
|
|
23498
23700
|
const resultText = await this.newFixesService.getFreshFixes({
|
|
23499
|
-
path:
|
|
23701
|
+
path: path26
|
|
23500
23702
|
});
|
|
23501
23703
|
logInfo("CheckForNewAvailableFixesTool execution completed", {
|
|
23502
23704
|
resultText
|
|
@@ -23674,8 +23876,8 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
23674
23876
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
23675
23877
|
);
|
|
23676
23878
|
}
|
|
23677
|
-
const
|
|
23678
|
-
const gitService = new GitService(
|
|
23879
|
+
const path26 = pathValidationResult.path;
|
|
23880
|
+
const gitService = new GitService(path26, log);
|
|
23679
23881
|
const gitValidation = await gitService.validateRepository();
|
|
23680
23882
|
if (!gitValidation.isValid) {
|
|
23681
23883
|
throw new Error(`Invalid git repository: ${gitValidation.error}`);
|
|
@@ -24060,9 +24262,9 @@ Example payload:
|
|
|
24060
24262
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
24061
24263
|
);
|
|
24062
24264
|
}
|
|
24063
|
-
const
|
|
24265
|
+
const path26 = pathValidationResult.path;
|
|
24064
24266
|
const files = await getLocalFiles({
|
|
24065
|
-
path:
|
|
24267
|
+
path: path26,
|
|
24066
24268
|
maxFileSize: MCP_MAX_FILE_SIZE,
|
|
24067
24269
|
maxFiles: args.maxFiles,
|
|
24068
24270
|
scanContext: ScanContext.USER_REQUEST,
|
|
@@ -24082,7 +24284,7 @@ Example payload:
|
|
|
24082
24284
|
try {
|
|
24083
24285
|
const fixResult = await this.vulnerabilityFixService.processVulnerabilities({
|
|
24084
24286
|
fileList: files.map((file) => file.relativePath),
|
|
24085
|
-
repositoryPath:
|
|
24287
|
+
repositoryPath: path26,
|
|
24086
24288
|
offset: args.offset,
|
|
24087
24289
|
limit: args.limit,
|
|
24088
24290
|
isRescan: args.rescan || !!args.maxFiles
|
|
@@ -24186,33 +24388,33 @@ var mcpHandler = async (_args) => {
|
|
|
24186
24388
|
};
|
|
24187
24389
|
|
|
24188
24390
|
// src/args/commands/review.ts
|
|
24189
|
-
import
|
|
24190
|
-
import
|
|
24391
|
+
import fs24 from "fs";
|
|
24392
|
+
import chalk12 from "chalk";
|
|
24191
24393
|
function reviewBuilder(yargs2) {
|
|
24192
24394
|
return yargs2.option("f", {
|
|
24193
24395
|
alias: "scan-file",
|
|
24194
24396
|
demandOption: true,
|
|
24195
24397
|
type: "string",
|
|
24196
|
-
describe:
|
|
24398
|
+
describe: chalk12.bold(
|
|
24197
24399
|
"Select the vulnerability report to analyze (Checkmarx, Snyk, Fortify, CodeQL, Sonarqube, Semgrep)"
|
|
24198
24400
|
)
|
|
24199
24401
|
}).option("repo", { ...repoOption, demandOption: true }).option("scanner", { ...scannerOptions, demandOption: true }).option("ref", { ...refOption, demandOption: true }).option("ch", {
|
|
24200
24402
|
alias: "commit-hash",
|
|
24201
|
-
describe:
|
|
24403
|
+
describe: chalk12.bold("Hash of the commit"),
|
|
24202
24404
|
type: "string",
|
|
24203
24405
|
demandOption: true
|
|
24204
24406
|
}).option("mobb-project-name", mobbProjectNameOption).option("api-key", { ...apiKeyOption, demandOption: true }).option("commit-hash", { ...commitHashOption, demandOption: true }).option("github-token", {
|
|
24205
|
-
describe:
|
|
24407
|
+
describe: chalk12.bold("Github action token"),
|
|
24206
24408
|
type: "string",
|
|
24207
24409
|
demandOption: true
|
|
24208
24410
|
}).option("pull-request", {
|
|
24209
24411
|
alias: ["pr", "pr-number", "pr-id"],
|
|
24210
|
-
describe:
|
|
24412
|
+
describe: chalk12.bold("Number of the pull request"),
|
|
24211
24413
|
type: "number",
|
|
24212
24414
|
demandOption: true
|
|
24213
24415
|
}).option("p", {
|
|
24214
24416
|
alias: "src-path",
|
|
24215
|
-
describe:
|
|
24417
|
+
describe: chalk12.bold(
|
|
24216
24418
|
"Path to the repository folder with the source code"
|
|
24217
24419
|
),
|
|
24218
24420
|
type: "string",
|
|
@@ -24223,9 +24425,9 @@ function reviewBuilder(yargs2) {
|
|
|
24223
24425
|
).help();
|
|
24224
24426
|
}
|
|
24225
24427
|
function validateReviewOptions(argv) {
|
|
24226
|
-
if (!
|
|
24428
|
+
if (!fs24.existsSync(argv.f)) {
|
|
24227
24429
|
throw new CliError(`
|
|
24228
|
-
Can't access ${
|
|
24430
|
+
Can't access ${chalk12.bold(argv.f)}`);
|
|
24229
24431
|
}
|
|
24230
24432
|
validateRepoUrl(argv);
|
|
24231
24433
|
validateReportFileFormat(argv.f);
|
|
@@ -24260,6 +24462,27 @@ async function scanHandler(args) {
|
|
|
24260
24462
|
await scan(args, { skipPrompts: args.yes });
|
|
24261
24463
|
}
|
|
24262
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
|
+
|
|
24263
24486
|
// src/args/commands/token.ts
|
|
24264
24487
|
function addScmTokenBuilder(args) {
|
|
24265
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(
|
|
@@ -24301,10 +24524,10 @@ init_client_generates();
|
|
|
24301
24524
|
init_urlParser2();
|
|
24302
24525
|
|
|
24303
24526
|
// src/features/codeium_intellij/codeium_language_server_grpc_client.ts
|
|
24304
|
-
import
|
|
24527
|
+
import path23 from "path";
|
|
24305
24528
|
import * as grpc from "@grpc/grpc-js";
|
|
24306
24529
|
import * as protoLoader from "@grpc/proto-loader";
|
|
24307
|
-
var PROTO_PATH =
|
|
24530
|
+
var PROTO_PATH = path23.join(
|
|
24308
24531
|
getModuleRootDir(),
|
|
24309
24532
|
"src/features/codeium_intellij/proto/exa/language_server_pb/language_server.proto"
|
|
24310
24533
|
);
|
|
@@ -24316,7 +24539,7 @@ function loadProto() {
|
|
|
24316
24539
|
defaults: true,
|
|
24317
24540
|
oneofs: true,
|
|
24318
24541
|
includeDirs: [
|
|
24319
|
-
|
|
24542
|
+
path23.join(getModuleRootDir(), "src/features/codeium_intellij/proto")
|
|
24320
24543
|
]
|
|
24321
24544
|
});
|
|
24322
24545
|
return grpc.loadPackageDefinition(
|
|
@@ -24370,30 +24593,30 @@ async function getGrpcClient(port, csrf3) {
|
|
|
24370
24593
|
}
|
|
24371
24594
|
|
|
24372
24595
|
// src/features/codeium_intellij/parse_intellij_logs.ts
|
|
24373
|
-
import
|
|
24596
|
+
import fs25 from "fs";
|
|
24374
24597
|
import os12 from "os";
|
|
24375
|
-
import
|
|
24598
|
+
import path24 from "path";
|
|
24376
24599
|
function getLogsDir() {
|
|
24377
24600
|
if (process.platform === "darwin") {
|
|
24378
|
-
return
|
|
24601
|
+
return path24.join(os12.homedir(), "Library/Logs/JetBrains");
|
|
24379
24602
|
} else if (process.platform === "win32") {
|
|
24380
|
-
return
|
|
24381
|
-
process.env["LOCALAPPDATA"] ||
|
|
24603
|
+
return path24.join(
|
|
24604
|
+
process.env["LOCALAPPDATA"] || path24.join(os12.homedir(), "AppData/Local"),
|
|
24382
24605
|
"JetBrains"
|
|
24383
24606
|
);
|
|
24384
24607
|
} else {
|
|
24385
|
-
return
|
|
24608
|
+
return path24.join(os12.homedir(), ".cache/JetBrains");
|
|
24386
24609
|
}
|
|
24387
24610
|
}
|
|
24388
24611
|
function parseIdeLogDir(ideLogDir) {
|
|
24389
|
-
const logFiles =
|
|
24612
|
+
const logFiles = fs25.readdirSync(ideLogDir).filter((f) => /^idea(\.\d+)?\.log$/.test(f)).map((f) => ({
|
|
24390
24613
|
name: f,
|
|
24391
|
-
mtime:
|
|
24614
|
+
mtime: fs25.statSync(path24.join(ideLogDir, f)).mtimeMs
|
|
24392
24615
|
})).sort((a, b) => a.mtime - b.mtime).map((f) => f.name);
|
|
24393
24616
|
let latestCsrf = null;
|
|
24394
24617
|
let latestPort = null;
|
|
24395
24618
|
for (const logFile of logFiles) {
|
|
24396
|
-
const lines =
|
|
24619
|
+
const lines = fs25.readFileSync(path24.join(ideLogDir, logFile), "utf-8").split("\n");
|
|
24397
24620
|
for (const line of lines) {
|
|
24398
24621
|
if (!line.includes(
|
|
24399
24622
|
"com.codeium.intellij.language_server.LanguageServerProcessHandler"
|
|
@@ -24419,13 +24642,13 @@ function parseIdeLogDir(ideLogDir) {
|
|
|
24419
24642
|
function findRunningCodeiumLanguageServers() {
|
|
24420
24643
|
const results = [];
|
|
24421
24644
|
const logsDir = getLogsDir();
|
|
24422
|
-
if (!
|
|
24423
|
-
for (const ide of
|
|
24424
|
-
let ideLogDir =
|
|
24645
|
+
if (!fs25.existsSync(logsDir)) return results;
|
|
24646
|
+
for (const ide of fs25.readdirSync(logsDir)) {
|
|
24647
|
+
let ideLogDir = path24.join(logsDir, ide);
|
|
24425
24648
|
if (process.platform !== "darwin") {
|
|
24426
|
-
ideLogDir =
|
|
24649
|
+
ideLogDir = path24.join(ideLogDir, "log");
|
|
24427
24650
|
}
|
|
24428
|
-
if (!
|
|
24651
|
+
if (!fs25.existsSync(ideLogDir) || !fs25.statSync(ideLogDir).isDirectory()) {
|
|
24429
24652
|
continue;
|
|
24430
24653
|
}
|
|
24431
24654
|
const result = parseIdeLogDir(ideLogDir);
|
|
@@ -24606,10 +24829,10 @@ function processChatStepCodeAction(step) {
|
|
|
24606
24829
|
// src/features/codeium_intellij/install_hook.ts
|
|
24607
24830
|
import fsPromises6 from "fs/promises";
|
|
24608
24831
|
import os13 from "os";
|
|
24609
|
-
import
|
|
24610
|
-
import
|
|
24832
|
+
import path25 from "path";
|
|
24833
|
+
import chalk14 from "chalk";
|
|
24611
24834
|
function getCodeiumHooksPath() {
|
|
24612
|
-
return
|
|
24835
|
+
return path25.join(os13.homedir(), ".codeium", "hooks.json");
|
|
24613
24836
|
}
|
|
24614
24837
|
async function readCodeiumHooks() {
|
|
24615
24838
|
const hooksPath = getCodeiumHooksPath();
|
|
@@ -24622,7 +24845,7 @@ async function readCodeiumHooks() {
|
|
|
24622
24845
|
}
|
|
24623
24846
|
async function writeCodeiumHooks(config2) {
|
|
24624
24847
|
const hooksPath = getCodeiumHooksPath();
|
|
24625
|
-
const dir =
|
|
24848
|
+
const dir = path25.dirname(hooksPath);
|
|
24626
24849
|
await fsPromises6.mkdir(dir, { recursive: true });
|
|
24627
24850
|
await fsPromises6.writeFile(
|
|
24628
24851
|
hooksPath,
|
|
@@ -24632,7 +24855,7 @@ async function writeCodeiumHooks(config2) {
|
|
|
24632
24855
|
}
|
|
24633
24856
|
async function installWindsurfHooks(options = {}) {
|
|
24634
24857
|
const hooksPath = getCodeiumHooksPath();
|
|
24635
|
-
console.log(
|
|
24858
|
+
console.log(chalk14.blue("Installing Mobb hooks in Windsurf IntelliJ..."));
|
|
24636
24859
|
const config2 = await readCodeiumHooks();
|
|
24637
24860
|
if (!config2.hooks) {
|
|
24638
24861
|
config2.hooks = {};
|
|
@@ -24652,7 +24875,7 @@ async function installWindsurfHooks(options = {}) {
|
|
|
24652
24875
|
if (envVars.length > 0) {
|
|
24653
24876
|
command = `${envVars.join(" ")} ${command}`;
|
|
24654
24877
|
console.log(
|
|
24655
|
-
|
|
24878
|
+
chalk14.blue(
|
|
24656
24879
|
`Adding environment variables to hook command: ${envVars.join(", ")}`
|
|
24657
24880
|
)
|
|
24658
24881
|
);
|
|
@@ -24666,15 +24889,15 @@ async function installWindsurfHooks(options = {}) {
|
|
|
24666
24889
|
(hook) => hook.command?.includes("mobbdev@latest windsurf-intellij-process-hook")
|
|
24667
24890
|
);
|
|
24668
24891
|
if (existingHookIndex >= 0) {
|
|
24669
|
-
console.log(
|
|
24892
|
+
console.log(chalk14.yellow("Mobb hook already exists, updating..."));
|
|
24670
24893
|
config2.hooks.post_write_code[existingHookIndex] = mobbHook;
|
|
24671
24894
|
} else {
|
|
24672
|
-
console.log(
|
|
24895
|
+
console.log(chalk14.green("Adding new Mobb hook..."));
|
|
24673
24896
|
config2.hooks.post_write_code.push(mobbHook);
|
|
24674
24897
|
}
|
|
24675
24898
|
await writeCodeiumHooks(config2);
|
|
24676
24899
|
console.log(
|
|
24677
|
-
|
|
24900
|
+
chalk14.green(
|
|
24678
24901
|
`\u2705 Mobb hooks ${options.saveEnv ? "and environment variables " : ""}installed successfully in ${hooksPath}`
|
|
24679
24902
|
)
|
|
24680
24903
|
);
|
|
@@ -24724,81 +24947,86 @@ var windsurfIntellijProcessHookHandler = async () => {
|
|
|
24724
24947
|
var parseArgs = async (args) => {
|
|
24725
24948
|
const yargsInstance = yargs(args);
|
|
24726
24949
|
return yargsInstance.updateStrings({
|
|
24727
|
-
"Commands:":
|
|
24728
|
-
"Options:":
|
|
24729
|
-
"Examples:":
|
|
24730
|
-
"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")
|
|
24731
24954
|
}).usage(
|
|
24732
|
-
`${
|
|
24955
|
+
`${chalk15.bold(
|
|
24733
24956
|
"\n Bugsy - Trusted, Automatic Vulnerability Fixer \u{1F575}\uFE0F\u200D\u2642\uFE0F\n\n"
|
|
24734
|
-
)} ${
|
|
24735
|
-
$0 ${
|
|
24957
|
+
)} ${chalk15.yellow.underline.bold("Usage:")}
|
|
24958
|
+
$0 ${chalk15.green(
|
|
24736
24959
|
"<command>"
|
|
24737
|
-
)} ${
|
|
24960
|
+
)} ${chalk15.dim("[options]")}
|
|
24738
24961
|
`
|
|
24739
24962
|
).version(false).command(
|
|
24740
24963
|
mobbCliCommand.scan,
|
|
24741
|
-
|
|
24964
|
+
chalk15.bold(
|
|
24742
24965
|
"Scan your code for vulnerabilities, get automated fixes right away."
|
|
24743
24966
|
),
|
|
24744
24967
|
scanBuilder,
|
|
24745
24968
|
scanHandler
|
|
24746
24969
|
).command(
|
|
24747
24970
|
mobbCliCommand.analyze,
|
|
24748
|
-
|
|
24971
|
+
chalk15.bold(
|
|
24749
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."
|
|
24750
24973
|
),
|
|
24751
24974
|
analyzeBuilder,
|
|
24752
24975
|
analyzeHandler
|
|
24753
24976
|
).command(
|
|
24754
24977
|
mobbCliCommand.review,
|
|
24755
|
-
|
|
24978
|
+
chalk15.bold(
|
|
24756
24979
|
"Mobb will review your github pull requests and provide comments with fixes "
|
|
24757
24980
|
),
|
|
24758
24981
|
reviewBuilder,
|
|
24759
24982
|
reviewHandler
|
|
24760
24983
|
).command(
|
|
24761
24984
|
mobbCliCommand.addScmToken,
|
|
24762
|
-
|
|
24985
|
+
chalk15.bold(
|
|
24763
24986
|
"Add your SCM (Github, Gitlab, Azure DevOps) token to Mobb to enable automated fixes."
|
|
24764
24987
|
),
|
|
24765
24988
|
addScmTokenBuilder,
|
|
24766
24989
|
addScmTokenHandler
|
|
24990
|
+
).command(
|
|
24991
|
+
mobbCliCommand.scanSkill,
|
|
24992
|
+
chalk15.bold("Scan an OpenClaw/ClawHub skill for security threats."),
|
|
24993
|
+
scanSkillBuilder,
|
|
24994
|
+
scanSkillHandler
|
|
24767
24995
|
).command(
|
|
24768
24996
|
mobbCliCommand.convertToSarif,
|
|
24769
|
-
|
|
24997
|
+
chalk15.bold("Convert an existing SAST report to SARIF format."),
|
|
24770
24998
|
convertToSarifBuilder,
|
|
24771
24999
|
convertToSarifHandler
|
|
24772
25000
|
).command(
|
|
24773
25001
|
mobbCliCommand.mcp,
|
|
24774
|
-
|
|
25002
|
+
chalk15.bold("Launch the MCP (Model Context Protocol) server."),
|
|
24775
25003
|
mcpBuilder,
|
|
24776
25004
|
mcpHandler
|
|
24777
25005
|
).command(
|
|
24778
25006
|
mobbCliCommand.uploadAiBlame,
|
|
24779
|
-
|
|
25007
|
+
chalk15.bold(
|
|
24780
25008
|
"Upload AI Blame inference artifacts (prompt + inference) and finalize them."
|
|
24781
25009
|
),
|
|
24782
25010
|
uploadAiBlameBuilder,
|
|
24783
25011
|
uploadAiBlameCommandHandler
|
|
24784
25012
|
).command(
|
|
24785
25013
|
mobbCliCommand.claudeCodeInstallHook,
|
|
24786
|
-
|
|
25014
|
+
chalk15.bold("Install Claude Code hooks for data collection."),
|
|
24787
25015
|
claudeCodeInstallHookBuilder,
|
|
24788
25016
|
claudeCodeInstallHookHandler
|
|
24789
25017
|
).command(
|
|
24790
25018
|
mobbCliCommand.claudeCodeProcessHook,
|
|
24791
|
-
|
|
25019
|
+
chalk15.bold("Process Claude Code hook data and upload to backend."),
|
|
24792
25020
|
claudeCodeProcessHookBuilder,
|
|
24793
25021
|
claudeCodeProcessHookHandler
|
|
24794
25022
|
).command(
|
|
24795
25023
|
mobbCliCommand.windsurfIntellijInstallHook,
|
|
24796
|
-
|
|
25024
|
+
chalk15.bold("Install Windsurf IntelliJ hooks for data collection."),
|
|
24797
25025
|
windsurfIntellijInstallHookBuilder,
|
|
24798
25026
|
windsurfIntellijInstallHookHandler
|
|
24799
25027
|
).command(
|
|
24800
25028
|
mobbCliCommand.windsurfIntellijProcessHook,
|
|
24801
|
-
|
|
25029
|
+
chalk15.bold("Process Windsurf IntelliJ hook data and upload to backend."),
|
|
24802
25030
|
windsurfIntellijProcessHookBuilder,
|
|
24803
25031
|
windsurfIntellijProcessHookHandler
|
|
24804
25032
|
).example(
|
|
@@ -24809,7 +25037,7 @@ var parseArgs = async (args) => {
|
|
|
24809
25037
|
handler() {
|
|
24810
25038
|
yargsInstance.showHelp();
|
|
24811
25039
|
}
|
|
24812
|
-
}).strictOptions().help("h").alias("h", "help").epilog(
|
|
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();
|
|
24813
25041
|
};
|
|
24814
25042
|
|
|
24815
25043
|
// src/index.ts
|