@perfai/mcp 1.0.24
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/LICENSE +21 -0
- package/README.md +352 -0
- package/dist/auth/authManager.d.ts +83 -0
- package/dist/auth/authManager.d.ts.map +1 -0
- package/dist/auth/authManager.js +555 -0
- package/dist/auth/sessionCache.d.ts +5 -0
- package/dist/auth/sessionCache.d.ts.map +1 -0
- package/dist/auth/sessionCache.js +29 -0
- package/dist/auth/sessionStorage.d.ts +53 -0
- package/dist/auth/sessionStorage.d.ts.map +1 -0
- package/dist/auth/sessionStorage.js +234 -0
- package/dist/auth/types.d.ts +28 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +1 -0
- package/dist/config.d.ts +65 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +74 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +144 -0
- package/dist/setup-config.d.ts +4 -0
- package/dist/setup-config.d.ts.map +1 -0
- package/dist/setup-config.js +69 -0
- package/dist/tools/index.d.ts +361 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +275 -0
- package/dist/tools/protected/aiFixDesignIssue.d.ts +17 -0
- package/dist/tools/protected/aiFixDesignIssue.d.ts.map +1 -0
- package/dist/tools/protected/aiFixDesignIssue.js +205 -0
- package/dist/tools/protected/aiFixQualityIssue.d.ts +17 -0
- package/dist/tools/protected/aiFixQualityIssue.d.ts.map +1 -0
- package/dist/tools/protected/aiFixQualityIssue.js +188 -0
- package/dist/tools/protected/aiFixSecurityIssue.d.ts +17 -0
- package/dist/tools/protected/aiFixSecurityIssue.d.ts.map +1 -0
- package/dist/tools/protected/aiFixSecurityIssue.js +205 -0
- package/dist/tools/protected/checkDesignFixes.d.ts +17 -0
- package/dist/tools/protected/checkDesignFixes.d.ts.map +1 -0
- package/dist/tools/protected/checkDesignFixes.js +199 -0
- package/dist/tools/protected/checkQualityFixes.d.ts +17 -0
- package/dist/tools/protected/checkQualityFixes.d.ts.map +1 -0
- package/dist/tools/protected/checkQualityFixes.js +199 -0
- package/dist/tools/protected/checkSecurityFixes.d.ts +17 -0
- package/dist/tools/protected/checkSecurityFixes.d.ts.map +1 -0
- package/dist/tools/protected/checkSecurityFixes.js +177 -0
- package/dist/tools/protected/listApis.d.ts +28 -0
- package/dist/tools/protected/listApis.d.ts.map +1 -0
- package/dist/tools/protected/listApis.js +102 -0
- package/dist/tools/protected/logout.d.ts +11 -0
- package/dist/tools/protected/logout.d.ts.map +1 -0
- package/dist/tools/protected/logout.js +22 -0
- package/dist/tools/protected/manageOrganizations.d.ts +26 -0
- package/dist/tools/protected/manageOrganizations.d.ts.map +1 -0
- package/dist/tools/protected/manageOrganizations.js +147 -0
- package/dist/tools/protected/runDesignTest.d.ts +21 -0
- package/dist/tools/protected/runDesignTest.d.ts.map +1 -0
- package/dist/tools/protected/runDesignTest.js +132 -0
- package/dist/tools/protected/runQualityTest.d.ts +21 -0
- package/dist/tools/protected/runQualityTest.d.ts.map +1 -0
- package/dist/tools/protected/runQualityTest.js +150 -0
- package/dist/tools/protected/runSecurityTest.d.ts +21 -0
- package/dist/tools/protected/runSecurityTest.d.ts.map +1 -0
- package/dist/tools/protected/runSecurityTest.js +107 -0
- package/dist/tools/protected/selectApi.d.ts +24 -0
- package/dist/tools/protected/selectApi.d.ts.map +1 -0
- package/dist/tools/protected/selectApi.js +172 -0
- package/dist/tools/protected/setup.d.ts +11 -0
- package/dist/tools/protected/setup.d.ts.map +1 -0
- package/dist/tools/protected/setup.js +151 -0
- package/dist/tools/protected/showDesignIssues.d.ts +38 -0
- package/dist/tools/protected/showDesignIssues.d.ts.map +1 -0
- package/dist/tools/protected/showDesignIssues.js +201 -0
- package/dist/tools/protected/showFixedIssues.d.ts +11 -0
- package/dist/tools/protected/showFixedIssues.d.ts.map +1 -0
- package/dist/tools/protected/showFixedIssues.js +36 -0
- package/dist/tools/protected/showQualityIssues.d.ts +33 -0
- package/dist/tools/protected/showQualityIssues.d.ts.map +1 -0
- package/dist/tools/protected/showQualityIssues.js +225 -0
- package/dist/tools/protected/showSecurityIssues.d.ts +47 -0
- package/dist/tools/protected/showSecurityIssues.d.ts.map +1 -0
- package/dist/tools/protected/showSecurityIssues.js +212 -0
- package/dist/tools/protected/summarizeIssues.d.ts +11 -0
- package/dist/tools/protected/summarizeIssues.d.ts.map +1 -0
- package/dist/tools/protected/summarizeIssues.js +161 -0
- package/dist/tools/protected/userInfo.d.ts +11 -0
- package/dist/tools/protected/userInfo.d.ts.map +1 -0
- package/dist/tools/protected/userInfo.js +21 -0
- package/dist/tools/protected/visionAiAppLearning.d.ts +37 -0
- package/dist/tools/protected/visionAiAppLearning.d.ts.map +1 -0
- package/dist/tools/protected/visionAiAppLearning.js +122 -0
- package/dist/tools/public/authStatus.d.ts +11 -0
- package/dist/tools/public/authStatus.d.ts.map +1 -0
- package/dist/tools/public/authStatus.js +78 -0
- package/dist/tools/public/login.d.ts +12 -0
- package/dist/tools/public/login.d.ts.map +1 -0
- package/dist/tools/public/login.js +230 -0
- package/dist/types/api.d.ts +12 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/api.js +1 -0
- package/dist/utils/dockerRunner.d.ts +44 -0
- package/dist/utils/dockerRunner.d.ts.map +1 -0
- package/dist/utils/dockerRunner.js +300 -0
- package/dist/utils/formatters.d.ts +14 -0
- package/dist/utils/formatters.d.ts.map +1 -0
- package/dist/utils/formatters.js +510 -0
- package/dist/utils/promptBuilder.d.ts +4 -0
- package/dist/utils/promptBuilder.d.ts.map +1 -0
- package/dist/utils/promptBuilder.js +132 -0
- package/package.json +67 -0
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
export function formatSecurityIssues(issues, userInfo, search, hasMore, nextCursor) {
|
|
2
|
+
if (!issues.length) {
|
|
3
|
+
return `**Security Issues Report**\n\n✓ **No security issues found!**\n\n${search ? `Search: "${search}"\n` : ''}**Total Issues**: 0\n**User**: ${userInfo?.email || 'Unknown'}\n\nYour applications are secure!`;
|
|
4
|
+
}
|
|
5
|
+
// Sort issues by severity first (Critical -> High -> Medium -> Low -> Unknown)
|
|
6
|
+
const severityOrder = ['critical', 'severe', 'high', 'medium', 'moderate', 'low', 'minor'];
|
|
7
|
+
const sortedIssues = issues.sort((a, b) => {
|
|
8
|
+
const aSeverity = (a.severity || '').toString().toLowerCase().trim();
|
|
9
|
+
const bSeverity = (b.severity || '').toString().toLowerCase().trim();
|
|
10
|
+
const aIndex = severityOrder.indexOf(aSeverity);
|
|
11
|
+
const bIndex = severityOrder.indexOf(bSeverity);
|
|
12
|
+
// If both are in the order, sort by position
|
|
13
|
+
if (aIndex !== -1 && bIndex !== -1) {
|
|
14
|
+
return aIndex - bIndex;
|
|
15
|
+
}
|
|
16
|
+
// If only one is in the order, prioritize it
|
|
17
|
+
if (aIndex !== -1)
|
|
18
|
+
return -1;
|
|
19
|
+
if (bIndex !== -1)
|
|
20
|
+
return 1;
|
|
21
|
+
// If neither is in the order, sort alphabetically
|
|
22
|
+
return aSeverity.localeCompare(bSeverity);
|
|
23
|
+
});
|
|
24
|
+
// Format issues in clean table format
|
|
25
|
+
const lines = [`**Security Issues**\n`];
|
|
26
|
+
if (search) {
|
|
27
|
+
lines.push(`Search: "${search}"`);
|
|
28
|
+
}
|
|
29
|
+
lines.push(`**Showing**: ${issues.length}${hasMore ? ' of many' : ''} issues`);
|
|
30
|
+
lines.push(`**User**: ${userInfo?.email || 'Unknown'}\n`);
|
|
31
|
+
// Table: Seq | Issue Type | Endpoint | Severity | CVSS
|
|
32
|
+
const W_SEQ = 3;
|
|
33
|
+
const W_ISSUE = 36;
|
|
34
|
+
const W_ENDPOINT = 36;
|
|
35
|
+
const W_SEVERITY = 10;
|
|
36
|
+
const W_CVSS = 6;
|
|
37
|
+
const sep = (n) => '-'.repeat(n);
|
|
38
|
+
const top = '+' + sep(W_SEQ + 2) + '+' + sep(W_ISSUE + 2) + '+' + sep(W_ENDPOINT + 2) + '+' + sep(W_SEVERITY + 2) + '+' + sep(W_CVSS + 2) + '+';
|
|
39
|
+
const mid = '+' + sep(W_SEQ + 2) + '+' + sep(W_ISSUE + 2) + '+' + sep(W_ENDPOINT + 2) + '+' + sep(W_SEVERITY + 2) + '+' + sep(W_CVSS + 2) + '+';
|
|
40
|
+
const bot = '+' + sep(W_SEQ + 2) + '+' + sep(W_ISSUE + 2) + '+' + sep(W_ENDPOINT + 2) + '+' + sep(W_SEVERITY + 2) + '+' + sep(W_CVSS + 2) + '+';
|
|
41
|
+
lines.push(top);
|
|
42
|
+
lines.push('| ' + 'Seq'.padEnd(W_SEQ) + ' | ' + 'Issue Type'.padEnd(W_ISSUE) + ' | ' + 'Endpoint'.padEnd(W_ENDPOINT) + ' | ' + 'Severity'.padEnd(W_SEVERITY) + ' | ' + 'CVSS'.padEnd(W_CVSS) + ' |');
|
|
43
|
+
lines.push(mid);
|
|
44
|
+
sortedIssues.forEach((issue, index) => {
|
|
45
|
+
const method = (issue.method || 'MULTIPLE').toUpperCase();
|
|
46
|
+
let path = (issue.path || '/unknown').trim();
|
|
47
|
+
if (path && !path.startsWith('/'))
|
|
48
|
+
path = '/' + path;
|
|
49
|
+
const label = issue.label || 'Unlabeled Issue';
|
|
50
|
+
const severity = issue.severity || 'Unknown';
|
|
51
|
+
const cvssScore = issue.cvss_score;
|
|
52
|
+
if (index < 3) {
|
|
53
|
+
console.error(`🔍 Debug Issue ${index + 1}: severity="${severity}" (type: ${typeof severity}), cvss_score="${cvssScore}" (type: ${typeof cvssScore})`);
|
|
54
|
+
}
|
|
55
|
+
const issueType = label;
|
|
56
|
+
let endpoint = '';
|
|
57
|
+
if (!issue.method && !issue.path) {
|
|
58
|
+
endpoint = 'Multiple Endpoints';
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
endpoint = method + ' ' + path;
|
|
62
|
+
}
|
|
63
|
+
const truncatedIssueType = issueType.length > W_ISSUE ? issueType.substring(0, W_ISSUE - 3) + '...' : issueType;
|
|
64
|
+
const truncatedEndpoint = endpoint.length > W_ENDPOINT ? endpoint.substring(0, W_ENDPOINT - 3) + '...' : endpoint;
|
|
65
|
+
const paddedIssueType = truncatedIssueType.padEnd(W_ISSUE);
|
|
66
|
+
const paddedEndpoint = truncatedEndpoint.padEnd(W_ENDPOINT);
|
|
67
|
+
// ASCII-only severity so table aligns in all IDEs/terminals (no double-width Unicode)
|
|
68
|
+
const normalizedSeverity = (severity || '').toString().toLowerCase().trim();
|
|
69
|
+
let severityIndicator;
|
|
70
|
+
let severitySymbol;
|
|
71
|
+
if (normalizedSeverity === 'critical') {
|
|
72
|
+
severityIndicator = 'CRITICAL';
|
|
73
|
+
severitySymbol = '*';
|
|
74
|
+
}
|
|
75
|
+
else if (normalizedSeverity === 'severe') {
|
|
76
|
+
severityIndicator = 'SEVERE';
|
|
77
|
+
severitySymbol = '*';
|
|
78
|
+
}
|
|
79
|
+
else if (normalizedSeverity === 'high') {
|
|
80
|
+
severityIndicator = 'HIGH';
|
|
81
|
+
severitySymbol = '*';
|
|
82
|
+
}
|
|
83
|
+
else if (normalizedSeverity === 'medium' || normalizedSeverity === 'moderate') {
|
|
84
|
+
severityIndicator = 'MED';
|
|
85
|
+
severitySymbol = '-';
|
|
86
|
+
}
|
|
87
|
+
else if (normalizedSeverity === 'low' || normalizedSeverity === 'minor') {
|
|
88
|
+
severityIndicator = 'LOW';
|
|
89
|
+
severitySymbol = '.';
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
severityIndicator = normalizedSeverity.toUpperCase() || 'UNK';
|
|
93
|
+
severitySymbol = '?';
|
|
94
|
+
}
|
|
95
|
+
const severityDisplay = (severitySymbol + ' ' + severityIndicator).padEnd(W_SEVERITY);
|
|
96
|
+
let cvssDisplay = 'N/A';
|
|
97
|
+
if (cvssScore !== undefined && cvssScore !== null) {
|
|
98
|
+
const score = parseFloat(cvssScore);
|
|
99
|
+
if (!isNaN(score)) {
|
|
100
|
+
cvssDisplay = score.toFixed(1);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const paddedCvss = cvssDisplay.padEnd(W_CVSS);
|
|
104
|
+
const rowNumber = (index + 1).toString().padStart(W_SEQ);
|
|
105
|
+
lines.push('| ' + rowNumber + ' | ' + paddedIssueType + ' | ' + paddedEndpoint + ' | ' + severityDisplay + ' | ' + paddedCvss + ' |');
|
|
106
|
+
});
|
|
107
|
+
lines.push(bot);
|
|
108
|
+
// Add pagination info
|
|
109
|
+
if (hasMore && nextCursor) {
|
|
110
|
+
lines.push(`\n📄 **Pagination Controls:**`);
|
|
111
|
+
lines.push(`• **Next 20 issues**: \`show_security_issues {"cursor": "${nextCursor}"}\``);
|
|
112
|
+
lines.push(`• **All remaining**: \`show_security_issues {"limit": 100, "cursor": "${nextCursor}"}\``);
|
|
113
|
+
}
|
|
114
|
+
else if (hasMore) {
|
|
115
|
+
lines.push(`\n📄 **More issues available** - Run \`show_security_issues\` again to see the next 20`);
|
|
116
|
+
}
|
|
117
|
+
return lines.join('\n');
|
|
118
|
+
}
|
|
119
|
+
export function formatAppList(apps, orgId, userInfo, selectedAppId, selectedAppData, authManager, filters) {
|
|
120
|
+
const filterDesc = [];
|
|
121
|
+
if (filters?.search)
|
|
122
|
+
filterDesc.push(`search="${filters.search}"`);
|
|
123
|
+
if (filters?.environment)
|
|
124
|
+
filterDesc.push(`environment="${filters.environment}"`);
|
|
125
|
+
if (!apps.length) {
|
|
126
|
+
const filterNote = filterDesc.length ? `\n**Active filters**: ${filterDesc.join(', ')}` : '';
|
|
127
|
+
return `**APP Catalog**\n\n✓ **No APPs found**\n\n**Organization**: ${orgId}\n**User**: ${userInfo?.email || 'Unknown'}${filterNote}\n\n**Note**: No APPs match the current filters. Try removing filters or checking the organization.`;
|
|
128
|
+
}
|
|
129
|
+
// Format APP list as a table
|
|
130
|
+
const lines = [`**APP Catalog**\n`];
|
|
131
|
+
lines.push(`**Organization**: ${orgId}`);
|
|
132
|
+
const pageNote = filters?.page && filters.page > 1 ? ` (page ${filters.page})` : '';
|
|
133
|
+
const totalNote = filters?.totalCount !== undefined ? ` of ${filters.totalCount} total` : '';
|
|
134
|
+
lines.push(`**APPs shown**: ${apps.length}${totalNote}${pageNote}`);
|
|
135
|
+
if (filterDesc.length)
|
|
136
|
+
lines.push(`**Filters**: ${filterDesc.join(', ')}`);
|
|
137
|
+
lines.push(`**User**: ${userInfo?.email || 'Unknown'}`);
|
|
138
|
+
if (selectedAppId && selectedAppData) {
|
|
139
|
+
const displayText = selectedAppData.label && selectedAppData.api_name
|
|
140
|
+
? `${selectedAppData.label} - ${selectedAppData.api_name}`
|
|
141
|
+
: selectedAppData.label || selectedAppData.api_name || selectedAppId;
|
|
142
|
+
lines.push(`**Selected APP**: ${displayText}\n`);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
lines.push(`**Selected APP**: None\n`);
|
|
146
|
+
}
|
|
147
|
+
// Create table with programmatic widths so borders/header/rows align
|
|
148
|
+
const W_SEQ = 3;
|
|
149
|
+
const W_APP = 60;
|
|
150
|
+
const W_LABEL = 60;
|
|
151
|
+
const sep = (n) => '-'.repeat(n);
|
|
152
|
+
const top = '+' + sep(W_SEQ + 2) + '+' + sep(W_APP + 2) + '+' + sep(W_LABEL + 2) + '+';
|
|
153
|
+
const mid = '+' + sep(W_SEQ + 2) + '+' + sep(W_APP + 2) + '+' + sep(W_LABEL + 2) + '+';
|
|
154
|
+
const bot = '+' + sep(W_SEQ + 2) + '+' + sep(W_APP + 2) + '+' + sep(W_LABEL + 2) + '+';
|
|
155
|
+
lines.push(top);
|
|
156
|
+
lines.push('| ' + 'Seq'.padEnd(W_SEQ) + ' | ' + 'App Name'.padEnd(W_APP) + ' | ' + 'Label'.padEnd(W_LABEL) + ' |');
|
|
157
|
+
lines.push(mid);
|
|
158
|
+
// Process apps and create unique entries + sequence mapping
|
|
159
|
+
const uniqueApps = new Map();
|
|
160
|
+
const sequenceMap = new Map();
|
|
161
|
+
apps.forEach((app) => {
|
|
162
|
+
const appName = app.api_name || 'Unnamed APP';
|
|
163
|
+
const appLabel = app.label || 'No Label';
|
|
164
|
+
const appId = app._id;
|
|
165
|
+
const uniqueKey = `${appName}-${appLabel}-${appId}`;
|
|
166
|
+
if (!uniqueApps.has(uniqueKey)) {
|
|
167
|
+
const seq = uniqueApps.size + 1;
|
|
168
|
+
uniqueApps.set(uniqueKey, {
|
|
169
|
+
seq,
|
|
170
|
+
appName,
|
|
171
|
+
appLabel,
|
|
172
|
+
appId,
|
|
173
|
+
isSelected: appId === selectedAppId,
|
|
174
|
+
environment: app.environment
|
|
175
|
+
});
|
|
176
|
+
sequenceMap.set(seq, appId);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
if (authManager) {
|
|
180
|
+
authManager.setAppSequenceMap(sequenceMap);
|
|
181
|
+
}
|
|
182
|
+
const selSuffix = ' [SELECTED]';
|
|
183
|
+
const maxNameLenWhenSelected = W_APP - selSuffix.length;
|
|
184
|
+
uniqueApps.forEach((app) => {
|
|
185
|
+
const { seq, appName, appLabel, isSelected } = app;
|
|
186
|
+
const maxNameLen = isSelected ? maxNameLenWhenSelected : W_APP;
|
|
187
|
+
const truncatedAppName = appName.length > maxNameLen ? appName.substring(0, maxNameLen - 3) + '...' : appName;
|
|
188
|
+
const appNameCell = (truncatedAppName + (isSelected ? selSuffix : '')).padEnd(W_APP);
|
|
189
|
+
const truncatedAppLabel = appLabel.length > W_LABEL ? appLabel.substring(0, W_LABEL - 3) + '...' : appLabel;
|
|
190
|
+
const paddedAppLabel = truncatedAppLabel.padEnd(W_LABEL);
|
|
191
|
+
const rowNumber = seq.toString().padStart(W_SEQ);
|
|
192
|
+
lines.push('| ' + rowNumber + ' | ' + appNameCell + ' | ' + paddedAppLabel + ' |');
|
|
193
|
+
});
|
|
194
|
+
lines.push(bot);
|
|
195
|
+
// Add environment info if available
|
|
196
|
+
const environments = [...new Set(Array.from(uniqueApps.values()).map(app => app.environment).filter(Boolean))];
|
|
197
|
+
if (environments.length > 0) {
|
|
198
|
+
lines.push(`\n**Environments**: ${environments.join(', ')}`);
|
|
199
|
+
}
|
|
200
|
+
// Pagination hint driven by the API's hasMore flag
|
|
201
|
+
const currentPage = filters?.page ?? 1;
|
|
202
|
+
if (filters?.hasMore) {
|
|
203
|
+
lines.push(`\n**More apps available** — fetch next page: \`list_apps {"page": ${currentPage + 1}}\``);
|
|
204
|
+
}
|
|
205
|
+
lines.push(`\n**To select an app**: \`select_app {"sequence": <n>}\` or \`select_app {"name_or_label": "<name>"}\` or \`select_app {"app_id": "<id>"}\``);
|
|
206
|
+
return lines.join('\n');
|
|
207
|
+
}
|
|
208
|
+
export function formatOrganizations(organizations, selectedOrgId) {
|
|
209
|
+
if (organizations.length === 0) {
|
|
210
|
+
return `**Organization Management**\n\n! **No Organizations Found**\n\n**Possible Causes**:\n• Organizations haven't been fetched yet\n• Account has no organization access\n• Response was empty\n\n**Try**: Use action=refresh to fetch organizations again\n\n**Note**: Some PerfAI features require organization membership`;
|
|
211
|
+
}
|
|
212
|
+
const W_SEQ = 3;
|
|
213
|
+
const W_NAME = 40;
|
|
214
|
+
const W_ROLE = 10;
|
|
215
|
+
const W_STATUS = 10;
|
|
216
|
+
const sep = (n) => '-'.repeat(n);
|
|
217
|
+
const border = '+' + sep(W_SEQ + 2) + '+' + sep(W_NAME + 2) + '+' + sep(W_ROLE + 2) + '+' + sep(W_STATUS + 2) + '+';
|
|
218
|
+
const lines = [
|
|
219
|
+
`**Organization Management**\n`,
|
|
220
|
+
`**Total Organizations**: ${organizations.length}`,
|
|
221
|
+
`**Currently Selected**: ${selectedOrgId || 'None'}\n`,
|
|
222
|
+
border,
|
|
223
|
+
'| ' + 'Seq'.padEnd(W_SEQ) + ' | ' + 'Name'.padEnd(W_NAME) + ' | ' + 'Role'.padEnd(W_ROLE) + ' | ' + 'Status'.padEnd(W_STATUS) + ' |',
|
|
224
|
+
border,
|
|
225
|
+
];
|
|
226
|
+
organizations.forEach((org, index) => {
|
|
227
|
+
const seq = (index + 1).toString().padStart(W_SEQ);
|
|
228
|
+
const isSelected = org.org_id === selectedOrgId;
|
|
229
|
+
const rawName = org.orgDetails?.name || 'Unknown';
|
|
230
|
+
const selSuffix = isSelected ? ' [*]' : '';
|
|
231
|
+
const maxLen = W_NAME - selSuffix.length;
|
|
232
|
+
const name = ((rawName.length > maxLen ? rawName.substring(0, maxLen - 3) + '...' : rawName) + selSuffix).padEnd(W_NAME);
|
|
233
|
+
const role = (org.role || 'Unknown').substring(0, W_ROLE).padEnd(W_ROLE);
|
|
234
|
+
const status = (org.status || 'Unknown').substring(0, W_STATUS).padEnd(W_STATUS);
|
|
235
|
+
lines.push('| ' + seq + ' | ' + name + ' | ' + role + ' | ' + status + ' |');
|
|
236
|
+
});
|
|
237
|
+
lines.push(border);
|
|
238
|
+
lines.push(`\n**To switch organizations**:`);
|
|
239
|
+
lines.push(`• By sequence: \`manage_organizations {"action": "select", "sequence": <n>}\``);
|
|
240
|
+
lines.push(`• By ID: \`manage_organizations {"action": "select", "org_id": "<id>"}\``);
|
|
241
|
+
return lines.join('\n');
|
|
242
|
+
}
|
|
243
|
+
export function formatFixedIssues(fixedIssues, userInfo) {
|
|
244
|
+
if (fixedIssues.length === 0) {
|
|
245
|
+
return `**Fixed Issues**\n\n✓ **No fixed issues yet**\n\n**User**: ${userInfo?.email || 'Unknown'}\n**Total Fixed**: 0\n\n**Note**: Use ai_fix_security_issue tool to generate AI fix prompts for security issues.`;
|
|
246
|
+
}
|
|
247
|
+
// Format fixed issues list with clean text formatting
|
|
248
|
+
const lines = [`**Fixed Issues**\n`];
|
|
249
|
+
lines.push(`**User**: ${userInfo?.email || 'Unknown'}`);
|
|
250
|
+
lines.push(`**Total Fixed**: ${fixedIssues.length}\n`);
|
|
251
|
+
for (const fixedIssue of fixedIssues) {
|
|
252
|
+
const issue = fixedIssue.issue;
|
|
253
|
+
const displayName = issue.label || 'Unknown Issue';
|
|
254
|
+
const severity = issue.severity || 'Unknown';
|
|
255
|
+
const method = issue.method || 'Multiple';
|
|
256
|
+
const path = issue.path || 'Endpoints';
|
|
257
|
+
const severitySymbol = severity === 'High' ? '●' : severity === 'Medium' ? '○' : severity === 'Low' ? '◯' : '?';
|
|
258
|
+
// Add method-specific symbols
|
|
259
|
+
const methodSymbol = method.toUpperCase() === 'GET' ? '→' :
|
|
260
|
+
method.toUpperCase() === 'POST' ? '↑' :
|
|
261
|
+
method.toUpperCase() === 'PUT' ? '↗' :
|
|
262
|
+
method.toUpperCase() === 'DELETE' ? '×' : '?';
|
|
263
|
+
// Add status-specific indicators
|
|
264
|
+
const statusIndicator = fixedIssue.status === 'ai-fixed' ? '[AI-FIXED]' :
|
|
265
|
+
fixedIssue.status === 'fixed' ? '[FIXED]' :
|
|
266
|
+
fixedIssue.status === 'pending' ? '[PENDING]' : '[UNKNOWN]';
|
|
267
|
+
lines.push(`${severitySymbol} **${displayName}** (${severity})`);
|
|
268
|
+
lines.push(` ID: ${fixedIssue.issueId}`);
|
|
269
|
+
lines.push(` Endpoint: ${methodSymbol} ${method} ${path}`);
|
|
270
|
+
lines.push(` Fixed: ${fixedIssue.fixedAt.toLocaleString()}`);
|
|
271
|
+
lines.push(` Status: ${statusIndicator} ${fixedIssue.status}`);
|
|
272
|
+
lines.push('');
|
|
273
|
+
}
|
|
274
|
+
lines.push(`**To view a specific fix prompt**:\nCopy an issue ID and use ai_fix_security_issue again to see the full prompt.`);
|
|
275
|
+
return lines.join('\n');
|
|
276
|
+
}
|
|
277
|
+
export function formatDesignIssues(issues, userInfo, search, hasMore, nextCursor) {
|
|
278
|
+
if (!issues.length) {
|
|
279
|
+
return `**Design Issues Report**\n\n✓ **No design issues found!**\n\n${search ? `Search: "${search}"\n` : ''}**Total Issues**: 0\n**User**: ${userInfo?.email || 'Unknown'}\n\nYour app design looks good!`;
|
|
280
|
+
}
|
|
281
|
+
// Sort issues by priority/severity first (Critical -> High -> Medium -> Low -> Unknown)
|
|
282
|
+
const severityOrder = ['critical', 'severe', 'high', 'medium', 'moderate', 'low', 'minor'];
|
|
283
|
+
const sortedIssues = issues.sort((a, b) => {
|
|
284
|
+
const aSeverity = (a.priority || a.severity || '').toString().toLowerCase().trim();
|
|
285
|
+
const bSeverity = (b.priority || b.severity || '').toString().toLowerCase().trim();
|
|
286
|
+
const aIndex = severityOrder.indexOf(aSeverity);
|
|
287
|
+
const bIndex = severityOrder.indexOf(bSeverity);
|
|
288
|
+
// If both are in the order, sort by position
|
|
289
|
+
if (aIndex !== -1 && bIndex !== -1) {
|
|
290
|
+
return aIndex - bIndex;
|
|
291
|
+
}
|
|
292
|
+
// If only one is in the order, prioritize it
|
|
293
|
+
if (aIndex !== -1)
|
|
294
|
+
return -1;
|
|
295
|
+
if (bIndex !== -1)
|
|
296
|
+
return 1;
|
|
297
|
+
// If neither is in the order, sort alphabetically
|
|
298
|
+
return aSeverity.localeCompare(bSeverity);
|
|
299
|
+
});
|
|
300
|
+
// Format issues in clean table format
|
|
301
|
+
const lines = [`**Design Issues**\n`];
|
|
302
|
+
if (search) {
|
|
303
|
+
lines.push(`Search: "${search}"`);
|
|
304
|
+
}
|
|
305
|
+
lines.push(`**Showing**: ${issues.length}${hasMore ? ' of many' : ''} issues`);
|
|
306
|
+
lines.push(`**User**: ${userInfo?.email || 'Unknown'}\n`);
|
|
307
|
+
const W_SEQ = 3;
|
|
308
|
+
const W_ISSUE = 36;
|
|
309
|
+
const W_ENDPOINT = 36;
|
|
310
|
+
const W_SEVERITY = 10;
|
|
311
|
+
const W_SCORE = 6;
|
|
312
|
+
const sep = (n) => '-'.repeat(n);
|
|
313
|
+
const top = '+' + sep(W_SEQ + 2) + '+' + sep(W_ISSUE + 2) + '+' + sep(W_ENDPOINT + 2) + '+' + sep(W_SEVERITY + 2) + '+' + sep(W_SCORE + 2) + '+';
|
|
314
|
+
const mid = '+' + sep(W_SEQ + 2) + '+' + sep(W_ISSUE + 2) + '+' + sep(W_ENDPOINT + 2) + '+' + sep(W_SEVERITY + 2) + '+' + sep(W_SCORE + 2) + '+';
|
|
315
|
+
const bot = '+' + sep(W_SEQ + 2) + '+' + sep(W_ISSUE + 2) + '+' + sep(W_ENDPOINT + 2) + '+' + sep(W_SEVERITY + 2) + '+' + sep(W_SCORE + 2) + '+';
|
|
316
|
+
lines.push(top);
|
|
317
|
+
lines.push('| ' + 'Seq'.padEnd(W_SEQ) + ' | ' + 'Issue Type'.padEnd(W_ISSUE) + ' | ' + 'Endpoint'.padEnd(W_ENDPOINT) + ' | ' + 'Severity'.padEnd(W_SEVERITY) + ' | ' + 'Score'.padEnd(W_SCORE) + ' |');
|
|
318
|
+
lines.push(mid);
|
|
319
|
+
sortedIssues.forEach((issue, index) => {
|
|
320
|
+
const method = (issue.method || 'MULTIPLE').toUpperCase();
|
|
321
|
+
let path = (issue.path || '/unknown').trim();
|
|
322
|
+
if (path && !path.startsWith('/'))
|
|
323
|
+
path = '/' + path;
|
|
324
|
+
const label = issue.category || issue.label || 'Unlabeled Issue';
|
|
325
|
+
const severity = issue.priority || issue.severity || 'Unknown';
|
|
326
|
+
const score = issue.score || issue.cvss_score;
|
|
327
|
+
if (index < 3) {
|
|
328
|
+
console.error(`🔍 Debug Design Issue ${index + 1}: severity="${severity}" (type: ${typeof severity}), score="${score}" (type: ${typeof score})`);
|
|
329
|
+
}
|
|
330
|
+
const issueType = label;
|
|
331
|
+
let endpoint = '';
|
|
332
|
+
if (!issue.method && !issue.path) {
|
|
333
|
+
endpoint = 'Multiple Endpoints';
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
endpoint = method + ' ' + path;
|
|
337
|
+
}
|
|
338
|
+
const truncatedIssueType = issueType.length > W_ISSUE ? issueType.substring(0, W_ISSUE - 3) + '...' : issueType;
|
|
339
|
+
const truncatedEndpoint = endpoint.length > W_ENDPOINT ? endpoint.substring(0, W_ENDPOINT - 3) + '...' : endpoint;
|
|
340
|
+
const paddedIssueType = truncatedIssueType.padEnd(W_ISSUE);
|
|
341
|
+
const paddedEndpoint = truncatedEndpoint.padEnd(W_ENDPOINT);
|
|
342
|
+
const normalizedSeverity = (severity || '').toString().toLowerCase().trim();
|
|
343
|
+
let severityIndicator;
|
|
344
|
+
let severitySymbol;
|
|
345
|
+
if (normalizedSeverity === 'critical') {
|
|
346
|
+
severityIndicator = 'CRITICAL';
|
|
347
|
+
severitySymbol = '*';
|
|
348
|
+
}
|
|
349
|
+
else if (normalizedSeverity === 'severe') {
|
|
350
|
+
severityIndicator = 'SEVERE';
|
|
351
|
+
severitySymbol = '*';
|
|
352
|
+
}
|
|
353
|
+
else if (normalizedSeverity === 'high') {
|
|
354
|
+
severityIndicator = 'HIGH';
|
|
355
|
+
severitySymbol = '*';
|
|
356
|
+
}
|
|
357
|
+
else if (normalizedSeverity === 'medium' || normalizedSeverity === 'moderate') {
|
|
358
|
+
severityIndicator = 'MED';
|
|
359
|
+
severitySymbol = '-';
|
|
360
|
+
}
|
|
361
|
+
else if (normalizedSeverity === 'low' || normalizedSeverity === 'minor') {
|
|
362
|
+
severityIndicator = 'LOW';
|
|
363
|
+
severitySymbol = '.';
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
severityIndicator = normalizedSeverity.toUpperCase() || 'UNK';
|
|
367
|
+
severitySymbol = '?';
|
|
368
|
+
}
|
|
369
|
+
const severityDisplay = (severitySymbol + ' ' + severityIndicator).padEnd(W_SEVERITY);
|
|
370
|
+
let scoreDisplay = 'N/A';
|
|
371
|
+
if (score !== undefined && score !== null) {
|
|
372
|
+
const scoreValue = parseFloat(score);
|
|
373
|
+
if (!isNaN(scoreValue)) {
|
|
374
|
+
scoreDisplay = scoreValue.toFixed(1);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const paddedScore = scoreDisplay.padEnd(W_SCORE);
|
|
378
|
+
const rowNumber = (index + 1).toString().padStart(W_SEQ);
|
|
379
|
+
lines.push('| ' + rowNumber + ' | ' + paddedIssueType + ' | ' + paddedEndpoint + ' | ' + severityDisplay + ' | ' + paddedScore + ' |');
|
|
380
|
+
});
|
|
381
|
+
lines.push(bot);
|
|
382
|
+
// Add pagination info
|
|
383
|
+
if (hasMore && nextCursor) {
|
|
384
|
+
lines.push(`\n📄 **Pagination Controls:**`);
|
|
385
|
+
lines.push(`• **Next 20 issues**: \`show_design_issues {"cursor": "${nextCursor}"}\``);
|
|
386
|
+
lines.push(`• **All remaining**: \`show_design_issues {"limit": 100, "cursor": "${nextCursor}"}\``);
|
|
387
|
+
}
|
|
388
|
+
else if (hasMore) {
|
|
389
|
+
lines.push(`\n📄 **More issues available** - Run \`show_design_issues\` again to see the next 20`);
|
|
390
|
+
}
|
|
391
|
+
return lines.join('\n');
|
|
392
|
+
}
|
|
393
|
+
export function formatQualityIssues(issues, userInfo, search, hasMore, nextCursor) {
|
|
394
|
+
if (!issues.length) {
|
|
395
|
+
return `**Quality Issues Report**\n\n✓ **No quality issues found!**\n\n${search ? `Search: "${search}"\n` : ''}**Total Issues**: 0\n**User**: ${userInfo?.email || 'Unknown'}\n\nYour app specifications are of high quality!`;
|
|
396
|
+
}
|
|
397
|
+
// Sort issues by severity first (Critical -> High -> Medium -> Low -> Unknown)
|
|
398
|
+
const severityOrder = ['critical', 'severe', 'high', 'medium', 'moderate', 'low', 'minor'];
|
|
399
|
+
const sortedIssues = issues.sort((a, b) => {
|
|
400
|
+
const aSeverity = (a.severity || a.priority || '').toString().toLowerCase().trim();
|
|
401
|
+
const bSeverity = (b.severity || b.priority || '').toString().toLowerCase().trim();
|
|
402
|
+
const aIndex = severityOrder.indexOf(aSeverity);
|
|
403
|
+
const bIndex = severityOrder.indexOf(bSeverity);
|
|
404
|
+
// If both are in the order, sort by position
|
|
405
|
+
if (aIndex !== -1 && bIndex !== -1) {
|
|
406
|
+
return aIndex - bIndex;
|
|
407
|
+
}
|
|
408
|
+
// If only one is in the order, prioritize it
|
|
409
|
+
if (aIndex !== -1)
|
|
410
|
+
return -1;
|
|
411
|
+
if (bIndex !== -1)
|
|
412
|
+
return 1;
|
|
413
|
+
// If neither is in the order, sort alphabetically
|
|
414
|
+
return aSeverity.localeCompare(bSeverity);
|
|
415
|
+
});
|
|
416
|
+
// Format issues in clean table format
|
|
417
|
+
const lines = [`**Quality Issues**\n`];
|
|
418
|
+
if (search) {
|
|
419
|
+
lines.push(`Search: "${search}"`);
|
|
420
|
+
}
|
|
421
|
+
lines.push(`**Showing**: ${issues.length}${hasMore ? ' of many' : ''} issues`);
|
|
422
|
+
lines.push(`**User**: ${userInfo?.email || 'Unknown'}\n`);
|
|
423
|
+
const W_SEQ = 3;
|
|
424
|
+
const W_ISSUE = 36;
|
|
425
|
+
const W_ENDPOINT = 36;
|
|
426
|
+
const W_SEVERITY = 10;
|
|
427
|
+
const W_SCORE = 6;
|
|
428
|
+
const sep = (n) => '-'.repeat(n);
|
|
429
|
+
const top = '+' + sep(W_SEQ + 2) + '+' + sep(W_ISSUE + 2) + '+' + sep(W_ENDPOINT + 2) + '+' + sep(W_SEVERITY + 2) + '+' + sep(W_SCORE + 2) + '+';
|
|
430
|
+
const mid = '+' + sep(W_SEQ + 2) + '+' + sep(W_ISSUE + 2) + '+' + sep(W_ENDPOINT + 2) + '+' + sep(W_SEVERITY + 2) + '+' + sep(W_SCORE + 2) + '+';
|
|
431
|
+
const bot = '+' + sep(W_SEQ + 2) + '+' + sep(W_ISSUE + 2) + '+' + sep(W_ENDPOINT + 2) + '+' + sep(W_SEVERITY + 2) + '+' + sep(W_SCORE + 2) + '+';
|
|
432
|
+
lines.push(top);
|
|
433
|
+
lines.push('| ' + 'Seq'.padEnd(W_SEQ) + ' | ' + 'Issue Type'.padEnd(W_ISSUE) + ' | ' + 'Endpoint'.padEnd(W_ENDPOINT) + ' | ' + 'Severity'.padEnd(W_SEVERITY) + ' | ' + 'Score'.padEnd(W_SCORE) + ' |');
|
|
434
|
+
lines.push(mid);
|
|
435
|
+
sortedIssues.forEach((issue, index) => {
|
|
436
|
+
const method = (issue.method || 'MULTIPLE').toUpperCase();
|
|
437
|
+
let path = (issue.path || '/unknown').trim();
|
|
438
|
+
if (path && !path.startsWith('/'))
|
|
439
|
+
path = '/' + path;
|
|
440
|
+
const bugTitle = issue.bug_title || 'Unlabeled Issue';
|
|
441
|
+
const tags = issue.tags && issue.tags.length > 0 ? `[${issue.tags.join(', ')}]` : '';
|
|
442
|
+
const label = tags ? `${bugTitle} ${tags}` : bugTitle;
|
|
443
|
+
const severity = issue.severity || issue.priority || 'Unknown';
|
|
444
|
+
const score = issue.score || issue.cvss_score || issue.execution_time_ms;
|
|
445
|
+
if (index < 3) {
|
|
446
|
+
console.error(`🔍 Debug Quality Issue ${index + 1}: severity="${severity}" (type: ${typeof severity}), score="${score}" (type: ${typeof score})`);
|
|
447
|
+
}
|
|
448
|
+
const issueType = label;
|
|
449
|
+
let endpoint = '';
|
|
450
|
+
if (!issue.method && !issue.path) {
|
|
451
|
+
endpoint = 'Multiple Endpoints';
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
endpoint = method + ' ' + path;
|
|
455
|
+
}
|
|
456
|
+
const truncatedIssueType = issueType.length > W_ISSUE ? issueType.substring(0, W_ISSUE - 3) + '...' : issueType;
|
|
457
|
+
const truncatedEndpoint = endpoint.length > W_ENDPOINT ? endpoint.substring(0, W_ENDPOINT - 3) + '...' : endpoint;
|
|
458
|
+
const paddedIssueType = truncatedIssueType.padEnd(W_ISSUE);
|
|
459
|
+
const paddedEndpoint = truncatedEndpoint.padEnd(W_ENDPOINT);
|
|
460
|
+
const normalizedSeverity = (severity || '').toString().toLowerCase().trim();
|
|
461
|
+
let severityIndicator;
|
|
462
|
+
let severitySymbol;
|
|
463
|
+
if (normalizedSeverity === 'critical') {
|
|
464
|
+
severityIndicator = 'CRITICAL';
|
|
465
|
+
severitySymbol = '*';
|
|
466
|
+
}
|
|
467
|
+
else if (normalizedSeverity === 'severe') {
|
|
468
|
+
severityIndicator = 'SEVERE';
|
|
469
|
+
severitySymbol = '*';
|
|
470
|
+
}
|
|
471
|
+
else if (normalizedSeverity === 'high') {
|
|
472
|
+
severityIndicator = 'HIGH';
|
|
473
|
+
severitySymbol = '*';
|
|
474
|
+
}
|
|
475
|
+
else if (normalizedSeverity === 'medium' || normalizedSeverity === 'moderate') {
|
|
476
|
+
severityIndicator = 'MED';
|
|
477
|
+
severitySymbol = '-';
|
|
478
|
+
}
|
|
479
|
+
else if (normalizedSeverity === 'low' || normalizedSeverity === 'minor') {
|
|
480
|
+
severityIndicator = 'LOW';
|
|
481
|
+
severitySymbol = '.';
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
severityIndicator = normalizedSeverity.toUpperCase() || 'UNK';
|
|
485
|
+
severitySymbol = '?';
|
|
486
|
+
}
|
|
487
|
+
const severityDisplay = (severitySymbol + ' ' + severityIndicator).padEnd(W_SEVERITY);
|
|
488
|
+
let scoreDisplay = 'N/A';
|
|
489
|
+
if (score !== undefined && score !== null) {
|
|
490
|
+
const scoreValue = parseFloat(score);
|
|
491
|
+
if (!isNaN(scoreValue)) {
|
|
492
|
+
scoreDisplay = scoreValue.toFixed(1);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
const paddedScore = scoreDisplay.padEnd(W_SCORE);
|
|
496
|
+
const rowNumber = (index + 1).toString().padStart(W_SEQ);
|
|
497
|
+
lines.push('| ' + rowNumber + ' | ' + paddedIssueType + ' | ' + paddedEndpoint + ' | ' + severityDisplay + ' | ' + paddedScore + ' |');
|
|
498
|
+
});
|
|
499
|
+
lines.push(bot);
|
|
500
|
+
// Add pagination info
|
|
501
|
+
if (hasMore && nextCursor) {
|
|
502
|
+
lines.push(`\n📄 **Pagination Controls:**`);
|
|
503
|
+
lines.push(`• **Next 20 issues**: \`show_quality_issues {"cursor": "${nextCursor}"}\``);
|
|
504
|
+
lines.push(`• **All remaining**: \`show_quality_issues {"limit": 100, "cursor": "${nextCursor}"}\``);
|
|
505
|
+
}
|
|
506
|
+
else if (hasMore) {
|
|
507
|
+
lines.push(`\n📄 **More issues available** - Run \`show_quality_issues\` again to see the next 20`);
|
|
508
|
+
}
|
|
509
|
+
return lines.join('\n');
|
|
510
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function buildAIFixPrompt(issue: any, isRefix?: boolean): string;
|
|
2
|
+
export declare function buildAIFixDesignPrompt(issue: any, isRefix?: boolean): string;
|
|
3
|
+
export declare function buildAIFixQualityPrompt(issue: any, isRefix?: boolean): string;
|
|
4
|
+
//# sourceMappingURL=promptBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promptBuilder.d.ts","sourceRoot":"","sources":["../../src/utils/promptBuilder.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,GAAE,OAAe,GAAG,MAAM,CA6D7E;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,GAAE,OAAe,GAAG,MAAM,CAiEnF;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,GAAE,OAAe,GAAG,MAAM,CAmCpF"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
export function buildAIFixPrompt(issue, isRefix = false) {
|
|
2
|
+
const excludeMethodPathLabels = ["Shadow Data"];
|
|
3
|
+
let methodPathBlock = "";
|
|
4
|
+
if (!excludeMethodPathLabels.includes(issue.label)) {
|
|
5
|
+
if (issue.method && issue.path) {
|
|
6
|
+
methodPathBlock = `HTTP Method: ${issue.method.toUpperCase()}\nPath: ${issue.path}\n\n`;
|
|
7
|
+
}
|
|
8
|
+
else if (!issue.method && !issue.path) {
|
|
9
|
+
methodPathBlock = "Endpoint: Multiple Endpoints\n\n";
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
methodPathBlock = `Endpoint: ${issue.method || 'UNKNOWN'} ${issue.path || '/unknown'}\n\n`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const prompt = `I need help implementing a code fix for the following Security issue:
|
|
16
|
+
|
|
17
|
+
${methodPathBlock}Category: ${issue.label}
|
|
18
|
+
|
|
19
|
+
Recommended remediation:
|
|
20
|
+
${issue.additionalDetails?.copilot_prompt || "No specific remediation prompt provided"}
|
|
21
|
+
|
|
22
|
+
Description:
|
|
23
|
+
${issue.additionalDetails?.description || "No description available"}
|
|
24
|
+
|
|
25
|
+
Mitigation Steps:
|
|
26
|
+
${Array.isArray(issue.additionalDetails?.mitigation)
|
|
27
|
+
? issue.additionalDetails.mitigation
|
|
28
|
+
.map((step, index) => `${index + 1}. ${step}`)
|
|
29
|
+
.join("\n")
|
|
30
|
+
: issue.additionalDetails?.mitigation || "No mitigation steps provided"}
|
|
31
|
+
|
|
32
|
+
${issue.label === "Shadow Data" && issue.errors
|
|
33
|
+
? `\nDetected Shadow Data:\n\`\`\`\n${JSON.stringify(issue.errors, null, 2)}\n\`\`\``
|
|
34
|
+
: ""}${!excludeMethodPathLabels.includes(issue.label) &&
|
|
35
|
+
Array.isArray(issue.erroneousEndpoints) &&
|
|
36
|
+
issue.erroneousEndpoints.length > 0
|
|
37
|
+
? `\nDetected Erroneous Endpoints:\n\`\`\`\n${JSON.stringify(issue.erroneousEndpoints, null, 2)}\n\`\`\``
|
|
38
|
+
: ""}
|
|
39
|
+
|
|
40
|
+
Please follow these steps:
|
|
41
|
+
1. Study the existing #codebase structure and patterns
|
|
42
|
+
2. Implement the recommended remediation
|
|
43
|
+
3. Ensure the fix adheres to best practices
|
|
44
|
+
|
|
45
|
+
Your response should address this specific security issue while maintaining the current code architecture.`;
|
|
46
|
+
return prompt;
|
|
47
|
+
}
|
|
48
|
+
export function buildAIFixDesignPrompt(issue, isRefix = false) {
|
|
49
|
+
const excludeMethodPathCategories = ["Application Design Issues"];
|
|
50
|
+
let methodPathBlock = "";
|
|
51
|
+
if (!excludeMethodPathCategories.includes(issue.category)) {
|
|
52
|
+
if (issue.method && issue.path) {
|
|
53
|
+
methodPathBlock = `HTTP Method: ${issue.method.toUpperCase()}\nPath: ${issue.path}\n\n`;
|
|
54
|
+
}
|
|
55
|
+
else if (!issue.method && !issue.path) {
|
|
56
|
+
methodPathBlock = "Endpoint: Multiple Endpoints\n\n";
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
methodPathBlock = `Endpoint: ${issue.method || 'UNKNOWN'} ${issue.path || '/unknown'}\n\n`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const prompt = `I need help implementing a code fix for the following Design issue:
|
|
63
|
+
|
|
64
|
+
${methodPathBlock}Category: ${issue.category || issue.label}
|
|
65
|
+
|
|
66
|
+
Recommended remediation:
|
|
67
|
+
${issue.remediation || "No specific remediation prompt provided"}
|
|
68
|
+
|
|
69
|
+
Description:
|
|
70
|
+
${issue.description || "No description available"}
|
|
71
|
+
|
|
72
|
+
Priority: ${issue.priority || issue.severity || "Unknown"}
|
|
73
|
+
|
|
74
|
+
Design Best Practices to Consider:
|
|
75
|
+
- RESTful API design principles
|
|
76
|
+
- Consistent naming conventions
|
|
77
|
+
- Proper HTTP status codes
|
|
78
|
+
- Resource hierarchy and relationships
|
|
79
|
+
- API versioning strategies
|
|
80
|
+
- Error handling patterns
|
|
81
|
+
- Response structure consistency
|
|
82
|
+
- Documentation standards
|
|
83
|
+
|
|
84
|
+
${issue.category === "Application Design Issues" && issue.errors
|
|
85
|
+
? `\nDetected Design Issues:\n\`\`\`\n${JSON.stringify(issue.errors, null, 2)}\n\`\`\``
|
|
86
|
+
: ""}${!excludeMethodPathCategories.includes(issue.category) &&
|
|
87
|
+
Array.isArray(issue.erroneousEndpoints) &&
|
|
88
|
+
issue.erroneousEndpoints.length > 0
|
|
89
|
+
? `\nDetected Problematic Endpoints:\n\`\`\`\n${JSON.stringify(issue.erroneousEndpoints, null, 2)}\n\`\`\``
|
|
90
|
+
: ""}
|
|
91
|
+
|
|
92
|
+
Please follow these steps:
|
|
93
|
+
1. Study the existing #codebase structure and API design patterns
|
|
94
|
+
2. Implement the recommended remediation following REST best practices
|
|
95
|
+
3. Ensure the fix improves API consistency, maintainability, and user experience
|
|
96
|
+
4. Consider backward compatibility and API versioning if needed
|
|
97
|
+
|
|
98
|
+
Your response should address this specific design issue while maintaining the current code architecture and improving overall API design quality.`;
|
|
99
|
+
return prompt;
|
|
100
|
+
}
|
|
101
|
+
export function buildAIFixQualityPrompt(issue, isRefix = false) {
|
|
102
|
+
const methodPathBlock = issue.method && issue.path
|
|
103
|
+
? `HTTP Method: ${issue.method.toUpperCase()}\nPath: ${issue.path}\n\n`
|
|
104
|
+
: issue.method || issue.path
|
|
105
|
+
? `Endpoint: ${issue.method?.toUpperCase() || 'UNKNOWN'} ${issue.path || '/unknown'}\n\n`
|
|
106
|
+
: "Endpoint: Multiple Endpoints\n\n";
|
|
107
|
+
const tagsBlock = issue.tags && issue.tags.length > 0
|
|
108
|
+
? `Tags: ${issue.tags.join(', ')}\n\n`
|
|
109
|
+
: "";
|
|
110
|
+
const metadataBlock = issue.metadata && Object.keys(issue.metadata).length > 0
|
|
111
|
+
? `Additional Details:\n${JSON.stringify(issue.metadata, null, 2)}\n\n`
|
|
112
|
+
: "";
|
|
113
|
+
const prompt = `I need help implementing a code fix for the following Quality/Specification Validation issue:
|
|
114
|
+
|
|
115
|
+
${methodPathBlock}${tagsBlock}Test Name: ${issue.display_name || issue.name}
|
|
116
|
+
|
|
117
|
+
Bug Title: ${issue.bug_title || 'No specific title provided'}
|
|
118
|
+
|
|
119
|
+
Status: ${issue.status}
|
|
120
|
+
Status Code: ${issue.status_code}
|
|
121
|
+
Severity: ${issue.severity}
|
|
122
|
+
Execution Time: ${issue.execution_time_ms}ms
|
|
123
|
+
|
|
124
|
+
${metadataBlock}Please follow these steps:
|
|
125
|
+
1. Study the existing #codebase structure and API specification patterns
|
|
126
|
+
2. Implement the recommended remediation to fix the specification validation issue
|
|
127
|
+
3. Ensure the fix adheres to OpenAPI/Swagger best practices and standards
|
|
128
|
+
4. Validate that the fix resolves the specific quality issue while maintaining API functionality
|
|
129
|
+
|
|
130
|
+
Your response should address this specific quality issue while maintaining the current code architecture and improving API specification compliance.`;
|
|
131
|
+
return prompt;
|
|
132
|
+
}
|