From c90cfe7af0c71cce6ac584862a9b54a7087a4845 Mon Sep 17 00:00:00 2001 From: yinanli1917-cloud Date: Sun, 22 Mar 2026 00:27:02 -0700 Subject: [PATCH] feat(browse): support Chrome extensions via BROWSE_EXTENSIONS_DIR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- browse/src/browser-manager.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/browse/src/browser-manager.ts b/browse/src/browser-manager.ts index 31a1f9def..c2f5574cb 100644 --- a/browse/src/browser-manager.ts +++ b/browse/src/browser-manager.ts @@ -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', () => {