Files
elizaos--eliza/scripts/view-audit/web-crawler.mjs
T
wehub-resource-sync 426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

172 lines
6.2 KiB
JavaScript

/**
* Playwright web view crawler — drives a headless Chromium against the local dev
* server (UI :2138) through every route, capturing the same per-view signals as
* the CDP crawler: console errors, page errors, network 4xx/5xx, render-state
* (error boundary / no-agent / 404 / empty), interactive-element inventory, shot.
*
* Usage: bun web-crawler.mjs --url http://127.0.0.1:2138 --out <dir>
*/
import { appendFileSync, mkdirSync, writeFileSync } from "node:fs";
import { chromium } from "@playwright/test";
import { ROUTES } from "./routes.mjs";
const args = Object.fromEntries(
process.argv.slice(2).reduce((a, v, i, arr) => {
if (v.startsWith("--")) a.push([v.slice(2), arr[i + 1]]);
return a;
}, []),
);
const BASE = args.url || "http://127.0.0.1:2138";
const OUT = args.out || "/tmp/view-audit/web";
mkdirSync(OUT, { recursive: true });
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const SNAP = `(()=>{
const t=document.body?document.body.innerText:"";
const low=t.toLowerCase();
const sig={
errorBoundary: /something went wrong|failed to load|is not a function|cannot read prop|unexpected token|chunkloaderror/i.test(t),
noAgent: /no agent (is )?(configured|available)|agent is not|no agent connected|not configured/i.test(t),
notFound: /\\b404\\b|not found|couldn'?t reach|unavailable|markets unavailable|reads blocked/i.test(low),
offline: /\\boffline\\b|disconnected|not connected/i.test(low),
emptyish: t.replace(/\\s+/g," ").trim().length < 40,
};
const q=(sel)=>[...document.querySelectorAll(sel)];
const label=(el)=>((el.getAttribute&&(el.getAttribute("aria-label")||el.getAttribute("title")))||el.textContent||el.value||el.placeholder||"").replace(/\\s+/g," ").trim().slice(0,40);
const buttons=q('button,[role="button"]').map(e=>({l:label(e),d:!!e.disabled||e.getAttribute("aria-disabled")==="true"}));
const inputs=q('input,textarea,select').map(e=>({l:label(e),type:e.type||e.tagName.toLowerCase(),d:!!e.disabled}));
const links=q('a[href]').length;
return {len:t.replace(/\\s+/g," ").trim().length, sig, snip:t.replace(/\\s+/g," ").trim().slice(0,140), buttons, inputs, links, path:location.pathname+location.hash};
})()`;
async function main() {
const browser = await chromium.launch({ headless: true });
const ctx = await browser.newContext({
viewport: { width: 1280, height: 900 },
ignoreHTTPSErrors: true,
});
const page = await ctx.newPage();
// Prime auth: force local dev agent active-server so the renderer skips
// onboarding and reaches the dashboard (mirrors the dev renderer default).
await page.addInitScript(() => {
try {
const local = JSON.stringify({
id: "local:dev",
kind: "remote",
label: "Local dev agent",
apiBase: "http://127.0.0.1:31337",
});
localStorage.setItem("elizaos:active-server", local);
localStorage.setItem("eliza:first-run-complete", "1");
localStorage.setItem("eliza:mobile-runtime-mode", "local");
} catch {}
});
await page
.goto(BASE, { waitUntil: "domcontentloaded", timeout: 30000 })
.catch(() => {});
await sleep(4000);
const findings = [];
for (const [route, slug] of ROUTES) {
const consoleErrors = [];
const pageErrors = [];
const netFailures = [];
const onConsole = (m) => {
if (["error", "warning"].includes(m.type())) {
const txt = m.text().slice(0, 300);
if (txt.trim() && !/favicon|DevTools/.test(txt))
consoleErrors.push(`[${m.type()}] ${txt}`);
}
};
const onPageErr = (e) =>
pageErrors.push(String(e.message || e).slice(0, 300));
const onResp = (r) => {
const s = r.status();
if (s >= 400)
netFailures.push(
`${s} ${r
.url()
.replace(/^https?:\/\/[^/]+/, "")
.slice(0, 120)}`,
);
};
page.on("console", onConsole);
page.on("pageerror", onPageErr);
page.on("response", onResp);
await page
.evaluate((u) => {
history.pushState(null, "", u);
window.dispatchEvent(new PopStateEvent("popstate"));
if (u.includes("#"))
window.dispatchEvent(new HashChangeEvent("hashchange"));
}, route)
.catch(() => {});
await sleep(2600);
let parsed = {};
try {
parsed = await page.evaluate(SNAP);
} catch (e) {
parsed = { __err: String(e.message).slice(0, 80) };
}
let shot = null;
try {
shot = `${slug}.png`;
await page.screenshot({ path: `${OUT}/${shot}` });
} catch {
shot = null;
}
page.off("console", onConsole);
page.off("pageerror", onPageErr);
page.off("response", onResp);
const f = {
route,
slug,
landedPath: parsed.path,
bodyLen: parsed.len,
snippet: parsed.snip,
signals: parsed.sig || {},
pageErrors: [...new Set(pageErrors)],
consoleErrors: [...new Set(consoleErrors)].slice(0, 12),
netFailures: [...new Set(netFailures)].slice(0, 12),
buttons: parsed.buttons || [],
inputs: parsed.inputs || [],
links: parsed.links || 0,
screenshot: shot,
};
findings.push(f);
const flags = [];
if (f.signals.errorBoundary) flags.push("ERR-BOUNDARY");
if (f.pageErrors.length) flags.push(`${f.pageErrors.length}pageerr`);
if (f.signals.noAgent) flags.push("NO-AGENT");
if (f.signals.notFound) flags.push("404/unavail");
if (f.netFailures.length) flags.push(`${f.netFailures.length}net4xx`);
if (f.signals.emptyish) flags.push("EMPTY");
const line = `${slug.padEnd(24)} land=${(f.landedPath || "?").padEnd(20)} len=${String(f.bodyLen).padStart(5)} btn=${String(f.buttons.length).padStart(2)} inp=${String(f.inputs.length).padStart(2)} ${flags.join(" ") || "ok"}`;
console.error(line);
appendFileSync(`${OUT}/progress.log`, line + "\n");
writeFileSync(
`${OUT}/report-web.json`,
JSON.stringify(
{ surface: "web", count: findings.length, findings },
null,
2,
),
);
}
await browser.close();
console.error(`\nWROTE ${OUT}/report-web.json (${findings.length})`);
}
main().then(
() => process.exit(0),
(e) => {
console.error("WEB CRAWLER ERR:", e.message);
process.exit(1);
},
);