browser-ipc-cdp 2.0.1 → 2.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.
package/brave_ipc.py CHANGED
@@ -33,35 +33,109 @@ from pathlib import Path
33
33
  CONFIG_FILE = Path(__file__).parent / "browser_config.json"
34
34
  IPC_INFO_FILE = Path(__file__).parent / "cdp_info.json"
35
35
 
36
- # Rutas de búsqueda por navegador (fallback si no hay config)
37
- BROWSER_SEARCH_PATHS = {
38
- "brave": [
39
- r"C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe",
40
- r"C:\Program Files (x86)\BraveSoftware\Brave-Browser\Application\brave.exe",
41
- os.path.expandvars(r"%LOCALAPPDATA%\BraveSoftware\Brave-Browser\Application\brave.exe"),
42
- ],
43
- "chrome": [
44
- r"C:\Program Files\Google\Chrome\Application\chrome.exe",
45
- r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe",
46
- os.path.expandvars(r"%LOCALAPPDATA%\Google\Chrome\Application\chrome.exe"),
47
- ],
48
- "edge": [
49
- r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
50
- r"C:\Program Files\Microsoft\Edge\Application\msedge.exe",
51
- ],
52
- "chromium": [
53
- os.path.expandvars(r"%LOCALAPPDATA%\Chromium\Application\chrome.exe"),
54
- ],
55
- }
56
-
57
- BROWSER_USER_DATA = {
58
- "brave": os.path.expandvars(r"%LOCALAPPDATA%\BraveSoftware\Brave-Browser\User Data"),
59
- "chrome": os.path.expandvars(r"%LOCALAPPDATA%\Google\Chrome\User Data"),
60
- "edge": os.path.expandvars(r"%LOCALAPPDATA%\Microsoft\Edge\User Data"),
61
- "chromium": os.path.expandvars(r"%LOCALAPPDATA%\Chromium\User Data"),
62
- }
63
-
64
- CLEAN_USER_DATA = Path(os.path.expandvars(r"%USERPROFILE%\browser-cdp-profile"))
36
+ # Rutas de búsqueda por navegador, según sistema operativo.
37
+ # Path(p).exists() filtra las que no aplican, pero separamos por plataforma
38
+ # para no depender de %VARS% de Windows en Mac/Linux (no se expanden ahí).
39
+ _HOME = Path.home()
40
+
41
+ if sys.platform == "win32":
42
+ BROWSER_SEARCH_PATHS = {
43
+ "brave": [
44
+ r"C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe",
45
+ r"C:\Program Files (x86)\BraveSoftware\Brave-Browser\Application\brave.exe",
46
+ os.path.expandvars(r"%LOCALAPPDATA%\BraveSoftware\Brave-Browser\Application\brave.exe"),
47
+ ],
48
+ "chrome": [
49
+ r"C:\Program Files\Google\Chrome\Application\chrome.exe",
50
+ r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe",
51
+ os.path.expandvars(r"%LOCALAPPDATA%\Google\Chrome\Application\chrome.exe"),
52
+ ],
53
+ "edge": [
54
+ r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
55
+ r"C:\Program Files\Microsoft\Edge\Application\msedge.exe",
56
+ ],
57
+ "chromium": [
58
+ os.path.expandvars(r"%LOCALAPPDATA%\Chromium\Application\chrome.exe"),
59
+ ],
60
+ }
61
+ BROWSER_USER_DATA = {
62
+ "brave": os.path.expandvars(r"%LOCALAPPDATA%\BraveSoftware\Brave-Browser\User Data"),
63
+ "chrome": os.path.expandvars(r"%LOCALAPPDATA%\Google\Chrome\User Data"),
64
+ "edge": os.path.expandvars(r"%LOCALAPPDATA%\Microsoft\Edge\User Data"),
65
+ "chromium": os.path.expandvars(r"%LOCALAPPDATA%\Chromium\User Data"),
66
+ }
67
+ elif sys.platform == "darwin":
68
+ BROWSER_SEARCH_PATHS = {
69
+ "brave": [
70
+ "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
71
+ str(_HOME / "Applications/Brave Browser.app/Contents/MacOS/Brave Browser"),
72
+ ],
73
+ "chrome": [
74
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
75
+ ],
76
+ "edge": [
77
+ "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
78
+ ],
79
+ "chromium": [
80
+ "/Applications/Chromium.app/Contents/MacOS/Chromium",
81
+ ],
82
+ }
83
+ _APP_SUPPORT = _HOME / "Library/Application Support"
84
+ BROWSER_USER_DATA = {
85
+ "brave": str(_APP_SUPPORT / "BraveSoftware/Brave-Browser"),
86
+ "chrome": str(_APP_SUPPORT / "Google/Chrome"),
87
+ "edge": str(_APP_SUPPORT / "Microsoft Edge"),
88
+ "chromium": str(_APP_SUPPORT / "Chromium"),
89
+ }
90
+ else: # linux y otros unix
91
+ BROWSER_SEARCH_PATHS = {
92
+ "brave": [
93
+ "/usr/bin/brave-browser",
94
+ "/usr/bin/brave-browser-stable",
95
+ "/opt/brave.com/brave/brave",
96
+ "/snap/bin/brave",
97
+ str(_HOME / ".local/share/flatpak/exports/bin/com.brave.Browser"),
98
+ "/var/lib/flatpak/exports/bin/com.brave.Browser",
99
+ ],
100
+ "chrome": [
101
+ "/usr/bin/google-chrome",
102
+ "/usr/bin/google-chrome-stable",
103
+ "/opt/google/chrome/chrome",
104
+ ],
105
+ "edge": [
106
+ "/usr/bin/microsoft-edge",
107
+ "/opt/microsoft/msedge/msedge",
108
+ ],
109
+ "chromium": [
110
+ "/usr/bin/chromium",
111
+ "/usr/bin/chromium-browser",
112
+ "/snap/bin/chromium",
113
+ ],
114
+ }
115
+ _CONFIG = _HOME / ".config"
116
+ BROWSER_USER_DATA = {
117
+ "brave": str(_CONFIG / "BraveSoftware/Brave-Browser"),
118
+ "chrome": str(_CONFIG / "google-chrome"),
119
+ "edge": str(_CONFIG / "microsoft-edge"),
120
+ "chromium": str(_CONFIG / "chromium"),
121
+ }
122
+
123
+ # Nombres de ejecutable a buscar en el PATH (fallback), por plataforma.
124
+ if sys.platform == "win32":
125
+ BROWSER_PATH_CMDS = ["brave", "chrome", "msedge", "chromium"]
126
+ elif sys.platform == "darwin":
127
+ BROWSER_PATH_CMDS = ["brave", "brave-browser", "google-chrome", "chromium"]
128
+ else:
129
+ BROWSER_PATH_CMDS = [
130
+ "brave-browser", "brave-browser-stable", "brave",
131
+ "google-chrome", "google-chrome-stable",
132
+ "chromium", "chromium-browser", "microsoft-edge",
133
+ ]
134
+
135
+ if sys.platform == "win32":
136
+ CLEAN_USER_DATA = Path(os.path.expandvars(r"%USERPROFILE%\browser-cdp-profile"))
137
+ else:
138
+ CLEAN_USER_DATA = _HOME / "browser-cdp-profile"
65
139
 
66
140
 
67
141
  # ─── Utilidades ───────────────────────────────────────────────────────────────
@@ -89,11 +163,22 @@ def detect_browsers() -> list[dict]:
89
163
  if Path(p).exists():
90
164
  found.append({"name": name, "exe": p, "user_data": BROWSER_USER_DATA.get(name, "")})
91
165
  break
92
- # Buscar también en PATH
93
- for cmd in ["brave", "chrome", "msedge", "chromium"]:
94
- exe = shutil.which(cmd) or shutil.which(f"{cmd}.exe")
166
+ # Buscar también en PATH (nombres de binario según plataforma)
167
+ for cmd in BROWSER_PATH_CMDS:
168
+ exe = shutil.which(cmd) or (shutil.which(f"{cmd}.exe") if sys.platform == "win32" else None)
95
169
  if exe and not any(b["exe"] == exe for b in found):
96
- found.append({"name": cmd, "exe": exe, "user_data": ""})
170
+ # Normaliza el nombre lógico para reusar BROWSER_USER_DATA
171
+ if "brave" in cmd:
172
+ name = "brave"
173
+ elif "chrome" in cmd:
174
+ name = "chrome"
175
+ elif "edge" in cmd:
176
+ name = "edge"
177
+ elif "chromium" in cmd:
178
+ name = "chromium"
179
+ else:
180
+ name = cmd
181
+ found.append({"name": name, "exe": exe, "user_data": BROWSER_USER_DATA.get(name, "")})
97
182
  return found
98
183
 
99
184
 
@@ -31,12 +31,24 @@ const HOME = process.env.USERPROFILE || process.env.HOME || '';
31
31
  const LOCALAPPDATA = process.env.LOCALAPPDATA || path.join(HOME, 'AppData', 'Local');
32
32
 
33
33
  const USER_DATA_DIRS = [
34
- { name: 'brave', path: path.join(LOCALAPPDATA, 'BraveSoftware', 'Brave-Browser', 'User Data') },
35
- { name: 'chrome', path: path.join(LOCALAPPDATA, 'Google', 'Chrome', 'User Data') },
36
- { name: 'edge', path: path.join(LOCALAPPDATA, 'Microsoft', 'Edge', 'User Data') },
37
- { name: 'chromium', path: path.join(LOCALAPPDATA, 'Chromium', 'User Data') },
34
+ { name: 'brave', path: path.join(LOCALAPPDATA, 'BraveSoftware', 'Brave-Browser', 'User Data') },
35
+ { name: 'chrome', path: path.join(LOCALAPPDATA, 'Google', 'Chrome', 'User Data') },
36
+ { name: 'edge', path: path.join(LOCALAPPDATA, 'Microsoft', 'Edge', 'User Data') },
37
+ { name: 'chromium', path: path.join(LOCALAPPDATA, 'Chromium', 'User Data') },
38
+ // Profiles custom usados por skills CDP (--user-data-dir=...)
39
+ { name: 'brave-cdp', path: path.join(HOME, 'brave-cdp-profile') },
40
+ { name: 'browser-cdp', path: path.join(HOME, 'browser-cdp-profile') },
41
+ { name: 'chrome-debug', path: path.join(HOME, 'chrome-debug') },
38
42
  ];
39
43
 
44
+ // Permite agregar profiles via env var: BROWSER_CDP_EXTRA_PROFILES="C:/path1;C:/path2"
45
+ if (process.env.BROWSER_CDP_EXTRA_PROFILES) {
46
+ for (const extra of process.env.BROWSER_CDP_EXTRA_PROFILES.split(/[;:,]/)) {
47
+ const trimmed = extra.trim();
48
+ if (trimmed) USER_DATA_DIRS.push({ name: 'env-extra', path: trimmed });
49
+ }
50
+ }
51
+
40
52
  function resolveChromeDevtoolsMcpBin() {
41
53
  try {
42
54
  return require.resolve('chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js');
@@ -91,14 +103,64 @@ function readDevToolsActivePort(userDataDir) {
91
103
  return null;
92
104
  }
93
105
 
106
+ function discoverProfilesDynamically() {
107
+ // Escanea HOME y LOCALAPPDATA buscando dirs con DevToolsActivePort
108
+ const found = [];
109
+ const seen = new Set();
110
+
111
+ function addIfHasFile(dirPath, name) {
112
+ if (!dirPath || seen.has(dirPath)) return;
113
+ seen.add(dirPath);
114
+ try {
115
+ if (fs.existsSync(path.join(dirPath, 'DevToolsActivePort'))) {
116
+ found.push({ name, path: dirPath });
117
+ }
118
+ } catch {}
119
+ }
120
+
121
+ // 1. Profiles hardcoded conocidos
122
+ for (const ud of USER_DATA_DIRS) addIfHasFile(ud.path, ud.name);
123
+
124
+ // 2. Escanear HOME por dirs *-profile, *-cdp*, *-debug
125
+ try {
126
+ for (const entry of fs.readdirSync(HOME, { withFileTypes: true })) {
127
+ if (!entry.isDirectory()) continue;
128
+ if (/profile|cdp|debug|chromium/i.test(entry.name)) {
129
+ addIfHasFile(path.join(HOME, entry.name), `home/${entry.name}`);
130
+ }
131
+ }
132
+ } catch {}
133
+
134
+ // 3. Escanear LOCALAPPDATA niveles 1-2 buscando "User Data"
135
+ try {
136
+ for (const entry of fs.readdirSync(LOCALAPPDATA, { withFileTypes: true })) {
137
+ if (!entry.isDirectory()) continue;
138
+ const sub = path.join(LOCALAPPDATA, entry.name);
139
+ addIfHasFile(path.join(sub, 'User Data'), `local/${entry.name}/User Data`);
140
+ try {
141
+ for (const sub2 of fs.readdirSync(sub, { withFileTypes: true })) {
142
+ if (!sub2.isDirectory()) continue;
143
+ addIfHasFile(path.join(sub, sub2.name, 'User Data'), `local/${entry.name}/${sub2.name}/User Data`);
144
+ }
145
+ } catch {}
146
+ }
147
+ } catch {}
148
+
149
+ return found;
150
+ }
151
+
94
152
  async function tryDevToolsActivePort() {
95
- for (const ud of USER_DATA_DIRS) {
153
+ const profiles = discoverProfilesDynamically();
154
+ log(`Profiles con DevToolsActivePort: ${profiles.length}`);
155
+ for (const ud of profiles) {
96
156
  const port = readDevToolsActivePort(ud.path);
97
157
  if (!port) continue;
98
158
  const version = await testCdp(`http://127.0.0.1:${port}`, 1500);
99
159
  if (version) {
100
160
  log(`DevToolsActivePort hit: ${ud.name} -> :${port}`);
101
161
  return { port, version };
162
+ } else {
163
+ log(`Stale port :${port} en ${ud.name}`);
102
164
  }
103
165
  }
104
166
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-ipc-cdp",
3
- "version": "2.0.1",
3
+ "version": "2.2.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",