#!/usr/bin/env npx tsx // ⚠️ GENERATED FILE – do not edit directly. Edit the canonical source in skills/web-automation/shared/ and run `pnpm run sync:pi`. /** * Browser launcher using CloakBrowser with persistent profile * * Usage: * npx tsx browse.ts --url "https://example.com" * npx tsx browse.ts --url "https://example.com" --screenshot --output page.png * npx tsx browse.ts --url "https://example.com" --headless false --wait 5000 */ import parseArgs from 'minimist'; import type { BrowserContext } from 'playwright-core'; import { getProfilePath, launchBrowser, getPage } from './lib/browser.js'; // Re-export shared helpers so existing imports of browse.ts continue to work. export { getProfilePath, launchBrowser, getPage }; interface BrowseOptions { url: string; headless?: boolean; screenshot?: boolean; output?: string; wait?: number; timeout?: number; interactive?: boolean; } interface BrowseResult { title: string; url: string; screenshotPath?: string; } function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } export async function browse(options: BrowseOptions): Promise { const browser = await launchBrowser({ headless: options.headless }); const page = browser.pages()[0] || await browser.newPage(); try { console.log(`Navigating to: ${options.url}`); await page.goto(options.url, { timeout: options.timeout ?? 60000, waitUntil: 'domcontentloaded', }); if (options.wait) { console.log(`Waiting ${options.wait}ms...`); await sleep(options.wait); } const result: BrowseResult = { title: await page.title(), url: page.url(), }; console.log(`Page title: ${result.title}`); console.log(`Final URL: ${result.url}`); if (options.screenshot) { const outputPath = options.output ?? 'screenshot.png'; await page.screenshot({ path: outputPath, fullPage: true }); result.screenshotPath = outputPath; console.log(`Screenshot saved: ${outputPath}`); } if (options.interactive) { console.log('\nInteractive mode - browser will stay open.'); console.log('Press Ctrl+C to close.'); await new Promise(() => {}); } return result; } finally { if (!options.interactive) { await browser.close(); } } } async function main() { const args = parseArgs(process.argv.slice(2), { string: ['url', 'output'], boolean: ['screenshot', 'headless', 'interactive', 'help'], default: { headless: true, screenshot: false, interactive: false, }, alias: { u: 'url', o: 'output', s: 'screenshot', h: 'help', i: 'interactive', }, }); if (args.help || !args.url) { console.log(` Web Browser with CloakBrowser Usage: npx tsx browse.ts --url [options] Options: -u, --url URL to navigate to (required) -s, --screenshot Take a screenshot of the page -o, --output Output path for screenshot (default: screenshot.png) --headless Run in headless mode (default: true) --wait Wait time after page load in milliseconds --timeout Navigation timeout (default: 60000) -i, --interactive Keep browser open for manual interaction -h, --help Show this help message Examples: npx tsx browse.ts --url "https://example.com" npx tsx browse.ts --url "https://example.com" --screenshot --output page.png npx tsx browse.ts --url "https://example.com" --headless false --interactive Environment Variables: CLOAKBROWSER_PROFILE_PATH Custom profile directory (default: ~/.cloakbrowser-profile/) CLOAKBROWSER_HEADLESS Default headless mode (true/false) `); process.exit(args.help ? 0 : 1); } try { await browse({ url: args.url, headless: args.headless, screenshot: args.screenshot, output: args.output, wait: args.wait ? parseInt(args.wait, 10) : undefined, timeout: args.timeout ? parseInt(args.timeout, 10) : undefined, interactive: args.interactive, }); } catch (error) { console.error('Error:', error instanceof Error ? error.message : error); process.exit(1); } } const isMainModule = process.argv[1]?.includes('browse.ts'); if (isMainModule) { main(); }