Files
ai-coding-skills/skills/web-automation/opencode/scripts/lib/browser.ts
T
2026-05-03 21:45:49 -05:00

77 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ⚠️ GENERATED FILE do not edit directly. Edit the canonical source in skills/web-automation/shared/ and run `pnpm run sync:pi`.
/**
* Shared browser-launch and profile helpers for web-automation scripts.
*
* Centralises the three reusable primitives that every command entry point
* needs:
* - getProfilePath() — resolve the persistent CloakBrowser profile dir
* - launchBrowser() — launch a CloakBrowser persistent context
* - getPage() — get a ready Page + BrowserContext pair
*
* All command entry points (auth.ts, browse.ts, flow.ts, scan-local-app.ts)
* import from here instead of duplicating these bodies.
*/
import { launchPersistentContext } from 'cloakbrowser';
import { existsSync, mkdirSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';
import type { BrowserContext, Page } from 'playwright-core';
/**
* Return the path to the persistent CloakBrowser profile directory.
*
* Uses `CLOAKBROWSER_PROFILE_PATH` env var when set; otherwise defaults to
* `~/.cloakbrowser-profile/` and creates it if it does not exist.
*/
export function getProfilePath(): string {
const customPath = process.env.CLOAKBROWSER_PROFILE_PATH;
if (customPath) return customPath;
const profileDir = join(homedir(), '.cloakbrowser-profile');
if (!existsSync(profileDir)) {
mkdirSync(profileDir, { recursive: true });
}
return profileDir;
}
/**
* Launch a CloakBrowser persistent context with the shared profile.
*
* Headless mode is resolved in order:
* 1. `options.headless` (explicit caller preference)
* 2. `CLOAKBROWSER_HEADLESS` env var
* 3. `true` (safe default)
*/
export async function launchBrowser(options: {
headless?: boolean;
}): Promise<BrowserContext> {
const profilePath = getProfilePath();
const envHeadless = process.env.CLOAKBROWSER_HEADLESS;
const headless = options.headless ?? (envHeadless ? envHeadless === 'true' : true);
console.log(`Using profile: ${profilePath}`);
console.log(`Headless mode: ${headless}`);
const context = await launchPersistentContext({
userDataDir: profilePath,
headless,
humanize: true,
});
return context;
}
/**
* Return a ready `{ page, browser }` pair using the shared persistent profile.
*
* Re-uses the first existing page or opens a new one if the context is empty.
*/
export async function getPage(options?: {
headless?: boolean;
}): Promise<{ page: Page; browser: BrowserContext }> {
const browser = await launchBrowser({ headless: options?.headless });
const page = browser.pages()[0] || (await browser.newPage());
return { page, browser };
}