@democratize-quality/mcp-server 1.2.0 → 1.2.1
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/cli.js +248 -0
- package/package.json +7 -5
- package/src/chatmodes//360/237/214/220 api-generator.chatmode.md" +409 -0
- package/src/chatmodes//360/237/214/220 api-healer.chatmode.md" +494 -0
- package/src/chatmodes//360/237/214/220 api-planner.chatmode.md" +954 -0
- package/src/config/environments/api-only.js +72 -0
- package/src/config/environments/development.js +73 -0
- package/src/config/environments/production.js +88 -0
- package/src/config/index.js +360 -0
- package/src/config/server.js +60 -0
- package/src/config/tools/api.js +86 -0
- package/src/config/tools/browser.js +109 -0
- package/src/config/tools/default.js +51 -0
- package/src/docs/Agent_README.md +310 -0
- package/src/docs/QUICK_REFERENCE.md +111 -0
- package/src/server.ts +234 -0
- package/src/services/browserService.js +344 -0
- package/src/skills/api-planning/SKILL.md +224 -0
- package/src/skills/test-execution/SKILL.md +777 -0
- package/src/skills/test-generation/SKILL.md +309 -0
- package/src/skills/test-healing/SKILL.md +405 -0
- package/src/tools/api/api-generator.js +1884 -0
- package/src/tools/api/api-healer.js +636 -0
- package/src/tools/api/api-planner.js +2617 -0
- package/src/tools/api/api-project-setup.js +332 -0
- package/src/tools/api/api-request.js +660 -0
- package/src/tools/api/api-session-report.js +1297 -0
- package/src/tools/api/api-session-status.js +414 -0
- package/src/tools/api/prompts/README.md +293 -0
- package/src/tools/api/prompts/generation-prompts.js +722 -0
- package/src/tools/api/prompts/healing-prompts.js +214 -0
- package/src/tools/api/prompts/index.js +44 -0
- package/src/tools/api/prompts/orchestrator.js +353 -0
- package/src/tools/api/prompts/validation-rules.js +358 -0
- package/src/tools/base/ToolBase.js +249 -0
- package/src/tools/base/ToolRegistry.js +288 -0
- package/src/tools/browser/advanced/browser-console.js +403 -0
- package/src/tools/browser/advanced/browser-dialog.js +338 -0
- package/src/tools/browser/advanced/browser-evaluate.js +356 -0
- package/src/tools/browser/advanced/browser-file.js +499 -0
- package/src/tools/browser/advanced/browser-keyboard.js +362 -0
- package/src/tools/browser/advanced/browser-mouse.js +351 -0
- package/src/tools/browser/advanced/browser-network.js +440 -0
- package/src/tools/browser/advanced/browser-pdf.js +426 -0
- package/src/tools/browser/advanced/browser-tabs.js +516 -0
- package/src/tools/browser/advanced/browser-wait.js +397 -0
- package/src/tools/browser/click.js +187 -0
- package/src/tools/browser/close.js +79 -0
- package/src/tools/browser/dom.js +89 -0
- package/src/tools/browser/launch.js +86 -0
- package/src/tools/browser/navigate.js +289 -0
- package/src/tools/browser/screenshot.js +370 -0
- package/src/tools/browser/type.js +193 -0
- package/src/tools/index.js +114 -0
- package/src/utils/agentInstaller.js +437 -0
- package/src/utils/browserHelpers.js +102 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2025 Democratize Quality
|
|
3
|
+
*
|
|
4
|
+
* This file is part of Democratize Quality MCP Server.
|
|
5
|
+
*
|
|
6
|
+
* Democratize Quality MCP Server is free software: you can redistribute it and/or modify
|
|
7
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
8
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
* (at your option) any later version.
|
|
10
|
+
*
|
|
11
|
+
* Democratize Quality MCP Server is distributed in the hope that it will be useful,
|
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
* GNU Affero General Public License for more details.
|
|
15
|
+
*
|
|
16
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
17
|
+
* along with Democratize Quality MCP Server. If not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const ToolBase = require('../base/ToolBase');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* API Session Status Tool - Query API test session status and results
|
|
24
|
+
*/
|
|
25
|
+
class ApiSessionStatusTool extends ToolBase {
|
|
26
|
+
static definition = {
|
|
27
|
+
name: "api_session_status",
|
|
28
|
+
description: "Query API test session status, logs, and results by sessionId. Provides detailed information about request history and validation results.",
|
|
29
|
+
input_schema: {
|
|
30
|
+
type: "object",
|
|
31
|
+
properties: {
|
|
32
|
+
sessionId: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "The session ID to query"
|
|
35
|
+
},
|
|
36
|
+
includeDetails: {
|
|
37
|
+
type: "boolean",
|
|
38
|
+
default: true,
|
|
39
|
+
description: "Whether to include detailed request/response data"
|
|
40
|
+
},
|
|
41
|
+
filterByType: {
|
|
42
|
+
type: "string",
|
|
43
|
+
enum: ["single", "request", "chain", "all"],
|
|
44
|
+
default: "all",
|
|
45
|
+
description: "Filter logs by request type"
|
|
46
|
+
},
|
|
47
|
+
limit: {
|
|
48
|
+
type: "number",
|
|
49
|
+
default: 50,
|
|
50
|
+
description: "Maximum number of log entries to return"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
required: ["sessionId"]
|
|
54
|
+
},
|
|
55
|
+
output_schema: {
|
|
56
|
+
type: "object",
|
|
57
|
+
properties: {
|
|
58
|
+
success: { type: "boolean", description: "Whether the session was found" },
|
|
59
|
+
found: { type: "boolean", description: "Whether the session exists" },
|
|
60
|
+
session: {
|
|
61
|
+
type: "object",
|
|
62
|
+
properties: {
|
|
63
|
+
sessionId: { type: "string" },
|
|
64
|
+
status: { type: "string" },
|
|
65
|
+
startTime: { type: "string" },
|
|
66
|
+
endTime: { type: "string" },
|
|
67
|
+
executionTime: { type: "number" },
|
|
68
|
+
error: { type: "string" }
|
|
69
|
+
},
|
|
70
|
+
description: "Session metadata"
|
|
71
|
+
},
|
|
72
|
+
summary: {
|
|
73
|
+
type: "object",
|
|
74
|
+
properties: {
|
|
75
|
+
totalRequests: { type: "number" },
|
|
76
|
+
successfulRequests: { type: "number" },
|
|
77
|
+
failedRequests: { type: "number" },
|
|
78
|
+
chainSteps: { type: "number" },
|
|
79
|
+
logEntries: { type: "number" }
|
|
80
|
+
},
|
|
81
|
+
description: "Session summary statistics"
|
|
82
|
+
},
|
|
83
|
+
logs: {
|
|
84
|
+
type: "array",
|
|
85
|
+
description: "Session log entries (filtered and limited)"
|
|
86
|
+
},
|
|
87
|
+
validationSummary: {
|
|
88
|
+
type: "object",
|
|
89
|
+
properties: {
|
|
90
|
+
passedValidations: { type: "number" },
|
|
91
|
+
failedValidations: { type: "number" },
|
|
92
|
+
validationRate: { type: "number" }
|
|
93
|
+
},
|
|
94
|
+
description: "Validation statistics"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
required: ["success", "found"]
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
constructor() {
|
|
102
|
+
super();
|
|
103
|
+
// Access the global session store
|
|
104
|
+
if (!global.__API_SESSION_STORE__) {
|
|
105
|
+
global.__API_SESSION_STORE__ = new Map();
|
|
106
|
+
}
|
|
107
|
+
this.sessionStore = global.__API_SESSION_STORE__;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async execute(parameters) {
|
|
111
|
+
const {
|
|
112
|
+
sessionId,
|
|
113
|
+
includeDetails = true,
|
|
114
|
+
filterByType = "all",
|
|
115
|
+
limit = 50
|
|
116
|
+
} = parameters;
|
|
117
|
+
|
|
118
|
+
const session = this.sessionStore.get(sessionId);
|
|
119
|
+
|
|
120
|
+
if (!session) {
|
|
121
|
+
return {
|
|
122
|
+
success: false,
|
|
123
|
+
found: false,
|
|
124
|
+
message: `Session not found: ${sessionId}`,
|
|
125
|
+
availableSessions: Array.from(this.sessionStore.keys())
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Filter logs by type
|
|
130
|
+
let filteredLogs = session.logs || [];
|
|
131
|
+
if (filterByType !== "all") {
|
|
132
|
+
filteredLogs = filteredLogs.filter(log => log.type === filterByType);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Apply limit
|
|
136
|
+
const logs = filteredLogs.slice(-limit);
|
|
137
|
+
|
|
138
|
+
// Generate summary statistics
|
|
139
|
+
const summary = this.generateSummary(session.logs || []);
|
|
140
|
+
const validationSummary = this.generateValidationSummary(session.logs || []);
|
|
141
|
+
|
|
142
|
+
// Prepare session metadata (without sensitive details if not requested)
|
|
143
|
+
const sessionMetadata = {
|
|
144
|
+
sessionId: session.sessionId,
|
|
145
|
+
status: session.status,
|
|
146
|
+
startTime: session.startTime,
|
|
147
|
+
endTime: session.endTime,
|
|
148
|
+
executionTime: session.executionTime,
|
|
149
|
+
error: session.error
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// Optionally strip detailed request/response data
|
|
153
|
+
const processedLogs = includeDetails
|
|
154
|
+
? logs
|
|
155
|
+
: logs.map(log => this.stripSensitiveData(log));
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
success: true,
|
|
159
|
+
found: true,
|
|
160
|
+
session: sessionMetadata,
|
|
161
|
+
summary,
|
|
162
|
+
validationSummary,
|
|
163
|
+
logs: processedLogs,
|
|
164
|
+
logCount: logs.length,
|
|
165
|
+
totalLogCount: (session.logs || []).length
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Generate summary statistics for the session
|
|
171
|
+
*/
|
|
172
|
+
generateSummary(logs) {
|
|
173
|
+
const summary = {
|
|
174
|
+
totalRequests: 0,
|
|
175
|
+
successfulRequests: 0,
|
|
176
|
+
failedRequests: 0,
|
|
177
|
+
chainSteps: 0,
|
|
178
|
+
singleRequests: 0,
|
|
179
|
+
logEntries: logs.length
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
for (const log of logs) {
|
|
183
|
+
switch (log.type) {
|
|
184
|
+
case 'single':
|
|
185
|
+
summary.totalRequests++;
|
|
186
|
+
summary.singleRequests++;
|
|
187
|
+
if (this.isRequestSuccessful(log)) {
|
|
188
|
+
summary.successfulRequests++;
|
|
189
|
+
} else {
|
|
190
|
+
summary.failedRequests++;
|
|
191
|
+
}
|
|
192
|
+
break;
|
|
193
|
+
|
|
194
|
+
case 'request':
|
|
195
|
+
summary.totalRequests++;
|
|
196
|
+
summary.chainSteps++;
|
|
197
|
+
if (this.isRequestSuccessful(log)) {
|
|
198
|
+
summary.successfulRequests++;
|
|
199
|
+
} else {
|
|
200
|
+
summary.failedRequests++;
|
|
201
|
+
}
|
|
202
|
+
break;
|
|
203
|
+
|
|
204
|
+
case 'chain':
|
|
205
|
+
// Chain logs contain summary of multiple steps
|
|
206
|
+
if (log.steps) {
|
|
207
|
+
summary.chainSteps += log.steps.length;
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return summary;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Generate validation summary statistics
|
|
218
|
+
*/
|
|
219
|
+
generateValidationSummary(logs) {
|
|
220
|
+
let passedValidations = 0;
|
|
221
|
+
let failedValidations = 0;
|
|
222
|
+
let totalValidations = 0;
|
|
223
|
+
|
|
224
|
+
for (const log of logs) {
|
|
225
|
+
if (log.validation && log.bodyValidation) {
|
|
226
|
+
totalValidations++;
|
|
227
|
+
|
|
228
|
+
const isValid = log.validation.status &&
|
|
229
|
+
log.validation.contentType &&
|
|
230
|
+
log.bodyValidation.matched;
|
|
231
|
+
|
|
232
|
+
if (isValid) {
|
|
233
|
+
passedValidations++;
|
|
234
|
+
} else {
|
|
235
|
+
failedValidations++;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Also check chain steps
|
|
240
|
+
if (log.type === 'chain' && log.steps) {
|
|
241
|
+
for (const step of log.steps) {
|
|
242
|
+
if (step.validation && step.bodyValidation) {
|
|
243
|
+
totalValidations++;
|
|
244
|
+
|
|
245
|
+
const isValid = step.validation.status &&
|
|
246
|
+
step.validation.contentType &&
|
|
247
|
+
step.bodyValidation.matched;
|
|
248
|
+
|
|
249
|
+
if (isValid) {
|
|
250
|
+
passedValidations++;
|
|
251
|
+
} else {
|
|
252
|
+
failedValidations++;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
passedValidations,
|
|
261
|
+
failedValidations,
|
|
262
|
+
totalValidations,
|
|
263
|
+
validationRate: totalValidations > 0
|
|
264
|
+
? Math.round((passedValidations / totalValidations) * 100) / 100
|
|
265
|
+
: 0
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Check if a request was successful based on validation
|
|
271
|
+
*/
|
|
272
|
+
isRequestSuccessful(log) {
|
|
273
|
+
return log.validation &&
|
|
274
|
+
log.bodyValidation &&
|
|
275
|
+
log.validation.status &&
|
|
276
|
+
log.validation.contentType &&
|
|
277
|
+
log.bodyValidation.matched;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Remove sensitive data from logs when details are not requested
|
|
282
|
+
*/
|
|
283
|
+
stripSensitiveData(log) {
|
|
284
|
+
const stripped = {
|
|
285
|
+
type: log.type,
|
|
286
|
+
timestamp: log.timestamp
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
if (log.request) {
|
|
290
|
+
stripped.request = {
|
|
291
|
+
method: log.request.method,
|
|
292
|
+
url: log.request.url,
|
|
293
|
+
hasHeaders: !!(log.request.headers && Object.keys(log.request.headers).length > 0),
|
|
294
|
+
hasData: !!log.request.data
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (log.response) {
|
|
299
|
+
stripped.response = {
|
|
300
|
+
status: log.response.status,
|
|
301
|
+
contentType: log.response.contentType,
|
|
302
|
+
hasBody: !!log.response.body
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (log.validation) {
|
|
307
|
+
stripped.validation = log.validation;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (log.bodyValidation) {
|
|
311
|
+
stripped.bodyValidation = {
|
|
312
|
+
matched: log.bodyValidation.matched,
|
|
313
|
+
reason: log.bodyValidation.reason
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Handle chain steps
|
|
318
|
+
if (log.steps) {
|
|
319
|
+
stripped.steps = log.steps.map(step => this.stripSensitiveData({
|
|
320
|
+
type: 'request',
|
|
321
|
+
request: step.request || {
|
|
322
|
+
method: step.method,
|
|
323
|
+
url: step.url,
|
|
324
|
+
headers: step.headers,
|
|
325
|
+
data: step.data
|
|
326
|
+
},
|
|
327
|
+
response: {
|
|
328
|
+
status: step.status,
|
|
329
|
+
contentType: step.contentType,
|
|
330
|
+
body: step.body
|
|
331
|
+
},
|
|
332
|
+
validation: step.validation,
|
|
333
|
+
bodyValidation: step.bodyValidation
|
|
334
|
+
}));
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return stripped;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Get detailed analysis of a specific request by index
|
|
342
|
+
*/
|
|
343
|
+
getRequestDetails(sessionId, requestIndex) {
|
|
344
|
+
const session = this.sessionStore.get(sessionId);
|
|
345
|
+
if (!session || !session.logs) {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const requestLogs = session.logs.filter(log =>
|
|
350
|
+
log.type === 'single' || log.type === 'request'
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
if (requestIndex >= requestLogs.length) {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return requestLogs[requestIndex];
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Get session timing analysis
|
|
362
|
+
*/
|
|
363
|
+
getTimingAnalysis(sessionId) {
|
|
364
|
+
const session = this.sessionStore.get(sessionId);
|
|
365
|
+
if (!session || !session.logs) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const requests = session.logs.filter(log =>
|
|
370
|
+
log.type === 'single' || log.type === 'request'
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
if (requests.length === 0) {
|
|
374
|
+
return { message: 'No requests found for timing analysis' };
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Calculate request intervals
|
|
378
|
+
const timings = [];
|
|
379
|
+
for (let i = 0; i < requests.length; i++) {
|
|
380
|
+
const current = new Date(requests[i].timestamp);
|
|
381
|
+
const previous = i > 0 ? new Date(requests[i - 1].timestamp) : new Date(session.startTime);
|
|
382
|
+
|
|
383
|
+
timings.push({
|
|
384
|
+
requestIndex: i,
|
|
385
|
+
timestamp: requests[i].timestamp,
|
|
386
|
+
intervalMs: current.getTime() - previous.getTime()
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return {
|
|
391
|
+
totalRequests: requests.length,
|
|
392
|
+
sessionDuration: session.executionTime || 0,
|
|
393
|
+
averageInterval: timings.reduce((sum, t) => sum + t.intervalMs, 0) / timings.length,
|
|
394
|
+
timings
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* List all available sessions
|
|
400
|
+
*/
|
|
401
|
+
listAllSessions() {
|
|
402
|
+
return Array.from(this.sessionStore.entries()).map(([id, session]) => ({
|
|
403
|
+
sessionId: id,
|
|
404
|
+
status: session.status,
|
|
405
|
+
startTime: session.startTime,
|
|
406
|
+
requestCount: (session.logs || []).filter(log =>
|
|
407
|
+
log.type === 'single' || log.type === 'request'
|
|
408
|
+
).length,
|
|
409
|
+
logCount: (session.logs || []).length
|
|
410
|
+
}));
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
module.exports = ApiSessionStatusTool;
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Prompt Orchestration System
|
|
2
|
+
|
|
3
|
+
This directory contains the prompt orchestration system for AI-based test code generation.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────────────────────────────┐
|
|
9
|
+
│ ORCHESTRATION PIPELINE │
|
|
10
|
+
└─────────────────────────────────────────────┘
|
|
11
|
+
|
|
12
|
+
1️⃣ PLANNING (Structured - Code)
|
|
13
|
+
├─ Parse test plan markdown
|
|
14
|
+
├─ Extract scenarios & context
|
|
15
|
+
└─ Build structured data
|
|
16
|
+
|
|
17
|
+
2️⃣ GENERATION (AI-Driven)
|
|
18
|
+
├─ Load generation prompts
|
|
19
|
+
├─ Construct context
|
|
20
|
+
├─ Call AI (GitHub Copilot API)
|
|
21
|
+
└─ Return generated code
|
|
22
|
+
|
|
23
|
+
3️⃣ VALIDATION (Automated - Code)
|
|
24
|
+
├─ Check syntax & structure
|
|
25
|
+
├─ Validate patterns & conventions
|
|
26
|
+
└─ Report issues
|
|
27
|
+
|
|
28
|
+
4️⃣ HEALING (AI-Driven - If Needed)
|
|
29
|
+
├─ Load healing prompts
|
|
30
|
+
├─ Include issue details
|
|
31
|
+
├─ Call AI to fix issues
|
|
32
|
+
└─ Return fixed code
|
|
33
|
+
|
|
34
|
+
5️⃣ OUTPUT
|
|
35
|
+
├─ Write validated test files
|
|
36
|
+
└─ Report generation status
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Files
|
|
40
|
+
|
|
41
|
+
### `generation-prompts.js`
|
|
42
|
+
Contains all prompts for generating test code.
|
|
43
|
+
|
|
44
|
+
**Exports:**
|
|
45
|
+
- `playwrightScenario` - Generate Playwright API tests
|
|
46
|
+
- `jestScenario` - Generate Jest/axios tests
|
|
47
|
+
- `postmanTestScript` - Generate Postman test scripts
|
|
48
|
+
|
|
49
|
+
**Usage:**
|
|
50
|
+
```javascript
|
|
51
|
+
const prompts = require('./generation-prompts');
|
|
52
|
+
|
|
53
|
+
const context = {
|
|
54
|
+
scenario: { title, method, endpoint, data, expect },
|
|
55
|
+
baseUrl: 'https://api.example.com',
|
|
56
|
+
language: 'typescript',
|
|
57
|
+
options: { format: 'playwright' }
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const systemPrompt = prompts.playwrightScenario.system;
|
|
61
|
+
const userPrompt = prompts.playwrightScenario.user(context);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### `validation-rules.js`
|
|
65
|
+
Validates generated code against quality rules.
|
|
66
|
+
|
|
67
|
+
**Exports:**
|
|
68
|
+
- `playwright` - Playwright validation rules
|
|
69
|
+
- `jest` - Jest validation rules
|
|
70
|
+
- `postman` - Postman validation rules
|
|
71
|
+
- `getValidator(format)` - Get validator for format
|
|
72
|
+
|
|
73
|
+
**Usage:**
|
|
74
|
+
```javascript
|
|
75
|
+
const validation = require('./validation-rules');
|
|
76
|
+
|
|
77
|
+
const validator = validation.getValidator('playwright');
|
|
78
|
+
const result = validator.validateAll(code, 'typescript');
|
|
79
|
+
|
|
80
|
+
if (!result.valid) {
|
|
81
|
+
console.log('Issues:', result.issues);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Validation Checks:**
|
|
86
|
+
- ✅ Proper async/await usage
|
|
87
|
+
- ✅ Correct URL construction (no template literal escaping bugs!)
|
|
88
|
+
- ✅ Required assertions present
|
|
89
|
+
- ✅ Syntax correctness (balanced brackets/braces)
|
|
90
|
+
- ✅ Framework-specific patterns
|
|
91
|
+
|
|
92
|
+
### `healing-prompts.js`
|
|
93
|
+
Prompts for fixing validation issues.
|
|
94
|
+
|
|
95
|
+
**Exports:**
|
|
96
|
+
- `playwrightHealing` - Fix Playwright test issues
|
|
97
|
+
- `jestHealing` - Fix Jest test issues
|
|
98
|
+
- `genericHealing` - Fix any code issues
|
|
99
|
+
|
|
100
|
+
**Usage:**
|
|
101
|
+
```javascript
|
|
102
|
+
const healing = require('./healing-prompts');
|
|
103
|
+
|
|
104
|
+
const context = {
|
|
105
|
+
originalCode: '...',
|
|
106
|
+
issues: [{ severity, message, fix }],
|
|
107
|
+
scenario: { ... }
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const systemPrompt = healing.playwrightHealing.system;
|
|
111
|
+
const userPrompt = healing.playwrightHealing.user(context);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### `orchestrator.js`
|
|
115
|
+
Main orchestrator class that coordinates the workflow.
|
|
116
|
+
|
|
117
|
+
**Usage:**
|
|
118
|
+
```javascript
|
|
119
|
+
const PromptOrchestrator = require('./orchestrator');
|
|
120
|
+
|
|
121
|
+
const orchestrator = new PromptOrchestrator({
|
|
122
|
+
maxHealingAttempts: 3,
|
|
123
|
+
language: 'typescript',
|
|
124
|
+
outputFormat: 'playwright',
|
|
125
|
+
verbose: true
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Generate single test scenario
|
|
129
|
+
const result = await orchestrator.generateTestCode(
|
|
130
|
+
{ scenario, baseUrl },
|
|
131
|
+
aiGenerator
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
// Generate complete test file
|
|
135
|
+
const fileContent = orchestrator.generateTestFile(
|
|
136
|
+
testBodies,
|
|
137
|
+
testPlan,
|
|
138
|
+
{ format, language, sessionId }
|
|
139
|
+
);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Key Methods:**
|
|
143
|
+
- `generateTestCode(context, aiGenerator)` - Generate & validate single test
|
|
144
|
+
- `generateTestFile(testBodies, testPlan, options)` - Generate complete file
|
|
145
|
+
- Internal: `_generateCode()`, `_validateCode()`, `_healCode()`
|
|
146
|
+
|
|
147
|
+
## Workflow Example
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
// 1. Create orchestrator
|
|
151
|
+
const orchestrator = new PromptOrchestrator({
|
|
152
|
+
language: 'typescript',
|
|
153
|
+
outputFormat: 'playwright',
|
|
154
|
+
maxHealingAttempts: 3,
|
|
155
|
+
verbose: true
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// 2. Generate test for each scenario
|
|
159
|
+
const testBodies = {};
|
|
160
|
+
for (const [sectionIdx, section] of testPlan.sections.entries()) {
|
|
161
|
+
for (const [scenarioIdx, scenario] of section.scenarios.entries()) {
|
|
162
|
+
const context = {
|
|
163
|
+
scenario,
|
|
164
|
+
baseUrl: testPlan.baseUrl
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// AI generates → validates → heals if needed
|
|
168
|
+
const result = await orchestrator.generateTestCode(context, aiGenerator);
|
|
169
|
+
|
|
170
|
+
testBodies[`${sectionIdx}-${scenarioIdx}`] = result.code;
|
|
171
|
+
|
|
172
|
+
if (!result.valid) {
|
|
173
|
+
console.warn(`⚠️ Test has issues:`, result.issues);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 3. Generate complete file
|
|
179
|
+
const fileContent = orchestrator.generateTestFile(testBodies, testPlan, {
|
|
180
|
+
format: 'playwright',
|
|
181
|
+
language: 'typescript',
|
|
182
|
+
sessionId: 'test-123'
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// 4. Write file
|
|
186
|
+
fs.writeFileSync('tests/api-tests.spec.ts', fileContent);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Benefits
|
|
190
|
+
|
|
191
|
+
### 🎯 **Separation of Concerns**
|
|
192
|
+
- **Planning** = Deterministic logic (code handles this)
|
|
193
|
+
- **Generation** = Creative task (AI handles this)
|
|
194
|
+
- **Validation** = Quality gates (code handles this)
|
|
195
|
+
- **Healing** = Error correction (AI handles this)
|
|
196
|
+
|
|
197
|
+
### 🔄 **Self-Correcting**
|
|
198
|
+
- Validation catches issues automatically
|
|
199
|
+
- Healing fixes them without manual intervention
|
|
200
|
+
- Up to 3 attempts to get perfect code
|
|
201
|
+
- Graceful degradation if healing fails
|
|
202
|
+
|
|
203
|
+
### 📝 **Easy Prompt Engineering**
|
|
204
|
+
- All prompts in one place
|
|
205
|
+
- Easy to iterate and improve
|
|
206
|
+
- Version control for prompts
|
|
207
|
+
- A/B testing different strategies
|
|
208
|
+
|
|
209
|
+
### 🚀 **Future-Proof**
|
|
210
|
+
- Swap AI providers easily
|
|
211
|
+
- Add new output formats quickly
|
|
212
|
+
- Extend validation rules
|
|
213
|
+
- Improve prompts without code changes
|
|
214
|
+
|
|
215
|
+
## Prompt Engineering Tips
|
|
216
|
+
|
|
217
|
+
### For Generation Prompts
|
|
218
|
+
1. **Be Specific**: Clear requirements and examples
|
|
219
|
+
2. **Include Context**: Provide all necessary data
|
|
220
|
+
3. **Set Constraints**: Specify what NOT to do
|
|
221
|
+
4. **Use Examples**: Show desired output format
|
|
222
|
+
5. **Iterate**: Test and refine based on results
|
|
223
|
+
|
|
224
|
+
### For Healing Prompts
|
|
225
|
+
1. **Include Original Code**: Show what needs fixing
|
|
226
|
+
2. **List Specific Issues**: Enumerate all problems
|
|
227
|
+
3. **Provide Fixes**: Suggest how to fix each issue
|
|
228
|
+
4. **Maintain Context**: Reference original scenario
|
|
229
|
+
5. **Keep It Focused**: Fix only reported issues
|
|
230
|
+
|
|
231
|
+
## Extending the System
|
|
232
|
+
|
|
233
|
+
### Add New Output Format
|
|
234
|
+
1. Add generation prompt in `generation-prompts.js`
|
|
235
|
+
2. Add validation rules in `validation-rules.js`
|
|
236
|
+
3. Add healing prompt in `healing-prompts.js`
|
|
237
|
+
4. Update orchestrator's `_getGenerationPrompt()` and `_getHealingPrompt()`
|
|
238
|
+
5. Add file generation in `generateTestFile()`
|
|
239
|
+
|
|
240
|
+
### Add New Validation Rule
|
|
241
|
+
1. Open `validation-rules.js`
|
|
242
|
+
2. Add new validation function to appropriate format
|
|
243
|
+
3. Update `validateAll()` to include new check
|
|
244
|
+
4. Test with sample code
|
|
245
|
+
|
|
246
|
+
### Improve Prompts
|
|
247
|
+
1. Edit prompt in respective file
|
|
248
|
+
2. Test with real scenarios
|
|
249
|
+
3. Compare before/after quality
|
|
250
|
+
4. Iterate based on results
|
|
251
|
+
|
|
252
|
+
## AI Generator Interface
|
|
253
|
+
|
|
254
|
+
The orchestrator expects an AI generator with this interface:
|
|
255
|
+
|
|
256
|
+
```javascript
|
|
257
|
+
class AIGenerator {
|
|
258
|
+
/**
|
|
259
|
+
* Generate code from prompts
|
|
260
|
+
* @param {string} systemPrompt - System/role prompt
|
|
261
|
+
* @param {string} userPrompt - User request prompt
|
|
262
|
+
* @returns {Promise<string>} - Generated code
|
|
263
|
+
*/
|
|
264
|
+
async generate(systemPrompt, userPrompt) {
|
|
265
|
+
// Call AI API (GitHub Copilot, OpenAI, etc.)
|
|
266
|
+
// Return generated code as string
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Configuration
|
|
272
|
+
|
|
273
|
+
**Orchestrator Options:**
|
|
274
|
+
- `maxHealingAttempts` (default: 3) - Max healing retries
|
|
275
|
+
- `language` (default: 'typescript') - Target language
|
|
276
|
+
- `outputFormat` (default: 'playwright') - Test format
|
|
277
|
+
- `verbose` (default: false) - Enable logging
|
|
278
|
+
|
|
279
|
+
## Future Enhancements
|
|
280
|
+
|
|
281
|
+
- [ ] Add LLM-specific prompt optimizations
|
|
282
|
+
- [ ] Support streaming responses
|
|
283
|
+
- [ ] Add prompt caching for performance
|
|
284
|
+
- [ ] Implement prompt versioning
|
|
285
|
+
- [ ] Add metrics and analytics
|
|
286
|
+
- [ ] Support custom validation rules
|
|
287
|
+
- [ ] Add prompt templates for common patterns
|
|
288
|
+
- [ ] Implement prompt AB testing framework
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
**Generated by:** Democratize Quality MCP Server
|
|
293
|
+
**Architecture:** Prompt Orchestration (Planning → Generation → Validation → Healing)
|