💬 Commit message: Update 2026-02-11 04:13:54, 13 files, 595 lines

📁 Files changed: 13
📝 Lines changed: 595

  • PLAN.md
  • TODO.md
  • browser.d.ts
  • browser.d.ts.map
  • browser.js
  • browser.js.map
  • mcp.js
  • mcp.js.map
  • types.d.ts
  • types.d.ts.map
  • browser.ts
  • mcp.ts
  • types.ts
This commit is contained in:
Adam Ladachowski
2026-02-11 04:13:54 +01:00
parent dd26376833
commit 5a7466b67d
13 changed files with 421 additions and 218 deletions
+41 -1
View File
@@ -1,13 +1,20 @@
import { resolve } from 'node:path';
import { type Browser, type BrowserContext, type Page, webkit } from 'playwright';
import * as image from './image.js';
import type { BrowserCommand, BrowserOptions, CommandResponse, ElementInfo } from './types.js';
import type {
BrowserCommand,
BrowserOptions,
CommandResponse,
ConsoleMessage,
ElementInfo,
} from './types.js';
export class ClaudeBrowser {
private browser: Browser | null = null;
private context: BrowserContext | null = null;
private page: Page | null = null;
private options: Required<BrowserOptions>;
private consoleMessages: ConsoleMessage[] = [];
constructor(options: BrowserOptions = {}) {
this.options = {
@@ -26,6 +33,19 @@ export class ClaudeBrowser {
},
});
this.page = await this.context.newPage();
this.setupConsoleListener(this.page);
}
private setupConsoleListener(page: Page): void {
page.on('console', (msg) => {
const location = msg.location();
this.consoleMessages.push({
level: msg.type(),
text: msg.text(),
timestamp: Date.now(),
location: location.url ? `${location.url}:${location.lineNumber}` : undefined,
});
});
}
async close(): Promise<void> {
@@ -135,6 +155,7 @@ export class ClaudeBrowser {
throw new Error('Browser not launched. Call launch() first.');
}
this.page = await this.context.newPage();
this.setupConsoleListener(this.page);
}
async eval(script: string): Promise<unknown> {
@@ -142,6 +163,21 @@ export class ClaudeBrowser {
return page.evaluate(script);
}
getConsole(level?: string, clear = false): ConsoleMessage[] {
let messages = this.consoleMessages;
if (level && level !== 'all') {
messages = messages.filter((m) => m.level === level);
}
if (clear) {
this.consoleMessages = [];
}
return messages;
}
clearConsole(): void {
this.consoleMessages = [];
}
async executeCommand(cmd: BrowserCommand): Promise<CommandResponse> {
try {
switch (cmd.cmd) {
@@ -201,6 +237,10 @@ export class ClaudeBrowser {
const result = await this.eval(cmd.script);
return { ok: true, result };
}
case 'console': {
const messages = this.getConsole(cmd.level, cmd.clear);
return { ok: true, count: messages.length, messages };
}
case 'favicon': {
const result = await image.createFavicon(cmd.input, cmd.outputDir);
return { ok: true, files: result.files, outputDir: result.outputDir };
+49
View File
@@ -183,6 +183,25 @@ server.tool(
})
);
// Console
server.tool(
'console',
'Get captured console messages (log, warn, error, etc.) from the browser',
{
level: z
.enum(['log', 'info', 'warn', 'error', 'debug', 'all'])
.optional()
.default('all')
.describe('Filter by log level'),
clear: z.boolean().optional().default(false).describe('Clear messages after retrieving'),
},
withLogging('console', async ({ level, clear }) => {
await ensureLaunched();
const messages = browser.getConsole(level, clear);
return textResult(JSON.stringify({ ok: true, count: messages.length, messages }));
})
);
// Utility
server.tool(
'wait',
@@ -512,6 +531,36 @@ server.resource(
}
);
// Resource: browser://console - Captured console messages
server.resource(
'Console Messages',
'browser://console',
{ description: 'Console messages captured from the browser', mimeType: 'application/json' },
async () => {
if (!launched) {
return {
contents: [
{
uri: 'browser://console',
mimeType: 'application/json',
text: JSON.stringify({ launched: false, messages: [] }),
},
],
};
}
const messages = browser.getConsole('all', false);
return {
contents: [
{
uri: 'browser://console',
mimeType: 'application/json',
text: JSON.stringify({ launched: true, count: messages.length, messages }),
},
],
};
}
);
// Resource: browser://screenshot - Current page screenshot (base64)
server.resource(
'Page Screenshot',
+17 -1
View File
@@ -124,6 +124,19 @@ export interface ThumbnailCommand {
size?: 'small' | 'medium' | 'large';
}
export interface ConsoleCommand {
cmd: 'console';
clear?: boolean;
level?: 'log' | 'info' | 'warn' | 'error' | 'debug' | 'all';
}
export interface ConsoleMessage {
level: string;
text: string;
timestamp: number;
location?: string;
}
export type BrowserCommand =
| GotoCommand
| ClickCommand
@@ -144,7 +157,8 @@ export type BrowserCommand =
| ResizeCommand
| CropCommand
| CompressCommand
| ThumbnailCommand;
| ThumbnailCommand
| ConsoleCommand;
// Response types
export interface SuccessResponse {
@@ -163,6 +177,8 @@ export interface SuccessResponse {
height?: number;
format?: string;
size?: number;
// Console fields
messages?: ConsoleMessage[];
}
export interface ErrorResponse {