browser-ipc-cdp 1.0.0 → 1.1.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.
- package/lib/browser.js +219 -67
- package/lib/mcp.js +23 -18
- package/lib/network.js +13 -2
- package/package.json +1 -1
package/lib/browser.js
CHANGED
|
@@ -4,43 +4,144 @@ const path = require('path');
|
|
|
4
4
|
const http = require('http');
|
|
5
5
|
const { log, success, warn } = require('./logger');
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
chrome: [
|
|
14
|
-
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
|
15
|
-
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
|
|
16
|
-
path.join(process.env.LOCALAPPDATA || '', 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
|
17
|
-
],
|
|
18
|
-
edge: [
|
|
19
|
-
'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe',
|
|
20
|
-
'C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe',
|
|
21
|
-
],
|
|
22
|
-
};
|
|
7
|
+
const IS_WIN = process.platform === 'win32';
|
|
8
|
+
const IS_MAC = process.platform === 'darwin';
|
|
9
|
+
const HOME = process.env.HOME || process.env.USERPROFILE || '';
|
|
10
|
+
const LOCALAPPDATA = process.env.LOCALAPPDATA || '';
|
|
11
|
+
const PROGRAMFILES = process.env.PROGRAMFILES || 'C:\\Program Files';
|
|
12
|
+
const PROGRAMFILES86 = process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)';
|
|
23
13
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
14
|
+
// Rutas dinámicas por plataforma
|
|
15
|
+
const BROWSER_REGISTRY = {
|
|
16
|
+
brave: {
|
|
17
|
+
win: [
|
|
18
|
+
path.join(PROGRAMFILES, 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'),
|
|
19
|
+
path.join(PROGRAMFILES86, 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'),
|
|
20
|
+
path.join(LOCALAPPDATA, 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'),
|
|
21
|
+
],
|
|
22
|
+
mac: [
|
|
23
|
+
'/Applications/Brave Browser.app/Contents/MacOS/Brave Browser',
|
|
24
|
+
path.join(HOME, 'Applications', 'Brave Browser.app', 'Contents', 'MacOS', 'Brave Browser'),
|
|
25
|
+
],
|
|
26
|
+
linux: [
|
|
27
|
+
'/usr/bin/brave-browser',
|
|
28
|
+
'/usr/bin/brave',
|
|
29
|
+
'/snap/bin/brave',
|
|
30
|
+
'/opt/brave.com/brave/brave-browser',
|
|
31
|
+
],
|
|
32
|
+
userData: {
|
|
33
|
+
win: path.join(LOCALAPPDATA, 'BraveSoftware', 'Brave-Browser', 'User Data'),
|
|
34
|
+
mac: path.join(HOME, 'Library', 'Application Support', 'BraveSoftware', 'Brave-Browser'),
|
|
35
|
+
linux: path.join(HOME, '.config', 'BraveSoftware', 'Brave-Browser'),
|
|
36
|
+
},
|
|
37
|
+
processName: { win: 'brave.exe', mac: 'Brave Browser', linux: 'brave' },
|
|
38
|
+
},
|
|
39
|
+
chrome: {
|
|
40
|
+
win: [
|
|
41
|
+
path.join(PROGRAMFILES, 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
|
42
|
+
path.join(PROGRAMFILES86, 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
|
43
|
+
path.join(LOCALAPPDATA, 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
|
44
|
+
],
|
|
45
|
+
mac: [
|
|
46
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
47
|
+
path.join(HOME, 'Applications', 'Google Chrome.app', 'Contents', 'MacOS', 'Google Chrome'),
|
|
48
|
+
],
|
|
49
|
+
linux: [
|
|
50
|
+
'/usr/bin/google-chrome',
|
|
51
|
+
'/usr/bin/google-chrome-stable',
|
|
52
|
+
'/snap/bin/chromium',
|
|
53
|
+
'/usr/bin/chromium-browser',
|
|
54
|
+
'/usr/bin/chromium',
|
|
55
|
+
],
|
|
56
|
+
userData: {
|
|
57
|
+
win: path.join(LOCALAPPDATA, 'Google', 'Chrome', 'User Data'),
|
|
58
|
+
mac: path.join(HOME, 'Library', 'Application Support', 'Google', 'Chrome'),
|
|
59
|
+
linux: path.join(HOME, '.config', 'google-chrome'),
|
|
60
|
+
},
|
|
61
|
+
processName: { win: 'chrome.exe', mac: 'Google Chrome', linux: 'chrome' },
|
|
62
|
+
},
|
|
63
|
+
edge: {
|
|
64
|
+
win: [
|
|
65
|
+
path.join(PROGRAMFILES86, 'Microsoft', 'Edge', 'Application', 'msedge.exe'),
|
|
66
|
+
path.join(PROGRAMFILES, 'Microsoft', 'Edge', 'Application', 'msedge.exe'),
|
|
67
|
+
],
|
|
68
|
+
mac: [
|
|
69
|
+
'/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
|
|
70
|
+
],
|
|
71
|
+
linux: [
|
|
72
|
+
'/usr/bin/microsoft-edge',
|
|
73
|
+
'/usr/bin/microsoft-edge-stable',
|
|
74
|
+
],
|
|
75
|
+
userData: {
|
|
76
|
+
win: path.join(LOCALAPPDATA, 'Microsoft', 'Edge', 'User Data'),
|
|
77
|
+
mac: path.join(HOME, 'Library', 'Application Support', 'Microsoft Edge'),
|
|
78
|
+
linux: path.join(HOME, '.config', 'microsoft-edge'),
|
|
79
|
+
},
|
|
80
|
+
processName: { win: 'msedge.exe', mac: 'Microsoft Edge', linux: 'msedge' },
|
|
81
|
+
},
|
|
82
|
+
chromium: {
|
|
83
|
+
win: [
|
|
84
|
+
path.join(LOCALAPPDATA, 'Chromium', 'Application', 'chrome.exe'),
|
|
85
|
+
],
|
|
86
|
+
mac: [
|
|
87
|
+
'/Applications/Chromium.app/Contents/MacOS/Chromium',
|
|
88
|
+
],
|
|
89
|
+
linux: [
|
|
90
|
+
'/usr/bin/chromium',
|
|
91
|
+
'/usr/bin/chromium-browser',
|
|
92
|
+
'/snap/bin/chromium',
|
|
93
|
+
],
|
|
94
|
+
userData: {
|
|
95
|
+
win: path.join(LOCALAPPDATA, 'Chromium', 'User Data'),
|
|
96
|
+
mac: path.join(HOME, 'Library', 'Application Support', 'Chromium'),
|
|
97
|
+
linux: path.join(HOME, '.config', 'chromium'),
|
|
98
|
+
},
|
|
99
|
+
processName: { win: 'chrome.exe', mac: 'Chromium', linux: 'chromium' },
|
|
100
|
+
},
|
|
28
101
|
};
|
|
29
102
|
|
|
103
|
+
function getPlatform() {
|
|
104
|
+
if (IS_WIN) return 'win';
|
|
105
|
+
if (IS_MAC) return 'mac';
|
|
106
|
+
return 'linux';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getBrowserPaths(name) {
|
|
110
|
+
const entry = BROWSER_REGISTRY[name];
|
|
111
|
+
if (!entry) return { paths: [], userData: '', processName: '' };
|
|
112
|
+
const plat = getPlatform();
|
|
113
|
+
return {
|
|
114
|
+
paths: entry[plat] || [],
|
|
115
|
+
userData: (entry.userData && entry.userData[plat]) || '',
|
|
116
|
+
processName: (entry.processName && entry.processName[plat]) || name,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
30
120
|
function detectBrowsers() {
|
|
31
121
|
const found = [];
|
|
32
|
-
for (const
|
|
122
|
+
for (const name of Object.keys(BROWSER_REGISTRY)) {
|
|
123
|
+
const { paths, userData } = getBrowserPaths(name);
|
|
33
124
|
for (const p of paths) {
|
|
34
125
|
if (fs.existsSync(p)) {
|
|
35
|
-
found.push({
|
|
36
|
-
name,
|
|
37
|
-
exe: p,
|
|
38
|
-
userData: BROWSER_USER_DATA[name] || '',
|
|
39
|
-
});
|
|
126
|
+
found.push({ name, exe: p, userData });
|
|
40
127
|
break;
|
|
41
128
|
}
|
|
42
129
|
}
|
|
43
130
|
}
|
|
131
|
+
// Fallback: buscar en PATH
|
|
132
|
+
const cmds = IS_WIN
|
|
133
|
+
? ['brave', 'chrome', 'msedge']
|
|
134
|
+
: ['brave-browser', 'brave', 'google-chrome', 'google-chrome-stable', 'chromium', 'chromium-browser', 'microsoft-edge'];
|
|
135
|
+
for (const cmd of cmds) {
|
|
136
|
+
try {
|
|
137
|
+
const which = IS_WIN
|
|
138
|
+
? execSync(`where ${cmd} 2>nul`, { encoding: 'utf-8', timeout: 5000 }).trim().split('\n')[0]
|
|
139
|
+
: execSync(`which ${cmd} 2>/dev/null`, { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
140
|
+
if (which && fs.existsSync(which) && !found.some(b => b.exe === which)) {
|
|
141
|
+
found.push({ name: cmd, exe: which, userData: '' });
|
|
142
|
+
}
|
|
143
|
+
} catch (e) {}
|
|
144
|
+
}
|
|
44
145
|
return found;
|
|
45
146
|
}
|
|
46
147
|
|
|
@@ -85,13 +186,18 @@ function testCdp(port, timeout = 3000) {
|
|
|
85
186
|
}
|
|
86
187
|
|
|
87
188
|
function isBrowserRunning(exe) {
|
|
88
|
-
const exeName = path.basename(exe)
|
|
189
|
+
const exeName = path.basename(exe);
|
|
89
190
|
try {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
191
|
+
if (IS_WIN) {
|
|
192
|
+
const result = execSync(
|
|
193
|
+
`tasklist /FI "IMAGENAME eq ${exeName}" /FO CSV /NH`,
|
|
194
|
+
{ timeout: 10000, encoding: 'utf-8', stdio: 'pipe' }
|
|
195
|
+
);
|
|
196
|
+
return result.toLowerCase().includes(exeName.toLowerCase());
|
|
197
|
+
} else {
|
|
198
|
+
const result = execSync(`pgrep -f "${exeName}"`, { timeout: 5000, stdio: 'pipe' });
|
|
199
|
+
return result.length > 0;
|
|
200
|
+
}
|
|
95
201
|
} catch (e) {
|
|
96
202
|
return false;
|
|
97
203
|
}
|
|
@@ -115,14 +221,22 @@ async function detectExistingCDP(browser) {
|
|
|
115
221
|
}
|
|
116
222
|
}
|
|
117
223
|
|
|
118
|
-
// 2. Command line
|
|
224
|
+
// 2. Command line scan
|
|
119
225
|
try {
|
|
120
|
-
const exeName = path.basename(browser.exe)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
226
|
+
const exeName = path.basename(browser.exe);
|
|
227
|
+
let cmdOutput = '';
|
|
228
|
+
if (IS_WIN) {
|
|
229
|
+
cmdOutput = execSync(
|
|
230
|
+
`wmic process where "name='${exeName}'" get commandline /format:list`,
|
|
231
|
+
{ timeout: 10000, encoding: 'utf-8', stdio: 'pipe' }
|
|
232
|
+
);
|
|
233
|
+
} else {
|
|
234
|
+
cmdOutput = execSync(
|
|
235
|
+
`ps aux | grep "${exeName}" | grep -v grep`,
|
|
236
|
+
{ timeout: 10000, encoding: 'utf-8', stdio: 'pipe' }
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
const match = cmdOutput.match(/--remote-debugging-port[=\s](\d{2,5})/);
|
|
126
240
|
if (match) {
|
|
127
241
|
const port = parseInt(match[1]);
|
|
128
242
|
if (port > 0) {
|
|
@@ -132,37 +246,67 @@ async function detectExistingCDP(browser) {
|
|
|
132
246
|
}
|
|
133
247
|
} catch (e) {}
|
|
134
248
|
|
|
135
|
-
// 3. Scan ports
|
|
249
|
+
// 3. Scan ports
|
|
136
250
|
try {
|
|
137
|
-
const exeName = path.basename(browser.exe)
|
|
138
|
-
const taskResult = execSync(
|
|
139
|
-
`tasklist /FI "IMAGENAME eq ${exeName}" /FO CSV /NH`,
|
|
140
|
-
{ timeout: 10000, encoding: 'utf-8' }
|
|
141
|
-
);
|
|
251
|
+
const exeName = path.basename(browser.exe);
|
|
142
252
|
const pids = new Set();
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
253
|
+
|
|
254
|
+
if (IS_WIN) {
|
|
255
|
+
const taskResult = execSync(
|
|
256
|
+
`tasklist /FI "IMAGENAME eq ${exeName}" /FO CSV /NH`,
|
|
257
|
+
{ timeout: 10000, encoding: 'utf-8', stdio: 'pipe' }
|
|
258
|
+
);
|
|
259
|
+
taskResult.split('\n').forEach(line => {
|
|
260
|
+
const parts = line.trim().replace(/"/g, '').split(',');
|
|
261
|
+
if (parts.length >= 2) {
|
|
262
|
+
const pid = parseInt(parts[1]);
|
|
263
|
+
if (!isNaN(pid)) pids.add(pid);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
} else {
|
|
267
|
+
const pgrepResult = execSync(`pgrep -f "${exeName}"`,
|
|
268
|
+
{ timeout: 5000, encoding: 'utf-8', stdio: 'pipe' });
|
|
269
|
+
pgrepResult.trim().split('\n').forEach(p => {
|
|
270
|
+
const pid = parseInt(p.trim());
|
|
147
271
|
if (!isNaN(pid)) pids.add(pid);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
272
|
+
});
|
|
273
|
+
}
|
|
150
274
|
|
|
151
275
|
if (pids.size > 0) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
276
|
+
if (IS_WIN) {
|
|
277
|
+
const netstat = execSync('netstat -ano -p tcp', { timeout: 10000, encoding: 'utf-8', stdio: 'pipe' });
|
|
278
|
+
for (const line of netstat.split('\n')) {
|
|
279
|
+
const tokens = line.trim().split(/\s+/);
|
|
280
|
+
if (tokens.length >= 5 && tokens[3] === 'LISTENING') {
|
|
281
|
+
const pid = parseInt(tokens[4]);
|
|
282
|
+
if (pids.has(pid)) {
|
|
283
|
+
const portStr = tokens[1].split(':').pop();
|
|
284
|
+
const port = parseInt(portStr);
|
|
285
|
+
if (port > 1024) {
|
|
286
|
+
const cdp = await testCdp(port);
|
|
287
|
+
if (cdp) return port;
|
|
288
|
+
}
|
|
163
289
|
}
|
|
164
290
|
}
|
|
165
291
|
}
|
|
292
|
+
} else {
|
|
293
|
+
// Mac/Linux: use lsof or ss
|
|
294
|
+
for (const pid of pids) {
|
|
295
|
+
try {
|
|
296
|
+
const lsof = execSync(`lsof -i -P -n -p ${pid} 2>/dev/null | grep LISTEN`,
|
|
297
|
+
{ timeout: 10000, encoding: 'utf-8', stdio: 'pipe' });
|
|
298
|
+
for (const line of lsof.split('\n')) {
|
|
299
|
+
const match = line.match(/:(\d+)\s/);
|
|
300
|
+
if (match) {
|
|
301
|
+
const port = parseInt(match[1]);
|
|
302
|
+
if (port > 1024) {
|
|
303
|
+
const cdp = await testCdp(port);
|
|
304
|
+
if (cdp) return port;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
} catch (e) {}
|
|
309
|
+
}
|
|
166
310
|
}
|
|
167
311
|
}
|
|
168
312
|
} catch (e) {}
|
|
@@ -173,7 +317,11 @@ async function detectExistingCDP(browser) {
|
|
|
173
317
|
function killBrowser(exe) {
|
|
174
318
|
const exeName = path.basename(exe);
|
|
175
319
|
try {
|
|
176
|
-
|
|
320
|
+
if (IS_WIN) {
|
|
321
|
+
execSync(`taskkill /F /IM ${exeName}`, { timeout: 10000, stdio: 'pipe' });
|
|
322
|
+
} else {
|
|
323
|
+
execSync(`pkill -f "${exeName}"`, { timeout: 10000, stdio: 'pipe' });
|
|
324
|
+
}
|
|
177
325
|
} catch (e) {}
|
|
178
326
|
}
|
|
179
327
|
|
|
@@ -198,10 +346,14 @@ function launchBrowser(browser, { port = 0, clean = false } = {}) {
|
|
|
198
346
|
];
|
|
199
347
|
if (clean) args.push(`--user-data-dir=${userData}`);
|
|
200
348
|
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
349
|
+
const spawnOpts = { detached: true, stdio: 'ignore' };
|
|
350
|
+
// En Mac, si el exe es un .app, necesita 'open' como wrapper
|
|
351
|
+
let cmd = browser.exe;
|
|
352
|
+
let spawnArgs = args;
|
|
353
|
+
if (IS_MAC && browser.exe.includes('.app/')) {
|
|
354
|
+
// Ejecutar directo el binario dentro del .app
|
|
355
|
+
}
|
|
356
|
+
const child = spawn(cmd, spawnArgs, spawnOpts);
|
|
205
357
|
child.unref();
|
|
206
358
|
|
|
207
359
|
log(` PID: ${child.pid}`);
|
package/lib/mcp.js
CHANGED
|
@@ -4,6 +4,13 @@ const path = require('path');
|
|
|
4
4
|
const { log, success, warn } = require('./logger');
|
|
5
5
|
|
|
6
6
|
function getWslHostIp() {
|
|
7
|
+
const IS_WIN = process.platform === 'win32';
|
|
8
|
+
|
|
9
|
+
// Mac/Linux: localhost funciona directo, no necesita IP especial
|
|
10
|
+
if (!IS_WIN) return '127.0.0.1';
|
|
11
|
+
|
|
12
|
+
// Windows: detectar IP para WSL
|
|
13
|
+
|
|
7
14
|
// 1. Desde WSL: leer resolv.conf directamente
|
|
8
15
|
try {
|
|
9
16
|
if (fs.existsSync('/etc/resolv.conf')) {
|
|
@@ -14,26 +21,24 @@ function getWslHostIp() {
|
|
|
14
21
|
} catch (e) {}
|
|
15
22
|
|
|
16
23
|
// 2. Desde Windows: via wsl.exe
|
|
17
|
-
|
|
24
|
+
try {
|
|
25
|
+
const result = execSync('wsl.exe -e grep nameserver /etc/resolv.conf',
|
|
26
|
+
{ timeout: 10000, encoding: 'utf-8', stdio: 'pipe' });
|
|
27
|
+
const match = result.match(/nameserver\s+(\d+\.\d+\.\d+\.\d+)/);
|
|
28
|
+
if (match) return match[1];
|
|
29
|
+
} catch (e) {}
|
|
30
|
+
|
|
31
|
+
// 3. Via \\wsl$
|
|
32
|
+
const distros = ['Ubuntu', 'Ubuntu-22.04', 'Ubuntu-24.04', 'Debian'];
|
|
33
|
+
for (const distro of distros) {
|
|
34
|
+
const resolvPath = `\\\\wsl$\\${distro}\\etc\\resolv.conf`;
|
|
18
35
|
try {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
36
|
+
if (fs.existsSync(resolvPath)) {
|
|
37
|
+
const content = fs.readFileSync(resolvPath, 'utf-8');
|
|
38
|
+
const match = content.match(/nameserver\s+(\d+\.\d+\.\d+\.\d+)/);
|
|
39
|
+
if (match) return match[1];
|
|
40
|
+
}
|
|
23
41
|
} catch (e) {}
|
|
24
|
-
|
|
25
|
-
// 3. Via \\wsl$
|
|
26
|
-
const distros = ['Ubuntu', 'Ubuntu-22.04', 'Ubuntu-24.04', 'Debian'];
|
|
27
|
-
for (const distro of distros) {
|
|
28
|
-
const resolvPath = `\\\\wsl$\\${distro}\\etc\\resolv.conf`;
|
|
29
|
-
try {
|
|
30
|
-
if (fs.existsSync(resolvPath)) {
|
|
31
|
-
const content = fs.readFileSync(resolvPath, 'utf-8');
|
|
32
|
-
const match = content.match(/nameserver\s+(\d+\.\d+\.\d+\.\d+)/);
|
|
33
|
-
if (match) return match[1];
|
|
34
|
-
}
|
|
35
|
-
} catch (e) {}
|
|
36
|
-
}
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
return '127.0.0.1';
|
package/lib/network.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
const { execSync } = require('child_process');
|
|
2
2
|
const { log, success, warn } = require('./logger');
|
|
3
3
|
|
|
4
|
+
const IS_WIN = process.platform === 'win32';
|
|
4
5
|
const FIREWALL_RULE = 'CDP All Ports (IPC)';
|
|
5
6
|
|
|
6
7
|
function setupFirewall() {
|
|
7
|
-
|
|
8
|
+
// Solo necesario en Windows (WSL requiere reglas de firewall)
|
|
9
|
+
// Mac/Linux no necesitan firewall para localhost
|
|
10
|
+
if (!IS_WIN) {
|
|
11
|
+
log(' Firewall: no necesario en esta plataforma');
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
8
14
|
|
|
9
15
|
// Verificar si ya existe
|
|
10
16
|
try {
|
|
@@ -30,7 +36,12 @@ function setupFirewall() {
|
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
function setupPortproxy(port) {
|
|
33
|
-
|
|
39
|
+
// Solo necesario en Windows (WSL no alcanza 127.0.0.1 de Windows)
|
|
40
|
+
// Mac/Linux: localhost funciona directo
|
|
41
|
+
if (!IS_WIN) {
|
|
42
|
+
log(' Portproxy: no necesario en esta plataforma');
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
34
45
|
|
|
35
46
|
// Verificar si ya existe
|
|
36
47
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "browser-ipc-cdp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Control remoto de navegadores Chromium (Brave, Chrome, Edge) via IPC + CDP dinamico. Un comando para conectar Claude Code a tu navegador real.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"browser-ipc-cdp": "bin/cli.js"
|