feat(browse): support Chrome extensions via BROWSE_EXTENSIONS_DIR

When the BROWSE_EXTENSIONS_DIR environment variable is set to a path
containing an unpacked Chrome extension, browse launches Chromium in
headed mode with the window off-screen (simulating headless) and loads
the extension.

This enables use cases like ad blockers (reducing token waste from
ad-heavy pages), accessibility tools, and custom request header
management — all while maintaining the same CLI interface.

Implementation:
- Read BROWSE_EXTENSIONS_DIR env var in launch()
- When set: switch to headed mode with --window-position=-9999,-9999
  (extensions require headed Chromium)
- Pass --load-extension and --disable-extensions-except to Chromium
- When unset: behavior is identical to before (headless, no extensions)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
yinanli1917-cloud
2026-03-22 00:27:02 -07:00
parent dbd98aff32
commit c90cfe7af0
+22 -1
View File
@@ -62,7 +62,28 @@ export class BrowserManager {
private consecutiveFailures: number = 0;
async launch() {
this.browser = await chromium.launch({ headless: true });
// ─── Extension Support ────────────────────────────────────
// BROWSE_EXTENSIONS_DIR points to an unpacked Chrome extension directory.
// Extensions only work in headed mode, so we use an off-screen window.
const extensionsDir = process.env.BROWSE_EXTENSIONS_DIR;
const launchArgs: string[] = [];
let useHeadless = true;
if (extensionsDir) {
launchArgs.push(
`--disable-extensions-except=${extensionsDir}`,
`--load-extension=${extensionsDir}`,
'--window-position=-9999,-9999',
'--window-size=1,1',
);
useHeadless = false; // extensions require headed mode; off-screen window simulates headless
console.log(`[browse] Extensions loaded from: ${extensionsDir}`);
}
this.browser = await chromium.launch({
headless: useHeadless,
...(launchArgs.length > 0 ? { args: launchArgs } : {}),
});
// Chromium crash → exit with clear message
this.browser.on('disconnected', () => {