chrometools-mcp 1.9.1 → 2.3.2

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.
@@ -0,0 +1,62 @@
1
+ /**
2
+ * utils/platform-utils.js
3
+ *
4
+ * Platform detection and platform-specific utilities
5
+ */
6
+
7
+ import { readFileSync } from 'fs';
8
+
9
+ /**
10
+ * Detect WSL environment
11
+ * @returns {boolean} - True if running in WSL
12
+ */
13
+ export const isWSL = (() => {
14
+ try {
15
+ const proc_version = readFileSync('/proc/version', 'utf8').toLowerCase();
16
+ return proc_version.includes('microsoft') || proc_version.includes('wsl');
17
+ } catch {
18
+ return false;
19
+ }
20
+ })();
21
+
22
+ /**
23
+ * Detect Windows environment (including WSL)
24
+ * @returns {boolean} - True if running on Windows or WSL
25
+ */
26
+ export const isWindows = process.platform === 'win32' || isWSL;
27
+
28
+ /**
29
+ * Get Chrome executable path based on platform
30
+ * @returns {string} - Path to Chrome executable
31
+ */
32
+ export function getChromePath() {
33
+ if (process.platform === 'win32') {
34
+ // Native Windows
35
+ return 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
36
+ } else if (isWSL) {
37
+ // WSL - use Windows Chrome
38
+ return '/mnt/c/Program Files/Google/Chrome/Application/chrome.exe';
39
+ } else {
40
+ // Linux
41
+ return '/usr/bin/google-chrome';
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Get temp directory based on platform
47
+ * @returns {string} - Path to temp directory
48
+ */
49
+ export function getTempDir() {
50
+ if (process.platform === 'win32') {
51
+ return process.env.TEMP || 'C:\\Windows\\Temp';
52
+ } else if (isWSL) {
53
+ return '/mnt/c/Windows/Temp';
54
+ } else {
55
+ return process.env.TMPDIR || '/tmp';
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Chrome remote debugging port
61
+ */
62
+ export const CHROME_DEBUG_PORT = 9222;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * utils/url-to-project.js
3
+ *
4
+ * Utilities for extracting project ID from website URLs.
5
+ * Used by scenario recorder to organize scenarios by domain.
6
+ */
7
+
8
+ /**
9
+ * Extract project ID from URL
10
+ *
11
+ * Strategy (v3.0):
12
+ * - Always use main domain only (strip all subdomains)
13
+ * - Include ports for ALL domains (localhost and others)
14
+ * - file:// URLs → "local"
15
+ * - Invalid URLs → "unknown"
16
+ *
17
+ * Examples:
18
+ * - https://www.google.com → "google"
19
+ * - https://dev.example.com:8080 → "example-8080"
20
+ * - https://mail.google.com → "google"
21
+ * - http://localhost:3000 → "localhost-3000"
22
+ * - https://api.stripe.com:443 → "stripe-443"
23
+ * - file:///C:/test.html → "local"
24
+ *
25
+ * @param {string} url - Full URL
26
+ * @returns {string} - Project ID (e.g., "google", "localhost-3000", "example-8080")
27
+ */
28
+ export function urlToProjectId(url) {
29
+ try {
30
+ // Handle file:// protocol
31
+ if (url.startsWith('file://')) {
32
+ return 'local';
33
+ }
34
+
35
+ const urlObj = new URL(url);
36
+ let hostname = urlObj.hostname.toLowerCase();
37
+ const port = urlObj.port;
38
+
39
+ // Remove www prefix
40
+ hostname = hostname.replace(/^www\./, '');
41
+
42
+ // Split hostname into parts
43
+ const parts = hostname.split('.');
44
+
45
+ // Single-level hostnames (e.g., "localhost", "example")
46
+ if (parts.length === 1) {
47
+ const projectId = sanitizeProjectId(parts[0]);
48
+ return port ? `${projectId}-${port}` : projectId;
49
+ }
50
+
51
+ // Multi-level hostnames: extract main domain (second-to-last part before TLD)
52
+ // Examples:
53
+ // - google.com → parts=['google', 'com'] → mainDomain='google'
54
+ // - dev.example.com → parts=['dev', 'example', 'com'] → mainDomain='example'
55
+ // - mail.google.co.uk → parts=['mail', 'google', 'co', 'uk'] → mainDomain='co' (not ideal, but simple)
56
+ const mainDomain = parts[parts.length - 2];
57
+ const projectId = sanitizeProjectId(mainDomain);
58
+
59
+ // Add port if present (for ALL domains, not just localhost)
60
+ return port ? `${projectId}-${port}` : projectId;
61
+
62
+ } catch (error) {
63
+ // Invalid URL, return safe fallback
64
+ console.error('[url-to-project] Invalid URL:', url, error);
65
+ return 'unknown';
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Sanitize project ID
71
+ * - Lowercase everything
72
+ * - Replace non-alphanumeric characters with hyphens
73
+ * - Collapse multiple hyphens into one
74
+ * - Remove leading/trailing hyphens
75
+ *
76
+ * @param {string} id - Raw project ID
77
+ * @returns {string} - Sanitized ID
78
+ */
79
+ function sanitizeProjectId(id) {
80
+ return id
81
+ .toLowerCase()
82
+ .replace(/[^a-z0-9-]/g, '-') // Replace non-alphanumeric with hyphens
83
+ .replace(/-+/g, '-') // Collapse multiple hyphens
84
+ .replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
85
+ }
86
+
87
+ /**
88
+ * Get browser-compatible version of urlToProjectId for injection
89
+ * Returns the function as a string to be injected into browser context
90
+ *
91
+ * @returns {string} - Function code as string
92
+ */
93
+ export function getUrlToProjectIdForBrowser() {
94
+ return `
95
+ /**
96
+ * Extract project ID from URL (browser version)
97
+ * @param {string} url - Full URL
98
+ * @returns {string} - Project ID
99
+ */
100
+ function urlToProjectId(url) {
101
+ try {
102
+ if (url.startsWith('file://')) {
103
+ return 'local';
104
+ }
105
+
106
+ const urlObj = new URL(url);
107
+ let hostname = urlObj.hostname.toLowerCase();
108
+ const port = urlObj.port;
109
+
110
+ hostname = hostname.replace(/^www\\./, '');
111
+ const parts = hostname.split('.');
112
+
113
+ if (parts.length === 1) {
114
+ const projectId = sanitizeProjectId(parts[0]);
115
+ return port ? \`\${projectId}-\${port}\` : projectId;
116
+ }
117
+
118
+ const mainDomain = parts[parts.length - 2];
119
+ const projectId = sanitizeProjectId(mainDomain);
120
+ return port ? \`\${projectId}-\${port}\` : projectId;
121
+
122
+ } catch (error) {
123
+ console.error('[url-to-project] Invalid URL:', url, error);
124
+ return 'unknown';
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Sanitize project ID (browser version)
130
+ * @param {string} id - Raw project ID
131
+ * @returns {string} - Sanitized ID
132
+ */
133
+ function sanitizeProjectId(id) {
134
+ return id
135
+ .toLowerCase()
136
+ .replace(/[^a-z0-9-]/g, '-')
137
+ .replace(/-+/g, '-')
138
+ .replace(/^-|-$/g, '');
139
+ }
140
+ `;
141
+ }
@@ -1,87 +0,0 @@
1
- /**
2
- * utils/project-detector.js
3
- *
4
- * Utilities for detecting the current project root directory.
5
- * Uses cascade strategy: env variables → Git root → cwd fallback
6
- */
7
-
8
- import { execSync } from 'child_process';
9
- import path from 'path';
10
-
11
- /**
12
- * Find Git repository root from a starting path
13
- * @param {string} startPath - Path to start searching from
14
- * @returns {string|null} - Git root path or null if not in a Git repository
15
- */
16
- function findGitRoot(startPath = process.cwd()) {
17
- try {
18
- const root = execSync('git rev-parse --show-toplevel', {
19
- cwd: startPath,
20
- encoding: 'utf-8',
21
- stdio: ['pipe', 'pipe', 'ignore'] // Suppress stderr
22
- }).trim();
23
-
24
- // Normalize path separators for Windows
25
- return path.normalize(root);
26
- } catch {
27
- // Not in a Git repository or git command not available
28
- return null;
29
- }
30
- }
31
-
32
- /**
33
- * Detect project root directory using cascade strategy
34
- *
35
- * Priority:
36
- * 1. CLAUDE_PROJECT_DIR environment variable
37
- * 2. PROJECT_DIR environment variable (custom)
38
- * 3. Git repository root
39
- * 4. Current working directory (fallback)
40
- *
41
- * @returns {string} - Detected project root path
42
- */
43
- export function detectProjectRoot() {
44
- // 1. Try CLAUDE_PROJECT_DIR (Claude Code specific)
45
- if (process.env.CLAUDE_PROJECT_DIR) {
46
- const claudeDir = path.normalize(process.env.CLAUDE_PROJECT_DIR);
47
- console.log('[chrometools-mcp] Project root from CLAUDE_PROJECT_DIR:', claudeDir);
48
- return claudeDir;
49
- }
50
-
51
- // 2. Try PROJECT_DIR (custom env variable)
52
- if (process.env.PROJECT_DIR) {
53
- const projectDir = path.normalize(process.env.PROJECT_DIR);
54
- console.log('[chrometools-mcp] Project root from PROJECT_DIR:', projectDir);
55
- return projectDir;
56
- }
57
-
58
- // 3. Try Git root
59
- const gitRoot = findGitRoot();
60
- if (gitRoot) {
61
- console.log('[chrometools-mcp] Project root from Git:', gitRoot);
62
- return gitRoot;
63
- }
64
-
65
- // 4. Fallback to current working directory
66
- const cwd = process.cwd();
67
- console.log('[chrometools-mcp] Project root fallback to cwd:', cwd);
68
- return cwd;
69
- }
70
-
71
- /**
72
- * Get scenarios directory path from base directory
73
- * @param {string} baseDir - Base directory
74
- * @returns {string} - Path to scenarios directory
75
- */
76
- export function getScenariosDir(baseDir) {
77
- return path.join(baseDir, 'scenarios');
78
- }
79
-
80
- /**
81
- * Get secrets directory path from base directory
82
- * @param {string} baseDir - Base directory
83
- * @returns {string} - Path to secrets directory
84
- */
85
- export function getSecretsDir(baseDir) {
86
- return path.join(baseDir, 'secrets');
87
- }