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>
This commit is contained in:
xianren
2026-03-17 22:05:02 +08:00
parent c8c2cbba33
commit 1a100a2a23
3 changed files with 17 additions and 38 deletions
+10 -10
View File
@@ -15,7 +15,7 @@
* restores state. Falls back to clean slate on any failure.
*/
import { chromium, type Browser, type BrowserContext, type Page, type Locator } from 'playwright';
import { chromium, type Browser, type BrowserContext, type BrowserContextOptions, type Page, type Locator } from 'playwright';
import { addConsoleEntry, addNetworkEntry, addDialogEntry, networkBuffer, type DialogEntry } from './buffers';
export interface RefEntry {
@@ -57,7 +57,7 @@ export class BrowserManager {
process.exit(1);
});
const contextOptions: any = {
const contextOptions: BrowserContextOptions = {
viewport: { width: 1280, height: 720 },
};
if (this.customUserAgent) {
@@ -282,7 +282,7 @@ export class BrowserManager {
try {
// 1. Save state from current context
const savedCookies = await this.context.cookies();
const savedPages: Array<{ url: string; isActive: boolean; storage: any }> = [];
const savedPages: Array<{ url: string; isActive: boolean; storage: { localStorage: Record<string, string>; sessionStorage: Record<string, string> } | null }> = [];
for (const [id, page] of this.pages) {
const url = page.url();
@@ -308,7 +308,7 @@ export class BrowserManager {
await this.context.close().catch(() => {});
// 3. Create new context with updated settings
const contextOptions: any = {
const contextOptions: BrowserContextOptions = {
viewport: { width: 1280, height: 720 },
};
if (this.customUserAgent) {
@@ -340,15 +340,15 @@ export class BrowserManager {
// 6. Restore storage
if (saved.storage) {
try {
await page.evaluate((s: any) => {
await page.evaluate((s: { localStorage: Record<string, string>; sessionStorage: Record<string, string> }) => {
if (s.localStorage) {
for (const [k, v] of Object.entries(s.localStorage)) {
localStorage.setItem(k, v as string);
localStorage.setItem(k, v);
}
}
if (s.sessionStorage) {
for (const [k, v] of Object.entries(s.sessionStorage)) {
sessionStorage.setItem(k, v as string);
sessionStorage.setItem(k, v);
}
}
}, saved.storage);
@@ -369,13 +369,13 @@ export class BrowserManager {
this.clearRefs();
return null; // success
} catch (err: any) {
} catch (err: unknown) {
// Fallback: create a clean context + blank tab
try {
this.pages.clear();
if (this.context) await this.context.close().catch(() => {});
const contextOptions: any = {
const contextOptions: BrowserContextOptions = {
viewport: { width: 1280, height: 720 },
};
if (this.customUserAgent) {
@@ -387,7 +387,7 @@ export class BrowserManager {
} catch {
// If even the fallback fails, we're in trouble — but browser is still alive
}
return `Context recreation failed: ${err.message}. Browser reset to blank tab.`;
return `Context recreation failed: ${err instanceof Error ? err.message : String(err)}. Browser reset to blank tab.`;
}
}