diff --git a/bun.lock b/bun.lock index 36a36b3..52eeffd 100644 --- a/bun.lock +++ b/bun.lock @@ -10,6 +10,7 @@ "devDependencies": { "@types/bun": "latest", "esbuild": "^0.25.12", + "typescript": "^5.9.3", }, }, }, @@ -212,6 +213,8 @@ "typed-query-selector": ["typed-query-selector@2.12.0", "", {}, "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "webdriver-bidi-protocol": ["webdriver-bidi-protocol@0.4.1", "", {}, "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw=="], diff --git a/package.json b/package.json index 344e840..8884d89 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ }, "devDependencies": { "@types/bun": "latest", - "esbuild": "^0.25.12" + "esbuild": "^0.25.12", + "typescript": "^5.9.3" }, "engines": { "node": ">=18" diff --git a/src/commands/logs.ts b/src/commands/logs.ts new file mode 100644 index 0000000..048ba3b --- /dev/null +++ b/src/commands/logs.ts @@ -0,0 +1,61 @@ +import puppeteer, { type Page, type Protocol } from "puppeteer-core" +import { CDP_URL, VIEWPORT } from "../lib/config" +import type { Flags } from "../lib/flags" + +export const logs = async (_args: string[], flags: Flags) => { + const browser = await puppeteer.connect({ + browserURL: CDP_URL, + defaultViewport: VIEWPORT, + }) + + const setupPage = async (page: Page, index: number) => { + const client = await page.createCDPSession() + await client.send("Runtime.enable") + + client.on("Runtime.consoleAPICalled", (event: Protocol.Runtime.ConsoleAPICalledEvent) => { + const args = event.args + .map((a) => a.value !== undefined ? String(a.value) : a.description ?? "") + .join(" ") + + const time = new Date().toLocaleTimeString("en-US", { hour12: false }) + const type = event.type === "warning" ? "warn" : event.type + + if (flags.json) { + console.log(JSON.stringify({ tab: index, type, time, message: args })) + } else { + const prefix = index > 0 ? `[${index}] ` : "" + console.log(`${prefix}[${time}] ${type}: ${args}`) + } + }) + } + + // Setup existing pages + const pages = await browser.pages() + for (let i = 0; i < pages.length; i++) { + await setupPage(pages[i]!, i) + } + + // Listen for new pages + browser.on("targetcreated", async (target) => { + if (target.type() === "page") { + const page = await target.page() + if (page) { + const allPages = await browser.pages() + const index = allPages.indexOf(page) + await setupPage(page, index) + } + } + }) + + console.error("Watching console logs... (Ctrl+C to stop)\n") + + // Keep alive until Ctrl+C + await new Promise((resolve) => { + process.on("SIGINT", () => { + console.error("\nStopped") + resolve() + }) + }) + + await browser.disconnect() +} diff --git a/src/index.ts b/src/index.ts index fc73e17..b770197 100755 --- a/src/index.ts +++ b/src/index.ts @@ -17,8 +17,9 @@ import { js } from "./commands/js" import { wait } from "./commands/wait" import { audit } from "./commands/audit" import { tab } from "./commands/tab" +import { logs } from "./commands/logs" -const commands = { go, url, back, forward, shot, snap, text, click, type, fill, key, move, drag, scroll, js, wait, audit, tab } +const commands = { go, url, back, forward, shot, snap, text, click, type, fill, key, move, drag, scroll, js, wait, audit, tab, logs } const help = `mb — Browser CLI for Agents @@ -48,6 +49,7 @@ Other: js Run JavaScript wait Wait for ms/selector/networkidle/url:... audit Design audit (colors, fonts, spacing, contrast) + logs Stream console logs (Ctrl+C to stop) Tabs: tab list List open tabs