feat: remove downloading crx for controller-ext and directly build and load (#140)

This commit is contained in:
Nikhil
2025-12-30 16:56:02 -08:00
committed by GitHub
parent 56686940b3
commit 473a7b8ebd

View File

@@ -1,5 +1,6 @@
import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'
import { join } from 'node:path'
import { existsSync, statSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { defineWebExtConfig } from 'wxt'
// biome-ignore lint/style/noProcessEnv: config file needs env access
@@ -7,68 +8,31 @@ const env = process.env
const useBrowserOS = env.USE_BROWSEROS_BINARY === 'true'
const DEV_EXTENSIONS_DIR = join(import.meta.dirname, '.dev-extensions')
// Controller extension is needed for agent controller MCP tools to work
const CONTROLLER_EXT_URL =
'https://cdn.browseros.com/extensions/controller-1.0.0.8.crx'
const CONTROLLER_EXT_DIR = join(DEV_EXTENSIONS_DIR, 'controller')
const MONOREPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), '../..')
const CONTROLLER_EXT_DIR = join(MONOREPO_ROOT, 'apps/controller-ext/dist')
const STALE_BUILD_THRESHOLD_MS = 24 * 60 * 60 * 1000
async function downloadAndExtractCrx(
url: string,
outputDir: string,
): Promise<void> {
if (existsSync(outputDir)) {
async function ensureControllerExtBuilt(): Promise<void> {
const manifestPath = join(CONTROLLER_EXT_DIR, 'manifest.json')
if (!existsSync(manifestPath)) {
// biome-ignore lint/suspicious/noConsole: intentional logging for dev tooling
console.log(`[web-ext] Extension already extracted at ${outputDir}`)
console.log('Controller extension not built, building...')
const { execSync } = await import('node:child_process')
execSync('bun run build:ext', { cwd: MONOREPO_ROOT, stdio: 'inherit' })
return
}
// biome-ignore lint/suspicious/noConsole: intentional logging for dev tooling
console.log(`[web-ext] Downloading CRX from ${url}...`)
const response = await fetch(url)
if (!response.ok) {
throw new Error(`Failed to download CRX: ${response.statusText}`)
const stats = statSync(manifestPath)
const ageMs = Date.now() - stats.mtimeMs
if (ageMs > STALE_BUILD_THRESHOLD_MS) {
const ageDays = Math.floor(ageMs / STALE_BUILD_THRESHOLD_MS)
// biome-ignore lint/suspicious/noConsole: intentional logging for dev tooling
console.warn(
`Controller extension build is ${ageDays} day(s) old. ` +
'Run "bun run build:ext" to pick up recent changes.',
)
}
const buffer = await response.arrayBuffer()
const bytes = new Uint8Array(buffer)
// CRX3 format: magic (4) + version (4) + header_length (4) + header + zip
// Find ZIP start by looking for PK signature (0x50, 0x4B, 0x03, 0x04)
let zipStart = -1
for (let i = 0; i < bytes.length - 4; i++) {
if (
bytes[i] === 0x50 &&
bytes[i + 1] === 0x4b &&
bytes[i + 2] === 0x03 &&
bytes[i + 3] === 0x04
) {
zipStart = i
break
}
}
if (zipStart === -1) {
throw new Error('Could not find ZIP signature in CRX file')
}
const zipData = bytes.slice(zipStart)
mkdirSync(DEV_EXTENSIONS_DIR, { recursive: true })
const tempZipPath = join(DEV_EXTENSIONS_DIR, 'temp.zip')
writeFileSync(tempZipPath, zipData)
mkdirSync(outputDir, { recursive: true })
const { execSync } = await import('node:child_process')
execSync(`unzip -o "${tempZipPath}" -d "${outputDir}"`)
rmSync(tempZipPath)
// biome-ignore lint/suspicious/noConsole: intentional logging for dev tooling
console.log(`[web-ext] Extension extracted to ${outputDir}`)
}
const chromiumArgs: string[] = []
@@ -79,7 +43,7 @@ if (useBrowserOS) {
if (env.BROWSEROS_DISABLE_SERVER === 'true') {
chromiumArgs.push('--disable-browseros-server')
await downloadAndExtractCrx(CONTROLLER_EXT_URL, CONTROLLER_EXT_DIR)
await ensureControllerExtBuilt()
chromiumArgs.push(`--load-extension=${CONTROLLER_EXT_DIR}`)
}
if (env.BROWSEROS_CDP_PORT) {