Files
vibn-agent-runner/vibn-frontend/app/api/mcp/browser.ts

121 lines
3.6 KiB
TypeScript

import { NextResponse } from "next/server";
import { execInDevContainer } from "@/lib/dev-container";
/**
* Executes a simple Playwright script inside the dev container to extract browser console logs.
*/
export async function toolBrowserConsole(projectId: string, url: string) {
const script = `
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
const errors = [];
page.on('console', msg => {
if (msg.type() === 'error') {
errors.push(msg.text());
}
});
page.on('pageerror', err => {
errors.push(err.message);
});
try {
await page.goto('${url}', { waitUntil: 'networkidle', timeout: 15000 });
console.log(JSON.stringify({ ok: true, errors }));
} catch (err) {
console.log(JSON.stringify({ ok: false, error: err.message, errors }));
} finally {
await browser.close();
}
})();
`;
// We need to ensure playwright is installed and the browsers are downloaded.
const setupCmd = `if [ ! -d "node_modules/playwright" ]; then npm install --no-save playwright && npx playwright install chromium; fi && node -e "${script.replace(/"/g, '\\"').replace(/\$/g, '\\$')}"`;
try {
const res = await execInDevContainer({
projectId,
command: setupCmd,
timeoutMs: 60000, // 60s since downloading chromium takes a moment on first run
});
if (res.code !== 0) {
return NextResponse.json({ error: "Failed to run browser test", details: res.stderr }, { status: 500 });
}
const lines = res.stdout.trim().split('\n');
const jsonLine = lines[lines.length - 1];
let result;
try {
result = JSON.parse(jsonLine);
} catch {
result = { ok: false, error: "Could not parse browser output", raw: res.stdout };
}
return NextResponse.json({ result });
} catch (e) {
return NextResponse.json({ error: e instanceof Error ? e.message : String(e) }, { status: 500 });
}
}
/**
* Executes a simple Playwright script inside the dev container to extract the page title and status code.
*/
export async function toolBrowserNavigate(projectId: string, url: string) {
const script = `
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
try {
const response = await page.goto('${url}', { waitUntil: 'domcontentloaded', timeout: 15000 });
const title = await page.title();
console.log(JSON.stringify({ ok: true, status: response ? response.status() : null, title }));
} catch (err) {
console.log(JSON.stringify({ ok: false, error: err.message }));
} finally {
await browser.close();
}
})();
`;
const setupCmd = `if [ ! -d "node_modules/playwright" ]; then npm install --no-save playwright && npx playwright install chromium; fi && node -e "\${script.replace(/\\"/g, '\\\\\"').replace(/\\$/g, '\\\\$')}"`;
try {
const res = await execInDevContainer({
projectId,
command: setupCmd,
timeoutMs: 60000,
});
if (res.code !== 0) {
return NextResponse.json({ error: "Failed to navigate", details: res.stderr }, { status: 500 });
}
const lines = res.stdout.trim().split('\n');
const jsonLine = lines[lines.length - 1];
let result;
try {
result = JSON.parse(jsonLine);
} catch {
result = { ok: false, error: "Could not parse browser output", raw: res.stdout };
}
return NextResponse.json({ result });
} catch (e) {
return NextResponse.json({ error: e instanceof Error ? e.message : String(e) }, { status: 500 });
}
}