mobbdev 1.0.217 → 1.1.0
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 +956 -486
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1323,7 +1323,7 @@ import Debug20 from "debug";
|
|
|
1323
1323
|
import { hideBin } from "yargs/helpers";
|
|
1324
1324
|
|
|
1325
1325
|
// src/args/yargs.ts
|
|
1326
|
-
import
|
|
1326
|
+
import chalk12 from "chalk";
|
|
1327
1327
|
import yargs from "yargs/yargs";
|
|
1328
1328
|
|
|
1329
1329
|
// src/args/commands/convert_to_sarif.ts
|
|
@@ -6247,7 +6247,7 @@ async function getAdoSdk(params) {
|
|
|
6247
6247
|
const url = new URL(repoUrl);
|
|
6248
6248
|
const origin2 = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
|
|
6249
6249
|
const params2 = `path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
|
|
6250
|
-
const
|
|
6250
|
+
const path22 = [
|
|
6251
6251
|
prefixPath,
|
|
6252
6252
|
owner,
|
|
6253
6253
|
projectName,
|
|
@@ -6258,7 +6258,7 @@ async function getAdoSdk(params) {
|
|
|
6258
6258
|
"items",
|
|
6259
6259
|
"items"
|
|
6260
6260
|
].filter(Boolean).join("/");
|
|
6261
|
-
return new URL(`${
|
|
6261
|
+
return new URL(`${path22}?${params2}`, origin2).toString();
|
|
6262
6262
|
},
|
|
6263
6263
|
async getAdoBranchList({ repoUrl }) {
|
|
6264
6264
|
try {
|
|
@@ -7805,14 +7805,14 @@ function getGithubSdk(params = {}) {
|
|
|
7805
7805
|
};
|
|
7806
7806
|
},
|
|
7807
7807
|
async getGithubBlameRanges(params2) {
|
|
7808
|
-
const { ref, gitHubUrl, path:
|
|
7808
|
+
const { ref, gitHubUrl, path: path22 } = params2;
|
|
7809
7809
|
const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
|
|
7810
7810
|
const res = await octokit.graphql(
|
|
7811
7811
|
GET_BLAME_DOCUMENT,
|
|
7812
7812
|
{
|
|
7813
7813
|
owner,
|
|
7814
7814
|
repo,
|
|
7815
|
-
path:
|
|
7815
|
+
path: path22,
|
|
7816
7816
|
ref
|
|
7817
7817
|
}
|
|
7818
7818
|
);
|
|
@@ -8179,11 +8179,11 @@ var GithubSCMLib = class extends SCMLib {
|
|
|
8179
8179
|
markdownComment: comment
|
|
8180
8180
|
});
|
|
8181
8181
|
}
|
|
8182
|
-
async getRepoBlameRanges(ref,
|
|
8182
|
+
async getRepoBlameRanges(ref, path22) {
|
|
8183
8183
|
this._validateUrl();
|
|
8184
8184
|
return await this.githubSdk.getGithubBlameRanges({
|
|
8185
8185
|
ref,
|
|
8186
|
-
path:
|
|
8186
|
+
path: path22,
|
|
8187
8187
|
gitHubUrl: this.url
|
|
8188
8188
|
});
|
|
8189
8189
|
}
|
|
@@ -8863,13 +8863,13 @@ function parseGitlabOwnerAndRepo(gitlabUrl) {
|
|
|
8863
8863
|
const { organization, repoName, projectPath } = parsingResult;
|
|
8864
8864
|
return { owner: organization, repo: repoName, projectPath };
|
|
8865
8865
|
}
|
|
8866
|
-
async function getGitlabBlameRanges({ ref, gitlabUrl, path:
|
|
8866
|
+
async function getGitlabBlameRanges({ ref, gitlabUrl, path: path22 }, options) {
|
|
8867
8867
|
const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
|
|
8868
8868
|
const api2 = getGitBeaker({
|
|
8869
8869
|
url: gitlabUrl,
|
|
8870
8870
|
gitlabAuthToken: options?.gitlabAuthToken
|
|
8871
8871
|
});
|
|
8872
|
-
const resp = await api2.RepositoryFiles.allFileBlames(projectPath,
|
|
8872
|
+
const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path22, ref);
|
|
8873
8873
|
let lineNumber = 1;
|
|
8874
8874
|
return resp.filter((range) => range.lines).map((range) => {
|
|
8875
8875
|
const oldLineNumber = lineNumber;
|
|
@@ -9046,10 +9046,10 @@ var GitlabSCMLib = class extends SCMLib {
|
|
|
9046
9046
|
markdownComment: comment
|
|
9047
9047
|
});
|
|
9048
9048
|
}
|
|
9049
|
-
async getRepoBlameRanges(ref,
|
|
9049
|
+
async getRepoBlameRanges(ref, path22) {
|
|
9050
9050
|
this._validateUrl();
|
|
9051
9051
|
return await getGitlabBlameRanges(
|
|
9052
|
-
{ ref, path:
|
|
9052
|
+
{ ref, path: path22, gitlabUrl: this.url },
|
|
9053
9053
|
{
|
|
9054
9054
|
url: this.url,
|
|
9055
9055
|
gitlabAuthToken: this.accessToken
|
|
@@ -10051,7 +10051,9 @@ var mobbCliCommand = {
|
|
|
10051
10051
|
review: "review",
|
|
10052
10052
|
convertToSarif: "convert-to-sarif",
|
|
10053
10053
|
mcp: "mcp",
|
|
10054
|
-
uploadAiBlame: "upload-ai-blame"
|
|
10054
|
+
uploadAiBlame: "upload-ai-blame",
|
|
10055
|
+
claudeCodeInstallHook: "claude-code-install-hook",
|
|
10056
|
+
claudeCodeProcessHook: "claude-code-process-hook"
|
|
10055
10057
|
};
|
|
10056
10058
|
var ScanContext = {
|
|
10057
10059
|
FULL_SCAN: "FULL_SCAN",
|
|
@@ -11088,7 +11090,7 @@ async function postIssueComment(params) {
|
|
|
11088
11090
|
fpDescription
|
|
11089
11091
|
} = params;
|
|
11090
11092
|
const {
|
|
11091
|
-
path:
|
|
11093
|
+
path: path22,
|
|
11092
11094
|
startLine,
|
|
11093
11095
|
vulnerabilityReportIssue: {
|
|
11094
11096
|
vulnerabilityReportIssueTags,
|
|
@@ -11103,7 +11105,7 @@ async function postIssueComment(params) {
|
|
|
11103
11105
|
Refresh the page in order to see the changes.`,
|
|
11104
11106
|
pull_number: pullRequest,
|
|
11105
11107
|
commit_id: commitSha,
|
|
11106
|
-
path:
|
|
11108
|
+
path: path22,
|
|
11107
11109
|
line: startLine
|
|
11108
11110
|
});
|
|
11109
11111
|
const commentId = commentRes.data.id;
|
|
@@ -11137,7 +11139,7 @@ async function postFixComment(params) {
|
|
|
11137
11139
|
scanner
|
|
11138
11140
|
} = params;
|
|
11139
11141
|
const {
|
|
11140
|
-
path:
|
|
11142
|
+
path: path22,
|
|
11141
11143
|
startLine,
|
|
11142
11144
|
vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
|
|
11143
11145
|
vulnerabilityReportIssueId
|
|
@@ -11155,7 +11157,7 @@ async function postFixComment(params) {
|
|
|
11155
11157
|
Refresh the page in order to see the changes.`,
|
|
11156
11158
|
pull_number: pullRequest,
|
|
11157
11159
|
commit_id: commitSha,
|
|
11158
|
-
path:
|
|
11160
|
+
path: path22,
|
|
11159
11161
|
line: startLine
|
|
11160
11162
|
});
|
|
11161
11163
|
const commentId = commentRes.data.id;
|
|
@@ -11736,8 +11738,8 @@ if (typeof __filename !== "undefined") {
|
|
|
11736
11738
|
}
|
|
11737
11739
|
var costumeRequire = createRequire(moduleUrl);
|
|
11738
11740
|
var getCheckmarxPath = () => {
|
|
11739
|
-
const
|
|
11740
|
-
const cxFileName =
|
|
11741
|
+
const os10 = type();
|
|
11742
|
+
const cxFileName = os10 === "Windows_NT" ? "cx.exe" : "cx";
|
|
11741
11743
|
try {
|
|
11742
11744
|
return costumeRequire.resolve(`.bin/${cxFileName}`);
|
|
11743
11745
|
} catch (e) {
|
|
@@ -11881,8 +11883,8 @@ async function forkSnyk(args, { display }) {
|
|
|
11881
11883
|
}
|
|
11882
11884
|
async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
11883
11885
|
debug17("get snyk report start %s %s", reportPath, repoRoot);
|
|
11884
|
-
const
|
|
11885
|
-
const { message: configMessage } =
|
|
11886
|
+
const config7 = await forkSnyk(["config"], { display: false });
|
|
11887
|
+
const { message: configMessage } = config7;
|
|
11886
11888
|
if (!configMessage.includes("api: ")) {
|
|
11887
11889
|
const snykLoginSpinner = createSpinner3().start();
|
|
11888
11890
|
if (!skipPrompts) {
|
|
@@ -11894,7 +11896,7 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
|
11894
11896
|
snykLoginSpinner.update({
|
|
11895
11897
|
text: "\u{1F513} Waiting for Snyk login to complete"
|
|
11896
11898
|
});
|
|
11897
|
-
debug17("no token in the config %s",
|
|
11899
|
+
debug17("no token in the config %s", config7);
|
|
11898
11900
|
await forkSnyk(["auth"], { display: true });
|
|
11899
11901
|
snykLoginSpinner.success({ text: "\u{1F513} Login to Snyk Successful" });
|
|
11900
11902
|
}
|
|
@@ -12894,6 +12896,645 @@ async function analyzeHandler(args) {
|
|
|
12894
12896
|
await analyze(args, { skipPrompts: args.yes });
|
|
12895
12897
|
}
|
|
12896
12898
|
|
|
12899
|
+
// src/args/commands/claude_code.ts
|
|
12900
|
+
import Configstore5 from "configstore";
|
|
12901
|
+
|
|
12902
|
+
// src/features/claude_code/data_collector.ts
|
|
12903
|
+
import { z as z32 } from "zod";
|
|
12904
|
+
|
|
12905
|
+
// src/args/commands/upload_ai_blame.ts
|
|
12906
|
+
import fsPromises3 from "fs/promises";
|
|
12907
|
+
import path11 from "path";
|
|
12908
|
+
import chalk9 from "chalk";
|
|
12909
|
+
import Configstore4 from "configstore";
|
|
12910
|
+
import { withFile } from "tmp-promise";
|
|
12911
|
+
import z31 from "zod";
|
|
12912
|
+
var PromptItemZ = z31.object({
|
|
12913
|
+
type: z31.enum(["USER_PROMPT", "AI_RESPONSE", "TOOL_EXECUTION", "AI_THINKING"]),
|
|
12914
|
+
attachedFiles: z31.array(
|
|
12915
|
+
z31.object({
|
|
12916
|
+
relativePath: z31.string(),
|
|
12917
|
+
startLine: z31.number().optional()
|
|
12918
|
+
})
|
|
12919
|
+
).optional(),
|
|
12920
|
+
tokens: z31.object({
|
|
12921
|
+
inputCount: z31.number(),
|
|
12922
|
+
outputCount: z31.number()
|
|
12923
|
+
}).optional(),
|
|
12924
|
+
text: z31.string().optional(),
|
|
12925
|
+
date: z31.date().optional(),
|
|
12926
|
+
tool: z31.object({
|
|
12927
|
+
name: z31.string(),
|
|
12928
|
+
parameters: z31.string(),
|
|
12929
|
+
result: z31.string(),
|
|
12930
|
+
rawArguments: z31.string().optional(),
|
|
12931
|
+
accepted: z31.boolean().optional()
|
|
12932
|
+
}).optional()
|
|
12933
|
+
});
|
|
12934
|
+
var PromptItemArrayZ = z31.array(PromptItemZ);
|
|
12935
|
+
function uploadAiBlameBuilder(args) {
|
|
12936
|
+
return args.option("prompt", {
|
|
12937
|
+
type: "string",
|
|
12938
|
+
array: true,
|
|
12939
|
+
demandOption: true,
|
|
12940
|
+
describe: chalk9.bold("Path(s) to prompt artifact(s) (one per session)")
|
|
12941
|
+
}).option("inference", {
|
|
12942
|
+
type: "string",
|
|
12943
|
+
array: true,
|
|
12944
|
+
demandOption: true,
|
|
12945
|
+
describe: chalk9.bold(
|
|
12946
|
+
"Path(s) to inference artifact(s) (one per session)"
|
|
12947
|
+
)
|
|
12948
|
+
}).option("ai-response-at", {
|
|
12949
|
+
type: "string",
|
|
12950
|
+
array: true,
|
|
12951
|
+
describe: chalk9.bold(
|
|
12952
|
+
"ISO timestamp(s) for AI response (one per session, defaults to now)"
|
|
12953
|
+
)
|
|
12954
|
+
}).option("model", {
|
|
12955
|
+
type: "string",
|
|
12956
|
+
array: true,
|
|
12957
|
+
describe: chalk9.bold("AI model name(s) (optional, one per session)")
|
|
12958
|
+
}).option("tool-name", {
|
|
12959
|
+
type: "string",
|
|
12960
|
+
array: true,
|
|
12961
|
+
describe: chalk9.bold("Tool/IDE name(s) (optional, one per session)")
|
|
12962
|
+
}).option("blame-type", {
|
|
12963
|
+
type: "string",
|
|
12964
|
+
array: true,
|
|
12965
|
+
choices: Object.values(AiBlameInferenceType),
|
|
12966
|
+
describe: chalk9.bold(
|
|
12967
|
+
"Blame type(s) (optional, one per session, defaults to CHAT)"
|
|
12968
|
+
)
|
|
12969
|
+
}).strict();
|
|
12970
|
+
}
|
|
12971
|
+
async function uploadAiBlameHandlerFromExtension(args) {
|
|
12972
|
+
const uploadArgs = {
|
|
12973
|
+
prompt: [],
|
|
12974
|
+
inference: [],
|
|
12975
|
+
model: [],
|
|
12976
|
+
toolName: [],
|
|
12977
|
+
aiResponseAt: [],
|
|
12978
|
+
blameType: []
|
|
12979
|
+
};
|
|
12980
|
+
await withFile(async (promptFile) => {
|
|
12981
|
+
await fsPromises3.writeFile(
|
|
12982
|
+
promptFile.path,
|
|
12983
|
+
JSON.stringify(args.prompts, null, 2),
|
|
12984
|
+
"utf-8"
|
|
12985
|
+
);
|
|
12986
|
+
uploadArgs.prompt.push(promptFile.path);
|
|
12987
|
+
await withFile(async (inferenceFile) => {
|
|
12988
|
+
await fsPromises3.writeFile(inferenceFile.path, args.inference, "utf-8");
|
|
12989
|
+
uploadArgs.inference.push(inferenceFile.path);
|
|
12990
|
+
uploadArgs.model.push(args.model);
|
|
12991
|
+
uploadArgs.toolName.push(args.tool);
|
|
12992
|
+
uploadArgs.aiResponseAt.push(args.responseTime);
|
|
12993
|
+
uploadArgs.blameType.push(args.blameType || "CHAT" /* Chat */);
|
|
12994
|
+
await uploadAiBlameHandler(uploadArgs, false);
|
|
12995
|
+
});
|
|
12996
|
+
});
|
|
12997
|
+
}
|
|
12998
|
+
var config5 = new Configstore4(packageJson.name, { apiToken: "" });
|
|
12999
|
+
async function getAuthenticatedGQLClientForIdeExtension() {
|
|
13000
|
+
let gqlClient = new GQLClient({
|
|
13001
|
+
apiKey: config5.get("apiToken") ?? "",
|
|
13002
|
+
type: "apiKey"
|
|
13003
|
+
});
|
|
13004
|
+
gqlClient = await handleMobbLogin({
|
|
13005
|
+
inGqlClient: gqlClient,
|
|
13006
|
+
skipPrompts: true
|
|
13007
|
+
});
|
|
13008
|
+
return gqlClient;
|
|
13009
|
+
}
|
|
13010
|
+
async function uploadAiBlameHandler(args, exitOnError = true) {
|
|
13011
|
+
const prompts = args.prompt || [];
|
|
13012
|
+
const inferences = args.inference || [];
|
|
13013
|
+
const models = args.model || [];
|
|
13014
|
+
const tools = args.toolName || args["tool-name"] || [];
|
|
13015
|
+
const responseTimes = args.aiResponseAt || args["ai-response-at"] || [];
|
|
13016
|
+
const blameTypes = args.blameType || args["blame-type"] || [];
|
|
13017
|
+
if (prompts.length !== inferences.length) {
|
|
13018
|
+
const errorMsg = "prompt and inference must have the same number of entries";
|
|
13019
|
+
console.error(chalk9.red(errorMsg));
|
|
13020
|
+
if (exitOnError) {
|
|
13021
|
+
process.exit(1);
|
|
13022
|
+
}
|
|
13023
|
+
throw new Error(errorMsg);
|
|
13024
|
+
}
|
|
13025
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
13026
|
+
const sessions = [];
|
|
13027
|
+
for (let i = 0; i < prompts.length; i++) {
|
|
13028
|
+
const promptPath = String(prompts[i]);
|
|
13029
|
+
const inferencePath = String(inferences[i]);
|
|
13030
|
+
try {
|
|
13031
|
+
await Promise.all([
|
|
13032
|
+
fsPromises3.access(promptPath),
|
|
13033
|
+
fsPromises3.access(inferencePath)
|
|
13034
|
+
]);
|
|
13035
|
+
} catch {
|
|
13036
|
+
const errorMsg = `File not found for session ${i + 1}`;
|
|
13037
|
+
console.error(chalk9.red(errorMsg));
|
|
13038
|
+
if (exitOnError) {
|
|
13039
|
+
process.exit(1);
|
|
13040
|
+
}
|
|
13041
|
+
throw new Error(errorMsg);
|
|
13042
|
+
}
|
|
13043
|
+
sessions.push({
|
|
13044
|
+
promptFileName: path11.basename(promptPath),
|
|
13045
|
+
inferenceFileName: path11.basename(inferencePath),
|
|
13046
|
+
aiResponseAt: responseTimes[i] || nowIso,
|
|
13047
|
+
model: models[i],
|
|
13048
|
+
toolName: tools[i],
|
|
13049
|
+
blameType: blameTypes[i] || "CHAT" /* Chat */
|
|
13050
|
+
});
|
|
13051
|
+
}
|
|
13052
|
+
const authenticatedClient = await getAuthenticatedGQLClientForIdeExtension();
|
|
13053
|
+
const initRes = await authenticatedClient.uploadAIBlameInferencesInitRaw({
|
|
13054
|
+
sessions
|
|
13055
|
+
});
|
|
13056
|
+
const uploadSessions = initRes.uploadAIBlameInferencesInit?.uploadSessions ?? [];
|
|
13057
|
+
if (uploadSessions.length !== sessions.length) {
|
|
13058
|
+
const errorMsg = "Init failed to return expected number of sessions";
|
|
13059
|
+
console.error(chalk9.red(errorMsg));
|
|
13060
|
+
if (exitOnError) {
|
|
13061
|
+
process.exit(1);
|
|
13062
|
+
}
|
|
13063
|
+
throw new Error(errorMsg);
|
|
13064
|
+
}
|
|
13065
|
+
for (let i = 0; i < uploadSessions.length; i++) {
|
|
13066
|
+
const us = uploadSessions[i];
|
|
13067
|
+
const promptPath = String(prompts[i]);
|
|
13068
|
+
const inferencePath = String(inferences[i]);
|
|
13069
|
+
await Promise.all([
|
|
13070
|
+
// Prompt
|
|
13071
|
+
uploadFile({
|
|
13072
|
+
file: promptPath,
|
|
13073
|
+
url: us.prompt.url,
|
|
13074
|
+
uploadFields: JSON.parse(us.prompt.uploadFieldsJSON),
|
|
13075
|
+
uploadKey: us.prompt.uploadKey
|
|
13076
|
+
}),
|
|
13077
|
+
// Inference
|
|
13078
|
+
uploadFile({
|
|
13079
|
+
file: inferencePath,
|
|
13080
|
+
url: us.inference.url,
|
|
13081
|
+
uploadFields: JSON.parse(us.inference.uploadFieldsJSON),
|
|
13082
|
+
uploadKey: us.inference.uploadKey
|
|
13083
|
+
})
|
|
13084
|
+
]);
|
|
13085
|
+
}
|
|
13086
|
+
const finalizeSessions = uploadSessions.map((us, i) => {
|
|
13087
|
+
const s = sessions[i];
|
|
13088
|
+
return {
|
|
13089
|
+
aiBlameInferenceId: us.aiBlameInferenceId,
|
|
13090
|
+
promptKey: us.prompt.uploadKey,
|
|
13091
|
+
inferenceKey: us.inference.uploadKey,
|
|
13092
|
+
aiResponseAt: s.aiResponseAt,
|
|
13093
|
+
model: s.model,
|
|
13094
|
+
toolName: s.toolName,
|
|
13095
|
+
blameType: s.blameType
|
|
13096
|
+
};
|
|
13097
|
+
});
|
|
13098
|
+
const finRes = await authenticatedClient.finalizeAIBlameInferencesUploadRaw({
|
|
13099
|
+
sessions: finalizeSessions
|
|
13100
|
+
});
|
|
13101
|
+
const status = finRes?.finalizeAIBlameInferencesUpload?.status;
|
|
13102
|
+
if (status !== "OK") {
|
|
13103
|
+
const errorMsg = finRes?.finalizeAIBlameInferencesUpload?.error || "unknown error";
|
|
13104
|
+
console.error(chalk9.red(errorMsg));
|
|
13105
|
+
if (exitOnError) {
|
|
13106
|
+
process.exit(1);
|
|
13107
|
+
}
|
|
13108
|
+
throw new Error(errorMsg);
|
|
13109
|
+
}
|
|
13110
|
+
console.log(chalk9.green("AI Blame uploads finalized successfully"));
|
|
13111
|
+
}
|
|
13112
|
+
|
|
13113
|
+
// src/features/claude_code/transcript_parser.ts
|
|
13114
|
+
import fsPromises4 from "fs/promises";
|
|
13115
|
+
function processTranscriptLine(entry) {
|
|
13116
|
+
const prompts = [];
|
|
13117
|
+
let model;
|
|
13118
|
+
let inputTokens = 0;
|
|
13119
|
+
let outputTokens = 0;
|
|
13120
|
+
let date;
|
|
13121
|
+
if (entry.message?.model) {
|
|
13122
|
+
model = entry.message.model;
|
|
13123
|
+
}
|
|
13124
|
+
if (entry.message?.usage) {
|
|
13125
|
+
inputTokens = entry.message.usage.input_tokens || 0;
|
|
13126
|
+
outputTokens = entry.message.usage.output_tokens || 0;
|
|
13127
|
+
}
|
|
13128
|
+
if (entry.timestamp) {
|
|
13129
|
+
date = new Date(entry.timestamp);
|
|
13130
|
+
}
|
|
13131
|
+
if (entry.type === "user" && entry.message?.role === "user") {
|
|
13132
|
+
if (typeof entry.message.content === "string") {
|
|
13133
|
+
prompts.push({
|
|
13134
|
+
type: "USER_PROMPT",
|
|
13135
|
+
text: entry.message.content,
|
|
13136
|
+
date: date || /* @__PURE__ */ new Date(),
|
|
13137
|
+
tokens: inputTokens > 0 ? {
|
|
13138
|
+
inputCount: inputTokens,
|
|
13139
|
+
outputCount: 0
|
|
13140
|
+
} : void 0
|
|
13141
|
+
});
|
|
13142
|
+
}
|
|
13143
|
+
} else if (entry.type === "assistant" && entry.message?.role === "assistant") {
|
|
13144
|
+
if (Array.isArray(entry.message.content)) {
|
|
13145
|
+
for (const item of entry.message.content) {
|
|
13146
|
+
if (item.type === "text" && item.text) {
|
|
13147
|
+
prompts.push({
|
|
13148
|
+
type: "AI_RESPONSE",
|
|
13149
|
+
text: item.text,
|
|
13150
|
+
date: date || /* @__PURE__ */ new Date(),
|
|
13151
|
+
tokens: outputTokens > 0 ? {
|
|
13152
|
+
inputCount: 0,
|
|
13153
|
+
outputCount: outputTokens
|
|
13154
|
+
} : void 0
|
|
13155
|
+
});
|
|
13156
|
+
} else if (item.type === "thinking" && item.thinking) {
|
|
13157
|
+
prompts.push({
|
|
13158
|
+
type: "AI_THINKING",
|
|
13159
|
+
text: item.thinking,
|
|
13160
|
+
date: date || /* @__PURE__ */ new Date()
|
|
13161
|
+
});
|
|
13162
|
+
}
|
|
13163
|
+
}
|
|
13164
|
+
}
|
|
13165
|
+
}
|
|
13166
|
+
return {
|
|
13167
|
+
prompts,
|
|
13168
|
+
model,
|
|
13169
|
+
inputTokens,
|
|
13170
|
+
outputTokens,
|
|
13171
|
+
date
|
|
13172
|
+
};
|
|
13173
|
+
}
|
|
13174
|
+
async function parseTranscriptAndCreateTrace(transcriptPath, hookData, inference) {
|
|
13175
|
+
const content = await fsPromises4.readFile(transcriptPath, "utf-8");
|
|
13176
|
+
const lines = content.trim().split("\n");
|
|
13177
|
+
let currentToolIndex = -1;
|
|
13178
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
13179
|
+
const line = lines[i]?.trim() ?? "";
|
|
13180
|
+
if (!line.includes('"type":"tool_use"')) continue;
|
|
13181
|
+
const isEditTool = line.includes('"name":"Edit"');
|
|
13182
|
+
const isWriteTool = line.includes('"name":"Write"');
|
|
13183
|
+
if (isEditTool || isWriteTool) {
|
|
13184
|
+
currentToolIndex = i;
|
|
13185
|
+
break;
|
|
13186
|
+
}
|
|
13187
|
+
}
|
|
13188
|
+
const startIndex = 0;
|
|
13189
|
+
const endIndex = currentToolIndex === -1 ? lines.length - 1 : currentToolIndex - 1;
|
|
13190
|
+
const prompts = [];
|
|
13191
|
+
let model;
|
|
13192
|
+
let latestDate;
|
|
13193
|
+
for (let i = startIndex; i <= endIndex; i++) {
|
|
13194
|
+
const line = lines[i]?.trim() ?? "";
|
|
13195
|
+
const entry = JSON.parse(line);
|
|
13196
|
+
const lineResult = processTranscriptLine(entry);
|
|
13197
|
+
prompts.push(...lineResult.prompts);
|
|
13198
|
+
if (lineResult.model && !model) {
|
|
13199
|
+
model = lineResult.model;
|
|
13200
|
+
}
|
|
13201
|
+
if (lineResult.date) {
|
|
13202
|
+
if (!latestDate || lineResult.date > latestDate) {
|
|
13203
|
+
latestDate = lineResult.date;
|
|
13204
|
+
}
|
|
13205
|
+
}
|
|
13206
|
+
}
|
|
13207
|
+
prompts.push({
|
|
13208
|
+
type: "TOOL_EXECUTION",
|
|
13209
|
+
date: latestDate || /* @__PURE__ */ new Date(),
|
|
13210
|
+
tool: {
|
|
13211
|
+
name: hookData.tool_name,
|
|
13212
|
+
parameters: JSON.stringify(hookData.tool_input, null, 2),
|
|
13213
|
+
result: JSON.stringify(hookData.tool_response, null, 2),
|
|
13214
|
+
rawArguments: JSON.stringify(hookData.tool_input),
|
|
13215
|
+
accepted: true
|
|
13216
|
+
}
|
|
13217
|
+
});
|
|
13218
|
+
return {
|
|
13219
|
+
prompts,
|
|
13220
|
+
inference,
|
|
13221
|
+
model: model || "claude-sonnet-4",
|
|
13222
|
+
// Use extracted model or fallback
|
|
13223
|
+
tool: "Claude Code",
|
|
13224
|
+
responseTime: (latestDate || /* @__PURE__ */ new Date()).toISOString()
|
|
13225
|
+
};
|
|
13226
|
+
}
|
|
13227
|
+
|
|
13228
|
+
// src/features/claude_code/data_collector.ts
|
|
13229
|
+
var StructuredPatchItemSchema = z32.object({
|
|
13230
|
+
oldStart: z32.number(),
|
|
13231
|
+
oldLines: z32.number(),
|
|
13232
|
+
newStart: z32.number(),
|
|
13233
|
+
newLines: z32.number(),
|
|
13234
|
+
lines: z32.array(z32.string())
|
|
13235
|
+
});
|
|
13236
|
+
var EditToolInputSchema = z32.object({
|
|
13237
|
+
file_path: z32.string(),
|
|
13238
|
+
old_string: z32.string(),
|
|
13239
|
+
new_string: z32.string()
|
|
13240
|
+
});
|
|
13241
|
+
var WriteToolInputSchema = z32.object({
|
|
13242
|
+
file_path: z32.string(),
|
|
13243
|
+
content: z32.string()
|
|
13244
|
+
});
|
|
13245
|
+
var EditToolResponseSchema = z32.object({
|
|
13246
|
+
filePath: z32.string(),
|
|
13247
|
+
oldString: z32.string().optional(),
|
|
13248
|
+
newString: z32.string().optional(),
|
|
13249
|
+
originalFile: z32.string().optional(),
|
|
13250
|
+
structuredPatch: z32.array(StructuredPatchItemSchema),
|
|
13251
|
+
userModified: z32.boolean().optional(),
|
|
13252
|
+
replaceAll: z32.boolean().optional()
|
|
13253
|
+
});
|
|
13254
|
+
var WriteToolResponseSchema = z32.object({
|
|
13255
|
+
type: z32.string().optional(),
|
|
13256
|
+
filePath: z32.string(),
|
|
13257
|
+
content: z32.string().optional(),
|
|
13258
|
+
structuredPatch: z32.array(z32.any()).optional()
|
|
13259
|
+
});
|
|
13260
|
+
var HookDataSchema = z32.object({
|
|
13261
|
+
session_id: z32.string(),
|
|
13262
|
+
transcript_path: z32.string(),
|
|
13263
|
+
cwd: z32.string(),
|
|
13264
|
+
permission_mode: z32.string().optional(),
|
|
13265
|
+
hook_event_name: z32.literal("PostToolUse"),
|
|
13266
|
+
tool_name: z32.enum(["Edit", "Write"]),
|
|
13267
|
+
tool_input: z32.union([EditToolInputSchema, WriteToolInputSchema]),
|
|
13268
|
+
tool_response: z32.union([EditToolResponseSchema, WriteToolResponseSchema])
|
|
13269
|
+
});
|
|
13270
|
+
async function readStdinData() {
|
|
13271
|
+
return new Promise((resolve, reject) => {
|
|
13272
|
+
let inputData = "";
|
|
13273
|
+
process.stdin.setEncoding("utf-8");
|
|
13274
|
+
process.stdin.on("data", (chunk) => {
|
|
13275
|
+
inputData += chunk;
|
|
13276
|
+
});
|
|
13277
|
+
process.stdin.on("end", () => {
|
|
13278
|
+
try {
|
|
13279
|
+
const parsedData = JSON.parse(inputData);
|
|
13280
|
+
resolve(parsedData);
|
|
13281
|
+
} catch (error) {
|
|
13282
|
+
reject(
|
|
13283
|
+
new Error(
|
|
13284
|
+
`Failed to parse JSON from stdin: ${error.message}`
|
|
13285
|
+
)
|
|
13286
|
+
);
|
|
13287
|
+
}
|
|
13288
|
+
});
|
|
13289
|
+
process.stdin.on("error", (error) => {
|
|
13290
|
+
reject(new Error(`Error reading from stdin: ${error.message}`));
|
|
13291
|
+
});
|
|
13292
|
+
});
|
|
13293
|
+
}
|
|
13294
|
+
function validateHookData(data) {
|
|
13295
|
+
return HookDataSchema.parse(data);
|
|
13296
|
+
}
|
|
13297
|
+
function extractInference(hookData) {
|
|
13298
|
+
if (hookData.tool_name === "Write") {
|
|
13299
|
+
const writeInput = hookData.tool_input;
|
|
13300
|
+
return writeInput.content || "";
|
|
13301
|
+
}
|
|
13302
|
+
if (hookData.tool_name === "Edit") {
|
|
13303
|
+
const editResponse = hookData.tool_response;
|
|
13304
|
+
const additions = [];
|
|
13305
|
+
for (const patch of editResponse.structuredPatch) {
|
|
13306
|
+
for (const line of patch.lines) {
|
|
13307
|
+
if (line.startsWith("+")) {
|
|
13308
|
+
additions.push(line.slice(1));
|
|
13309
|
+
}
|
|
13310
|
+
}
|
|
13311
|
+
}
|
|
13312
|
+
return additions.join("\n");
|
|
13313
|
+
}
|
|
13314
|
+
return "";
|
|
13315
|
+
}
|
|
13316
|
+
async function collectHookData() {
|
|
13317
|
+
const rawData = await readStdinData();
|
|
13318
|
+
const hookData = validateHookData(rawData);
|
|
13319
|
+
const inference = extractInference(hookData);
|
|
13320
|
+
let tracePayload;
|
|
13321
|
+
try {
|
|
13322
|
+
tracePayload = await parseTranscriptAndCreateTrace(
|
|
13323
|
+
hookData.transcript_path,
|
|
13324
|
+
hookData,
|
|
13325
|
+
inference
|
|
13326
|
+
);
|
|
13327
|
+
} catch (error) {
|
|
13328
|
+
console.warn(
|
|
13329
|
+
"Warning: Could not parse transcript:",
|
|
13330
|
+
error.message
|
|
13331
|
+
);
|
|
13332
|
+
tracePayload = {
|
|
13333
|
+
prompts: [
|
|
13334
|
+
{
|
|
13335
|
+
type: "TOOL_EXECUTION",
|
|
13336
|
+
date: /* @__PURE__ */ new Date(),
|
|
13337
|
+
tool: {
|
|
13338
|
+
name: hookData.tool_name,
|
|
13339
|
+
parameters: JSON.stringify(hookData.tool_input, null, 2),
|
|
13340
|
+
result: JSON.stringify(hookData.tool_response, null, 2),
|
|
13341
|
+
rawArguments: JSON.stringify(hookData.tool_input),
|
|
13342
|
+
accepted: true
|
|
13343
|
+
}
|
|
13344
|
+
}
|
|
13345
|
+
],
|
|
13346
|
+
inference,
|
|
13347
|
+
model: "claude-sonnet-4",
|
|
13348
|
+
tool: "Claude Code",
|
|
13349
|
+
responseTime: (/* @__PURE__ */ new Date()).toISOString()
|
|
13350
|
+
};
|
|
13351
|
+
}
|
|
13352
|
+
return {
|
|
13353
|
+
hookData,
|
|
13354
|
+
inference,
|
|
13355
|
+
tracePayload
|
|
13356
|
+
};
|
|
13357
|
+
}
|
|
13358
|
+
async function processAndUploadHookData() {
|
|
13359
|
+
const result = await collectHookData();
|
|
13360
|
+
let uploadSuccess;
|
|
13361
|
+
try {
|
|
13362
|
+
await uploadAiBlameHandlerFromExtension({
|
|
13363
|
+
prompts: result.tracePayload.prompts,
|
|
13364
|
+
inference: result.tracePayload.inference,
|
|
13365
|
+
model: result.tracePayload.model,
|
|
13366
|
+
tool: result.tracePayload.tool,
|
|
13367
|
+
responseTime: result.tracePayload.responseTime,
|
|
13368
|
+
blameType: "CHAT" /* Chat */
|
|
13369
|
+
});
|
|
13370
|
+
uploadSuccess = true;
|
|
13371
|
+
} catch (error) {
|
|
13372
|
+
console.warn(
|
|
13373
|
+
"Warning: Failed to upload trace data:",
|
|
13374
|
+
error.message
|
|
13375
|
+
);
|
|
13376
|
+
uploadSuccess = false;
|
|
13377
|
+
}
|
|
13378
|
+
return {
|
|
13379
|
+
...result,
|
|
13380
|
+
uploadSuccess
|
|
13381
|
+
};
|
|
13382
|
+
}
|
|
13383
|
+
|
|
13384
|
+
// src/features/claude_code/install_hook.ts
|
|
13385
|
+
import fsPromises5 from "fs/promises";
|
|
13386
|
+
import os2 from "os";
|
|
13387
|
+
import path12 from "path";
|
|
13388
|
+
import chalk10 from "chalk";
|
|
13389
|
+
var CLAUDE_SETTINGS_PATH = path12.join(os2.homedir(), ".claude", "settings.json");
|
|
13390
|
+
async function claudeSettingsExists() {
|
|
13391
|
+
try {
|
|
13392
|
+
await fsPromises5.access(CLAUDE_SETTINGS_PATH);
|
|
13393
|
+
return true;
|
|
13394
|
+
} catch {
|
|
13395
|
+
return false;
|
|
13396
|
+
}
|
|
13397
|
+
}
|
|
13398
|
+
async function readClaudeSettings() {
|
|
13399
|
+
const settingsContent = await fsPromises5.readFile(
|
|
13400
|
+
CLAUDE_SETTINGS_PATH,
|
|
13401
|
+
"utf-8"
|
|
13402
|
+
);
|
|
13403
|
+
return JSON.parse(settingsContent);
|
|
13404
|
+
}
|
|
13405
|
+
async function writeClaudeSettings(settings) {
|
|
13406
|
+
await fsPromises5.writeFile(
|
|
13407
|
+
CLAUDE_SETTINGS_PATH,
|
|
13408
|
+
JSON.stringify(settings, null, 2),
|
|
13409
|
+
"utf-8"
|
|
13410
|
+
);
|
|
13411
|
+
}
|
|
13412
|
+
async function installMobbHooks() {
|
|
13413
|
+
console.log(chalk10.blue("Installing Mobb hooks in Claude Code settings..."));
|
|
13414
|
+
if (!await claudeSettingsExists()) {
|
|
13415
|
+
console.log(chalk10.red("\u274C Claude Code settings file not found"));
|
|
13416
|
+
console.log(chalk10.yellow(`Expected location: ${CLAUDE_SETTINGS_PATH}`));
|
|
13417
|
+
console.log(chalk10.yellow("Is Claude Code installed on your system?"));
|
|
13418
|
+
console.log(chalk10.yellow("Please install Claude Code and try again."));
|
|
13419
|
+
throw new Error(
|
|
13420
|
+
"Claude Code settings file not found. Is Claude Code installed?"
|
|
13421
|
+
);
|
|
13422
|
+
}
|
|
13423
|
+
const settings = await readClaudeSettings();
|
|
13424
|
+
if (!settings.hooks) {
|
|
13425
|
+
settings.hooks = {};
|
|
13426
|
+
}
|
|
13427
|
+
if (!settings.hooks.PostToolUse) {
|
|
13428
|
+
settings.hooks.PostToolUse = [];
|
|
13429
|
+
}
|
|
13430
|
+
const mobbHookConfig = {
|
|
13431
|
+
matcher: "Edit|Write",
|
|
13432
|
+
hooks: [
|
|
13433
|
+
{
|
|
13434
|
+
type: "command",
|
|
13435
|
+
command: "npx --yes mobbdev@latest claude-code-process-hook"
|
|
13436
|
+
}
|
|
13437
|
+
]
|
|
13438
|
+
};
|
|
13439
|
+
const existingHookIndex = settings.hooks.PostToolUse.findIndex(
|
|
13440
|
+
(hook) => hook.matcher === "Edit|Write" && hook.hooks.some(
|
|
13441
|
+
(h) => h.command?.includes("mobbdev@latest claude-code-process-hook")
|
|
13442
|
+
)
|
|
13443
|
+
);
|
|
13444
|
+
if (existingHookIndex >= 0) {
|
|
13445
|
+
console.log(chalk10.yellow("Mobb hook already exists, updating..."));
|
|
13446
|
+
settings.hooks.PostToolUse[existingHookIndex] = mobbHookConfig;
|
|
13447
|
+
} else {
|
|
13448
|
+
console.log(chalk10.green("Adding new Mobb hook..."));
|
|
13449
|
+
settings.hooks.PostToolUse.push(mobbHookConfig);
|
|
13450
|
+
}
|
|
13451
|
+
await writeClaudeSettings(settings);
|
|
13452
|
+
console.log(
|
|
13453
|
+
chalk10.green(
|
|
13454
|
+
`\u2705 Mobb hooks installed successfully in ${CLAUDE_SETTINGS_PATH}`
|
|
13455
|
+
)
|
|
13456
|
+
);
|
|
13457
|
+
}
|
|
13458
|
+
|
|
13459
|
+
// src/args/commands/claude_code.ts
|
|
13460
|
+
var config6 = new Configstore5(packageJson.name, { apiToken: "" });
|
|
13461
|
+
var claudeCodeInstallHookBuilder = (yargs2) => {
|
|
13462
|
+
return yargs2.example(
|
|
13463
|
+
"$0 claude-code-install-hook",
|
|
13464
|
+
"Install Claude Code hooks for data collection"
|
|
13465
|
+
).strict();
|
|
13466
|
+
};
|
|
13467
|
+
var claudeCodeProcessHookBuilder = (yargs2) => {
|
|
13468
|
+
return yargs2.example(
|
|
13469
|
+
"$0 claude-code-process-hook",
|
|
13470
|
+
"Process Claude Code hook data and upload to backend"
|
|
13471
|
+
).strict();
|
|
13472
|
+
};
|
|
13473
|
+
var claudeCodeInstallHookHandler = async () => {
|
|
13474
|
+
try {
|
|
13475
|
+
const gqlClient = new GQLClient({
|
|
13476
|
+
apiKey: config6.get("apiToken") ?? "",
|
|
13477
|
+
type: "apiKey"
|
|
13478
|
+
});
|
|
13479
|
+
await handleMobbLogin({
|
|
13480
|
+
inGqlClient: gqlClient,
|
|
13481
|
+
skipPrompts: false
|
|
13482
|
+
});
|
|
13483
|
+
await installMobbHooks();
|
|
13484
|
+
process.exit(0);
|
|
13485
|
+
} catch (error) {
|
|
13486
|
+
console.error("Failed to install Claude Code hooks:", error);
|
|
13487
|
+
process.exit(1);
|
|
13488
|
+
}
|
|
13489
|
+
};
|
|
13490
|
+
var claudeCodeProcessHookHandler = async () => {
|
|
13491
|
+
try {
|
|
13492
|
+
const { hookData, inference, tracePayload, uploadSuccess } = await processAndUploadHookData();
|
|
13493
|
+
console.log("Successfully processed Claude Code hook:");
|
|
13494
|
+
console.log("Session ID:", hookData.session_id);
|
|
13495
|
+
console.log("Tool:", hookData.tool_name);
|
|
13496
|
+
console.log("Transcript path:", hookData.transcript_path);
|
|
13497
|
+
console.log("Inference length:", inference.length);
|
|
13498
|
+
const userPrompts = tracePayload.prompts.filter(
|
|
13499
|
+
(p) => p.type === "USER_PROMPT"
|
|
13500
|
+
);
|
|
13501
|
+
const assistantResponses = tracePayload.prompts.filter(
|
|
13502
|
+
(p) => p.type === "AI_RESPONSE"
|
|
13503
|
+
);
|
|
13504
|
+
const aiThinking = tracePayload.prompts.filter(
|
|
13505
|
+
(p) => p.type === "AI_THINKING"
|
|
13506
|
+
);
|
|
13507
|
+
console.log("Conversation context extracted:");
|
|
13508
|
+
console.log("- User prompts:", userPrompts.length);
|
|
13509
|
+
console.log("- Assistant responses:", assistantResponses.length);
|
|
13510
|
+
console.log("- AI thinking entries:", aiThinking.length);
|
|
13511
|
+
console.log("- Model:", tracePayload.model);
|
|
13512
|
+
const totalInputTokens = tracePayload.prompts.reduce(
|
|
13513
|
+
(sum, p) => sum + (p.tokens?.inputCount || 0),
|
|
13514
|
+
0
|
|
13515
|
+
);
|
|
13516
|
+
const totalOutputTokens = tracePayload.prompts.reduce(
|
|
13517
|
+
(sum, p) => sum + (p.tokens?.outputCount || 0),
|
|
13518
|
+
0
|
|
13519
|
+
);
|
|
13520
|
+
console.log("- Input tokens:", totalInputTokens);
|
|
13521
|
+
console.log("- Output tokens:", totalOutputTokens);
|
|
13522
|
+
console.log("Trace data formatted:");
|
|
13523
|
+
console.log("- Prompt items:", tracePayload.prompts.length);
|
|
13524
|
+
console.log("- Model:", tracePayload.model);
|
|
13525
|
+
console.log("- Tool:", tracePayload.tool);
|
|
13526
|
+
console.log("- Response time:", tracePayload.responseTime);
|
|
13527
|
+
console.log("- Upload success:", uploadSuccess ? "\u2705" : "\u274C");
|
|
13528
|
+
if (uploadSuccess) {
|
|
13529
|
+
console.log("\u2705 Claude Code trace uploaded successfully to Mobb backend");
|
|
13530
|
+
}
|
|
13531
|
+
process.exit(0);
|
|
13532
|
+
} catch (error) {
|
|
13533
|
+
console.error("Failed to process Claude Code hook data:", error);
|
|
13534
|
+
process.exit(1);
|
|
13535
|
+
}
|
|
13536
|
+
};
|
|
13537
|
+
|
|
12897
13538
|
// src/mcp/core/McpServer.ts
|
|
12898
13539
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
12899
13540
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -12905,7 +13546,7 @@ import {
|
|
|
12905
13546
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
12906
13547
|
|
|
12907
13548
|
// src/mcp/Logger.ts
|
|
12908
|
-
import
|
|
13549
|
+
import Configstore6 from "configstore";
|
|
12909
13550
|
|
|
12910
13551
|
// src/mcp/services/WorkspaceService.ts
|
|
12911
13552
|
var WorkspaceService = class {
|
|
@@ -12913,8 +13554,8 @@ var WorkspaceService = class {
|
|
|
12913
13554
|
* Sets a known workspace path that was discovered through successful validation
|
|
12914
13555
|
* @param path The validated workspace path to store
|
|
12915
13556
|
*/
|
|
12916
|
-
static setKnownWorkspacePath(
|
|
12917
|
-
this.knownWorkspacePath =
|
|
13557
|
+
static setKnownWorkspacePath(path22) {
|
|
13558
|
+
this.knownWorkspacePath = path22;
|
|
12918
13559
|
}
|
|
12919
13560
|
/**
|
|
12920
13561
|
* Gets the known workspace path that was previously validated
|
|
@@ -12991,7 +13632,7 @@ var Logger = class {
|
|
|
12991
13632
|
__publicField(this, "lastKnownPath", null);
|
|
12992
13633
|
this.host = WorkspaceService.getHost();
|
|
12993
13634
|
this.unknownPathSuffix = Math.floor(1e3 + Math.random() * 9e3).toString();
|
|
12994
|
-
this.mobbConfigStore = new
|
|
13635
|
+
this.mobbConfigStore = new Configstore6("mobb-logs", {});
|
|
12995
13636
|
this.mobbConfigStore.set("version", packageJson.version);
|
|
12996
13637
|
}
|
|
12997
13638
|
/**
|
|
@@ -13061,135 +13702,135 @@ import { v4 as uuidv42 } from "uuid";
|
|
|
13061
13702
|
init_configs();
|
|
13062
13703
|
|
|
13063
13704
|
// src/mcp/types.ts
|
|
13064
|
-
import { z as
|
|
13065
|
-
var ScanAndFixVulnerabilitiesToolSchema =
|
|
13066
|
-
path:
|
|
13705
|
+
import { z as z33 } from "zod";
|
|
13706
|
+
var ScanAndFixVulnerabilitiesToolSchema = z33.object({
|
|
13707
|
+
path: z33.string()
|
|
13067
13708
|
});
|
|
13068
|
-
var VulnerabilityReportIssueTagSchema =
|
|
13069
|
-
vulnerability_report_issue_tag_value:
|
|
13709
|
+
var VulnerabilityReportIssueTagSchema = z33.object({
|
|
13710
|
+
vulnerability_report_issue_tag_value: z33.nativeEnum(
|
|
13070
13711
|
Vulnerability_Report_Issue_Tag_Enum
|
|
13071
13712
|
)
|
|
13072
13713
|
});
|
|
13073
|
-
var VulnerabilityReportIssueSchema =
|
|
13074
|
-
category:
|
|
13075
|
-
parsedIssueType:
|
|
13076
|
-
parsedSeverity:
|
|
13077
|
-
vulnerabilityReportIssueTags:
|
|
13714
|
+
var VulnerabilityReportIssueSchema = z33.object({
|
|
13715
|
+
category: z33.any().optional().nullable(),
|
|
13716
|
+
parsedIssueType: z33.nativeEnum(IssueType_Enum).nullable().optional(),
|
|
13717
|
+
parsedSeverity: z33.nativeEnum(Vulnerability_Severity_Enum).nullable().optional(),
|
|
13718
|
+
vulnerabilityReportIssueTags: z33.array(VulnerabilityReportIssueTagSchema)
|
|
13078
13719
|
});
|
|
13079
|
-
var SharedStateSchema =
|
|
13080
|
-
__typename:
|
|
13081
|
-
id:
|
|
13720
|
+
var SharedStateSchema = z33.object({
|
|
13721
|
+
__typename: z33.literal("fix_shared_state").optional(),
|
|
13722
|
+
id: z33.any(),
|
|
13082
13723
|
// GraphQL uses `any` type for UUID
|
|
13083
|
-
downloadedBy:
|
|
13724
|
+
downloadedBy: z33.array(z33.any().nullable()).optional().nullable()
|
|
13084
13725
|
});
|
|
13085
|
-
var UnstructuredFixExtraContextSchema =
|
|
13086
|
-
__typename:
|
|
13087
|
-
key:
|
|
13088
|
-
value:
|
|
13726
|
+
var UnstructuredFixExtraContextSchema = z33.object({
|
|
13727
|
+
__typename: z33.literal("UnstructuredFixExtraContext").optional(),
|
|
13728
|
+
key: z33.string(),
|
|
13729
|
+
value: z33.any()
|
|
13089
13730
|
// GraphQL JSON type
|
|
13090
13731
|
});
|
|
13091
|
-
var FixExtraContextResponseSchema =
|
|
13092
|
-
__typename:
|
|
13093
|
-
extraContext:
|
|
13094
|
-
fixDescription:
|
|
13732
|
+
var FixExtraContextResponseSchema = z33.object({
|
|
13733
|
+
__typename: z33.literal("FixExtraContextResponse").optional(),
|
|
13734
|
+
extraContext: z33.array(UnstructuredFixExtraContextSchema),
|
|
13735
|
+
fixDescription: z33.string()
|
|
13095
13736
|
});
|
|
13096
|
-
var FixDataSchema =
|
|
13097
|
-
__typename:
|
|
13098
|
-
patch:
|
|
13099
|
-
patchOriginalEncodingBase64:
|
|
13737
|
+
var FixDataSchema = z33.object({
|
|
13738
|
+
__typename: z33.literal("FixData"),
|
|
13739
|
+
patch: z33.string(),
|
|
13740
|
+
patchOriginalEncodingBase64: z33.string(),
|
|
13100
13741
|
extraContext: FixExtraContextResponseSchema
|
|
13101
13742
|
});
|
|
13102
|
-
var GetFixNoFixErrorSchema =
|
|
13103
|
-
__typename:
|
|
13743
|
+
var GetFixNoFixErrorSchema = z33.object({
|
|
13744
|
+
__typename: z33.literal("GetFixNoFixError")
|
|
13104
13745
|
});
|
|
13105
|
-
var PatchAndQuestionsSchema =
|
|
13106
|
-
var McpFixSchema =
|
|
13107
|
-
__typename:
|
|
13108
|
-
id:
|
|
13746
|
+
var PatchAndQuestionsSchema = z33.union([FixDataSchema, GetFixNoFixErrorSchema]);
|
|
13747
|
+
var McpFixSchema = z33.object({
|
|
13748
|
+
__typename: z33.literal("fix").optional(),
|
|
13749
|
+
id: z33.any(),
|
|
13109
13750
|
// GraphQL uses `any` type for UUID
|
|
13110
|
-
confidence:
|
|
13111
|
-
safeIssueType:
|
|
13112
|
-
severityText:
|
|
13113
|
-
gitBlameLogin:
|
|
13751
|
+
confidence: z33.number(),
|
|
13752
|
+
safeIssueType: z33.string().nullable(),
|
|
13753
|
+
severityText: z33.string().nullable(),
|
|
13754
|
+
gitBlameLogin: z33.string().nullable().optional(),
|
|
13114
13755
|
// Optional in GraphQL
|
|
13115
|
-
severityValue:
|
|
13116
|
-
vulnerabilityReportIssues:
|
|
13756
|
+
severityValue: z33.number().nullable(),
|
|
13757
|
+
vulnerabilityReportIssues: z33.array(VulnerabilityReportIssueSchema),
|
|
13117
13758
|
sharedState: SharedStateSchema.nullable().optional(),
|
|
13118
13759
|
// Optional in GraphQL
|
|
13119
13760
|
patchAndQuestions: PatchAndQuestionsSchema,
|
|
13120
13761
|
// Additional field added by the client
|
|
13121
|
-
fixUrl:
|
|
13762
|
+
fixUrl: z33.string().optional()
|
|
13122
13763
|
});
|
|
13123
|
-
var FixAggregateSchema =
|
|
13124
|
-
__typename:
|
|
13125
|
-
aggregate:
|
|
13126
|
-
__typename:
|
|
13127
|
-
count:
|
|
13764
|
+
var FixAggregateSchema = z33.object({
|
|
13765
|
+
__typename: z33.literal("fix_aggregate").optional(),
|
|
13766
|
+
aggregate: z33.object({
|
|
13767
|
+
__typename: z33.literal("fix_aggregate_fields").optional(),
|
|
13768
|
+
count: z33.number()
|
|
13128
13769
|
}).nullable()
|
|
13129
13770
|
});
|
|
13130
|
-
var VulnerabilityReportIssueAggregateSchema =
|
|
13131
|
-
__typename:
|
|
13132
|
-
aggregate:
|
|
13133
|
-
__typename:
|
|
13134
|
-
count:
|
|
13771
|
+
var VulnerabilityReportIssueAggregateSchema = z33.object({
|
|
13772
|
+
__typename: z33.literal("vulnerability_report_issue_aggregate").optional(),
|
|
13773
|
+
aggregate: z33.object({
|
|
13774
|
+
__typename: z33.literal("vulnerability_report_issue_aggregate_fields").optional(),
|
|
13775
|
+
count: z33.number()
|
|
13135
13776
|
}).nullable()
|
|
13136
13777
|
});
|
|
13137
|
-
var RepoSchema =
|
|
13138
|
-
__typename:
|
|
13139
|
-
originalUrl:
|
|
13778
|
+
var RepoSchema = z33.object({
|
|
13779
|
+
__typename: z33.literal("repo").optional(),
|
|
13780
|
+
originalUrl: z33.string()
|
|
13140
13781
|
});
|
|
13141
|
-
var ProjectSchema =
|
|
13142
|
-
id:
|
|
13782
|
+
var ProjectSchema = z33.object({
|
|
13783
|
+
id: z33.any(),
|
|
13143
13784
|
// GraphQL uses `any` type for UUID
|
|
13144
|
-
organizationId:
|
|
13785
|
+
organizationId: z33.any()
|
|
13145
13786
|
// GraphQL uses `any` type for UUID
|
|
13146
13787
|
});
|
|
13147
|
-
var VulnerabilityReportSchema =
|
|
13148
|
-
scanDate:
|
|
13788
|
+
var VulnerabilityReportSchema = z33.object({
|
|
13789
|
+
scanDate: z33.any().nullable(),
|
|
13149
13790
|
// GraphQL uses `any` type for timestamp
|
|
13150
|
-
vendor:
|
|
13791
|
+
vendor: z33.string(),
|
|
13151
13792
|
// GraphQL generates as string, not enum
|
|
13152
|
-
projectId:
|
|
13793
|
+
projectId: z33.any().optional(),
|
|
13153
13794
|
// GraphQL uses `any` type for UUID
|
|
13154
13795
|
project: ProjectSchema,
|
|
13155
13796
|
totalVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema,
|
|
13156
13797
|
notFixableVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema
|
|
13157
13798
|
});
|
|
13158
|
-
var FixReportSummarySchema =
|
|
13159
|
-
__typename:
|
|
13160
|
-
id:
|
|
13799
|
+
var FixReportSummarySchema = z33.object({
|
|
13800
|
+
__typename: z33.literal("fixReport").optional(),
|
|
13801
|
+
id: z33.any(),
|
|
13161
13802
|
// GraphQL uses `any` type for UUID
|
|
13162
|
-
createdOn:
|
|
13803
|
+
createdOn: z33.any(),
|
|
13163
13804
|
// GraphQL uses `any` type for timestamp
|
|
13164
13805
|
repo: RepoSchema.nullable(),
|
|
13165
|
-
issueTypes:
|
|
13806
|
+
issueTypes: z33.any().nullable(),
|
|
13166
13807
|
// GraphQL uses `any` type for JSON
|
|
13167
13808
|
CRITICAL: FixAggregateSchema,
|
|
13168
13809
|
HIGH: FixAggregateSchema,
|
|
13169
13810
|
MEDIUM: FixAggregateSchema,
|
|
13170
13811
|
LOW: FixAggregateSchema,
|
|
13171
|
-
fixes:
|
|
13172
|
-
userFixes:
|
|
13812
|
+
fixes: z33.array(McpFixSchema),
|
|
13813
|
+
userFixes: z33.array(McpFixSchema).optional(),
|
|
13173
13814
|
// Present in some responses but can be omitted
|
|
13174
13815
|
filteredFixesCount: FixAggregateSchema,
|
|
13175
13816
|
totalFixesCount: FixAggregateSchema,
|
|
13176
13817
|
vulnerabilityReport: VulnerabilityReportSchema
|
|
13177
13818
|
});
|
|
13178
|
-
var ExpiredReportSchema =
|
|
13179
|
-
__typename:
|
|
13180
|
-
id:
|
|
13819
|
+
var ExpiredReportSchema = z33.object({
|
|
13820
|
+
__typename: z33.literal("fixReport").optional(),
|
|
13821
|
+
id: z33.any(),
|
|
13181
13822
|
// GraphQL uses `any` type for UUID
|
|
13182
|
-
expirationOn:
|
|
13823
|
+
expirationOn: z33.any().nullable()
|
|
13183
13824
|
// GraphQL uses `any` type for timestamp
|
|
13184
13825
|
});
|
|
13185
|
-
var GetLatestReportByRepoUrlResponseSchema =
|
|
13186
|
-
__typename:
|
|
13187
|
-
fixReport:
|
|
13188
|
-
expiredReport:
|
|
13826
|
+
var GetLatestReportByRepoUrlResponseSchema = z33.object({
|
|
13827
|
+
__typename: z33.literal("query_root").optional(),
|
|
13828
|
+
fixReport: z33.array(FixReportSummarySchema),
|
|
13829
|
+
expiredReport: z33.array(ExpiredReportSchema)
|
|
13189
13830
|
});
|
|
13190
13831
|
|
|
13191
13832
|
// src/mcp/services/ConfigStoreService.ts
|
|
13192
|
-
import
|
|
13833
|
+
import Configstore7 from "configstore";
|
|
13193
13834
|
init_configs();
|
|
13194
13835
|
function createConfigStore(defaultValues = { apiToken: "" }) {
|
|
13195
13836
|
const API_URL2 = process.env["API_URL"] || MCP_DEFAULT_API_URL;
|
|
@@ -13201,7 +13842,7 @@ function createConfigStore(defaultValues = { apiToken: "" }) {
|
|
|
13201
13842
|
domain = API_URL2.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/:\d+$/, "");
|
|
13202
13843
|
}
|
|
13203
13844
|
const sanitizedDomain = domain.replace(/\./g, "_");
|
|
13204
|
-
return new
|
|
13845
|
+
return new Configstore7(
|
|
13205
13846
|
`${packageJson.name}-${sanitizedDomain}`,
|
|
13206
13847
|
defaultValues
|
|
13207
13848
|
);
|
|
@@ -13213,7 +13854,7 @@ var configStore = getConfigStore();
|
|
|
13213
13854
|
|
|
13214
13855
|
// src/mcp/services/McpAuthService.ts
|
|
13215
13856
|
import crypto2 from "crypto";
|
|
13216
|
-
import
|
|
13857
|
+
import os3 from "os";
|
|
13217
13858
|
import open4 from "open";
|
|
13218
13859
|
init_configs();
|
|
13219
13860
|
var McpAuthService = class {
|
|
@@ -13257,7 +13898,7 @@ var McpAuthService = class {
|
|
|
13257
13898
|
}
|
|
13258
13899
|
logDebug(`cli login created ${loginId}`);
|
|
13259
13900
|
const webLoginUrl2 = `${WEB_APP_URL}/mvs-login`;
|
|
13260
|
-
const browserUrl = `${webLoginUrl2}/${loginId}?hostname=${
|
|
13901
|
+
const browserUrl = `${webLoginUrl2}/${loginId}?hostname=${os3.hostname()}`;
|
|
13261
13902
|
await this.openBrowser(browserUrl, isBackgoundCall);
|
|
13262
13903
|
logDebug(`waiting for login to complete`);
|
|
13263
13904
|
let newApiToken = null;
|
|
@@ -13918,8 +14559,8 @@ async function createAuthenticatedMcpGQLClient({
|
|
|
13918
14559
|
// src/mcp/services/McpUsageService/host.ts
|
|
13919
14560
|
import { execSync } from "child_process";
|
|
13920
14561
|
import fs11 from "fs";
|
|
13921
|
-
import
|
|
13922
|
-
import
|
|
14562
|
+
import os4 from "os";
|
|
14563
|
+
import path13 from "path";
|
|
13923
14564
|
var IDEs = ["cursor", "windsurf", "webstorm", "vscode", "claude"];
|
|
13924
14565
|
var runCommand = (cmd) => {
|
|
13925
14566
|
try {
|
|
@@ -13933,8 +14574,8 @@ var gitInfo = {
|
|
|
13933
14574
|
email: runCommand("git config user.email")
|
|
13934
14575
|
};
|
|
13935
14576
|
var getClaudeWorkspacePaths = () => {
|
|
13936
|
-
const home =
|
|
13937
|
-
const claudeIdePath =
|
|
14577
|
+
const home = os4.homedir();
|
|
14578
|
+
const claudeIdePath = path13.join(home, ".claude", "ide");
|
|
13938
14579
|
const workspacePaths = [];
|
|
13939
14580
|
if (!fs11.existsSync(claudeIdePath)) {
|
|
13940
14581
|
return workspacePaths;
|
|
@@ -13942,7 +14583,7 @@ var getClaudeWorkspacePaths = () => {
|
|
|
13942
14583
|
try {
|
|
13943
14584
|
const lockFiles = fs11.readdirSync(claudeIdePath).filter((file) => file.endsWith(".lock"));
|
|
13944
14585
|
for (const lockFile of lockFiles) {
|
|
13945
|
-
const lockFilePath =
|
|
14586
|
+
const lockFilePath = path13.join(claudeIdePath, lockFile);
|
|
13946
14587
|
try {
|
|
13947
14588
|
const lockContent = JSON.parse(fs11.readFileSync(lockFilePath, "utf8"));
|
|
13948
14589
|
if (lockContent.workspaceFolders && Array.isArray(lockContent.workspaceFolders)) {
|
|
@@ -13962,29 +14603,29 @@ var getClaudeWorkspacePaths = () => {
|
|
|
13962
14603
|
return workspacePaths;
|
|
13963
14604
|
};
|
|
13964
14605
|
var getMCPConfigPaths = (hostName) => {
|
|
13965
|
-
const home =
|
|
14606
|
+
const home = os4.homedir();
|
|
13966
14607
|
const currentDir = process.env["WORKSPACE_FOLDER_PATHS"] || process.env["PWD"] || process.cwd();
|
|
13967
14608
|
switch (hostName.toLowerCase()) {
|
|
13968
14609
|
case "cursor":
|
|
13969
14610
|
return [
|
|
13970
|
-
|
|
14611
|
+
path13.join(currentDir, ".cursor", "mcp.json"),
|
|
13971
14612
|
// local first
|
|
13972
|
-
|
|
14613
|
+
path13.join(home, ".cursor", "mcp.json")
|
|
13973
14614
|
];
|
|
13974
14615
|
case "windsurf":
|
|
13975
14616
|
return [
|
|
13976
|
-
|
|
14617
|
+
path13.join(currentDir, ".codeium", "mcp_config.json"),
|
|
13977
14618
|
// local first
|
|
13978
|
-
|
|
14619
|
+
path13.join(home, ".codeium", "windsurf", "mcp_config.json")
|
|
13979
14620
|
];
|
|
13980
14621
|
case "webstorm":
|
|
13981
14622
|
return [];
|
|
13982
14623
|
case "visualstudiocode":
|
|
13983
14624
|
case "vscode":
|
|
13984
14625
|
return [
|
|
13985
|
-
|
|
14626
|
+
path13.join(currentDir, ".vscode", "mcp.json"),
|
|
13986
14627
|
// local first
|
|
13987
|
-
process.platform === "win32" ?
|
|
14628
|
+
process.platform === "win32" ? path13.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path13.join(
|
|
13988
14629
|
home,
|
|
13989
14630
|
"Library",
|
|
13990
14631
|
"Application Support",
|
|
@@ -13995,13 +14636,13 @@ var getMCPConfigPaths = (hostName) => {
|
|
|
13995
14636
|
];
|
|
13996
14637
|
case "claude": {
|
|
13997
14638
|
const claudePaths = [
|
|
13998
|
-
|
|
14639
|
+
path13.join(currentDir, ".claude.json"),
|
|
13999
14640
|
// local first
|
|
14000
|
-
|
|
14641
|
+
path13.join(home, ".claude.json")
|
|
14001
14642
|
];
|
|
14002
14643
|
const workspacePaths = getClaudeWorkspacePaths();
|
|
14003
14644
|
for (const workspacePath of workspacePaths) {
|
|
14004
|
-
claudePaths.push(
|
|
14645
|
+
claudePaths.push(path13.join(workspacePath, ".mcp.json"));
|
|
14005
14646
|
}
|
|
14006
14647
|
return claudePaths;
|
|
14007
14648
|
}
|
|
@@ -14018,41 +14659,41 @@ var readConfigFile = (filePath) => {
|
|
|
14018
14659
|
return null;
|
|
14019
14660
|
}
|
|
14020
14661
|
};
|
|
14021
|
-
var mergeConfigIntoResult = (
|
|
14022
|
-
if (
|
|
14662
|
+
var mergeConfigIntoResult = (config7, mergedConfig) => {
|
|
14663
|
+
if (config7?.projects) {
|
|
14023
14664
|
const allMcpServers = {};
|
|
14024
|
-
for (const projectPath in
|
|
14025
|
-
const project =
|
|
14665
|
+
for (const projectPath in config7.projects) {
|
|
14666
|
+
const project = config7.projects[projectPath];
|
|
14026
14667
|
if (project?.mcpServers) {
|
|
14027
14668
|
Object.assign(allMcpServers, project.mcpServers);
|
|
14028
14669
|
}
|
|
14029
14670
|
}
|
|
14030
14671
|
mergedConfig.mcpServers = { ...mergedConfig.mcpServers, ...allMcpServers };
|
|
14031
14672
|
}
|
|
14032
|
-
if (
|
|
14673
|
+
if (config7?.mcpServers) {
|
|
14033
14674
|
mergedConfig.mcpServers = {
|
|
14034
14675
|
...mergedConfig.mcpServers,
|
|
14035
|
-
...
|
|
14676
|
+
...config7.mcpServers
|
|
14036
14677
|
};
|
|
14037
14678
|
}
|
|
14038
|
-
if (
|
|
14039
|
-
mergedConfig.servers = { ...mergedConfig.servers, ...
|
|
14679
|
+
if (config7?.servers) {
|
|
14680
|
+
mergedConfig.servers = { ...mergedConfig.servers, ...config7.servers };
|
|
14040
14681
|
}
|
|
14041
14682
|
};
|
|
14042
14683
|
var readMCPConfig = (hostName) => {
|
|
14043
14684
|
const configPaths = getMCPConfigPaths(hostName);
|
|
14044
14685
|
const mergedConfig = {};
|
|
14045
14686
|
for (const configPath of configPaths) {
|
|
14046
|
-
const
|
|
14047
|
-
if (
|
|
14048
|
-
mergeConfigIntoResult(
|
|
14687
|
+
const config7 = readConfigFile(configPath);
|
|
14688
|
+
if (config7) {
|
|
14689
|
+
mergeConfigIntoResult(config7, mergedConfig);
|
|
14049
14690
|
}
|
|
14050
14691
|
}
|
|
14051
14692
|
return Object.keys(mergedConfig).length > 0 ? mergedConfig : null;
|
|
14052
14693
|
};
|
|
14053
14694
|
var getRunningProcesses = () => {
|
|
14054
14695
|
try {
|
|
14055
|
-
return
|
|
14696
|
+
return os4.platform() === "win32" ? execSync("tasklist", { encoding: "utf8" }) : execSync("ps aux", { encoding: "utf8" });
|
|
14056
14697
|
} catch {
|
|
14057
14698
|
return "";
|
|
14058
14699
|
}
|
|
@@ -14127,7 +14768,7 @@ var versionCommands = {
|
|
|
14127
14768
|
}
|
|
14128
14769
|
};
|
|
14129
14770
|
var getProcessInfo = (pid) => {
|
|
14130
|
-
const platform2 =
|
|
14771
|
+
const platform2 = os4.platform();
|
|
14131
14772
|
try {
|
|
14132
14773
|
if (platform2 === "linux" || platform2 === "darwin") {
|
|
14133
14774
|
const output = execSync(`ps -o pid=,ppid=,comm= -p ${pid}`, {
|
|
@@ -14162,20 +14803,20 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
14162
14803
|
const ideConfigPaths = /* @__PURE__ */ new Set();
|
|
14163
14804
|
for (const ide of IDEs) {
|
|
14164
14805
|
const configPaths = getMCPConfigPaths(ide);
|
|
14165
|
-
configPaths.forEach((
|
|
14806
|
+
configPaths.forEach((path22) => ideConfigPaths.add(path22));
|
|
14166
14807
|
}
|
|
14167
14808
|
const uniqueAdditionalPaths = additionalMcpList.filter(
|
|
14168
|
-
(
|
|
14809
|
+
(path22) => !ideConfigPaths.has(path22)
|
|
14169
14810
|
);
|
|
14170
14811
|
for (const ide of IDEs) {
|
|
14171
14812
|
const cfg = readMCPConfig(ide);
|
|
14172
14813
|
if (cfg) allConfigs[ide] = cfg;
|
|
14173
14814
|
}
|
|
14174
14815
|
for (const additionalPath of uniqueAdditionalPaths) {
|
|
14175
|
-
const
|
|
14176
|
-
if (!
|
|
14816
|
+
const config7 = readConfigFile(additionalPath);
|
|
14817
|
+
if (!config7) continue;
|
|
14177
14818
|
const mergedConfig = {};
|
|
14178
|
-
mergeConfigIntoResult(
|
|
14819
|
+
mergeConfigIntoResult(config7, mergedConfig);
|
|
14179
14820
|
if (Object.keys(mergedConfig).length > 0) {
|
|
14180
14821
|
allConfigs["system"] = mergedConfig;
|
|
14181
14822
|
}
|
|
@@ -14243,10 +14884,10 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
14243
14884
|
}
|
|
14244
14885
|
}
|
|
14245
14886
|
for (const { ide, name, command, isRunning } of servers) {
|
|
14246
|
-
const
|
|
14887
|
+
const config7 = allConfigs[ide] || null;
|
|
14247
14888
|
const ideName = ide.charAt(0).toUpperCase() + ide.slice(1) || "Unknown";
|
|
14248
14889
|
let ideVersion = "Unknown";
|
|
14249
|
-
const platform2 =
|
|
14890
|
+
const platform2 = os4.platform();
|
|
14250
14891
|
const cmds = versionCommands[ideName]?.[platform2] ?? [];
|
|
14251
14892
|
for (const cmd of cmds) {
|
|
14252
14893
|
try {
|
|
@@ -14260,8 +14901,8 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
14260
14901
|
}
|
|
14261
14902
|
}
|
|
14262
14903
|
let mcpConfigObj = {};
|
|
14263
|
-
if (
|
|
14264
|
-
const allServers =
|
|
14904
|
+
if (config7) {
|
|
14905
|
+
const allServers = config7.mcpServers || config7.servers || {};
|
|
14265
14906
|
if (name in allServers && allServers[name]) {
|
|
14266
14907
|
mcpConfigObj = allServers[name];
|
|
14267
14908
|
}
|
|
@@ -14279,15 +14920,15 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
14279
14920
|
|
|
14280
14921
|
// src/mcp/services/McpUsageService/McpUsageService.ts
|
|
14281
14922
|
import fetch5 from "node-fetch";
|
|
14282
|
-
import
|
|
14923
|
+
import os6 from "os";
|
|
14283
14924
|
import { v4 as uuidv43, v5 as uuidv5 } from "uuid";
|
|
14284
14925
|
init_configs();
|
|
14285
14926
|
|
|
14286
14927
|
// src/mcp/services/McpUsageService/system.ts
|
|
14287
14928
|
init_configs();
|
|
14288
14929
|
import fs12 from "fs";
|
|
14289
|
-
import
|
|
14290
|
-
import
|
|
14930
|
+
import os5 from "os";
|
|
14931
|
+
import path14 from "path";
|
|
14291
14932
|
var MAX_DEPTH = 2;
|
|
14292
14933
|
var patterns = ["mcp", "claude"];
|
|
14293
14934
|
var isFileMatch = (fileName) => {
|
|
@@ -14307,7 +14948,7 @@ var searchDir = async (dir, depth = 0) => {
|
|
|
14307
14948
|
if (depth > MAX_DEPTH) return results;
|
|
14308
14949
|
const entries = await fs12.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
14309
14950
|
for (const entry of entries) {
|
|
14310
|
-
const fullPath =
|
|
14951
|
+
const fullPath = path14.join(dir, entry.name);
|
|
14311
14952
|
if (entry.isFile() && isFileMatch(entry.name)) {
|
|
14312
14953
|
results.push(fullPath);
|
|
14313
14954
|
} else if (entry.isDirectory()) {
|
|
@@ -14321,17 +14962,17 @@ var searchDir = async (dir, depth = 0) => {
|
|
|
14321
14962
|
};
|
|
14322
14963
|
var findSystemMCPConfigs = async () => {
|
|
14323
14964
|
try {
|
|
14324
|
-
const home =
|
|
14325
|
-
const platform2 =
|
|
14965
|
+
const home = os5.homedir();
|
|
14966
|
+
const platform2 = os5.platform();
|
|
14326
14967
|
const knownDirs = platform2 === "win32" ? [
|
|
14327
|
-
|
|
14328
|
-
|
|
14329
|
-
|
|
14968
|
+
path14.join(home, ".cursor"),
|
|
14969
|
+
path14.join(home, "Documents"),
|
|
14970
|
+
path14.join(home, "Downloads")
|
|
14330
14971
|
] : [
|
|
14331
|
-
|
|
14332
|
-
process.env["XDG_CONFIG_HOME"] ||
|
|
14333
|
-
|
|
14334
|
-
|
|
14972
|
+
path14.join(home, ".cursor"),
|
|
14973
|
+
process.env["XDG_CONFIG_HOME"] || path14.join(home, ".config"),
|
|
14974
|
+
path14.join(home, "Documents"),
|
|
14975
|
+
path14.join(home, "Downloads")
|
|
14335
14976
|
];
|
|
14336
14977
|
const timeoutPromise = new Promise(
|
|
14337
14978
|
(resolve) => setTimeout(() => {
|
|
@@ -14394,7 +15035,7 @@ var McpUsageService = class {
|
|
|
14394
15035
|
generateHostId() {
|
|
14395
15036
|
const stored = configStore.get(this.configKey);
|
|
14396
15037
|
if (stored?.mcpHostId) return stored.mcpHostId;
|
|
14397
|
-
const interfaces =
|
|
15038
|
+
const interfaces = os6.networkInterfaces();
|
|
14398
15039
|
const macs = [];
|
|
14399
15040
|
for (const iface of Object.values(interfaces)) {
|
|
14400
15041
|
if (!iface) continue;
|
|
@@ -14402,7 +15043,7 @@ var McpUsageService = class {
|
|
|
14402
15043
|
if (net.mac && net.mac !== "00:00:00:00:00:00") macs.push(net.mac);
|
|
14403
15044
|
}
|
|
14404
15045
|
}
|
|
14405
|
-
const macString = macs.length ? macs.sort().join(",") : `${
|
|
15046
|
+
const macString = macs.length ? macs.sort().join(",") : `${os6.hostname()}-${uuidv43()}`;
|
|
14406
15047
|
const hostId = uuidv5(macString, uuidv5.DNS);
|
|
14407
15048
|
logDebug("[UsageService] Generated new host ID", { hostId });
|
|
14408
15049
|
return hostId;
|
|
@@ -14425,7 +15066,7 @@ var McpUsageService = class {
|
|
|
14425
15066
|
mcpHostId,
|
|
14426
15067
|
organizationId,
|
|
14427
15068
|
mcpVersion: packageJson.version,
|
|
14428
|
-
mcpOsName:
|
|
15069
|
+
mcpOsName: os6.platform(),
|
|
14429
15070
|
mcps: JSON.stringify(mcps),
|
|
14430
15071
|
status,
|
|
14431
15072
|
userName: user.name,
|
|
@@ -14599,7 +15240,7 @@ var ToolRegistry = class {
|
|
|
14599
15240
|
|
|
14600
15241
|
// src/mcp/core/McpServer.ts
|
|
14601
15242
|
var McpServer = class {
|
|
14602
|
-
constructor(
|
|
15243
|
+
constructor(config7, govOrgId = "") {
|
|
14603
15244
|
__publicField(this, "server");
|
|
14604
15245
|
__publicField(this, "toolRegistry");
|
|
14605
15246
|
__publicField(this, "promptRegistry");
|
|
@@ -14613,8 +15254,8 @@ var McpServer = class {
|
|
|
14613
15254
|
this.mcpUsageService = govOrgId ? new McpUsageService(govOrgId) : null;
|
|
14614
15255
|
this.server = new Server(
|
|
14615
15256
|
{
|
|
14616
|
-
name:
|
|
14617
|
-
version:
|
|
15257
|
+
name: config7.name,
|
|
15258
|
+
version: config7.version
|
|
14618
15259
|
},
|
|
14619
15260
|
{
|
|
14620
15261
|
capabilities: {
|
|
@@ -14630,7 +15271,7 @@ var McpServer = class {
|
|
|
14630
15271
|
this.setupParentProcessMonitoring();
|
|
14631
15272
|
logInfo("MCP server instance created");
|
|
14632
15273
|
logDebug("MCP server instance config", {
|
|
14633
|
-
config:
|
|
15274
|
+
config: config7,
|
|
14634
15275
|
parentPid: this.parentPid
|
|
14635
15276
|
});
|
|
14636
15277
|
}
|
|
@@ -15088,10 +15729,10 @@ var McpServer = class {
|
|
|
15088
15729
|
};
|
|
15089
15730
|
|
|
15090
15731
|
// src/mcp/prompts/CheckForNewVulnerabilitiesPrompt.ts
|
|
15091
|
-
import { z as
|
|
15732
|
+
import { z as z35 } from "zod";
|
|
15092
15733
|
|
|
15093
15734
|
// src/mcp/prompts/base/BasePrompt.ts
|
|
15094
|
-
import { z as
|
|
15735
|
+
import { z as z34 } from "zod";
|
|
15095
15736
|
var BasePrompt = class {
|
|
15096
15737
|
getDefinition() {
|
|
15097
15738
|
return {
|
|
@@ -15120,7 +15761,7 @@ var BasePrompt = class {
|
|
|
15120
15761
|
const argsToValidate = args === void 0 ? {} : args;
|
|
15121
15762
|
return this.argumentsValidationSchema.parse(argsToValidate);
|
|
15122
15763
|
} catch (error) {
|
|
15123
|
-
if (error instanceof
|
|
15764
|
+
if (error instanceof z34.ZodError) {
|
|
15124
15765
|
const errorDetails = error.errors.map((e) => {
|
|
15125
15766
|
const fieldPath = e.path.length > 0 ? e.path.join(".") : "root";
|
|
15126
15767
|
const message = e.message === "Required" ? `Missing required argument '${fieldPath}'` : `Invalid value for '${fieldPath}': ${e.message}`;
|
|
@@ -15149,8 +15790,8 @@ var BasePrompt = class {
|
|
|
15149
15790
|
};
|
|
15150
15791
|
|
|
15151
15792
|
// src/mcp/prompts/CheckForNewVulnerabilitiesPrompt.ts
|
|
15152
|
-
var CheckForNewVulnerabilitiesArgsSchema =
|
|
15153
|
-
path:
|
|
15793
|
+
var CheckForNewVulnerabilitiesArgsSchema = z35.object({
|
|
15794
|
+
path: z35.string().optional()
|
|
15154
15795
|
});
|
|
15155
15796
|
var CheckForNewVulnerabilitiesPrompt = class extends BasePrompt {
|
|
15156
15797
|
constructor() {
|
|
@@ -15395,9 +16036,9 @@ Call the \`check_for_new_available_fixes\` tool now${args?.path ? ` for ${args.p
|
|
|
15395
16036
|
};
|
|
15396
16037
|
|
|
15397
16038
|
// src/mcp/prompts/FullSecurityAuditPrompt.ts
|
|
15398
|
-
import { z as
|
|
15399
|
-
var FullSecurityAuditArgsSchema =
|
|
15400
|
-
path:
|
|
16039
|
+
import { z as z36 } from "zod";
|
|
16040
|
+
var FullSecurityAuditArgsSchema = z36.object({
|
|
16041
|
+
path: z36.string().optional()
|
|
15401
16042
|
});
|
|
15402
16043
|
var FullSecurityAuditPrompt = class extends BasePrompt {
|
|
15403
16044
|
constructor() {
|
|
@@ -15848,9 +16489,9 @@ Begin the audit now${args?.path ? ` for ${args.path}` : ""}.
|
|
|
15848
16489
|
};
|
|
15849
16490
|
|
|
15850
16491
|
// src/mcp/prompts/ReviewAndFixCriticalPrompt.ts
|
|
15851
|
-
import { z as
|
|
15852
|
-
var ReviewAndFixCriticalArgsSchema =
|
|
15853
|
-
path:
|
|
16492
|
+
import { z as z37 } from "zod";
|
|
16493
|
+
var ReviewAndFixCriticalArgsSchema = z37.object({
|
|
16494
|
+
path: z37.string().optional()
|
|
15854
16495
|
});
|
|
15855
16496
|
var ReviewAndFixCriticalPrompt = class extends BasePrompt {
|
|
15856
16497
|
constructor() {
|
|
@@ -16154,9 +16795,9 @@ Start by scanning${args?.path ? ` ${args.path}` : " the repository"} and priorit
|
|
|
16154
16795
|
};
|
|
16155
16796
|
|
|
16156
16797
|
// src/mcp/prompts/ScanRecentChangesPrompt.ts
|
|
16157
|
-
import { z as
|
|
16158
|
-
var ScanRecentChangesArgsSchema =
|
|
16159
|
-
path:
|
|
16798
|
+
import { z as z38 } from "zod";
|
|
16799
|
+
var ScanRecentChangesArgsSchema = z38.object({
|
|
16800
|
+
path: z38.string().optional()
|
|
16160
16801
|
});
|
|
16161
16802
|
var ScanRecentChangesPrompt = class extends BasePrompt {
|
|
16162
16803
|
constructor() {
|
|
@@ -16367,9 +17008,9 @@ You now have the guidance needed to perform a fast, targeted security scan of re
|
|
|
16367
17008
|
};
|
|
16368
17009
|
|
|
16369
17010
|
// src/mcp/prompts/ScanRepositoryPrompt.ts
|
|
16370
|
-
import { z as
|
|
16371
|
-
var ScanRepositoryArgsSchema =
|
|
16372
|
-
path:
|
|
17011
|
+
import { z as z39 } from "zod";
|
|
17012
|
+
var ScanRepositoryArgsSchema = z39.object({
|
|
17013
|
+
path: z39.string().optional()
|
|
16373
17014
|
});
|
|
16374
17015
|
var ScanRepositoryPrompt = class extends BasePrompt {
|
|
16375
17016
|
constructor() {
|
|
@@ -16748,30 +17389,30 @@ For a complete security audit workflow, use the \`full-security-audit\` prompt.
|
|
|
16748
17389
|
|
|
16749
17390
|
// src/mcp/services/McpDetectionService/CursorMcpDetectionService.ts
|
|
16750
17391
|
import * as fs15 from "fs";
|
|
16751
|
-
import * as
|
|
16752
|
-
import * as
|
|
17392
|
+
import * as os8 from "os";
|
|
17393
|
+
import * as path16 from "path";
|
|
16753
17394
|
|
|
16754
17395
|
// src/mcp/services/McpDetectionService/BaseMcpDetectionService.ts
|
|
16755
17396
|
init_configs();
|
|
16756
17397
|
import * as fs14 from "fs";
|
|
16757
17398
|
import fetch6 from "node-fetch";
|
|
16758
|
-
import * as
|
|
17399
|
+
import * as path15 from "path";
|
|
16759
17400
|
|
|
16760
17401
|
// src/mcp/services/McpDetectionService/McpDetectionServiceUtils.ts
|
|
16761
17402
|
import * as fs13 from "fs";
|
|
16762
|
-
import * as
|
|
17403
|
+
import * as os7 from "os";
|
|
16763
17404
|
|
|
16764
17405
|
// src/mcp/services/McpDetectionService/VscodeMcpDetectionService.ts
|
|
16765
17406
|
import * as fs16 from "fs";
|
|
16766
|
-
import * as
|
|
16767
|
-
import * as
|
|
17407
|
+
import * as os9 from "os";
|
|
17408
|
+
import * as path17 from "path";
|
|
16768
17409
|
|
|
16769
17410
|
// src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesTool.ts
|
|
16770
|
-
import { z as
|
|
17411
|
+
import { z as z42 } from "zod";
|
|
16771
17412
|
|
|
16772
17413
|
// src/mcp/services/PathValidation.ts
|
|
16773
17414
|
import fs17 from "fs";
|
|
16774
|
-
import
|
|
17415
|
+
import path18 from "path";
|
|
16775
17416
|
async function validatePath(inputPath) {
|
|
16776
17417
|
logDebug("Validating MCP path", { inputPath });
|
|
16777
17418
|
if (/^\/[a-zA-Z]:\//.test(inputPath)) {
|
|
@@ -16803,7 +17444,7 @@ async function validatePath(inputPath) {
|
|
|
16803
17444
|
logError(error);
|
|
16804
17445
|
return { isValid: false, error, path: inputPath };
|
|
16805
17446
|
}
|
|
16806
|
-
const normalizedPath =
|
|
17447
|
+
const normalizedPath = path18.normalize(inputPath);
|
|
16807
17448
|
if (normalizedPath.includes("..")) {
|
|
16808
17449
|
const error = `Normalized path contains path traversal patterns: ${inputPath}`;
|
|
16809
17450
|
logError(error);
|
|
@@ -16843,7 +17484,7 @@ async function validatePath(inputPath) {
|
|
|
16843
17484
|
}
|
|
16844
17485
|
|
|
16845
17486
|
// src/mcp/tools/base/BaseTool.ts
|
|
16846
|
-
import { z as
|
|
17487
|
+
import { z as z40 } from "zod";
|
|
16847
17488
|
var BaseTool = class {
|
|
16848
17489
|
getDefinition() {
|
|
16849
17490
|
return {
|
|
@@ -16873,7 +17514,7 @@ var BaseTool = class {
|
|
|
16873
17514
|
try {
|
|
16874
17515
|
return this.inputValidationSchema.parse(args);
|
|
16875
17516
|
} catch (error) {
|
|
16876
|
-
if (error instanceof
|
|
17517
|
+
if (error instanceof z40.ZodError) {
|
|
16877
17518
|
const errorDetails = error.errors.map((e) => {
|
|
16878
17519
|
const fieldPath = e.path.length > 0 ? e.path.join(".") : "root";
|
|
16879
17520
|
const message = e.message === "Required" ? `Missing required parameter '${fieldPath}'` : `Invalid value for '${fieldPath}': ${e.message}`;
|
|
@@ -17457,7 +18098,7 @@ init_configs();
|
|
|
17457
18098
|
import fs18 from "fs/promises";
|
|
17458
18099
|
import nodePath from "path";
|
|
17459
18100
|
var getLocalFiles = async ({
|
|
17460
|
-
path:
|
|
18101
|
+
path: path22,
|
|
17461
18102
|
maxFileSize = MCP_MAX_FILE_SIZE,
|
|
17462
18103
|
maxFiles,
|
|
17463
18104
|
isAllFilesScan,
|
|
@@ -17465,17 +18106,17 @@ var getLocalFiles = async ({
|
|
|
17465
18106
|
scanRecentlyChangedFiles
|
|
17466
18107
|
}) => {
|
|
17467
18108
|
logDebug(`[${scanContext}] Starting getLocalFiles`, {
|
|
17468
|
-
path:
|
|
18109
|
+
path: path22,
|
|
17469
18110
|
maxFileSize,
|
|
17470
18111
|
maxFiles,
|
|
17471
18112
|
isAllFilesScan,
|
|
17472
18113
|
scanRecentlyChangedFiles
|
|
17473
18114
|
});
|
|
17474
18115
|
try {
|
|
17475
|
-
const resolvedRepoPath = await fs18.realpath(
|
|
18116
|
+
const resolvedRepoPath = await fs18.realpath(path22);
|
|
17476
18117
|
logDebug(`[${scanContext}] Resolved repository path`, {
|
|
17477
18118
|
resolvedRepoPath,
|
|
17478
|
-
originalPath:
|
|
18119
|
+
originalPath: path22
|
|
17479
18120
|
});
|
|
17480
18121
|
const gitService = new GitService(resolvedRepoPath, log);
|
|
17481
18122
|
const gitValidation = await gitService.validateRepository();
|
|
@@ -17488,7 +18129,7 @@ var getLocalFiles = async ({
|
|
|
17488
18129
|
if (!gitValidation.isValid || isAllFilesScan) {
|
|
17489
18130
|
try {
|
|
17490
18131
|
files = await FileUtils.getLastChangedFiles({
|
|
17491
|
-
dir:
|
|
18132
|
+
dir: path22,
|
|
17492
18133
|
maxFileSize,
|
|
17493
18134
|
maxFiles,
|
|
17494
18135
|
isAllFilesScan
|
|
@@ -17580,7 +18221,7 @@ var getLocalFiles = async ({
|
|
|
17580
18221
|
logError(`${scanContext}Unexpected error in getLocalFiles`, {
|
|
17581
18222
|
error: error instanceof Error ? error.message : String(error),
|
|
17582
18223
|
stack: error instanceof Error ? error.stack : void 0,
|
|
17583
|
-
path:
|
|
18224
|
+
path: path22
|
|
17584
18225
|
});
|
|
17585
18226
|
throw error;
|
|
17586
18227
|
}
|
|
@@ -17588,15 +18229,15 @@ var getLocalFiles = async ({
|
|
|
17588
18229
|
|
|
17589
18230
|
// src/mcp/services/LocalMobbFolderService.ts
|
|
17590
18231
|
import fs19 from "fs";
|
|
17591
|
-
import
|
|
17592
|
-
import { z as
|
|
18232
|
+
import path19 from "path";
|
|
18233
|
+
import { z as z41 } from "zod";
|
|
17593
18234
|
init_GitService();
|
|
17594
18235
|
function extractPathFromPatch(patch) {
|
|
17595
18236
|
const match = patch?.match(/diff --git a\/([^\s]+) b\//);
|
|
17596
18237
|
return match?.[1] ?? null;
|
|
17597
18238
|
}
|
|
17598
18239
|
function parsedIssueTypeRes(issueType) {
|
|
17599
|
-
return
|
|
18240
|
+
return z41.nativeEnum(IssueType_Enum).safeParse(issueType);
|
|
17600
18241
|
}
|
|
17601
18242
|
var LocalMobbFolderService = class {
|
|
17602
18243
|
/**
|
|
@@ -17675,7 +18316,7 @@ var LocalMobbFolderService = class {
|
|
|
17675
18316
|
"[LocalMobbFolderService] Non-git repository detected, skipping .gitignore operations"
|
|
17676
18317
|
);
|
|
17677
18318
|
}
|
|
17678
|
-
const mobbFolderPath =
|
|
18319
|
+
const mobbFolderPath = path19.join(
|
|
17679
18320
|
this.repoPath,
|
|
17680
18321
|
this.defaultMobbFolderName
|
|
17681
18322
|
);
|
|
@@ -17847,7 +18488,7 @@ var LocalMobbFolderService = class {
|
|
|
17847
18488
|
mobbFolderPath,
|
|
17848
18489
|
baseFileName
|
|
17849
18490
|
);
|
|
17850
|
-
const filePath =
|
|
18491
|
+
const filePath = path19.join(mobbFolderPath, uniqueFileName);
|
|
17851
18492
|
await fs19.promises.writeFile(filePath, patch, "utf8");
|
|
17852
18493
|
logInfo("[LocalMobbFolderService] Patch saved successfully", {
|
|
17853
18494
|
filePath,
|
|
@@ -17905,11 +18546,11 @@ var LocalMobbFolderService = class {
|
|
|
17905
18546
|
* @returns Unique filename that doesn't conflict with existing files
|
|
17906
18547
|
*/
|
|
17907
18548
|
getUniqueFileName(folderPath, baseFileName) {
|
|
17908
|
-
const baseName =
|
|
17909
|
-
const extension =
|
|
18549
|
+
const baseName = path19.parse(baseFileName).name;
|
|
18550
|
+
const extension = path19.parse(baseFileName).ext;
|
|
17910
18551
|
let uniqueFileName = baseFileName;
|
|
17911
18552
|
let index = 1;
|
|
17912
|
-
while (fs19.existsSync(
|
|
18553
|
+
while (fs19.existsSync(path19.join(folderPath, uniqueFileName))) {
|
|
17913
18554
|
uniqueFileName = `${baseName}-${index}${extension}`;
|
|
17914
18555
|
index++;
|
|
17915
18556
|
if (index > 1e3) {
|
|
@@ -17940,7 +18581,7 @@ var LocalMobbFolderService = class {
|
|
|
17940
18581
|
logDebug("[LocalMobbFolderService] Logging patch info", { fixId: fix.id });
|
|
17941
18582
|
try {
|
|
17942
18583
|
const mobbFolderPath = await this.getFolder();
|
|
17943
|
-
const patchInfoPath =
|
|
18584
|
+
const patchInfoPath = path19.join(mobbFolderPath, "patchInfo.md");
|
|
17944
18585
|
const markdownContent = this.generateFixMarkdown(fix, savedPatchFileName);
|
|
17945
18586
|
let existingContent = "";
|
|
17946
18587
|
if (fs19.existsSync(patchInfoPath)) {
|
|
@@ -17982,7 +18623,7 @@ var LocalMobbFolderService = class {
|
|
|
17982
18623
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
17983
18624
|
const patch = this.extractPatchFromFix(fix);
|
|
17984
18625
|
const relativePatchedFilePath = patch ? extractPathFromPatch(patch) : null;
|
|
17985
|
-
const patchedFilePath = relativePatchedFilePath ?
|
|
18626
|
+
const patchedFilePath = relativePatchedFilePath ? path19.resolve(this.repoPath, relativePatchedFilePath) : null;
|
|
17986
18627
|
const fixIdentifier = savedPatchFileName ? savedPatchFileName.replace(".patch", "") : fix.id;
|
|
17987
18628
|
let markdown = `# Fix ${fixIdentifier}
|
|
17988
18629
|
|
|
@@ -18326,14 +18967,14 @@ import {
|
|
|
18326
18967
|
} from "fs";
|
|
18327
18968
|
import fs20 from "fs/promises";
|
|
18328
18969
|
import parseDiff2 from "parse-diff";
|
|
18329
|
-
import
|
|
18970
|
+
import path20 from "path";
|
|
18330
18971
|
var PatchApplicationService = class {
|
|
18331
18972
|
/**
|
|
18332
18973
|
* Gets the appropriate comment syntax for a file based on its extension
|
|
18333
18974
|
*/
|
|
18334
18975
|
static getCommentSyntax(filePath) {
|
|
18335
|
-
const ext =
|
|
18336
|
-
const basename2 =
|
|
18976
|
+
const ext = path20.extname(filePath).toLowerCase();
|
|
18977
|
+
const basename2 = path20.basename(filePath);
|
|
18337
18978
|
const commentMap = {
|
|
18338
18979
|
// C-style languages (single line comments)
|
|
18339
18980
|
".js": "//",
|
|
@@ -18536,7 +19177,7 @@ var PatchApplicationService = class {
|
|
|
18536
19177
|
}
|
|
18537
19178
|
);
|
|
18538
19179
|
}
|
|
18539
|
-
const dirPath =
|
|
19180
|
+
const dirPath = path20.dirname(filePath);
|
|
18540
19181
|
mkdirSync(dirPath, { recursive: true });
|
|
18541
19182
|
writeFileSync(filePath, finalContent, "utf8");
|
|
18542
19183
|
return filePath;
|
|
@@ -18820,7 +19461,7 @@ var PatchApplicationService = class {
|
|
|
18820
19461
|
continue;
|
|
18821
19462
|
}
|
|
18822
19463
|
try {
|
|
18823
|
-
const absolutePath =
|
|
19464
|
+
const absolutePath = path20.resolve(repositoryPath, targetFile);
|
|
18824
19465
|
if (existsSync6(absolutePath)) {
|
|
18825
19466
|
const stats = await fs20.stat(absolutePath);
|
|
18826
19467
|
const fileModTime = stats.mtime.getTime();
|
|
@@ -19011,11 +19652,11 @@ var PatchApplicationService = class {
|
|
|
19011
19652
|
}) {
|
|
19012
19653
|
const sanitizedRepoPath = String(repositoryPath || "").replace("\0", "").replace(/^(\.\.(\/|\\))+/, "");
|
|
19013
19654
|
const sanitizedTargetFile = String(targetFile || "").replace("\0", "").replace(/^(\.\.(\/|\\))+/, "");
|
|
19014
|
-
const absoluteFilePath =
|
|
19655
|
+
const absoluteFilePath = path20.resolve(
|
|
19015
19656
|
sanitizedRepoPath,
|
|
19016
19657
|
sanitizedTargetFile
|
|
19017
19658
|
);
|
|
19018
|
-
const relativePath =
|
|
19659
|
+
const relativePath = path20.relative(sanitizedRepoPath, absoluteFilePath);
|
|
19019
19660
|
if (relativePath.startsWith("..")) {
|
|
19020
19661
|
throw new Error(
|
|
19021
19662
|
`Security violation: target file ${targetFile} resolves outside repository`
|
|
@@ -19049,7 +19690,7 @@ var PatchApplicationService = class {
|
|
|
19049
19690
|
fix,
|
|
19050
19691
|
scanContext
|
|
19051
19692
|
});
|
|
19052
|
-
appliedFiles.push(
|
|
19693
|
+
appliedFiles.push(path20.relative(repositoryPath, actualPath));
|
|
19053
19694
|
logDebug(`[${scanContext}] Created new file: ${relativePath}`);
|
|
19054
19695
|
}
|
|
19055
19696
|
/**
|
|
@@ -19097,7 +19738,7 @@ var PatchApplicationService = class {
|
|
|
19097
19738
|
fix,
|
|
19098
19739
|
scanContext
|
|
19099
19740
|
});
|
|
19100
|
-
appliedFiles.push(
|
|
19741
|
+
appliedFiles.push(path20.relative(repositoryPath, actualPath));
|
|
19101
19742
|
logDebug(`[${scanContext}] Modified file: ${relativePath}`);
|
|
19102
19743
|
}
|
|
19103
19744
|
}
|
|
@@ -19293,7 +19934,7 @@ init_configs();
|
|
|
19293
19934
|
// src/mcp/services/FileOperations.ts
|
|
19294
19935
|
init_FileUtils();
|
|
19295
19936
|
import fs21 from "fs";
|
|
19296
|
-
import
|
|
19937
|
+
import path21 from "path";
|
|
19297
19938
|
import AdmZip2 from "adm-zip";
|
|
19298
19939
|
var FileOperations = class {
|
|
19299
19940
|
/**
|
|
@@ -19313,10 +19954,10 @@ var FileOperations = class {
|
|
|
19313
19954
|
let packedFilesCount = 0;
|
|
19314
19955
|
const packedFiles = [];
|
|
19315
19956
|
const excludedFiles = [];
|
|
19316
|
-
const resolvedRepoPath =
|
|
19957
|
+
const resolvedRepoPath = path21.resolve(repositoryPath);
|
|
19317
19958
|
for (const filepath of fileList) {
|
|
19318
|
-
const absoluteFilepath =
|
|
19319
|
-
const resolvedFilePath =
|
|
19959
|
+
const absoluteFilepath = path21.join(repositoryPath, filepath);
|
|
19960
|
+
const resolvedFilePath = path21.resolve(absoluteFilepath);
|
|
19320
19961
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
19321
19962
|
const reason = "potential path traversal security risk";
|
|
19322
19963
|
logDebug(`[FileOperations] Skipping ${filepath} due to ${reason}`);
|
|
@@ -19363,11 +20004,11 @@ var FileOperations = class {
|
|
|
19363
20004
|
fileList,
|
|
19364
20005
|
repositoryPath
|
|
19365
20006
|
}) {
|
|
19366
|
-
const resolvedRepoPath =
|
|
20007
|
+
const resolvedRepoPath = path21.resolve(repositoryPath);
|
|
19367
20008
|
const validatedPaths = [];
|
|
19368
20009
|
for (const filepath of fileList) {
|
|
19369
|
-
const absoluteFilepath =
|
|
19370
|
-
const resolvedFilePath =
|
|
20010
|
+
const absoluteFilepath = path21.join(repositoryPath, filepath);
|
|
20011
|
+
const resolvedFilePath = path21.resolve(absoluteFilepath);
|
|
19371
20012
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
19372
20013
|
logDebug(
|
|
19373
20014
|
`[FileOperations] Rejecting ${filepath} - path traversal attempt detected`
|
|
@@ -19395,7 +20036,7 @@ var FileOperations = class {
|
|
|
19395
20036
|
for (const absolutePath of filePaths) {
|
|
19396
20037
|
try {
|
|
19397
20038
|
const content = await fs21.promises.readFile(absolutePath);
|
|
19398
|
-
const relativePath =
|
|
20039
|
+
const relativePath = path21.basename(absolutePath);
|
|
19399
20040
|
fileDataArray.push({
|
|
19400
20041
|
relativePath,
|
|
19401
20042
|
absolutePath,
|
|
@@ -19707,14 +20348,14 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
19707
20348
|
* since the last scan.
|
|
19708
20349
|
*/
|
|
19709
20350
|
async scanForSecurityVulnerabilities({
|
|
19710
|
-
path:
|
|
20351
|
+
path: path22,
|
|
19711
20352
|
isAllDetectionRulesScan,
|
|
19712
20353
|
isAllFilesScan,
|
|
19713
20354
|
scanContext
|
|
19714
20355
|
}) {
|
|
19715
20356
|
this.hasAuthenticationFailed = false;
|
|
19716
20357
|
logDebug(`[${scanContext}] Scanning for new security vulnerabilities`, {
|
|
19717
|
-
path:
|
|
20358
|
+
path: path22
|
|
19718
20359
|
});
|
|
19719
20360
|
if (!this.gqlClient) {
|
|
19720
20361
|
logInfo(`[${scanContext}] No GQL client found, skipping scan`);
|
|
@@ -19730,11 +20371,11 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
19730
20371
|
}
|
|
19731
20372
|
logDebug(
|
|
19732
20373
|
`[${scanContext}] Connected to the API, assembling list of files to scan`,
|
|
19733
|
-
{ path:
|
|
20374
|
+
{ path: path22 }
|
|
19734
20375
|
);
|
|
19735
20376
|
const isBackgroundScan = scanContext === ScanContext.BACKGROUND_INITIAL || scanContext === ScanContext.BACKGROUND_PERIODIC;
|
|
19736
20377
|
const files = await getLocalFiles({
|
|
19737
|
-
path:
|
|
20378
|
+
path: path22,
|
|
19738
20379
|
isAllFilesScan,
|
|
19739
20380
|
scanContext,
|
|
19740
20381
|
scanRecentlyChangedFiles: !isBackgroundScan
|
|
@@ -19760,13 +20401,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
19760
20401
|
});
|
|
19761
20402
|
const { fixReportId, projectId } = await scanFiles({
|
|
19762
20403
|
fileList: filesToScan.map((file) => file.relativePath),
|
|
19763
|
-
repositoryPath:
|
|
20404
|
+
repositoryPath: path22,
|
|
19764
20405
|
gqlClient: this.gqlClient,
|
|
19765
20406
|
isAllDetectionRulesScan,
|
|
19766
20407
|
scanContext
|
|
19767
20408
|
});
|
|
19768
20409
|
logInfo(
|
|
19769
|
-
`[${scanContext}] Security scan completed for ${
|
|
20410
|
+
`[${scanContext}] Security scan completed for ${path22} reportId: ${fixReportId} projectId: ${projectId}`
|
|
19770
20411
|
);
|
|
19771
20412
|
if (isAllFilesScan) {
|
|
19772
20413
|
return;
|
|
@@ -20060,13 +20701,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
20060
20701
|
});
|
|
20061
20702
|
return scannedFiles.some((file) => file.relativePath === fixFile);
|
|
20062
20703
|
}
|
|
20063
|
-
async getFreshFixes({ path:
|
|
20704
|
+
async getFreshFixes({ path: path22 }) {
|
|
20064
20705
|
const scanContext = ScanContext.USER_REQUEST;
|
|
20065
|
-
logDebug(`[${scanContext}] Getting fresh fixes`, { path:
|
|
20066
|
-
if (this.path !==
|
|
20067
|
-
this.path =
|
|
20706
|
+
logDebug(`[${scanContext}] Getting fresh fixes`, { path: path22 });
|
|
20707
|
+
if (this.path !== path22) {
|
|
20708
|
+
this.path = path22;
|
|
20068
20709
|
this.reset();
|
|
20069
|
-
logInfo(`[${scanContext}] Reset service state for new path`, { path:
|
|
20710
|
+
logInfo(`[${scanContext}] Reset service state for new path`, { path: path22 });
|
|
20070
20711
|
}
|
|
20071
20712
|
try {
|
|
20072
20713
|
this.gqlClient = await createAuthenticatedMcpGQLClient();
|
|
@@ -20084,7 +20725,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
20084
20725
|
}
|
|
20085
20726
|
throw error;
|
|
20086
20727
|
}
|
|
20087
|
-
this.triggerScan({ path:
|
|
20728
|
+
this.triggerScan({ path: path22, gqlClient: this.gqlClient });
|
|
20088
20729
|
let isMvsAutoFixEnabled = null;
|
|
20089
20730
|
try {
|
|
20090
20731
|
isMvsAutoFixEnabled = await this.gqlClient.getMvsAutoFixSettings();
|
|
@@ -20118,33 +20759,33 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
20118
20759
|
return noFreshFixesPrompt;
|
|
20119
20760
|
}
|
|
20120
20761
|
triggerScan({
|
|
20121
|
-
path:
|
|
20762
|
+
path: path22,
|
|
20122
20763
|
gqlClient
|
|
20123
20764
|
}) {
|
|
20124
|
-
if (this.path !==
|
|
20125
|
-
this.path =
|
|
20765
|
+
if (this.path !== path22) {
|
|
20766
|
+
this.path = path22;
|
|
20126
20767
|
this.reset();
|
|
20127
|
-
logInfo(`Reset service state for new path in triggerScan`, { path:
|
|
20768
|
+
logInfo(`Reset service state for new path in triggerScan`, { path: path22 });
|
|
20128
20769
|
}
|
|
20129
20770
|
this.gqlClient = gqlClient;
|
|
20130
20771
|
if (!this.intervalId) {
|
|
20131
|
-
this.startPeriodicScanning(
|
|
20132
|
-
this.executeInitialScan(
|
|
20133
|
-
void this.executeInitialFullScan(
|
|
20772
|
+
this.startPeriodicScanning(path22);
|
|
20773
|
+
this.executeInitialScan(path22);
|
|
20774
|
+
void this.executeInitialFullScan(path22);
|
|
20134
20775
|
}
|
|
20135
20776
|
}
|
|
20136
|
-
startPeriodicScanning(
|
|
20777
|
+
startPeriodicScanning(path22) {
|
|
20137
20778
|
const scanContext = ScanContext.BACKGROUND_PERIODIC;
|
|
20138
20779
|
logDebug(
|
|
20139
20780
|
`[${scanContext}] Starting periodic scan for new security vulnerabilities`,
|
|
20140
20781
|
{
|
|
20141
|
-
path:
|
|
20782
|
+
path: path22
|
|
20142
20783
|
}
|
|
20143
20784
|
);
|
|
20144
20785
|
this.intervalId = setInterval(() => {
|
|
20145
|
-
logDebug(`[${scanContext}] Triggering periodic security scan`, { path:
|
|
20786
|
+
logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path22 });
|
|
20146
20787
|
this.scanForSecurityVulnerabilities({
|
|
20147
|
-
path:
|
|
20788
|
+
path: path22,
|
|
20148
20789
|
scanContext
|
|
20149
20790
|
}).catch((error) => {
|
|
20150
20791
|
logError(`[${scanContext}] Error during periodic security scan`, {
|
|
@@ -20153,45 +20794,45 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
20153
20794
|
});
|
|
20154
20795
|
}, MCP_PERIODIC_CHECK_INTERVAL);
|
|
20155
20796
|
}
|
|
20156
|
-
async executeInitialFullScan(
|
|
20797
|
+
async executeInitialFullScan(path22) {
|
|
20157
20798
|
const scanContext = ScanContext.FULL_SCAN;
|
|
20158
|
-
logDebug(`[${scanContext}] Triggering initial full security scan`, { path:
|
|
20799
|
+
logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path22 });
|
|
20159
20800
|
logDebug(`[${scanContext}] Full scan paths scanned`, {
|
|
20160
20801
|
fullScanPathsScanned: this.fullScanPathsScanned
|
|
20161
20802
|
});
|
|
20162
|
-
if (this.fullScanPathsScanned.includes(
|
|
20803
|
+
if (this.fullScanPathsScanned.includes(path22)) {
|
|
20163
20804
|
logDebug(`[${scanContext}] Full scan already executed for this path`, {
|
|
20164
|
-
path:
|
|
20805
|
+
path: path22
|
|
20165
20806
|
});
|
|
20166
20807
|
return;
|
|
20167
20808
|
}
|
|
20168
20809
|
configStore.set("fullScanPathsScanned", [
|
|
20169
20810
|
...this.fullScanPathsScanned,
|
|
20170
|
-
|
|
20811
|
+
path22
|
|
20171
20812
|
]);
|
|
20172
20813
|
try {
|
|
20173
20814
|
await this.scanForSecurityVulnerabilities({
|
|
20174
|
-
path:
|
|
20815
|
+
path: path22,
|
|
20175
20816
|
isAllFilesScan: true,
|
|
20176
20817
|
isAllDetectionRulesScan: true,
|
|
20177
20818
|
scanContext: ScanContext.FULL_SCAN
|
|
20178
20819
|
});
|
|
20179
|
-
if (!this.fullScanPathsScanned.includes(
|
|
20180
|
-
this.fullScanPathsScanned.push(
|
|
20820
|
+
if (!this.fullScanPathsScanned.includes(path22)) {
|
|
20821
|
+
this.fullScanPathsScanned.push(path22);
|
|
20181
20822
|
configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
|
|
20182
20823
|
}
|
|
20183
|
-
logInfo(`[${scanContext}] Full scan completed`, { path:
|
|
20824
|
+
logInfo(`[${scanContext}] Full scan completed`, { path: path22 });
|
|
20184
20825
|
} catch (error) {
|
|
20185
20826
|
logError(`[${scanContext}] Error during initial full security scan`, {
|
|
20186
20827
|
error
|
|
20187
20828
|
});
|
|
20188
20829
|
}
|
|
20189
20830
|
}
|
|
20190
|
-
executeInitialScan(
|
|
20831
|
+
executeInitialScan(path22) {
|
|
20191
20832
|
const scanContext = ScanContext.BACKGROUND_INITIAL;
|
|
20192
|
-
logDebug(`[${scanContext}] Triggering initial security scan`, { path:
|
|
20833
|
+
logDebug(`[${scanContext}] Triggering initial security scan`, { path: path22 });
|
|
20193
20834
|
this.scanForSecurityVulnerabilities({
|
|
20194
|
-
path:
|
|
20835
|
+
path: path22,
|
|
20195
20836
|
scanContext: ScanContext.BACKGROUND_INITIAL
|
|
20196
20837
|
}).catch((error) => {
|
|
20197
20838
|
logError(`[${scanContext}] Error during initial security scan`, { error });
|
|
@@ -20270,8 +20911,8 @@ Example payload:
|
|
|
20270
20911
|
},
|
|
20271
20912
|
required: ["path"]
|
|
20272
20913
|
});
|
|
20273
|
-
__publicField(this, "inputValidationSchema",
|
|
20274
|
-
path:
|
|
20914
|
+
__publicField(this, "inputValidationSchema", z42.object({
|
|
20915
|
+
path: z42.string().describe(
|
|
20275
20916
|
"Full local path to the cloned git repository to check for new available fixes"
|
|
20276
20917
|
)
|
|
20277
20918
|
}));
|
|
@@ -20288,9 +20929,9 @@ Example payload:
|
|
|
20288
20929
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
20289
20930
|
);
|
|
20290
20931
|
}
|
|
20291
|
-
const
|
|
20932
|
+
const path22 = pathValidationResult.path;
|
|
20292
20933
|
const resultText = await this.newFixesService.getFreshFixes({
|
|
20293
|
-
path:
|
|
20934
|
+
path: path22
|
|
20294
20935
|
});
|
|
20295
20936
|
logInfo("CheckForNewAvailableFixesTool execution completed", {
|
|
20296
20937
|
resultText
|
|
@@ -20301,7 +20942,7 @@ Example payload:
|
|
|
20301
20942
|
|
|
20302
20943
|
// src/mcp/tools/fetchAvailableFixes/FetchAvailableFixesTool.ts
|
|
20303
20944
|
init_GitService();
|
|
20304
|
-
import { z as
|
|
20945
|
+
import { z as z43 } from "zod";
|
|
20305
20946
|
|
|
20306
20947
|
// src/mcp/tools/fetchAvailableFixes/FetchAvailableFixesService.ts
|
|
20307
20948
|
init_configs();
|
|
@@ -20443,16 +21084,16 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
20443
21084
|
},
|
|
20444
21085
|
required: ["path"]
|
|
20445
21086
|
});
|
|
20446
|
-
__publicField(this, "inputValidationSchema",
|
|
20447
|
-
path:
|
|
21087
|
+
__publicField(this, "inputValidationSchema", z43.object({
|
|
21088
|
+
path: z43.string().describe(
|
|
20448
21089
|
"Full local path to the cloned git repository to check for available fixes"
|
|
20449
21090
|
),
|
|
20450
|
-
offset:
|
|
20451
|
-
limit:
|
|
20452
|
-
fileFilter:
|
|
21091
|
+
offset: z43.number().optional().describe("Optional offset for pagination"),
|
|
21092
|
+
limit: z43.number().optional().describe("Optional maximum number of fixes to return"),
|
|
21093
|
+
fileFilter: z43.array(z43.string()).optional().describe(
|
|
20453
21094
|
"Optional list of file paths relative to the path parameter to filter fixes by. INCOMPATIBLE with fetchFixesFromAnyFile"
|
|
20454
21095
|
),
|
|
20455
|
-
fetchFixesFromAnyFile:
|
|
21096
|
+
fetchFixesFromAnyFile: z43.boolean().optional().describe(
|
|
20456
21097
|
"Optional boolean to fetch fixes for all files. INCOMPATIBLE with fileFilter"
|
|
20457
21098
|
)
|
|
20458
21099
|
}));
|
|
@@ -20467,8 +21108,8 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
20467
21108
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
20468
21109
|
);
|
|
20469
21110
|
}
|
|
20470
|
-
const
|
|
20471
|
-
const gitService = new GitService(
|
|
21111
|
+
const path22 = pathValidationResult.path;
|
|
21112
|
+
const gitService = new GitService(path22, log);
|
|
20472
21113
|
const gitValidation = await gitService.validateRepository();
|
|
20473
21114
|
if (!gitValidation.isValid) {
|
|
20474
21115
|
throw new Error(`Invalid git repository: ${gitValidation.error}`);
|
|
@@ -20521,7 +21162,7 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
20521
21162
|
};
|
|
20522
21163
|
|
|
20523
21164
|
// src/mcp/tools/mcpChecker/mcpCheckerTool.ts
|
|
20524
|
-
import
|
|
21165
|
+
import z44 from "zod";
|
|
20525
21166
|
|
|
20526
21167
|
// src/mcp/tools/mcpChecker/mcpCheckerService.ts
|
|
20527
21168
|
var _McpCheckerService = class _McpCheckerService {
|
|
@@ -20582,7 +21223,7 @@ var McpCheckerTool = class extends BaseTool {
|
|
|
20582
21223
|
__publicField(this, "displayName", "MCP Checker");
|
|
20583
21224
|
// A detailed description to guide the LLM on when and how to invoke this tool.
|
|
20584
21225
|
__publicField(this, "description", "Check the MCP servers running on this IDE against organization policies.");
|
|
20585
|
-
__publicField(this, "inputValidationSchema",
|
|
21226
|
+
__publicField(this, "inputValidationSchema", z44.object({}));
|
|
20586
21227
|
__publicField(this, "inputSchema", {
|
|
20587
21228
|
type: "object",
|
|
20588
21229
|
properties: {},
|
|
@@ -20608,7 +21249,7 @@ var McpCheckerTool = class extends BaseTool {
|
|
|
20608
21249
|
};
|
|
20609
21250
|
|
|
20610
21251
|
// src/mcp/tools/scanAndFixVulnerabilities/ScanAndFixVulnerabilitiesTool.ts
|
|
20611
|
-
import
|
|
21252
|
+
import z45 from "zod";
|
|
20612
21253
|
init_configs();
|
|
20613
21254
|
|
|
20614
21255
|
// src/mcp/tools/scanAndFixVulnerabilities/ScanAndFixVulnerabilitiesService.ts
|
|
@@ -20795,17 +21436,17 @@ Example payload:
|
|
|
20795
21436
|
"rescan": false
|
|
20796
21437
|
}`);
|
|
20797
21438
|
__publicField(this, "hasAuthentication", true);
|
|
20798
|
-
__publicField(this, "inputValidationSchema",
|
|
20799
|
-
path:
|
|
21439
|
+
__publicField(this, "inputValidationSchema", z45.object({
|
|
21440
|
+
path: z45.string().describe(
|
|
20800
21441
|
"Full local path to repository to scan and fix vulnerabilities"
|
|
20801
21442
|
),
|
|
20802
|
-
offset:
|
|
20803
|
-
limit:
|
|
20804
|
-
maxFiles:
|
|
21443
|
+
offset: z45.number().optional().describe("Optional offset for pagination"),
|
|
21444
|
+
limit: z45.number().optional().describe("Optional maximum number of results to return"),
|
|
21445
|
+
maxFiles: z45.number().optional().describe(
|
|
20805
21446
|
`Optional maximum number of files to scan (default: ${MCP_DEFAULT_MAX_FILES_TO_SCAN}). Increase for comprehensive scans of larger codebases or decrease for faster focused scans.`
|
|
20806
21447
|
),
|
|
20807
|
-
rescan:
|
|
20808
|
-
scanRecentlyChangedFiles:
|
|
21448
|
+
rescan: z45.boolean().optional().describe("Optional whether to rescan the repository"),
|
|
21449
|
+
scanRecentlyChangedFiles: z45.boolean().optional().describe(
|
|
20809
21450
|
"Optional whether to automatically scan recently changed files when no changed files are found in git status. If false, the tool will prompt the user instead."
|
|
20810
21451
|
)
|
|
20811
21452
|
}));
|
|
@@ -20856,9 +21497,9 @@ Example payload:
|
|
|
20856
21497
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
20857
21498
|
);
|
|
20858
21499
|
}
|
|
20859
|
-
const
|
|
21500
|
+
const path22 = pathValidationResult.path;
|
|
20860
21501
|
const files = await getLocalFiles({
|
|
20861
|
-
path:
|
|
21502
|
+
path: path22,
|
|
20862
21503
|
maxFileSize: MCP_MAX_FILE_SIZE,
|
|
20863
21504
|
maxFiles: args.maxFiles,
|
|
20864
21505
|
scanContext: ScanContext.USER_REQUEST,
|
|
@@ -20878,7 +21519,7 @@ Example payload:
|
|
|
20878
21519
|
try {
|
|
20879
21520
|
const fixResult = await this.vulnerabilityFixService.processVulnerabilities({
|
|
20880
21521
|
fileList: files.map((file) => file.relativePath),
|
|
20881
|
-
repositoryPath:
|
|
21522
|
+
repositoryPath: path22,
|
|
20882
21523
|
offset: args.offset,
|
|
20883
21524
|
limit: args.limit,
|
|
20884
21525
|
isRescan: args.rescan || !!args.maxFiles
|
|
@@ -20983,32 +21624,32 @@ var mcpHandler = async (_args) => {
|
|
|
20983
21624
|
|
|
20984
21625
|
// src/args/commands/review.ts
|
|
20985
21626
|
import fs22 from "fs";
|
|
20986
|
-
import
|
|
21627
|
+
import chalk11 from "chalk";
|
|
20987
21628
|
function reviewBuilder(yargs2) {
|
|
20988
21629
|
return yargs2.option("f", {
|
|
20989
21630
|
alias: "scan-file",
|
|
20990
21631
|
demandOption: true,
|
|
20991
21632
|
type: "string",
|
|
20992
|
-
describe:
|
|
21633
|
+
describe: chalk11.bold(
|
|
20993
21634
|
"Select the vulnerability report to analyze (Checkmarx, Snyk, Fortify, CodeQL, Sonarqube, Semgrep)"
|
|
20994
21635
|
)
|
|
20995
21636
|
}).option("repo", { ...repoOption, demandOption: true }).option("scanner", { ...scannerOptions, demandOption: true }).option("ref", { ...refOption, demandOption: true }).option("ch", {
|
|
20996
21637
|
alias: "commit-hash",
|
|
20997
|
-
describe:
|
|
21638
|
+
describe: chalk11.bold("Hash of the commit"),
|
|
20998
21639
|
type: "string",
|
|
20999
21640
|
demandOption: true
|
|
21000
21641
|
}).option("mobb-project-name", mobbProjectNameOption).option("api-key", { ...apiKeyOption, demandOption: true }).option("commit-hash", { ...commitHashOption, demandOption: true }).option("github-token", {
|
|
21001
|
-
describe:
|
|
21642
|
+
describe: chalk11.bold("Github action token"),
|
|
21002
21643
|
type: "string",
|
|
21003
21644
|
demandOption: true
|
|
21004
21645
|
}).option("pull-request", {
|
|
21005
21646
|
alias: ["pr", "pr-number", "pr-id"],
|
|
21006
|
-
describe:
|
|
21647
|
+
describe: chalk11.bold("Number of the pull request"),
|
|
21007
21648
|
type: "number",
|
|
21008
21649
|
demandOption: true
|
|
21009
21650
|
}).option("p", {
|
|
21010
21651
|
alias: "src-path",
|
|
21011
|
-
describe:
|
|
21652
|
+
describe: chalk11.bold(
|
|
21012
21653
|
"Path to the repository folder with the source code"
|
|
21013
21654
|
),
|
|
21014
21655
|
type: "string",
|
|
@@ -21021,7 +21662,7 @@ function reviewBuilder(yargs2) {
|
|
|
21021
21662
|
function validateReviewOptions(argv) {
|
|
21022
21663
|
if (!fs22.existsSync(argv.f)) {
|
|
21023
21664
|
throw new CliError(`
|
|
21024
|
-
Can't access ${
|
|
21665
|
+
Can't access ${chalk11.bold(argv.f)}`);
|
|
21025
21666
|
}
|
|
21026
21667
|
validateRepoUrl(argv);
|
|
21027
21668
|
validateReportFileFormat(argv.f);
|
|
@@ -21091,248 +21732,77 @@ async function addScmTokenHandler(args) {
|
|
|
21091
21732
|
await addScmToken(args);
|
|
21092
21733
|
}
|
|
21093
21734
|
|
|
21094
|
-
// src/args/commands/upload_ai_blame.ts
|
|
21095
|
-
import fsPromises3 from "fs/promises";
|
|
21096
|
-
import path20 from "path";
|
|
21097
|
-
import chalk10 from "chalk";
|
|
21098
|
-
import Configstore6 from "configstore";
|
|
21099
|
-
import { withFile } from "tmp-promise";
|
|
21100
|
-
import z44 from "zod";
|
|
21101
|
-
var PromptItemZ = z44.object({
|
|
21102
|
-
type: z44.enum(["USER_PROMPT", "AI_RESPONSE", "TOOL_EXECUTION", "AI_THINKING"]),
|
|
21103
|
-
attachedFiles: z44.array(
|
|
21104
|
-
z44.object({
|
|
21105
|
-
relativePath: z44.string(),
|
|
21106
|
-
startLine: z44.number().optional()
|
|
21107
|
-
})
|
|
21108
|
-
).optional(),
|
|
21109
|
-
tokens: z44.object({
|
|
21110
|
-
inputCount: z44.number(),
|
|
21111
|
-
outputCount: z44.number()
|
|
21112
|
-
}).optional(),
|
|
21113
|
-
text: z44.string().optional(),
|
|
21114
|
-
date: z44.date().optional(),
|
|
21115
|
-
tool: z44.object({
|
|
21116
|
-
name: z44.string(),
|
|
21117
|
-
parameters: z44.string(),
|
|
21118
|
-
result: z44.string(),
|
|
21119
|
-
rawArguments: z44.string().optional(),
|
|
21120
|
-
accepted: z44.boolean().optional()
|
|
21121
|
-
}).optional()
|
|
21122
|
-
});
|
|
21123
|
-
var PromptItemArrayZ = z44.array(PromptItemZ);
|
|
21124
|
-
function uploadAiBlameBuilder(args) {
|
|
21125
|
-
return args.option("prompt", {
|
|
21126
|
-
type: "string",
|
|
21127
|
-
array: true,
|
|
21128
|
-
demandOption: true,
|
|
21129
|
-
describe: chalk10.bold("Path(s) to prompt artifact(s) (one per session)")
|
|
21130
|
-
}).option("inference", {
|
|
21131
|
-
type: "string",
|
|
21132
|
-
array: true,
|
|
21133
|
-
demandOption: true,
|
|
21134
|
-
describe: chalk10.bold(
|
|
21135
|
-
"Path(s) to inference artifact(s) (one per session)"
|
|
21136
|
-
)
|
|
21137
|
-
}).option("ai-response-at", {
|
|
21138
|
-
type: "string",
|
|
21139
|
-
array: true,
|
|
21140
|
-
describe: chalk10.bold(
|
|
21141
|
-
"ISO timestamp(s) for AI response (one per session, defaults to now)"
|
|
21142
|
-
)
|
|
21143
|
-
}).option("model", {
|
|
21144
|
-
type: "string",
|
|
21145
|
-
array: true,
|
|
21146
|
-
describe: chalk10.bold("AI model name(s) (optional, one per session)")
|
|
21147
|
-
}).option("tool-name", {
|
|
21148
|
-
type: "string",
|
|
21149
|
-
array: true,
|
|
21150
|
-
describe: chalk10.bold("Tool/IDE name(s) (optional, one per session)")
|
|
21151
|
-
}).option("blame-type", {
|
|
21152
|
-
type: "string",
|
|
21153
|
-
array: true,
|
|
21154
|
-
choices: Object.values(AiBlameInferenceType),
|
|
21155
|
-
describe: chalk10.bold(
|
|
21156
|
-
"Blame type(s) (optional, one per session, defaults to CHAT)"
|
|
21157
|
-
)
|
|
21158
|
-
}).strict();
|
|
21159
|
-
}
|
|
21160
|
-
var config5 = new Configstore6(packageJson.name, { apiToken: "" });
|
|
21161
|
-
async function getAuthenticatedGQLClientForIdeExtension() {
|
|
21162
|
-
let gqlClient = new GQLClient({
|
|
21163
|
-
apiKey: config5.get("apiToken") ?? "",
|
|
21164
|
-
type: "apiKey"
|
|
21165
|
-
});
|
|
21166
|
-
gqlClient = await handleMobbLogin({
|
|
21167
|
-
inGqlClient: gqlClient,
|
|
21168
|
-
skipPrompts: true
|
|
21169
|
-
});
|
|
21170
|
-
return gqlClient;
|
|
21171
|
-
}
|
|
21172
|
-
async function uploadAiBlameHandler(args, exitOnError = true) {
|
|
21173
|
-
const prompts = args.prompt || [];
|
|
21174
|
-
const inferences = args.inference || [];
|
|
21175
|
-
const models = args.model || [];
|
|
21176
|
-
const tools = args.toolName || args["tool-name"] || [];
|
|
21177
|
-
const responseTimes = args.aiResponseAt || args["ai-response-at"] || [];
|
|
21178
|
-
const blameTypes = args.blameType || args["blame-type"] || [];
|
|
21179
|
-
if (prompts.length !== inferences.length) {
|
|
21180
|
-
const errorMsg = "prompt and inference must have the same number of entries";
|
|
21181
|
-
console.error(chalk10.red(errorMsg));
|
|
21182
|
-
if (exitOnError) {
|
|
21183
|
-
process.exit(1);
|
|
21184
|
-
}
|
|
21185
|
-
throw new Error(errorMsg);
|
|
21186
|
-
}
|
|
21187
|
-
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
21188
|
-
const sessions = [];
|
|
21189
|
-
for (let i = 0; i < prompts.length; i++) {
|
|
21190
|
-
const promptPath = String(prompts[i]);
|
|
21191
|
-
const inferencePath = String(inferences[i]);
|
|
21192
|
-
try {
|
|
21193
|
-
await Promise.all([
|
|
21194
|
-
fsPromises3.access(promptPath),
|
|
21195
|
-
fsPromises3.access(inferencePath)
|
|
21196
|
-
]);
|
|
21197
|
-
} catch {
|
|
21198
|
-
const errorMsg = `File not found for session ${i + 1}`;
|
|
21199
|
-
console.error(chalk10.red(errorMsg));
|
|
21200
|
-
if (exitOnError) {
|
|
21201
|
-
process.exit(1);
|
|
21202
|
-
}
|
|
21203
|
-
throw new Error(errorMsg);
|
|
21204
|
-
}
|
|
21205
|
-
sessions.push({
|
|
21206
|
-
promptFileName: path20.basename(promptPath),
|
|
21207
|
-
inferenceFileName: path20.basename(inferencePath),
|
|
21208
|
-
aiResponseAt: responseTimes[i] || nowIso,
|
|
21209
|
-
model: models[i],
|
|
21210
|
-
toolName: tools[i],
|
|
21211
|
-
blameType: blameTypes[i] || "CHAT" /* Chat */
|
|
21212
|
-
});
|
|
21213
|
-
}
|
|
21214
|
-
const authenticatedClient = await getAuthenticatedGQLClientForIdeExtension();
|
|
21215
|
-
const initRes = await authenticatedClient.uploadAIBlameInferencesInitRaw({
|
|
21216
|
-
sessions
|
|
21217
|
-
});
|
|
21218
|
-
const uploadSessions = initRes.uploadAIBlameInferencesInit?.uploadSessions ?? [];
|
|
21219
|
-
if (uploadSessions.length !== sessions.length) {
|
|
21220
|
-
const errorMsg = "Init failed to return expected number of sessions";
|
|
21221
|
-
console.error(chalk10.red(errorMsg));
|
|
21222
|
-
if (exitOnError) {
|
|
21223
|
-
process.exit(1);
|
|
21224
|
-
}
|
|
21225
|
-
throw new Error(errorMsg);
|
|
21226
|
-
}
|
|
21227
|
-
for (let i = 0; i < uploadSessions.length; i++) {
|
|
21228
|
-
const us = uploadSessions[i];
|
|
21229
|
-
const promptPath = String(prompts[i]);
|
|
21230
|
-
const inferencePath = String(inferences[i]);
|
|
21231
|
-
await Promise.all([
|
|
21232
|
-
// Prompt
|
|
21233
|
-
uploadFile({
|
|
21234
|
-
file: promptPath,
|
|
21235
|
-
url: us.prompt.url,
|
|
21236
|
-
uploadFields: JSON.parse(us.prompt.uploadFieldsJSON),
|
|
21237
|
-
uploadKey: us.prompt.uploadKey
|
|
21238
|
-
}),
|
|
21239
|
-
// Inference
|
|
21240
|
-
uploadFile({
|
|
21241
|
-
file: inferencePath,
|
|
21242
|
-
url: us.inference.url,
|
|
21243
|
-
uploadFields: JSON.parse(us.inference.uploadFieldsJSON),
|
|
21244
|
-
uploadKey: us.inference.uploadKey
|
|
21245
|
-
})
|
|
21246
|
-
]);
|
|
21247
|
-
}
|
|
21248
|
-
const finalizeSessions = uploadSessions.map((us, i) => {
|
|
21249
|
-
const s = sessions[i];
|
|
21250
|
-
return {
|
|
21251
|
-
aiBlameInferenceId: us.aiBlameInferenceId,
|
|
21252
|
-
promptKey: us.prompt.uploadKey,
|
|
21253
|
-
inferenceKey: us.inference.uploadKey,
|
|
21254
|
-
aiResponseAt: s.aiResponseAt,
|
|
21255
|
-
model: s.model,
|
|
21256
|
-
toolName: s.toolName,
|
|
21257
|
-
blameType: s.blameType
|
|
21258
|
-
};
|
|
21259
|
-
});
|
|
21260
|
-
const finRes = await authenticatedClient.finalizeAIBlameInferencesUploadRaw({
|
|
21261
|
-
sessions: finalizeSessions
|
|
21262
|
-
});
|
|
21263
|
-
const status = finRes?.finalizeAIBlameInferencesUpload?.status;
|
|
21264
|
-
if (status !== "OK") {
|
|
21265
|
-
const errorMsg = finRes?.finalizeAIBlameInferencesUpload?.error || "unknown error";
|
|
21266
|
-
console.error(chalk10.red(errorMsg));
|
|
21267
|
-
if (exitOnError) {
|
|
21268
|
-
process.exit(1);
|
|
21269
|
-
}
|
|
21270
|
-
throw new Error(errorMsg);
|
|
21271
|
-
}
|
|
21272
|
-
console.log(chalk10.green("AI Blame uploads finalized successfully"));
|
|
21273
|
-
}
|
|
21274
|
-
|
|
21275
21735
|
// src/args/yargs.ts
|
|
21276
21736
|
var parseArgs = async (args) => {
|
|
21277
21737
|
const yargsInstance = yargs(args);
|
|
21278
21738
|
return yargsInstance.updateStrings({
|
|
21279
|
-
"Commands:":
|
|
21280
|
-
"Options:":
|
|
21281
|
-
"Examples:":
|
|
21282
|
-
"Show help":
|
|
21739
|
+
"Commands:": chalk12.yellow.underline.bold("Commands:"),
|
|
21740
|
+
"Options:": chalk12.yellow.underline.bold("Options:"),
|
|
21741
|
+
"Examples:": chalk12.yellow.underline.bold("Examples:"),
|
|
21742
|
+
"Show help": chalk12.bold("Show help")
|
|
21283
21743
|
}).usage(
|
|
21284
|
-
`${
|
|
21744
|
+
`${chalk12.bold(
|
|
21285
21745
|
"\n Bugsy - Trusted, Automatic Vulnerability Fixer \u{1F575}\uFE0F\u200D\u2642\uFE0F\n\n"
|
|
21286
|
-
)} ${
|
|
21287
|
-
$0 ${
|
|
21746
|
+
)} ${chalk12.yellow.underline.bold("Usage:")}
|
|
21747
|
+
$0 ${chalk12.green(
|
|
21288
21748
|
"<command>"
|
|
21289
|
-
)} ${
|
|
21749
|
+
)} ${chalk12.dim("[options]")}
|
|
21290
21750
|
`
|
|
21291
21751
|
).version(false).command(
|
|
21292
21752
|
mobbCliCommand.scan,
|
|
21293
|
-
|
|
21753
|
+
chalk12.bold(
|
|
21294
21754
|
"Scan your code for vulnerabilities, get automated fixes right away."
|
|
21295
21755
|
),
|
|
21296
21756
|
scanBuilder,
|
|
21297
21757
|
scanHandler
|
|
21298
21758
|
).command(
|
|
21299
21759
|
mobbCliCommand.analyze,
|
|
21300
|
-
|
|
21760
|
+
chalk12.bold(
|
|
21301
21761
|
"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."
|
|
21302
21762
|
),
|
|
21303
21763
|
analyzeBuilder,
|
|
21304
21764
|
analyzeHandler
|
|
21305
21765
|
).command(
|
|
21306
21766
|
mobbCliCommand.review,
|
|
21307
|
-
|
|
21767
|
+
chalk12.bold(
|
|
21308
21768
|
"Mobb will review your github pull requests and provide comments with fixes "
|
|
21309
21769
|
),
|
|
21310
21770
|
reviewBuilder,
|
|
21311
21771
|
reviewHandler
|
|
21312
21772
|
).command(
|
|
21313
21773
|
mobbCliCommand.addScmToken,
|
|
21314
|
-
|
|
21774
|
+
chalk12.bold(
|
|
21315
21775
|
"Add your SCM (Github, Gitlab, Azure DevOps) token to Mobb to enable automated fixes."
|
|
21316
21776
|
),
|
|
21317
21777
|
addScmTokenBuilder,
|
|
21318
21778
|
addScmTokenHandler
|
|
21319
21779
|
).command(
|
|
21320
21780
|
mobbCliCommand.convertToSarif,
|
|
21321
|
-
|
|
21781
|
+
chalk12.bold("Convert an existing SAST report to SARIF format."),
|
|
21322
21782
|
convertToSarifBuilder,
|
|
21323
21783
|
convertToSarifHandler
|
|
21324
21784
|
).command(
|
|
21325
21785
|
mobbCliCommand.mcp,
|
|
21326
|
-
|
|
21786
|
+
chalk12.bold("Launch the MCP (Model Context Protocol) server."),
|
|
21327
21787
|
mcpBuilder,
|
|
21328
21788
|
mcpHandler
|
|
21329
21789
|
).command(
|
|
21330
21790
|
mobbCliCommand.uploadAiBlame,
|
|
21331
|
-
|
|
21791
|
+
chalk12.bold(
|
|
21332
21792
|
"Upload AI Blame inference artifacts (prompt + inference) and finalize them."
|
|
21333
21793
|
),
|
|
21334
21794
|
uploadAiBlameBuilder,
|
|
21335
21795
|
uploadAiBlameHandler
|
|
21796
|
+
).command(
|
|
21797
|
+
mobbCliCommand.claudeCodeInstallHook,
|
|
21798
|
+
chalk12.bold("Install Claude Code hooks for data collection."),
|
|
21799
|
+
claudeCodeInstallHookBuilder,
|
|
21800
|
+
claudeCodeInstallHookHandler
|
|
21801
|
+
).command(
|
|
21802
|
+
mobbCliCommand.claudeCodeProcessHook,
|
|
21803
|
+
chalk12.bold("Process Claude Code hook data and upload to backend."),
|
|
21804
|
+
claudeCodeProcessHookBuilder,
|
|
21805
|
+
claudeCodeProcessHookHandler
|
|
21336
21806
|
).example(
|
|
21337
21807
|
"npx mobbdev@latest scan -r https://github.com/WebGoat/WebGoat",
|
|
21338
21808
|
"Scan an existing repository"
|
|
@@ -21341,7 +21811,7 @@ var parseArgs = async (args) => {
|
|
|
21341
21811
|
handler() {
|
|
21342
21812
|
yargsInstance.showHelp();
|
|
21343
21813
|
}
|
|
21344
|
-
}).strictOptions().help("h").alias("h", "help").epilog(
|
|
21814
|
+
}).strictOptions().help("h").alias("h", "help").epilog(chalk12.bgBlue("Made with \u2764\uFE0F by Mobb")).showHelpOnFail(true).wrap(Math.min(120, yargsInstance.terminalWidth())).parse();
|
|
21345
21815
|
};
|
|
21346
21816
|
|
|
21347
21817
|
// src/index.ts
|