Skip to content

Commit 1a100a2

Browse files
xr843claude
andcommitted
fix: eliminate duplicate command sets in chain, improve flush perf and type safety
- Remove duplicate CHAIN_READ/CHAIN_WRITE/CHAIN_META sets from meta-commands.ts and import from commands.ts (single source of truth). The duplicated sets would silently fail to route new commands added to commands.ts. - Replace read+concat+write log flush with fs.appendFileSync — O(new entries) instead of O(total log size) per flush cycle. - Replace `any` types for contextOptions with Playwright's BrowserContextOptions and add proper types for storage state in recreateContext(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c8c2cbb commit 1a100a2

3 files changed

Lines changed: 17 additions & 38 deletions

File tree

browse/src/browser-manager.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* restores state. Falls back to clean slate on any failure.
1616
*/
1717

18-
import { chromium, type Browser, type BrowserContext, type Page, type Locator } from 'playwright';
18+
import { chromium, type Browser, type BrowserContext, type BrowserContextOptions, type Page, type Locator } from 'playwright';
1919
import { addConsoleEntry, addNetworkEntry, addDialogEntry, networkBuffer, type DialogEntry } from './buffers';
2020

2121
export interface RefEntry {
@@ -57,7 +57,7 @@ export class BrowserManager {
5757
process.exit(1);
5858
});
5959

60-
const contextOptions: any = {
60+
const contextOptions: BrowserContextOptions = {
6161
viewport: { width: 1280, height: 720 },
6262
};
6363
if (this.customUserAgent) {
@@ -282,7 +282,7 @@ export class BrowserManager {
282282
try {
283283
// 1. Save state from current context
284284
const savedCookies = await this.context.cookies();
285-
const savedPages: Array<{ url: string; isActive: boolean; storage: any }> = [];
285+
const savedPages: Array<{ url: string; isActive: boolean; storage: { localStorage: Record<string, string>; sessionStorage: Record<string, string> } | null }> = [];
286286

287287
for (const [id, page] of this.pages) {
288288
const url = page.url();
@@ -308,7 +308,7 @@ export class BrowserManager {
308308
await this.context.close().catch(() => {});
309309

310310
// 3. Create new context with updated settings
311-
const contextOptions: any = {
311+
const contextOptions: BrowserContextOptions = {
312312
viewport: { width: 1280, height: 720 },
313313
};
314314
if (this.customUserAgent) {
@@ -340,15 +340,15 @@ export class BrowserManager {
340340
// 6. Restore storage
341341
if (saved.storage) {
342342
try {
343-
await page.evaluate((s: any) => {
343+
await page.evaluate((s: { localStorage: Record<string, string>; sessionStorage: Record<string, string> }) => {
344344
if (s.localStorage) {
345345
for (const [k, v] of Object.entries(s.localStorage)) {
346-
localStorage.setItem(k, v as string);
346+
localStorage.setItem(k, v);
347347
}
348348
}
349349
if (s.sessionStorage) {
350350
for (const [k, v] of Object.entries(s.sessionStorage)) {
351-
sessionStorage.setItem(k, v as string);
351+
sessionStorage.setItem(k, v);
352352
}
353353
}
354354
}, saved.storage);
@@ -369,13 +369,13 @@ export class BrowserManager {
369369
this.clearRefs();
370370

371371
return null; // success
372-
} catch (err: any) {
372+
} catch (err: unknown) {
373373
// Fallback: create a clean context + blank tab
374374
try {
375375
this.pages.clear();
376376
if (this.context) await this.context.close().catch(() => {});
377377

378-
const contextOptions: any = {
378+
const contextOptions: BrowserContextOptions = {
379379
viewport: { width: 1280, height: 720 },
380380
};
381381
if (this.customUserAgent) {
@@ -387,7 +387,7 @@ export class BrowserManager {
387387
} catch {
388388
// If even the fallback fails, we're in trouble — but browser is still alive
389389
}
390-
return `Context recreation failed: ${err.message}. Browser reset to blank tab.`;
390+
return `Context recreation failed: ${err instanceof Error ? err.message : String(err)}. Browser reset to blank tab.`;
391391
}
392392
}
393393

browse/src/meta-commands.ts

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import type { BrowserManager } from './browser-manager';
66
import { handleSnapshot } from './snapshot';
77
import { getCleanText } from './read-commands';
8+
import { READ_COMMANDS, WRITE_COMMANDS, META_COMMANDS } from './commands';
89
import * as Diff from 'diff';
910
import * as fs from 'fs';
1011
import * as path from 'path';
@@ -20,28 +21,6 @@ function validateOutputPath(filePath: string): void {
2021
}
2122
}
2223

23-
// Command sets for chain routing (mirrors server.ts — kept local to avoid circular import)
24-
const CHAIN_READ = new Set([
25-
'text', 'html', 'links', 'forms', 'accessibility',
26-
'js', 'eval', 'css', 'attrs',
27-
'console', 'network', 'cookies', 'storage', 'perf',
28-
'dialog', 'is',
29-
]);
30-
const CHAIN_WRITE = new Set([
31-
'goto', 'back', 'forward', 'reload',
32-
'click', 'fill', 'select', 'hover', 'type', 'press', 'scroll', 'wait',
33-
'viewport', 'cookie', 'cookie-import', 'header', 'useragent',
34-
'upload', 'dialog-accept', 'dialog-dismiss',
35-
'cookie-import-browser',
36-
]);
37-
const CHAIN_META = new Set([
38-
'tabs', 'tab', 'newtab', 'closetab',
39-
'status', 'stop', 'restart',
40-
'screenshot', 'pdf', 'responsive',
41-
'chain', 'diff',
42-
'url', 'snapshot',
43-
]);
44-
4524
export async function handleMetaCommand(
4625
command: string,
4726
args: string[],
@@ -223,9 +202,9 @@ export async function handleMetaCommand(
223202
const [name, ...cmdArgs] = cmd;
224203
try {
225204
let result: string;
226-
if (CHAIN_WRITE.has(name)) result = await handleWriteCommand(name, cmdArgs, bm);
227-
else if (CHAIN_READ.has(name)) result = await handleReadCommand(name, cmdArgs, bm);
228-
else if (CHAIN_META.has(name)) result = await handleMetaCommand(name, cmdArgs, bm, shutdown);
205+
if (WRITE_COMMANDS.has(name)) result = await handleWriteCommand(name, cmdArgs, bm);
206+
else if (READ_COMMANDS.has(name)) result = await handleReadCommand(name, cmdArgs, bm);
207+
else if (META_COMMANDS.has(name)) result = await handleMetaCommand(name, cmdArgs, bm, shutdown);
229208
else throw new Error(`Unknown command: ${name}`);
230209
results.push(`[${name}] ${result}`);
231210
} catch (err: any) {

browse/src/server.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ async function flushBuffers() {
104104
const lines = entries.map(e =>
105105
`[${new Date(e.timestamp).toISOString()}] [${e.level}] ${e.text}`
106106
).join('\n') + '\n';
107-
await Bun.write(CONSOLE_LOG_PATH, (await Bun.file(CONSOLE_LOG_PATH).text().catch(() => '')) + lines);
107+
fs.appendFileSync(CONSOLE_LOG_PATH, lines);
108108
lastConsoleFlushed = consoleBuffer.totalAdded;
109109
}
110110

@@ -115,7 +115,7 @@ async function flushBuffers() {
115115
const lines = entries.map(e =>
116116
`[${new Date(e.timestamp).toISOString()}] ${e.method} ${e.url}${e.status || 'pending'} (${e.duration || '?'}ms, ${e.size || '?'}B)`
117117
).join('\n') + '\n';
118-
await Bun.write(NETWORK_LOG_PATH, (await Bun.file(NETWORK_LOG_PATH).text().catch(() => '')) + lines);
118+
fs.appendFileSync(NETWORK_LOG_PATH, lines);
119119
lastNetworkFlushed = networkBuffer.totalAdded;
120120
}
121121

@@ -126,7 +126,7 @@ async function flushBuffers() {
126126
const lines = entries.map(e =>
127127
`[${new Date(e.timestamp).toISOString()}] [${e.type}] "${e.message}" → ${e.action}${e.response ? ` "${e.response}"` : ''}`
128128
).join('\n') + '\n';
129-
await Bun.write(DIALOG_LOG_PATH, (await Bun.file(DIALOG_LOG_PATH).text().catch(() => '')) + lines);
129+
fs.appendFileSync(DIALOG_LOG_PATH, lines);
130130
lastDialogFlushed = dialogBuffer.totalAdded;
131131
}
132132
} catch {

0 commit comments

Comments
 (0)