@dynamicu/chromedebug-mcp 2.6.7 → 2.7.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.
Files changed (49) hide show
  1. package/CLAUDE.md +17 -1
  2. package/README.md +1 -1
  3. package/chrome-extension/activation-manager.js +10 -10
  4. package/chrome-extension/background.js +1045 -736
  5. package/chrome-extension/browser-recording-manager.js +1 -1
  6. package/chrome-extension/chrome-debug-logger.js +168 -0
  7. package/chrome-extension/chrome-session-manager.js +5 -5
  8. package/chrome-extension/console-interception-library.js +430 -0
  9. package/chrome-extension/content.css +16 -16
  10. package/chrome-extension/content.js +739 -221
  11. package/chrome-extension/data-buffer.js +5 -5
  12. package/chrome-extension/dom-tracker.js +9 -9
  13. package/chrome-extension/extension-config.js +1 -1
  14. package/chrome-extension/firebase-client.js +13 -13
  15. package/chrome-extension/frame-capture.js +20 -38
  16. package/chrome-extension/license-helper.js +33 -7
  17. package/chrome-extension/manifest.free.json +3 -6
  18. package/chrome-extension/network-tracker.js +9 -9
  19. package/chrome-extension/options.html +10 -0
  20. package/chrome-extension/options.js +21 -8
  21. package/chrome-extension/performance-monitor.js +17 -17
  22. package/chrome-extension/popup.html +230 -193
  23. package/chrome-extension/popup.js +146 -458
  24. package/chrome-extension/pro/enhanced-capture.js +406 -0
  25. package/chrome-extension/pro/frame-editor.html +433 -0
  26. package/chrome-extension/pro/frame-editor.js +1567 -0
  27. package/chrome-extension/pro/function-tracker.js +843 -0
  28. package/chrome-extension/pro/jszip.min.js +13 -0
  29. package/chrome-extension/upload-manager.js +7 -7
  30. package/dist/chromedebug-extension-free.zip +0 -0
  31. package/package.json +3 -1
  32. package/scripts/webpack.config.free.cjs +8 -8
  33. package/scripts/webpack.config.pro.cjs +2 -0
  34. package/src/cli.js +2 -2
  35. package/src/database.js +55 -7
  36. package/src/index.js +9 -6
  37. package/src/mcp/server.js +2 -2
  38. package/src/services/process-manager.js +10 -6
  39. package/src/services/process-tracker.js +10 -5
  40. package/src/services/profile-manager.js +17 -2
  41. package/src/validation/schemas.js +12 -11
  42. package/src/index-direct.js +0 -157
  43. package/src/index-modular.js +0 -219
  44. package/src/index-monolithic-backup.js +0 -2230
  45. package/src/legacy/chrome-controller-old.js +0 -1406
  46. package/src/legacy/index-express.js +0 -625
  47. package/src/legacy/index-old.js +0 -977
  48. package/src/legacy/routes.js +0 -260
  49. package/src/legacy/shared-storage.js +0 -101
@@ -62,7 +62,7 @@ async function safeKillProcess(pid, signal = 'SIGTERM') {
62
62
  * Process cleanup is skipped on Windows to allow the server to start. A proper cross-platform
63
63
  * solution will be implemented in a future update.
64
64
  */
65
- async function findChromePilotProcesses() {
65
+ async function findChromeDebugProcesses() {
66
66
  // Skip process cleanup on Windows - ps command doesn't exist
67
67
  // This allows the server to start on Windows without crashing
68
68
  // TODO: Implement proper Windows process management using tasklist or Node.js process handles
@@ -107,6 +107,7 @@ async function findChromePilotProcesses() {
107
107
  if (!pid || pid === currentPid) continue;
108
108
 
109
109
  // Check if it's a ChromeDebug MCP related process
110
+ // Look for both new and old process names for backward compatibility
110
111
  let processType = '';
111
112
  if (line.includes('src/index.js')) {
112
113
  processType = 'MCP server';
@@ -117,7 +118,7 @@ async function findChromePilotProcesses() {
117
118
  } else if (line.includes('http-server.js')) {
118
119
  processType = 'HTTP server';
119
120
  pidsToKill.push(pid);
120
- } else if (line.includes('chrome-pilot') && line.includes('node')) {
121
+ } else if ((line.includes('chromedebug') || line.includes('chrome-pilot') || line.includes('ChromePilot')) && line.includes('node')) {
121
122
  processType = 'ChromeDebug MCP process';
122
123
  pidsToKill.push(pid);
123
124
  }
@@ -221,8 +222,8 @@ export class ProcessManager {
221
222
  * Finds and kills ChromeDebug MCP processes
222
223
  * @returns {Promise<Object>} Cleanup results
223
224
  */
224
- async cleanupChromePilotProcesses() {
225
- const { pidsToKill, processDescriptions } = await findChromePilotProcesses();
225
+ async cleanupChromeDebugProcesses() {
226
+ const { pidsToKill, processDescriptions } = await findChromeDebugProcesses();
226
227
 
227
228
  const results = {
228
229
  found: processDescriptions,
@@ -326,5 +327,8 @@ export class ProcessManager {
326
327
  }
327
328
  }
328
329
 
329
- // Export utility functions for backward compatibility
330
- export { validateProcessId, safeKillProcess, findChromePilotProcesses };
330
+ // Export utility functions
331
+ export { validateProcessId, safeKillProcess, findChromeDebugProcesses };
332
+
333
+ // Backward compatibility aliases
334
+ export { findChromeDebugProcesses as findChromePilotProcesses };
@@ -306,7 +306,7 @@ export async function killAllRegisteredProcesses() {
306
306
  * Find ChromeDebug processes using pattern matching (for untracked processes)
307
307
  * This is a fallback for processes started before tracking was implemented
308
308
  */
309
- export async function findUntrackedChromePilotProcesses() {
309
+ export async function findUntrackedChromeDebugProcesses() {
310
310
  const currentPid = process.pid;
311
311
  const foundProcesses = [];
312
312
 
@@ -342,6 +342,7 @@ export async function findUntrackedChromePilotProcesses() {
342
342
  if (registeredPids.has(pid)) continue;
343
343
 
344
344
  // Check if it's a ChromeDebug/ChromePilot process
345
+ // Look for both new and old process names for backward compatibility
345
346
  let processType = '';
346
347
  if (line.includes('src/index.js')) {
347
348
  processType = 'untracked-mcp-server';
@@ -349,7 +350,7 @@ export async function findUntrackedChromePilotProcesses() {
349
350
  processType = 'untracked-http-server';
350
351
  } else if (line.includes('standalone-server.js')) {
351
352
  processType = 'untracked-standalone-server';
352
- } else if (line.includes('chromedebug-mcp') && line.includes('node')) {
353
+ } else if ((line.includes('chromedebug-mcp') || line.includes('chrome-pilot') || line.includes('ChromePilot')) && line.includes('node')) {
353
354
  processType = 'untracked-chromedebug-process';
354
355
  }
355
356
 
@@ -380,8 +381,8 @@ export async function findUntrackedChromePilotProcesses() {
380
381
  /**
381
382
  * Kill untracked ChromeDebug processes (emergency cleanup)
382
383
  */
383
- export async function killUntrackedChromePilotProcesses() {
384
- const untrackedProcesses = await findUntrackedChromePilotProcesses();
384
+ export async function killUntrackedChromeDebugProcesses() {
385
+ const untrackedProcesses = await findUntrackedChromeDebugProcesses();
385
386
  const results = {
386
387
  found: untrackedProcesses,
387
388
  killed: [],
@@ -571,4 +572,8 @@ export async function cleanupCurrentSession() {
571
572
  }
572
573
 
573
574
  return results;
574
- }
575
+ }
576
+
577
+ // Backward compatibility aliases
578
+ export { findUntrackedChromeDebugProcesses as findUntrackedChromePilotProcesses };
579
+ export { killUntrackedChromeDebugProcesses as killUntrackedChromePilotProcesses };
@@ -13,14 +13,29 @@
13
13
  * - Profile lifecycle management with proper resource tracking
14
14
  */
15
15
 
16
- import { promises as fs } from 'fs';
16
+ import { promises as fs, existsSync } from 'fs';
17
17
  import path from 'path';
18
18
  import os from 'os';
19
19
  import { randomUUID } from 'crypto';
20
20
 
21
21
  export class ProfileManager {
22
22
  constructor(options = {}) {
23
- this.profilesDir = options.profilesDir || path.join(os.tmpdir(), 'chrome-pilot-profiles');
23
+ // Use new directory name, but check old directory for migration
24
+ const defaultDir = path.join(os.tmpdir(), 'chromedebug-profiles');
25
+ const oldDir = path.join(os.tmpdir(), 'chrome-pilot-profiles');
26
+
27
+ // If old directory exists and new doesn't, use old directory for compatibility
28
+ let profilesDir = defaultDir;
29
+ try {
30
+ if (!options.profilesDir && existsSync(oldDir) && !existsSync(defaultDir)) {
31
+ profilesDir = oldDir;
32
+ console.error(`[ProfileManager] Using existing chrome-pilot-profiles directory for backward compatibility`);
33
+ }
34
+ } catch (error) {
35
+ // Ignore errors, use default
36
+ }
37
+
38
+ this.profilesDir = options.profilesDir || profilesDir;
24
39
  this.activeProfiles = new Map(); // sessionId -> { profilePath, claudeInstanceId, createdAt, size }
25
40
  this.initialized = false;
26
41
 
@@ -27,21 +27,22 @@ export const workflowRecordingSchema = Joi.object({
27
27
  selector: Joi.string().optional(),
28
28
  x: Joi.number().optional(),
29
29
  y: Joi.number().optional(),
30
- value: Joi.string().optional(),
31
- text: Joi.string().optional(),
30
+ value: Joi.string().allow('').optional(),
31
+ text: Joi.string().allow('').optional(),
32
32
  placeholder: Joi.string().optional(),
33
33
  index: Joi.number().optional(),
34
- // Enhanced click tracking fields
34
+ // Enhanced click tracking fields - accept both strings and objects for flexibility
35
+ // (matches screenInteractionsSchema pattern - extension sends objects, database handles serialization)
35
36
  element_html: Joi.string().max(10240).optional(),
36
37
  elementHTML: Joi.string().max(10240).optional(), // camelCase variant
37
- component_data: Joi.string().max(3072).optional(),
38
- componentData: Joi.string().max(3072).optional(), // camelCase variant
39
- event_handlers: Joi.string().max(2048).optional(),
40
- eventHandlers: Joi.string().max(2048).optional(), // camelCase variant
41
- element_state: Joi.string().max(2048).optional(),
42
- elementState: Joi.string().max(2048).optional(), // camelCase variant
43
- performance_metrics: Joi.string().max(1024).optional(),
44
- performanceMetrics: Joi.string().max(1024).optional(), // camelCase variant
38
+ component_data: Joi.alternatives().try(Joi.string().max(3072), Joi.object()).optional(),
39
+ componentData: Joi.alternatives().try(Joi.string().max(3072), Joi.object()).optional(), // camelCase variant
40
+ event_handlers: Joi.alternatives().try(Joi.string().max(2048), Joi.object()).optional(),
41
+ eventHandlers: Joi.alternatives().try(Joi.string().max(2048), Joi.object()).optional(), // camelCase variant
42
+ element_state: Joi.alternatives().try(Joi.string().max(2048), Joi.object()).optional(),
43
+ elementState: Joi.alternatives().try(Joi.string().max(2048), Joi.object()).optional(), // camelCase variant
44
+ performance_metrics: Joi.alternatives().try(Joi.string().max(1024), Joi.object()).optional(),
45
+ performanceMetrics: Joi.alternatives().try(Joi.string().max(1024), Joi.object()).optional(), // camelCase variant
45
46
  // Function trace fields
46
47
  component: Joi.string().optional(),
47
48
  args: Joi.alternatives().try(Joi.array(), Joi.string()).optional(),
@@ -1,157 +0,0 @@
1
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
- import {
4
- ListToolsRequestSchema,
5
- CallToolRequestSchema
6
- } from '@modelcontextprotocol/sdk/types.js';
7
- import { ChromeController } from './chrome-controller.js';
8
-
9
- // Create a single Chrome controller instance for this MCP server
10
- const chromeController = new ChromeController();
11
-
12
- const server = new Server(
13
- {
14
- name: 'chrome-pilot',
15
- version: '1.0.0',
16
- },
17
- {
18
- capabilities: {
19
- tools: {},
20
- },
21
- }
22
- );
23
-
24
- const tools = [
25
- {
26
- name: 'launch_chrome',
27
- description: 'Launch a Chrome browser instance for this MCP server',
28
- inputSchema: {
29
- type: 'object',
30
- properties: {},
31
- },
32
- },
33
- {
34
- name: 'get_chrome_info',
35
- description: 'Get Chrome debugging port and connection info for extensions',
36
- inputSchema: {
37
- type: 'object',
38
- properties: {},
39
- },
40
- },
41
- {
42
- name: 'connect_to_existing_chrome',
43
- description: 'Connect to an existing Chrome instance with debugging enabled',
44
- inputSchema: {
45
- type: 'object',
46
- properties: {
47
- port: {
48
- type: 'number',
49
- description: 'Debugging port Chrome is running on (default: 9222)',
50
- default: 9222,
51
- },
52
- },
53
- },
54
- },
55
- // ... other tools remain the same
56
- ];
57
-
58
- server.setRequestHandler(ListToolsRequestSchema, async () => {
59
- return { tools };
60
- });
61
-
62
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
63
- const { name, arguments: args } = request.params;
64
-
65
- try {
66
- switch (name) {
67
- case 'launch_chrome': {
68
- const result = await chromeController.launch();
69
-
70
- // Write Chrome info to a known location for the extension
71
- const chromeInfo = {
72
- debugPort: result.debugPort,
73
- wsEndpoint: result.browserWSEndpoint,
74
- timestamp: new Date().toISOString()
75
- };
76
-
77
- // The extension can read this file or connect directly to debugPort
78
- await fs.writeFile(
79
- '/tmp/chrome-pilot-current.json',
80
- JSON.stringify(chromeInfo, null, 2)
81
- );
82
-
83
- return {
84
- content: [
85
- {
86
- type: 'text',
87
- text: `Chrome launched on debugging port ${result.debugPort}\n\n` +
88
- `The Chrome extension can now connect directly to:\n` +
89
- `http://localhost:${result.debugPort}\n\n` +
90
- JSON.stringify(result, null, 2),
91
- },
92
- ],
93
- };
94
- }
95
-
96
- case 'get_chrome_info': {
97
- const status = await chromeController.getConnectionStatus();
98
- if (!status.connected) {
99
- return {
100
- content: [
101
- {
102
- type: 'text',
103
- text: 'Chrome is not connected. Launch Chrome first using launch_chrome.',
104
- },
105
- ],
106
- };
107
- }
108
-
109
- return {
110
- content: [
111
- {
112
- type: 'text',
113
- text: `Chrome debugging info:\n` +
114
- `Port: ${status.debugPort}\n` +
115
- `WebSocket: ${status.browserWSEndpoint}\n\n` +
116
- `Extensions can connect to: http://localhost:${status.debugPort}`,
117
- },
118
- ],
119
- };
120
- }
121
-
122
- // ... rest of the cases
123
- }
124
- } catch (error) {
125
- return {
126
- content: [
127
- {
128
- type: 'text',
129
- text: `Error: ${error.message}`,
130
- },
131
- ],
132
- isError: true,
133
- };
134
- }
135
- });
136
-
137
- async function main() {
138
- const transport = new StdioServerTransport();
139
- await server.connect(transport);
140
- console.error('Chrome Debug MCP server running (direct mode - no Express)');
141
- }
142
-
143
- // Clean shutdown
144
- process.on('SIGINT', async () => {
145
- await chromeController.close();
146
- process.exit(0);
147
- });
148
-
149
- process.on('SIGTERM', async () => {
150
- await chromeController.close();
151
- process.exit(0);
152
- });
153
-
154
- main().catch((error) => {
155
- console.error('Fatal error:', error);
156
- process.exit(1);
157
- });
@@ -1,219 +0,0 @@
1
- /**
2
- * Chrome Debug MCP Server - Modular Architecture
3
- * Refactored from monolithic design to modular components
4
- * Maintains all security fixes and functionality while improving maintainability
5
- */
6
-
7
- import { ChromeController } from './chrome-controller.js';
8
- import { MCPServer } from './mcp/server.js';
9
- import { ChromeService } from './services/chrome-service.js';
10
- import { ProcessManager } from './services/process-manager.js';
11
-
12
- /**
13
- * Main application class that orchestrates all components
14
- */
15
- class ChromePilotApp {
16
- constructor() {
17
- this.chromeController = null;
18
- this.chromeService = null;
19
- this.mcpServer = null;
20
- this.processManager = null;
21
- this.initialized = false;
22
- }
23
-
24
- /**
25
- * Initializes all components
26
- * @param {Object} options - Initialization options
27
- */
28
- async initialize(options = {}) {
29
- try {
30
- // Parse command line arguments
31
- const args = this.parseArguments();
32
- const finalOptions = { ...options, ...args };
33
-
34
- // Create Chrome controller instance
35
- this.chromeController = new ChromeController();
36
-
37
- // Create Chrome service wrapper with process management
38
- this.chromeService = new ChromeService(this.chromeController);
39
- this.processManager = this.chromeService.getProcessManager();
40
-
41
- // Initialize Chrome service (starts HTTP server if needed)
42
- const serviceResult = await this.chromeService.initialize(finalOptions);
43
-
44
- if (serviceResult.httpServer) {
45
- console.error(`Chrome service initialized with HTTP server on port ${serviceResult.httpServer.port}`);
46
- }
47
-
48
- // Create and configure MCP server
49
- this.mcpServer = new MCPServer(this.chromeService);
50
-
51
- this.initialized = true;
52
- return {
53
- status: 'initialized',
54
- options: finalOptions,
55
- serviceResult
56
- };
57
- } catch (error) {
58
- console.error('Failed to initialize Chrome Debug:', error);
59
- throw error;
60
- }
61
- }
62
-
63
- /**
64
- * Starts the MCP server
65
- */
66
- async start() {
67
- if (!this.initialized) {
68
- await this.initialize();
69
- }
70
-
71
- try {
72
- // Clean up any existing Chrome Debug processes
73
- const cleanupResult = await this.processManager.cleanupChromePilotProcesses();
74
- if (cleanupResult.total > 0) {
75
- console.error(`Cleaned up ${cleanupResult.killed.length} existing processes`);
76
- }
77
-
78
- // Start the MCP server
79
- await this.mcpServer.start();
80
- } catch (error) {
81
- console.error('Failed to start Chrome Debug MCP server:', error);
82
- process.exit(1);
83
- }
84
- }
85
-
86
- /**
87
- * Gets the status of all components
88
- */
89
- async getStatus() {
90
- if (!this.initialized) {
91
- return { status: 'not_initialized' };
92
- }
93
-
94
- return {
95
- status: 'running',
96
- components: {
97
- chromeService: await this.chromeService.getStatus(),
98
- processManager: this.processManager.getStatistics(),
99
- mcpServer: {
100
- initialized: !!this.mcpServer,
101
- tools: this.mcpServer ? this.mcpServer.toolRegistry.getAllTools().length : 0
102
- }
103
- },
104
- timestamp: new Date().toISOString()
105
- };
106
- }
107
-
108
- /**
109
- * Parses command line arguments
110
- * @returns {Object} Parsed arguments
111
- */
112
- parseArguments() {
113
- const args = {
114
- singleServer: false,
115
- watch: false,
116
- debug: false
117
- };
118
-
119
- for (const arg of process.argv.slice(2)) {
120
- switch (arg) {
121
- case '--single-server':
122
- args.singleServer = true;
123
- break;
124
- case '--watch':
125
- args.watch = true;
126
- break;
127
- case '--debug':
128
- args.debug = true;
129
- break;
130
- case '--help':
131
- this.showHelp();
132
- process.exit(0);
133
- break;
134
- }
135
- }
136
-
137
- return args;
138
- }
139
-
140
- /**
141
- * Shows help information
142
- */
143
- showHelp() {
144
- console.error(`
145
- Chrome Debug MCP Server - Modular Architecture
146
-
147
- Usage: node src/index.js [options]
148
-
149
- Options:
150
- --single-server Run without HTTP server (MCP only)
151
- --watch Watch for file changes (development mode)
152
- --debug Enable debug logging
153
- --help Show this help message
154
-
155
- Environment Variables:
156
- NODE_ENV Set to 'development' for debug mode
157
- CHROME_PILOT_PORT Configure HTTP server port
158
-
159
- For more information, see the documentation in CLAUDE.md
160
- `);
161
- }
162
-
163
- /**
164
- * Graceful shutdown
165
- */
166
- async shutdown() {
167
- console.error('Shutting down Chrome Debug...');
168
-
169
- try {
170
- if (this.chromeService) {
171
- await this.chromeService.cleanup();
172
- }
173
-
174
- if (this.processManager) {
175
- await this.processManager.killAllManagedProcesses();
176
- }
177
-
178
- console.error('Chrome Debug shutdown complete');
179
- } catch (error) {
180
- console.error('Error during shutdown:', error);
181
- }
182
- }
183
- }
184
-
185
- /**
186
- * Main entry point
187
- */
188
- async function main() {
189
- const app = new ChromePilotApp();
190
-
191
- try {
192
- await app.start();
193
- } catch (error) {
194
- console.error('Fatal error starting Chrome Debug:', error);
195
- process.exit(1);
196
- }
197
- }
198
-
199
- // Handle graceful shutdown
200
- process.on('SIGINT', async () => {
201
- console.error('Received SIGINT, shutting down gracefully...');
202
- process.exit(0);
203
- });
204
-
205
- process.on('SIGTERM', async () => {
206
- console.error('Received SIGTERM, shutting down gracefully...');
207
- process.exit(0);
208
- });
209
-
210
- // Export for testing
211
- export { ChromePilotApp };
212
-
213
- // Run if this is the main module
214
- if (import.meta.url === `file://${process.argv[1]}`) {
215
- main().catch((error) => {
216
- console.error('Unhandled error:', error);
217
- process.exit(1);
218
- });
219
- }