251148c3ff
## Summary - add repository-wide quality tooling and verification scaffolding, including CI workflows, pnpm workspace setup, ESLint/Prettier/markdown checks, and generated-output verification helpers - reorganize skill sources and generation flow by introducing canonical `_source` variants, generator/manifests, reusable helper abstractions, and shared web-automation/browser utilities - clean up and expand documentation so the root README flows into docs and skill docs, with clearer development, reviewer, installer, and workflow guidance ## Notable changes - docs flow and consistency cleanup across `README.md`, `docs/README.md`, and related docs - new scripts for `check`, docs verification, generated-file verification, shell portability, and safe directory replacement - refactors in Atlassian and web-automation skill runtimes to reduce duplication and centralize reusable code - changelog, development documentation, and CI surface updates ## Test Plan - [ ] `pnpm run check` - [ ] review generated/manifests and skill sync outputs - [ ] smoke-check docs flow from `README.md` to `docs/README.md` to skill docs ## Notes - this branch currently includes tracked `skills/web-automation/shared/node_modules` content that should be reviewed carefully as potentially noisy/accidental committed artifacts Co-authored-by: Stefano Fiorini <stefano.fiorini@firsthorizon.com> Reviewed-on: #1
77 lines
2.6 KiB
TypeScript
77 lines
2.6 KiB
TypeScript
// ⚠️ 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 };
|
||
}
|