Files
dotfiles/pi/files/agent/skills/pi-skills/browser-tools/browser-start.js
T

163 lines
4.2 KiB
JavaScript
Executable File

#!/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" : ""}`);