@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.
Files changed (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +352 -0
  3. package/dist/auth/authManager.d.ts +83 -0
  4. package/dist/auth/authManager.d.ts.map +1 -0
  5. package/dist/auth/authManager.js +555 -0
  6. package/dist/auth/sessionCache.d.ts +5 -0
  7. package/dist/auth/sessionCache.d.ts.map +1 -0
  8. package/dist/auth/sessionCache.js +29 -0
  9. package/dist/auth/sessionStorage.d.ts +53 -0
  10. package/dist/auth/sessionStorage.d.ts.map +1 -0
  11. package/dist/auth/sessionStorage.js +234 -0
  12. package/dist/auth/types.d.ts +28 -0
  13. package/dist/auth/types.d.ts.map +1 -0
  14. package/dist/auth/types.js +1 -0
  15. package/dist/config.d.ts +65 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/config.js +74 -0
  18. package/dist/server.d.ts +3 -0
  19. package/dist/server.d.ts.map +1 -0
  20. package/dist/server.js +144 -0
  21. package/dist/setup-config.d.ts +4 -0
  22. package/dist/setup-config.d.ts.map +1 -0
  23. package/dist/setup-config.js +69 -0
  24. package/dist/tools/index.d.ts +361 -0
  25. package/dist/tools/index.d.ts.map +1 -0
  26. package/dist/tools/index.js +275 -0
  27. package/dist/tools/protected/aiFixDesignIssue.d.ts +17 -0
  28. package/dist/tools/protected/aiFixDesignIssue.d.ts.map +1 -0
  29. package/dist/tools/protected/aiFixDesignIssue.js +205 -0
  30. package/dist/tools/protected/aiFixQualityIssue.d.ts +17 -0
  31. package/dist/tools/protected/aiFixQualityIssue.d.ts.map +1 -0
  32. package/dist/tools/protected/aiFixQualityIssue.js +188 -0
  33. package/dist/tools/protected/aiFixSecurityIssue.d.ts +17 -0
  34. package/dist/tools/protected/aiFixSecurityIssue.d.ts.map +1 -0
  35. package/dist/tools/protected/aiFixSecurityIssue.js +205 -0
  36. package/dist/tools/protected/checkDesignFixes.d.ts +17 -0
  37. package/dist/tools/protected/checkDesignFixes.d.ts.map +1 -0
  38. package/dist/tools/protected/checkDesignFixes.js +199 -0
  39. package/dist/tools/protected/checkQualityFixes.d.ts +17 -0
  40. package/dist/tools/protected/checkQualityFixes.d.ts.map +1 -0
  41. package/dist/tools/protected/checkQualityFixes.js +199 -0
  42. package/dist/tools/protected/checkSecurityFixes.d.ts +17 -0
  43. package/dist/tools/protected/checkSecurityFixes.d.ts.map +1 -0
  44. package/dist/tools/protected/checkSecurityFixes.js +177 -0
  45. package/dist/tools/protected/listApis.d.ts +28 -0
  46. package/dist/tools/protected/listApis.d.ts.map +1 -0
  47. package/dist/tools/protected/listApis.js +102 -0
  48. package/dist/tools/protected/logout.d.ts +11 -0
  49. package/dist/tools/protected/logout.d.ts.map +1 -0
  50. package/dist/tools/protected/logout.js +22 -0
  51. package/dist/tools/protected/manageOrganizations.d.ts +26 -0
  52. package/dist/tools/protected/manageOrganizations.d.ts.map +1 -0
  53. package/dist/tools/protected/manageOrganizations.js +147 -0
  54. package/dist/tools/protected/runDesignTest.d.ts +21 -0
  55. package/dist/tools/protected/runDesignTest.d.ts.map +1 -0
  56. package/dist/tools/protected/runDesignTest.js +132 -0
  57. package/dist/tools/protected/runQualityTest.d.ts +21 -0
  58. package/dist/tools/protected/runQualityTest.d.ts.map +1 -0
  59. package/dist/tools/protected/runQualityTest.js +150 -0
  60. package/dist/tools/protected/runSecurityTest.d.ts +21 -0
  61. package/dist/tools/protected/runSecurityTest.d.ts.map +1 -0
  62. package/dist/tools/protected/runSecurityTest.js +107 -0
  63. package/dist/tools/protected/selectApi.d.ts +24 -0
  64. package/dist/tools/protected/selectApi.d.ts.map +1 -0
  65. package/dist/tools/protected/selectApi.js +172 -0
  66. package/dist/tools/protected/setup.d.ts +11 -0
  67. package/dist/tools/protected/setup.d.ts.map +1 -0
  68. package/dist/tools/protected/setup.js +151 -0
  69. package/dist/tools/protected/showDesignIssues.d.ts +38 -0
  70. package/dist/tools/protected/showDesignIssues.d.ts.map +1 -0
  71. package/dist/tools/protected/showDesignIssues.js +201 -0
  72. package/dist/tools/protected/showFixedIssues.d.ts +11 -0
  73. package/dist/tools/protected/showFixedIssues.d.ts.map +1 -0
  74. package/dist/tools/protected/showFixedIssues.js +36 -0
  75. package/dist/tools/protected/showQualityIssues.d.ts +33 -0
  76. package/dist/tools/protected/showQualityIssues.d.ts.map +1 -0
  77. package/dist/tools/protected/showQualityIssues.js +225 -0
  78. package/dist/tools/protected/showSecurityIssues.d.ts +47 -0
  79. package/dist/tools/protected/showSecurityIssues.d.ts.map +1 -0
  80. package/dist/tools/protected/showSecurityIssues.js +212 -0
  81. package/dist/tools/protected/summarizeIssues.d.ts +11 -0
  82. package/dist/tools/protected/summarizeIssues.d.ts.map +1 -0
  83. package/dist/tools/protected/summarizeIssues.js +161 -0
  84. package/dist/tools/protected/userInfo.d.ts +11 -0
  85. package/dist/tools/protected/userInfo.d.ts.map +1 -0
  86. package/dist/tools/protected/userInfo.js +21 -0
  87. package/dist/tools/protected/visionAiAppLearning.d.ts +37 -0
  88. package/dist/tools/protected/visionAiAppLearning.d.ts.map +1 -0
  89. package/dist/tools/protected/visionAiAppLearning.js +122 -0
  90. package/dist/tools/public/authStatus.d.ts +11 -0
  91. package/dist/tools/public/authStatus.d.ts.map +1 -0
  92. package/dist/tools/public/authStatus.js +78 -0
  93. package/dist/tools/public/login.d.ts +12 -0
  94. package/dist/tools/public/login.d.ts.map +1 -0
  95. package/dist/tools/public/login.js +230 -0
  96. package/dist/types/api.d.ts +12 -0
  97. package/dist/types/api.d.ts.map +1 -0
  98. package/dist/types/api.js +1 -0
  99. package/dist/utils/dockerRunner.d.ts +44 -0
  100. package/dist/utils/dockerRunner.d.ts.map +1 -0
  101. package/dist/utils/dockerRunner.js +300 -0
  102. package/dist/utils/formatters.d.ts +14 -0
  103. package/dist/utils/formatters.d.ts.map +1 -0
  104. package/dist/utils/formatters.js +510 -0
  105. package/dist/utils/promptBuilder.d.ts +4 -0
  106. package/dist/utils/promptBuilder.d.ts.map +1 -0
  107. package/dist/utils/promptBuilder.js +132 -0
  108. 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
+ }