#!/usr/bin/env node import { spawn, execSync } from "node:child_process"; import puppeteer from "puppeteer-core"; import { homedir, platform } from "node:os"; import { existsSync } from "node:fs"; const useProfile = process.argv[2] === "--profile"; if (process.argv[2] && process.argv[2] !== "--profile") { console.log("Usage: browser-start.js [--profile]"); console.log("\nOptions:"); console.log(" --profile Copy your default browser profile (cookies, logins)"); process.exit(1); } const SCRAPING_DIR = `${homedir()}/.cache/browser-tools`; // Check if already running on :9222 try { const browser = await puppeteer.connect({ browserURL: "http://localhost:9222", defaultViewport: null, }); await browser.disconnect(); console.log("✓ Browser already running on :9222"); process.exit(0); } catch {} // Detect platform and find browser binary const isMac = platform() === "darwin"; const isLinux = platform() === "linux"; function findBrowser() { // Try to find browser using `which` command const candidates = isMac ? ["Helium", "Google Chrome", "Chromium", "Microsoft Edge"] : ["helium", "chromium", "google-chrome", "google-chrome-stable", "chrome", "brave", "edge"]; for (const name of candidates) { try { if (isMac) { // On macOS, check /Applications const appPath = `/Applications/${name}.app/Contents/MacOS/${name}`; if (existsSync(appPath)) { return appPath; } } else { // On Linux, use `which` const result = execSync(`which ${name} 2>/dev/null`, { encoding: "utf-8" }).trim(); if (result) return result; } } catch {} } return null; } function findProfilePath() { const home = homedir(); if (isMac) { return [ `${home}/Library/Application Support/Helium`, `${home}/Library/Application Support/Google/Chrome`, `${home}/Library/Application Support/Google/Chrome Canary`, `${home}/Library/Application Support/Chromium`, `${home}/Library/Application Support/Microsoft Edge`, ]; } else { return [ `${home}/.config/helium`, `${home}/.config/chromium`, `${home}/.config/google-chrome`, `${home}/.config/google-chrome-stable`, `${home}/.config/BraveSoftware/Brave-Browser`, `${home}/.config/microsoft-edge`, ]; } } const browserPath = findBrowser(); if (!browserPath) { console.error("✗ Could not find a Chromium-based browser (tried: helium, chromium, google-chrome, edge, brave)"); process.exit(1); } // Setup profile directory execSync(`mkdir -p "${SCRAPING_DIR}"`, { stdio: "ignore" }); // Remove SingletonLock to allow new instance try { execSync(`rm -f "${SCRAPING_DIR}/SingletonLock" "${SCRAPING_DIR}/SingletonSocket" "${SCRAPING_DIR}/SingletonCookie"`, { stdio: "ignore" }); } catch {} if (useProfile) { console.log("Syncing profile..."); const profilePaths = findProfilePath(); let synced = false; for (const sourcePath of profilePaths) { if (existsSync(sourcePath)) { try { execSync( `rsync -a --delete \ --exclude='SingletonLock' \ --exclude='SingletonSocket' \ --exclude='SingletonCookie' \ --exclude='*/Sessions/*' \ --exclude='*/Current Session' \ --exclude='*/Current Tabs' \ --exclude='*/Last Session' \ --exclude='*/Last Tabs' \ "${sourcePath}/" "${SCRAPING_DIR}/"`, { stdio: "pipe" }, ); console.log(`✓ Synced profile from ${sourcePath}`); synced = true; break; } catch (e) { // Try next path } } } if (!synced) { console.log("⚠ No existing browser profile found, starting fresh"); } } // Start browser with remote debugging spawn( browserPath, [ "--remote-debugging-port=9222", `--user-data-dir=${SCRAPING_DIR}`, "--no-first-run", "--no-default-browser-check", ], { detached: true, stdio: "ignore" }, ).unref(); // Wait for browser to be ready let connected = false; for (let i = 0; i < 30; i++) { try { const browser = await puppeteer.connect({ browserURL: "http://localhost:9222", defaultViewport: null, }); await browser.disconnect(); connected = true; break; } catch { await new Promise((r) => setTimeout(r, 500)); } } if (!connected) { console.error("✗ Failed to connect to browser"); process.exit(1); } console.log(`✓ Browser started on :9222${useProfile ? " with your profile" : ""}`);