mobbdev 1.0.217 → 1.1.1
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 +984 -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,673 @@ 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(options = {}) {
|
|
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
|
+
let command = "npx --yes mobbdev@latest claude-code-process-hook";
|
|
13431
|
+
if (options.saveEnv) {
|
|
13432
|
+
const envVars = [];
|
|
13433
|
+
if (process.env["WEB_LOGIN_URL"]) {
|
|
13434
|
+
envVars.push(`WEB_LOGIN_URL="${process.env["WEB_LOGIN_URL"]}"`);
|
|
13435
|
+
}
|
|
13436
|
+
if (process.env["WEB_APP_URL"]) {
|
|
13437
|
+
envVars.push(`WEB_APP_URL="${process.env["WEB_APP_URL"]}"`);
|
|
13438
|
+
}
|
|
13439
|
+
if (process.env["API_URL"]) {
|
|
13440
|
+
envVars.push(`API_URL="${process.env["API_URL"]}"`);
|
|
13441
|
+
}
|
|
13442
|
+
if (envVars.length > 0) {
|
|
13443
|
+
command = `${envVars.join(" ")} ${command}`;
|
|
13444
|
+
console.log(
|
|
13445
|
+
chalk10.blue(
|
|
13446
|
+
`Adding environment variables to hook command: ${envVars.join(", ")}`
|
|
13447
|
+
)
|
|
13448
|
+
);
|
|
13449
|
+
}
|
|
13450
|
+
}
|
|
13451
|
+
const mobbHookConfig = {
|
|
13452
|
+
matcher: "Edit|Write",
|
|
13453
|
+
hooks: [
|
|
13454
|
+
{
|
|
13455
|
+
type: "command",
|
|
13456
|
+
command
|
|
13457
|
+
}
|
|
13458
|
+
]
|
|
13459
|
+
};
|
|
13460
|
+
const existingHookIndex = settings.hooks.PostToolUse.findIndex(
|
|
13461
|
+
(hook) => hook.matcher === "Edit|Write" && hook.hooks.some(
|
|
13462
|
+
(h) => h.command?.includes("mobbdev@latest claude-code-process-hook")
|
|
13463
|
+
)
|
|
13464
|
+
);
|
|
13465
|
+
if (existingHookIndex >= 0) {
|
|
13466
|
+
console.log(chalk10.yellow("Mobb hook already exists, updating..."));
|
|
13467
|
+
settings.hooks.PostToolUse[existingHookIndex] = mobbHookConfig;
|
|
13468
|
+
} else {
|
|
13469
|
+
console.log(chalk10.green("Adding new Mobb hook..."));
|
|
13470
|
+
settings.hooks.PostToolUse.push(mobbHookConfig);
|
|
13471
|
+
}
|
|
13472
|
+
await writeClaudeSettings(settings);
|
|
13473
|
+
console.log(
|
|
13474
|
+
chalk10.green(
|
|
13475
|
+
`\u2705 Mobb hooks ${options.saveEnv ? "and environment variables " : ""}installed successfully in ${CLAUDE_SETTINGS_PATH}`
|
|
13476
|
+
)
|
|
13477
|
+
);
|
|
13478
|
+
}
|
|
13479
|
+
|
|
13480
|
+
// src/args/commands/claude_code.ts
|
|
13481
|
+
var config6 = new Configstore5(packageJson.name, { apiToken: "" });
|
|
13482
|
+
var claudeCodeInstallHookBuilder = (yargs2) => {
|
|
13483
|
+
return yargs2.option("save-env", {
|
|
13484
|
+
type: "boolean",
|
|
13485
|
+
description: "Save WEB_LOGIN_URL, WEB_APP_URL, and API_URL environment variables to hooks config",
|
|
13486
|
+
default: false
|
|
13487
|
+
}).example(
|
|
13488
|
+
"$0 claude-code-install-hook",
|
|
13489
|
+
"Install Claude Code hooks for data collection"
|
|
13490
|
+
).example(
|
|
13491
|
+
"$0 claude-code-install-hook --save-env",
|
|
13492
|
+
"Install hooks and save environment variables to config"
|
|
13493
|
+
).strict();
|
|
13494
|
+
};
|
|
13495
|
+
var claudeCodeProcessHookBuilder = (yargs2) => {
|
|
13496
|
+
return yargs2.example(
|
|
13497
|
+
"$0 claude-code-process-hook",
|
|
13498
|
+
"Process Claude Code hook data and upload to backend"
|
|
13499
|
+
).strict();
|
|
13500
|
+
};
|
|
13501
|
+
var claudeCodeInstallHookHandler = async (argv) => {
|
|
13502
|
+
try {
|
|
13503
|
+
const gqlClient = new GQLClient({
|
|
13504
|
+
apiKey: config6.get("apiToken") ?? "",
|
|
13505
|
+
type: "apiKey"
|
|
13506
|
+
});
|
|
13507
|
+
await handleMobbLogin({
|
|
13508
|
+
inGqlClient: gqlClient,
|
|
13509
|
+
skipPrompts: false
|
|
13510
|
+
});
|
|
13511
|
+
await installMobbHooks({ saveEnv: argv["save-env"] });
|
|
13512
|
+
process.exit(0);
|
|
13513
|
+
} catch (error) {
|
|
13514
|
+
console.error("Failed to install Claude Code hooks:", error);
|
|
13515
|
+
process.exit(1);
|
|
13516
|
+
}
|
|
13517
|
+
};
|
|
13518
|
+
var claudeCodeProcessHookHandler = async () => {
|
|
13519
|
+
try {
|
|
13520
|
+
const { hookData, inference, tracePayload, uploadSuccess } = await processAndUploadHookData();
|
|
13521
|
+
console.log("Successfully processed Claude Code hook:");
|
|
13522
|
+
console.log("Session ID:", hookData.session_id);
|
|
13523
|
+
console.log("Tool:", hookData.tool_name);
|
|
13524
|
+
console.log("Transcript path:", hookData.transcript_path);
|
|
13525
|
+
console.log("Inference length:", inference.length);
|
|
13526
|
+
const userPrompts = tracePayload.prompts.filter(
|
|
13527
|
+
(p) => p.type === "USER_PROMPT"
|
|
13528
|
+
);
|
|
13529
|
+
const assistantResponses = tracePayload.prompts.filter(
|
|
13530
|
+
(p) => p.type === "AI_RESPONSE"
|
|
13531
|
+
);
|
|
13532
|
+
const aiThinking = tracePayload.prompts.filter(
|
|
13533
|
+
(p) => p.type === "AI_THINKING"
|
|
13534
|
+
);
|
|
13535
|
+
console.log("Conversation context extracted:");
|
|
13536
|
+
console.log("- User prompts:", userPrompts.length);
|
|
13537
|
+
console.log("- Assistant responses:", assistantResponses.length);
|
|
13538
|
+
console.log("- AI thinking entries:", aiThinking.length);
|
|
13539
|
+
console.log("- Model:", tracePayload.model);
|
|
13540
|
+
const totalInputTokens = tracePayload.prompts.reduce(
|
|
13541
|
+
(sum, p) => sum + (p.tokens?.inputCount || 0),
|
|
13542
|
+
0
|
|
13543
|
+
);
|
|
13544
|
+
const totalOutputTokens = tracePayload.prompts.reduce(
|
|
13545
|
+
(sum, p) => sum + (p.tokens?.outputCount || 0),
|
|
13546
|
+
0
|
|
13547
|
+
);
|
|
13548
|
+
console.log("- Input tokens:", totalInputTokens);
|
|
13549
|
+
console.log("- Output tokens:", totalOutputTokens);
|
|
13550
|
+
console.log("Trace data formatted:");
|
|
13551
|
+
console.log("- Prompt items:", tracePayload.prompts.length);
|
|
13552
|
+
console.log("- Model:", tracePayload.model);
|
|
13553
|
+
console.log("- Tool:", tracePayload.tool);
|
|
13554
|
+
console.log("- Response time:", tracePayload.responseTime);
|
|
13555
|
+
console.log("- Upload success:", uploadSuccess ? "\u2705" : "\u274C");
|
|
13556
|
+
if (uploadSuccess) {
|
|
13557
|
+
console.log("\u2705 Claude Code trace uploaded successfully to Mobb backend");
|
|
13558
|
+
}
|
|
13559
|
+
process.exit(0);
|
|
13560
|
+
} catch (error) {
|
|
13561
|
+
console.error("Failed to process Claude Code hook data:", error);
|
|
13562
|
+
process.exit(1);
|
|
13563
|
+
}
|
|
13564
|
+
};
|
|
13565
|
+
|
|
12897
13566
|
// src/mcp/core/McpServer.ts
|
|
12898
13567
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
12899
13568
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -12905,7 +13574,7 @@ import {
|
|
|
12905
13574
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
12906
13575
|
|
|
12907
13576
|
// src/mcp/Logger.ts
|
|
12908
|
-
import
|
|
13577
|
+
import Configstore6 from "configstore";
|
|
12909
13578
|
|
|
12910
13579
|
// src/mcp/services/WorkspaceService.ts
|
|
12911
13580
|
var WorkspaceService = class {
|
|
@@ -12913,8 +13582,8 @@ var WorkspaceService = class {
|
|
|
12913
13582
|
* Sets a known workspace path that was discovered through successful validation
|
|
12914
13583
|
* @param path The validated workspace path to store
|
|
12915
13584
|
*/
|
|
12916
|
-
static setKnownWorkspacePath(
|
|
12917
|
-
this.knownWorkspacePath =
|
|
13585
|
+
static setKnownWorkspacePath(path22) {
|
|
13586
|
+
this.knownWorkspacePath = path22;
|
|
12918
13587
|
}
|
|
12919
13588
|
/**
|
|
12920
13589
|
* Gets the known workspace path that was previously validated
|
|
@@ -12991,7 +13660,7 @@ var Logger = class {
|
|
|
12991
13660
|
__publicField(this, "lastKnownPath", null);
|
|
12992
13661
|
this.host = WorkspaceService.getHost();
|
|
12993
13662
|
this.unknownPathSuffix = Math.floor(1e3 + Math.random() * 9e3).toString();
|
|
12994
|
-
this.mobbConfigStore = new
|
|
13663
|
+
this.mobbConfigStore = new Configstore6("mobb-logs", {});
|
|
12995
13664
|
this.mobbConfigStore.set("version", packageJson.version);
|
|
12996
13665
|
}
|
|
12997
13666
|
/**
|
|
@@ -13061,135 +13730,135 @@ import { v4 as uuidv42 } from "uuid";
|
|
|
13061
13730
|
init_configs();
|
|
13062
13731
|
|
|
13063
13732
|
// src/mcp/types.ts
|
|
13064
|
-
import { z as
|
|
13065
|
-
var ScanAndFixVulnerabilitiesToolSchema =
|
|
13066
|
-
path:
|
|
13733
|
+
import { z as z33 } from "zod";
|
|
13734
|
+
var ScanAndFixVulnerabilitiesToolSchema = z33.object({
|
|
13735
|
+
path: z33.string()
|
|
13067
13736
|
});
|
|
13068
|
-
var VulnerabilityReportIssueTagSchema =
|
|
13069
|
-
vulnerability_report_issue_tag_value:
|
|
13737
|
+
var VulnerabilityReportIssueTagSchema = z33.object({
|
|
13738
|
+
vulnerability_report_issue_tag_value: z33.nativeEnum(
|
|
13070
13739
|
Vulnerability_Report_Issue_Tag_Enum
|
|
13071
13740
|
)
|
|
13072
13741
|
});
|
|
13073
|
-
var VulnerabilityReportIssueSchema =
|
|
13074
|
-
category:
|
|
13075
|
-
parsedIssueType:
|
|
13076
|
-
parsedSeverity:
|
|
13077
|
-
vulnerabilityReportIssueTags:
|
|
13742
|
+
var VulnerabilityReportIssueSchema = z33.object({
|
|
13743
|
+
category: z33.any().optional().nullable(),
|
|
13744
|
+
parsedIssueType: z33.nativeEnum(IssueType_Enum).nullable().optional(),
|
|
13745
|
+
parsedSeverity: z33.nativeEnum(Vulnerability_Severity_Enum).nullable().optional(),
|
|
13746
|
+
vulnerabilityReportIssueTags: z33.array(VulnerabilityReportIssueTagSchema)
|
|
13078
13747
|
});
|
|
13079
|
-
var SharedStateSchema =
|
|
13080
|
-
__typename:
|
|
13081
|
-
id:
|
|
13748
|
+
var SharedStateSchema = z33.object({
|
|
13749
|
+
__typename: z33.literal("fix_shared_state").optional(),
|
|
13750
|
+
id: z33.any(),
|
|
13082
13751
|
// GraphQL uses `any` type for UUID
|
|
13083
|
-
downloadedBy:
|
|
13752
|
+
downloadedBy: z33.array(z33.any().nullable()).optional().nullable()
|
|
13084
13753
|
});
|
|
13085
|
-
var UnstructuredFixExtraContextSchema =
|
|
13086
|
-
__typename:
|
|
13087
|
-
key:
|
|
13088
|
-
value:
|
|
13754
|
+
var UnstructuredFixExtraContextSchema = z33.object({
|
|
13755
|
+
__typename: z33.literal("UnstructuredFixExtraContext").optional(),
|
|
13756
|
+
key: z33.string(),
|
|
13757
|
+
value: z33.any()
|
|
13089
13758
|
// GraphQL JSON type
|
|
13090
13759
|
});
|
|
13091
|
-
var FixExtraContextResponseSchema =
|
|
13092
|
-
__typename:
|
|
13093
|
-
extraContext:
|
|
13094
|
-
fixDescription:
|
|
13760
|
+
var FixExtraContextResponseSchema = z33.object({
|
|
13761
|
+
__typename: z33.literal("FixExtraContextResponse").optional(),
|
|
13762
|
+
extraContext: z33.array(UnstructuredFixExtraContextSchema),
|
|
13763
|
+
fixDescription: z33.string()
|
|
13095
13764
|
});
|
|
13096
|
-
var FixDataSchema =
|
|
13097
|
-
__typename:
|
|
13098
|
-
patch:
|
|
13099
|
-
patchOriginalEncodingBase64:
|
|
13765
|
+
var FixDataSchema = z33.object({
|
|
13766
|
+
__typename: z33.literal("FixData"),
|
|
13767
|
+
patch: z33.string(),
|
|
13768
|
+
patchOriginalEncodingBase64: z33.string(),
|
|
13100
13769
|
extraContext: FixExtraContextResponseSchema
|
|
13101
13770
|
});
|
|
13102
|
-
var GetFixNoFixErrorSchema =
|
|
13103
|
-
__typename:
|
|
13771
|
+
var GetFixNoFixErrorSchema = z33.object({
|
|
13772
|
+
__typename: z33.literal("GetFixNoFixError")
|
|
13104
13773
|
});
|
|
13105
|
-
var PatchAndQuestionsSchema =
|
|
13106
|
-
var McpFixSchema =
|
|
13107
|
-
__typename:
|
|
13108
|
-
id:
|
|
13774
|
+
var PatchAndQuestionsSchema = z33.union([FixDataSchema, GetFixNoFixErrorSchema]);
|
|
13775
|
+
var McpFixSchema = z33.object({
|
|
13776
|
+
__typename: z33.literal("fix").optional(),
|
|
13777
|
+
id: z33.any(),
|
|
13109
13778
|
// GraphQL uses `any` type for UUID
|
|
13110
|
-
confidence:
|
|
13111
|
-
safeIssueType:
|
|
13112
|
-
severityText:
|
|
13113
|
-
gitBlameLogin:
|
|
13779
|
+
confidence: z33.number(),
|
|
13780
|
+
safeIssueType: z33.string().nullable(),
|
|
13781
|
+
severityText: z33.string().nullable(),
|
|
13782
|
+
gitBlameLogin: z33.string().nullable().optional(),
|
|
13114
13783
|
// Optional in GraphQL
|
|
13115
|
-
severityValue:
|
|
13116
|
-
vulnerabilityReportIssues:
|
|
13784
|
+
severityValue: z33.number().nullable(),
|
|
13785
|
+
vulnerabilityReportIssues: z33.array(VulnerabilityReportIssueSchema),
|
|
13117
13786
|
sharedState: SharedStateSchema.nullable().optional(),
|
|
13118
13787
|
// Optional in GraphQL
|
|
13119
13788
|
patchAndQuestions: PatchAndQuestionsSchema,
|
|
13120
13789
|
// Additional field added by the client
|
|
13121
|
-
fixUrl:
|
|
13790
|
+
fixUrl: z33.string().optional()
|
|
13122
13791
|
});
|
|
13123
|
-
var FixAggregateSchema =
|
|
13124
|
-
__typename:
|
|
13125
|
-
aggregate:
|
|
13126
|
-
__typename:
|
|
13127
|
-
count:
|
|
13792
|
+
var FixAggregateSchema = z33.object({
|
|
13793
|
+
__typename: z33.literal("fix_aggregate").optional(),
|
|
13794
|
+
aggregate: z33.object({
|
|
13795
|
+
__typename: z33.literal("fix_aggregate_fields").optional(),
|
|
13796
|
+
count: z33.number()
|
|
13128
13797
|
}).nullable()
|
|
13129
13798
|
});
|
|
13130
|
-
var VulnerabilityReportIssueAggregateSchema =
|
|
13131
|
-
__typename:
|
|
13132
|
-
aggregate:
|
|
13133
|
-
__typename:
|
|
13134
|
-
count:
|
|
13799
|
+
var VulnerabilityReportIssueAggregateSchema = z33.object({
|
|
13800
|
+
__typename: z33.literal("vulnerability_report_issue_aggregate").optional(),
|
|
13801
|
+
aggregate: z33.object({
|
|
13802
|
+
__typename: z33.literal("vulnerability_report_issue_aggregate_fields").optional(),
|
|
13803
|
+
count: z33.number()
|
|
13135
13804
|
}).nullable()
|
|
13136
13805
|
});
|
|
13137
|
-
var RepoSchema =
|
|
13138
|
-
__typename:
|
|
13139
|
-
originalUrl:
|
|
13806
|
+
var RepoSchema = z33.object({
|
|
13807
|
+
__typename: z33.literal("repo").optional(),
|
|
13808
|
+
originalUrl: z33.string()
|
|
13140
13809
|
});
|
|
13141
|
-
var ProjectSchema =
|
|
13142
|
-
id:
|
|
13810
|
+
var ProjectSchema = z33.object({
|
|
13811
|
+
id: z33.any(),
|
|
13143
13812
|
// GraphQL uses `any` type for UUID
|
|
13144
|
-
organizationId:
|
|
13813
|
+
organizationId: z33.any()
|
|
13145
13814
|
// GraphQL uses `any` type for UUID
|
|
13146
13815
|
});
|
|
13147
|
-
var VulnerabilityReportSchema =
|
|
13148
|
-
scanDate:
|
|
13816
|
+
var VulnerabilityReportSchema = z33.object({
|
|
13817
|
+
scanDate: z33.any().nullable(),
|
|
13149
13818
|
// GraphQL uses `any` type for timestamp
|
|
13150
|
-
vendor:
|
|
13819
|
+
vendor: z33.string(),
|
|
13151
13820
|
// GraphQL generates as string, not enum
|
|
13152
|
-
projectId:
|
|
13821
|
+
projectId: z33.any().optional(),
|
|
13153
13822
|
// GraphQL uses `any` type for UUID
|
|
13154
13823
|
project: ProjectSchema,
|
|
13155
13824
|
totalVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema,
|
|
13156
13825
|
notFixableVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema
|
|
13157
13826
|
});
|
|
13158
|
-
var FixReportSummarySchema =
|
|
13159
|
-
__typename:
|
|
13160
|
-
id:
|
|
13827
|
+
var FixReportSummarySchema = z33.object({
|
|
13828
|
+
__typename: z33.literal("fixReport").optional(),
|
|
13829
|
+
id: z33.any(),
|
|
13161
13830
|
// GraphQL uses `any` type for UUID
|
|
13162
|
-
createdOn:
|
|
13831
|
+
createdOn: z33.any(),
|
|
13163
13832
|
// GraphQL uses `any` type for timestamp
|
|
13164
13833
|
repo: RepoSchema.nullable(),
|
|
13165
|
-
issueTypes:
|
|
13834
|
+
issueTypes: z33.any().nullable(),
|
|
13166
13835
|
// GraphQL uses `any` type for JSON
|
|
13167
13836
|
CRITICAL: FixAggregateSchema,
|
|
13168
13837
|
HIGH: FixAggregateSchema,
|
|
13169
13838
|
MEDIUM: FixAggregateSchema,
|
|
13170
13839
|
LOW: FixAggregateSchema,
|
|
13171
|
-
fixes:
|
|
13172
|
-
userFixes:
|
|
13840
|
+
fixes: z33.array(McpFixSchema),
|
|
13841
|
+
userFixes: z33.array(McpFixSchema).optional(),
|
|
13173
13842
|
// Present in some responses but can be omitted
|
|
13174
13843
|
filteredFixesCount: FixAggregateSchema,
|
|
13175
13844
|
totalFixesCount: FixAggregateSchema,
|
|
13176
13845
|
vulnerabilityReport: VulnerabilityReportSchema
|
|
13177
13846
|
});
|
|
13178
|
-
var ExpiredReportSchema =
|
|
13179
|
-
__typename:
|
|
13180
|
-
id:
|
|
13847
|
+
var ExpiredReportSchema = z33.object({
|
|
13848
|
+
__typename: z33.literal("fixReport").optional(),
|
|
13849
|
+
id: z33.any(),
|
|
13181
13850
|
// GraphQL uses `any` type for UUID
|
|
13182
|
-
expirationOn:
|
|
13851
|
+
expirationOn: z33.any().nullable()
|
|
13183
13852
|
// GraphQL uses `any` type for timestamp
|
|
13184
13853
|
});
|
|
13185
|
-
var GetLatestReportByRepoUrlResponseSchema =
|
|
13186
|
-
__typename:
|
|
13187
|
-
fixReport:
|
|
13188
|
-
expiredReport:
|
|
13854
|
+
var GetLatestReportByRepoUrlResponseSchema = z33.object({
|
|
13855
|
+
__typename: z33.literal("query_root").optional(),
|
|
13856
|
+
fixReport: z33.array(FixReportSummarySchema),
|
|
13857
|
+
expiredReport: z33.array(ExpiredReportSchema)
|
|
13189
13858
|
});
|
|
13190
13859
|
|
|
13191
13860
|
// src/mcp/services/ConfigStoreService.ts
|
|
13192
|
-
import
|
|
13861
|
+
import Configstore7 from "configstore";
|
|
13193
13862
|
init_configs();
|
|
13194
13863
|
function createConfigStore(defaultValues = { apiToken: "" }) {
|
|
13195
13864
|
const API_URL2 = process.env["API_URL"] || MCP_DEFAULT_API_URL;
|
|
@@ -13201,7 +13870,7 @@ function createConfigStore(defaultValues = { apiToken: "" }) {
|
|
|
13201
13870
|
domain = API_URL2.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/:\d+$/, "");
|
|
13202
13871
|
}
|
|
13203
13872
|
const sanitizedDomain = domain.replace(/\./g, "_");
|
|
13204
|
-
return new
|
|
13873
|
+
return new Configstore7(
|
|
13205
13874
|
`${packageJson.name}-${sanitizedDomain}`,
|
|
13206
13875
|
defaultValues
|
|
13207
13876
|
);
|
|
@@ -13213,7 +13882,7 @@ var configStore = getConfigStore();
|
|
|
13213
13882
|
|
|
13214
13883
|
// src/mcp/services/McpAuthService.ts
|
|
13215
13884
|
import crypto2 from "crypto";
|
|
13216
|
-
import
|
|
13885
|
+
import os3 from "os";
|
|
13217
13886
|
import open4 from "open";
|
|
13218
13887
|
init_configs();
|
|
13219
13888
|
var McpAuthService = class {
|
|
@@ -13257,7 +13926,7 @@ var McpAuthService = class {
|
|
|
13257
13926
|
}
|
|
13258
13927
|
logDebug(`cli login created ${loginId}`);
|
|
13259
13928
|
const webLoginUrl2 = `${WEB_APP_URL}/mvs-login`;
|
|
13260
|
-
const browserUrl = `${webLoginUrl2}/${loginId}?hostname=${
|
|
13929
|
+
const browserUrl = `${webLoginUrl2}/${loginId}?hostname=${os3.hostname()}`;
|
|
13261
13930
|
await this.openBrowser(browserUrl, isBackgoundCall);
|
|
13262
13931
|
logDebug(`waiting for login to complete`);
|
|
13263
13932
|
let newApiToken = null;
|
|
@@ -13918,8 +14587,8 @@ async function createAuthenticatedMcpGQLClient({
|
|
|
13918
14587
|
// src/mcp/services/McpUsageService/host.ts
|
|
13919
14588
|
import { execSync } from "child_process";
|
|
13920
14589
|
import fs11 from "fs";
|
|
13921
|
-
import
|
|
13922
|
-
import
|
|
14590
|
+
import os4 from "os";
|
|
14591
|
+
import path13 from "path";
|
|
13923
14592
|
var IDEs = ["cursor", "windsurf", "webstorm", "vscode", "claude"];
|
|
13924
14593
|
var runCommand = (cmd) => {
|
|
13925
14594
|
try {
|
|
@@ -13933,8 +14602,8 @@ var gitInfo = {
|
|
|
13933
14602
|
email: runCommand("git config user.email")
|
|
13934
14603
|
};
|
|
13935
14604
|
var getClaudeWorkspacePaths = () => {
|
|
13936
|
-
const home =
|
|
13937
|
-
const claudeIdePath =
|
|
14605
|
+
const home = os4.homedir();
|
|
14606
|
+
const claudeIdePath = path13.join(home, ".claude", "ide");
|
|
13938
14607
|
const workspacePaths = [];
|
|
13939
14608
|
if (!fs11.existsSync(claudeIdePath)) {
|
|
13940
14609
|
return workspacePaths;
|
|
@@ -13942,7 +14611,7 @@ var getClaudeWorkspacePaths = () => {
|
|
|
13942
14611
|
try {
|
|
13943
14612
|
const lockFiles = fs11.readdirSync(claudeIdePath).filter((file) => file.endsWith(".lock"));
|
|
13944
14613
|
for (const lockFile of lockFiles) {
|
|
13945
|
-
const lockFilePath =
|
|
14614
|
+
const lockFilePath = path13.join(claudeIdePath, lockFile);
|
|
13946
14615
|
try {
|
|
13947
14616
|
const lockContent = JSON.parse(fs11.readFileSync(lockFilePath, "utf8"));
|
|
13948
14617
|
if (lockContent.workspaceFolders && Array.isArray(lockContent.workspaceFolders)) {
|
|
@@ -13962,29 +14631,29 @@ var getClaudeWorkspacePaths = () => {
|
|
|
13962
14631
|
return workspacePaths;
|
|
13963
14632
|
};
|
|
13964
14633
|
var getMCPConfigPaths = (hostName) => {
|
|
13965
|
-
const home =
|
|
14634
|
+
const home = os4.homedir();
|
|
13966
14635
|
const currentDir = process.env["WORKSPACE_FOLDER_PATHS"] || process.env["PWD"] || process.cwd();
|
|
13967
14636
|
switch (hostName.toLowerCase()) {
|
|
13968
14637
|
case "cursor":
|
|
13969
14638
|
return [
|
|
13970
|
-
|
|
14639
|
+
path13.join(currentDir, ".cursor", "mcp.json"),
|
|
13971
14640
|
// local first
|
|
13972
|
-
|
|
14641
|
+
path13.join(home, ".cursor", "mcp.json")
|
|
13973
14642
|
];
|
|
13974
14643
|
case "windsurf":
|
|
13975
14644
|
return [
|
|
13976
|
-
|
|
14645
|
+
path13.join(currentDir, ".codeium", "mcp_config.json"),
|
|
13977
14646
|
// local first
|
|
13978
|
-
|
|
14647
|
+
path13.join(home, ".codeium", "windsurf", "mcp_config.json")
|
|
13979
14648
|
];
|
|
13980
14649
|
case "webstorm":
|
|
13981
14650
|
return [];
|
|
13982
14651
|
case "visualstudiocode":
|
|
13983
14652
|
case "vscode":
|
|
13984
14653
|
return [
|
|
13985
|
-
|
|
14654
|
+
path13.join(currentDir, ".vscode", "mcp.json"),
|
|
13986
14655
|
// local first
|
|
13987
|
-
process.platform === "win32" ?
|
|
14656
|
+
process.platform === "win32" ? path13.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path13.join(
|
|
13988
14657
|
home,
|
|
13989
14658
|
"Library",
|
|
13990
14659
|
"Application Support",
|
|
@@ -13995,13 +14664,13 @@ var getMCPConfigPaths = (hostName) => {
|
|
|
13995
14664
|
];
|
|
13996
14665
|
case "claude": {
|
|
13997
14666
|
const claudePaths = [
|
|
13998
|
-
|
|
14667
|
+
path13.join(currentDir, ".claude.json"),
|
|
13999
14668
|
// local first
|
|
14000
|
-
|
|
14669
|
+
path13.join(home, ".claude.json")
|
|
14001
14670
|
];
|
|
14002
14671
|
const workspacePaths = getClaudeWorkspacePaths();
|
|
14003
14672
|
for (const workspacePath of workspacePaths) {
|
|
14004
|
-
claudePaths.push(
|
|
14673
|
+
claudePaths.push(path13.join(workspacePath, ".mcp.json"));
|
|
14005
14674
|
}
|
|
14006
14675
|
return claudePaths;
|
|
14007
14676
|
}
|
|
@@ -14018,41 +14687,41 @@ var readConfigFile = (filePath) => {
|
|
|
14018
14687
|
return null;
|
|
14019
14688
|
}
|
|
14020
14689
|
};
|
|
14021
|
-
var mergeConfigIntoResult = (
|
|
14022
|
-
if (
|
|
14690
|
+
var mergeConfigIntoResult = (config7, mergedConfig) => {
|
|
14691
|
+
if (config7?.projects) {
|
|
14023
14692
|
const allMcpServers = {};
|
|
14024
|
-
for (const projectPath in
|
|
14025
|
-
const project =
|
|
14693
|
+
for (const projectPath in config7.projects) {
|
|
14694
|
+
const project = config7.projects[projectPath];
|
|
14026
14695
|
if (project?.mcpServers) {
|
|
14027
14696
|
Object.assign(allMcpServers, project.mcpServers);
|
|
14028
14697
|
}
|
|
14029
14698
|
}
|
|
14030
14699
|
mergedConfig.mcpServers = { ...mergedConfig.mcpServers, ...allMcpServers };
|
|
14031
14700
|
}
|
|
14032
|
-
if (
|
|
14701
|
+
if (config7?.mcpServers) {
|
|
14033
14702
|
mergedConfig.mcpServers = {
|
|
14034
14703
|
...mergedConfig.mcpServers,
|
|
14035
|
-
...
|
|
14704
|
+
...config7.mcpServers
|
|
14036
14705
|
};
|
|
14037
14706
|
}
|
|
14038
|
-
if (
|
|
14039
|
-
mergedConfig.servers = { ...mergedConfig.servers, ...
|
|
14707
|
+
if (config7?.servers) {
|
|
14708
|
+
mergedConfig.servers = { ...mergedConfig.servers, ...config7.servers };
|
|
14040
14709
|
}
|
|
14041
14710
|
};
|
|
14042
14711
|
var readMCPConfig = (hostName) => {
|
|
14043
14712
|
const configPaths = getMCPConfigPaths(hostName);
|
|
14044
14713
|
const mergedConfig = {};
|
|
14045
14714
|
for (const configPath of configPaths) {
|
|
14046
|
-
const
|
|
14047
|
-
if (
|
|
14048
|
-
mergeConfigIntoResult(
|
|
14715
|
+
const config7 = readConfigFile(configPath);
|
|
14716
|
+
if (config7) {
|
|
14717
|
+
mergeConfigIntoResult(config7, mergedConfig);
|
|
14049
14718
|
}
|
|
14050
14719
|
}
|
|
14051
14720
|
return Object.keys(mergedConfig).length > 0 ? mergedConfig : null;
|
|
14052
14721
|
};
|
|
14053
14722
|
var getRunningProcesses = () => {
|
|
14054
14723
|
try {
|
|
14055
|
-
return
|
|
14724
|
+
return os4.platform() === "win32" ? execSync("tasklist", { encoding: "utf8" }) : execSync("ps aux", { encoding: "utf8" });
|
|
14056
14725
|
} catch {
|
|
14057
14726
|
return "";
|
|
14058
14727
|
}
|
|
@@ -14127,7 +14796,7 @@ var versionCommands = {
|
|
|
14127
14796
|
}
|
|
14128
14797
|
};
|
|
14129
14798
|
var getProcessInfo = (pid) => {
|
|
14130
|
-
const platform2 =
|
|
14799
|
+
const platform2 = os4.platform();
|
|
14131
14800
|
try {
|
|
14132
14801
|
if (platform2 === "linux" || platform2 === "darwin") {
|
|
14133
14802
|
const output = execSync(`ps -o pid=,ppid=,comm= -p ${pid}`, {
|
|
@@ -14162,20 +14831,20 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
14162
14831
|
const ideConfigPaths = /* @__PURE__ */ new Set();
|
|
14163
14832
|
for (const ide of IDEs) {
|
|
14164
14833
|
const configPaths = getMCPConfigPaths(ide);
|
|
14165
|
-
configPaths.forEach((
|
|
14834
|
+
configPaths.forEach((path22) => ideConfigPaths.add(path22));
|
|
14166
14835
|
}
|
|
14167
14836
|
const uniqueAdditionalPaths = additionalMcpList.filter(
|
|
14168
|
-
(
|
|
14837
|
+
(path22) => !ideConfigPaths.has(path22)
|
|
14169
14838
|
);
|
|
14170
14839
|
for (const ide of IDEs) {
|
|
14171
14840
|
const cfg = readMCPConfig(ide);
|
|
14172
14841
|
if (cfg) allConfigs[ide] = cfg;
|
|
14173
14842
|
}
|
|
14174
14843
|
for (const additionalPath of uniqueAdditionalPaths) {
|
|
14175
|
-
const
|
|
14176
|
-
if (!
|
|
14844
|
+
const config7 = readConfigFile(additionalPath);
|
|
14845
|
+
if (!config7) continue;
|
|
14177
14846
|
const mergedConfig = {};
|
|
14178
|
-
mergeConfigIntoResult(
|
|
14847
|
+
mergeConfigIntoResult(config7, mergedConfig);
|
|
14179
14848
|
if (Object.keys(mergedConfig).length > 0) {
|
|
14180
14849
|
allConfigs["system"] = mergedConfig;
|
|
14181
14850
|
}
|
|
@@ -14243,10 +14912,10 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
14243
14912
|
}
|
|
14244
14913
|
}
|
|
14245
14914
|
for (const { ide, name, command, isRunning } of servers) {
|
|
14246
|
-
const
|
|
14915
|
+
const config7 = allConfigs[ide] || null;
|
|
14247
14916
|
const ideName = ide.charAt(0).toUpperCase() + ide.slice(1) || "Unknown";
|
|
14248
14917
|
let ideVersion = "Unknown";
|
|
14249
|
-
const platform2 =
|
|
14918
|
+
const platform2 = os4.platform();
|
|
14250
14919
|
const cmds = versionCommands[ideName]?.[platform2] ?? [];
|
|
14251
14920
|
for (const cmd of cmds) {
|
|
14252
14921
|
try {
|
|
@@ -14260,8 +14929,8 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
14260
14929
|
}
|
|
14261
14930
|
}
|
|
14262
14931
|
let mcpConfigObj = {};
|
|
14263
|
-
if (
|
|
14264
|
-
const allServers =
|
|
14932
|
+
if (config7) {
|
|
14933
|
+
const allServers = config7.mcpServers || config7.servers || {};
|
|
14265
14934
|
if (name in allServers && allServers[name]) {
|
|
14266
14935
|
mcpConfigObj = allServers[name];
|
|
14267
14936
|
}
|
|
@@ -14279,15 +14948,15 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
14279
14948
|
|
|
14280
14949
|
// src/mcp/services/McpUsageService/McpUsageService.ts
|
|
14281
14950
|
import fetch5 from "node-fetch";
|
|
14282
|
-
import
|
|
14951
|
+
import os6 from "os";
|
|
14283
14952
|
import { v4 as uuidv43, v5 as uuidv5 } from "uuid";
|
|
14284
14953
|
init_configs();
|
|
14285
14954
|
|
|
14286
14955
|
// src/mcp/services/McpUsageService/system.ts
|
|
14287
14956
|
init_configs();
|
|
14288
14957
|
import fs12 from "fs";
|
|
14289
|
-
import
|
|
14290
|
-
import
|
|
14958
|
+
import os5 from "os";
|
|
14959
|
+
import path14 from "path";
|
|
14291
14960
|
var MAX_DEPTH = 2;
|
|
14292
14961
|
var patterns = ["mcp", "claude"];
|
|
14293
14962
|
var isFileMatch = (fileName) => {
|
|
@@ -14307,7 +14976,7 @@ var searchDir = async (dir, depth = 0) => {
|
|
|
14307
14976
|
if (depth > MAX_DEPTH) return results;
|
|
14308
14977
|
const entries = await fs12.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
14309
14978
|
for (const entry of entries) {
|
|
14310
|
-
const fullPath =
|
|
14979
|
+
const fullPath = path14.join(dir, entry.name);
|
|
14311
14980
|
if (entry.isFile() && isFileMatch(entry.name)) {
|
|
14312
14981
|
results.push(fullPath);
|
|
14313
14982
|
} else if (entry.isDirectory()) {
|
|
@@ -14321,17 +14990,17 @@ var searchDir = async (dir, depth = 0) => {
|
|
|
14321
14990
|
};
|
|
14322
14991
|
var findSystemMCPConfigs = async () => {
|
|
14323
14992
|
try {
|
|
14324
|
-
const home =
|
|
14325
|
-
const platform2 =
|
|
14993
|
+
const home = os5.homedir();
|
|
14994
|
+
const platform2 = os5.platform();
|
|
14326
14995
|
const knownDirs = platform2 === "win32" ? [
|
|
14327
|
-
|
|
14328
|
-
|
|
14329
|
-
|
|
14996
|
+
path14.join(home, ".cursor"),
|
|
14997
|
+
path14.join(home, "Documents"),
|
|
14998
|
+
path14.join(home, "Downloads")
|
|
14330
14999
|
] : [
|
|
14331
|
-
|
|
14332
|
-
process.env["XDG_CONFIG_HOME"] ||
|
|
14333
|
-
|
|
14334
|
-
|
|
15000
|
+
path14.join(home, ".cursor"),
|
|
15001
|
+
process.env["XDG_CONFIG_HOME"] || path14.join(home, ".config"),
|
|
15002
|
+
path14.join(home, "Documents"),
|
|
15003
|
+
path14.join(home, "Downloads")
|
|
14335
15004
|
];
|
|
14336
15005
|
const timeoutPromise = new Promise(
|
|
14337
15006
|
(resolve) => setTimeout(() => {
|
|
@@ -14394,7 +15063,7 @@ var McpUsageService = class {
|
|
|
14394
15063
|
generateHostId() {
|
|
14395
15064
|
const stored = configStore.get(this.configKey);
|
|
14396
15065
|
if (stored?.mcpHostId) return stored.mcpHostId;
|
|
14397
|
-
const interfaces =
|
|
15066
|
+
const interfaces = os6.networkInterfaces();
|
|
14398
15067
|
const macs = [];
|
|
14399
15068
|
for (const iface of Object.values(interfaces)) {
|
|
14400
15069
|
if (!iface) continue;
|
|
@@ -14402,7 +15071,7 @@ var McpUsageService = class {
|
|
|
14402
15071
|
if (net.mac && net.mac !== "00:00:00:00:00:00") macs.push(net.mac);
|
|
14403
15072
|
}
|
|
14404
15073
|
}
|
|
14405
|
-
const macString = macs.length ? macs.sort().join(",") : `${
|
|
15074
|
+
const macString = macs.length ? macs.sort().join(",") : `${os6.hostname()}-${uuidv43()}`;
|
|
14406
15075
|
const hostId = uuidv5(macString, uuidv5.DNS);
|
|
14407
15076
|
logDebug("[UsageService] Generated new host ID", { hostId });
|
|
14408
15077
|
return hostId;
|
|
@@ -14425,7 +15094,7 @@ var McpUsageService = class {
|
|
|
14425
15094
|
mcpHostId,
|
|
14426
15095
|
organizationId,
|
|
14427
15096
|
mcpVersion: packageJson.version,
|
|
14428
|
-
mcpOsName:
|
|
15097
|
+
mcpOsName: os6.platform(),
|
|
14429
15098
|
mcps: JSON.stringify(mcps),
|
|
14430
15099
|
status,
|
|
14431
15100
|
userName: user.name,
|
|
@@ -14599,7 +15268,7 @@ var ToolRegistry = class {
|
|
|
14599
15268
|
|
|
14600
15269
|
// src/mcp/core/McpServer.ts
|
|
14601
15270
|
var McpServer = class {
|
|
14602
|
-
constructor(
|
|
15271
|
+
constructor(config7, govOrgId = "") {
|
|
14603
15272
|
__publicField(this, "server");
|
|
14604
15273
|
__publicField(this, "toolRegistry");
|
|
14605
15274
|
__publicField(this, "promptRegistry");
|
|
@@ -14613,8 +15282,8 @@ var McpServer = class {
|
|
|
14613
15282
|
this.mcpUsageService = govOrgId ? new McpUsageService(govOrgId) : null;
|
|
14614
15283
|
this.server = new Server(
|
|
14615
15284
|
{
|
|
14616
|
-
name:
|
|
14617
|
-
version:
|
|
15285
|
+
name: config7.name,
|
|
15286
|
+
version: config7.version
|
|
14618
15287
|
},
|
|
14619
15288
|
{
|
|
14620
15289
|
capabilities: {
|
|
@@ -14630,7 +15299,7 @@ var McpServer = class {
|
|
|
14630
15299
|
this.setupParentProcessMonitoring();
|
|
14631
15300
|
logInfo("MCP server instance created");
|
|
14632
15301
|
logDebug("MCP server instance config", {
|
|
14633
|
-
config:
|
|
15302
|
+
config: config7,
|
|
14634
15303
|
parentPid: this.parentPid
|
|
14635
15304
|
});
|
|
14636
15305
|
}
|
|
@@ -15088,10 +15757,10 @@ var McpServer = class {
|
|
|
15088
15757
|
};
|
|
15089
15758
|
|
|
15090
15759
|
// src/mcp/prompts/CheckForNewVulnerabilitiesPrompt.ts
|
|
15091
|
-
import { z as
|
|
15760
|
+
import { z as z35 } from "zod";
|
|
15092
15761
|
|
|
15093
15762
|
// src/mcp/prompts/base/BasePrompt.ts
|
|
15094
|
-
import { z as
|
|
15763
|
+
import { z as z34 } from "zod";
|
|
15095
15764
|
var BasePrompt = class {
|
|
15096
15765
|
getDefinition() {
|
|
15097
15766
|
return {
|
|
@@ -15120,7 +15789,7 @@ var BasePrompt = class {
|
|
|
15120
15789
|
const argsToValidate = args === void 0 ? {} : args;
|
|
15121
15790
|
return this.argumentsValidationSchema.parse(argsToValidate);
|
|
15122
15791
|
} catch (error) {
|
|
15123
|
-
if (error instanceof
|
|
15792
|
+
if (error instanceof z34.ZodError) {
|
|
15124
15793
|
const errorDetails = error.errors.map((e) => {
|
|
15125
15794
|
const fieldPath = e.path.length > 0 ? e.path.join(".") : "root";
|
|
15126
15795
|
const message = e.message === "Required" ? `Missing required argument '${fieldPath}'` : `Invalid value for '${fieldPath}': ${e.message}`;
|
|
@@ -15149,8 +15818,8 @@ var BasePrompt = class {
|
|
|
15149
15818
|
};
|
|
15150
15819
|
|
|
15151
15820
|
// src/mcp/prompts/CheckForNewVulnerabilitiesPrompt.ts
|
|
15152
|
-
var CheckForNewVulnerabilitiesArgsSchema =
|
|
15153
|
-
path:
|
|
15821
|
+
var CheckForNewVulnerabilitiesArgsSchema = z35.object({
|
|
15822
|
+
path: z35.string().optional()
|
|
15154
15823
|
});
|
|
15155
15824
|
var CheckForNewVulnerabilitiesPrompt = class extends BasePrompt {
|
|
15156
15825
|
constructor() {
|
|
@@ -15395,9 +16064,9 @@ Call the \`check_for_new_available_fixes\` tool now${args?.path ? ` for ${args.p
|
|
|
15395
16064
|
};
|
|
15396
16065
|
|
|
15397
16066
|
// src/mcp/prompts/FullSecurityAuditPrompt.ts
|
|
15398
|
-
import { z as
|
|
15399
|
-
var FullSecurityAuditArgsSchema =
|
|
15400
|
-
path:
|
|
16067
|
+
import { z as z36 } from "zod";
|
|
16068
|
+
var FullSecurityAuditArgsSchema = z36.object({
|
|
16069
|
+
path: z36.string().optional()
|
|
15401
16070
|
});
|
|
15402
16071
|
var FullSecurityAuditPrompt = class extends BasePrompt {
|
|
15403
16072
|
constructor() {
|
|
@@ -15848,9 +16517,9 @@ Begin the audit now${args?.path ? ` for ${args.path}` : ""}.
|
|
|
15848
16517
|
};
|
|
15849
16518
|
|
|
15850
16519
|
// src/mcp/prompts/ReviewAndFixCriticalPrompt.ts
|
|
15851
|
-
import { z as
|
|
15852
|
-
var ReviewAndFixCriticalArgsSchema =
|
|
15853
|
-
path:
|
|
16520
|
+
import { z as z37 } from "zod";
|
|
16521
|
+
var ReviewAndFixCriticalArgsSchema = z37.object({
|
|
16522
|
+
path: z37.string().optional()
|
|
15854
16523
|
});
|
|
15855
16524
|
var ReviewAndFixCriticalPrompt = class extends BasePrompt {
|
|
15856
16525
|
constructor() {
|
|
@@ -16154,9 +16823,9 @@ Start by scanning${args?.path ? ` ${args.path}` : " the repository"} and priorit
|
|
|
16154
16823
|
};
|
|
16155
16824
|
|
|
16156
16825
|
// src/mcp/prompts/ScanRecentChangesPrompt.ts
|
|
16157
|
-
import { z as
|
|
16158
|
-
var ScanRecentChangesArgsSchema =
|
|
16159
|
-
path:
|
|
16826
|
+
import { z as z38 } from "zod";
|
|
16827
|
+
var ScanRecentChangesArgsSchema = z38.object({
|
|
16828
|
+
path: z38.string().optional()
|
|
16160
16829
|
});
|
|
16161
16830
|
var ScanRecentChangesPrompt = class extends BasePrompt {
|
|
16162
16831
|
constructor() {
|
|
@@ -16367,9 +17036,9 @@ You now have the guidance needed to perform a fast, targeted security scan of re
|
|
|
16367
17036
|
};
|
|
16368
17037
|
|
|
16369
17038
|
// src/mcp/prompts/ScanRepositoryPrompt.ts
|
|
16370
|
-
import { z as
|
|
16371
|
-
var ScanRepositoryArgsSchema =
|
|
16372
|
-
path:
|
|
17039
|
+
import { z as z39 } from "zod";
|
|
17040
|
+
var ScanRepositoryArgsSchema = z39.object({
|
|
17041
|
+
path: z39.string().optional()
|
|
16373
17042
|
});
|
|
16374
17043
|
var ScanRepositoryPrompt = class extends BasePrompt {
|
|
16375
17044
|
constructor() {
|
|
@@ -16748,30 +17417,30 @@ For a complete security audit workflow, use the \`full-security-audit\` prompt.
|
|
|
16748
17417
|
|
|
16749
17418
|
// src/mcp/services/McpDetectionService/CursorMcpDetectionService.ts
|
|
16750
17419
|
import * as fs15 from "fs";
|
|
16751
|
-
import * as
|
|
16752
|
-
import * as
|
|
17420
|
+
import * as os8 from "os";
|
|
17421
|
+
import * as path16 from "path";
|
|
16753
17422
|
|
|
16754
17423
|
// src/mcp/services/McpDetectionService/BaseMcpDetectionService.ts
|
|
16755
17424
|
init_configs();
|
|
16756
17425
|
import * as fs14 from "fs";
|
|
16757
17426
|
import fetch6 from "node-fetch";
|
|
16758
|
-
import * as
|
|
17427
|
+
import * as path15 from "path";
|
|
16759
17428
|
|
|
16760
17429
|
// src/mcp/services/McpDetectionService/McpDetectionServiceUtils.ts
|
|
16761
17430
|
import * as fs13 from "fs";
|
|
16762
|
-
import * as
|
|
17431
|
+
import * as os7 from "os";
|
|
16763
17432
|
|
|
16764
17433
|
// src/mcp/services/McpDetectionService/VscodeMcpDetectionService.ts
|
|
16765
17434
|
import * as fs16 from "fs";
|
|
16766
|
-
import * as
|
|
16767
|
-
import * as
|
|
17435
|
+
import * as os9 from "os";
|
|
17436
|
+
import * as path17 from "path";
|
|
16768
17437
|
|
|
16769
17438
|
// src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesTool.ts
|
|
16770
|
-
import { z as
|
|
17439
|
+
import { z as z42 } from "zod";
|
|
16771
17440
|
|
|
16772
17441
|
// src/mcp/services/PathValidation.ts
|
|
16773
17442
|
import fs17 from "fs";
|
|
16774
|
-
import
|
|
17443
|
+
import path18 from "path";
|
|
16775
17444
|
async function validatePath(inputPath) {
|
|
16776
17445
|
logDebug("Validating MCP path", { inputPath });
|
|
16777
17446
|
if (/^\/[a-zA-Z]:\//.test(inputPath)) {
|
|
@@ -16803,7 +17472,7 @@ async function validatePath(inputPath) {
|
|
|
16803
17472
|
logError(error);
|
|
16804
17473
|
return { isValid: false, error, path: inputPath };
|
|
16805
17474
|
}
|
|
16806
|
-
const normalizedPath =
|
|
17475
|
+
const normalizedPath = path18.normalize(inputPath);
|
|
16807
17476
|
if (normalizedPath.includes("..")) {
|
|
16808
17477
|
const error = `Normalized path contains path traversal patterns: ${inputPath}`;
|
|
16809
17478
|
logError(error);
|
|
@@ -16843,7 +17512,7 @@ async function validatePath(inputPath) {
|
|
|
16843
17512
|
}
|
|
16844
17513
|
|
|
16845
17514
|
// src/mcp/tools/base/BaseTool.ts
|
|
16846
|
-
import { z as
|
|
17515
|
+
import { z as z40 } from "zod";
|
|
16847
17516
|
var BaseTool = class {
|
|
16848
17517
|
getDefinition() {
|
|
16849
17518
|
return {
|
|
@@ -16873,7 +17542,7 @@ var BaseTool = class {
|
|
|
16873
17542
|
try {
|
|
16874
17543
|
return this.inputValidationSchema.parse(args);
|
|
16875
17544
|
} catch (error) {
|
|
16876
|
-
if (error instanceof
|
|
17545
|
+
if (error instanceof z40.ZodError) {
|
|
16877
17546
|
const errorDetails = error.errors.map((e) => {
|
|
16878
17547
|
const fieldPath = e.path.length > 0 ? e.path.join(".") : "root";
|
|
16879
17548
|
const message = e.message === "Required" ? `Missing required parameter '${fieldPath}'` : `Invalid value for '${fieldPath}': ${e.message}`;
|
|
@@ -17457,7 +18126,7 @@ init_configs();
|
|
|
17457
18126
|
import fs18 from "fs/promises";
|
|
17458
18127
|
import nodePath from "path";
|
|
17459
18128
|
var getLocalFiles = async ({
|
|
17460
|
-
path:
|
|
18129
|
+
path: path22,
|
|
17461
18130
|
maxFileSize = MCP_MAX_FILE_SIZE,
|
|
17462
18131
|
maxFiles,
|
|
17463
18132
|
isAllFilesScan,
|
|
@@ -17465,17 +18134,17 @@ var getLocalFiles = async ({
|
|
|
17465
18134
|
scanRecentlyChangedFiles
|
|
17466
18135
|
}) => {
|
|
17467
18136
|
logDebug(`[${scanContext}] Starting getLocalFiles`, {
|
|
17468
|
-
path:
|
|
18137
|
+
path: path22,
|
|
17469
18138
|
maxFileSize,
|
|
17470
18139
|
maxFiles,
|
|
17471
18140
|
isAllFilesScan,
|
|
17472
18141
|
scanRecentlyChangedFiles
|
|
17473
18142
|
});
|
|
17474
18143
|
try {
|
|
17475
|
-
const resolvedRepoPath = await fs18.realpath(
|
|
18144
|
+
const resolvedRepoPath = await fs18.realpath(path22);
|
|
17476
18145
|
logDebug(`[${scanContext}] Resolved repository path`, {
|
|
17477
18146
|
resolvedRepoPath,
|
|
17478
|
-
originalPath:
|
|
18147
|
+
originalPath: path22
|
|
17479
18148
|
});
|
|
17480
18149
|
const gitService = new GitService(resolvedRepoPath, log);
|
|
17481
18150
|
const gitValidation = await gitService.validateRepository();
|
|
@@ -17488,7 +18157,7 @@ var getLocalFiles = async ({
|
|
|
17488
18157
|
if (!gitValidation.isValid || isAllFilesScan) {
|
|
17489
18158
|
try {
|
|
17490
18159
|
files = await FileUtils.getLastChangedFiles({
|
|
17491
|
-
dir:
|
|
18160
|
+
dir: path22,
|
|
17492
18161
|
maxFileSize,
|
|
17493
18162
|
maxFiles,
|
|
17494
18163
|
isAllFilesScan
|
|
@@ -17580,7 +18249,7 @@ var getLocalFiles = async ({
|
|
|
17580
18249
|
logError(`${scanContext}Unexpected error in getLocalFiles`, {
|
|
17581
18250
|
error: error instanceof Error ? error.message : String(error),
|
|
17582
18251
|
stack: error instanceof Error ? error.stack : void 0,
|
|
17583
|
-
path:
|
|
18252
|
+
path: path22
|
|
17584
18253
|
});
|
|
17585
18254
|
throw error;
|
|
17586
18255
|
}
|
|
@@ -17588,15 +18257,15 @@ var getLocalFiles = async ({
|
|
|
17588
18257
|
|
|
17589
18258
|
// src/mcp/services/LocalMobbFolderService.ts
|
|
17590
18259
|
import fs19 from "fs";
|
|
17591
|
-
import
|
|
17592
|
-
import { z as
|
|
18260
|
+
import path19 from "path";
|
|
18261
|
+
import { z as z41 } from "zod";
|
|
17593
18262
|
init_GitService();
|
|
17594
18263
|
function extractPathFromPatch(patch) {
|
|
17595
18264
|
const match = patch?.match(/diff --git a\/([^\s]+) b\//);
|
|
17596
18265
|
return match?.[1] ?? null;
|
|
17597
18266
|
}
|
|
17598
18267
|
function parsedIssueTypeRes(issueType) {
|
|
17599
|
-
return
|
|
18268
|
+
return z41.nativeEnum(IssueType_Enum).safeParse(issueType);
|
|
17600
18269
|
}
|
|
17601
18270
|
var LocalMobbFolderService = class {
|
|
17602
18271
|
/**
|
|
@@ -17675,7 +18344,7 @@ var LocalMobbFolderService = class {
|
|
|
17675
18344
|
"[LocalMobbFolderService] Non-git repository detected, skipping .gitignore operations"
|
|
17676
18345
|
);
|
|
17677
18346
|
}
|
|
17678
|
-
const mobbFolderPath =
|
|
18347
|
+
const mobbFolderPath = path19.join(
|
|
17679
18348
|
this.repoPath,
|
|
17680
18349
|
this.defaultMobbFolderName
|
|
17681
18350
|
);
|
|
@@ -17847,7 +18516,7 @@ var LocalMobbFolderService = class {
|
|
|
17847
18516
|
mobbFolderPath,
|
|
17848
18517
|
baseFileName
|
|
17849
18518
|
);
|
|
17850
|
-
const filePath =
|
|
18519
|
+
const filePath = path19.join(mobbFolderPath, uniqueFileName);
|
|
17851
18520
|
await fs19.promises.writeFile(filePath, patch, "utf8");
|
|
17852
18521
|
logInfo("[LocalMobbFolderService] Patch saved successfully", {
|
|
17853
18522
|
filePath,
|
|
@@ -17905,11 +18574,11 @@ var LocalMobbFolderService = class {
|
|
|
17905
18574
|
* @returns Unique filename that doesn't conflict with existing files
|
|
17906
18575
|
*/
|
|
17907
18576
|
getUniqueFileName(folderPath, baseFileName) {
|
|
17908
|
-
const baseName =
|
|
17909
|
-
const extension =
|
|
18577
|
+
const baseName = path19.parse(baseFileName).name;
|
|
18578
|
+
const extension = path19.parse(baseFileName).ext;
|
|
17910
18579
|
let uniqueFileName = baseFileName;
|
|
17911
18580
|
let index = 1;
|
|
17912
|
-
while (fs19.existsSync(
|
|
18581
|
+
while (fs19.existsSync(path19.join(folderPath, uniqueFileName))) {
|
|
17913
18582
|
uniqueFileName = `${baseName}-${index}${extension}`;
|
|
17914
18583
|
index++;
|
|
17915
18584
|
if (index > 1e3) {
|
|
@@ -17940,7 +18609,7 @@ var LocalMobbFolderService = class {
|
|
|
17940
18609
|
logDebug("[LocalMobbFolderService] Logging patch info", { fixId: fix.id });
|
|
17941
18610
|
try {
|
|
17942
18611
|
const mobbFolderPath = await this.getFolder();
|
|
17943
|
-
const patchInfoPath =
|
|
18612
|
+
const patchInfoPath = path19.join(mobbFolderPath, "patchInfo.md");
|
|
17944
18613
|
const markdownContent = this.generateFixMarkdown(fix, savedPatchFileName);
|
|
17945
18614
|
let existingContent = "";
|
|
17946
18615
|
if (fs19.existsSync(patchInfoPath)) {
|
|
@@ -17982,7 +18651,7 @@ var LocalMobbFolderService = class {
|
|
|
17982
18651
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
17983
18652
|
const patch = this.extractPatchFromFix(fix);
|
|
17984
18653
|
const relativePatchedFilePath = patch ? extractPathFromPatch(patch) : null;
|
|
17985
|
-
const patchedFilePath = relativePatchedFilePath ?
|
|
18654
|
+
const patchedFilePath = relativePatchedFilePath ? path19.resolve(this.repoPath, relativePatchedFilePath) : null;
|
|
17986
18655
|
const fixIdentifier = savedPatchFileName ? savedPatchFileName.replace(".patch", "") : fix.id;
|
|
17987
18656
|
let markdown = `# Fix ${fixIdentifier}
|
|
17988
18657
|
|
|
@@ -18326,14 +18995,14 @@ import {
|
|
|
18326
18995
|
} from "fs";
|
|
18327
18996
|
import fs20 from "fs/promises";
|
|
18328
18997
|
import parseDiff2 from "parse-diff";
|
|
18329
|
-
import
|
|
18998
|
+
import path20 from "path";
|
|
18330
18999
|
var PatchApplicationService = class {
|
|
18331
19000
|
/**
|
|
18332
19001
|
* Gets the appropriate comment syntax for a file based on its extension
|
|
18333
19002
|
*/
|
|
18334
19003
|
static getCommentSyntax(filePath) {
|
|
18335
|
-
const ext =
|
|
18336
|
-
const basename2 =
|
|
19004
|
+
const ext = path20.extname(filePath).toLowerCase();
|
|
19005
|
+
const basename2 = path20.basename(filePath);
|
|
18337
19006
|
const commentMap = {
|
|
18338
19007
|
// C-style languages (single line comments)
|
|
18339
19008
|
".js": "//",
|
|
@@ -18536,7 +19205,7 @@ var PatchApplicationService = class {
|
|
|
18536
19205
|
}
|
|
18537
19206
|
);
|
|
18538
19207
|
}
|
|
18539
|
-
const dirPath =
|
|
19208
|
+
const dirPath = path20.dirname(filePath);
|
|
18540
19209
|
mkdirSync(dirPath, { recursive: true });
|
|
18541
19210
|
writeFileSync(filePath, finalContent, "utf8");
|
|
18542
19211
|
return filePath;
|
|
@@ -18820,7 +19489,7 @@ var PatchApplicationService = class {
|
|
|
18820
19489
|
continue;
|
|
18821
19490
|
}
|
|
18822
19491
|
try {
|
|
18823
|
-
const absolutePath =
|
|
19492
|
+
const absolutePath = path20.resolve(repositoryPath, targetFile);
|
|
18824
19493
|
if (existsSync6(absolutePath)) {
|
|
18825
19494
|
const stats = await fs20.stat(absolutePath);
|
|
18826
19495
|
const fileModTime = stats.mtime.getTime();
|
|
@@ -19011,11 +19680,11 @@ var PatchApplicationService = class {
|
|
|
19011
19680
|
}) {
|
|
19012
19681
|
const sanitizedRepoPath = String(repositoryPath || "").replace("\0", "").replace(/^(\.\.(\/|\\))+/, "");
|
|
19013
19682
|
const sanitizedTargetFile = String(targetFile || "").replace("\0", "").replace(/^(\.\.(\/|\\))+/, "");
|
|
19014
|
-
const absoluteFilePath =
|
|
19683
|
+
const absoluteFilePath = path20.resolve(
|
|
19015
19684
|
sanitizedRepoPath,
|
|
19016
19685
|
sanitizedTargetFile
|
|
19017
19686
|
);
|
|
19018
|
-
const relativePath =
|
|
19687
|
+
const relativePath = path20.relative(sanitizedRepoPath, absoluteFilePath);
|
|
19019
19688
|
if (relativePath.startsWith("..")) {
|
|
19020
19689
|
throw new Error(
|
|
19021
19690
|
`Security violation: target file ${targetFile} resolves outside repository`
|
|
@@ -19049,7 +19718,7 @@ var PatchApplicationService = class {
|
|
|
19049
19718
|
fix,
|
|
19050
19719
|
scanContext
|
|
19051
19720
|
});
|
|
19052
|
-
appliedFiles.push(
|
|
19721
|
+
appliedFiles.push(path20.relative(repositoryPath, actualPath));
|
|
19053
19722
|
logDebug(`[${scanContext}] Created new file: ${relativePath}`);
|
|
19054
19723
|
}
|
|
19055
19724
|
/**
|
|
@@ -19097,7 +19766,7 @@ var PatchApplicationService = class {
|
|
|
19097
19766
|
fix,
|
|
19098
19767
|
scanContext
|
|
19099
19768
|
});
|
|
19100
|
-
appliedFiles.push(
|
|
19769
|
+
appliedFiles.push(path20.relative(repositoryPath, actualPath));
|
|
19101
19770
|
logDebug(`[${scanContext}] Modified file: ${relativePath}`);
|
|
19102
19771
|
}
|
|
19103
19772
|
}
|
|
@@ -19293,7 +19962,7 @@ init_configs();
|
|
|
19293
19962
|
// src/mcp/services/FileOperations.ts
|
|
19294
19963
|
init_FileUtils();
|
|
19295
19964
|
import fs21 from "fs";
|
|
19296
|
-
import
|
|
19965
|
+
import path21 from "path";
|
|
19297
19966
|
import AdmZip2 from "adm-zip";
|
|
19298
19967
|
var FileOperations = class {
|
|
19299
19968
|
/**
|
|
@@ -19313,10 +19982,10 @@ var FileOperations = class {
|
|
|
19313
19982
|
let packedFilesCount = 0;
|
|
19314
19983
|
const packedFiles = [];
|
|
19315
19984
|
const excludedFiles = [];
|
|
19316
|
-
const resolvedRepoPath =
|
|
19985
|
+
const resolvedRepoPath = path21.resolve(repositoryPath);
|
|
19317
19986
|
for (const filepath of fileList) {
|
|
19318
|
-
const absoluteFilepath =
|
|
19319
|
-
const resolvedFilePath =
|
|
19987
|
+
const absoluteFilepath = path21.join(repositoryPath, filepath);
|
|
19988
|
+
const resolvedFilePath = path21.resolve(absoluteFilepath);
|
|
19320
19989
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
19321
19990
|
const reason = "potential path traversal security risk";
|
|
19322
19991
|
logDebug(`[FileOperations] Skipping ${filepath} due to ${reason}`);
|
|
@@ -19363,11 +20032,11 @@ var FileOperations = class {
|
|
|
19363
20032
|
fileList,
|
|
19364
20033
|
repositoryPath
|
|
19365
20034
|
}) {
|
|
19366
|
-
const resolvedRepoPath =
|
|
20035
|
+
const resolvedRepoPath = path21.resolve(repositoryPath);
|
|
19367
20036
|
const validatedPaths = [];
|
|
19368
20037
|
for (const filepath of fileList) {
|
|
19369
|
-
const absoluteFilepath =
|
|
19370
|
-
const resolvedFilePath =
|
|
20038
|
+
const absoluteFilepath = path21.join(repositoryPath, filepath);
|
|
20039
|
+
const resolvedFilePath = path21.resolve(absoluteFilepath);
|
|
19371
20040
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
19372
20041
|
logDebug(
|
|
19373
20042
|
`[FileOperations] Rejecting ${filepath} - path traversal attempt detected`
|
|
@@ -19395,7 +20064,7 @@ var FileOperations = class {
|
|
|
19395
20064
|
for (const absolutePath of filePaths) {
|
|
19396
20065
|
try {
|
|
19397
20066
|
const content = await fs21.promises.readFile(absolutePath);
|
|
19398
|
-
const relativePath =
|
|
20067
|
+
const relativePath = path21.basename(absolutePath);
|
|
19399
20068
|
fileDataArray.push({
|
|
19400
20069
|
relativePath,
|
|
19401
20070
|
absolutePath,
|
|
@@ -19707,14 +20376,14 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
19707
20376
|
* since the last scan.
|
|
19708
20377
|
*/
|
|
19709
20378
|
async scanForSecurityVulnerabilities({
|
|
19710
|
-
path:
|
|
20379
|
+
path: path22,
|
|
19711
20380
|
isAllDetectionRulesScan,
|
|
19712
20381
|
isAllFilesScan,
|
|
19713
20382
|
scanContext
|
|
19714
20383
|
}) {
|
|
19715
20384
|
this.hasAuthenticationFailed = false;
|
|
19716
20385
|
logDebug(`[${scanContext}] Scanning for new security vulnerabilities`, {
|
|
19717
|
-
path:
|
|
20386
|
+
path: path22
|
|
19718
20387
|
});
|
|
19719
20388
|
if (!this.gqlClient) {
|
|
19720
20389
|
logInfo(`[${scanContext}] No GQL client found, skipping scan`);
|
|
@@ -19730,11 +20399,11 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
19730
20399
|
}
|
|
19731
20400
|
logDebug(
|
|
19732
20401
|
`[${scanContext}] Connected to the API, assembling list of files to scan`,
|
|
19733
|
-
{ path:
|
|
20402
|
+
{ path: path22 }
|
|
19734
20403
|
);
|
|
19735
20404
|
const isBackgroundScan = scanContext === ScanContext.BACKGROUND_INITIAL || scanContext === ScanContext.BACKGROUND_PERIODIC;
|
|
19736
20405
|
const files = await getLocalFiles({
|
|
19737
|
-
path:
|
|
20406
|
+
path: path22,
|
|
19738
20407
|
isAllFilesScan,
|
|
19739
20408
|
scanContext,
|
|
19740
20409
|
scanRecentlyChangedFiles: !isBackgroundScan
|
|
@@ -19760,13 +20429,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
19760
20429
|
});
|
|
19761
20430
|
const { fixReportId, projectId } = await scanFiles({
|
|
19762
20431
|
fileList: filesToScan.map((file) => file.relativePath),
|
|
19763
|
-
repositoryPath:
|
|
20432
|
+
repositoryPath: path22,
|
|
19764
20433
|
gqlClient: this.gqlClient,
|
|
19765
20434
|
isAllDetectionRulesScan,
|
|
19766
20435
|
scanContext
|
|
19767
20436
|
});
|
|
19768
20437
|
logInfo(
|
|
19769
|
-
`[${scanContext}] Security scan completed for ${
|
|
20438
|
+
`[${scanContext}] Security scan completed for ${path22} reportId: ${fixReportId} projectId: ${projectId}`
|
|
19770
20439
|
);
|
|
19771
20440
|
if (isAllFilesScan) {
|
|
19772
20441
|
return;
|
|
@@ -20060,13 +20729,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
20060
20729
|
});
|
|
20061
20730
|
return scannedFiles.some((file) => file.relativePath === fixFile);
|
|
20062
20731
|
}
|
|
20063
|
-
async getFreshFixes({ path:
|
|
20732
|
+
async getFreshFixes({ path: path22 }) {
|
|
20064
20733
|
const scanContext = ScanContext.USER_REQUEST;
|
|
20065
|
-
logDebug(`[${scanContext}] Getting fresh fixes`, { path:
|
|
20066
|
-
if (this.path !==
|
|
20067
|
-
this.path =
|
|
20734
|
+
logDebug(`[${scanContext}] Getting fresh fixes`, { path: path22 });
|
|
20735
|
+
if (this.path !== path22) {
|
|
20736
|
+
this.path = path22;
|
|
20068
20737
|
this.reset();
|
|
20069
|
-
logInfo(`[${scanContext}] Reset service state for new path`, { path:
|
|
20738
|
+
logInfo(`[${scanContext}] Reset service state for new path`, { path: path22 });
|
|
20070
20739
|
}
|
|
20071
20740
|
try {
|
|
20072
20741
|
this.gqlClient = await createAuthenticatedMcpGQLClient();
|
|
@@ -20084,7 +20753,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
20084
20753
|
}
|
|
20085
20754
|
throw error;
|
|
20086
20755
|
}
|
|
20087
|
-
this.triggerScan({ path:
|
|
20756
|
+
this.triggerScan({ path: path22, gqlClient: this.gqlClient });
|
|
20088
20757
|
let isMvsAutoFixEnabled = null;
|
|
20089
20758
|
try {
|
|
20090
20759
|
isMvsAutoFixEnabled = await this.gqlClient.getMvsAutoFixSettings();
|
|
@@ -20118,33 +20787,33 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
20118
20787
|
return noFreshFixesPrompt;
|
|
20119
20788
|
}
|
|
20120
20789
|
triggerScan({
|
|
20121
|
-
path:
|
|
20790
|
+
path: path22,
|
|
20122
20791
|
gqlClient
|
|
20123
20792
|
}) {
|
|
20124
|
-
if (this.path !==
|
|
20125
|
-
this.path =
|
|
20793
|
+
if (this.path !== path22) {
|
|
20794
|
+
this.path = path22;
|
|
20126
20795
|
this.reset();
|
|
20127
|
-
logInfo(`Reset service state for new path in triggerScan`, { path:
|
|
20796
|
+
logInfo(`Reset service state for new path in triggerScan`, { path: path22 });
|
|
20128
20797
|
}
|
|
20129
20798
|
this.gqlClient = gqlClient;
|
|
20130
20799
|
if (!this.intervalId) {
|
|
20131
|
-
this.startPeriodicScanning(
|
|
20132
|
-
this.executeInitialScan(
|
|
20133
|
-
void this.executeInitialFullScan(
|
|
20800
|
+
this.startPeriodicScanning(path22);
|
|
20801
|
+
this.executeInitialScan(path22);
|
|
20802
|
+
void this.executeInitialFullScan(path22);
|
|
20134
20803
|
}
|
|
20135
20804
|
}
|
|
20136
|
-
startPeriodicScanning(
|
|
20805
|
+
startPeriodicScanning(path22) {
|
|
20137
20806
|
const scanContext = ScanContext.BACKGROUND_PERIODIC;
|
|
20138
20807
|
logDebug(
|
|
20139
20808
|
`[${scanContext}] Starting periodic scan for new security vulnerabilities`,
|
|
20140
20809
|
{
|
|
20141
|
-
path:
|
|
20810
|
+
path: path22
|
|
20142
20811
|
}
|
|
20143
20812
|
);
|
|
20144
20813
|
this.intervalId = setInterval(() => {
|
|
20145
|
-
logDebug(`[${scanContext}] Triggering periodic security scan`, { path:
|
|
20814
|
+
logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path22 });
|
|
20146
20815
|
this.scanForSecurityVulnerabilities({
|
|
20147
|
-
path:
|
|
20816
|
+
path: path22,
|
|
20148
20817
|
scanContext
|
|
20149
20818
|
}).catch((error) => {
|
|
20150
20819
|
logError(`[${scanContext}] Error during periodic security scan`, {
|
|
@@ -20153,45 +20822,45 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
20153
20822
|
});
|
|
20154
20823
|
}, MCP_PERIODIC_CHECK_INTERVAL);
|
|
20155
20824
|
}
|
|
20156
|
-
async executeInitialFullScan(
|
|
20825
|
+
async executeInitialFullScan(path22) {
|
|
20157
20826
|
const scanContext = ScanContext.FULL_SCAN;
|
|
20158
|
-
logDebug(`[${scanContext}] Triggering initial full security scan`, { path:
|
|
20827
|
+
logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path22 });
|
|
20159
20828
|
logDebug(`[${scanContext}] Full scan paths scanned`, {
|
|
20160
20829
|
fullScanPathsScanned: this.fullScanPathsScanned
|
|
20161
20830
|
});
|
|
20162
|
-
if (this.fullScanPathsScanned.includes(
|
|
20831
|
+
if (this.fullScanPathsScanned.includes(path22)) {
|
|
20163
20832
|
logDebug(`[${scanContext}] Full scan already executed for this path`, {
|
|
20164
|
-
path:
|
|
20833
|
+
path: path22
|
|
20165
20834
|
});
|
|
20166
20835
|
return;
|
|
20167
20836
|
}
|
|
20168
20837
|
configStore.set("fullScanPathsScanned", [
|
|
20169
20838
|
...this.fullScanPathsScanned,
|
|
20170
|
-
|
|
20839
|
+
path22
|
|
20171
20840
|
]);
|
|
20172
20841
|
try {
|
|
20173
20842
|
await this.scanForSecurityVulnerabilities({
|
|
20174
|
-
path:
|
|
20843
|
+
path: path22,
|
|
20175
20844
|
isAllFilesScan: true,
|
|
20176
20845
|
isAllDetectionRulesScan: true,
|
|
20177
20846
|
scanContext: ScanContext.FULL_SCAN
|
|
20178
20847
|
});
|
|
20179
|
-
if (!this.fullScanPathsScanned.includes(
|
|
20180
|
-
this.fullScanPathsScanned.push(
|
|
20848
|
+
if (!this.fullScanPathsScanned.includes(path22)) {
|
|
20849
|
+
this.fullScanPathsScanned.push(path22);
|
|
20181
20850
|
configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
|
|
20182
20851
|
}
|
|
20183
|
-
logInfo(`[${scanContext}] Full scan completed`, { path:
|
|
20852
|
+
logInfo(`[${scanContext}] Full scan completed`, { path: path22 });
|
|
20184
20853
|
} catch (error) {
|
|
20185
20854
|
logError(`[${scanContext}] Error during initial full security scan`, {
|
|
20186
20855
|
error
|
|
20187
20856
|
});
|
|
20188
20857
|
}
|
|
20189
20858
|
}
|
|
20190
|
-
executeInitialScan(
|
|
20859
|
+
executeInitialScan(path22) {
|
|
20191
20860
|
const scanContext = ScanContext.BACKGROUND_INITIAL;
|
|
20192
|
-
logDebug(`[${scanContext}] Triggering initial security scan`, { path:
|
|
20861
|
+
logDebug(`[${scanContext}] Triggering initial security scan`, { path: path22 });
|
|
20193
20862
|
this.scanForSecurityVulnerabilities({
|
|
20194
|
-
path:
|
|
20863
|
+
path: path22,
|
|
20195
20864
|
scanContext: ScanContext.BACKGROUND_INITIAL
|
|
20196
20865
|
}).catch((error) => {
|
|
20197
20866
|
logError(`[${scanContext}] Error during initial security scan`, { error });
|
|
@@ -20270,8 +20939,8 @@ Example payload:
|
|
|
20270
20939
|
},
|
|
20271
20940
|
required: ["path"]
|
|
20272
20941
|
});
|
|
20273
|
-
__publicField(this, "inputValidationSchema",
|
|
20274
|
-
path:
|
|
20942
|
+
__publicField(this, "inputValidationSchema", z42.object({
|
|
20943
|
+
path: z42.string().describe(
|
|
20275
20944
|
"Full local path to the cloned git repository to check for new available fixes"
|
|
20276
20945
|
)
|
|
20277
20946
|
}));
|
|
@@ -20288,9 +20957,9 @@ Example payload:
|
|
|
20288
20957
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
20289
20958
|
);
|
|
20290
20959
|
}
|
|
20291
|
-
const
|
|
20960
|
+
const path22 = pathValidationResult.path;
|
|
20292
20961
|
const resultText = await this.newFixesService.getFreshFixes({
|
|
20293
|
-
path:
|
|
20962
|
+
path: path22
|
|
20294
20963
|
});
|
|
20295
20964
|
logInfo("CheckForNewAvailableFixesTool execution completed", {
|
|
20296
20965
|
resultText
|
|
@@ -20301,7 +20970,7 @@ Example payload:
|
|
|
20301
20970
|
|
|
20302
20971
|
// src/mcp/tools/fetchAvailableFixes/FetchAvailableFixesTool.ts
|
|
20303
20972
|
init_GitService();
|
|
20304
|
-
import { z as
|
|
20973
|
+
import { z as z43 } from "zod";
|
|
20305
20974
|
|
|
20306
20975
|
// src/mcp/tools/fetchAvailableFixes/FetchAvailableFixesService.ts
|
|
20307
20976
|
init_configs();
|
|
@@ -20443,16 +21112,16 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
20443
21112
|
},
|
|
20444
21113
|
required: ["path"]
|
|
20445
21114
|
});
|
|
20446
|
-
__publicField(this, "inputValidationSchema",
|
|
20447
|
-
path:
|
|
21115
|
+
__publicField(this, "inputValidationSchema", z43.object({
|
|
21116
|
+
path: z43.string().describe(
|
|
20448
21117
|
"Full local path to the cloned git repository to check for available fixes"
|
|
20449
21118
|
),
|
|
20450
|
-
offset:
|
|
20451
|
-
limit:
|
|
20452
|
-
fileFilter:
|
|
21119
|
+
offset: z43.number().optional().describe("Optional offset for pagination"),
|
|
21120
|
+
limit: z43.number().optional().describe("Optional maximum number of fixes to return"),
|
|
21121
|
+
fileFilter: z43.array(z43.string()).optional().describe(
|
|
20453
21122
|
"Optional list of file paths relative to the path parameter to filter fixes by. INCOMPATIBLE with fetchFixesFromAnyFile"
|
|
20454
21123
|
),
|
|
20455
|
-
fetchFixesFromAnyFile:
|
|
21124
|
+
fetchFixesFromAnyFile: z43.boolean().optional().describe(
|
|
20456
21125
|
"Optional boolean to fetch fixes for all files. INCOMPATIBLE with fileFilter"
|
|
20457
21126
|
)
|
|
20458
21127
|
}));
|
|
@@ -20467,8 +21136,8 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
20467
21136
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
20468
21137
|
);
|
|
20469
21138
|
}
|
|
20470
|
-
const
|
|
20471
|
-
const gitService = new GitService(
|
|
21139
|
+
const path22 = pathValidationResult.path;
|
|
21140
|
+
const gitService = new GitService(path22, log);
|
|
20472
21141
|
const gitValidation = await gitService.validateRepository();
|
|
20473
21142
|
if (!gitValidation.isValid) {
|
|
20474
21143
|
throw new Error(`Invalid git repository: ${gitValidation.error}`);
|
|
@@ -20521,7 +21190,7 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
20521
21190
|
};
|
|
20522
21191
|
|
|
20523
21192
|
// src/mcp/tools/mcpChecker/mcpCheckerTool.ts
|
|
20524
|
-
import
|
|
21193
|
+
import z44 from "zod";
|
|
20525
21194
|
|
|
20526
21195
|
// src/mcp/tools/mcpChecker/mcpCheckerService.ts
|
|
20527
21196
|
var _McpCheckerService = class _McpCheckerService {
|
|
@@ -20582,7 +21251,7 @@ var McpCheckerTool = class extends BaseTool {
|
|
|
20582
21251
|
__publicField(this, "displayName", "MCP Checker");
|
|
20583
21252
|
// A detailed description to guide the LLM on when and how to invoke this tool.
|
|
20584
21253
|
__publicField(this, "description", "Check the MCP servers running on this IDE against organization policies.");
|
|
20585
|
-
__publicField(this, "inputValidationSchema",
|
|
21254
|
+
__publicField(this, "inputValidationSchema", z44.object({}));
|
|
20586
21255
|
__publicField(this, "inputSchema", {
|
|
20587
21256
|
type: "object",
|
|
20588
21257
|
properties: {},
|
|
@@ -20608,7 +21277,7 @@ var McpCheckerTool = class extends BaseTool {
|
|
|
20608
21277
|
};
|
|
20609
21278
|
|
|
20610
21279
|
// src/mcp/tools/scanAndFixVulnerabilities/ScanAndFixVulnerabilitiesTool.ts
|
|
20611
|
-
import
|
|
21280
|
+
import z45 from "zod";
|
|
20612
21281
|
init_configs();
|
|
20613
21282
|
|
|
20614
21283
|
// src/mcp/tools/scanAndFixVulnerabilities/ScanAndFixVulnerabilitiesService.ts
|
|
@@ -20795,17 +21464,17 @@ Example payload:
|
|
|
20795
21464
|
"rescan": false
|
|
20796
21465
|
}`);
|
|
20797
21466
|
__publicField(this, "hasAuthentication", true);
|
|
20798
|
-
__publicField(this, "inputValidationSchema",
|
|
20799
|
-
path:
|
|
21467
|
+
__publicField(this, "inputValidationSchema", z45.object({
|
|
21468
|
+
path: z45.string().describe(
|
|
20800
21469
|
"Full local path to repository to scan and fix vulnerabilities"
|
|
20801
21470
|
),
|
|
20802
|
-
offset:
|
|
20803
|
-
limit:
|
|
20804
|
-
maxFiles:
|
|
21471
|
+
offset: z45.number().optional().describe("Optional offset for pagination"),
|
|
21472
|
+
limit: z45.number().optional().describe("Optional maximum number of results to return"),
|
|
21473
|
+
maxFiles: z45.number().optional().describe(
|
|
20805
21474
|
`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
21475
|
),
|
|
20807
|
-
rescan:
|
|
20808
|
-
scanRecentlyChangedFiles:
|
|
21476
|
+
rescan: z45.boolean().optional().describe("Optional whether to rescan the repository"),
|
|
21477
|
+
scanRecentlyChangedFiles: z45.boolean().optional().describe(
|
|
20809
21478
|
"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
21479
|
)
|
|
20811
21480
|
}));
|
|
@@ -20856,9 +21525,9 @@ Example payload:
|
|
|
20856
21525
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
20857
21526
|
);
|
|
20858
21527
|
}
|
|
20859
|
-
const
|
|
21528
|
+
const path22 = pathValidationResult.path;
|
|
20860
21529
|
const files = await getLocalFiles({
|
|
20861
|
-
path:
|
|
21530
|
+
path: path22,
|
|
20862
21531
|
maxFileSize: MCP_MAX_FILE_SIZE,
|
|
20863
21532
|
maxFiles: args.maxFiles,
|
|
20864
21533
|
scanContext: ScanContext.USER_REQUEST,
|
|
@@ -20878,7 +21547,7 @@ Example payload:
|
|
|
20878
21547
|
try {
|
|
20879
21548
|
const fixResult = await this.vulnerabilityFixService.processVulnerabilities({
|
|
20880
21549
|
fileList: files.map((file) => file.relativePath),
|
|
20881
|
-
repositoryPath:
|
|
21550
|
+
repositoryPath: path22,
|
|
20882
21551
|
offset: args.offset,
|
|
20883
21552
|
limit: args.limit,
|
|
20884
21553
|
isRescan: args.rescan || !!args.maxFiles
|
|
@@ -20983,32 +21652,32 @@ var mcpHandler = async (_args) => {
|
|
|
20983
21652
|
|
|
20984
21653
|
// src/args/commands/review.ts
|
|
20985
21654
|
import fs22 from "fs";
|
|
20986
|
-
import
|
|
21655
|
+
import chalk11 from "chalk";
|
|
20987
21656
|
function reviewBuilder(yargs2) {
|
|
20988
21657
|
return yargs2.option("f", {
|
|
20989
21658
|
alias: "scan-file",
|
|
20990
21659
|
demandOption: true,
|
|
20991
21660
|
type: "string",
|
|
20992
|
-
describe:
|
|
21661
|
+
describe: chalk11.bold(
|
|
20993
21662
|
"Select the vulnerability report to analyze (Checkmarx, Snyk, Fortify, CodeQL, Sonarqube, Semgrep)"
|
|
20994
21663
|
)
|
|
20995
21664
|
}).option("repo", { ...repoOption, demandOption: true }).option("scanner", { ...scannerOptions, demandOption: true }).option("ref", { ...refOption, demandOption: true }).option("ch", {
|
|
20996
21665
|
alias: "commit-hash",
|
|
20997
|
-
describe:
|
|
21666
|
+
describe: chalk11.bold("Hash of the commit"),
|
|
20998
21667
|
type: "string",
|
|
20999
21668
|
demandOption: true
|
|
21000
21669
|
}).option("mobb-project-name", mobbProjectNameOption).option("api-key", { ...apiKeyOption, demandOption: true }).option("commit-hash", { ...commitHashOption, demandOption: true }).option("github-token", {
|
|
21001
|
-
describe:
|
|
21670
|
+
describe: chalk11.bold("Github action token"),
|
|
21002
21671
|
type: "string",
|
|
21003
21672
|
demandOption: true
|
|
21004
21673
|
}).option("pull-request", {
|
|
21005
21674
|
alias: ["pr", "pr-number", "pr-id"],
|
|
21006
|
-
describe:
|
|
21675
|
+
describe: chalk11.bold("Number of the pull request"),
|
|
21007
21676
|
type: "number",
|
|
21008
21677
|
demandOption: true
|
|
21009
21678
|
}).option("p", {
|
|
21010
21679
|
alias: "src-path",
|
|
21011
|
-
describe:
|
|
21680
|
+
describe: chalk11.bold(
|
|
21012
21681
|
"Path to the repository folder with the source code"
|
|
21013
21682
|
),
|
|
21014
21683
|
type: "string",
|
|
@@ -21021,7 +21690,7 @@ function reviewBuilder(yargs2) {
|
|
|
21021
21690
|
function validateReviewOptions(argv) {
|
|
21022
21691
|
if (!fs22.existsSync(argv.f)) {
|
|
21023
21692
|
throw new CliError(`
|
|
21024
|
-
Can't access ${
|
|
21693
|
+
Can't access ${chalk11.bold(argv.f)}`);
|
|
21025
21694
|
}
|
|
21026
21695
|
validateRepoUrl(argv);
|
|
21027
21696
|
validateReportFileFormat(argv.f);
|
|
@@ -21091,248 +21760,77 @@ async function addScmTokenHandler(args) {
|
|
|
21091
21760
|
await addScmToken(args);
|
|
21092
21761
|
}
|
|
21093
21762
|
|
|
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
21763
|
// src/args/yargs.ts
|
|
21276
21764
|
var parseArgs = async (args) => {
|
|
21277
21765
|
const yargsInstance = yargs(args);
|
|
21278
21766
|
return yargsInstance.updateStrings({
|
|
21279
|
-
"Commands:":
|
|
21280
|
-
"Options:":
|
|
21281
|
-
"Examples:":
|
|
21282
|
-
"Show help":
|
|
21767
|
+
"Commands:": chalk12.yellow.underline.bold("Commands:"),
|
|
21768
|
+
"Options:": chalk12.yellow.underline.bold("Options:"),
|
|
21769
|
+
"Examples:": chalk12.yellow.underline.bold("Examples:"),
|
|
21770
|
+
"Show help": chalk12.bold("Show help")
|
|
21283
21771
|
}).usage(
|
|
21284
|
-
`${
|
|
21772
|
+
`${chalk12.bold(
|
|
21285
21773
|
"\n Bugsy - Trusted, Automatic Vulnerability Fixer \u{1F575}\uFE0F\u200D\u2642\uFE0F\n\n"
|
|
21286
|
-
)} ${
|
|
21287
|
-
$0 ${
|
|
21774
|
+
)} ${chalk12.yellow.underline.bold("Usage:")}
|
|
21775
|
+
$0 ${chalk12.green(
|
|
21288
21776
|
"<command>"
|
|
21289
|
-
)} ${
|
|
21777
|
+
)} ${chalk12.dim("[options]")}
|
|
21290
21778
|
`
|
|
21291
21779
|
).version(false).command(
|
|
21292
21780
|
mobbCliCommand.scan,
|
|
21293
|
-
|
|
21781
|
+
chalk12.bold(
|
|
21294
21782
|
"Scan your code for vulnerabilities, get automated fixes right away."
|
|
21295
21783
|
),
|
|
21296
21784
|
scanBuilder,
|
|
21297
21785
|
scanHandler
|
|
21298
21786
|
).command(
|
|
21299
21787
|
mobbCliCommand.analyze,
|
|
21300
|
-
|
|
21788
|
+
chalk12.bold(
|
|
21301
21789
|
"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
21790
|
),
|
|
21303
21791
|
analyzeBuilder,
|
|
21304
21792
|
analyzeHandler
|
|
21305
21793
|
).command(
|
|
21306
21794
|
mobbCliCommand.review,
|
|
21307
|
-
|
|
21795
|
+
chalk12.bold(
|
|
21308
21796
|
"Mobb will review your github pull requests and provide comments with fixes "
|
|
21309
21797
|
),
|
|
21310
21798
|
reviewBuilder,
|
|
21311
21799
|
reviewHandler
|
|
21312
21800
|
).command(
|
|
21313
21801
|
mobbCliCommand.addScmToken,
|
|
21314
|
-
|
|
21802
|
+
chalk12.bold(
|
|
21315
21803
|
"Add your SCM (Github, Gitlab, Azure DevOps) token to Mobb to enable automated fixes."
|
|
21316
21804
|
),
|
|
21317
21805
|
addScmTokenBuilder,
|
|
21318
21806
|
addScmTokenHandler
|
|
21319
21807
|
).command(
|
|
21320
21808
|
mobbCliCommand.convertToSarif,
|
|
21321
|
-
|
|
21809
|
+
chalk12.bold("Convert an existing SAST report to SARIF format."),
|
|
21322
21810
|
convertToSarifBuilder,
|
|
21323
21811
|
convertToSarifHandler
|
|
21324
21812
|
).command(
|
|
21325
21813
|
mobbCliCommand.mcp,
|
|
21326
|
-
|
|
21814
|
+
chalk12.bold("Launch the MCP (Model Context Protocol) server."),
|
|
21327
21815
|
mcpBuilder,
|
|
21328
21816
|
mcpHandler
|
|
21329
21817
|
).command(
|
|
21330
21818
|
mobbCliCommand.uploadAiBlame,
|
|
21331
|
-
|
|
21819
|
+
chalk12.bold(
|
|
21332
21820
|
"Upload AI Blame inference artifacts (prompt + inference) and finalize them."
|
|
21333
21821
|
),
|
|
21334
21822
|
uploadAiBlameBuilder,
|
|
21335
21823
|
uploadAiBlameHandler
|
|
21824
|
+
).command(
|
|
21825
|
+
mobbCliCommand.claudeCodeInstallHook,
|
|
21826
|
+
chalk12.bold("Install Claude Code hooks for data collection."),
|
|
21827
|
+
claudeCodeInstallHookBuilder,
|
|
21828
|
+
claudeCodeInstallHookHandler
|
|
21829
|
+
).command(
|
|
21830
|
+
mobbCliCommand.claudeCodeProcessHook,
|
|
21831
|
+
chalk12.bold("Process Claude Code hook data and upload to backend."),
|
|
21832
|
+
claudeCodeProcessHookBuilder,
|
|
21833
|
+
claudeCodeProcessHookHandler
|
|
21336
21834
|
).example(
|
|
21337
21835
|
"npx mobbdev@latest scan -r https://github.com/WebGoat/WebGoat",
|
|
21338
21836
|
"Scan an existing repository"
|
|
@@ -21341,7 +21839,7 @@ var parseArgs = async (args) => {
|
|
|
21341
21839
|
handler() {
|
|
21342
21840
|
yargsInstance.showHelp();
|
|
21343
21841
|
}
|
|
21344
|
-
}).strictOptions().help("h").alias("h", "help").epilog(
|
|
21842
|
+
}).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
21843
|
};
|
|
21346
21844
|
|
|
21347
21845
|
// src/index.ts
|