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
172 lines
6.2 KiB
JavaScript
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);
|
|
},
|
|
);
|