browser-ipc-cdp 1.8.2 → 1.8.3
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/brave_mcp_launcher.js +101 -4
- package/package.json +1 -1
package/brave_mcp_launcher.js
CHANGED
|
@@ -17,10 +17,11 @@
|
|
|
17
17
|
*
|
|
18
18
|
* Flujo:
|
|
19
19
|
* 1. Lee cdp_info.json -> puerto candidato
|
|
20
|
-
* 2. Verifica CDP (
|
|
20
|
+
* 2. Verifica CDP (/json/version) en hostIP:puerto
|
|
21
21
|
* 3. Si responde -> lanza chrome-devtools-mcp con ese URL
|
|
22
|
-
* 4. Si
|
|
23
|
-
* 5.
|
|
22
|
+
* 4. Si stale -> auto-discovery via tasklist+netstat de procesos Chromium
|
|
23
|
+
* 5. Si encuentra port vivo -> reescribe cdp_info.json y conecta
|
|
24
|
+
* 6. Ultimo recurso -> brave_ipc.py --no-kill (auto-launch)
|
|
24
25
|
*/
|
|
25
26
|
const { execSync, spawn, spawnSync } = require('child_process');
|
|
26
27
|
const fs = require('fs');
|
|
@@ -112,6 +113,90 @@ function testCdp(url, timeoutMs = 3000) {
|
|
|
112
113
|
});
|
|
113
114
|
}
|
|
114
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Descubre el puerto CDP real de cualquier proceso Chromium activo.
|
|
118
|
+
* Usa tasklist (PIDs por imagen) + netstat (LISTENING por PID) y
|
|
119
|
+
* prueba /json/version en cada candidato.
|
|
120
|
+
*
|
|
121
|
+
* Retorna { port, version } si encuentra uno vivo, o null.
|
|
122
|
+
*/
|
|
123
|
+
async function discoverBrowserCdp() {
|
|
124
|
+
if (!IS_WIN) return null;
|
|
125
|
+
|
|
126
|
+
const images = ['brave.exe', 'chrome.exe', 'msedge.exe', 'chromium.exe'];
|
|
127
|
+
const pids = new Set();
|
|
128
|
+
|
|
129
|
+
for (const img of images) {
|
|
130
|
+
try {
|
|
131
|
+
const out = execSync(
|
|
132
|
+
`tasklist /FI "IMAGENAME eq ${img}" /FO CSV /NH`,
|
|
133
|
+
{ encoding: 'utf-8', timeout: 8000, maxBuffer: 16 * 1024 * 1024, stdio: ['ignore', 'pipe', 'ignore'] }
|
|
134
|
+
);
|
|
135
|
+
for (const line of out.split('\n')) {
|
|
136
|
+
const parts = line.trim().split('","');
|
|
137
|
+
if (parts.length >= 2) {
|
|
138
|
+
const pid = parseInt(parts[1].replace(/"/g, ''), 10);
|
|
139
|
+
if (Number.isFinite(pid) && pid > 0) pids.add(pid);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
} catch (e) {}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (pids.size === 0) {
|
|
146
|
+
logErr('Auto-discovery: ningun proceso Chromium corriendo');
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let netstatOut = '';
|
|
151
|
+
try {
|
|
152
|
+
netstatOut = execSync('netstat -ano', {
|
|
153
|
+
encoding: 'utf-8', timeout: 20000, maxBuffer: 64 * 1024 * 1024, stdio: ['ignore', 'pipe', 'ignore'],
|
|
154
|
+
});
|
|
155
|
+
} catch (e) {
|
|
156
|
+
logErr(`Auto-discovery netstat fallo: ${e.message}`);
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const ports = new Set();
|
|
161
|
+
for (const line of netstatOut.split('\n')) {
|
|
162
|
+
const tokens = line.trim().split(/\s+/);
|
|
163
|
+
if (tokens.length < 5 || tokens[0] !== 'TCP' || !tokens[3].includes('LISTENING')) continue;
|
|
164
|
+
const pid = parseInt(tokens[4], 10);
|
|
165
|
+
if (!pids.has(pid)) continue;
|
|
166
|
+
const m = tokens[1].match(/:(\d+)$/);
|
|
167
|
+
if (!m) continue;
|
|
168
|
+
const port = parseInt(m[1], 10);
|
|
169
|
+
if (port > 1024 && port < 65536) ports.add(port);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
logErr(`Auto-discovery: ${ports.size} ports candidatos de ${pids.size} procesos`);
|
|
173
|
+
|
|
174
|
+
for (const port of ports) {
|
|
175
|
+
const version = await testCdp(`http://127.0.0.1:${port}`, 1500);
|
|
176
|
+
if (version) {
|
|
177
|
+
logErr(`Auto-discovery: CDP vivo en puerto ${port}`);
|
|
178
|
+
return { port, version };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function rewriteCdpInfo(port, version) {
|
|
186
|
+
const ws = (version && version.webSocketDebuggerUrl) || '';
|
|
187
|
+
const browser = (version && version.Browser) || 'Unknown';
|
|
188
|
+
const data = {
|
|
189
|
+
DEBUG_PORT: port,
|
|
190
|
+
DEBUG_WS: ws,
|
|
191
|
+
BROWSER: browser,
|
|
192
|
+
CDP_URL: `http://127.0.0.1:${port}`,
|
|
193
|
+
MODE: 'AUTO_DISCOVERED',
|
|
194
|
+
};
|
|
195
|
+
for (const p of [HOME_CDP_INFO, CDP_INFO]) {
|
|
196
|
+
try { fs.writeFileSync(p, JSON.stringify(data, null, 2), 'utf-8'); } catch (e) {}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
115
200
|
async function ensureCdpReady() {
|
|
116
201
|
const candidates = getHostCandidates();
|
|
117
202
|
logErr(`Candidatos host: ${candidates.join(', ')}`);
|
|
@@ -125,9 +210,21 @@ async function ensureCdpReady() {
|
|
|
125
210
|
logErr(`CDP activo en ${url}`);
|
|
126
211
|
return url;
|
|
127
212
|
}
|
|
213
|
+
logErr(`Puerto ${port} de cdp_info.json stale. Auto-discovery...`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Intento 2: auto-discovery via tasklist+netstat (no reinicia browser)
|
|
217
|
+
const discovered = await discoverBrowserCdp();
|
|
218
|
+
if (discovered) {
|
|
219
|
+
rewriteCdpInfo(discovered.port, discovered.version);
|
|
220
|
+
const url = await tryCandidates(discovered.port, candidates, 3000);
|
|
221
|
+
if (url) {
|
|
222
|
+
logErr(`CDP descubierto y cdp_info.json actualizado: ${url}`);
|
|
223
|
+
return url;
|
|
224
|
+
}
|
|
128
225
|
}
|
|
129
226
|
|
|
130
|
-
// Intento
|
|
227
|
+
// Intento 3: auto-launch via brave_ipc.py
|
|
131
228
|
logErr('CDP no responde. Auto-lanzando Brave via brave_ipc.py...');
|
|
132
229
|
if (!fs.existsSync(BRAVE_IPC_PY)) {
|
|
133
230
|
logErr(`brave_ipc.py no encontrado en ${BRAVE_IPC_PY}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "browser-ipc-cdp",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.3",
|
|
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"
|