mobbdev 1.0.191 → 1.0.193
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/args/commands/upload_ai_blame.mjs +5 -2
- package/dist/index.mjs +366 -21
- package/package.json +1 -1
|
@@ -4123,7 +4123,7 @@ var scmTypeToScmLibScmType = {
|
|
|
4123
4123
|
["Ado" /* Ado */]: "ADO" /* ADO */,
|
|
4124
4124
|
["Bitbucket" /* Bitbucket */]: "BITBUCKET" /* BITBUCKET */
|
|
4125
4125
|
};
|
|
4126
|
-
var
|
|
4126
|
+
var GetReferenceResultZ = z14.object({
|
|
4127
4127
|
date: z14.date().optional(),
|
|
4128
4128
|
sha: z14.string(),
|
|
4129
4129
|
type: z14.nativeEnum(ReferenceType)
|
|
@@ -4744,6 +4744,8 @@ var VulnerabilityReportSchema = z26.object({
|
|
|
4744
4744
|
// GraphQL uses `any` type for timestamp
|
|
4745
4745
|
vendor: z26.string(),
|
|
4746
4746
|
// GraphQL generates as string, not enum
|
|
4747
|
+
projectId: z26.any().optional(),
|
|
4748
|
+
// GraphQL uses `any` type for UUID
|
|
4747
4749
|
project: ProjectSchema,
|
|
4748
4750
|
totalVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema,
|
|
4749
4751
|
notFixableVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema
|
|
@@ -5243,7 +5245,7 @@ var McpGQLClient = class {
|
|
|
5243
5245
|
const reportMetadata = {
|
|
5244
5246
|
id: reportData.id,
|
|
5245
5247
|
organizationId: reportData.vulnerabilityReport?.project?.organizationId,
|
|
5246
|
-
projectId: reportData.vulnerabilityReport?.
|
|
5248
|
+
projectId: reportData.vulnerabilityReport?.projectId
|
|
5247
5249
|
};
|
|
5248
5250
|
const { userFixes = [], fixes = [] } = reportData;
|
|
5249
5251
|
const fixMap = /* @__PURE__ */ new Map();
|
|
@@ -5460,6 +5462,7 @@ var McpGQLClient = class {
|
|
|
5460
5462
|
reportData: latestReport,
|
|
5461
5463
|
limit
|
|
5462
5464
|
});
|
|
5465
|
+
logDebug("[GraphQL] GetReportFixes response parsed", { fixes });
|
|
5463
5466
|
return {
|
|
5464
5467
|
fixes,
|
|
5465
5468
|
totalCount: res.fixReport?.[0]?.filteredFixesCount?.aggregate?.count || 0,
|
package/dist/index.mjs
CHANGED
|
@@ -5793,7 +5793,7 @@ var scmTypeToScmLibScmType = {
|
|
|
5793
5793
|
["Ado" /* Ado */]: "ADO" /* ADO */,
|
|
5794
5794
|
["Bitbucket" /* Bitbucket */]: "BITBUCKET" /* BITBUCKET */
|
|
5795
5795
|
};
|
|
5796
|
-
var
|
|
5796
|
+
var GetReferenceResultZ = z13.object({
|
|
5797
5797
|
date: z13.date().optional(),
|
|
5798
5798
|
sha: z13.string(),
|
|
5799
5799
|
type: z13.nativeEnum(ReferenceType)
|
|
@@ -6764,7 +6764,7 @@ var AdoSCMLib = class extends SCMLib {
|
|
|
6764
6764
|
return String(pullRequestId);
|
|
6765
6765
|
} catch (e) {
|
|
6766
6766
|
console.warn(
|
|
6767
|
-
`error creating pull request for ADO. Try number ${i + 1}`,
|
|
6767
|
+
`error creating pull request for ADO. Try number ${String(i + 1).replace(/\n|\r/g, "")}`,
|
|
6768
6768
|
e
|
|
6769
6769
|
);
|
|
6770
6770
|
await setTimeout2(1e3);
|
|
@@ -6924,6 +6924,12 @@ var AdoSCMLib = class extends SCMLib {
|
|
|
6924
6924
|
async getCommitDiff(_commitSha) {
|
|
6925
6925
|
throw new Error("getCommitDiff not implemented for ADO");
|
|
6926
6926
|
}
|
|
6927
|
+
async getSubmitRequestDiff(_submitRequestId) {
|
|
6928
|
+
throw new Error("getSubmitRequestDiff not implemented for ADO");
|
|
6929
|
+
}
|
|
6930
|
+
async getSubmitRequests(_repoUrl) {
|
|
6931
|
+
throw new Error("getSubmitRequests not implemented for ADO");
|
|
6932
|
+
}
|
|
6927
6933
|
};
|
|
6928
6934
|
|
|
6929
6935
|
// src/features/analysis/scm/bitbucket/bitbucket.ts
|
|
@@ -6969,15 +6975,15 @@ function parseBitbucketOrganizationAndRepo(bitbucketUrl) {
|
|
|
6969
6975
|
repo_slug: validatedBitbucketResult.repoName
|
|
6970
6976
|
};
|
|
6971
6977
|
}
|
|
6972
|
-
function
|
|
6973
|
-
const
|
|
6978
|
+
function getBitbucketInstance(params) {
|
|
6979
|
+
const BitbucketConstructor = bitbucketPkg && "Bitbucket" in bitbucketPkg ? bitbucketPkg.Bitbucket : bitbucketPkgNode.Bitbucket;
|
|
6974
6980
|
switch (params.authType) {
|
|
6975
6981
|
case "public":
|
|
6976
|
-
return new
|
|
6982
|
+
return new BitbucketConstructor();
|
|
6977
6983
|
case "token":
|
|
6978
|
-
return new
|
|
6984
|
+
return new BitbucketConstructor({ auth: { token: params.token } });
|
|
6979
6985
|
case "basic":
|
|
6980
|
-
return new
|
|
6986
|
+
return new BitbucketConstructor({
|
|
6981
6987
|
auth: {
|
|
6982
6988
|
password: params.password,
|
|
6983
6989
|
username: params.username
|
|
@@ -6986,7 +6992,7 @@ function getBitbucketIntance(params) {
|
|
|
6986
6992
|
}
|
|
6987
6993
|
}
|
|
6988
6994
|
function getBitbucketSdk(params) {
|
|
6989
|
-
const bitbucketClient =
|
|
6995
|
+
const bitbucketClient = getBitbucketInstance(params);
|
|
6990
6996
|
return {
|
|
6991
6997
|
getAuthType() {
|
|
6992
6998
|
return params.authType;
|
|
@@ -6994,12 +7000,11 @@ function getBitbucketSdk(params) {
|
|
|
6994
7000
|
async getRepos(params2) {
|
|
6995
7001
|
const repoRes = params2?.workspaceSlug ? await getRepositoriesByWorkspace(bitbucketClient, {
|
|
6996
7002
|
workspaceSlug: params2.workspaceSlug
|
|
6997
|
-
}) : await
|
|
7003
|
+
}) : await getAllUsersRepositories(bitbucketClient);
|
|
6998
7004
|
return repoRes.map((repo) => ({
|
|
6999
7005
|
repoIsPublic: !repo.is_private,
|
|
7000
7006
|
repoName: repo.name || "unknown repo name",
|
|
7001
7007
|
repoOwner: repo.owner?.username || "unknown owner",
|
|
7002
|
-
// language can be empty string
|
|
7003
7008
|
repoLanguages: repo.language ? [repo.language] : [],
|
|
7004
7009
|
repoUpdatedAt: repo.updated_on ? repo.updated_on : (/* @__PURE__ */ new Date()).toISOString(),
|
|
7005
7010
|
repoUrl: repo.links?.html?.href || ""
|
|
@@ -7059,7 +7064,7 @@ function getBitbucketSdk(params) {
|
|
|
7059
7064
|
});
|
|
7060
7065
|
return res.data;
|
|
7061
7066
|
},
|
|
7062
|
-
async
|
|
7067
|
+
async getDownloadLink(params2) {
|
|
7063
7068
|
const { repo_slug, workspace } = parseBitbucketOrganizationAndRepo(
|
|
7064
7069
|
params2.repoUrl
|
|
7065
7070
|
);
|
|
@@ -7131,7 +7136,7 @@ function getBitbucketSdk(params) {
|
|
|
7131
7136
|
workspace,
|
|
7132
7137
|
name: tagName
|
|
7133
7138
|
});
|
|
7134
|
-
return
|
|
7139
|
+
return GetReferenceResultZ.parse({
|
|
7135
7140
|
sha: tagRes.data.target?.hash,
|
|
7136
7141
|
type: "TAG" /* TAG */,
|
|
7137
7142
|
date: new Date(z19.string().parse(tagRes.data.target?.date))
|
|
@@ -7139,7 +7144,7 @@ function getBitbucketSdk(params) {
|
|
|
7139
7144
|
},
|
|
7140
7145
|
async getBranchRef(params2) {
|
|
7141
7146
|
const getBranchRes = await this.getBranch(params2);
|
|
7142
|
-
return
|
|
7147
|
+
return GetReferenceResultZ.parse({
|
|
7143
7148
|
sha: getBranchRes.target?.hash,
|
|
7144
7149
|
type: "BRANCH" /* BRANCH */,
|
|
7145
7150
|
date: new Date(z19.string().parse(getBranchRes.target?.date))
|
|
@@ -7147,7 +7152,7 @@ function getBitbucketSdk(params) {
|
|
|
7147
7152
|
},
|
|
7148
7153
|
async getCommitRef(params2) {
|
|
7149
7154
|
const getCommitRes = await this.getCommit(params2);
|
|
7150
|
-
return
|
|
7155
|
+
return GetReferenceResultZ.parse({
|
|
7151
7156
|
sha: getCommitRes.hash,
|
|
7152
7157
|
type: "COMMIT" /* COMMIT */,
|
|
7153
7158
|
date: new Date(z19.string().parse(getCommitRes.date))
|
|
@@ -7177,7 +7182,7 @@ function getBitbucketSdk(params) {
|
|
|
7177
7182
|
}) {
|
|
7178
7183
|
const { repo_slug, workspace } = parseBitbucketOrganizationAndRepo(url);
|
|
7179
7184
|
const res = await bitbucketClient.pullrequests.createComment({
|
|
7180
|
-
//@ts-expect-error
|
|
7185
|
+
//@ts-expect-error type requires _body.type, but it its uses api fails
|
|
7181
7186
|
_body: {
|
|
7182
7187
|
content: {
|
|
7183
7188
|
raw: markdownComment
|
|
@@ -7219,17 +7224,17 @@ async function validateBitbucketParams(params) {
|
|
|
7219
7224
|
);
|
|
7220
7225
|
}
|
|
7221
7226
|
}
|
|
7222
|
-
async function
|
|
7227
|
+
async function getUsersWorkspacesSlugs(bitbucketClient) {
|
|
7223
7228
|
const res = await bitbucketClient.workspaces.getWorkspaces({});
|
|
7224
7229
|
return res.data.values?.map((v) => z19.string().parse(v.slug));
|
|
7225
7230
|
}
|
|
7226
|
-
async function
|
|
7227
|
-
const
|
|
7228
|
-
if (!
|
|
7231
|
+
async function getAllUsersRepositories(bitbucketClient) {
|
|
7232
|
+
const userWorkspacesSlugs = await getUsersWorkspacesSlugs(bitbucketClient);
|
|
7233
|
+
if (!userWorkspacesSlugs) {
|
|
7229
7234
|
return [];
|
|
7230
7235
|
}
|
|
7231
7236
|
const allWorkspaceRepos = [];
|
|
7232
|
-
for (const workspaceSlug of
|
|
7237
|
+
for (const workspaceSlug of userWorkspacesSlugs) {
|
|
7233
7238
|
const repos = await bitbucketClient.repositories.list({
|
|
7234
7239
|
workspace: workspaceSlug
|
|
7235
7240
|
});
|
|
@@ -7490,6 +7495,12 @@ var BitbucketSCMLib = class extends SCMLib {
|
|
|
7490
7495
|
async getCommitDiff(_commitSha) {
|
|
7491
7496
|
throw new Error("getCommitDiff not implemented for Bitbucket");
|
|
7492
7497
|
}
|
|
7498
|
+
async getSubmitRequestDiff(_submitRequestId) {
|
|
7499
|
+
throw new Error("getSubmitRequestDiff not implemented for Bitbucket");
|
|
7500
|
+
}
|
|
7501
|
+
async getSubmitRequests(_repoUrl) {
|
|
7502
|
+
throw new Error("getSubmitRequests not implemented for Bitbucket");
|
|
7503
|
+
}
|
|
7493
7504
|
};
|
|
7494
7505
|
|
|
7495
7506
|
// src/features/analysis/scm/constants.ts
|
|
@@ -8084,6 +8095,31 @@ function getGithubSdk(params = {}) {
|
|
|
8084
8095
|
},
|
|
8085
8096
|
async getUserInfo() {
|
|
8086
8097
|
return octokit.request(GET_USER);
|
|
8098
|
+
},
|
|
8099
|
+
async getPrCommits(params2) {
|
|
8100
|
+
return octokit.rest.pulls.listCommits({
|
|
8101
|
+
owner: params2.owner,
|
|
8102
|
+
repo: params2.repo,
|
|
8103
|
+
pull_number: params2.pull_number
|
|
8104
|
+
});
|
|
8105
|
+
},
|
|
8106
|
+
async getUserRepos() {
|
|
8107
|
+
return octokit.rest.repos.listForAuthenticatedUser({
|
|
8108
|
+
visibility: "all",
|
|
8109
|
+
affiliation: "owner,collaborator,organization_member",
|
|
8110
|
+
sort: "updated",
|
|
8111
|
+
per_page: 100
|
|
8112
|
+
});
|
|
8113
|
+
},
|
|
8114
|
+
async getRepoPullRequests(params2) {
|
|
8115
|
+
return octokit.rest.pulls.list({
|
|
8116
|
+
owner: params2.owner,
|
|
8117
|
+
repo: params2.repo,
|
|
8118
|
+
state: "all",
|
|
8119
|
+
sort: "updated",
|
|
8120
|
+
direction: "desc",
|
|
8121
|
+
per_page: 100
|
|
8122
|
+
});
|
|
8087
8123
|
}
|
|
8088
8124
|
};
|
|
8089
8125
|
}
|
|
@@ -8362,6 +8398,284 @@ var GithubSCMLib = class extends SCMLib {
|
|
|
8362
8398
|
message: commit.commit.message
|
|
8363
8399
|
};
|
|
8364
8400
|
}
|
|
8401
|
+
async getSubmitRequestDiff(submitRequestId) {
|
|
8402
|
+
this._validateAccessTokenAndUrl();
|
|
8403
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
8404
|
+
const prNumber = Number(submitRequestId);
|
|
8405
|
+
const prRes = await this.githubSdk.getPr({
|
|
8406
|
+
owner,
|
|
8407
|
+
repo,
|
|
8408
|
+
pull_number: prNumber
|
|
8409
|
+
});
|
|
8410
|
+
const prDiff = await this.getPrDiff({ pull_number: prNumber });
|
|
8411
|
+
const commitsRes = await this.githubSdk.getPrCommits({
|
|
8412
|
+
owner,
|
|
8413
|
+
repo,
|
|
8414
|
+
pull_number: prNumber
|
|
8415
|
+
});
|
|
8416
|
+
const commits = [];
|
|
8417
|
+
for (const commit of commitsRes.data) {
|
|
8418
|
+
const commitDiff = await this.getCommitDiff(commit.sha);
|
|
8419
|
+
commits.push(commitDiff);
|
|
8420
|
+
}
|
|
8421
|
+
const pr = prRes.data;
|
|
8422
|
+
const diffLines = this._calculateDiffLineAttributions(prDiff, commits);
|
|
8423
|
+
return {
|
|
8424
|
+
diff: prDiff,
|
|
8425
|
+
createdAt: new Date(pr.created_at),
|
|
8426
|
+
updatedAt: new Date(pr.updated_at),
|
|
8427
|
+
submitRequestId,
|
|
8428
|
+
submitRequestNumber: prNumber,
|
|
8429
|
+
sourceBranch: pr.head.ref,
|
|
8430
|
+
targetBranch: pr.base.ref,
|
|
8431
|
+
authorName: pr.user?.name || pr.user?.login,
|
|
8432
|
+
authorEmail: pr.user?.email || void 0,
|
|
8433
|
+
title: pr.title,
|
|
8434
|
+
description: pr.body || void 0,
|
|
8435
|
+
commits,
|
|
8436
|
+
diffLines
|
|
8437
|
+
};
|
|
8438
|
+
}
|
|
8439
|
+
async getSubmitRequests(repoUrl) {
|
|
8440
|
+
this._validateAccessToken();
|
|
8441
|
+
const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
|
|
8442
|
+
const pullsRes = await this.githubSdk.getRepoPullRequests({ owner, repo });
|
|
8443
|
+
const submitRequests = await Promise.all(
|
|
8444
|
+
pullsRes.data.map(async (pr) => {
|
|
8445
|
+
let status = "open";
|
|
8446
|
+
if (pr.state === "closed") {
|
|
8447
|
+
status = pr.merged_at ? "merged" : "closed";
|
|
8448
|
+
} else if (pr.draft) {
|
|
8449
|
+
status = "draft";
|
|
8450
|
+
}
|
|
8451
|
+
const [tickets, changedLines] = await Promise.all([
|
|
8452
|
+
this._extractLinearTicketsFromPR(owner, repo, pr.number),
|
|
8453
|
+
this._calculateChangedLinesFromPR(owner, repo, pr.number)
|
|
8454
|
+
]);
|
|
8455
|
+
return {
|
|
8456
|
+
submitRequestId: String(pr.number),
|
|
8457
|
+
submitRequestNumber: pr.number,
|
|
8458
|
+
title: pr.title,
|
|
8459
|
+
status,
|
|
8460
|
+
sourceBranch: pr.head.ref,
|
|
8461
|
+
targetBranch: pr.base.ref,
|
|
8462
|
+
authorName: pr.user?.name || pr.user?.login,
|
|
8463
|
+
authorEmail: pr.user?.email || void 0,
|
|
8464
|
+
createdAt: new Date(pr.created_at),
|
|
8465
|
+
updatedAt: new Date(pr.updated_at),
|
|
8466
|
+
description: pr.body || void 0,
|
|
8467
|
+
tickets,
|
|
8468
|
+
changedLines
|
|
8469
|
+
};
|
|
8470
|
+
})
|
|
8471
|
+
);
|
|
8472
|
+
return submitRequests;
|
|
8473
|
+
}
|
|
8474
|
+
async _extractLinearTicketsFromPR(owner, repo, prNumber) {
|
|
8475
|
+
try {
|
|
8476
|
+
const commentsRes = await this.githubSdk.getGeneralPrComments({
|
|
8477
|
+
owner,
|
|
8478
|
+
repo,
|
|
8479
|
+
issue_number: prNumber
|
|
8480
|
+
});
|
|
8481
|
+
const tickets = [];
|
|
8482
|
+
for (const comment of commentsRes.data) {
|
|
8483
|
+
if (comment.user?.login === "linear[bot]" || comment.user?.type === "Bot") {
|
|
8484
|
+
const htmlLinkPattern = /<a href="(https:\/\/linear\.app\/[^"]+)">([A-Z]+-\d+)<\/a>/g;
|
|
8485
|
+
let match;
|
|
8486
|
+
while ((match = htmlLinkPattern.exec(comment.body || "")) !== null) {
|
|
8487
|
+
const url = match[1];
|
|
8488
|
+
const name = match[2];
|
|
8489
|
+
if (!name || !url) {
|
|
8490
|
+
continue;
|
|
8491
|
+
}
|
|
8492
|
+
const urlParts = url.split("/");
|
|
8493
|
+
const titleSlug = urlParts[urlParts.length - 1] || "";
|
|
8494
|
+
const title = titleSlug.replace(/-/g, " ");
|
|
8495
|
+
tickets.push({ name, title, url });
|
|
8496
|
+
}
|
|
8497
|
+
const markdownLinkPattern = /\[([A-Z]+-\d+)\]\((https:\/\/linear\.app\/[^)]+)\)/g;
|
|
8498
|
+
while ((match = markdownLinkPattern.exec(comment.body || "")) !== null) {
|
|
8499
|
+
const name = match[1];
|
|
8500
|
+
const url = match[2];
|
|
8501
|
+
if (tickets.some((t) => t.name === name && t.url === url)) {
|
|
8502
|
+
continue;
|
|
8503
|
+
}
|
|
8504
|
+
if (!name || !url) {
|
|
8505
|
+
continue;
|
|
8506
|
+
}
|
|
8507
|
+
const urlParts = url.split("/");
|
|
8508
|
+
const titleSlug = urlParts[urlParts.length - 1] || "";
|
|
8509
|
+
const title = titleSlug.replace(/-/g, " ");
|
|
8510
|
+
tickets.push({ name, title, url });
|
|
8511
|
+
}
|
|
8512
|
+
}
|
|
8513
|
+
}
|
|
8514
|
+
return tickets;
|
|
8515
|
+
} catch (error) {
|
|
8516
|
+
return [];
|
|
8517
|
+
}
|
|
8518
|
+
}
|
|
8519
|
+
async _calculateChangedLinesFromPR(owner, repo, prNumber) {
|
|
8520
|
+
try {
|
|
8521
|
+
const diffRes = await this.githubSdk.getPrDiff({
|
|
8522
|
+
owner,
|
|
8523
|
+
repo,
|
|
8524
|
+
pull_number: prNumber
|
|
8525
|
+
});
|
|
8526
|
+
const diff = z21.string().parse(diffRes.data);
|
|
8527
|
+
let added = 0;
|
|
8528
|
+
let removed = 0;
|
|
8529
|
+
const lines = diff.split("\n");
|
|
8530
|
+
for (const line of lines) {
|
|
8531
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
8532
|
+
added++;
|
|
8533
|
+
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
8534
|
+
removed++;
|
|
8535
|
+
}
|
|
8536
|
+
}
|
|
8537
|
+
return { added, removed };
|
|
8538
|
+
} catch (error) {
|
|
8539
|
+
return { added: 0, removed: 0 };
|
|
8540
|
+
}
|
|
8541
|
+
}
|
|
8542
|
+
_calculateDiffLineAttributions(prDiff, commits) {
|
|
8543
|
+
const attributions = [];
|
|
8544
|
+
const prDiffLines = prDiff.split("\n");
|
|
8545
|
+
let currentFile = "";
|
|
8546
|
+
let currentLineNumber = 0;
|
|
8547
|
+
for (const line of prDiffLines) {
|
|
8548
|
+
if (line.startsWith("+++")) {
|
|
8549
|
+
const match = line.match(/^\+\+\+ b\/(.+)$/);
|
|
8550
|
+
currentFile = match?.[1] || "";
|
|
8551
|
+
currentLineNumber = 0;
|
|
8552
|
+
continue;
|
|
8553
|
+
}
|
|
8554
|
+
if (line.startsWith("@@")) {
|
|
8555
|
+
const match = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)/);
|
|
8556
|
+
if (match?.[1]) {
|
|
8557
|
+
currentLineNumber = parseInt(match[1], 10);
|
|
8558
|
+
}
|
|
8559
|
+
continue;
|
|
8560
|
+
}
|
|
8561
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
8562
|
+
const commitSha = this._findCommitForLine(
|
|
8563
|
+
currentFile,
|
|
8564
|
+
currentLineNumber,
|
|
8565
|
+
line.substring(1),
|
|
8566
|
+
// Remove the '+' prefix
|
|
8567
|
+
commits
|
|
8568
|
+
);
|
|
8569
|
+
if (commitSha && currentFile) {
|
|
8570
|
+
attributions.push({
|
|
8571
|
+
file: currentFile,
|
|
8572
|
+
line: currentLineNumber,
|
|
8573
|
+
commitSha
|
|
8574
|
+
});
|
|
8575
|
+
}
|
|
8576
|
+
currentLineNumber++;
|
|
8577
|
+
} else if (!line.startsWith("-")) {
|
|
8578
|
+
currentLineNumber++;
|
|
8579
|
+
}
|
|
8580
|
+
}
|
|
8581
|
+
return attributions;
|
|
8582
|
+
}
|
|
8583
|
+
_findCommitForLine(file, lineNumber, lineContent, commits) {
|
|
8584
|
+
const normalizedContent = lineContent.trim();
|
|
8585
|
+
for (let i = commits.length - 1; i >= 0; i--) {
|
|
8586
|
+
const commit = commits[i];
|
|
8587
|
+
if (!commit) {
|
|
8588
|
+
continue;
|
|
8589
|
+
}
|
|
8590
|
+
const commitLines = commit.diff.split("\n");
|
|
8591
|
+
let commitCurrentFile = "";
|
|
8592
|
+
for (const commitLine of commitLines) {
|
|
8593
|
+
if (commitLine.startsWith("+++")) {
|
|
8594
|
+
const match = commitLine.match(/^\+\+\+ b\/(.+)$/);
|
|
8595
|
+
commitCurrentFile = match?.[1] || "";
|
|
8596
|
+
continue;
|
|
8597
|
+
}
|
|
8598
|
+
if (commitLine.startsWith("@@")) {
|
|
8599
|
+
continue;
|
|
8600
|
+
}
|
|
8601
|
+
if (commitCurrentFile === file && commitLine.startsWith("+") && !commitLine.startsWith("+++")) {
|
|
8602
|
+
const commitLineContent = commitLine.substring(1).trim();
|
|
8603
|
+
if (commitLineContent === normalizedContent) {
|
|
8604
|
+
return commit.commitSha;
|
|
8605
|
+
}
|
|
8606
|
+
}
|
|
8607
|
+
}
|
|
8608
|
+
}
|
|
8609
|
+
for (let i = commits.length - 1; i >= 0; i--) {
|
|
8610
|
+
const commit = commits[i];
|
|
8611
|
+
if (!commit) {
|
|
8612
|
+
continue;
|
|
8613
|
+
}
|
|
8614
|
+
const addedLinesInFile = this._getAddedLinesFromCommit(commit, file);
|
|
8615
|
+
for (const { lineNum, content } of addedLinesInFile) {
|
|
8616
|
+
if (Math.abs(lineNum - lineNumber) <= 10 && this._contentSimilarity(content, normalizedContent) > 0.9) {
|
|
8617
|
+
return commit.commitSha;
|
|
8618
|
+
}
|
|
8619
|
+
}
|
|
8620
|
+
}
|
|
8621
|
+
const lastCommit = commits[commits.length - 1];
|
|
8622
|
+
return lastCommit ? lastCommit.commitSha : null;
|
|
8623
|
+
}
|
|
8624
|
+
_getAddedLinesFromCommit(commit, targetFile) {
|
|
8625
|
+
const addedLines = [];
|
|
8626
|
+
const commitLines = commit.diff.split("\n");
|
|
8627
|
+
let currentFile = "";
|
|
8628
|
+
let currentLineNumber = 0;
|
|
8629
|
+
for (const line of commitLines) {
|
|
8630
|
+
if (line.startsWith("+++")) {
|
|
8631
|
+
const match = line.match(/^\+\+\+ b\/(.+)$/);
|
|
8632
|
+
currentFile = match?.[1] || "";
|
|
8633
|
+
currentLineNumber = 0;
|
|
8634
|
+
continue;
|
|
8635
|
+
}
|
|
8636
|
+
if (line.startsWith("@@")) {
|
|
8637
|
+
const match = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)/);
|
|
8638
|
+
if (match?.[1]) {
|
|
8639
|
+
currentLineNumber = parseInt(match[1], 10);
|
|
8640
|
+
}
|
|
8641
|
+
continue;
|
|
8642
|
+
}
|
|
8643
|
+
if (currentFile === targetFile && line.startsWith("+") && !line.startsWith("+++")) {
|
|
8644
|
+
addedLines.push({
|
|
8645
|
+
lineNum: currentLineNumber,
|
|
8646
|
+
content: line.substring(1).trim()
|
|
8647
|
+
});
|
|
8648
|
+
currentLineNumber++;
|
|
8649
|
+
} else if (!line.startsWith("-")) {
|
|
8650
|
+
if (currentFile === targetFile) {
|
|
8651
|
+
currentLineNumber++;
|
|
8652
|
+
}
|
|
8653
|
+
}
|
|
8654
|
+
}
|
|
8655
|
+
return addedLines;
|
|
8656
|
+
}
|
|
8657
|
+
_contentSimilarity(content1, content2) {
|
|
8658
|
+
if (content1 === content2) {
|
|
8659
|
+
return 1;
|
|
8660
|
+
}
|
|
8661
|
+
const normalized1 = content1.replace(/\s+/g, " ");
|
|
8662
|
+
const normalized2 = content2.replace(/\s+/g, " ");
|
|
8663
|
+
if (normalized1 === normalized2) {
|
|
8664
|
+
return 0.95;
|
|
8665
|
+
}
|
|
8666
|
+
const longer = normalized1.length > normalized2.length ? normalized1 : normalized2;
|
|
8667
|
+
const shorter = normalized1.length > normalized2.length ? normalized2 : normalized1;
|
|
8668
|
+
if (longer.length === 0) {
|
|
8669
|
+
return 1;
|
|
8670
|
+
}
|
|
8671
|
+
if (longer.includes(shorter)) {
|
|
8672
|
+
return shorter.length / longer.length;
|
|
8673
|
+
}
|
|
8674
|
+
const set1 = new Set(normalized1.split(""));
|
|
8675
|
+
const set2 = new Set(normalized2.split(""));
|
|
8676
|
+
const intersection = new Set([...set1].filter((x) => set2.has(x)));
|
|
8677
|
+
return intersection.size / Math.max(set1.size, set2.size);
|
|
8678
|
+
}
|
|
8365
8679
|
};
|
|
8366
8680
|
|
|
8367
8681
|
// src/features/analysis/scm/gitlab/gitlab.ts
|
|
@@ -8930,6 +9244,12 @@ var GitlabSCMLib = class extends SCMLib {
|
|
|
8930
9244
|
async getCommitDiff(_commitSha) {
|
|
8931
9245
|
throw new Error("getCommitDiff not implemented for GitLab");
|
|
8932
9246
|
}
|
|
9247
|
+
async getSubmitRequestDiff(_submitRequestId) {
|
|
9248
|
+
throw new Error("getSubmitRequestDiff not implemented for GitLab");
|
|
9249
|
+
}
|
|
9250
|
+
async getSubmitRequests(_repoUrl) {
|
|
9251
|
+
throw new Error("getSubmitRequests not implemented for GitLab");
|
|
9252
|
+
}
|
|
8933
9253
|
};
|
|
8934
9254
|
|
|
8935
9255
|
// src/features/analysis/scm/scmFactory.ts
|
|
@@ -9037,6 +9357,28 @@ var StubSCMLib = class extends SCMLib {
|
|
|
9037
9357
|
message: void 0
|
|
9038
9358
|
};
|
|
9039
9359
|
}
|
|
9360
|
+
async getSubmitRequestDiff(_submitRequestId) {
|
|
9361
|
+
console.warn("getSubmitRequestDiff() returning stub diff");
|
|
9362
|
+
return {
|
|
9363
|
+
diff: "",
|
|
9364
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
9365
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
9366
|
+
submitRequestId: _submitRequestId,
|
|
9367
|
+
submitRequestNumber: parseInt(_submitRequestId) || 0,
|
|
9368
|
+
sourceBranch: "",
|
|
9369
|
+
targetBranch: "",
|
|
9370
|
+
authorName: void 0,
|
|
9371
|
+
authorEmail: void 0,
|
|
9372
|
+
title: void 0,
|
|
9373
|
+
description: void 0,
|
|
9374
|
+
commits: [],
|
|
9375
|
+
diffLines: []
|
|
9376
|
+
};
|
|
9377
|
+
}
|
|
9378
|
+
async getSubmitRequests(_repoUrl) {
|
|
9379
|
+
console.warn("getSubmitRequests() returning empty array");
|
|
9380
|
+
return [];
|
|
9381
|
+
}
|
|
9040
9382
|
};
|
|
9041
9383
|
|
|
9042
9384
|
// src/features/analysis/scm/scmFactory.ts
|
|
@@ -12637,6 +12979,8 @@ var VulnerabilityReportSchema = z31.object({
|
|
|
12637
12979
|
// GraphQL uses `any` type for timestamp
|
|
12638
12980
|
vendor: z31.string(),
|
|
12639
12981
|
// GraphQL generates as string, not enum
|
|
12982
|
+
projectId: z31.any().optional(),
|
|
12983
|
+
// GraphQL uses `any` type for UUID
|
|
12640
12984
|
project: ProjectSchema,
|
|
12641
12985
|
totalVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema,
|
|
12642
12986
|
notFixableVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema
|
|
@@ -13136,7 +13480,7 @@ var McpGQLClient = class {
|
|
|
13136
13480
|
const reportMetadata = {
|
|
13137
13481
|
id: reportData.id,
|
|
13138
13482
|
organizationId: reportData.vulnerabilityReport?.project?.organizationId,
|
|
13139
|
-
projectId: reportData.vulnerabilityReport?.
|
|
13483
|
+
projectId: reportData.vulnerabilityReport?.projectId
|
|
13140
13484
|
};
|
|
13141
13485
|
const { userFixes = [], fixes = [] } = reportData;
|
|
13142
13486
|
const fixMap = /* @__PURE__ */ new Map();
|
|
@@ -13353,6 +13697,7 @@ var McpGQLClient = class {
|
|
|
13353
13697
|
reportData: latestReport,
|
|
13354
13698
|
limit
|
|
13355
13699
|
});
|
|
13700
|
+
logDebug("[GraphQL] GetReportFixes response parsed", { fixes });
|
|
13356
13701
|
return {
|
|
13357
13702
|
fixes,
|
|
13358
13703
|
totalCount: res.fixReport?.[0]?.filteredFixesCount?.aggregate?.count || 0,
|