refactor: update handler signatures to use TabSession

Change handleReadCommand and handleSnapshot to take TabSession instead of
BrowserManager. Change handleWriteCommand to take both TabSession (per-tab
ops) and BrowserManager (global ops like viewport, headers, dialog).
handleMetaCommand keeps BrowserManager for tab management.

Tests use thin wrapper functions that bridge the old 3-arg call pattern to
the new signatures via bm.getActiveSession().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan 2026-04-06 16:51:49 -07:00
parent 9f45acb074
commit c3785e09cc
No known key found for this signature in database
GPG Key ID: C1F69E85C74EFE1D
10 changed files with 89 additions and 63 deletions

View File

@ -155,7 +155,7 @@ export async function handleCookiePickerRoute(
} }
// Add to Playwright context // Add to Playwright context
const page = bm.getPage(); const page = bm.getActiveSession().getPage();
await page.context().addCookies(result.cookies); await page.context().addCookies(result.cookies);
// Track what was imported // Track what was imported
@ -187,7 +187,7 @@ export async function handleCookiePickerRoute(
return errorResponse("Missing or empty 'domains' array", 'missing_param', { port }); return errorResponse("Missing or empty 'domains' array", 'missing_param', { port });
} }
const page = bm.getPage(); const page = bm.getActiveSession().getPage();
const context = page.context(); const context = page.context();
for (const domain of domains) { for (const domain of domains) {
await context.clearCookies({ domain }); await context.clearCookies({ domain });

View File

@ -50,6 +50,9 @@ export async function handleMetaCommand(
bm: BrowserManager, bm: BrowserManager,
shutdown: () => Promise<void> | void shutdown: () => Promise<void> | void
): Promise<string> { ): Promise<string> {
// Per-tab operations use the active session; global operations use bm directly
const session = bm.getActiveSession();
switch (command) { switch (command) {
// ─── Tabs ────────────────────────────────────────── // ─── Tabs ──────────────────────────────────────────
case 'tabs': { case 'tabs': {
@ -80,7 +83,7 @@ export async function handleMetaCommand(
// ─── Server Control ──────────────────────────────── // ─── Server Control ────────────────────────────────
case 'status': { case 'status': {
const page = bm.getPage(); const page = session.getPage();
const tabs = bm.getTabCount(); const tabs = bm.getTabCount();
const mode = bm.getConnectionMode(); const mode = bm.getConnectionMode();
return [ return [
@ -111,7 +114,7 @@ export async function handleMetaCommand(
// ─── Visual ──────────────────────────────────────── // ─── Visual ────────────────────────────────────────
case 'screenshot': { case 'screenshot': {
// Parse priority: flags (--viewport, --clip) → selector (@ref, CSS) → output path // Parse priority: flags (--viewport, --clip) → selector (@ref, CSS) → output path
const page = bm.getPage(); const page = session.getPage();
let outputPath = `${TEMP_DIR}/browse-screenshot.png`; let outputPath = `${TEMP_DIR}/browse-screenshot.png`;
let clipRect: { x: number; y: number; width: number; height: number } | undefined; let clipRect: { x: number; y: number; width: number; height: number } | undefined;
let targetSelector: string | undefined; let targetSelector: string | undefined;
@ -158,7 +161,7 @@ export async function handleMetaCommand(
} }
if (targetSelector) { if (targetSelector) {
const resolved = await bm.resolveRef(targetSelector); const resolved = await session.resolveRef(targetSelector);
const locator = 'locator' in resolved ? resolved.locator : page.locator(resolved.selector); const locator = 'locator' in resolved ? resolved.locator : page.locator(resolved.selector);
await locator.screenshot({ path: outputPath, timeout: 5000 }); await locator.screenshot({ path: outputPath, timeout: 5000 });
return `Screenshot saved (element): ${outputPath}`; return `Screenshot saved (element): ${outputPath}`;
@ -174,7 +177,7 @@ export async function handleMetaCommand(
} }
case 'pdf': { case 'pdf': {
const page = bm.getPage(); const page = session.getPage();
const pdfPath = args[0] || `${TEMP_DIR}/browse-page.pdf`; const pdfPath = args[0] || `${TEMP_DIR}/browse-page.pdf`;
validateOutputPath(pdfPath); validateOutputPath(pdfPath);
await page.pdf({ path: pdfPath, format: 'A4' }); await page.pdf({ path: pdfPath, format: 'A4' });
@ -182,7 +185,7 @@ export async function handleMetaCommand(
} }
case 'responsive': { case 'responsive': {
const page = bm.getPage(); const page = session.getPage();
const prefix = args[0] || `${TEMP_DIR}/browse-responsive`; const prefix = args[0] || `${TEMP_DIR}/browse-responsive`;
validateOutputPath(prefix); validateOutputPath(prefix);
const viewports = [ const viewports = [
@ -238,10 +241,10 @@ export async function handleMetaCommand(
try { try {
let result: string; let result: string;
if (WRITE_COMMANDS.has(name)) { if (WRITE_COMMANDS.has(name)) {
result = await handleWriteCommand(name, cmdArgs, bm); result = await handleWriteCommand(name, cmdArgs, session, bm);
lastWasWrite = true; lastWasWrite = true;
} else if (READ_COMMANDS.has(name)) { } else if (READ_COMMANDS.has(name)) {
result = await handleReadCommand(name, cmdArgs, bm); result = await handleReadCommand(name, cmdArgs, session);
if (PAGE_CONTENT_COMMANDS.has(name)) { if (PAGE_CONTENT_COMMANDS.has(name)) {
result = wrapUntrustedContent(result, bm.getCurrentUrl()); result = wrapUntrustedContent(result, bm.getCurrentUrl());
} }
@ -260,7 +263,7 @@ export async function handleMetaCommand(
// Wait for network to settle after write commands before returning // Wait for network to settle after write commands before returning
if (lastWasWrite) { if (lastWasWrite) {
await bm.getPage().waitForLoadState('networkidle', { timeout: 2000 }).catch(() => {}); await session.getPage().waitForLoadState('networkidle', { timeout: 2000 }).catch(() => {});
} }
return results.join('\n\n'); return results.join('\n\n');
@ -271,7 +274,7 @@ export async function handleMetaCommand(
const [url1, url2] = args; const [url1, url2] = args;
if (!url1 || !url2) throw new Error('Usage: browse diff <url1> <url2>'); if (!url1 || !url2) throw new Error('Usage: browse diff <url1> <url2>');
const page = bm.getPage(); const page = session.getPage();
await validateNavigationUrl(url1); await validateNavigationUrl(url1);
await page.goto(url1, { waitUntil: 'domcontentloaded', timeout: 15000 }); await page.goto(url1, { waitUntil: 'domcontentloaded', timeout: 15000 });
const text1 = await getCleanText(page); const text1 = await getCleanText(page);
@ -296,7 +299,7 @@ export async function handleMetaCommand(
// ─── Snapshot ───────────────────────────────────── // ─── Snapshot ─────────────────────────────────────
case 'snapshot': { case 'snapshot': {
const snapshotResult = await handleSnapshot(args, bm); const snapshotResult = await handleSnapshot(args, session);
return wrapUntrustedContent(snapshotResult, bm.getCurrentUrl()); return wrapUntrustedContent(snapshotResult, bm.getCurrentUrl());
} }
@ -309,7 +312,7 @@ export async function handleMetaCommand(
case 'resume': { case 'resume': {
bm.resume(); bm.resume();
// Re-snapshot to capture current page state after human interaction // Re-snapshot to capture current page state after human interaction
const snapshot = await handleSnapshot(['-i'], bm); const snapshot = await handleSnapshot(['-i'], session);
return `RESUMED\n${wrapUntrustedContent(snapshot, bm.getCurrentUrl())}`; return `RESUMED\n${wrapUntrustedContent(snapshot, bm.getCurrentUrl())}`;
} }
@ -359,7 +362,7 @@ export async function handleMetaCommand(
// If a ref was passed, scroll it into view // If a ref was passed, scroll it into view
if (args.length > 0 && args[0].startsWith('@')) { if (args.length > 0 && args[0].startsWith('@')) {
try { try {
const resolved = await bm.resolveRef(args[0]); const resolved = await session.resolveRef(args[0]);
if ('locator' in resolved) { if ('locator' in resolved) {
await resolved.locator.scrollIntoViewIfNeeded({ timeout: 5000 }); await resolved.locator.scrollIntoViewIfNeeded({ timeout: 5000 });
return `Browser activated. Scrolled ${args[0]} into view.`; return `Browser activated. Scrolled ${args[0]} into view.`;
@ -504,7 +507,7 @@ export async function handleMetaCommand(
} }
} }
// Close existing pages, then restore (replace, not merge) // Close existing pages, then restore (replace, not merge)
bm.setFrame(null); session.setFrame(null);
await bm.closeAllPages(); await bm.closeAllPages();
await bm.restoreState({ await bm.restoreState({
cookies: data.cookies, cookies: data.cookies,
@ -522,12 +525,12 @@ export async function handleMetaCommand(
if (!target) throw new Error('Usage: frame <selector|@ref|--name name|--url pattern|main>'); if (!target) throw new Error('Usage: frame <selector|@ref|--name name|--url pattern|main>');
if (target === 'main') { if (target === 'main') {
bm.setFrame(null); session.setFrame(null);
bm.clearRefs(); session.clearRefs();
return 'Switched to main frame'; return 'Switched to main frame';
} }
const page = bm.getPage(); const page = session.getPage();
let frame: Frame | null = null; let frame: Frame | null = null;
if (target === '--name') { if (target === '--name') {
@ -538,7 +541,7 @@ export async function handleMetaCommand(
frame = page.frame({ url: new RegExp(args[1]) }); frame = page.frame({ url: new RegExp(args[1]) });
} else { } else {
// CSS selector or @ref for the iframe element // CSS selector or @ref for the iframe element
const resolved = await bm.resolveRef(target); const resolved = await session.resolveRef(target);
const locator = 'locator' in resolved ? resolved.locator : page.locator(resolved.selector); const locator = 'locator' in resolved ? resolved.locator : page.locator(resolved.selector);
const elementHandle = await locator.elementHandle({ timeout: 5000 }); const elementHandle = await locator.elementHandle({ timeout: 5000 });
frame = await elementHandle?.contentFrame() ?? null; frame = await elementHandle?.contentFrame() ?? null;
@ -546,8 +549,8 @@ export async function handleMetaCommand(
} }
if (!frame) throw new Error(`Frame not found: ${target}`); if (!frame) throw new Error(`Frame not found: ${target}`);
bm.setFrame(frame); session.setFrame(frame);
bm.clearRefs(); session.clearRefs();
return `Switched to frame: ${frame.url()}`; return `Switched to frame: ${frame.url()}`;
} }

View File

@ -5,7 +5,7 @@
* console, network, cookies, storage, perf * console, network, cookies, storage, perf
*/ */
import type { BrowserManager } from './browser-manager'; import type { TabSession } from './tab-session';
import { consoleBuffer, networkBuffer, dialogBuffer } from './buffers'; import { consoleBuffer, networkBuffer, dialogBuffer } from './buffers';
import type { Page, Frame } from 'playwright'; import type { Page, Frame } from 'playwright';
import * as fs from 'fs'; import * as fs from 'fs';
@ -90,11 +90,11 @@ export async function getCleanText(page: Page | Frame): Promise<string> {
export async function handleReadCommand( export async function handleReadCommand(
command: string, command: string,
args: string[], args: string[],
bm: BrowserManager session: TabSession
): Promise<string> { ): Promise<string> {
const page = bm.getPage(); const page = session.getPage();
// Frame-aware target for content extraction // Frame-aware target for content extraction
const target = bm.getActiveFrameOrPage(); const target = session.getActiveFrameOrPage();
switch (command) { switch (command) {
case 'text': { case 'text': {
@ -104,7 +104,7 @@ export async function handleReadCommand(
case 'html': { case 'html': {
const selector = args[0]; const selector = args[0];
if (selector) { if (selector) {
const resolved = await bm.resolveRef(selector); const resolved = await session.resolveRef(selector);
if ('locator' in resolved) { if ('locator' in resolved) {
return await resolved.locator.innerHTML({ timeout: 5000 }); return await resolved.locator.innerHTML({ timeout: 5000 });
} }
@ -186,7 +186,7 @@ export async function handleReadCommand(
case 'css': { case 'css': {
const [selector, property] = args; const [selector, property] = args;
if (!selector || !property) throw new Error('Usage: browse css <selector> <property>'); if (!selector || !property) throw new Error('Usage: browse css <selector> <property>');
const resolved = await bm.resolveRef(selector); const resolved = await session.resolveRef(selector);
if ('locator' in resolved) { if ('locator' in resolved) {
const value = await resolved.locator.evaluate( const value = await resolved.locator.evaluate(
(el, prop) => getComputedStyle(el).getPropertyValue(prop), (el, prop) => getComputedStyle(el).getPropertyValue(prop),
@ -208,7 +208,7 @@ export async function handleReadCommand(
case 'attrs': { case 'attrs': {
const selector = args[0]; const selector = args[0];
if (!selector) throw new Error('Usage: browse attrs <selector>'); if (!selector) throw new Error('Usage: browse attrs <selector>');
const resolved = await bm.resolveRef(selector); const resolved = await session.resolveRef(selector);
if ('locator' in resolved) { if ('locator' in resolved) {
const attrs = await resolved.locator.evaluate((el) => { const attrs = await resolved.locator.evaluate((el) => {
const result: Record<string, string> = {}; const result: Record<string, string> = {};
@ -272,7 +272,7 @@ export async function handleReadCommand(
const selector = args[1]; const selector = args[1];
if (!property || !selector) throw new Error('Usage: browse is <property> <selector>\nProperties: visible, hidden, enabled, disabled, checked, editable, focused'); if (!property || !selector) throw new Error('Usage: browse is <property> <selector>\nProperties: visible, hidden, enabled, disabled, checked, editable, focused');
const resolved = await bm.resolveRef(selector); const resolved = await session.resolveRef(selector);
let locator; let locator;
if ('locator' in resolved) { if ('locator' in resolved) {
locator = resolved.locator; locator = resolved.locator;

View File

@ -823,13 +823,15 @@ async function handleCommand(body: any): Promise<Response> {
try { try {
let result: string; let result: string;
const session = browserManager.getActiveSession();
if (READ_COMMANDS.has(command)) { if (READ_COMMANDS.has(command)) {
result = await handleReadCommand(command, args, browserManager); result = await handleReadCommand(command, args, session);
if (PAGE_CONTENT_COMMANDS.has(command)) { if (PAGE_CONTENT_COMMANDS.has(command)) {
result = wrapUntrustedContent(result, browserManager.getCurrentUrl()); result = wrapUntrustedContent(result, browserManager.getCurrentUrl());
} }
} else if (WRITE_COMMANDS.has(command)) { } else if (WRITE_COMMANDS.has(command)) {
result = await handleWriteCommand(command, args, browserManager); result = await handleWriteCommand(command, args, session, browserManager);
} else if (META_COMMANDS.has(command)) { } else if (META_COMMANDS.has(command)) {
result = await handleMetaCommand(command, args, browserManager, shutdown); result = await handleMetaCommand(command, args, browserManager, shutdown);
// Start periodic snapshot interval when watch mode begins // Start periodic snapshot interval when watch mode begins
@ -840,7 +842,7 @@ async function handleCommand(body: any): Promise<Response> {
return; return;
} }
try { try {
const snapshot = await handleSnapshot(['-i'], browserManager); const snapshot = await handleSnapshot(['-i'], browserManager.getActiveSession());
browserManager.addWatchSnapshot(snapshot); browserManager.addWatchSnapshot(snapshot);
} catch { } catch {
// Page may be navigating — skip this snapshot // Page may be navigating — skip this snapshot

View File

@ -18,7 +18,7 @@
*/ */
import type { Page, Frame, Locator } from 'playwright'; import type { Page, Frame, Locator } from 'playwright';
import type { BrowserManager, RefEntry } from './browser-manager'; import type { TabSession, RefEntry } from './tab-session';
import * as Diff from 'diff'; import * as Diff from 'diff';
import { TEMP_DIR, isPathWithin } from './platform'; import { TEMP_DIR, isPathWithin } from './platform';
@ -132,13 +132,13 @@ function parseLine(line: string): ParsedNode | null {
*/ */
export async function handleSnapshot( export async function handleSnapshot(
args: string[], args: string[],
bm: BrowserManager session: TabSession
): Promise<string> { ): Promise<string> {
const opts = parseSnapshotArgs(args); const opts = parseSnapshotArgs(args);
const page = bm.getPage(); const page = session.getPage();
// Frame-aware target for accessibility tree // Frame-aware target for accessibility tree
const target = bm.getActiveFrameOrPage(); const target = session.getActiveFrameOrPage();
const inFrame = bm.getFrame() !== null; const inFrame = session.getFrame() !== null;
// Get accessibility tree via ariaSnapshot // Get accessibility tree via ariaSnapshot
let rootLocator: Locator; let rootLocator: Locator;
@ -152,7 +152,7 @@ export async function handleSnapshot(
const ariaText = await rootLocator.ariaSnapshot(); const ariaText = await rootLocator.ariaSnapshot();
if (!ariaText || ariaText.trim().length === 0) { if (!ariaText || ariaText.trim().length === 0) {
bm.setRefMap(new Map()); session.setRefMap(new Map());
return '(no accessible elements found)'; return '(no accessible elements found)';
} }
@ -337,7 +337,7 @@ export async function handleSnapshot(
} }
// Store ref map on BrowserManager // Store ref map on BrowserManager
bm.setRefMap(refMap); session.setRefMap(refMap);
if (output.length === 0) { if (output.length === 0) {
return '(no interactive elements found)'; return '(no interactive elements found)';
@ -408,9 +408,9 @@ export async function handleSnapshot(
// ─── Diff mode (-D) ─────────────────────────────────────── // ─── Diff mode (-D) ───────────────────────────────────────
if (opts.diff) { if (opts.diff) {
const lastSnapshot = bm.getLastSnapshot(); const lastSnapshot = session.getLastSnapshot();
if (!lastSnapshot) { if (!lastSnapshot) {
bm.setLastSnapshot(snapshotText); session.setLastSnapshot(snapshotText);
return snapshotText + '\n\n(no previous snapshot to diff against — this snapshot stored as baseline)'; return snapshotText + '\n\n(no previous snapshot to diff against — this snapshot stored as baseline)';
} }
@ -425,16 +425,16 @@ export async function handleSnapshot(
} }
} }
bm.setLastSnapshot(snapshotText); session.setLastSnapshot(snapshotText);
return diffOutput.join('\n'); return diffOutput.join('\n');
} }
// Store for future diffs // Store for future diffs
bm.setLastSnapshot(snapshotText); session.setLastSnapshot(snapshotText);
// Add frame context header when operating inside an iframe // Add frame context header when operating inside an iframe
if (inFrame) { if (inFrame) {
const frameUrl = bm.getFrame()?.url() ?? 'unknown'; const frameUrl = session.getFrame()?.url() ?? 'unknown';
output.unshift(`[Context: iframe src="${frameUrl}"]`); output.unshift(`[Context: iframe src="${frameUrl}"]`);
} }

View File

@ -5,6 +5,7 @@
* press, scroll, wait, viewport, cookie, header, useragent * press, scroll, wait, viewport, cookie, header, useragent
*/ */
import type { TabSession } from './tab-session';
import type { BrowserManager } from './browser-manager'; import type { BrowserManager } from './browser-manager';
import { findInstalledBrowsers, importCookies, listSupportedBrowserNames } from './cookie-import-browser'; import { findInstalledBrowsers, importCookies, listSupportedBrowserNames } from './cookie-import-browser';
import { validateNavigationUrl } from './url-validation'; import { validateNavigationUrl } from './url-validation';
@ -165,12 +166,13 @@ const CLEANUP_SELECTORS = {
export async function handleWriteCommand( export async function handleWriteCommand(
command: string, command: string,
args: string[], args: string[],
session: TabSession,
bm: BrowserManager bm: BrowserManager
): Promise<string> { ): Promise<string> {
const page = bm.getPage(); const page = session.getPage();
// Frame-aware target for locator-based operations (click, fill, etc.) // Frame-aware target for locator-based operations (click, fill, etc.)
const target = bm.getActiveFrameOrPage(); const target = session.getActiveFrameOrPage();
const inFrame = bm.getFrame() !== null; const inFrame = session.getFrame() !== null;
switch (command) { switch (command) {
case 'goto': { case 'goto': {
@ -206,9 +208,9 @@ export async function handleWriteCommand(
if (!selector) throw new Error('Usage: browse click <selector>'); if (!selector) throw new Error('Usage: browse click <selector>');
// Auto-route: if ref points to a real <option> inside a <select>, use selectOption // Auto-route: if ref points to a real <option> inside a <select>, use selectOption
const role = bm.getRefRole(selector); const role = session.getRefRole(selector);
if (role === 'option') { if (role === 'option') {
const resolved = await bm.resolveRef(selector); const resolved = await session.resolveRef(selector);
if ('locator' in resolved) { if ('locator' in resolved) {
const optionInfo = await resolved.locator.evaluate(el => { const optionInfo = await resolved.locator.evaluate(el => {
if (el.tagName !== 'OPTION') return null; // custom [role=option], not real <option> if (el.tagName !== 'OPTION') return null; // custom [role=option], not real <option>
@ -225,7 +227,7 @@ export async function handleWriteCommand(
} }
} }
const resolved = await bm.resolveRef(selector); const resolved = await session.resolveRef(selector);
try { try {
if ('locator' in resolved) { if ('locator' in resolved) {
await resolved.locator.click({ timeout: 5000 }); await resolved.locator.click({ timeout: 5000 });
@ -255,7 +257,7 @@ export async function handleWriteCommand(
const [selector, ...valueParts] = args; const [selector, ...valueParts] = args;
const value = valueParts.join(' '); const value = valueParts.join(' ');
if (!selector || !value) throw new Error('Usage: browse fill <selector> <value>'); if (!selector || !value) throw new Error('Usage: browse fill <selector> <value>');
const resolved = await bm.resolveRef(selector); const resolved = await session.resolveRef(selector);
if ('locator' in resolved) { if ('locator' in resolved) {
await resolved.locator.fill(value, { timeout: 5000 }); await resolved.locator.fill(value, { timeout: 5000 });
} else { } else {
@ -270,7 +272,7 @@ export async function handleWriteCommand(
const [selector, ...valueParts] = args; const [selector, ...valueParts] = args;
const value = valueParts.join(' '); const value = valueParts.join(' ');
if (!selector || !value) throw new Error('Usage: browse select <selector> <value>'); if (!selector || !value) throw new Error('Usage: browse select <selector> <value>');
const resolved = await bm.resolveRef(selector); const resolved = await session.resolveRef(selector);
if ('locator' in resolved) { if ('locator' in resolved) {
await resolved.locator.selectOption(value, { timeout: 5000 }); await resolved.locator.selectOption(value, { timeout: 5000 });
} else { } else {
@ -284,7 +286,7 @@ export async function handleWriteCommand(
case 'hover': { case 'hover': {
const selector = args[0]; const selector = args[0];
if (!selector) throw new Error('Usage: browse hover <selector>'); if (!selector) throw new Error('Usage: browse hover <selector>');
const resolved = await bm.resolveRef(selector); const resolved = await session.resolveRef(selector);
if ('locator' in resolved) { if ('locator' in resolved) {
await resolved.locator.hover({ timeout: 5000 }); await resolved.locator.hover({ timeout: 5000 });
} else { } else {
@ -310,7 +312,7 @@ export async function handleWriteCommand(
case 'scroll': { case 'scroll': {
const selector = args[0]; const selector = args[0];
if (selector) { if (selector) {
const resolved = await bm.resolveRef(selector); const resolved = await session.resolveRef(selector);
if ('locator' in resolved) { if ('locator' in resolved) {
await resolved.locator.scrollIntoViewIfNeeded({ timeout: 5000 }); await resolved.locator.scrollIntoViewIfNeeded({ timeout: 5000 });
} else { } else {
@ -339,7 +341,7 @@ export async function handleWriteCommand(
return 'DOM content loaded'; return 'DOM content loaded';
} }
const timeout = args[1] ? parseInt(args[1], 10) : 15000; const timeout = args[1] ? parseInt(args[1], 10) : 15000;
const resolved = await bm.resolveRef(selector); const resolved = await session.resolveRef(selector);
if ('locator' in resolved) { if ('locator' in resolved) {
await resolved.locator.waitFor({ state: 'visible', timeout }); await resolved.locator.waitFor({ state: 'visible', timeout });
} else { } else {
@ -404,7 +406,7 @@ export async function handleWriteCommand(
if (!fs.existsSync(fp)) throw new Error(`File not found: ${fp}`); if (!fs.existsSync(fp)) throw new Error(`File not found: ${fp}`);
} }
const resolved = await bm.resolveRef(selector); const resolved = await session.resolveRef(selector);
if ('locator' in resolved) { if ('locator' in resolved) {
await resolved.locator.setInputFiles(filePaths); await resolved.locator.setInputFiles(filePaths);
} else { } else {

View File

@ -9,14 +9,20 @@ import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
import { startTestServer } from './test-server'; import { startTestServer } from './test-server';
import { BrowserManager } from '../src/browser-manager'; import { BrowserManager } from '../src/browser-manager';
import { resolveServerScript } from '../src/cli'; import { resolveServerScript } from '../src/cli';
import { handleReadCommand } from '../src/read-commands'; import { handleReadCommand as _handleReadCommand } from '../src/read-commands';
import { handleWriteCommand } from '../src/write-commands'; import { handleWriteCommand as _handleWriteCommand } from '../src/write-commands';
import { handleMetaCommand } from '../src/meta-commands'; import { handleMetaCommand } from '../src/meta-commands';
import { consoleBuffer, networkBuffer, dialogBuffer, addConsoleEntry, addNetworkEntry, addDialogEntry, CircularBuffer } from '../src/buffers'; import { consoleBuffer, networkBuffer, dialogBuffer, addConsoleEntry, addNetworkEntry, addDialogEntry, CircularBuffer } from '../src/buffers';
import * as fs from 'fs'; import * as fs from 'fs';
import { spawn } from 'child_process'; import { spawn } from 'child_process';
import * as path from 'path'; import * as path from 'path';
// Thin wrappers that bridge old test calls (bm as 3rd arg) to new signatures (session + bm)
const handleReadCommand = (cmd: string, args: string[], b: BrowserManager) =>
_handleReadCommand(cmd, args, b.getActiveSession());
const handleWriteCommand = (cmd: string, args: string[], b: BrowserManager) =>
_handleWriteCommand(cmd, args, b.getActiveSession(), b);
let testServer: ReturnType<typeof startTestServer>; let testServer: ReturnType<typeof startTestServer>;
let bm: BrowserManager; let bm: BrowserManager;
let baseUrl: string; let baseUrl: string;

View File

@ -12,8 +12,13 @@
import { describe, test, expect, beforeAll, afterAll } from 'bun:test'; import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
import { BrowserManager } from '../src/browser-manager'; import { BrowserManager } from '../src/browser-manager';
import { handleReadCommand } from '../src/read-commands'; import { handleReadCommand as _handleReadCommand } from '../src/read-commands';
import { handleWriteCommand } from '../src/write-commands'; import { handleWriteCommand as _handleWriteCommand } from '../src/write-commands';
const handleReadCommand = (cmd: string, args: string[], b: BrowserManager) =>
_handleReadCommand(cmd, args, b.getActiveSession());
const handleWriteCommand = (cmd: string, args: string[], b: BrowserManager) =>
_handleWriteCommand(cmd, args, b.getActiveSession(), b);
import { generateCompareHtml } from '../../design/src/compare'; import { generateCompareHtml } from '../../design/src/compare';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';

View File

@ -8,9 +8,12 @@
import { describe, test, expect, beforeAll, afterAll } from 'bun:test'; import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
import { startTestServer } from './test-server'; import { startTestServer } from './test-server';
import { BrowserManager, type BrowserState } from '../src/browser-manager'; import { BrowserManager, type BrowserState } from '../src/browser-manager';
import { handleWriteCommand } from '../src/write-commands'; import { handleWriteCommand as _handleWriteCommand } from '../src/write-commands';
import { handleMetaCommand } from '../src/meta-commands'; import { handleMetaCommand } from '../src/meta-commands';
const handleWriteCommand = (cmd: string, args: string[], b: BrowserManager) =>
_handleWriteCommand(cmd, args, b.getActiveSession(), b);
let testServer: ReturnType<typeof startTestServer>; let testServer: ReturnType<typeof startTestServer>;
let bm: BrowserManager; let bm: BrowserManager;
let baseUrl: string; let baseUrl: string;

View File

@ -8,11 +8,16 @@
import { describe, test, expect, beforeAll, afterAll } from 'bun:test'; import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
import { startTestServer } from './test-server'; import { startTestServer } from './test-server';
import { BrowserManager } from '../src/browser-manager'; import { BrowserManager } from '../src/browser-manager';
import { handleReadCommand } from '../src/read-commands'; import { handleReadCommand as _handleReadCommand } from '../src/read-commands';
import { handleWriteCommand } from '../src/write-commands'; import { handleWriteCommand as _handleWriteCommand } from '../src/write-commands';
import { handleMetaCommand } from '../src/meta-commands'; import { handleMetaCommand } from '../src/meta-commands';
import * as fs from 'fs'; import * as fs from 'fs';
const handleReadCommand = (cmd: string, args: string[], b: BrowserManager) =>
_handleReadCommand(cmd, args, b.getActiveSession());
const handleWriteCommand = (cmd: string, args: string[], b: BrowserManager) =>
_handleWriteCommand(cmd, args, b.getActiveSession(), b);
let testServer: ReturnType<typeof startTestServer>; let testServer: ReturnType<typeof startTestServer>;
let bm: BrowserManager; let bm: BrowserManager;
let baseUrl: string; let baseUrl: string;