mobbdev 1.4.11 → 1.4.12

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.
@@ -56,17 +56,17 @@ declare const PromptItemZ: z.ZodObject<{
56
56
  name: string;
57
57
  parameters: string;
58
58
  result: string;
59
+ mcpServer?: string | undefined;
59
60
  accepted?: boolean | undefined;
60
61
  rawArguments?: string | undefined;
61
- mcpServer?: string | undefined;
62
62
  mcpToolName?: string | undefined;
63
63
  }, {
64
64
  name: string;
65
65
  parameters: string;
66
66
  result: string;
67
+ mcpServer?: string | undefined;
67
68
  accepted?: boolean | undefined;
68
69
  rawArguments?: string | undefined;
69
- mcpServer?: string | undefined;
70
70
  mcpToolName?: string | undefined;
71
71
  }>>;
72
72
  }, "strip", z.ZodTypeAny, {
@@ -75,9 +75,9 @@ declare const PromptItemZ: z.ZodObject<{
75
75
  name: string;
76
76
  parameters: string;
77
77
  result: string;
78
+ mcpServer?: string | undefined;
78
79
  accepted?: boolean | undefined;
79
80
  rawArguments?: string | undefined;
80
- mcpServer?: string | undefined;
81
81
  mcpToolName?: string | undefined;
82
82
  } | undefined;
83
83
  date?: Date | undefined;
@@ -96,9 +96,9 @@ declare const PromptItemZ: z.ZodObject<{
96
96
  name: string;
97
97
  parameters: string;
98
98
  result: string;
99
+ mcpServer?: string | undefined;
99
100
  accepted?: boolean | undefined;
100
101
  rawArguments?: string | undefined;
101
- mcpServer?: string | undefined;
102
102
  mcpToolName?: string | undefined;
103
103
  } | undefined;
104
104
  date?: Date | undefined;
@@ -149,17 +149,17 @@ declare const PromptItemArrayZ: z.ZodArray<z.ZodObject<{
149
149
  name: string;
150
150
  parameters: string;
151
151
  result: string;
152
+ mcpServer?: string | undefined;
152
153
  accepted?: boolean | undefined;
153
154
  rawArguments?: string | undefined;
154
- mcpServer?: string | undefined;
155
155
  mcpToolName?: string | undefined;
156
156
  }, {
157
157
  name: string;
158
158
  parameters: string;
159
159
  result: string;
160
+ mcpServer?: string | undefined;
160
161
  accepted?: boolean | undefined;
161
162
  rawArguments?: string | undefined;
162
- mcpServer?: string | undefined;
163
163
  mcpToolName?: string | undefined;
164
164
  }>>;
165
165
  }, "strip", z.ZodTypeAny, {
@@ -168,9 +168,9 @@ declare const PromptItemArrayZ: z.ZodArray<z.ZodObject<{
168
168
  name: string;
169
169
  parameters: string;
170
170
  result: string;
171
+ mcpServer?: string | undefined;
171
172
  accepted?: boolean | undefined;
172
173
  rawArguments?: string | undefined;
173
- mcpServer?: string | undefined;
174
174
  mcpToolName?: string | undefined;
175
175
  } | undefined;
176
176
  date?: Date | undefined;
@@ -189,9 +189,9 @@ declare const PromptItemArrayZ: z.ZodArray<z.ZodObject<{
189
189
  name: string;
190
190
  parameters: string;
191
191
  result: string;
192
+ mcpServer?: string | undefined;
192
193
  accepted?: boolean | undefined;
193
194
  rawArguments?: string | undefined;
194
- mcpServer?: string | undefined;
195
195
  mcpToolName?: string | undefined;
196
196
  } | undefined;
197
197
  date?: Date | undefined;
@@ -109,6 +109,9 @@ function getSdk(client, withWrapper = defaultWrapper) {
109
109
  autoPrAnalysis(variables, requestHeaders, signal) {
110
110
  return withWrapper((wrappedRequestHeaders) => client.request({ document: AutoPrAnalysisDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "autoPrAnalysis", "mutation", variables);
111
111
  },
112
+ getFixWithAnswers(variables, requestHeaders, signal) {
113
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetFixWithAnswersDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getFixWithAnswers", "query", variables);
114
+ },
112
115
  GetFixReportsByRepoUrl(variables, requestHeaders, signal) {
113
116
  return withWrapper((wrappedRequestHeaders) => client.request({ document: GetFixReportsByRepoUrlDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetFixReportsByRepoUrl", "query", variables);
114
117
  },
@@ -138,7 +141,7 @@ function getSdk(client, withWrapper = defaultWrapper) {
138
141
  }
139
142
  };
140
143
  }
141
- var AiBlameInferenceType, FixQuestionInputType, Language, ManifestAction, Effort_To_Apply_Fix_Enum, Fix_Rating_Tag_Enum, Fix_Report_State_Enum, Fix_State_Enum, IssueLanguage_Enum, IssueType_Enum, Pr_Status_Enum, Project_Role_Type_Enum, Vulnerability_Report_Issue_Category_Enum, Vulnerability_Report_Issue_State_Enum, Vulnerability_Report_Issue_Tag_Enum, Vulnerability_Report_Vendor_Enum, Vulnerability_Severity_Enum, FixDetailsFragmentDoc, FixReportSummaryFieldsFragmentDoc, MeDocument, GetLastOrgAndNamedProjectDocument, GetLastOrgDocument, GetEncryptedApiTokenDocument, FixReportStateDocument, GetVulnerabilityReportPathsDocument, GetAnalysisSubscriptionDocument, GetAnalysisDocument, GetFixesDocument, GetVulByNodesMetadataDocument, GetFalsePositiveDocument, UpdateScmTokenDocument, UploadS3BucketInfoDocument, GetTracyDiffUploadUrlDocument, AnalyzeCommitForExtensionAiBlameDocument, GetAiBlameInferenceDocument, GetAiBlameAttributionPromptDocument, GetPromptSummaryDocument, UploadAiBlameInferencesInitDocument, FinalizeAiBlameInferencesUploadDocument, UploadTracyRecordsDocument, GetTracyRawDataUploadUrlDocument, DigestVulnerabilityReportDocument, SubmitVulnerabilityReportDocument, CreateCommunityUserDocument, CreateCliLoginDocument, PerformCliLoginDocument, SetQuarantineEnabledDocument, CreateProjectDocument, ValidateRepoUrlDocument, GitReferenceDocument, AutoPrAnalysisDocument, GetFixReportsByRepoUrlDocument, GetReportFixesDocument, GetLatestReportByRepoUrlDocument, UpdateDownloadedFixDataDocument, GetUserMvsAutoFixDocument, StreamBlameAiAnalysisRequestsDocument, StreamCommitBlameRequestsDocument, ScanSkillDocument, SkillVerdictsByMd5Document, defaultWrapper;
144
+ var AiBlameInferenceType, FixQuestionInputType, Language, ManifestAction, Effort_To_Apply_Fix_Enum, Fix_Rating_Tag_Enum, Fix_Report_State_Enum, Fix_State_Enum, IssueLanguage_Enum, IssueType_Enum, Pr_Status_Enum, Project_Role_Type_Enum, Vulnerability_Report_Issue_Category_Enum, Vulnerability_Report_Issue_State_Enum, Vulnerability_Report_Issue_Tag_Enum, Vulnerability_Report_Vendor_Enum, Vulnerability_Severity_Enum, FixDetailsFragmentDoc, FixReportSummaryFieldsFragmentDoc, MeDocument, GetLastOrgAndNamedProjectDocument, GetLastOrgDocument, GetEncryptedApiTokenDocument, FixReportStateDocument, GetVulnerabilityReportPathsDocument, GetAnalysisSubscriptionDocument, GetAnalysisDocument, GetFixesDocument, GetVulByNodesMetadataDocument, GetFalsePositiveDocument, UpdateScmTokenDocument, UploadS3BucketInfoDocument, GetTracyDiffUploadUrlDocument, AnalyzeCommitForExtensionAiBlameDocument, GetAiBlameInferenceDocument, GetAiBlameAttributionPromptDocument, GetPromptSummaryDocument, UploadAiBlameInferencesInitDocument, FinalizeAiBlameInferencesUploadDocument, UploadTracyRecordsDocument, GetTracyRawDataUploadUrlDocument, DigestVulnerabilityReportDocument, SubmitVulnerabilityReportDocument, CreateCommunityUserDocument, CreateCliLoginDocument, PerformCliLoginDocument, SetQuarantineEnabledDocument, CreateProjectDocument, ValidateRepoUrlDocument, GitReferenceDocument, AutoPrAnalysisDocument, GetFixWithAnswersDocument, GetFixReportsByRepoUrlDocument, GetReportFixesDocument, GetLatestReportByRepoUrlDocument, UpdateDownloadedFixDataDocument, GetUserMvsAutoFixDocument, StreamBlameAiAnalysisRequestsDocument, StreamCommitBlameRequestsDocument, ScanSkillDocument, SkillVerdictsByMd5Document, defaultWrapper;
142
145
  var init_client_generates = __esm({
143
146
  "src/features/analysis/scm/generates/client_generates.ts"() {
144
147
  "use strict";
@@ -312,6 +315,7 @@ var init_client_generates = __esm({
312
315
  IssueType_Enum2["NoReturnInFinally"] = "NO_RETURN_IN_FINALLY";
313
316
  IssueType_Enum2["NoVar"] = "NO_VAR";
314
317
  IssueType_Enum2["NullDereference"] = "NULL_DEREFERENCE";
318
+ IssueType_Enum2["OftenMisusedBooleanGetBoolean"] = "OFTEN_MISUSED_BOOLEAN_GET_BOOLEAN";
315
319
  IssueType_Enum2["OpenRedirect"] = "OPEN_REDIRECT";
316
320
  IssueType_Enum2["OverlyBroadCatch"] = "OVERLY_BROAD_CATCH";
317
321
  IssueType_Enum2["OverlyLargeRange"] = "OVERLY_LARGE_RANGE";
@@ -442,6 +446,7 @@ var init_client_generates = __esm({
442
446
  id
443
447
  confidence
444
448
  safeIssueType
449
+ safeIssueLanguage
445
450
  severityText
446
451
  gitBlameLogin
447
452
  severityValue
@@ -465,7 +470,17 @@ var init_client_generates = __esm({
465
470
  patch
466
471
  patchOriginalEncodingBase64
467
472
  questions {
473
+ key
468
474
  name
475
+ defaultValue
476
+ value
477
+ inputType
478
+ options
479
+ index
480
+ extraContext {
481
+ key
482
+ value
483
+ }
469
484
  }
470
485
  extraContext {
471
486
  extraContext {
@@ -1182,6 +1197,37 @@ var init_client_generates = __esm({
1182
1197
  error
1183
1198
  }
1184
1199
  }
1200
+ }
1201
+ `;
1202
+ GetFixWithAnswersDocument = `
1203
+ query getFixWithAnswers($fixId: uuid!, $userInput: [QuestionAnswer!]!) {
1204
+ fixData: getFix(fixId: $fixId, userInput: $userInput, loadAnswers: false) {
1205
+ __typename
1206
+ ... on FixData {
1207
+ patch
1208
+ patchOriginalEncodingBase64
1209
+ questions {
1210
+ key
1211
+ name
1212
+ defaultValue
1213
+ value
1214
+ inputType
1215
+ options
1216
+ index
1217
+ extraContext {
1218
+ key
1219
+ value
1220
+ }
1221
+ }
1222
+ extraContext {
1223
+ extraContext {
1224
+ key
1225
+ value
1226
+ }
1227
+ fixDescription
1228
+ }
1229
+ }
1230
+ }
1185
1231
  }
1186
1232
  `;
1187
1233
  GetFixReportsByRepoUrlDocument = `
@@ -1830,7 +1876,8 @@ var init_getIssueType = __esm({
1830
1876
  ["MISSING_X_FRAME_OPTIONS" /* MissingXFrameOptions */]: "Missing X-Frame-Options Header",
1831
1877
  ["IMPROPER_VALIDATION_OF_ARRAY_INDEX" /* ImproperValidationOfArrayIndex */]: "Improper Validation of Array Index",
1832
1878
  ["INCORRECT_INTEGER_CONVERSION" /* IncorrectIntegerConversion */]: "Incorrect Integer Conversion",
1833
- ["IMPROPER_CERTIFICATE_VALIDATION" /* ImproperCertificateValidation */]: "Improper Certificate Validation"
1879
+ ["IMPROPER_CERTIFICATE_VALIDATION" /* ImproperCertificateValidation */]: "Improper Certificate Validation",
1880
+ ["OFTEN_MISUSED_BOOLEAN_GET_BOOLEAN" /* OftenMisusedBooleanGetBoolean */]: "Often Misused: Boolean.getBoolean()"
1834
1881
  };
1835
1882
  issueTypeZ = z5.nativeEnum(IssueType_Enum);
1836
1883
  getIssueTypeFriendlyString = (issueType) => {
@@ -5037,7 +5084,8 @@ var fixDetailsData = {
5037
5084
  ["MISSING_X_FRAME_OPTIONS" /* MissingXFrameOptions */]: void 0,
5038
5085
  ["IMPROPER_VALIDATION_OF_ARRAY_INDEX" /* ImproperValidationOfArrayIndex */]: void 0,
5039
5086
  ["INCORRECT_INTEGER_CONVERSION" /* IncorrectIntegerConversion */]: void 0,
5040
- ["IMPROPER_CERTIFICATE_VALIDATION" /* ImproperCertificateValidation */]: void 0
5087
+ ["IMPROPER_CERTIFICATE_VALIDATION" /* ImproperCertificateValidation */]: void 0,
5088
+ ["OFTEN_MISUSED_BOOLEAN_GET_BOOLEAN" /* OftenMisusedBooleanGetBoolean */]: void 0
5041
5089
  };
5042
5090
 
5043
5091
  // src/features/analysis/scm/shared/src/commitDescriptionMarkup.ts
@@ -7437,8 +7485,16 @@ var ADO_PAT_PATTERN = {
7437
7485
  severity: "high",
7438
7486
  validator: (match) => match.length >= 52 && match.length <= 100
7439
7487
  };
7488
+ var DATADOG_APP_KEY_PATTERN = {
7489
+ type: "DATADOG_APP_KEY",
7490
+ regex: /\bddapp_[a-zA-Z0-9]{30,}\b/g,
7491
+ priority: 95,
7492
+ placeholder: "[DATADOG_APP_KEY_{n}]",
7493
+ description: "Datadog Application Key",
7494
+ severity: "high"
7495
+ };
7440
7496
  var openRedaction = new OpenRedaction({
7441
- customPatterns: [ADO_PAT_PATTERN],
7497
+ customPatterns: [ADO_PAT_PATTERN, DATADOG_APP_KEY_PATTERN],
7442
7498
  patterns: [
7443
7499
  // Core Personal Data
7444
7500
  // Removed EMAIL - causes false positives in code/test snippets (e.g. --author="Eve Author <eve@example.com>")
package/dist/index.mjs CHANGED
@@ -109,6 +109,9 @@ function getSdk(client, withWrapper = defaultWrapper) {
109
109
  autoPrAnalysis(variables, requestHeaders, signal) {
110
110
  return withWrapper((wrappedRequestHeaders) => client.request({ document: AutoPrAnalysisDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "autoPrAnalysis", "mutation", variables);
111
111
  },
112
+ getFixWithAnswers(variables, requestHeaders, signal) {
113
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetFixWithAnswersDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "getFixWithAnswers", "query", variables);
114
+ },
112
115
  GetFixReportsByRepoUrl(variables, requestHeaders, signal) {
113
116
  return withWrapper((wrappedRequestHeaders) => client.request({ document: GetFixReportsByRepoUrlDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetFixReportsByRepoUrl", "query", variables);
114
117
  },
@@ -138,7 +141,7 @@ function getSdk(client, withWrapper = defaultWrapper) {
138
141
  }
139
142
  };
140
143
  }
141
- var AiBlameInferenceType, FixQuestionInputType, Language, ManifestAction, Effort_To_Apply_Fix_Enum, Fix_Rating_Tag_Enum, Fix_Report_State_Enum, Fix_State_Enum, IssueLanguage_Enum, IssueType_Enum, Pr_Status_Enum, Project_Role_Type_Enum, Vulnerability_Report_Issue_Category_Enum, Vulnerability_Report_Issue_State_Enum, Vulnerability_Report_Issue_Tag_Enum, Vulnerability_Report_Vendor_Enum, Vulnerability_Severity_Enum, FixDetailsFragmentDoc, FixReportSummaryFieldsFragmentDoc, MeDocument, GetLastOrgAndNamedProjectDocument, GetLastOrgDocument, GetEncryptedApiTokenDocument, FixReportStateDocument, GetVulnerabilityReportPathsDocument, GetAnalysisSubscriptionDocument, GetAnalysisDocument, GetFixesDocument, GetVulByNodesMetadataDocument, GetFalsePositiveDocument, UpdateScmTokenDocument, UploadS3BucketInfoDocument, GetTracyDiffUploadUrlDocument, AnalyzeCommitForExtensionAiBlameDocument, GetAiBlameInferenceDocument, GetAiBlameAttributionPromptDocument, GetPromptSummaryDocument, UploadAiBlameInferencesInitDocument, FinalizeAiBlameInferencesUploadDocument, UploadTracyRecordsDocument, GetTracyRawDataUploadUrlDocument, DigestVulnerabilityReportDocument, SubmitVulnerabilityReportDocument, CreateCommunityUserDocument, CreateCliLoginDocument, PerformCliLoginDocument, SetQuarantineEnabledDocument, CreateProjectDocument, ValidateRepoUrlDocument, GitReferenceDocument, AutoPrAnalysisDocument, GetFixReportsByRepoUrlDocument, GetReportFixesDocument, GetLatestReportByRepoUrlDocument, UpdateDownloadedFixDataDocument, GetUserMvsAutoFixDocument, StreamBlameAiAnalysisRequestsDocument, StreamCommitBlameRequestsDocument, ScanSkillDocument, SkillVerdictsByMd5Document, defaultWrapper;
144
+ var AiBlameInferenceType, FixQuestionInputType, Language, ManifestAction, Effort_To_Apply_Fix_Enum, Fix_Rating_Tag_Enum, Fix_Report_State_Enum, Fix_State_Enum, IssueLanguage_Enum, IssueType_Enum, Pr_Status_Enum, Project_Role_Type_Enum, Vulnerability_Report_Issue_Category_Enum, Vulnerability_Report_Issue_State_Enum, Vulnerability_Report_Issue_Tag_Enum, Vulnerability_Report_Vendor_Enum, Vulnerability_Severity_Enum, FixDetailsFragmentDoc, FixReportSummaryFieldsFragmentDoc, MeDocument, GetLastOrgAndNamedProjectDocument, GetLastOrgDocument, GetEncryptedApiTokenDocument, FixReportStateDocument, GetVulnerabilityReportPathsDocument, GetAnalysisSubscriptionDocument, GetAnalysisDocument, GetFixesDocument, GetVulByNodesMetadataDocument, GetFalsePositiveDocument, UpdateScmTokenDocument, UploadS3BucketInfoDocument, GetTracyDiffUploadUrlDocument, AnalyzeCommitForExtensionAiBlameDocument, GetAiBlameInferenceDocument, GetAiBlameAttributionPromptDocument, GetPromptSummaryDocument, UploadAiBlameInferencesInitDocument, FinalizeAiBlameInferencesUploadDocument, UploadTracyRecordsDocument, GetTracyRawDataUploadUrlDocument, DigestVulnerabilityReportDocument, SubmitVulnerabilityReportDocument, CreateCommunityUserDocument, CreateCliLoginDocument, PerformCliLoginDocument, SetQuarantineEnabledDocument, CreateProjectDocument, ValidateRepoUrlDocument, GitReferenceDocument, AutoPrAnalysisDocument, GetFixWithAnswersDocument, GetFixReportsByRepoUrlDocument, GetReportFixesDocument, GetLatestReportByRepoUrlDocument, UpdateDownloadedFixDataDocument, GetUserMvsAutoFixDocument, StreamBlameAiAnalysisRequestsDocument, StreamCommitBlameRequestsDocument, ScanSkillDocument, SkillVerdictsByMd5Document, defaultWrapper;
142
145
  var init_client_generates = __esm({
143
146
  "src/features/analysis/scm/generates/client_generates.ts"() {
144
147
  "use strict";
@@ -312,6 +315,7 @@ var init_client_generates = __esm({
312
315
  IssueType_Enum2["NoReturnInFinally"] = "NO_RETURN_IN_FINALLY";
313
316
  IssueType_Enum2["NoVar"] = "NO_VAR";
314
317
  IssueType_Enum2["NullDereference"] = "NULL_DEREFERENCE";
318
+ IssueType_Enum2["OftenMisusedBooleanGetBoolean"] = "OFTEN_MISUSED_BOOLEAN_GET_BOOLEAN";
315
319
  IssueType_Enum2["OpenRedirect"] = "OPEN_REDIRECT";
316
320
  IssueType_Enum2["OverlyBroadCatch"] = "OVERLY_BROAD_CATCH";
317
321
  IssueType_Enum2["OverlyLargeRange"] = "OVERLY_LARGE_RANGE";
@@ -442,6 +446,7 @@ var init_client_generates = __esm({
442
446
  id
443
447
  confidence
444
448
  safeIssueType
449
+ safeIssueLanguage
445
450
  severityText
446
451
  gitBlameLogin
447
452
  severityValue
@@ -465,7 +470,17 @@ var init_client_generates = __esm({
465
470
  patch
466
471
  patchOriginalEncodingBase64
467
472
  questions {
473
+ key
468
474
  name
475
+ defaultValue
476
+ value
477
+ inputType
478
+ options
479
+ index
480
+ extraContext {
481
+ key
482
+ value
483
+ }
469
484
  }
470
485
  extraContext {
471
486
  extraContext {
@@ -1182,6 +1197,37 @@ var init_client_generates = __esm({
1182
1197
  error
1183
1198
  }
1184
1199
  }
1200
+ }
1201
+ `;
1202
+ GetFixWithAnswersDocument = `
1203
+ query getFixWithAnswers($fixId: uuid!, $userInput: [QuestionAnswer!]!) {
1204
+ fixData: getFix(fixId: $fixId, userInput: $userInput, loadAnswers: false) {
1205
+ __typename
1206
+ ... on FixData {
1207
+ patch
1208
+ patchOriginalEncodingBase64
1209
+ questions {
1210
+ key
1211
+ name
1212
+ defaultValue
1213
+ value
1214
+ inputType
1215
+ options
1216
+ index
1217
+ extraContext {
1218
+ key
1219
+ value
1220
+ }
1221
+ }
1222
+ extraContext {
1223
+ extraContext {
1224
+ key
1225
+ value
1226
+ }
1227
+ fixDescription
1228
+ }
1229
+ }
1230
+ }
1185
1231
  }
1186
1232
  `;
1187
1233
  GetFixReportsByRepoUrlDocument = `
@@ -1502,7 +1548,8 @@ var init_getIssueType = __esm({
1502
1548
  ["MISSING_X_FRAME_OPTIONS" /* MissingXFrameOptions */]: "Missing X-Frame-Options Header",
1503
1549
  ["IMPROPER_VALIDATION_OF_ARRAY_INDEX" /* ImproperValidationOfArrayIndex */]: "Improper Validation of Array Index",
1504
1550
  ["INCORRECT_INTEGER_CONVERSION" /* IncorrectIntegerConversion */]: "Incorrect Integer Conversion",
1505
- ["IMPROPER_CERTIFICATE_VALIDATION" /* ImproperCertificateValidation */]: "Improper Certificate Validation"
1551
+ ["IMPROPER_CERTIFICATE_VALIDATION" /* ImproperCertificateValidation */]: "Improper Certificate Validation",
1552
+ ["OFTEN_MISUSED_BOOLEAN_GET_BOOLEAN" /* OftenMisusedBooleanGetBoolean */]: "Often Misused: Boolean.getBoolean()"
1506
1553
  };
1507
1554
  issueTypeZ = z.nativeEnum(IssueType_Enum);
1508
1555
  getIssueTypeFriendlyString = (issueType) => {
@@ -4753,7 +4800,8 @@ var fixDetailsData = {
4753
4800
  ["MISSING_X_FRAME_OPTIONS" /* MissingXFrameOptions */]: void 0,
4754
4801
  ["IMPROPER_VALIDATION_OF_ARRAY_INDEX" /* ImproperValidationOfArrayIndex */]: void 0,
4755
4802
  ["INCORRECT_INTEGER_CONVERSION" /* IncorrectIntegerConversion */]: void 0,
4756
- ["IMPROPER_CERTIFICATE_VALIDATION" /* ImproperCertificateValidation */]: void 0
4803
+ ["IMPROPER_CERTIFICATE_VALIDATION" /* ImproperCertificateValidation */]: void 0,
4804
+ ["OFTEN_MISUSED_BOOLEAN_GET_BOOLEAN" /* OftenMisusedBooleanGetBoolean */]: void 0
4757
4805
  };
4758
4806
 
4759
4807
  // src/features/analysis/scm/shared/src/commitDescriptionMarkup.ts
@@ -14106,8 +14154,16 @@ var ADO_PAT_PATTERN = {
14106
14154
  severity: "high",
14107
14155
  validator: (match) => match.length >= 52 && match.length <= 100
14108
14156
  };
14157
+ var DATADOG_APP_KEY_PATTERN = {
14158
+ type: "DATADOG_APP_KEY",
14159
+ regex: /\bddapp_[a-zA-Z0-9]{30,}\b/g,
14160
+ priority: 95,
14161
+ placeholder: "[DATADOG_APP_KEY_{n}]",
14162
+ description: "Datadog Application Key",
14163
+ severity: "high"
14164
+ };
14109
14165
  var openRedaction = new OpenRedaction({
14110
- customPatterns: [ADO_PAT_PATTERN],
14166
+ customPatterns: [ADO_PAT_PATTERN, DATADOG_APP_KEY_PATTERN],
14111
14167
  patterns: [
14112
14168
  // Core Personal Data
14113
14169
  // Removed EMAIL - causes false positives in code/test snippets (e.g. --author="Eve Author <eve@example.com>")
@@ -19313,7 +19369,7 @@ function createLogger(config2) {
19313
19369
 
19314
19370
  // src/features/claude_code/hook_logger.ts
19315
19371
  var DD_RUM_TOKEN = true ? "pubf59c0182545bfb4c299175119f1abf9b" : "";
19316
- var CLI_VERSION = true ? "1.4.11" : "unknown";
19372
+ var CLI_VERSION = true ? "1.4.12" : "unknown";
19317
19373
  var NAMESPACE = "mobbdev-claude-code-hook-logs";
19318
19374
  var claudeCodeVersion;
19319
19375
  function buildDdTags() {
@@ -20801,7 +20857,14 @@ var FixExtraContextResponseSchema = z33.object({
20801
20857
  });
20802
20858
  var FixQuestionSchema = z33.object({
20803
20859
  __typename: z33.literal("FixQuestion").optional(),
20804
- name: z33.string()
20860
+ key: z33.string(),
20861
+ name: z33.string(),
20862
+ defaultValue: z33.string(),
20863
+ value: z33.string().nullable().optional(),
20864
+ inputType: z33.nativeEnum(FixQuestionInputType),
20865
+ options: z33.array(z33.string()),
20866
+ index: z33.number(),
20867
+ extraContext: z33.array(UnstructuredFixExtraContextSchema)
20805
20868
  });
20806
20869
  var FixDataSchema = z33.object({
20807
20870
  __typename: z33.literal("FixData"),
@@ -20820,6 +20883,7 @@ var McpFixSchema = z33.object({
20820
20883
  // GraphQL uses `any` type for UUID
20821
20884
  confidence: z33.number(),
20822
20885
  safeIssueType: z33.string().nullable(),
20886
+ safeIssueLanguage: z33.string().nullable().optional(),
20823
20887
  severityText: z33.string().nullable(),
20824
20888
  gitBlameLogin: z33.string().nullable().optional(),
20825
20889
  // Optional in GraphQL
@@ -20900,10 +20964,6 @@ var GetLatestReportByRepoUrlResponseSchema = z33.object({
20900
20964
  });
20901
20965
 
20902
20966
  // src/mcp/services/InteractiveFixFilter.ts
20903
- var isFilterDisabled = () => {
20904
- const raw = process.env["MOBB_MCP_DISABLE_INTERACTIVE_FILTER"];
20905
- return raw === "1" || raw === "true";
20906
- };
20907
20967
  var isInteractiveFix = (fix) => {
20908
20968
  if (fix.patchAndQuestions.__typename !== "FixData") {
20909
20969
  return false;
@@ -20918,27 +20978,46 @@ var countByRule = (ruleIds) => {
20918
20978
  }
20919
20979
  return counts;
20920
20980
  };
20981
+ var MOBB_MCP_DISABLE_INTERACTIVE_FILTER_DEFAULT = false;
20982
+ var isInteractiveRoutingDisabled = () => {
20983
+ const raw = process.env["MOBB_MCP_DISABLE_INTERACTIVE_FILTER"];
20984
+ if (!raw) return MOBB_MCP_DISABLE_INTERACTIVE_FILTER_DEFAULT;
20985
+ const normalized = raw.toLowerCase();
20986
+ return normalized === "1" || normalized === "true";
20987
+ };
20921
20988
  var partitionInteractiveFixes = (fixes) => {
20922
- if (isFilterDisabled()) {
20923
- return { applicableFixes: fixes, skippedRuleIds: [] };
20924
- }
20989
+ const disabled = isInteractiveRoutingDisabled();
20925
20990
  const applicableFixes = [];
20926
- const skippedRuleIds = [];
20991
+ const interactiveFixes = [];
20992
+ const droppedInteractive = [];
20927
20993
  for (const fix of fixes) {
20928
20994
  if (isInteractiveFix(fix)) {
20929
- skippedRuleIds.push(ruleIdFor(fix));
20995
+ if (disabled) {
20996
+ droppedInteractive.push(fix);
20997
+ } else {
20998
+ interactiveFixes.push(fix);
20999
+ }
20930
21000
  } else {
20931
21001
  applicableFixes.push(fix);
20932
21002
  }
20933
21003
  }
20934
- if (skippedRuleIds.length > 0) {
20935
- logInfo("[InteractiveFixFilter] Skipped interactive fixes", {
21004
+ if (disabled && droppedInteractive.length > 0) {
21005
+ logInfo(
21006
+ "[InteractiveFixFilter] Dropping interactive fixes (MOBB_MCP_DISABLE_INTERACTIVE_FILTER=true)",
21007
+ {
21008
+ totalFixes: fixes.length,
21009
+ droppedCount: droppedInteractive.length,
21010
+ droppedByRule: countByRule(droppedInteractive.map(ruleIdFor))
21011
+ }
21012
+ );
21013
+ } else if (interactiveFixes.length > 0) {
21014
+ logInfo("[InteractiveFixFilter] Routing interactive fixes to LLM", {
20936
21015
  totalFixes: fixes.length,
20937
- skippedCount: skippedRuleIds.length,
20938
- skippedByRule: countByRule(skippedRuleIds)
21016
+ interactiveCount: interactiveFixes.length,
21017
+ interactiveByRule: countByRule(interactiveFixes.map(ruleIdFor))
20939
21018
  });
20940
21019
  }
20941
- return { applicableFixes, skippedRuleIds };
21020
+ return { applicableFixes, interactiveFixes };
20942
21021
  };
20943
21022
 
20944
21023
  // src/mcp/services/McpGQLClient.ts
@@ -21223,7 +21302,7 @@ var McpGQLClient = class extends GQLClient {
21223
21302
  reportData,
21224
21303
  limit
21225
21304
  }) {
21226
- if (!reportData) return { applicableFixes: [], skippedRuleIds: [] };
21305
+ if (!reportData) return { applicableFixes: [], interactiveFixes: [] };
21227
21306
  const reportMetadata = {
21228
21307
  id: reportData.id,
21229
21308
  organizationId: reportData.vulnerabilityReport?.project?.organizationId,
@@ -21260,10 +21339,10 @@ var McpGQLClient = class extends GQLClient {
21260
21339
  }
21261
21340
  }
21262
21341
  const merged = Array.from(fixMap.values());
21263
- const { applicableFixes, skippedRuleIds } = partitionInteractiveFixes(merged);
21342
+ const { applicableFixes, interactiveFixes } = partitionInteractiveFixes(merged);
21264
21343
  return {
21265
21344
  applicableFixes: applicableFixes.slice(0, limit),
21266
- skippedRuleIds
21345
+ interactiveFixes: interactiveFixes.slice(0, limit)
21267
21346
  };
21268
21347
  }
21269
21348
  async updateFixesDownloadStatus(fixIds) {
@@ -21368,7 +21447,7 @@ var McpGQLClient = class extends GQLClient {
21368
21447
  reportCount: resp.fixReport?.length || 0
21369
21448
  });
21370
21449
  const latestReport = resp.fixReport?.[0] && FixReportSummarySchema.parse(resp.fixReport?.[0]);
21371
- const { applicableFixes, skippedRuleIds } = this.mergeUserAndSystemFixes({
21450
+ const { applicableFixes, interactiveFixes } = this.mergeUserAndSystemFixes({
21372
21451
  reportData: latestReport,
21373
21452
  limit
21374
21453
  });
@@ -21376,7 +21455,7 @@ var McpGQLClient = class extends GQLClient {
21376
21455
  fixReport: latestReport ? {
21377
21456
  ...latestReport,
21378
21457
  fixes: applicableFixes,
21379
- skippedRuleIds
21458
+ interactiveFixes
21380
21459
  } : null,
21381
21460
  expiredReport: resp.expiredReport?.[0] || null
21382
21461
  };
@@ -21446,17 +21525,17 @@ var McpGQLClient = class extends GQLClient {
21446
21525
  return null;
21447
21526
  }
21448
21527
  const latestReport = FixReportSummarySchema.parse(res.fixReport?.[0]);
21449
- const { applicableFixes, skippedRuleIds } = this.mergeUserAndSystemFixes({
21528
+ const { applicableFixes, interactiveFixes } = this.mergeUserAndSystemFixes({
21450
21529
  reportData: latestReport,
21451
21530
  limit
21452
21531
  });
21453
21532
  logDebug("[GraphQL] GetReportFixes response parsed", {
21454
21533
  fixes: applicableFixes,
21455
- skippedCount: skippedRuleIds.length
21534
+ interactiveCount: interactiveFixes.length
21456
21535
  });
21457
21536
  return {
21458
21537
  fixes: applicableFixes,
21459
- skippedRuleIds,
21538
+ interactiveFixes,
21460
21539
  totalCount: res.fixReport?.[0]?.filteredFixesCount?.aggregate?.count || 0,
21461
21540
  expiredReport: res.expiredReport?.[0] || null,
21462
21541
  fixReport: res.fixReport?.[0] ? {
@@ -21474,6 +21553,36 @@ var McpGQLClient = class extends GQLClient {
21474
21553
  throw e;
21475
21554
  }
21476
21555
  }
21556
+ /** Root getFix recomputes the patch; fix_by_pk.patchAndQuestions(userInput) does not (stale questions looked like cascading). */
21557
+ async getFixWithAnswers({
21558
+ fixId,
21559
+ answers
21560
+ }) {
21561
+ try {
21562
+ logDebug("[GraphQL] Calling getFixWithAnswers query", {
21563
+ fixId,
21564
+ answerCount: answers.length,
21565
+ userInput: answers
21566
+ });
21567
+ const resp = await this._clientSdk.getFixWithAnswers({
21568
+ fixId,
21569
+ userInput: answers
21570
+ });
21571
+ logDebug("[GraphQL] getFixWithAnswers successful", {
21572
+ fixId,
21573
+ responseTypename: resp.fixData?.__typename,
21574
+ remainingQuestionKeys: resp.fixData?.__typename === "FixData" ? resp.fixData.questions.map((q) => q.key) : void 0
21575
+ });
21576
+ return { fixData: resp.fixData ?? null };
21577
+ } catch (e) {
21578
+ logError("[GraphQL] getFixWithAnswers failed", {
21579
+ error: e,
21580
+ fixId,
21581
+ ...this.getErrorContext()
21582
+ });
21583
+ throw e;
21584
+ }
21585
+ }
21477
21586
  };
21478
21587
  async function createAuthenticatedMcpGQLClient({
21479
21588
  isBackgroundCall = false,
@@ -24516,6 +24625,7 @@ init_client_generates();
24516
24625
  init_configs();
24517
24626
 
24518
24627
  // src/mcp/core/prompts.ts
24628
+ init_client_generates();
24519
24629
  init_configs();
24520
24630
  function friendlyType(s) {
24521
24631
  const withoutUnderscores = s.replace(/_/g, " ");
@@ -24524,17 +24634,133 @@ function friendlyType(s) {
24524
24634
  }
24525
24635
  var noFixesReturnedForParameters = `No fixes returned for the given offset and limit parameters.
24526
24636
  `;
24527
- var skippedInteractiveFixesNotice = (skippedCount) => {
24528
- if (skippedCount <= 0) return "";
24529
- const s = skippedCount === 1 ? "" : "es";
24530
- const verb = skippedCount === 1 ? "requires" : "require";
24531
- const wasWere = skippedCount === 1 ? "was" : "were";
24637
+ var resolveQuestionText = ({
24638
+ fix,
24639
+ question
24640
+ }) => {
24641
+ const language = fix.safeIssueLanguage ?? void 0;
24642
+ const issueType = fix.safeIssueType ?? void 0;
24643
+ if (!language || !issueType) {
24644
+ return { content: question.name, description: "" };
24645
+ }
24646
+ const item = storedQuestionData_default[language]?.[issueType]?.[question.name];
24647
+ if (!item) {
24648
+ return { content: question.name, description: "" };
24649
+ }
24650
+ const args = question.extraContext.reduce(
24651
+ (acc, ctx) => {
24652
+ acc[ctx.key] = ctx.value;
24653
+ return acc;
24654
+ },
24655
+ {}
24656
+ );
24657
+ try {
24658
+ return {
24659
+ content: item.content(args) || question.name,
24660
+ description: item.description(args) || ""
24661
+ };
24662
+ } catch {
24663
+ return { content: question.name, description: "" };
24664
+ }
24665
+ };
24666
+ var formatQuestionInputContract = (question) => {
24667
+ switch (question.inputType) {
24668
+ case "SELECT" /* Select */:
24669
+ return `Pick exactly ONE of: ${question.options.map((o) => `\`${o}\``).join(", ")}`;
24670
+ case "NUMBER" /* Number */:
24671
+ return 'Provide a numeric string (e.g. "60").';
24672
+ case "TEXT" /* Text */:
24673
+ return "Provide a free-form string (or an empty string to accept the default).";
24674
+ }
24675
+ };
24676
+ var renderInteractiveFix = (fix, index) => {
24677
+ if (fix.patchAndQuestions.__typename !== "FixData") return "";
24678
+ const { questions, extraContext } = fix.patchAndQuestions;
24679
+ const vulnerabilityType = friendlyType(fix.safeIssueType ?? "Unknown");
24680
+ const questionsBlock = questions.slice().sort((a, b) => a.index - b.index).map((q, qIdx) => {
24681
+ const { content, description } = resolveQuestionText({ fix, question: q });
24682
+ const desc = description ? `
24683
+ *Why it matters:* ${description}` : "";
24684
+ const defaultLine = q.defaultValue ? `
24685
+ *Default if you don't decide:* \`${q.defaultValue}\`` : "";
24686
+ return `${qIdx + 1}. **\`${q.key}\`** \u2014 ${content}
24687
+ *Input:* ${formatQuestionInputContract(q)}${defaultLine}${desc}`;
24688
+ }).join("\n\n");
24689
+ return `### Interactive fix ${index + 1}: ${vulnerabilityType}
24690
+
24691
+ **Fix id:** \`${fix.id}\`
24692
+ **Description:** ${extraContext?.fixDescription || "Security vulnerability fix that requires answers before it can be tailored."}
24693
+
24694
+ **Questions you must answer before this fix can be applied:**
24695
+
24696
+ ${questionsBlock}
24697
+ `;
24698
+ };
24699
+ var interactiveFixesPrompt = ({
24700
+ interactiveFixes,
24701
+ repositoryPath
24702
+ }) => {
24703
+ if (interactiveFixes.length === 0) return "";
24704
+ const fixesBlock = interactiveFixes.map((fix, idx) => renderInteractiveFix(fix, idx)).join("\n---\n");
24532
24705
  return `
24533
- ## Skipped fixes
24706
+ ## Interactive fixes \u2014 decide from code, then apply or abstain
24707
+
24708
+ The Mobb backend produced ${interactiveFixes.length} fix${interactiveFixes.length === 1 ? "" : "es"} that need context before the patch can be tailored. **Infer answers only from the real code**: touched files, imports, framework, and how untrusted data flows (SSR/XSS/PT/SSRF, etc.). **Do NOT ask the end user** \u2014 use tooling/read-only repo inspection only.
24709
+
24710
+ ### CRITICAL INSTRUCTIONS \u2014 READ CAREFULLY
24711
+
24712
+ 1. **Defaults are hints from Mobb, not autopilot.** The line *Default if you don't decide* shows what the backend would fall back to. Prefer answers **consistent with the codebase**. Do **not** pick an answer **only** because it equals that default \u2014 a mismatched default can produce the wrong tailored patch.
24713
+ 2. **Time budget \u2014 ~5 seconds per interactive fix, as one shared pool.** With ${interactiveFixes.length} interactive fix${interactiveFixes.length === 1 ? "" : "es"} above, spend **at most ~${interactiveFixes.length * 5} seconds total** inspecting the codebase before re-calling \`${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES}\` with \`interactiveAnswers\`. The budget is a pool \u2014 one fix may take 8s if it's genuinely ambiguous while another takes 2s if the call site is obvious, as long as the total stays near the bound. If a fix is still uncertain when its share runs out, **omit it from \`interactiveAnswers\`** (rule 4) rather than over-deliberating.
24714
+ 3. **Confidence required.** Include in \`interactiveAnswers\` **only** fixes where your answers are justified by what you see in code (exact SELECT strings where applicable).
24715
+ 4. **Abstain rather than guess.** If you **cannot** justify any responsible answer after inspecting the code (ambiguous flows, missing callers, isomorphic bundles, unclear SSRF allowlists, etc.), **omit that fix id entirely** from \`interactiveAnswers\`. Tell the user in prose what was skipped and why so they can fix manually or follow up later \u2014 **do not fabricate answers**.
24716
+ 5. **Skipping everything.** If you skip **all** interactive fixes, still call **\`${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES}\`** once with \`"interactiveAnswers": []\` (empty array) together with \`path\`. That acknowledges abstention **without** starting a new scan. Omitting \`interactiveAnswers\` entirely falls back to scan mode instead \u2014 avoid that when you intend purely to abstain.
24717
+ 6. **Use exact option strings for SELECT questions.** Copy them character-for-character from the option list. Do **not** append explanation, rationale, or commentary to the value \u2014 that turns the answer into a non-matching string and the backend silently falls back to its default.
24718
+ 7. **Use the \`key\` verbatim, not the human label.** Each question shows a backtick-quoted key (e.g. \`is_server_side_code\`, \`tainted_term_type\`). That exact string goes into \`answers[].key\`. The display name (e.g. \`isServerSideCode\`, \`taintedTermType\`) is for humans only \u2014 sending it as a key means the backend won't recognise the answer and falls back to the default.
24719
+ 8. **After the tool call**, summarize: fixes applied with reasoning; fixes skipped (confidence/abstention/time-budget); tool failures.
24720
+
24721
+ ### Decision heuristics for common questions
24722
+
24723
+ (Keys shown in snake_case \u2014 copy them verbatim from each fix's question block.)
24724
+
24725
+ - **\`is_server_side_code\` (XSS)** \u2014 \`yes\` when server-render or Node HTTP handlers dominate; \`no\` when clearly browser-only. If bundle/context is genuinely ambiguous after inspection, **omit** this fix from \`interactiveAnswers\`.
24726
+ - **\`tainted_term_type\` (Path Traversal)** \u2014 match how user input is joined/consumed (single filename vs path segments vs absolute). If usage cannot be determined, **omit**.
24727
+ - **\`iframe_restrictions\`** \u2014 strict sandbox (\`""\`) unless embedded content clearly needs listed capabilities.
24534
24728
 
24535
- ${skippedCount} fix${s} ${verb} user input that is not available over MCP and ${wasWere} skipped. Mention this to the user when summarizing results.
24729
+ ### How to call \`${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES}\`
24730
+
24731
+ Apply fixes you are confident about (subset allowed):
24732
+
24733
+ \`\`\`json
24734
+ {
24735
+ "path": "${repositoryPath}",
24736
+ "interactiveAnswers": [
24737
+ {
24738
+ "fixId": "<fix id from below>",
24739
+ "answers": [
24740
+ { "key": "<question key, exactly as shown>", "value": "<your decided value>" }
24741
+ ]
24742
+ }
24743
+ ]
24744
+ }
24745
+ \`\`\`
24746
+
24747
+ Explicit abstention \u2014 skip **all** interactive fixes without rescanning:
24748
+
24749
+ \`\`\`json
24750
+ {
24751
+ "path": "${repositoryPath}",
24752
+ "interactiveAnswers": []
24753
+ }
24754
+ \`\`\`
24755
+
24756
+ ${fixesBlock}
24536
24757
  `;
24537
24758
  };
24759
+ var interactiveAnswersAbstainAllToolResponse = `## Interactive fixes \u2014 none applied
24760
+
24761
+ \`interactiveAnswers\` was an empty array: **no** tailored patches were requested and **no** scan was run.
24762
+
24763
+ State clearly for the user which interactive fixes you **skipped**, why the code did not support a confident answer, and that they can apply those manually or re-run after clarifying the codebase.`;
24538
24764
  var noFixesReturnedForParametersWithGuidance = ({
24539
24765
  offset,
24540
24766
  limit,
@@ -24593,9 +24819,13 @@ var applyFixesPrompt = ({
24593
24819
  currentTool,
24594
24820
  offset,
24595
24821
  limit,
24596
- gqlClient
24822
+ gqlClient,
24823
+ hasInteractiveFixes = false
24597
24824
  }) => {
24598
24825
  if (fixes.length === 0) {
24826
+ if (hasInteractiveFixes) {
24827
+ return "";
24828
+ }
24599
24829
  if (totalCount > 0) {
24600
24830
  return noFixesReturnedForParametersWithGuidance({
24601
24831
  offset,
@@ -24782,11 +25012,16 @@ var fixesFoundPrompt = ({
24782
25012
  offset,
24783
25013
  limit,
24784
25014
  gqlClient,
24785
- skippedInteractiveCount = 0
25015
+ interactiveFixes = [],
25016
+ repositoryPath
24786
25017
  }) => {
24787
25018
  const totalFixes = fixReport.filteredFixesCount.aggregate?.count || 0;
25019
+ const interactiveBlock = interactiveFixesPrompt({
25020
+ interactiveFixes,
25021
+ repositoryPath
25022
+ });
24788
25023
  if (totalFixes === 0) {
24789
- return noFixesAvailablePrompt + skippedInteractiveFixesNotice(skippedInteractiveCount);
25024
+ return noFixesAvailablePrompt + interactiveBlock;
24790
25025
  }
24791
25026
  const criticalFixes = fixReport.CRITICAL?.aggregate?.count || 0;
24792
25027
  const highFixes = fixReport.HIGH?.aggregate?.count || 0;
@@ -24828,8 +25063,9 @@ ${applyFixesPrompt({
24828
25063
  currentTool: MCP_TOOL_FETCH_AVAILABLE_FIXES,
24829
25064
  offset,
24830
25065
  limit,
24831
- gqlClient
24832
- })}${skippedInteractiveFixesNotice(skippedInteractiveCount)}`;
25066
+ gqlClient,
25067
+ hasInteractiveFixes: interactiveFixes.length > 0
25068
+ })}${interactiveBlock}`;
24833
25069
  };
24834
25070
  var nextStepsPrompt = ({ scannedFiles }) => `
24835
25071
  ### \u{1F4C1} Scanned Files
@@ -24876,10 +25112,15 @@ var fixesPrompt = ({
24876
25112
  scannedFiles,
24877
25113
  limit,
24878
25114
  gqlClient,
24879
- skippedInteractiveCount = 0
25115
+ interactiveFixes = [],
25116
+ repositoryPath
24880
25117
  }) => {
25118
+ const interactiveBlock = interactiveFixesPrompt({
25119
+ interactiveFixes,
25120
+ repositoryPath
25121
+ });
24881
25122
  if (totalCount === 0) {
24882
- return noFixesFoundPrompt({ scannedFiles }) + skippedInteractiveFixesNotice(skippedInteractiveCount);
25123
+ return noFixesFoundPrompt({ scannedFiles }) + interactiveBlock;
24883
25124
  }
24884
25125
  const shownCount = fixes.length;
24885
25126
  const nextOffset = offset + shownCount;
@@ -24895,9 +25136,10 @@ ${applyFixesPrompt({
24895
25136
  currentTool: MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES,
24896
25137
  offset,
24897
25138
  limit,
24898
- gqlClient
25139
+ gqlClient,
25140
+ hasInteractiveFixes: interactiveFixes.length > 0
24899
25141
  })}
24900
- ${skippedInteractiveFixesNotice(skippedInteractiveCount)}
25142
+ ${interactiveBlock}
24901
25143
  ${nextStepsPrompt({ scannedFiles })}
24902
25144
  `;
24903
25145
  };
@@ -24971,7 +25213,8 @@ var freshFixesPrompt = ({
24971
25213
  fixes,
24972
25214
  limit,
24973
25215
  gqlClient,
24974
- skippedInteractiveCount = 0
25216
+ interactiveFixes = [],
25217
+ repositoryPath
24975
25218
  }) => {
24976
25219
  return `Here are the fresh fixes to the vulnerabilities discovered by Mobb MCP
24977
25220
 
@@ -24984,9 +25227,10 @@ ${applyFixesPrompt({
24984
25227
  currentTool: MCP_TOOL_FETCH_AVAILABLE_FIXES,
24985
25228
  offset: 0,
24986
25229
  limit,
24987
- gqlClient
25230
+ gqlClient,
25231
+ hasInteractiveFixes: interactiveFixes.length > 0
24988
25232
  })}
24989
- ${skippedInteractiveFixesNotice(skippedInteractiveCount)}
25233
+ ${interactiveFixesPrompt({ interactiveFixes, repositoryPath })}
24990
25234
  `;
24991
25235
  };
24992
25236
  function extractTargetFileFromPatch(patch) {
@@ -25006,7 +25250,8 @@ function formatSeverity(severityText, severityValue) {
25006
25250
  var appliedFixesSummaryPrompt = ({
25007
25251
  fixes,
25008
25252
  gqlClient,
25009
- skippedInteractiveCount = 0
25253
+ interactiveFixes = [],
25254
+ repositoryPath
25010
25255
  }) => {
25011
25256
  const fixIds = fixes.map((fix) => fix.id);
25012
25257
  void gqlClient.updateFixesDownloadStatus(fixIds);
@@ -25041,7 +25286,7 @@ ${fixes.map((fix, index) => {
25041
25286
  ${continuousMonitoringSection}
25042
25287
 
25043
25288
  ${autoFixSettingsSection}
25044
- ${skippedInteractiveFixesNotice(skippedInteractiveCount)}
25289
+ ${interactiveFixesPrompt({ interactiveFixes, repositoryPath })}
25045
25290
  ## \u{1F4CB} Next Steps
25046
25291
 
25047
25292
  1. **Review the changes** - Check the modified files to understand what was fixed
@@ -25948,6 +26193,7 @@ var LocalMobbFolderService = class {
25948
26193
  };
25949
26194
 
25950
26195
  // src/mcp/services/PatchApplicationService.ts
26196
+ init_client_generates();
25951
26197
  init_configs();
25952
26198
  import {
25953
26199
  existsSync as existsSync6,
@@ -26513,7 +26759,8 @@ var PatchApplicationService = class {
26513
26759
  repositoryPath,
26514
26760
  scanStartTime,
26515
26761
  gqlClient,
26516
- scanContext
26762
+ scanContext,
26763
+ downloadSource = "AUTO_MVS" /* AutoMvs */
26517
26764
  }) {
26518
26765
  const appliedFixes = [];
26519
26766
  const failedFixes = [];
@@ -26572,20 +26819,26 @@ var PatchApplicationService = class {
26572
26819
  if (appliedFixes.length > 0 && gqlClient) {
26573
26820
  try {
26574
26821
  const appliedFixIds = appliedFixes.map((fix) => fix.id).filter(Boolean);
26575
- await gqlClient.updateAutoAppliedFixesStatus(appliedFixIds);
26822
+ if (downloadSource === "MCP" /* Mcp */) {
26823
+ await gqlClient.updateFixesDownloadStatus(appliedFixIds);
26824
+ } else {
26825
+ await gqlClient.updateAutoAppliedFixesStatus(appliedFixIds);
26826
+ }
26576
26827
  logDebug(
26577
- `[${scanContext}] Successfully updated download status for auto-applied fixes`,
26828
+ `[${scanContext}] Successfully updated download status for applied fixes`,
26578
26829
  {
26579
26830
  appliedFixIds,
26580
- count: appliedFixIds.length
26831
+ count: appliedFixIds.length,
26832
+ downloadSource
26581
26833
  }
26582
26834
  );
26583
26835
  } catch (error) {
26584
26836
  logError(
26585
- `[${scanContext}] Failed to update download status for auto-applied fixes`,
26837
+ `[${scanContext}] Failed to update download status for applied fixes`,
26586
26838
  {
26587
26839
  error: error instanceof Error ? error.message : String(error),
26588
- appliedFixCount: appliedFixes.length
26840
+ appliedFixCount: appliedFixes.length,
26841
+ downloadSource
26589
26842
  }
26590
26843
  );
26591
26844
  }
@@ -27327,6 +27580,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
27327
27580
  __publicField(this, "path", "");
27328
27581
  __publicField(this, "filesLastScanned", {});
27329
27582
  __publicField(this, "freshFixes", []);
27583
+ __publicField(this, "interactiveFixes", []);
27330
27584
  __publicField(this, "reportedFixes", []);
27331
27585
  __publicField(this, "intervalId", null);
27332
27586
  __publicField(this, "isInitialScanComplete", false);
@@ -27348,6 +27602,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
27348
27602
  reset() {
27349
27603
  this.filesLastScanned = {};
27350
27604
  this.freshFixes = [];
27605
+ this.interactiveFixes = [];
27351
27606
  this.reportedFixes = [];
27352
27607
  this.hasAuthenticationFailed = false;
27353
27608
  this.fullScanPathsScanned = configStore.get("fullScanPathsScanned") || [];
@@ -27433,6 +27688,16 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
27433
27688
  const newFixes = fixes?.fixes?.filter(
27434
27689
  (fix) => !this.isFixAlreadyReported(fix)
27435
27690
  );
27691
+ const newInteractiveFixes = fixes?.interactiveFixes?.filter(
27692
+ (fix) => !this.isFixAlreadyReported(fix)
27693
+ ) ?? [];
27694
+ if (newInteractiveFixes.length > 0) {
27695
+ this.interactiveFixes.push(...newInteractiveFixes);
27696
+ logInfo(
27697
+ `[${scanContext}] Buffered ${newInteractiveFixes.length} interactive fixes for next response`,
27698
+ { totalBuffered: this.interactiveFixes.length }
27699
+ );
27700
+ }
27436
27701
  logInfo(
27437
27702
  `[${scanContext}] Security fixes retrieved, total: ${fixes?.fixes?.length || 0}, new: ${newFixes?.length || 0}`
27438
27703
  );
@@ -27862,7 +28127,9 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
27862
28127
  return freshFixesPrompt({
27863
28128
  fixes: freshFixes,
27864
28129
  limit: MCP_DEFAULT_LIMIT,
27865
- gqlClient: this.gqlClient
28130
+ gqlClient: this.gqlClient,
28131
+ interactiveFixes: this.interactiveFixes.splice(0, MCP_DEFAULT_LIMIT),
28132
+ repositoryPath: this.path
27866
28133
  });
27867
28134
  }
27868
28135
  logInfo(`[${scanContext}] No fresh fixes to report`);
@@ -27876,7 +28143,9 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
27876
28143
  );
27877
28144
  return appliedFixesSummaryPrompt({
27878
28145
  fixes: appliedFixesToShow,
27879
- gqlClient: this.gqlClient
28146
+ gqlClient: this.gqlClient,
28147
+ interactiveFixes: this.interactiveFixes.splice(0, MCP_DEFAULT_LIMIT),
28148
+ repositoryPath: this.path
27880
28149
  });
27881
28150
  }
27882
28151
  logInfo(`[${scanContext}] No applied fixes to report`);
@@ -27983,6 +28252,7 @@ var _FetchAvailableFixesService = class _FetchAvailableFixesService {
27983
28252
  }
27984
28253
  async checkForAvailableFixes({
27985
28254
  repoUrl,
28255
+ repositoryPath,
27986
28256
  limit = MCP_DEFAULT_LIMIT,
27987
28257
  offset,
27988
28258
  fileFilter
@@ -28020,7 +28290,8 @@ var _FetchAvailableFixesService = class _FetchAvailableFixesService {
28020
28290
  offset: effectiveOffset,
28021
28291
  limit,
28022
28292
  gqlClient,
28023
- skippedInteractiveCount: fixReport.skippedRuleIds?.length ?? 0
28293
+ interactiveFixes: fixReport.interactiveFixes ?? [],
28294
+ repositoryPath
28024
28295
  });
28025
28296
  this.currentOffset = effectiveOffset + (fixReport.fixes?.length || 0);
28026
28297
  return prompt;
@@ -28162,6 +28433,7 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
28162
28433
  }
28163
28434
  const fixResult = await this.availableFixesService.checkForAvailableFixes({
28164
28435
  repoUrl: originUrl,
28436
+ repositoryPath: path37,
28165
28437
  limit: args.limit,
28166
28438
  offset: args.offset,
28167
28439
  fileFilter: actualFileFilter
@@ -28265,6 +28537,7 @@ import z45 from "zod";
28265
28537
  init_configs();
28266
28538
 
28267
28539
  // src/mcp/tools/scanAndFixVulnerabilities/ScanAndFixVulnerabilitiesService.ts
28540
+ init_client_generates();
28268
28541
  init_configs();
28269
28542
  var _ScanAndFixVulnerabilitiesService = class _ScanAndFixVulnerabilitiesService {
28270
28543
  constructor() {
@@ -28356,7 +28629,8 @@ var _ScanAndFixVulnerabilitiesService = class _ScanAndFixVulnerabilitiesService
28356
28629
  scannedFiles: [...fileList],
28357
28630
  limit: effectiveLimit,
28358
28631
  gqlClient: this.gqlClient,
28359
- skippedInteractiveCount: fixes.skippedRuleIds.length
28632
+ interactiveFixes: fixes.interactiveFixes,
28633
+ repositoryPath
28360
28634
  });
28361
28635
  this.currentOffset = effectiveOffset + (fixes.fixes?.length || 0);
28362
28636
  return prompt;
@@ -28401,12 +28675,164 @@ var _ScanAndFixVulnerabilitiesService = class _ScanAndFixVulnerabilitiesService
28401
28675
  return {
28402
28676
  fixes: fixes?.fixes || [],
28403
28677
  totalCount: fixes?.totalCount || 0,
28404
- skippedRuleIds: fixes?.skippedRuleIds || []
28678
+ interactiveFixes: fixes?.interactiveFixes || []
28405
28679
  };
28406
28680
  }
28681
+ /** Applies patches from interactiveAnswers only (no scan). */
28682
+ async applyInteractiveAnswers({
28683
+ interactiveAnswers,
28684
+ repositoryPath
28685
+ }) {
28686
+ this.gqlClient = await this.initializeGqlClient();
28687
+ logInfo(
28688
+ `Applying ${interactiveAnswers.length} interactive fix(es) with LLM-supplied answers`,
28689
+ { repositoryPath }
28690
+ );
28691
+ const applied = [];
28692
+ const failed = [];
28693
+ const skipped = [];
28694
+ for (const entry of interactiveAnswers) {
28695
+ try {
28696
+ const { fixData } = await this.gqlClient.getFixWithAnswers({
28697
+ fixId: entry.fixId,
28698
+ answers: entry.answers
28699
+ });
28700
+ if (!fixData) {
28701
+ failed.push({
28702
+ fixId: entry.fixId,
28703
+ reason: "Fix not found on the server (may have expired)"
28704
+ });
28705
+ continue;
28706
+ }
28707
+ if (fixData.__typename !== "FixData") {
28708
+ failed.push({
28709
+ fixId: entry.fixId,
28710
+ reason: `Backend returned ${fixData.__typename} \u2014 could not produce a patch with the supplied answers`
28711
+ });
28712
+ continue;
28713
+ }
28714
+ if (!fixData.patch) {
28715
+ failed.push({
28716
+ fixId: entry.fixId,
28717
+ reason: "Backend returned FixData with no patch \u2014 answers did not yield an applicable fix"
28718
+ });
28719
+ continue;
28720
+ }
28721
+ const sentByKey = new Map(entry.answers.map((a) => [a.key, a.value]));
28722
+ const invalidSelectAnswers = [];
28723
+ for (const q of fixData.questions) {
28724
+ if (q.inputType !== "SELECT" /* Select */) continue;
28725
+ const sentValue = sentByKey.get(q.key);
28726
+ if (sentValue === void 0) continue;
28727
+ if (!q.options.includes(sentValue)) {
28728
+ invalidSelectAnswers.push({
28729
+ key: q.key,
28730
+ sentValue,
28731
+ options: [...q.options]
28732
+ });
28733
+ }
28734
+ }
28735
+ if (invalidSelectAnswers.length > 0) {
28736
+ skipped.push({
28737
+ fixId: entry.fixId,
28738
+ invalidSelectAnswers
28739
+ });
28740
+ continue;
28741
+ }
28742
+ const newPendingKeys = fixData.questions.map((q) => q.key).filter((k) => !sentByKey.has(k));
28743
+ const mcpFix = McpFixSchema.parse({
28744
+ __typename: "fix",
28745
+ id: entry.fixId,
28746
+ confidence: 0,
28747
+ safeIssueType: null,
28748
+ safeIssueLanguage: null,
28749
+ severityText: null,
28750
+ severityValue: null,
28751
+ vulnerabilityReportIssues: [],
28752
+ patchAndQuestions: fixData
28753
+ });
28754
+ const result = await PatchApplicationService.applyFixes({
28755
+ fixes: [mcpFix],
28756
+ repositoryPath,
28757
+ gqlClient: this.gqlClient,
28758
+ scanContext: ScanContext.USER_REQUEST,
28759
+ downloadSource: "MCP" /* Mcp */
28760
+ });
28761
+ if (result.appliedFixes.length > 0) {
28762
+ const targetFile = extractTargetFile(fixData.patch) ?? "unknown file";
28763
+ applied.push({
28764
+ fixId: entry.fixId,
28765
+ targetFile,
28766
+ newPendingKeys
28767
+ });
28768
+ } else {
28769
+ failed.push({
28770
+ fixId: entry.fixId,
28771
+ reason: result.failedFixes[0]?.error ?? "patch application failed"
28772
+ });
28773
+ }
28774
+ } catch (error) {
28775
+ failed.push({
28776
+ fixId: entry.fixId,
28777
+ reason: error.message
28778
+ });
28779
+ }
28780
+ }
28781
+ return formatApplyAnswersSummary({ applied, failed, skipped });
28782
+ }
28407
28783
  };
28408
28784
  __publicField(_ScanAndFixVulnerabilitiesService, "instance");
28409
28785
  var ScanAndFixVulnerabilitiesService = _ScanAndFixVulnerabilitiesService;
28786
+ function extractTargetFile(patch) {
28787
+ const match = patch.match(/^\+\+\+ b\/(.+)$/m);
28788
+ return match?.[1] ?? null;
28789
+ }
28790
+ function formatApplyAnswersSummary({
28791
+ applied,
28792
+ failed,
28793
+ skipped
28794
+ }) {
28795
+ const sections = [];
28796
+ if (applied.length > 0) {
28797
+ sections.push(
28798
+ `## \u2705 Applied ${applied.length} fix${applied.length === 1 ? "" : "es"}
28799
+
28800
+ ` + applied.map((a) => {
28801
+ const hint = a.newPendingKeys.length > 0 ? `
28802
+ \u26A0\uFE0F The backend returned additional question key(s) we didn't send: [${a.newPendingKeys.map((k) => `\`${k}\``).join(
28803
+ ", "
28804
+ )}]. This is either (a) a true cascading question \u2014 re-call \`scan_and_fix_vulnerabilities\` with those added to \`interactiveAnswers\` if you have a confident answer; or (b) the key we sent was wrong (e.g. camelCase vs snake_case) and the backend fell back to its default \u2014 copy the echoed key verbatim and retry. The patch above was already applied using defaults.` : "";
28805
+ return `- **\`${a.fixId}\`** \u2192 \`${a.targetFile}\`${hint}`;
28806
+ }).join("\n")
28807
+ );
28808
+ }
28809
+ if (skipped.length > 0) {
28810
+ sections.push(
28811
+ `## \u23ED\uFE0F Skipped ${skipped.length} fix${skipped.length === 1 ? "" : "es"} \u2014 invalid SELECT answer value(s)
28812
+
28813
+ ` + skipped.map((s) => {
28814
+ const detail = s.invalidSelectAnswers.map(
28815
+ (a) => `\`${a.key}\` got \`"${a.sentValue}"\` \u2014 allowed options: [${a.options.map((o) => `\`"${o}"\``).join(", ")}]`
28816
+ ).join("; ");
28817
+ return `- **\`${s.fixId}\`** \u2014 ${detail}
28818
+ The file was **not modified**. Re-call \`scan_and_fix_vulnerabilities\` with one of the exact allowed option strings (copy character-for-character, no commentary appended) or omit this fix entirely if no option is justified by the code.`;
28819
+ }).join("\n") + `
28820
+
28821
+ This guardrail exists to prevent the backend from silently falling back to its default sanitizer for an answer it didn't recognize \u2014 which could apply a semantically-wrong patch and break legitimate code paths.`
28822
+ );
28823
+ }
28824
+ if (failed.length > 0) {
28825
+ sections.push(
28826
+ `## \u274C Failed
28827
+
28828
+ ` + failed.map((f) => `- **\`${f.fixId}\`** \u2014 ${f.reason}`).join("\n")
28829
+ );
28830
+ }
28831
+ if (sections.length === 0) {
28832
+ return "No fixes were processed.";
28833
+ }
28834
+ return sections.join("\n\n");
28835
+ }
28410
28836
 
28411
28837
  // src/mcp/tools/scanAndFixVulnerabilities/ScanAndFixVulnerabilitiesTool.ts
28412
28838
  var ScanAndFixVulnerabilitiesTool = class extends BaseTool {
@@ -28414,13 +28840,23 @@ var ScanAndFixVulnerabilitiesTool = class extends BaseTool {
28414
28840
  super();
28415
28841
  __publicField(this, "name", MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES);
28416
28842
  __publicField(this, "displayName", "Scan and Fix Vulnerabilities");
28417
- // A detailed description to guide the LLM on when and how to invoke this tool.
28418
- __publicField(this, "description", `Scans a given local repository for security vulnerabilities and returns auto-generated code fixes.
28843
+ __publicField(this, "description", `Scans a given local repository for security vulnerabilities, applies the auto-fixable ones, and surfaces any fix that needs your input as an "Interactive fix". Re-invoke with "interactiveAnswers" to apply those.
28844
+
28845
+ Two modes of operation:
28846
+
28847
+ A) SCAN MODE (default \u2014 interactiveAnswers omitted)
28848
+ - Scans changed/recent files at "path"
28849
+ - Auto-applies fixes that need no input
28850
+ - Returns "Interactive fix" entries for fixes that need decisions; you (the AI) decide answers from the surrounding code
28851
+
28852
+ B) APPLY-WITH-ANSWERS MODE (interactiveAnswers field supplied \u2014 array may be empty or partial)
28853
+ - SKIPS scanning entirely (does NOT fall back to scan mode just because some fixes were skipped)
28854
+ - Include ONLY fixes where answers are justified by code/context; omit fix IDs you are not confident about
28855
+ - Empty array []: abstain from applying ALL interactive fixes (no patches fetched \u2014 summarize skips for the user)
28419
28856
 
28420
28857
  When to invoke:
28421
- \u2022 Use when the user explicitly asks to "scan for vulnerabilities", "run a security check", or "test for security issues" in a local repository.
28422
- \u2022 The repository must exist on disk; supply its absolute path with the required "path" argument.
28423
- \u2022 Ideal after the user makes code changes (added/modified/staged files) but before committing, or whenever they request a full rescan.
28858
+ \u2022 Mode A \u2014 when the user asks to "scan for vulnerabilities", "run a security check", or after they make code changes.
28859
+ \u2022 Mode B \u2014 immediately after Mode A returns interactive fixes; pass confident answers only; use [] only when abstaining from every interactive fix.
28424
28860
 
28425
28861
  How to invoke:
28426
28862
  \u2022 Required argument:
@@ -28430,25 +28866,32 @@ How to invoke:
28430
28866
  \u2013 limit (number): maximum number of fixes to include in the response.
28431
28867
  \u2013 maxFiles (number): maximum number of files to scan (default: ${MCP_DEFAULT_MAX_FILES_TO_SCAN}). Provide this value to increase the scope of the scan.
28432
28868
  \u2013 rescan (boolean): true to force a complete rescan even if cached results exist.
28869
+ \u2013 interactiveAnswers (array): triggers Mode B. Each entry: { fixId, answers: [{ key, value }] }. SELECT values MUST be exact strings from the option list. Omit fixes you cannot answer confidently. Use [] to abstain from all interactive fixes without rescanning.
28433
28870
 
28434
- Behaviour:
28435
- \u2022 If the directory is a valid Git repository, the tool scans the changed files in the repository. If there are no changes, it scans the files included in the las commit.
28871
+ Behaviour (Mode A):
28872
+ \u2022 If the directory is a valid Git repository, the tool scans the changed files in the repository. If there are no changes, it scans the files included in the last commit.
28436
28873
  \u2022 If the directory is not a valid Git repository, the tool falls back to scanning recently changed files in the folder.
28437
28874
  \u2022 If maxFiles is provided, the tool scans the maxFiles most recently changed files in the repository.
28438
- \u2022 By default, only new, modified, or staged files are scanned; if none are found, it checks recently changed files.
28439
- \u2022 The tool NEVER commits or pushes changes; it only returns proposed diffs/fixes as text.
28875
+ \u2022 The tool NEVER commits or pushes changes.
28440
28876
 
28441
28877
  Return value:
28442
- The response is an object with a single "content" array containing one text element. The text is either:
28443
- \u2022 A human-readable summary of the fixes / patches, or
28444
- \u2022 A diagnostic or error message if the scan fails or finds nothing to fix.
28878
+ A "content" array with one text element. Either a human-readable summary of fixes/patches, an interactive-fix prompt, an apply-with-answers result, or an error message.
28445
28879
 
28446
- Example payload:
28880
+ Example payload (Mode A):
28881
+ { "path": "/home/user/my-project", "limit": 20, "maxFiles": 50 }
28882
+
28883
+ Example payload (Mode B \u2014 subset or abstain):
28447
28884
  {
28448
28885
  "path": "/home/user/my-project",
28449
- "limit": 20,
28450
- "maxFiles": 50,
28451
- "rescan": false
28886
+ "interactiveAnswers": [
28887
+ { "fixId": "abc-123", "answers": [{ "key": "isServerSideCode", "value": "yes" }] }
28888
+ ]
28889
+ }
28890
+
28891
+ Example payload (Mode B \u2014 abstain from every interactive fix, no rescan):
28892
+ {
28893
+ "path": "/home/user/my-project",
28894
+ "interactiveAnswers": []
28452
28895
  }`);
28453
28896
  __publicField(this, "hasAuthentication", true);
28454
28897
  __publicField(this, "inputValidationSchema", z45.object({
@@ -28463,6 +28906,21 @@ Example payload:
28463
28906
  rescan: z45.boolean().optional().describe("Optional whether to rescan the repository"),
28464
28907
  scanRecentlyChangedFiles: z45.boolean().optional().describe(
28465
28908
  "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."
28909
+ ),
28910
+ interactiveAnswers: z45.array(
28911
+ z45.object({
28912
+ fixId: z45.string().min(1).describe('Fix id from a previous "Interactive fix" prompt block.'),
28913
+ answers: z45.array(
28914
+ z45.object({
28915
+ key: z45.string().min(1).describe("FixQuestion key."),
28916
+ value: z45.string().describe(
28917
+ "For SELECT questions MUST be one of the listed options; for TEXT/NUMBER, a free-form value."
28918
+ )
28919
+ })
28920
+ ).min(1)
28921
+ })
28922
+ ).optional().describe(
28923
+ "When supplied (including []), SKIPS scanning. Non-empty: apply each listed interactive fix. Empty []: abstain from all interactive fixes \u2014 no patches applied. Omit entirely for scan mode."
28466
28924
  )
28467
28925
  }));
28468
28926
  __publicField(this, "inputSchema", {
@@ -28491,6 +28949,34 @@ Example payload:
28491
28949
  scanRecentlyChangedFiles: {
28492
28950
  type: "boolean",
28493
28951
  description: "[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."
28952
+ },
28953
+ interactiveAnswers: {
28954
+ type: "array",
28955
+ items: {
28956
+ type: "object",
28957
+ properties: {
28958
+ fixId: {
28959
+ type: "string",
28960
+ description: 'Fix id from a previous "Interactive fix" prompt.'
28961
+ },
28962
+ answers: {
28963
+ type: "array",
28964
+ items: {
28965
+ type: "object",
28966
+ properties: {
28967
+ key: { type: "string", description: "FixQuestion key." },
28968
+ value: {
28969
+ type: "string",
28970
+ description: "Decided value (SELECT must match an option exactly)."
28971
+ }
28972
+ },
28973
+ required: ["key", "value"]
28974
+ }
28975
+ }
28976
+ },
28977
+ required: ["fixId", "answers"]
28978
+ },
28979
+ description: "[Optional] When supplied (including []), skips scanning. Non-empty: apply interactive fixes with answers. Empty []: abstain from all interactive fixes without rescanning. Omit for scan mode."
28494
28980
  }
28495
28981
  },
28496
28982
  required: ["path"]
@@ -28501,7 +28987,8 @@ Example payload:
28501
28987
  }
28502
28988
  async executeInternal(args) {
28503
28989
  logDebug(`Executing tool: ${this.name}`, {
28504
- path: args.path
28990
+ path: args.path,
28991
+ mode: args.interactiveAnswers === void 0 ? "scan" : args.interactiveAnswers.length === 0 ? "apply-interactive-abstain-all" : "apply-with-answers"
28505
28992
  });
28506
28993
  if (!args.path) {
28507
28994
  throw new Error("Invalid arguments: Missing required parameter 'path'");
@@ -28513,6 +29000,26 @@ Example payload:
28513
29000
  );
28514
29001
  }
28515
29002
  const path37 = pathValidationResult.path;
29003
+ if (args.interactiveAnswers !== void 0) {
29004
+ if (args.interactiveAnswers.length === 0) {
29005
+ return this.createSuccessResponse(
29006
+ interactiveAnswersAbstainAllToolResponse
29007
+ );
29008
+ }
29009
+ try {
29010
+ const result = await this.vulnerabilityFixService.applyInteractiveAnswers({
29011
+ interactiveAnswers: args.interactiveAnswers,
29012
+ repositoryPath: path37
29013
+ });
29014
+ return this.createSuccessResponse(result);
29015
+ } catch (error) {
29016
+ const message = error.message;
29017
+ logError("Tool execution failed (apply-with-answers)", {
29018
+ error: message
29019
+ });
29020
+ return this.createSuccessResponse(message);
29021
+ }
29022
+ }
28516
29023
  const files = await getLocalFiles({
28517
29024
  path: path37,
28518
29025
  maxFileSize: MCP_MAX_FILE_SIZE,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "1.4.11",
3
+ "version": "1.4.12",
4
4
  "description": "Automated secure code remediation tool",
5
5
  "repository": "git+https://github.com/mobb-dev/bugsy.git",
6
6
  "main": "dist/index.mjs",