@panerelay/bridge
Advanced tools
| export declare const PANERELAY_BROWSER_USE_GATEWAY_PROTOCOL: "panerelay.browser-use-gateway.v1"; | ||
| export declare const PANERELAY_BROWSER_USE_GATEWAY_PORT = 43827; | ||
| export interface BrowserUseGatewayState { | ||
| protocol: typeof PANERELAY_BROWSER_USE_GATEWAY_PROTOCOL; | ||
| port: number; | ||
| pid: number; | ||
| updatedAt: string; | ||
| } | ||
| export type BrowserUseGatewayStopResult = 'absent' | 'stopped' | 'remaining'; | ||
| export declare function browserUseGatewayStatePath(homeDirectory?: string): string; | ||
| export declare function browserUseGatewayUrl(port?: number): string; | ||
| export declare function runBrowserUseGateway(options?: { | ||
| homeDirectory?: string; | ||
| }): Promise<void>; | ||
| export declare function stopBrowserUseGateway(options?: { | ||
| homeDirectory?: string; | ||
| }): Promise<BrowserUseGatewayStopResult>; | ||
| export declare function ensureBrowserUseGateway(options?: { | ||
| homeDirectory?: string; | ||
| }): Promise<string>; | ||
| //# sourceMappingURL=browser-use-gateway.d.ts.map |
| {"version":3,"file":"browser-use-gateway.d.ts","sourceRoot":"","sources":["../src/browser-use-gateway.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,sCAAsC,EAAG,kCAA2C,CAAC;AAClG,eAAO,MAAM,kCAAkC,QAAQ,CAAC;AAIxD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,OAAO,sCAAsC,CAAC;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,2BAA2B,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;AAE7E,wBAAgB,0BAA0B,CAAC,aAAa,SAAY,GAAG,MAAM,CAE5E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,SAAqC,GAAG,MAAM,CAEtF;AAoOD,wBAAsB,oBAAoB,CACxC,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,OAAO,CAAC,IAAI,CAAC,CAkDf;AAED,wBAAsB,qBAAqB,CACzC,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,OAAO,CAAC,2BAA2B,CAAC,CAwCtC;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,OAAO,CAAC,MAAM,CAAC,CA8CjB"} |
| import { randomBytes } from 'node:crypto'; | ||
| import { createServer } from 'node:http'; | ||
| import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'; | ||
| import { homedir } from 'node:os'; | ||
| import { join } from 'node:path'; | ||
| import { spawn } from 'node:child_process'; | ||
| import { PANERELAY_BROWSER_ENV, PANERELAY_BROWSER_ID_ENV, selectBrowserRegistration, } from '@panerelay/browser-registry'; | ||
| import { PANERELAY_BROWSER_USE_GATEWAY_PATH, parseBrowserUseGatewaySelection, } from '@panerelay/browser-use/environment'; | ||
| import { PANERELAY_PROTOCOL_VERSION } from '@panerelay/protocol'; | ||
| export const PANERELAY_BROWSER_USE_GATEWAY_PROTOCOL = 'panerelay.browser-use-gateway.v1'; | ||
| export const PANERELAY_BROWSER_USE_GATEWAY_PORT = 43827; | ||
| const MAX_GATEWAY_RESPONSE_BYTES = 16 * 1024; | ||
| const BOOTSTRAP_TICKET_PATTERN = /^[A-Za-z0-9_-]{43}$/; | ||
| export function browserUseGatewayStatePath(homeDirectory = homedir()) { | ||
| return join(homeDirectory, '.panerelay', 'browser-use', 'gateway.json'); | ||
| } | ||
| export function browserUseGatewayUrl(port = PANERELAY_BROWSER_USE_GATEWAY_PORT) { | ||
| return `http://127.0.0.1:${port}${PANERELAY_BROWSER_USE_GATEWAY_PATH}`; | ||
| } | ||
| async function json(response, status, value) { | ||
| const body = JSON.stringify(value); | ||
| response.writeHead(status, { | ||
| 'cache-control': 'no-store', | ||
| 'content-type': 'application/json', | ||
| 'content-length': Buffer.byteLength(body), | ||
| }); | ||
| response.end(body); | ||
| } | ||
| function gatewayRegistryOptions(homeDirectory) { | ||
| return { | ||
| defaultPath: join(homeDirectory, '.panerelay', 'browser-default.json'), | ||
| environment: gatewaySelectionEnvironment(), | ||
| legacyPath: join(homeDirectory, '.panerelay', 'bridge.json'), | ||
| registryDirectory: join(homeDirectory, '.panerelay', 'browsers'), | ||
| }; | ||
| } | ||
| function gatewaySelectionEnvironment(selection) { | ||
| const environment = { ...process.env }; | ||
| delete environment[PANERELAY_BROWSER_ID_ENV]; | ||
| delete environment[PANERELAY_BROWSER_ENV]; | ||
| if (selection) | ||
| environment[PANERELAY_BROWSER_ID_ENV] = selection.browserId; | ||
| return environment; | ||
| } | ||
| async function boundedText(response) { | ||
| const contentLength = Number(response.headers.get('content-length')); | ||
| if (Number.isFinite(contentLength) && contentLength > MAX_GATEWAY_RESPONSE_BYTES) { | ||
| throw new Error('Gateway response exceeded the protocol limit'); | ||
| } | ||
| if (!response.body) { | ||
| const body = await response.text(); | ||
| if (Buffer.byteLength(body) > MAX_GATEWAY_RESPONSE_BYTES) { | ||
| throw new Error('Gateway response exceeded the protocol limit'); | ||
| } | ||
| return body; | ||
| } | ||
| const reader = response.body.getReader(); | ||
| const chunks = []; | ||
| let size = 0; | ||
| try { | ||
| while (true) { | ||
| const chunk = await reader.read(); | ||
| if (chunk.done) | ||
| break; | ||
| size += chunk.value.byteLength; | ||
| if (size > MAX_GATEWAY_RESPONSE_BYTES) { | ||
| await reader.cancel(); | ||
| throw new Error('Gateway response exceeded the protocol limit'); | ||
| } | ||
| chunks.push(chunk.value); | ||
| } | ||
| } | ||
| finally { | ||
| reader.releaseLock(); | ||
| } | ||
| return Buffer.concat(chunks.map(chunk => Buffer.from(chunk))).toString('utf8'); | ||
| } | ||
| function controlledWebSocketUrl(value) { | ||
| if (typeof value !== 'string' || value.length > 2_048) | ||
| return false; | ||
| try { | ||
| const url = new URL(value); | ||
| const queryKeys = [...url.searchParams.keys()]; | ||
| return (url.protocol === 'ws:' && | ||
| url.hostname === '127.0.0.1' && | ||
| url.port !== '' && | ||
| url.username === '' && | ||
| url.password === '' && | ||
| url.pathname === '/cdp' && | ||
| url.searchParams.getAll('session').length === 1 && | ||
| url.searchParams.get('session') !== '' && | ||
| url.searchParams.getAll('token').length === 1 && | ||
| url.searchParams.get('token') !== '' && | ||
| queryKeys.every(key => key === 'session' || key === 'token') && | ||
| url.hash === ''); | ||
| } | ||
| catch { | ||
| return false; | ||
| } | ||
| } | ||
| function controlledVersionMetadata(value) { | ||
| if (!value || typeof value !== 'object' || Array.isArray(value)) | ||
| return false; | ||
| const keys = Object.keys(value).sort(); | ||
| const expectedKeys = [ | ||
| 'Browser', | ||
| 'Protocol-Version', | ||
| 'User-Agent', | ||
| 'V8-Version', | ||
| 'WebKit-Version', | ||
| 'webSocketDebuggerUrl', | ||
| ].sort(); | ||
| if (keys.length !== expectedKeys.length || | ||
| !keys.every((key, index) => key === expectedKeys[index])) { | ||
| return false; | ||
| } | ||
| const metadata = value; | ||
| return (typeof metadata.Browser === 'string' && | ||
| metadata.Browser.length > 0 && | ||
| metadata.Browser.length <= 512 && | ||
| typeof metadata['Protocol-Version'] === 'string' && | ||
| metadata['Protocol-Version'].length > 0 && | ||
| metadata['Protocol-Version'].length <= 128 && | ||
| typeof metadata['User-Agent'] === 'string' && | ||
| metadata['User-Agent'].length > 0 && | ||
| metadata['User-Agent'].length <= 512 && | ||
| typeof metadata['V8-Version'] === 'string' && | ||
| metadata['V8-Version'].length > 0 && | ||
| metadata['V8-Version'].length <= 512 && | ||
| typeof metadata['WebKit-Version'] === 'string' && | ||
| metadata['WebKit-Version'].length > 0 && | ||
| metadata['WebKit-Version'].length <= 512 && | ||
| controlledWebSocketUrl(metadata.webSocketDebuggerUrl)); | ||
| } | ||
| function controlledBootstrapUrl(value) { | ||
| if (typeof value !== 'string' || value.length > 4_096) | ||
| return false; | ||
| try { | ||
| const url = new URL(value); | ||
| return (url.protocol === 'http:' && | ||
| url.hostname === '127.0.0.1' && | ||
| url.port !== '' && | ||
| url.username === '' && | ||
| url.password === '' && | ||
| url.pathname.startsWith('/cdp/bootstrap/') && | ||
| BOOTSTRAP_TICKET_PATTERN.test(url.pathname.slice('/cdp/bootstrap/'.length)) && | ||
| url.search === '' && | ||
| url.hash === ''); | ||
| } | ||
| catch { | ||
| return false; | ||
| } | ||
| } | ||
| async function proxyVersion(response, homeDirectory, selection) { | ||
| try { | ||
| const selected = await selectBrowserRegistration({ | ||
| ...gatewayRegistryOptions(homeDirectory), | ||
| environment: gatewaySelectionEnvironment(selection), | ||
| }); | ||
| if (selection && selected.state.generation !== selection.generation) { | ||
| throw new Error('The selected browser connection changed; resolve it again'); | ||
| } | ||
| const bootstrap = await fetch(`http://127.0.0.1:${selected.state.port}/cdp/bootstrap`, { | ||
| method: 'POST', | ||
| headers: { | ||
| authorization: `Bearer ${selected.state.token}`, | ||
| 'content-type': 'application/json', | ||
| }, | ||
| body: JSON.stringify({ | ||
| protocol: PANERELAY_PROTOCOL_VERSION, | ||
| browser: { | ||
| browserId: selected.state.browserId, | ||
| generation: selected.state.generation, | ||
| }, | ||
| actor: { kind: 'automation', name: 'Browser Use', sessionLabel: 'panerelay' }, | ||
| engine: 'browser-use', | ||
| laneKey: 'browser-use:panerelay', | ||
| connectionPolicy: 'single', | ||
| }), | ||
| signal: AbortSignal.timeout(5_000), | ||
| }); | ||
| if (bootstrap.status !== 201) { | ||
| await json(response, bootstrap.status === 429 ? 429 : 503, { | ||
| protocol: PANERELAY_BROWSER_USE_GATEWAY_PROTOCOL, | ||
| error: 'Panerelay Browser Use connection is unavailable', | ||
| }); | ||
| return; | ||
| } | ||
| const createdText = await boundedText(bootstrap); | ||
| const created = JSON.parse(createdText); | ||
| if (!controlledBootstrapUrl(created.cdpUrl)) | ||
| throw new Error('invalid bootstrap response'); | ||
| const version = await fetch(`${created.cdpUrl}/json/version`, { | ||
| signal: AbortSignal.timeout(5_000), | ||
| }); | ||
| if (version.status !== 200) | ||
| throw new Error('invalid Browser Use version response'); | ||
| const metadata = JSON.parse(await boundedText(version)); | ||
| if (!controlledVersionMetadata(metadata)) | ||
| throw new Error('invalid Browser Use version response'); | ||
| await json(response, 200, metadata); | ||
| } | ||
| catch { | ||
| await json(response, 503, { | ||
| protocol: PANERELAY_BROWSER_USE_GATEWAY_PROTOCOL, | ||
| error: 'Panerelay Browser Use connection is unavailable', | ||
| }); | ||
| } | ||
| } | ||
| async function gatewayHealthState(port) { | ||
| const response = await fetch(`http://127.0.0.1:${port}/health`, { | ||
| signal: AbortSignal.timeout(500), | ||
| }); | ||
| if (!response.ok) | ||
| return null; | ||
| try { | ||
| const body = JSON.parse(await boundedText(response)); | ||
| return body.protocol === PANERELAY_BROWSER_USE_GATEWAY_PROTOCOL && | ||
| body.ready === true && | ||
| typeof body.pid === 'number' && | ||
| Number.isSafeInteger(body.pid) && | ||
| body.pid > 0 | ||
| ? { pid: body.pid, protocol: body.protocol } | ||
| : null; | ||
| } | ||
| catch { | ||
| return null; | ||
| } | ||
| } | ||
| async function gatewayHealth(port) { | ||
| return (await gatewayHealthState(port)) !== null; | ||
| } | ||
| export async function runBrowserUseGateway(options = {}) { | ||
| const homeDirectory = options.homeDirectory ?? homedir(); | ||
| const path = browserUseGatewayStatePath(homeDirectory); | ||
| const server = createServer(async (request, response) => { | ||
| const url = new URL(request.url ?? '/', 'http://127.0.0.1'); | ||
| if (request.method === 'GET' && url.pathname === '/health' && url.search === '') { | ||
| await json(response, 200, { | ||
| pid: process.pid, | ||
| protocol: PANERELAY_BROWSER_USE_GATEWAY_PROTOCOL, | ||
| ready: true, | ||
| }); | ||
| return; | ||
| } | ||
| if (request.method === 'GET' && url.search === '') { | ||
| const selection = parseBrowserUseGatewaySelection(url.pathname); | ||
| if (selection !== null) { | ||
| await proxyVersion(response, homeDirectory, selection); | ||
| return; | ||
| } | ||
| } | ||
| await json(response, 404, { | ||
| protocol: PANERELAY_BROWSER_USE_GATEWAY_PROTOCOL, | ||
| error: 'Unknown Panerelay Browser Use gateway endpoint', | ||
| }); | ||
| }); | ||
| await new Promise((resolve, reject) => { | ||
| server.once('error', reject); | ||
| server.listen(PANERELAY_BROWSER_USE_GATEWAY_PORT, '127.0.0.1', resolve); | ||
| }); | ||
| await mkdir(join(homeDirectory, '.panerelay', 'browser-use'), { recursive: true, mode: 0o700 }); | ||
| const state = { | ||
| protocol: PANERELAY_BROWSER_USE_GATEWAY_PROTOCOL, | ||
| port: PANERELAY_BROWSER_USE_GATEWAY_PORT, | ||
| pid: process.pid, | ||
| updatedAt: new Date().toISOString(), | ||
| }; | ||
| const temporary = `${path}.${process.pid}.${randomBytes(6).toString('hex')}.tmp`; | ||
| await writeFile(temporary, `${JSON.stringify(state, null, 2)}\n`, { mode: 0o600 }); | ||
| await rename(temporary, path); | ||
| const cleanup = async () => { | ||
| try { | ||
| const current = JSON.parse(await readFile(path, 'utf8')); | ||
| if (current.pid === process.pid) | ||
| await rm(path, { force: true }); | ||
| } | ||
| catch { | ||
| // The state may already have been removed or replaced by a newer owner. | ||
| } | ||
| server.close(); | ||
| }; | ||
| process.once('SIGTERM', () => void cleanup().finally(() => process.exit(0))); | ||
| process.once('SIGINT', () => void cleanup().finally(() => process.exit(0))); | ||
| } | ||
| export async function stopBrowserUseGateway(options = {}) { | ||
| const homeDirectory = options.homeDirectory ?? homedir(); | ||
| const path = browserUseGatewayStatePath(homeDirectory); | ||
| let state; | ||
| try { | ||
| state = JSON.parse(await readFile(path, 'utf8')); | ||
| } | ||
| catch (error) { | ||
| if (error.code === 'ENOENT') | ||
| return 'absent'; | ||
| return 'remaining'; | ||
| } | ||
| if (state.protocol !== PANERELAY_BROWSER_USE_GATEWAY_PROTOCOL || | ||
| state.port !== PANERELAY_BROWSER_USE_GATEWAY_PORT || | ||
| typeof state.pid !== 'number' || | ||
| !Number.isSafeInteger(state.pid) || | ||
| state.pid <= 0) { | ||
| return 'remaining'; | ||
| } | ||
| let health; | ||
| try { | ||
| health = await gatewayHealthState(state.port); | ||
| } | ||
| catch { | ||
| health = null; | ||
| } | ||
| if (!health || health.pid !== state.pid) | ||
| return 'remaining'; | ||
| try { | ||
| process.kill(state.pid, 'SIGTERM'); | ||
| } | ||
| catch (error) { | ||
| if (error.code !== 'ESRCH') | ||
| return 'remaining'; | ||
| } | ||
| for (let attempt = 0; attempt < 20; attempt += 1) { | ||
| await new Promise(resolve => setTimeout(resolve, 50)); | ||
| try { | ||
| if (!(await gatewayHealth(state.port))) | ||
| return 'stopped'; | ||
| } | ||
| catch { | ||
| return 'stopped'; | ||
| } | ||
| } | ||
| return 'remaining'; | ||
| } | ||
| export async function ensureBrowserUseGateway(options = {}) { | ||
| const homeDirectory = options.homeDirectory ?? homedir(); | ||
| const path = browserUseGatewayStatePath(homeDirectory); | ||
| try { | ||
| const state = JSON.parse(await readFile(path, 'utf8')); | ||
| if (state.protocol === PANERELAY_BROWSER_USE_GATEWAY_PROTOCOL && | ||
| state.port === PANERELAY_BROWSER_USE_GATEWAY_PORT && | ||
| (await gatewayHealth(state.port))) { | ||
| return browserUseGatewayUrl(state.port); | ||
| } | ||
| } | ||
| catch { | ||
| // Start or recover the gateway below. | ||
| } | ||
| const entry = process.argv[1]; | ||
| if (!entry) | ||
| throw new Error('Panerelay Browser Use gateway entrypoint is unavailable'); | ||
| const gatewayEnvironment = { | ||
| ...process.env, | ||
| HOME: homeDirectory, | ||
| USERPROFILE: homeDirectory, | ||
| }; | ||
| delete gatewayEnvironment[PANERELAY_BROWSER_ID_ENV]; | ||
| delete gatewayEnvironment[PANERELAY_BROWSER_ENV]; | ||
| const child = spawn(process.execPath, [entry, '--browser-use-gateway'], { | ||
| detached: true, | ||
| stdio: 'ignore', | ||
| env: gatewayEnvironment, | ||
| }); | ||
| child.unref(); | ||
| for (let attempt = 0; attempt < 50; attempt += 1) { | ||
| await new Promise(resolve => setTimeout(resolve, 100)); | ||
| try { | ||
| const state = JSON.parse(await readFile(path, 'utf8')); | ||
| if (state.protocol === PANERELAY_BROWSER_USE_GATEWAY_PROTOCOL && | ||
| state.port === PANERELAY_BROWSER_USE_GATEWAY_PORT && | ||
| (await gatewayHealth(state.port))) { | ||
| return browserUseGatewayUrl(state.port); | ||
| } | ||
| } | ||
| catch { | ||
| // Keep waiting for the detached gateway to bind. | ||
| } | ||
| } | ||
| throw new Error('Panerelay Browser Use gateway did not become ready'); | ||
| } |
| import { type BridgeState, type HostToExtensionMessage, type IntegrationRequestMessage } from '@panerelay/protocol'; | ||
| import { type CliAdapterRegistration } from '@panerelay/cli/adapter-config'; | ||
| import { setCliAdapterMode, type CliAdapterRegistration } from '@panerelay/cli/adapter-config'; | ||
| import { setBrowserUseEnvironmentMode } from '@panerelay/browser-use'; | ||
| import { clearBrowserDefault, listBrowserRegistrations, readBrowserDefault, setBrowserDefault } from '@panerelay/browser-registry'; | ||
@@ -19,2 +20,4 @@ import { clearPanerelayUserDefaultProvider, readPanerelayProviderAvailable, readUserDefaultProvider, setPanerelayUserDefaultProvider } from './agent-browser-config.js'; | ||
| setBrowserDefault?: typeof setBrowserDefault; | ||
| setBrowserUseEnvironmentMode?: typeof setBrowserUseEnvironmentMode; | ||
| setCliAdapterMode?: typeof setCliAdapterMode; | ||
| setBrowserUseMode?: (mode: 'direct' | 'extension') => Promise<void>; | ||
@@ -21,0 +24,0 @@ setDefaultProvider?: typeof setPanerelayUserDefaultProvider; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"integration-service.d.ts","sourceRoot":"","sources":["../src/integration-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAI3B,KAAK,yBAAyB,EAC/B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAIL,KAAK,sBAAsB,EAC5B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,iCAAiC,EACjC,8BAA8B,EAC9B,uBAAuB,EACvB,+BAA+B,EAEhC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAE1E,MAAM,WAAW,yBAAyB;IACxC,mBAAmB,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACjD,oBAAoB,CAAC,EAAE,OAAO,iCAAiC,CAAC;IAChE,cAAc,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IAC1C,kBAAkB,CAAC,EAAE,OAAO,4BAA4B,CAAC;IACzD,YAAY,CAAC,EAAE,OAAO,wBAAwB,CAAC;IAC/C,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC;IACrE,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,QAAQ,GAAG,WAAW,GAAG,IAAI,CAAC,CAAC;IAClE,kBAAkB,CAAC,EAAE,OAAO,kBAAkB,CAAC;IAC/C,mBAAmB,CAAC,EAAE,OAAO,uBAAuB,CAAC;IACrD,wBAAwB,CAAC,EAAE,OAAO,8BAA8B,CAAC;IACjE,iBAAiB,CAAC,EAAE,OAAO,iBAAiB,CAAC;IAC7C,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,kBAAkB,CAAC,EAAE,OAAO,+BAA+B,CAAC;IAC5D,aAAa,CAAC,EAAE,OAAO,sBAAsB,CAAC;CAC/C;AAiDD,qBAAa,kBAAkB;;gBAmB3B,IAAI,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,EAC/C,OAAO,GAAE,yBAA8B;IA+BnC,MAAM,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;CA+KhE"} | ||
| {"version":3,"file":"integration-service.d.ts","sourceRoot":"","sources":["../src/integration-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAI3B,KAAK,yBAAyB,EAC/B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAGL,iBAAiB,EACjB,KAAK,sBAAsB,EAC5B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,iCAAiC,EACjC,8BAA8B,EAC9B,uBAAuB,EACvB,+BAA+B,EAEhC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAE1E,MAAM,WAAW,yBAAyB;IACxC,mBAAmB,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACjD,oBAAoB,CAAC,EAAE,OAAO,iCAAiC,CAAC;IAChE,cAAc,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IAC1C,kBAAkB,CAAC,EAAE,OAAO,4BAA4B,CAAC;IACzD,YAAY,CAAC,EAAE,OAAO,wBAAwB,CAAC;IAC/C,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC;IACrE,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,QAAQ,GAAG,WAAW,GAAG,IAAI,CAAC,CAAC;IAClE,kBAAkB,CAAC,EAAE,OAAO,kBAAkB,CAAC;IAC/C,mBAAmB,CAAC,EAAE,OAAO,uBAAuB,CAAC;IACrD,wBAAwB,CAAC,EAAE,OAAO,8BAA8B,CAAC;IACjE,iBAAiB,CAAC,EAAE,OAAO,iBAAiB,CAAC;IAC7C,4BAA4B,CAAC,EAAE,OAAO,4BAA4B,CAAC;IACnE,iBAAiB,CAAC,EAAE,OAAO,iBAAiB,CAAC;IAC7C,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,kBAAkB,CAAC,EAAE,OAAO,+BAA+B,CAAC;IAC5D,aAAa,CAAC,EAAE,OAAO,sBAAsB,CAAC;CAC/C;AAiDD,qBAAa,kBAAkB;;gBAqB3B,IAAI,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,EAC/C,OAAO,GAAE,yBAA8B;IAsCnC,MAAM,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;CA+KhE"} |
| import { PANERELAY_PROTOCOL_VERSION, } from '@panerelay/protocol'; | ||
| import { readCliAdapterMode, readCliAdapterRegistration, setCliAdapterMode, } from '@panerelay/cli/adapter-config'; | ||
| import { setBrowserUseEnvironmentMode } from '@panerelay/browser-use'; | ||
| import { clearBrowserDefault, listBrowserRegistrations, readBrowserDefault, setBrowserDefault, } from '@panerelay/browser-registry'; | ||
@@ -54,2 +55,4 @@ import { clearPanerelayUserDefaultProvider, readPanerelayProviderAvailable, readUserDefaultProvider, setPanerelayUserDefaultProvider, } from './agent-browser-config.js'; | ||
| #setBrowserDefault; | ||
| #setBrowserUseEnvironmentMode; | ||
| #setCliAdapterMode; | ||
| #setBrowserUseMode; | ||
@@ -74,4 +77,11 @@ #setDefaultProvider; | ||
| this.#setBrowserDefault = options.setBrowserDefault ?? setBrowserDefault; | ||
| this.#setBrowserUseEnvironmentMode = | ||
| options.setBrowserUseEnvironmentMode ?? setBrowserUseEnvironmentMode; | ||
| this.#setCliAdapterMode = options.setCliAdapterMode ?? setCliAdapterMode; | ||
| this.#setBrowserUseMode = | ||
| options.setBrowserUseMode ?? (mode => setCliAdapterMode('browser-use', mode)); | ||
| options.setBrowserUseMode ?? | ||
| (async (mode) => { | ||
| await this.#setBrowserUseEnvironmentMode(mode); | ||
| await this.#setCliAdapterMode('browser-use', mode); | ||
| }); | ||
| this.#setDefaultProvider = options.setDefaultProvider ?? setPanerelayUserDefaultProvider; | ||
@@ -78,0 +88,0 @@ this.#pickDirectory = options.pickDirectory ?? pickWorkspaceDirectory; |
@@ -10,2 +10,3 @@ #!/usr/bin/env node | ||
| import { IntegrationService } from './integration-service.js'; | ||
| import { ensureBrowserUseGateway, runBrowserUseGateway } from './browser-use-gateway.js'; | ||
| function log(message) { | ||
@@ -70,2 +71,3 @@ process.stderr.write(`[Panerelay] ${message}\n`); | ||
| log(`Extension registered; CDP relay listening on 127.0.0.1:${relay.port}`); | ||
| await ensureBrowserUseGateway().catch(error => log(`Browser Use gateway unavailable: ${error instanceof Error ? error.message : String(error)}`)); | ||
| }, | ||
@@ -150,5 +152,7 @@ onBrowserDisconnected: async () => { | ||
| } | ||
| const operation = process.argv.includes('--agent-browser-plugin') | ||
| ? runAgentBrowserPlugin() | ||
| : main(); | ||
| const operation = process.argv.includes('--browser-use-gateway') | ||
| ? runBrowserUseGateway() | ||
| : process.argv.includes('--agent-browser-plugin') | ||
| ? runAgentBrowserPlugin() | ||
| : main(); | ||
| void operation.catch(error => { | ||
@@ -155,0 +159,0 @@ log(`Bridge failed to start: ${error instanceof Error ? error.message : String(error)}`); |
+11
-8
| { | ||
| "name": "@panerelay/bridge", | ||
| "version": "0.3.0", | ||
| "version": "0.4.0", | ||
| "description": "Panerelay Native Messaging host and local browser-level CDP relay.", | ||
@@ -38,2 +38,6 @@ "type": "module", | ||
| "import": "./dist/agent-browser-config.js" | ||
| }, | ||
| "./browser-use-gateway": { | ||
| "types": "./dist/browser-use-gateway.d.ts", | ||
| "import": "./dist/browser-use-gateway.js" | ||
| } | ||
@@ -54,10 +58,9 @@ }, | ||
| "ws": "^8.21.1", | ||
| "@panerelay/agent-browser": "0.3.0", | ||
| "@panerelay/browser-registry": "0.3.0", | ||
| "@panerelay/cli": "0.3.0", | ||
| "@panerelay/protocol": "0.3.0" | ||
| "@panerelay/agent-browser": "0.4.0", | ||
| "@panerelay/browser-registry": "0.4.0", | ||
| "@panerelay/browser-use": "0.4.0", | ||
| "@panerelay/cli": "0.4.0", | ||
| "@panerelay/protocol": "0.4.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@panerelay/browser-use": "0.3.0" | ||
| }, | ||
| "devDependencies": {}, | ||
| "scripts": { | ||
@@ -64,0 +67,0 @@ "build": "node clean.mjs && tsc -p tsconfig.json && node build.mjs", |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Network access
Supply chain riskThis module accesses the network.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 2 instances
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
3265429
2.37%0
-100%89
3.49%37336
2.16%7
16.67%30
7.14%13
62.5%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
Updated
Updated