Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 17:55:23 +08:00
commit ff43aa6f4d
42 changed files with 4239 additions and 0 deletions

View File

@@ -0,0 +1,175 @@
#!/usr/bin/env node
/**
* browser-console.js - Get console messages from page
*
* Usage:
* ./browser-console.js # Get all console messages
* ./browser-console.js --errors # Only errors
* ./browser-console.js --warnings # Errors and warnings
* ./browser-console.js --watch # Watch for new messages
*/
import puppeteer from "puppeteer-core";
const args = process.argv.slice(2);
const errorsOnly = args.includes("--errors");
const warningsPlus = args.includes("--warnings");
const watch = args.includes("--watch");
const port = args.find(a => a.startsWith("--port="))?.split("=")[1] || "9222";
if (args.includes("--help") || args.includes("-h")) {
console.log(`
browser-console.js - Capture console messages
Usage:
./browser-console.js [options]
Options:
--errors Show only errors
--warnings Show errors and warnings
--watch Watch for new messages in real-time
--port=PORT Connect to custom debug port (default: 9222)
Message Types:
[ERR] - console.error, exceptions
[WARN] - console.warn
[LOG] - console.log
[INFO] - console.info
[DBG] - console.debug
Examples:
./browser-console.js
./browser-console.js --errors
./browser-console.js --watch
`);
process.exit(0);
}
try {
const browser = await puppeteer.connect({
browserURL: `http://localhost:${port}`,
defaultViewport: null
});
const pages = await browser.pages();
const page = pages[pages.length - 1];
if (!page) {
console.error("✗ No active tab found");
process.exit(1);
}
if (watch) {
console.log("Watching console... (Ctrl+C to stop)\n");
const shouldShow = (type) => {
if (errorsOnly) return type === "error";
if (warningsPlus) return type === "error" || type === "warning";
return true;
};
const typeLabels = {
error: "[ERR] ",
warning: "[WARN]",
log: "[LOG] ",
info: "[INFO]",
debug: "[DBG] "
};
page.on("console", msg => {
const type = msg.type();
if (shouldShow(type)) {
const label = typeLabels[type] || `[${type.toUpperCase()}]`;
const text = msg.text();
console.log(`${label} ${text}`);
}
});
page.on("pageerror", err => {
console.log(`[ERR] Uncaught: ${err.message}`);
});
// Keep alive
await new Promise(() => {});
} else {
// Get existing console messages by injecting capture
const messages = await page.evaluate(() => {
// Return any cached messages if we have them
return window.__consoleMessages || [];
});
// Also get any runtime exceptions
const client = await page.target().createCDPSession();
await client.send("Runtime.enable");
// Collect current console messages by re-evaluating with capture
const capturedMessages = await page.evaluate(() => {
const msgs = [];
const originalConsole = {
log: console.log,
error: console.error,
warn: console.warn,
info: console.info,
debug: console.debug
};
// This is for future messages - we can't capture past ones without this being set up earlier
// So we'll note that limitation
return msgs;
});
// Get recent exceptions from CDP
const { result } = await client.send("Runtime.evaluate", {
expression: `
(function() {
// Check for any unhandled errors stored in window
const errors = window.__webdebugErrors || [];
return errors;
})()
`,
returnByValue: true
});
if (messages.length === 0 && (!result.value || result.value.length === 0)) {
console.log("No console messages captured.");
console.log("\nTip: Use --watch to capture messages in real-time, or inject capture script:");
console.log(' ./browser-eval.js "window.__consoleMessages=[];[\'log\',\'error\',\'warn\',\'info\'].forEach(t=>{const o=console[t];console[t]=(...a)=>{window.__consoleMessages.push({type:t,text:a.join(\' \'),time:Date.now()});o.apply(console,a)}});"');
} else {
const allMessages = [...messages, ...(result.value || [])];
const typeLabels = {
error: "[ERR] ",
warning: "[WARN]",
warn: "[WARN]",
log: "[LOG] ",
info: "[INFO]",
debug: "[DBG] "
};
allMessages.forEach(msg => {
const type = msg.type || "log";
const shouldShow = () => {
if (errorsOnly) return type === "error";
if (warningsPlus) return type === "error" || type === "warning" || type === "warn";
return true;
};
if (shouldShow()) {
const label = typeLabels[type] || `[${type.toUpperCase()}]`;
console.log(`${label} ${msg.text || msg.message || JSON.stringify(msg)}`);
}
});
}
}
if (!watch) {
await browser.disconnect();
}
} catch (e) {
if (e.message?.includes("ECONNREFUSED")) {
console.error("✗ Cannot connect to browser. Run: ./browser-start.js");
} else {
console.error(`✗ Console capture failed: ${e.message}`);
}
process.exit(1);
}