mobbdev 1.2.50 → 1.2.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -4170,6 +4170,9 @@ import multimatch from "multimatch";
4170
4170
  import StreamZip from "node-stream-zip";
4171
4171
  import tmp from "tmp";
4172
4172
 
4173
+ // src/features/analysis/scm/ado/ado.ts
4174
+ import pLimit from "p-limit";
4175
+
4173
4176
  // src/features/analysis/scm/errors.ts
4174
4177
  var InvalidAccessTokenError = class extends Error {
4175
4178
  constructor(m, scmType) {
@@ -7043,7 +7046,7 @@ async function getAdoSdk(params) {
7043
7046
  const url = new URL(repoUrl);
7044
7047
  const origin2 = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
7045
7048
  const params2 = `path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
7046
- const path26 = [
7049
+ const path27 = [
7047
7050
  prefixPath,
7048
7051
  owner,
7049
7052
  projectName,
@@ -7054,7 +7057,7 @@ async function getAdoSdk(params) {
7054
7057
  "items",
7055
7058
  "items"
7056
7059
  ].filter(Boolean).join("/");
7057
- return new URL(`${path26}?${params2}`, origin2).toString();
7060
+ return new URL(`${path27}?${params2}`, origin2).toString();
7058
7061
  },
7059
7062
  async getAdoBranchList({ repoUrl }) {
7060
7063
  try {
@@ -7094,6 +7097,136 @@ async function getAdoSdk(params) {
7094
7097
  );
7095
7098
  return res.pullRequestId;
7096
7099
  },
7100
+ async getAdoPullRequestMetadata({
7101
+ repoUrl,
7102
+ prNumber
7103
+ }) {
7104
+ const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
7105
+ const git = await api2.getGitApi();
7106
+ const pr = await git.getPullRequest(repo, prNumber, projectName);
7107
+ if (!pr) {
7108
+ throw new Error(`Pull request #${prNumber} not found`);
7109
+ }
7110
+ return {
7111
+ title: pr.title,
7112
+ targetBranch: (pr.targetRefName || "").replace("refs/heads/", ""),
7113
+ sourceBranch: (pr.sourceRefName || "").replace("refs/heads/", ""),
7114
+ headCommitSha: pr.lastMergeSourceCommit?.commitId || pr.lastMergeCommit?.commitId || ""
7115
+ };
7116
+ },
7117
+ async getAdoPrFiles({
7118
+ repoUrl,
7119
+ prNumber
7120
+ }) {
7121
+ const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
7122
+ const git = await api2.getGitApi();
7123
+ const iterations = await git.getPullRequestIterations(
7124
+ repo,
7125
+ prNumber,
7126
+ projectName
7127
+ );
7128
+ if (!iterations || iterations.length === 0) {
7129
+ return [];
7130
+ }
7131
+ const lastIteration = iterations[iterations.length - 1];
7132
+ if (!lastIteration?.id) {
7133
+ return [];
7134
+ }
7135
+ const iterationId = lastIteration.id;
7136
+ const changes = await git.getPullRequestIterationChanges(
7137
+ repo,
7138
+ prNumber,
7139
+ iterationId,
7140
+ projectName
7141
+ );
7142
+ if (!changes?.changeEntries) {
7143
+ return [];
7144
+ }
7145
+ return changes.changeEntries.filter((entry) => {
7146
+ const changeType = entry.changeType;
7147
+ return changeType !== 16 && entry.item?.path;
7148
+ }).map((entry) => {
7149
+ const path27 = entry.item.path;
7150
+ return path27.startsWith("/") ? path27.slice(1) : path27;
7151
+ });
7152
+ },
7153
+ async searchAdoPullRequests({
7154
+ repoUrl,
7155
+ status,
7156
+ skip,
7157
+ top
7158
+ }) {
7159
+ const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
7160
+ const git = await api2.getGitApi();
7161
+ const searchCriteria = {
7162
+ // Cast to number to avoid TypeScript enum compatibility issues between
7163
+ // our AdoPullRequestStatus and azure-devops-node-api's PullRequestStatus
7164
+ status: status ?? 4 /* All */
7165
+ };
7166
+ const prs = await git.getPullRequests(
7167
+ repo,
7168
+ searchCriteria,
7169
+ projectName,
7170
+ void 0,
7171
+ // maxCommentLength
7172
+ skip,
7173
+ top
7174
+ );
7175
+ return prs;
7176
+ },
7177
+ async getAdoPullRequestMetrics({
7178
+ repoUrl,
7179
+ prNumber
7180
+ }) {
7181
+ const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
7182
+ const git = await api2.getGitApi();
7183
+ const pr = await git.getPullRequest(repo, prNumber, projectName);
7184
+ if (!pr) {
7185
+ throw new Error(`Pull request #${prNumber} not found`);
7186
+ }
7187
+ const threads = await git.getThreads(repo, prNumber, projectName);
7188
+ const commentIds = (threads || []).filter((t) => t.id && t.comments && t.comments.length > 0).map((t) => String(t.id));
7189
+ return {
7190
+ pr,
7191
+ commentIds,
7192
+ linesAdded: 0
7193
+ };
7194
+ },
7195
+ async getAdoRecentCommits({
7196
+ repoUrl,
7197
+ since
7198
+ }) {
7199
+ const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
7200
+ const git = await api2.getGitApi();
7201
+ const repository = await git.getRepository(
7202
+ decodeURI(repo),
7203
+ projectName ? decodeURI(projectName) : void 0
7204
+ );
7205
+ const defaultBranch = repository.defaultBranch?.replace("refs/heads/", "");
7206
+ const commits = await git.getCommits(
7207
+ repo,
7208
+ {
7209
+ fromDate: since,
7210
+ itemVersion: defaultBranch ? { version: defaultBranch } : void 0,
7211
+ $top: 100
7212
+ },
7213
+ projectName
7214
+ );
7215
+ return commits;
7216
+ },
7217
+ async getAdoPrCommits({
7218
+ repoUrl,
7219
+ prNumber
7220
+ }) {
7221
+ const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
7222
+ const git = await api2.getGitApi();
7223
+ const commits = await git.getPullRequestCommits(
7224
+ repo,
7225
+ prNumber,
7226
+ projectName
7227
+ );
7228
+ return (commits || []).filter((c) => c.commitId).map((c) => c.commitId);
7229
+ },
7097
7230
  async getAdoRepoDefaultBranch({
7098
7231
  repoUrl
7099
7232
  }) {
@@ -7232,28 +7365,38 @@ async function getAdoRepoList({
7232
7365
  });
7233
7366
  const gitOrg = await orgApi.getGitApi();
7234
7367
  const orgRepos = await gitOrg.getRepositories();
7368
+ const repoLimit = pLimit(5);
7235
7369
  const repoInfoList = (await Promise.allSettled(
7236
- orgRepos.map(async (repo) => {
7237
- if (!repo.name || !repo.remoteUrl || !repo.defaultBranch) {
7238
- throw new InvalidRepoUrlError("bad repo");
7239
- }
7240
- const branch = await gitOrg.getBranch(
7241
- repo.name,
7242
- repo.defaultBranch.replace(/^refs\/heads\//, ""),
7243
- repo.project?.name
7244
- );
7245
- return {
7246
- repoName: repo.name,
7247
- repoUrl: repo.remoteUrl.replace(
7248
- /^[hH][tT][tT][pP][sS]:\/\/[^/]+@/,
7249
- "https://"
7250
- ),
7251
- repoOwner: org,
7252
- repoIsPublic: repo.project?.visibility === 2 /* Public */,
7253
- repoLanguages: [],
7254
- repoUpdatedAt: branch.commit?.committer?.date?.toDateString() || repo.project?.lastUpdateTime?.toDateString() || (/* @__PURE__ */ new Date()).toDateString()
7255
- };
7256
- })
7370
+ orgRepos.map(
7371
+ (repo) => repoLimit(async () => {
7372
+ if (!repo.name || !repo.remoteUrl || !repo.defaultBranch) {
7373
+ throw new InvalidRepoUrlError("bad repo");
7374
+ }
7375
+ const branch = await gitOrg.getBranch(
7376
+ repo.name,
7377
+ repo.defaultBranch.replace(/^refs\/heads\//, ""),
7378
+ repo.project?.name
7379
+ );
7380
+ return {
7381
+ repoName: repo.name,
7382
+ repoUrl: repo.remoteUrl.replace(
7383
+ /^[hH][tT][tT][pP][sS]:\/\/[^/]+@/,
7384
+ "https://"
7385
+ ),
7386
+ repoOwner: org,
7387
+ repoIsPublic: repo.project?.visibility === 2 /* Public */,
7388
+ repoLanguages: [],
7389
+ repoUpdatedAt: (
7390
+ // Use the latest available timestamp.
7391
+ // branch.commit.committer.date = last commit on default branch.
7392
+ // project.lastUpdateTime = last project-level change (may be stale).
7393
+ // ADO doesn't expose a per-repo "last pushed" date like GitHub does,
7394
+ // so feature branch pushes won't be reflected until merged.
7395
+ branch.commit?.committer?.date?.toISOString() || repo.project?.lastUpdateTime?.toISOString() || (/* @__PURE__ */ new Date()).toISOString()
7396
+ )
7397
+ };
7398
+ })
7399
+ )
7257
7400
  )).reduce((acc, res) => {
7258
7401
  if (res.status === "fulfilled") {
7259
7402
  acc.push(res.value);
@@ -7273,6 +7416,8 @@ async function getAdoRepoList({
7273
7416
 
7274
7417
  // src/features/analysis/scm/ado/AdoSCMLib.ts
7275
7418
  import { setTimeout as setTimeout2 } from "timers/promises";
7419
+ import pLimit2 from "p-limit";
7420
+ init_client_generates();
7276
7421
 
7277
7422
  // src/features/analysis/scm/scmSubmit/index.ts
7278
7423
  init_GitService();
@@ -7407,6 +7552,19 @@ var SCMLib = class {
7407
7552
  }
7408
7553
  };
7409
7554
 
7555
+ // src/features/analysis/scm/utils/cursorValidation.ts
7556
+ var MAX_CURSOR_VALUE = 1e5;
7557
+ function parseCursorSafe(cursor, defaultValue = 0, maxValue = MAX_CURSOR_VALUE) {
7558
+ if (cursor === null || cursor === void 0 || cursor === "") {
7559
+ return defaultValue;
7560
+ }
7561
+ const parsed = parseInt(cursor, 10);
7562
+ if (isNaN(parsed) || parsed < 0 || parsed > maxValue) {
7563
+ return defaultValue;
7564
+ }
7565
+ return parsed;
7566
+ }
7567
+
7410
7568
  // src/features/analysis/scm/ado/AdoSCMLib.ts
7411
7569
  async function initAdoSdk(params) {
7412
7570
  const { url, accessToken, scmOrg } = params;
@@ -7599,28 +7757,190 @@ var AdoSCMLib = class extends SCMLib {
7599
7757
  markdownComment: comment
7600
7758
  });
7601
7759
  }
7602
- async getSubmitRequestMetadata(_submitRequestId) {
7603
- throw new Error("getSubmitRequestMetadata not implemented for ADO");
7760
+ async getSubmitRequestMetadata(submitRequestId) {
7761
+ this._validateAccessTokenAndUrl();
7762
+ const adoSdk = await this.getAdoSdk();
7763
+ return adoSdk.getAdoPullRequestMetadata({
7764
+ repoUrl: this.url,
7765
+ prNumber: Number(submitRequestId)
7766
+ });
7604
7767
  }
7605
- async getPrFiles(_prNumber) {
7606
- throw new Error("getPrFiles not implemented for ADO");
7768
+ async getPrFiles(prNumber) {
7769
+ this._validateAccessTokenAndUrl();
7770
+ const adoSdk = await this.getAdoSdk();
7771
+ return adoSdk.getAdoPrFiles({
7772
+ repoUrl: this.url,
7773
+ prNumber
7774
+ });
7607
7775
  }
7608
- async searchSubmitRequests(_params) {
7609
- throw new Error("searchSubmitRequests not implemented for ADO");
7776
+ async searchSubmitRequests(params) {
7777
+ this._validateAccessToken();
7778
+ const adoSdk = await this.getAdoSdk();
7779
+ const skip = parseCursorSafe(params.cursor, 0);
7780
+ const top = params.limit || 10;
7781
+ let status = 4 /* All */;
7782
+ if (params.filters?.state === "open") {
7783
+ status = 1 /* Active */;
7784
+ } else if (params.filters?.state === "closed") {
7785
+ status = 4 /* All */;
7786
+ }
7787
+ const prs = await adoSdk.searchAdoPullRequests({
7788
+ repoUrl: params.repoUrl,
7789
+ status,
7790
+ skip,
7791
+ top: top + 1
7792
+ // Fetch one extra to determine hasMore
7793
+ });
7794
+ const apiHasMore = prs.length > top;
7795
+ const prsPage = prs.slice(0, top);
7796
+ const getAdoPrUpdatedDate = (pr) => pr.closedDate || pr.lastMergeSourceCommit?.committer?.date || pr.creationDate || /* @__PURE__ */ new Date();
7797
+ let filtered = prsPage;
7798
+ if (params.filters?.updatedAfter) {
7799
+ const afterDate = params.filters.updatedAfter;
7800
+ filtered = prsPage.filter((pr) => getAdoPrUpdatedDate(pr) > afterDate);
7801
+ }
7802
+ if (params.filters?.state === "closed") {
7803
+ filtered = filtered.filter(
7804
+ (pr) => pr.status === 3 /* Completed */ || pr.status === 2 /* Abandoned */
7805
+ );
7806
+ }
7807
+ const results = filtered.map((pr) => {
7808
+ let prStatus = "open";
7809
+ if (pr.status === 3 /* Completed */) {
7810
+ prStatus = "merged";
7811
+ } else if (pr.status === 2 /* Abandoned */) {
7812
+ prStatus = "closed";
7813
+ }
7814
+ return {
7815
+ submitRequestId: String(pr.pullRequestId),
7816
+ submitRequestNumber: pr.pullRequestId || 0,
7817
+ title: pr.title || "",
7818
+ status: prStatus,
7819
+ sourceBranch: (pr.sourceRefName || "").replace("refs/heads/", ""),
7820
+ targetBranch: (pr.targetRefName || "").replace("refs/heads/", ""),
7821
+ authorName: pr.createdBy?.displayName,
7822
+ authorEmail: pr.createdBy?.uniqueName,
7823
+ createdAt: pr.creationDate || /* @__PURE__ */ new Date(),
7824
+ updatedAt: getAdoPrUpdatedDate(pr),
7825
+ description: pr.description,
7826
+ tickets: [],
7827
+ changedLines: { added: 0, removed: 0 }
7828
+ };
7829
+ });
7830
+ return {
7831
+ results,
7832
+ nextCursor: apiHasMore ? String(skip + top) : void 0,
7833
+ hasMore: apiHasMore
7834
+ };
7610
7835
  }
7611
- async searchRepos(_params) {
7612
- throw new Error("searchRepos not implemented for ADO");
7836
+ // TODO: Performance — this fetches ALL repositories on every call, then paginates
7837
+ // in-memory. For orgs with thousands of repos this can be slow and wasteful,
7838
+ // especially when the UI pages through results (each page triggers a full re-fetch).
7839
+ // Consider caching the fetched list with a short TTL, or using ADO's
7840
+ // getRepositoriesPaged() API per-project for true server-side pagination.
7841
+ async searchRepos(params) {
7842
+ this._validateAccessToken();
7843
+ if (this.url && new URL(this.url).origin !== scmCloudUrl.Ado) {
7844
+ throw new Error(
7845
+ `Oauth token is not supported for ADO on prem - ${this.url}`
7846
+ );
7847
+ }
7848
+ const allRepos = await getAdoRepoList({
7849
+ orgName: params.scmOrg,
7850
+ accessToken: this.accessToken,
7851
+ tokenOrg: this.scmOrg
7852
+ });
7853
+ allRepos.sort((a, b) => {
7854
+ const dateA = a.repoUpdatedAt ? new Date(a.repoUpdatedAt).getTime() : 0;
7855
+ const dateB = b.repoUpdatedAt ? new Date(b.repoUpdatedAt).getTime() : 0;
7856
+ return dateB - dateA;
7857
+ });
7858
+ const page = parseCursorSafe(params.cursor, 0);
7859
+ const limit = params.limit || 100;
7860
+ const start = page;
7861
+ const pageResults = allRepos.slice(start, start + limit);
7862
+ const hasMore = start + limit < allRepos.length;
7863
+ return {
7864
+ results: pageResults,
7865
+ nextCursor: hasMore ? String(start + limit) : void 0,
7866
+ hasMore
7867
+ };
7613
7868
  }
7614
- // TODO: Add comprehensive tests for getPullRequestMetrics (ADO)
7615
- // See clients/cli/src/features/analysis/scm/__tests__/github.test.ts:589-648 for reference
7616
- async getPullRequestMetrics(_prNumber) {
7617
- throw new Error("getPullRequestMetrics not implemented for ADO");
7869
+ async getPrCommitsBatch(repoUrl, prNumbers) {
7870
+ this._validateAccessToken();
7871
+ const adoSdk = await this.getAdoSdk();
7872
+ const result = /* @__PURE__ */ new Map();
7873
+ const limit = pLimit2(5);
7874
+ await Promise.all(
7875
+ prNumbers.map(
7876
+ (prNumber) => limit(async () => {
7877
+ try {
7878
+ const commits = await adoSdk.getAdoPrCommits({
7879
+ repoUrl,
7880
+ prNumber
7881
+ });
7882
+ result.set(prNumber, commits);
7883
+ } catch (error) {
7884
+ console.warn(
7885
+ `[AdoSCMLib.getPrCommitsBatch] Failed to fetch commits for PR #${prNumber}:`,
7886
+ error instanceof Error ? error.message : String(error)
7887
+ );
7888
+ result.set(prNumber, []);
7889
+ }
7890
+ })
7891
+ )
7892
+ );
7893
+ return result;
7618
7894
  }
7619
- async getRecentCommits(_since) {
7620
- throw new Error("getRecentCommits not implemented for ADO");
7895
+ async getPullRequestMetrics(prNumber) {
7896
+ this._validateAccessTokenAndUrl();
7897
+ const adoSdk = await this.getAdoSdk();
7898
+ const { pr, commentIds, linesAdded } = await adoSdk.getAdoPullRequestMetrics({
7899
+ repoUrl: this.url,
7900
+ prNumber
7901
+ });
7902
+ let prStatus = "ACTIVE" /* Active */;
7903
+ if (pr.status === 3) {
7904
+ prStatus = "MERGED" /* Merged */;
7905
+ } else if (pr.status === 2) {
7906
+ prStatus = "CLOSED" /* Closed */;
7907
+ } else if (pr.isDraft) {
7908
+ prStatus = "DRAFT" /* Draft */;
7909
+ }
7910
+ return {
7911
+ prId: String(prNumber),
7912
+ repositoryUrl: this.url,
7913
+ prCreatedAt: pr.creationDate || /* @__PURE__ */ new Date(),
7914
+ prMergedAt: pr.closedDate && pr.status === 3 ? pr.closedDate : null,
7915
+ linesAdded,
7916
+ prStatus,
7917
+ commentIds
7918
+ };
7919
+ }
7920
+ async getRecentCommits(since) {
7921
+ this._validateAccessTokenAndUrl();
7922
+ const adoSdk = await this.getAdoSdk();
7923
+ const commits = await adoSdk.getAdoRecentCommits({
7924
+ repoUrl: this.url,
7925
+ since
7926
+ });
7927
+ return {
7928
+ data: commits.map((c) => ({
7929
+ sha: c.commitId || "",
7930
+ commit: {
7931
+ committer: c.committer?.date ? { date: c.committer.date.toISOString() } : void 0,
7932
+ author: c.author ? { email: c.author.email, name: c.author.name } : void 0,
7933
+ message: c.comment
7934
+ },
7935
+ parents: c.parents?.map((sha) => ({ sha }))
7936
+ }))
7937
+ };
7621
7938
  }
7622
7939
  async getRateLimitStatus() {
7623
- return null;
7940
+ return {
7941
+ remaining: 1e4,
7942
+ reset: new Date(Date.now() + 36e5)
7943
+ };
7624
7944
  }
7625
7945
  };
7626
7946
 
@@ -8218,19 +8538,6 @@ init_env();
8218
8538
  import { z as z22 } from "zod";
8219
8539
  init_client_generates();
8220
8540
 
8221
- // src/features/analysis/scm/utils/cursorValidation.ts
8222
- var MAX_CURSOR_VALUE = 1e5;
8223
- function parseCursorSafe(cursor, defaultValue = 0, maxValue = MAX_CURSOR_VALUE) {
8224
- if (cursor === null || cursor === void 0 || cursor === "") {
8225
- return defaultValue;
8226
- }
8227
- const parsed = parseInt(cursor, 10);
8228
- if (isNaN(parsed) || parsed < 0 || parsed > maxValue) {
8229
- return defaultValue;
8230
- }
8231
- return parsed;
8232
- }
8233
-
8234
8541
  // src/features/analysis/scm/github/github.ts
8235
8542
  import { RequestError } from "@octokit/request-error";
8236
8543
 
@@ -9597,7 +9904,7 @@ import {
9597
9904
  Gitlab
9598
9905
  } from "@gitbeaker/rest";
9599
9906
  import Debug3 from "debug";
9600
- import pLimit from "p-limit";
9907
+ import pLimit3 from "p-limit";
9601
9908
  import {
9602
9909
  Agent,
9603
9910
  fetch as undiciFetch,
@@ -10026,7 +10333,7 @@ async function getGitlabMrCommitsBatch({
10026
10333
  url: repoUrl,
10027
10334
  gitlabAuthToken: accessToken
10028
10335
  });
10029
- const limit = pLimit(GITLAB_API_CONCURRENCY);
10336
+ const limit = pLimit3(GITLAB_API_CONCURRENCY);
10030
10337
  const results = await Promise.all(
10031
10338
  mrNumbers.map(
10032
10339
  (mrNumber) => limit(async () => {
@@ -10065,7 +10372,7 @@ async function getGitlabMrDataBatch({
10065
10372
  url: repoUrl,
10066
10373
  gitlabAuthToken: accessToken
10067
10374
  });
10068
- const limit = pLimit(GITLAB_API_CONCURRENCY);
10375
+ const limit = pLimit3(GITLAB_API_CONCURRENCY);
10069
10376
  const results = await Promise.all(
10070
10377
  mrNumbers.map(
10071
10378
  (mrNumber) => limit(async () => {
@@ -13060,7 +13367,7 @@ async function getRepositoryUrl() {
13060
13367
  }
13061
13368
  const remoteUrl = await gitService.getRemoteUrl();
13062
13369
  const parsed = parseScmURL(remoteUrl);
13063
- return parsed?.scmType === "GitHub" /* GitHub */ || parsed?.scmType === "GitLab" /* GitLab */ ? remoteUrl : null;
13370
+ return parsed?.scmType && parsed.scmType !== "Unknown" ? remoteUrl : null;
13064
13371
  } catch {
13065
13372
  return null;
13066
13373
  }
@@ -13867,7 +14174,7 @@ async function postIssueComment(params) {
13867
14174
  fpDescription
13868
14175
  } = params;
13869
14176
  const {
13870
- path: path26,
14177
+ path: path27,
13871
14178
  startLine,
13872
14179
  vulnerabilityReportIssue: {
13873
14180
  vulnerabilityReportIssueTags,
@@ -13882,7 +14189,7 @@ async function postIssueComment(params) {
13882
14189
  Refresh the page in order to see the changes.`,
13883
14190
  pull_number: pullRequest,
13884
14191
  commit_id: commitSha,
13885
- path: path26,
14192
+ path: path27,
13886
14193
  line: startLine
13887
14194
  });
13888
14195
  const commentId = commentRes.data.id;
@@ -13916,7 +14223,7 @@ async function postFixComment(params) {
13916
14223
  scanner
13917
14224
  } = params;
13918
14225
  const {
13919
- path: path26,
14226
+ path: path27,
13920
14227
  startLine,
13921
14228
  vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
13922
14229
  vulnerabilityReportIssueId
@@ -13934,7 +14241,7 @@ async function postFixComment(params) {
13934
14241
  Refresh the page in order to see the changes.`,
13935
14242
  pull_number: pullRequest,
13936
14243
  commit_id: commitSha,
13937
- path: path26,
14244
+ path: path27,
13938
14245
  line: startLine
13939
14246
  });
13940
14247
  const commentId = commentRes.data.id;
@@ -15857,6 +16164,47 @@ init_client_generates();
15857
16164
  init_GitService();
15858
16165
  init_urlParser2();
15859
16166
 
16167
+ // src/utils/computeGitDiffAdditions.ts
16168
+ import { mkdtemp, rm, writeFile } from "fs/promises";
16169
+ import { tmpdir } from "os";
16170
+ import path13 from "path";
16171
+ import { simpleGit as simpleGit4 } from "simple-git";
16172
+ async function computeGitDiffAdditions(oldStr, newStr) {
16173
+ const tmpDir = await mkdtemp(path13.join(tmpdir(), "diff-"));
16174
+ const oldFile = path13.join(tmpDir, "old");
16175
+ const newFile = path13.join(tmpDir, "new");
16176
+ try {
16177
+ await writeFile(oldFile, oldStr);
16178
+ await writeFile(newFile, newStr);
16179
+ const git = simpleGit4();
16180
+ let result;
16181
+ try {
16182
+ result = await git.raw([
16183
+ "diff",
16184
+ "--no-index",
16185
+ "--unified=0",
16186
+ oldFile,
16187
+ newFile
16188
+ ]);
16189
+ } catch (err) {
16190
+ if (err instanceof Error && "stdOut" in err) {
16191
+ result = err.stdOut;
16192
+ } else {
16193
+ throw err;
16194
+ }
16195
+ }
16196
+ const additions = [];
16197
+ for (const line of result.split("\n")) {
16198
+ if (line.startsWith("+") && !line.startsWith("+++")) {
16199
+ additions.push(line.slice(1));
16200
+ }
16201
+ }
16202
+ return additions.join("\n");
16203
+ } finally {
16204
+ await rm(tmpDir, { recursive: true, force: true });
16205
+ }
16206
+ }
16207
+
15860
16208
  // src/features/claude_code/transcript_parser.ts
15861
16209
  import fsPromises4 from "fs/promises";
15862
16210
  function processTranscriptLine(entry) {
@@ -16041,29 +16389,40 @@ async function readStdinData() {
16041
16389
  function validateHookData(data) {
16042
16390
  return HookDataSchema.parse(data);
16043
16391
  }
16044
- function extractInference(hookData) {
16392
+ function extractStructuredPatchAdditions(hookData) {
16393
+ const editResponse = hookData.tool_response;
16394
+ const additions = [];
16395
+ for (const patch of editResponse.structuredPatch) {
16396
+ for (const line of patch.lines) {
16397
+ if (line.startsWith("+")) {
16398
+ additions.push(line.slice(1));
16399
+ }
16400
+ }
16401
+ }
16402
+ return additions.join("\n");
16403
+ }
16404
+ async function extractInference(hookData) {
16045
16405
  if (hookData.tool_name === "Write") {
16046
16406
  const writeInput = hookData.tool_input;
16047
16407
  return writeInput.content || "";
16048
16408
  }
16049
16409
  if (hookData.tool_name === "Edit") {
16050
- const editResponse = hookData.tool_response;
16051
- const additions = [];
16052
- for (const patch of editResponse.structuredPatch) {
16053
- for (const line of patch.lines) {
16054
- if (line.startsWith("+")) {
16055
- additions.push(line.slice(1));
16056
- }
16057
- }
16410
+ const editInput = hookData.tool_input;
16411
+ try {
16412
+ return await computeGitDiffAdditions(
16413
+ editInput.old_string,
16414
+ editInput.new_string
16415
+ );
16416
+ } catch {
16417
+ return extractStructuredPatchAdditions(hookData);
16058
16418
  }
16059
- return additions.join("\n");
16060
16419
  }
16061
16420
  return "";
16062
16421
  }
16063
16422
  async function collectHookData() {
16064
16423
  const rawData = await readStdinData();
16065
16424
  const hookData = validateHookData(rawData);
16066
- const inference = extractInference(hookData);
16425
+ const inference = await extractInference(hookData);
16067
16426
  let tracePayload;
16068
16427
  try {
16069
16428
  tracePayload = await parseTranscriptAndCreateTrace(
@@ -16148,9 +16507,9 @@ async function processAndUploadHookData() {
16148
16507
  // src/features/claude_code/install_hook.ts
16149
16508
  import fsPromises5 from "fs/promises";
16150
16509
  import os4 from "os";
16151
- import path13 from "path";
16510
+ import path14 from "path";
16152
16511
  import chalk11 from "chalk";
16153
- var CLAUDE_SETTINGS_PATH = path13.join(os4.homedir(), ".claude", "settings.json");
16512
+ var CLAUDE_SETTINGS_PATH = path14.join(os4.homedir(), ".claude", "settings.json");
16154
16513
  async function claudeSettingsExists() {
16155
16514
  try {
16156
16515
  await fsPromises5.access(CLAUDE_SETTINGS_PATH);
@@ -16335,8 +16694,8 @@ var WorkspaceService = class {
16335
16694
  * Sets a known workspace path that was discovered through successful validation
16336
16695
  * @param path The validated workspace path to store
16337
16696
  */
16338
- static setKnownWorkspacePath(path26) {
16339
- this.knownWorkspacePath = path26;
16697
+ static setKnownWorkspacePath(path27) {
16698
+ this.knownWorkspacePath = path27;
16340
16699
  }
16341
16700
  /**
16342
16701
  * Gets the known workspace path that was previously validated
@@ -17197,7 +17556,7 @@ async function createAuthenticatedMcpGQLClient({
17197
17556
  import { execSync as execSync2 } from "child_process";
17198
17557
  import fs13 from "fs";
17199
17558
  import os5 from "os";
17200
- import path14 from "path";
17559
+ import path15 from "path";
17201
17560
  var IDEs = ["cursor", "windsurf", "webstorm", "vscode", "claude"];
17202
17561
  var runCommand = (cmd) => {
17203
17562
  try {
@@ -17212,7 +17571,7 @@ var gitInfo = {
17212
17571
  };
17213
17572
  var getClaudeWorkspacePaths = () => {
17214
17573
  const home = os5.homedir();
17215
- const claudeIdePath = path14.join(home, ".claude", "ide");
17574
+ const claudeIdePath = path15.join(home, ".claude", "ide");
17216
17575
  const workspacePaths = [];
17217
17576
  if (!fs13.existsSync(claudeIdePath)) {
17218
17577
  return workspacePaths;
@@ -17220,7 +17579,7 @@ var getClaudeWorkspacePaths = () => {
17220
17579
  try {
17221
17580
  const lockFiles = fs13.readdirSync(claudeIdePath).filter((file) => file.endsWith(".lock"));
17222
17581
  for (const lockFile of lockFiles) {
17223
- const lockFilePath = path14.join(claudeIdePath, lockFile);
17582
+ const lockFilePath = path15.join(claudeIdePath, lockFile);
17224
17583
  try {
17225
17584
  const lockContent = JSON.parse(fs13.readFileSync(lockFilePath, "utf8"));
17226
17585
  if (lockContent.workspaceFolders && Array.isArray(lockContent.workspaceFolders)) {
@@ -17245,24 +17604,24 @@ var getMCPConfigPaths = (hostName) => {
17245
17604
  switch (hostName.toLowerCase()) {
17246
17605
  case "cursor":
17247
17606
  return [
17248
- path14.join(currentDir, ".cursor", "mcp.json"),
17607
+ path15.join(currentDir, ".cursor", "mcp.json"),
17249
17608
  // local first
17250
- path14.join(home, ".cursor", "mcp.json")
17609
+ path15.join(home, ".cursor", "mcp.json")
17251
17610
  ];
17252
17611
  case "windsurf":
17253
17612
  return [
17254
- path14.join(currentDir, ".codeium", "mcp_config.json"),
17613
+ path15.join(currentDir, ".codeium", "mcp_config.json"),
17255
17614
  // local first
17256
- path14.join(home, ".codeium", "windsurf", "mcp_config.json")
17615
+ path15.join(home, ".codeium", "windsurf", "mcp_config.json")
17257
17616
  ];
17258
17617
  case "webstorm":
17259
17618
  return [];
17260
17619
  case "visualstudiocode":
17261
17620
  case "vscode":
17262
17621
  return [
17263
- path14.join(currentDir, ".vscode", "mcp.json"),
17622
+ path15.join(currentDir, ".vscode", "mcp.json"),
17264
17623
  // local first
17265
- process.platform === "win32" ? path14.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path14.join(
17624
+ process.platform === "win32" ? path15.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path15.join(
17266
17625
  home,
17267
17626
  "Library",
17268
17627
  "Application Support",
@@ -17273,13 +17632,13 @@ var getMCPConfigPaths = (hostName) => {
17273
17632
  ];
17274
17633
  case "claude": {
17275
17634
  const claudePaths = [
17276
- path14.join(currentDir, ".claude.json"),
17635
+ path15.join(currentDir, ".claude.json"),
17277
17636
  // local first
17278
- path14.join(home, ".claude.json")
17637
+ path15.join(home, ".claude.json")
17279
17638
  ];
17280
17639
  const workspacePaths = getClaudeWorkspacePaths();
17281
17640
  for (const workspacePath of workspacePaths) {
17282
- claudePaths.push(path14.join(workspacePath, ".mcp.json"));
17641
+ claudePaths.push(path15.join(workspacePath, ".mcp.json"));
17283
17642
  }
17284
17643
  return claudePaths;
17285
17644
  }
@@ -17440,10 +17799,10 @@ var getHostInfo = (additionalMcpList) => {
17440
17799
  const ideConfigPaths = /* @__PURE__ */ new Set();
17441
17800
  for (const ide of IDEs) {
17442
17801
  const configPaths = getMCPConfigPaths(ide);
17443
- configPaths.forEach((path26) => ideConfigPaths.add(path26));
17802
+ configPaths.forEach((path27) => ideConfigPaths.add(path27));
17444
17803
  }
17445
17804
  const uniqueAdditionalPaths = additionalMcpList.filter(
17446
- (path26) => !ideConfigPaths.has(path26)
17805
+ (path27) => !ideConfigPaths.has(path27)
17447
17806
  );
17448
17807
  for (const ide of IDEs) {
17449
17808
  const cfg = readMCPConfig(ide);
@@ -17565,7 +17924,7 @@ init_configs();
17565
17924
  init_configs();
17566
17925
  import fs14 from "fs";
17567
17926
  import os6 from "os";
17568
- import path15 from "path";
17927
+ import path16 from "path";
17569
17928
  var MAX_DEPTH = 2;
17570
17929
  var patterns = ["mcp", "claude"];
17571
17930
  var isFileMatch = (fileName) => {
@@ -17585,7 +17944,7 @@ var searchDir = async (dir, depth = 0) => {
17585
17944
  if (depth > MAX_DEPTH) return results;
17586
17945
  const entries = await fs14.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
17587
17946
  for (const entry of entries) {
17588
- const fullPath = path15.join(dir, entry.name);
17947
+ const fullPath = path16.join(dir, entry.name);
17589
17948
  if (entry.isFile() && isFileMatch(entry.name)) {
17590
17949
  results.push(fullPath);
17591
17950
  } else if (entry.isDirectory()) {
@@ -17602,14 +17961,14 @@ var findSystemMCPConfigs = async () => {
17602
17961
  const home = os6.homedir();
17603
17962
  const platform2 = os6.platform();
17604
17963
  const knownDirs = platform2 === "win32" ? [
17605
- path15.join(home, ".cursor"),
17606
- path15.join(home, "Documents"),
17607
- path15.join(home, "Downloads")
17964
+ path16.join(home, ".cursor"),
17965
+ path16.join(home, "Documents"),
17966
+ path16.join(home, "Downloads")
17608
17967
  ] : [
17609
- path15.join(home, ".cursor"),
17610
- process.env["XDG_CONFIG_HOME"] || path15.join(home, ".config"),
17611
- path15.join(home, "Documents"),
17612
- path15.join(home, "Downloads")
17968
+ path16.join(home, ".cursor"),
17969
+ process.env["XDG_CONFIG_HOME"] || path16.join(home, ".config"),
17970
+ path16.join(home, "Documents"),
17971
+ path16.join(home, "Downloads")
17613
17972
  ];
17614
17973
  const timeoutPromise = new Promise(
17615
17974
  (resolve) => setTimeout(() => {
@@ -20025,13 +20384,13 @@ For a complete security audit workflow, use the \`full-security-audit\` prompt.
20025
20384
  // src/mcp/services/McpDetectionService/CursorMcpDetectionService.ts
20026
20385
  import * as fs17 from "fs";
20027
20386
  import * as os9 from "os";
20028
- import * as path17 from "path";
20387
+ import * as path18 from "path";
20029
20388
 
20030
20389
  // src/mcp/services/McpDetectionService/BaseMcpDetectionService.ts
20031
20390
  init_configs();
20032
20391
  import * as fs16 from "fs";
20033
20392
  import fetch6 from "node-fetch";
20034
- import * as path16 from "path";
20393
+ import * as path17 from "path";
20035
20394
 
20036
20395
  // src/mcp/services/McpDetectionService/McpDetectionServiceUtils.ts
20037
20396
  import * as fs15 from "fs";
@@ -20040,14 +20399,14 @@ import * as os8 from "os";
20040
20399
  // src/mcp/services/McpDetectionService/VscodeMcpDetectionService.ts
20041
20400
  import * as fs18 from "fs";
20042
20401
  import * as os10 from "os";
20043
- import * as path18 from "path";
20402
+ import * as path19 from "path";
20044
20403
 
20045
20404
  // src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesTool.ts
20046
20405
  import { z as z43 } from "zod";
20047
20406
 
20048
20407
  // src/mcp/services/PathValidation.ts
20049
20408
  import fs19 from "fs";
20050
- import path19 from "path";
20409
+ import path20 from "path";
20051
20410
  async function validatePath(inputPath) {
20052
20411
  logDebug("Validating MCP path", { inputPath });
20053
20412
  if (/^\/[a-zA-Z]:\//.test(inputPath)) {
@@ -20079,7 +20438,7 @@ async function validatePath(inputPath) {
20079
20438
  logError(error);
20080
20439
  return { isValid: false, error, path: inputPath };
20081
20440
  }
20082
- const normalizedPath = path19.normalize(inputPath);
20441
+ const normalizedPath = path20.normalize(inputPath);
20083
20442
  if (normalizedPath.includes("..")) {
20084
20443
  const error = `Normalized path contains path traversal patterns: ${inputPath}`;
20085
20444
  logError(error);
@@ -20731,7 +21090,7 @@ init_configs();
20731
21090
  import fs20 from "fs/promises";
20732
21091
  import nodePath from "path";
20733
21092
  var getLocalFiles = async ({
20734
- path: path26,
21093
+ path: path27,
20735
21094
  maxFileSize = MCP_MAX_FILE_SIZE,
20736
21095
  maxFiles,
20737
21096
  isAllFilesScan,
@@ -20739,17 +21098,17 @@ var getLocalFiles = async ({
20739
21098
  scanRecentlyChangedFiles
20740
21099
  }) => {
20741
21100
  logDebug(`[${scanContext}] Starting getLocalFiles`, {
20742
- path: path26,
21101
+ path: path27,
20743
21102
  maxFileSize,
20744
21103
  maxFiles,
20745
21104
  isAllFilesScan,
20746
21105
  scanRecentlyChangedFiles
20747
21106
  });
20748
21107
  try {
20749
- const resolvedRepoPath = await fs20.realpath(path26);
21108
+ const resolvedRepoPath = await fs20.realpath(path27);
20750
21109
  logDebug(`[${scanContext}] Resolved repository path`, {
20751
21110
  resolvedRepoPath,
20752
- originalPath: path26
21111
+ originalPath: path27
20753
21112
  });
20754
21113
  const gitService = new GitService(resolvedRepoPath, log);
20755
21114
  const gitValidation = await gitService.validateRepository();
@@ -20762,7 +21121,7 @@ var getLocalFiles = async ({
20762
21121
  if (!gitValidation.isValid || isAllFilesScan) {
20763
21122
  try {
20764
21123
  files = await FileUtils.getLastChangedFiles({
20765
- dir: path26,
21124
+ dir: path27,
20766
21125
  maxFileSize,
20767
21126
  maxFiles,
20768
21127
  isAllFilesScan
@@ -20854,7 +21213,7 @@ var getLocalFiles = async ({
20854
21213
  logError(`${scanContext}Unexpected error in getLocalFiles`, {
20855
21214
  error: error instanceof Error ? error.message : String(error),
20856
21215
  stack: error instanceof Error ? error.stack : void 0,
20857
- path: path26
21216
+ path: path27
20858
21217
  });
20859
21218
  throw error;
20860
21219
  }
@@ -20864,7 +21223,7 @@ var getLocalFiles = async ({
20864
21223
  init_client_generates();
20865
21224
  init_GitService();
20866
21225
  import fs21 from "fs";
20867
- import path20 from "path";
21226
+ import path21 from "path";
20868
21227
  import { z as z42 } from "zod";
20869
21228
  function extractPathFromPatch(patch) {
20870
21229
  const match = patch?.match(/diff --git a\/([^\s]+) b\//);
@@ -20950,7 +21309,7 @@ var LocalMobbFolderService = class {
20950
21309
  "[LocalMobbFolderService] Non-git repository detected, skipping .gitignore operations"
20951
21310
  );
20952
21311
  }
20953
- const mobbFolderPath = path20.join(
21312
+ const mobbFolderPath = path21.join(
20954
21313
  this.repoPath,
20955
21314
  this.defaultMobbFolderName
20956
21315
  );
@@ -21122,7 +21481,7 @@ var LocalMobbFolderService = class {
21122
21481
  mobbFolderPath,
21123
21482
  baseFileName
21124
21483
  );
21125
- const filePath = path20.join(mobbFolderPath, uniqueFileName);
21484
+ const filePath = path21.join(mobbFolderPath, uniqueFileName);
21126
21485
  await fs21.promises.writeFile(filePath, patch, "utf8");
21127
21486
  logInfo("[LocalMobbFolderService] Patch saved successfully", {
21128
21487
  filePath,
@@ -21180,11 +21539,11 @@ var LocalMobbFolderService = class {
21180
21539
  * @returns Unique filename that doesn't conflict with existing files
21181
21540
  */
21182
21541
  getUniqueFileName(folderPath, baseFileName) {
21183
- const baseName = path20.parse(baseFileName).name;
21184
- const extension = path20.parse(baseFileName).ext;
21542
+ const baseName = path21.parse(baseFileName).name;
21543
+ const extension = path21.parse(baseFileName).ext;
21185
21544
  let uniqueFileName = baseFileName;
21186
21545
  let index = 1;
21187
- while (fs21.existsSync(path20.join(folderPath, uniqueFileName))) {
21546
+ while (fs21.existsSync(path21.join(folderPath, uniqueFileName))) {
21188
21547
  uniqueFileName = `${baseName}-${index}${extension}`;
21189
21548
  index++;
21190
21549
  if (index > 1e3) {
@@ -21215,7 +21574,7 @@ var LocalMobbFolderService = class {
21215
21574
  logDebug("[LocalMobbFolderService] Logging patch info", { fixId: fix.id });
21216
21575
  try {
21217
21576
  const mobbFolderPath = await this.getFolder();
21218
- const patchInfoPath = path20.join(mobbFolderPath, "patchInfo.md");
21577
+ const patchInfoPath = path21.join(mobbFolderPath, "patchInfo.md");
21219
21578
  const markdownContent = this.generateFixMarkdown(fix, savedPatchFileName);
21220
21579
  let existingContent = "";
21221
21580
  if (fs21.existsSync(patchInfoPath)) {
@@ -21257,7 +21616,7 @@ var LocalMobbFolderService = class {
21257
21616
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
21258
21617
  const patch = this.extractPatchFromFix(fix);
21259
21618
  const relativePatchedFilePath = patch ? extractPathFromPatch(patch) : null;
21260
- const patchedFilePath = relativePatchedFilePath ? path20.resolve(this.repoPath, relativePatchedFilePath) : null;
21619
+ const patchedFilePath = relativePatchedFilePath ? path21.resolve(this.repoPath, relativePatchedFilePath) : null;
21261
21620
  const fixIdentifier = savedPatchFileName ? savedPatchFileName.replace(".patch", "") : fix.id;
21262
21621
  let markdown = `# Fix ${fixIdentifier}
21263
21622
 
@@ -21601,14 +21960,14 @@ import {
21601
21960
  } from "fs";
21602
21961
  import fs22 from "fs/promises";
21603
21962
  import parseDiff2 from "parse-diff";
21604
- import path21 from "path";
21963
+ import path22 from "path";
21605
21964
  var PatchApplicationService = class {
21606
21965
  /**
21607
21966
  * Gets the appropriate comment syntax for a file based on its extension
21608
21967
  */
21609
21968
  static getCommentSyntax(filePath) {
21610
- const ext = path21.extname(filePath).toLowerCase();
21611
- const basename2 = path21.basename(filePath);
21969
+ const ext = path22.extname(filePath).toLowerCase();
21970
+ const basename2 = path22.basename(filePath);
21612
21971
  const commentMap = {
21613
21972
  // C-style languages (single line comments)
21614
21973
  ".js": "//",
@@ -21816,7 +22175,7 @@ var PatchApplicationService = class {
21816
22175
  }
21817
22176
  );
21818
22177
  }
21819
- const dirPath = path21.dirname(normalizedFilePath);
22178
+ const dirPath = path22.dirname(normalizedFilePath);
21820
22179
  mkdirSync(dirPath, { recursive: true });
21821
22180
  writeFileSync(normalizedFilePath, finalContent, "utf8");
21822
22181
  return normalizedFilePath;
@@ -21825,9 +22184,9 @@ var PatchApplicationService = class {
21825
22184
  repositoryPath,
21826
22185
  targetPath
21827
22186
  }) {
21828
- const repoRoot = path21.resolve(repositoryPath);
21829
- const normalizedPath = path21.resolve(repoRoot, targetPath);
21830
- const repoRootWithSep = repoRoot.endsWith(path21.sep) ? repoRoot : `${repoRoot}${path21.sep}`;
22187
+ const repoRoot = path22.resolve(repositoryPath);
22188
+ const normalizedPath = path22.resolve(repoRoot, targetPath);
22189
+ const repoRootWithSep = repoRoot.endsWith(path22.sep) ? repoRoot : `${repoRoot}${path22.sep}`;
21831
22190
  if (normalizedPath !== repoRoot && !normalizedPath.startsWith(repoRootWithSep)) {
21832
22191
  throw new Error(
21833
22192
  `Security violation: target path ${targetPath} resolves outside repository`
@@ -21836,7 +22195,7 @@ var PatchApplicationService = class {
21836
22195
  return {
21837
22196
  repoRoot,
21838
22197
  normalizedPath,
21839
- relativePath: path21.relative(repoRoot, normalizedPath)
22198
+ relativePath: path22.relative(repoRoot, normalizedPath)
21840
22199
  };
21841
22200
  }
21842
22201
  /**
@@ -22118,7 +22477,7 @@ var PatchApplicationService = class {
22118
22477
  continue;
22119
22478
  }
22120
22479
  try {
22121
- const absolutePath = path21.resolve(repositoryPath, targetFile);
22480
+ const absolutePath = path22.resolve(repositoryPath, targetFile);
22122
22481
  if (existsSync6(absolutePath)) {
22123
22482
  const stats = await fs22.stat(absolutePath);
22124
22483
  const fileModTime = stats.mtime.getTime();
@@ -22344,7 +22703,7 @@ var PatchApplicationService = class {
22344
22703
  fix,
22345
22704
  scanContext
22346
22705
  });
22347
- appliedFiles.push(path21.relative(repositoryPath, actualPath));
22706
+ appliedFiles.push(path22.relative(repositoryPath, actualPath));
22348
22707
  logDebug(`[${scanContext}] Created new file: ${relativePath}`);
22349
22708
  }
22350
22709
  /**
@@ -22393,7 +22752,7 @@ var PatchApplicationService = class {
22393
22752
  fix,
22394
22753
  scanContext
22395
22754
  });
22396
- appliedFiles.push(path21.relative(repositoryPath, actualPath));
22755
+ appliedFiles.push(path22.relative(repositoryPath, actualPath));
22397
22756
  logDebug(`[${scanContext}] Modified file: ${relativePath}`);
22398
22757
  }
22399
22758
  }
@@ -22590,7 +22949,7 @@ init_configs();
22590
22949
  // src/mcp/services/FileOperations.ts
22591
22950
  init_FileUtils();
22592
22951
  import fs23 from "fs";
22593
- import path22 from "path";
22952
+ import path23 from "path";
22594
22953
  import AdmZip3 from "adm-zip";
22595
22954
  var FileOperations = class {
22596
22955
  /**
@@ -22610,10 +22969,10 @@ var FileOperations = class {
22610
22969
  let packedFilesCount = 0;
22611
22970
  const packedFiles = [];
22612
22971
  const excludedFiles = [];
22613
- const resolvedRepoPath = path22.resolve(repositoryPath);
22972
+ const resolvedRepoPath = path23.resolve(repositoryPath);
22614
22973
  for (const filepath of fileList) {
22615
- const absoluteFilepath = path22.join(repositoryPath, filepath);
22616
- const resolvedFilePath = path22.resolve(absoluteFilepath);
22974
+ const absoluteFilepath = path23.join(repositoryPath, filepath);
22975
+ const resolvedFilePath = path23.resolve(absoluteFilepath);
22617
22976
  if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
22618
22977
  const reason = "potential path traversal security risk";
22619
22978
  logDebug(`[FileOperations] Skipping ${filepath} due to ${reason}`);
@@ -22660,11 +23019,11 @@ var FileOperations = class {
22660
23019
  fileList,
22661
23020
  repositoryPath
22662
23021
  }) {
22663
- const resolvedRepoPath = path22.resolve(repositoryPath);
23022
+ const resolvedRepoPath = path23.resolve(repositoryPath);
22664
23023
  const validatedPaths = [];
22665
23024
  for (const filepath of fileList) {
22666
- const absoluteFilepath = path22.join(repositoryPath, filepath);
22667
- const resolvedFilePath = path22.resolve(absoluteFilepath);
23025
+ const absoluteFilepath = path23.join(repositoryPath, filepath);
23026
+ const resolvedFilePath = path23.resolve(absoluteFilepath);
22668
23027
  if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
22669
23028
  logDebug(
22670
23029
  `[FileOperations] Rejecting ${filepath} - path traversal attempt detected`
@@ -22692,7 +23051,7 @@ var FileOperations = class {
22692
23051
  for (const absolutePath of filePaths) {
22693
23052
  try {
22694
23053
  const content = await fs23.promises.readFile(absolutePath);
22695
- const relativePath = path22.basename(absolutePath);
23054
+ const relativePath = path23.basename(absolutePath);
22696
23055
  fileDataArray.push({
22697
23056
  relativePath,
22698
23057
  absolutePath,
@@ -23004,14 +23363,14 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
23004
23363
  * since the last scan.
23005
23364
  */
23006
23365
  async scanForSecurityVulnerabilities({
23007
- path: path26,
23366
+ path: path27,
23008
23367
  isAllDetectionRulesScan,
23009
23368
  isAllFilesScan,
23010
23369
  scanContext
23011
23370
  }) {
23012
23371
  this.hasAuthenticationFailed = false;
23013
23372
  logDebug(`[${scanContext}] Scanning for new security vulnerabilities`, {
23014
- path: path26
23373
+ path: path27
23015
23374
  });
23016
23375
  if (!this.gqlClient) {
23017
23376
  logInfo(`[${scanContext}] No GQL client found, skipping scan`);
@@ -23027,11 +23386,11 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
23027
23386
  }
23028
23387
  logDebug(
23029
23388
  `[${scanContext}] Connected to the API, assembling list of files to scan`,
23030
- { path: path26 }
23389
+ { path: path27 }
23031
23390
  );
23032
23391
  const isBackgroundScan = scanContext === ScanContext.BACKGROUND_INITIAL || scanContext === ScanContext.BACKGROUND_PERIODIC;
23033
23392
  const files = await getLocalFiles({
23034
- path: path26,
23393
+ path: path27,
23035
23394
  isAllFilesScan,
23036
23395
  scanContext,
23037
23396
  scanRecentlyChangedFiles: !isBackgroundScan
@@ -23057,13 +23416,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
23057
23416
  });
23058
23417
  const { fixReportId, projectId } = await scanFiles({
23059
23418
  fileList: filesToScan.map((file) => file.relativePath),
23060
- repositoryPath: path26,
23419
+ repositoryPath: path27,
23061
23420
  gqlClient: this.gqlClient,
23062
23421
  isAllDetectionRulesScan,
23063
23422
  scanContext
23064
23423
  });
23065
23424
  logInfo(
23066
- `[${scanContext}] Security scan completed for ${path26} reportId: ${fixReportId} projectId: ${projectId}`
23425
+ `[${scanContext}] Security scan completed for ${path27} reportId: ${fixReportId} projectId: ${projectId}`
23067
23426
  );
23068
23427
  if (isAllFilesScan) {
23069
23428
  return;
@@ -23357,13 +23716,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
23357
23716
  });
23358
23717
  return scannedFiles.some((file) => file.relativePath === fixFile);
23359
23718
  }
23360
- async getFreshFixes({ path: path26 }) {
23719
+ async getFreshFixes({ path: path27 }) {
23361
23720
  const scanContext = ScanContext.USER_REQUEST;
23362
- logDebug(`[${scanContext}] Getting fresh fixes`, { path: path26 });
23363
- if (this.path !== path26) {
23364
- this.path = path26;
23721
+ logDebug(`[${scanContext}] Getting fresh fixes`, { path: path27 });
23722
+ if (this.path !== path27) {
23723
+ this.path = path27;
23365
23724
  this.reset();
23366
- logInfo(`[${scanContext}] Reset service state for new path`, { path: path26 });
23725
+ logInfo(`[${scanContext}] Reset service state for new path`, { path: path27 });
23367
23726
  }
23368
23727
  try {
23369
23728
  const loginContext = createMcpLoginContext("check_new_fixes");
@@ -23382,7 +23741,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
23382
23741
  }
23383
23742
  throw error;
23384
23743
  }
23385
- this.triggerScan({ path: path26, gqlClient: this.gqlClient });
23744
+ this.triggerScan({ path: path27, gqlClient: this.gqlClient });
23386
23745
  let isMvsAutoFixEnabled = null;
23387
23746
  try {
23388
23747
  isMvsAutoFixEnabled = await this.gqlClient.getMvsAutoFixSettings();
@@ -23416,33 +23775,33 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
23416
23775
  return noFreshFixesPrompt;
23417
23776
  }
23418
23777
  triggerScan({
23419
- path: path26,
23778
+ path: path27,
23420
23779
  gqlClient
23421
23780
  }) {
23422
- if (this.path !== path26) {
23423
- this.path = path26;
23781
+ if (this.path !== path27) {
23782
+ this.path = path27;
23424
23783
  this.reset();
23425
- logInfo(`Reset service state for new path in triggerScan`, { path: path26 });
23784
+ logInfo(`Reset service state for new path in triggerScan`, { path: path27 });
23426
23785
  }
23427
23786
  this.gqlClient = gqlClient;
23428
23787
  if (!this.intervalId) {
23429
- this.startPeriodicScanning(path26);
23430
- this.executeInitialScan(path26);
23431
- void this.executeInitialFullScan(path26);
23788
+ this.startPeriodicScanning(path27);
23789
+ this.executeInitialScan(path27);
23790
+ void this.executeInitialFullScan(path27);
23432
23791
  }
23433
23792
  }
23434
- startPeriodicScanning(path26) {
23793
+ startPeriodicScanning(path27) {
23435
23794
  const scanContext = ScanContext.BACKGROUND_PERIODIC;
23436
23795
  logDebug(
23437
23796
  `[${scanContext}] Starting periodic scan for new security vulnerabilities`,
23438
23797
  {
23439
- path: path26
23798
+ path: path27
23440
23799
  }
23441
23800
  );
23442
23801
  this.intervalId = setInterval(() => {
23443
- logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path26 });
23802
+ logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path27 });
23444
23803
  this.scanForSecurityVulnerabilities({
23445
- path: path26,
23804
+ path: path27,
23446
23805
  scanContext
23447
23806
  }).catch((error) => {
23448
23807
  logError(`[${scanContext}] Error during periodic security scan`, {
@@ -23451,45 +23810,45 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
23451
23810
  });
23452
23811
  }, MCP_PERIODIC_CHECK_INTERVAL);
23453
23812
  }
23454
- async executeInitialFullScan(path26) {
23813
+ async executeInitialFullScan(path27) {
23455
23814
  const scanContext = ScanContext.FULL_SCAN;
23456
- logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path26 });
23815
+ logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path27 });
23457
23816
  logDebug(`[${scanContext}] Full scan paths scanned`, {
23458
23817
  fullScanPathsScanned: this.fullScanPathsScanned
23459
23818
  });
23460
- if (this.fullScanPathsScanned.includes(path26)) {
23819
+ if (this.fullScanPathsScanned.includes(path27)) {
23461
23820
  logDebug(`[${scanContext}] Full scan already executed for this path`, {
23462
- path: path26
23821
+ path: path27
23463
23822
  });
23464
23823
  return;
23465
23824
  }
23466
23825
  configStore.set("fullScanPathsScanned", [
23467
23826
  ...this.fullScanPathsScanned,
23468
- path26
23827
+ path27
23469
23828
  ]);
23470
23829
  try {
23471
23830
  await this.scanForSecurityVulnerabilities({
23472
- path: path26,
23831
+ path: path27,
23473
23832
  isAllFilesScan: true,
23474
23833
  isAllDetectionRulesScan: true,
23475
23834
  scanContext: ScanContext.FULL_SCAN
23476
23835
  });
23477
- if (!this.fullScanPathsScanned.includes(path26)) {
23478
- this.fullScanPathsScanned.push(path26);
23836
+ if (!this.fullScanPathsScanned.includes(path27)) {
23837
+ this.fullScanPathsScanned.push(path27);
23479
23838
  configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
23480
23839
  }
23481
- logInfo(`[${scanContext}] Full scan completed`, { path: path26 });
23840
+ logInfo(`[${scanContext}] Full scan completed`, { path: path27 });
23482
23841
  } catch (error) {
23483
23842
  logError(`[${scanContext}] Error during initial full security scan`, {
23484
23843
  error
23485
23844
  });
23486
23845
  }
23487
23846
  }
23488
- executeInitialScan(path26) {
23847
+ executeInitialScan(path27) {
23489
23848
  const scanContext = ScanContext.BACKGROUND_INITIAL;
23490
- logDebug(`[${scanContext}] Triggering initial security scan`, { path: path26 });
23849
+ logDebug(`[${scanContext}] Triggering initial security scan`, { path: path27 });
23491
23850
  this.scanForSecurityVulnerabilities({
23492
- path: path26,
23851
+ path: path27,
23493
23852
  scanContext: ScanContext.BACKGROUND_INITIAL
23494
23853
  }).catch((error) => {
23495
23854
  logError(`[${scanContext}] Error during initial security scan`, { error });
@@ -23586,9 +23945,9 @@ Example payload:
23586
23945
  `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
23587
23946
  );
23588
23947
  }
23589
- const path26 = pathValidationResult.path;
23948
+ const path27 = pathValidationResult.path;
23590
23949
  const resultText = await this.newFixesService.getFreshFixes({
23591
- path: path26
23950
+ path: path27
23592
23951
  });
23593
23952
  logInfo("CheckForNewAvailableFixesTool execution completed", {
23594
23953
  resultText
@@ -23766,8 +24125,8 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
23766
24125
  `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
23767
24126
  );
23768
24127
  }
23769
- const path26 = pathValidationResult.path;
23770
- const gitService = new GitService(path26, log);
24128
+ const path27 = pathValidationResult.path;
24129
+ const gitService = new GitService(path27, log);
23771
24130
  const gitValidation = await gitService.validateRepository();
23772
24131
  if (!gitValidation.isValid) {
23773
24132
  throw new Error(`Invalid git repository: ${gitValidation.error}`);
@@ -24152,9 +24511,9 @@ Example payload:
24152
24511
  `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
24153
24512
  );
24154
24513
  }
24155
- const path26 = pathValidationResult.path;
24514
+ const path27 = pathValidationResult.path;
24156
24515
  const files = await getLocalFiles({
24157
- path: path26,
24516
+ path: path27,
24158
24517
  maxFileSize: MCP_MAX_FILE_SIZE,
24159
24518
  maxFiles: args.maxFiles,
24160
24519
  scanContext: ScanContext.USER_REQUEST,
@@ -24174,7 +24533,7 @@ Example payload:
24174
24533
  try {
24175
24534
  const fixResult = await this.vulnerabilityFixService.processVulnerabilities({
24176
24535
  fileList: files.map((file) => file.relativePath),
24177
- repositoryPath: path26,
24536
+ repositoryPath: path27,
24178
24537
  offset: args.offset,
24179
24538
  limit: args.limit,
24180
24539
  isRescan: args.rescan || !!args.maxFiles
@@ -24414,10 +24773,10 @@ init_client_generates();
24414
24773
  init_urlParser2();
24415
24774
 
24416
24775
  // src/features/codeium_intellij/codeium_language_server_grpc_client.ts
24417
- import path23 from "path";
24776
+ import path24 from "path";
24418
24777
  import * as grpc from "@grpc/grpc-js";
24419
24778
  import * as protoLoader from "@grpc/proto-loader";
24420
- var PROTO_PATH = path23.join(
24779
+ var PROTO_PATH = path24.join(
24421
24780
  getModuleRootDir(),
24422
24781
  "src/features/codeium_intellij/proto/exa/language_server_pb/language_server.proto"
24423
24782
  );
@@ -24429,7 +24788,7 @@ function loadProto() {
24429
24788
  defaults: true,
24430
24789
  oneofs: true,
24431
24790
  includeDirs: [
24432
- path23.join(getModuleRootDir(), "src/features/codeium_intellij/proto")
24791
+ path24.join(getModuleRootDir(), "src/features/codeium_intellij/proto")
24433
24792
  ]
24434
24793
  });
24435
24794
  return grpc.loadPackageDefinition(
@@ -24485,28 +24844,28 @@ async function getGrpcClient(port, csrf3) {
24485
24844
  // src/features/codeium_intellij/parse_intellij_logs.ts
24486
24845
  import fs25 from "fs";
24487
24846
  import os11 from "os";
24488
- import path24 from "path";
24847
+ import path25 from "path";
24489
24848
  function getLogsDir() {
24490
24849
  if (process.platform === "darwin") {
24491
- return path24.join(os11.homedir(), "Library/Logs/JetBrains");
24850
+ return path25.join(os11.homedir(), "Library/Logs/JetBrains");
24492
24851
  } else if (process.platform === "win32") {
24493
- return path24.join(
24494
- process.env["LOCALAPPDATA"] || path24.join(os11.homedir(), "AppData/Local"),
24852
+ return path25.join(
24853
+ process.env["LOCALAPPDATA"] || path25.join(os11.homedir(), "AppData/Local"),
24495
24854
  "JetBrains"
24496
24855
  );
24497
24856
  } else {
24498
- return path24.join(os11.homedir(), ".cache/JetBrains");
24857
+ return path25.join(os11.homedir(), ".cache/JetBrains");
24499
24858
  }
24500
24859
  }
24501
24860
  function parseIdeLogDir(ideLogDir) {
24502
24861
  const logFiles = fs25.readdirSync(ideLogDir).filter((f) => /^idea(\.\d+)?\.log$/.test(f)).map((f) => ({
24503
24862
  name: f,
24504
- mtime: fs25.statSync(path24.join(ideLogDir, f)).mtimeMs
24863
+ mtime: fs25.statSync(path25.join(ideLogDir, f)).mtimeMs
24505
24864
  })).sort((a, b) => a.mtime - b.mtime).map((f) => f.name);
24506
24865
  let latestCsrf = null;
24507
24866
  let latestPort = null;
24508
24867
  for (const logFile of logFiles) {
24509
- const lines = fs25.readFileSync(path24.join(ideLogDir, logFile), "utf-8").split("\n");
24868
+ const lines = fs25.readFileSync(path25.join(ideLogDir, logFile), "utf-8").split("\n");
24510
24869
  for (const line of lines) {
24511
24870
  if (!line.includes(
24512
24871
  "com.codeium.intellij.language_server.LanguageServerProcessHandler"
@@ -24534,9 +24893,9 @@ function findRunningCodeiumLanguageServers() {
24534
24893
  const logsDir = getLogsDir();
24535
24894
  if (!fs25.existsSync(logsDir)) return results;
24536
24895
  for (const ide of fs25.readdirSync(logsDir)) {
24537
- let ideLogDir = path24.join(logsDir, ide);
24896
+ let ideLogDir = path25.join(logsDir, ide);
24538
24897
  if (process.platform !== "darwin") {
24539
- ideLogDir = path24.join(ideLogDir, "log");
24898
+ ideLogDir = path25.join(ideLogDir, "log");
24540
24899
  }
24541
24900
  if (!fs25.existsSync(ideLogDir) || !fs25.statSync(ideLogDir).isDirectory()) {
24542
24901
  continue;
@@ -24719,10 +25078,10 @@ function processChatStepCodeAction(step) {
24719
25078
  // src/features/codeium_intellij/install_hook.ts
24720
25079
  import fsPromises6 from "fs/promises";
24721
25080
  import os12 from "os";
24722
- import path25 from "path";
25081
+ import path26 from "path";
24723
25082
  import chalk14 from "chalk";
24724
25083
  function getCodeiumHooksPath() {
24725
- return path25.join(os12.homedir(), ".codeium", "hooks.json");
25084
+ return path26.join(os12.homedir(), ".codeium", "hooks.json");
24726
25085
  }
24727
25086
  async function readCodeiumHooks() {
24728
25087
  const hooksPath = getCodeiumHooksPath();
@@ -24735,7 +25094,7 @@ async function readCodeiumHooks() {
24735
25094
  }
24736
25095
  async function writeCodeiumHooks(config2) {
24737
25096
  const hooksPath = getCodeiumHooksPath();
24738
- const dir = path25.dirname(hooksPath);
25097
+ const dir = path26.dirname(hooksPath);
24739
25098
  await fsPromises6.mkdir(dir, { recursive: true });
24740
25099
  await fsPromises6.writeFile(
24741
25100
  hooksPath,