153 lines
4.3 KiB
TypeScript
153 lines
4.3 KiB
TypeScript
#!/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<void> {
|
||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||
}
|
||
|
||
export async function browse(options: BrowseOptions): Promise<BrowseResult> {
|
||
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 <url> [options]
|
||
|
||
Options:
|
||
-u, --url <url> URL to navigate to (required)
|
||
-s, --screenshot Take a screenshot of the page
|
||
-o, --output <path> Output path for screenshot (default: screenshot.png)
|
||
--headless <bool> Run in headless mode (default: true)
|
||
--wait <ms> Wait time after page load in milliseconds
|
||
--timeout <ms> 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();
|
||
}
|