@democratize-quality/mcp-server 1.1.8 → 1.2.0

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 (64) hide show
  1. package/LICENSE +658 -12
  2. package/README.md +11 -6
  3. package/dist/server.d.ts +41 -0
  4. package/dist/server.d.ts.map +1 -0
  5. package/dist/server.js +225 -0
  6. package/dist/server.js.map +1 -0
  7. package/package.json +24 -25
  8. package/browserControl.js +0 -113
  9. package/cli.js +0 -228
  10. package/mcpServer.js +0 -335
  11. package/run-server.js +0 -140
  12. package/src/chatmodes//360/237/214/220 api-generator.chatmode.md" +0 -409
  13. package/src/chatmodes//360/237/214/220 api-healer.chatmode.md" +0 -494
  14. package/src/chatmodes//360/237/214/220 api-planner.chatmode.md" +0 -954
  15. package/src/config/environments/api-only.js +0 -53
  16. package/src/config/environments/development.js +0 -54
  17. package/src/config/environments/production.js +0 -69
  18. package/src/config/index.js +0 -341
  19. package/src/config/server.js +0 -41
  20. package/src/config/tools/api.js +0 -67
  21. package/src/config/tools/browser.js +0 -90
  22. package/src/config/tools/default.js +0 -32
  23. package/src/docs/Agent_README.md +0 -310
  24. package/src/docs/QUICK_REFERENCE.md +0 -111
  25. package/src/services/browserService.js +0 -325
  26. package/src/skills/api-planning/SKILL.md +0 -224
  27. package/src/skills/test-execution/SKILL.md +0 -728
  28. package/src/skills/test-generation/SKILL.md +0 -309
  29. package/src/skills/test-healing/SKILL.md +0 -405
  30. package/src/tools/api/api-generator.js +0 -1865
  31. package/src/tools/api/api-healer.js +0 -617
  32. package/src/tools/api/api-planner.js +0 -2598
  33. package/src/tools/api/api-project-setup.js +0 -313
  34. package/src/tools/api/api-request.js +0 -641
  35. package/src/tools/api/api-session-report.js +0 -1278
  36. package/src/tools/api/api-session-status.js +0 -395
  37. package/src/tools/api/prompts/README.md +0 -293
  38. package/src/tools/api/prompts/generation-prompts.js +0 -703
  39. package/src/tools/api/prompts/healing-prompts.js +0 -195
  40. package/src/tools/api/prompts/index.js +0 -25
  41. package/src/tools/api/prompts/orchestrator.js +0 -334
  42. package/src/tools/api/prompts/validation-rules.js +0 -339
  43. package/src/tools/base/ToolBase.js +0 -230
  44. package/src/tools/base/ToolRegistry.js +0 -269
  45. package/src/tools/browser/advanced/browser-console.js +0 -384
  46. package/src/tools/browser/advanced/browser-dialog.js +0 -319
  47. package/src/tools/browser/advanced/browser-evaluate.js +0 -337
  48. package/src/tools/browser/advanced/browser-file.js +0 -480
  49. package/src/tools/browser/advanced/browser-keyboard.js +0 -343
  50. package/src/tools/browser/advanced/browser-mouse.js +0 -332
  51. package/src/tools/browser/advanced/browser-network.js +0 -421
  52. package/src/tools/browser/advanced/browser-pdf.js +0 -407
  53. package/src/tools/browser/advanced/browser-tabs.js +0 -497
  54. package/src/tools/browser/advanced/browser-wait.js +0 -378
  55. package/src/tools/browser/click.js +0 -168
  56. package/src/tools/browser/close.js +0 -60
  57. package/src/tools/browser/dom.js +0 -70
  58. package/src/tools/browser/launch.js +0 -67
  59. package/src/tools/browser/navigate.js +0 -270
  60. package/src/tools/browser/screenshot.js +0 -351
  61. package/src/tools/browser/type.js +0 -174
  62. package/src/tools/index.js +0 -95
  63. package/src/utils/agentInstaller.js +0 -418
  64. package/src/utils/browserHelpers.js +0 -83
@@ -1,174 +0,0 @@
1
- const ToolBase = require('../base/ToolBase');
2
- const browserService = require('../../services/browserService');
3
-
4
- /**
5
- * Browser Type Tool
6
- * Types text into a specific input field in the browser with Playwright-style locators
7
- */
8
- class BrowserTypeTool extends ToolBase {
9
- static definition = {
10
- name: "browser_type",
11
- description: "Types text into a specific input field in the browser.",
12
- input_schema: {
13
- type: "object",
14
- properties: {
15
- browserId: {
16
- type: "string",
17
- description: "The ID of the browser instance."
18
- },
19
- locatorType: {
20
- type: "string",
21
- enum: ["css", "xpath", "text", "role", "label", "placeholder", "testId", "altText"],
22
- default: "css",
23
- description: "The type of locator to use"
24
- },
25
- locatorValue: {
26
- type: "string",
27
- description: "The locator value (CSS selector, XPath, text content, etc.)"
28
- },
29
- text: {
30
- type: "string",
31
- description: "The text to type into the input field."
32
- },
33
- // Keep backward compatibility
34
- selector: {
35
- type: "string",
36
- description: "The CSS selector of the input field (deprecated, use locatorType and locatorValue instead)."
37
- },
38
- options: {
39
- type: "object",
40
- properties: {
41
- timeout: {
42
- type: "number",
43
- default: 30000,
44
- description: "Timeout in milliseconds"
45
- },
46
- delay: {
47
- type: "number",
48
- default: 0,
49
- description: "Delay between keystrokes in milliseconds"
50
- },
51
- clear: {
52
- type: "boolean",
53
- default: true,
54
- description: "Clear the field before typing"
55
- },
56
- noWaitAfter: {
57
- type: "boolean",
58
- default: false,
59
- description: "Do not wait for navigation after typing"
60
- }
61
- },
62
- description: "Additional typing options"
63
- }
64
- },
65
- anyOf: [
66
- { required: ["browserId", "locatorType", "locatorValue", "text"] },
67
- { required: ["browserId", "selector", "text"] }
68
- ]
69
- },
70
- output_schema: {
71
- type: "object",
72
- properties: {
73
- success: { type: "boolean", description: "Indicates if the typing was successful." },
74
- locatorType: { type: "string", description: "The locator type that was used." },
75
- locatorValue: { type: "string", description: "The locator value that was used." },
76
- text: { type: "string", description: "The text that was typed." },
77
- browserId: { type: "string", description: "The browser instance ID that was used." },
78
- elementFound: { type: "boolean", description: "Whether the element was found." },
79
- message: { type: "string", description: "Success or error message." }
80
- },
81
- required: ["success", "browserId"]
82
- }
83
- };
84
-
85
- async execute(parameters) {
86
- const { browserId, locatorType, locatorValue, selector, text, options = {} } = parameters;
87
-
88
- // Handle backward compatibility
89
- let finalLocatorType, finalLocatorValue;
90
- if (selector) {
91
- finalLocatorType = "css";
92
- finalLocatorValue = selector;
93
- } else {
94
- finalLocatorType = locatorType || "css";
95
- finalLocatorValue = locatorValue;
96
- }
97
-
98
- console.error(`[BrowserTypeTool] Typing in browser ${browserId} with locator: ${finalLocatorType}="${finalLocatorValue}"`);
99
-
100
- try {
101
- // Convert Playwright-style locator to appropriate format for browser service
102
- const elementSelector = this.convertLocatorToSelector(finalLocatorType, finalLocatorValue);
103
-
104
- await browserService.typeIntoElement(browserId, elementSelector, text, options);
105
-
106
- console.error(`[BrowserTypeTool] Successfully typed in browser: ${browserId}`);
107
-
108
- return {
109
- success: true,
110
- browserId: browserId,
111
- locatorType: finalLocatorType,
112
- locatorValue: finalLocatorValue,
113
- text: text,
114
- elementFound: true,
115
- message: `Successfully typed "${text}" into element with ${finalLocatorType} locator: ${finalLocatorValue}`
116
- };
117
- } catch (error) {
118
- console.error(`[BrowserTypeTool] Failed to type in element:`, error.message);
119
-
120
- return {
121
- success: false,
122
- browserId: browserId,
123
- locatorType: finalLocatorType,
124
- locatorValue: finalLocatorValue,
125
- text: text,
126
- elementFound: false,
127
- message: `Failed to type into element: ${error.message}`
128
- };
129
- }
130
- }
131
-
132
- /**
133
- * Convert Playwright-style locator to CSS selector or XPath
134
- */
135
- convertLocatorToSelector(locatorType, locatorValue) {
136
- switch (locatorType) {
137
- case "css":
138
- return locatorValue;
139
-
140
- case "xpath":
141
- return locatorValue;
142
-
143
- case "text":
144
- // Convert text locator to XPath for input elements
145
- return `//input[contains(@placeholder, "${locatorValue}")] | //input[contains(@value, "${locatorValue}")] | //textarea[contains(text(), "${locatorValue}")] | //label[contains(text(), "${locatorValue}")]/following-sibling::input | //label[contains(text(), "${locatorValue}")]/following::input[1]`;
146
-
147
- case "role":
148
- // Convert role locator to CSS attribute selector
149
- return `[role="${locatorValue}"]`;
150
-
151
- case "label":
152
- // Convert label locator to XPath for label association
153
- return `//input[@aria-label="${locatorValue}"] | //input[@id=//label[contains(text(), "${locatorValue}")]/@for] | //label[contains(text(), "${locatorValue}")]/following-sibling::input | //label[contains(text(), "${locatorValue}")]/following::input[1]`;
154
-
155
- case "placeholder":
156
- // Convert placeholder locator to CSS attribute selector
157
- return `[placeholder="${locatorValue}"]`;
158
-
159
- case "testId":
160
- // Convert test ID to CSS attribute selector (assuming data-testid)
161
- return `[data-testid="${locatorValue}"]`;
162
-
163
- case "altText":
164
- // Convert alt text to CSS attribute selector (less common for input fields)
165
- return `[alt="${locatorValue}"]`;
166
-
167
- default:
168
- // Default to CSS selector
169
- return locatorValue;
170
- }
171
- }
172
- }
173
-
174
- module.exports = BrowserTypeTool;
@@ -1,95 +0,0 @@
1
- const ToolRegistry = require('./base/ToolRegistry');
2
- const path = require('path');
3
-
4
- /**
5
- * Initialize and configure the tool registry
6
- * This file serves as the main entry point for the tools system
7
- */
8
-
9
- // Create the global tool registry instance
10
- const toolRegistry = new ToolRegistry();
11
-
12
- /**
13
- * Initialize the tool registry by discovering and loading all tools
14
- * @param {boolean} debugMode - Whether to enable debug logging
15
- * @returns {Promise<ToolRegistry>} - The initialized tool registry
16
- */
17
- async function initializeTools(debugMode = false) {
18
- if (debugMode) {
19
- console.error('[Tools] Initializing tool system...');
20
- }
21
-
22
- try {
23
- // Get the tools directory path
24
- const toolsDir = path.join(__dirname);
25
-
26
- // Discover and load all tools
27
- await toolRegistry.discoverTools(toolsDir, debugMode);
28
-
29
- // Log registry statistics
30
- const stats = toolRegistry.getStats();
31
- console.error(`[Tools] Tool system initialized successfully:`);
32
- console.error(`[Tools] - Total tools: ${stats.total_tools}`);
33
- if (debugMode) {
34
- console.error(`[Tools] - Available tools: ${stats.tool_names.join(', ')}`);
35
- }
36
-
37
- return toolRegistry;
38
-
39
- } catch (error) {
40
- console.error('[Tools] Failed to initialize tool system:', error.message);
41
- throw error;
42
- }
43
- }
44
-
45
- /**
46
- * Get the tool registry instance
47
- * @returns {ToolRegistry} - The tool registry instance
48
- */
49
- function getToolRegistry() {
50
- return toolRegistry;
51
- }
52
-
53
- /**
54
- * Get all tool definitions for MCP tools/list response
55
- * @returns {Array} - Array of tool definitions
56
- */
57
- function getToolDefinitions() {
58
- return toolRegistry.getDefinitions();
59
- }
60
-
61
- /**
62
- * Execute a tool by name
63
- * @param {string} toolName - The name of the tool to execute
64
- * @param {object} parameters - The parameters to pass to the tool
65
- * @returns {Promise<object>} - The tool execution result
66
- */
67
- async function executeTool(toolName, parameters) {
68
- return await toolRegistry.executeTool(toolName, parameters);
69
- }
70
-
71
- /**
72
- * Check if a tool is available
73
- * @param {string} toolName - The name of the tool to check
74
- * @returns {boolean} - True if the tool is available
75
- */
76
- function isToolAvailable(toolName) {
77
- return toolRegistry.hasTool(toolName);
78
- }
79
-
80
- /**
81
- * Get list of available tool names
82
- * @returns {Array<string>} - Array of available tool names
83
- */
84
- function getAvailableTools() {
85
- return toolRegistry.getToolNames();
86
- }
87
-
88
- module.exports = {
89
- initializeTools,
90
- getToolRegistry,
91
- getToolDefinitions,
92
- executeTool,
93
- isToolAvailable,
94
- getAvailableTools
95
- };
@@ -1,418 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const { promisify } = require('util');
4
-
5
- const readFile = promisify(fs.readFile);
6
- const writeFile = promisify(fs.writeFile);
7
- const mkdir = promisify(fs.mkdir);
8
- const copyFile = promisify(fs.copyFile);
9
- const stat = promisify(fs.stat);
10
- const readdir = promisify(fs.readdir);
11
- const symlink = promisify(fs.symlink);
12
- const unlink = promisify(fs.unlink);
13
- const lstat = promisify(fs.lstat);
14
-
15
- /**
16
- * Agent Installer - Handles installation of Agent Skills and MCP configuration
17
- */
18
- class AgentInstaller {
19
- constructor(options = {}) {
20
- this.verbose = options.verbose || false;
21
- this.targetDir = options.targetDir || process.cwd();
22
- this.sourceDir = options.sourceDir || path.join(__dirname, '..', '..');
23
- }
24
-
25
- /**
26
- * Main installation function
27
- */
28
- async install() {
29
- console.log('🚀 Installing Democratize Quality Agent Skills...\n');
30
-
31
- try {
32
- // Step 1: Install Agent Skills
33
- await this.installSkills();
34
-
35
- // Step 2: Install Chat Modes
36
- await this.installChatModes();
37
-
38
- // Step 3: Setup MCP configuration
39
- await this.setupMCPConfiguration();
40
-
41
- // Step 4: Show completion message
42
- this.showCompletionMessage();
43
-
44
- } catch (error) {
45
- console.error('❌ Installation failed:', error.message);
46
- if (this.verbose) {
47
- console.error('Stack trace:', error.stack);
48
- }
49
- throw error;
50
- }
51
- }
52
-
53
- /**
54
- * Install Agent Skills to .agents/skills/ with symlinks for compatibility
55
- */
56
- async installSkills() {
57
- console.log('📁 Installing Agent Skills...');
58
-
59
- const sourceSkillsDir = path.join(this.sourceDir, 'src', 'skills');
60
- const primarySkillsDir = path.join(this.targetDir, '.agents', 'skills');
61
-
62
- // Create primary skills directory
63
- try {
64
- await mkdir(primarySkillsDir, { recursive: true });
65
- } catch (error) {
66
- if (error.code !== 'EEXIST') {
67
- throw new Error(`Failed to create .agents/skills directory: ${error.message}`);
68
- }
69
- }
70
-
71
- // Get list of skill directories
72
- let skillDirs;
73
- try {
74
- const allItems = await readdir(sourceSkillsDir);
75
- // Filter for directories only
76
- skillDirs = [];
77
- for (const item of allItems) {
78
- const itemPath = path.join(sourceSkillsDir, item);
79
- const itemStat = await stat(itemPath);
80
- if (itemStat.isDirectory()) {
81
- skillDirs.push(item);
82
- }
83
- }
84
- } catch (error) {
85
- throw new Error(`Failed to read source skills directory: ${error.message}`);
86
- }
87
-
88
- if (skillDirs.length === 0) {
89
- console.log(' ⚠️ No skills found to install');
90
- return;
91
- }
92
-
93
- // Copy each skill directory
94
- for (const skillDir of skillDirs) {
95
- const sourceSkillPath = path.join(sourceSkillsDir, skillDir);
96
- const targetSkillPath = path.join(primarySkillsDir, skillDir);
97
-
98
- try {
99
- await this.copyDirectory(sourceSkillPath, targetSkillPath);
100
- console.log(` ✅ ${skillDir}/`);
101
- } catch (error) {
102
- console.error(` ❌ Failed to copy ${skillDir}: ${error.message}`);
103
- throw error;
104
- }
105
- }
106
-
107
- console.log('');
108
-
109
- // Create symlinks for maximum compatibility
110
- await this.createCompatibilitySymlinks(primarySkillsDir);
111
- }
112
-
113
- /**
114
- * Recursively copy a directory
115
- */
116
- async copyDirectory(source, target) {
117
- await mkdir(target, { recursive: true });
118
-
119
- const items = await readdir(source);
120
-
121
- for (const item of items) {
122
- const sourcePath = path.join(source, item);
123
- const targetPath = path.join(target, item);
124
- const itemStat = await stat(sourcePath);
125
-
126
- if (itemStat.isDirectory()) {
127
- await this.copyDirectory(sourcePath, targetPath);
128
- } else {
129
- await copyFile(sourcePath, targetPath);
130
- }
131
- }
132
- }
133
-
134
- /**
135
- * Create symlinks for compatibility with different tools
136
- */
137
- async createCompatibilitySymlinks(primarySkillsDir) {
138
- console.log('🔗 Creating compatibility symlinks...');
139
-
140
- const symlinks = [
141
- { from: primarySkillsDir, to: path.join(this.targetDir, '.github', 'skills') },
142
- { from: primarySkillsDir, to: path.join(this.targetDir, '.claude', 'skills') }
143
- ];
144
-
145
- for (const link of symlinks) {
146
- try {
147
- // Check if symlink or directory already exists
148
- try {
149
- const linkStat = await lstat(link.to);
150
- if (linkStat.isSymbolicLink()) {
151
- // Remove existing symlink
152
- await unlink(link.to);
153
- if (this.verbose) {
154
- console.log(` 🔄 Removed existing symlink: ${path.relative(this.targetDir, link.to)}`);
155
- }
156
- } else if (linkStat.isDirectory()) {
157
- console.log(` ⚠️ Directory already exists, skipping symlink: ${path.relative(this.targetDir, link.to)}`);
158
- continue;
159
- }
160
- } catch (error) {
161
- if (error.code !== 'ENOENT') {
162
- throw error;
163
- }
164
- // Path doesn't exist, proceed with symlink creation
165
- }
166
-
167
- // Create parent directory if it doesn't exist
168
- const parentDir = path.dirname(link.to);
169
- await mkdir(parentDir, { recursive: true });
170
-
171
- // Create relative symlink
172
- const relativeTarget = path.relative(path.dirname(link.to), link.from);
173
- await symlink(relativeTarget, link.to, 'dir');
174
- console.log(` ✅ ${path.relative(this.targetDir, link.to)} → ${path.relative(this.targetDir, link.from)}`);
175
- } catch (error) {
176
- console.warn(` ⚠️ Could not create symlink ${path.relative(this.targetDir, link.to)}: ${error.message}`);
177
- if (this.verbose) {
178
- console.warn(` (This is not critical - skills will still work from .agents/skills/)`);
179
- }
180
- }
181
- }
182
-
183
- console.log('');
184
- }
185
-
186
- /**
187
- * Install Chat Modes to .github/agents/
188
- */
189
- async installChatModes() {
190
- console.log('💬 Installing Chat Modes...');
191
-
192
- const sourceChatModesDir = path.join(this.sourceDir, 'src', 'chatmodes');
193
- const targetAgentsDir = path.join(this.targetDir, '.github', 'agents');
194
-
195
- // Create .github/agents directory
196
- try {
197
- await mkdir(targetAgentsDir, { recursive: true });
198
- } catch (error) {
199
- if (error.code !== 'EEXIST') {
200
- throw new Error(`Failed to create .github/agents directory: ${error.message}`);
201
- }
202
- }
203
-
204
- // Get list of chatmode files
205
- let chatModeFiles;
206
- try {
207
- const allItems = await readdir(sourceChatModesDir);
208
- // Filter for .chatmode.md files only
209
- chatModeFiles = allItems.filter(item => item.endsWith('.chatmode.md'));
210
- } catch (error) {
211
- if (error.code === 'ENOENT') {
212
- console.log(' ⚠️ No chatmodes directory found, skipping...');
213
- console.log('');
214
- return;
215
- }
216
- throw new Error(`Failed to read source chatmodes directory: ${error.message}`);
217
- }
218
-
219
- if (chatModeFiles.length === 0) {
220
- console.log(' ⚠️ No chatmode files found to install');
221
- console.log('');
222
- return;
223
- }
224
-
225
- // Copy each chatmode file
226
- for (const chatModeFile of chatModeFiles) {
227
- const sourcePath = path.join(sourceChatModesDir, chatModeFile);
228
- const targetPath = path.join(targetAgentsDir, chatModeFile);
229
-
230
- try {
231
- await copyFile(sourcePath, targetPath);
232
- console.log(` ✅ ${chatModeFile}`);
233
- } catch (error) {
234
- console.error(` ❌ Failed to copy ${chatModeFile}: ${error.message}`);
235
- throw error;
236
- }
237
- }
238
-
239
- console.log('');
240
- }
241
-
242
- /**
243
- * Setup MCP configuration in .vscode/mcp.json
244
- */
245
- async setupMCPConfiguration() {
246
- console.log('⚙️ Setting up MCP configuration...');
247
-
248
- const vscodeDir = path.join(this.targetDir, '.vscode');
249
- const mcpConfigPath = path.join(vscodeDir, 'mcp.json');
250
-
251
- // Create .vscode directory if it doesn't exist
252
- try {
253
- await mkdir(vscodeDir, { recursive: true });
254
- } catch (error) {
255
- if (error.code !== 'EEXIST') {
256
- throw new Error(`Failed to create .vscode directory: ${error.message}`);
257
- }
258
- }
259
-
260
- // Check if mcp.json already exists
261
- let existingConfig = null;
262
- let configExists = false;
263
-
264
- try {
265
- await stat(mcpConfigPath);
266
- configExists = true;
267
- console.log(' 📋 Found existing .vscode/mcp.json');
268
-
269
- const configContent = await readFile(mcpConfigPath, 'utf8');
270
- existingConfig = JSON.parse(configContent);
271
-
272
- } catch (error) {
273
- if (error.code === 'ENOENT') {
274
- console.log(' 📋 Creating new .vscode/mcp.json');
275
- configExists = false;
276
- } else if (error instanceof SyntaxError) {
277
- throw new Error(`Existing mcp.json is malformed: ${error.message}`);
278
- } else {
279
- throw new Error(`Failed to read existing mcp.json: ${error.message}`);
280
- }
281
- }
282
-
283
- // Create new server configuration
284
- const newServerConfig = {
285
- type: "stdio",
286
- command: "npx",
287
- args: ["@democratize-quality/mcp-server@latest"],
288
- cwd: "${workspaceFolder}",
289
- env: {
290
- OUTPUT_DIR: "./api-test-reports"
291
- }
292
- };
293
-
294
- let finalConfig;
295
-
296
- if (configExists && existingConfig) {
297
- // Handle existing configuration
298
- await this.handleExistingMCPConfig(existingConfig, newServerConfig, mcpConfigPath);
299
- return;
300
- } else {
301
- // Create new configuration
302
- finalConfig = {
303
- servers: {
304
- "democratize-quality": newServerConfig
305
- },
306
- inputs: []
307
- };
308
- }
309
-
310
- // Write the configuration
311
- try {
312
- await writeFile(mcpConfigPath, JSON.stringify(finalConfig, null, 2), 'utf8');
313
- console.log(' ✅ MCP configuration created');
314
- } catch (error) {
315
- throw new Error(`Failed to write mcp.json: ${error.message}`);
316
- }
317
-
318
- console.log('');
319
- }
320
-
321
- /**
322
- * Handle existing MCP configuration
323
- */
324
- async handleExistingMCPConfig(existingConfig, newServerConfig, mcpConfigPath) {
325
- // Ensure servers object exists
326
- if (!existingConfig.servers) {
327
- existingConfig.servers = {};
328
- }
329
-
330
- // Check if democratize-quality server already exists
331
- if (existingConfig.servers['democratize-quality']) {
332
- console.log(' 🔍 Found existing "democratize-quality" server configuration');
333
-
334
- const existingServer = existingConfig.servers['democratize-quality'];
335
- console.log(' Current configuration:');
336
- console.log(' ', JSON.stringify(existingServer, null, 4));
337
- console.log(' \n Proposed configuration:');
338
- console.log(' ', JSON.stringify(newServerConfig, null, 4));
339
-
340
- // For now, we'll update automatically with backup
341
- // In a real implementation, you might want to prompt the user
342
- console.log(' 💾 Creating backup and updating configuration...');
343
-
344
- // Create backup
345
- const backupPath = `${mcpConfigPath}.backup.${new Date().toISOString().replace(/[:.]/g, '-')}`;
346
- await writeFile(backupPath, JSON.stringify(existingConfig, null, 2), 'utf8');
347
- console.log(` 📄 Backup created: ${path.basename(backupPath)}`);
348
- }
349
-
350
- // Update configuration
351
- const updatedConfig = {
352
- ...existingConfig,
353
- servers: {
354
- ...existingConfig.servers,
355
- 'democratize-quality': newServerConfig
356
- },
357
- inputs: existingConfig.inputs || []
358
- };
359
-
360
- // Write updated configuration
361
- try {
362
- await writeFile(mcpConfigPath, JSON.stringify(updatedConfig, null, 2), 'utf8');
363
- console.log(' ✅ MCP configuration updated');
364
- } catch (error) {
365
- throw new Error(`Failed to update mcp.json: ${error.message}`);
366
- }
367
- }
368
-
369
- /**
370
- * Show completion message with next steps
371
- */
372
- showCompletionMessage() {
373
- console.log('🎉 Installation complete!\n');
374
-
375
- console.log('📁 Agent Skills installed to:');
376
- console.log(' → .agents/skills/api-planning/');
377
- console.log(' → .agents/skills/test-generation/');
378
- console.log(' → .agents/skills/test-execution/');
379
- console.log(' → .agents/skills/test-healing/');
380
- console.log(' → .github/skills/ (symlink for GitHub Copilot)');
381
- console.log(' → .claude/skills/ (symlink for Claude Code)\n');
382
-
383
- console.log('💬 Chat Modes installed to:');
384
- console.log(' → .github/agents/🌐 api-planner.chatmode.md');
385
- console.log(' → .github/agents/🌐 api-generator.chatmode.md');
386
- console.log(' → .github/agents/🌐 api-healer.chatmode.md\n');
387
-
388
- console.log('⚙️ MCP configuration updated:');
389
- console.log(' → .vscode/mcp.json (democratize-quality server added/updated)\n');
390
-
391
- console.log('🚀 Next steps:');
392
- console.log(' 1. Restart VS Code / IDE to reload configuration');
393
- console.log(' 2. Use skills in your AI coding assistant:');
394
- console.log(' • /api-planning - Create comprehensive API test plans');
395
- console.log(' • /test-generation - Generate executable API tests');
396
- console.log(' • /test-execution - Execute API tests from test plans');
397
- console.log(' • /test-healing - Debug and fix failing API tests');
398
- console.log(' 3. Skills work automatically when you mention relevant tasks!');
399
- console.log(' 4. Example: "Help me create an API test plan for my REST API"\n');
400
-
401
- console.log('✨ Compatible with:');
402
- console.log(' • GitHub Copilot (VS Code, CLI)');
403
- console.log(' • Codex CLI (OpenAI)');
404
- console.log(' • Claude Code');
405
-
406
- console.log('📚 For more information, visit: https://github.com/uppadhyayraj/democratize-quality-mcp-server');
407
- }
408
-
409
- /**
410
- * Rollback installation (future feature)
411
- */
412
- async rollback() {
413
- console.log('🔄 Rollback functionality will be implemented in a future version');
414
- // TODO: Implement rollback functionality
415
- }
416
- }
417
-
418
- module.exports = AgentInstaller;