cbrowser 18.19.0 → 18.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/accessibility-empathy.d.ts.map +1 -1
- package/dist/analysis/accessibility-empathy.js +2 -1
- package/dist/analysis/accessibility-empathy.js.map +1 -1
- package/dist/analysis/agent-ready-audit.d.ts.map +1 -1
- package/dist/analysis/agent-ready-audit.js +2 -1
- package/dist/analysis/agent-ready-audit.js.map +1 -1
- package/dist/analysis/competitive-benchmark.d.ts.map +1 -1
- package/dist/analysis/competitive-benchmark.js +2 -1
- package/dist/analysis/competitive-benchmark.js.map +1 -1
- package/dist/browser.d.ts +20 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +98 -0
- package/dist/browser.js.map +1 -1
- package/dist/cli.js +243 -27
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lightpanda.d.ts +136 -0
- package/dist/lightpanda.d.ts.map +1 -0
- package/dist/lightpanda.js +293 -0
- package/dist/lightpanda.js.map +1 -0
- package/dist/remediation/llms-txt.d.ts.map +1 -1
- package/dist/remediation/llms-txt.js +2 -1
- package/dist/remediation/llms-txt.js.map +1 -1
- package/dist/remediation/structured-data.d.ts.map +1 -1
- package/dist/remediation/structured-data.js +2 -1
- package/dist/remediation/structured-data.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { CBrowser } from "./browser.js";
|
|
13
13
|
// Analysis module imports
|
|
14
|
-
import { executeNaturalLanguage, executeNaturalLanguageScript, huntBugs, runChaosTest, comparePersonas, formatComparisonReport, findElementByIntent, runAgentReadyAudit, formatAgentReadyReport, generateAgentReadyHtmlReport, runCompetitiveBenchmark, formatCompetitiveBenchmarkReport, generateCompetitiveBenchmarkHtmlReport, runEmpathyAudit, formatEmpathyAuditReport, generateEmpathyAuditHtmlReport, runWebMCPReadyAudit, generateWebMCPReadyHtmlReport } from "./analysis/index.js";
|
|
14
|
+
import { executeNaturalLanguage, executeNaturalLanguageScript, huntBugs, runChaosTest, comparePersonas, formatComparisonReport, findElementByIntent, runAgentReadyAudit, formatAgentReadyReport, generateAgentReadyHtmlReport, runCompetitiveBenchmark, formatCompetitiveBenchmarkReport, generateCompetitiveBenchmarkHtmlReport, runEmpathyAudit, formatEmpathyAuditReport, generateEmpathyAuditHtmlReport, runWebMCPReadyAudit, generateWebMCPReadyHtmlReport, runAIReadinessBenchmark } from "./analysis/index.js";
|
|
15
15
|
// Testing module imports
|
|
16
16
|
import { parseNLInstruction, parseNLTestSuite, runNLTestSuite, formatNLTestReport, dryRunNLTestSuite, repairTestSuite, formatRepairReport, exportRepairedTest, detectFlakyTests, formatFlakyTestReport, generateCoverageMap, formatCoverageReport, generateCoverageHtmlReport } from "./testing/index.js";
|
|
17
17
|
// Performance module imports
|
|
@@ -26,6 +26,8 @@ import { startDaemon, stopDaemon, getDaemonStatus, isDaemonRunning, sendToDaemon
|
|
|
26
26
|
import { getStatusInfo, formatStatus, getDataDir } from "./config.js";
|
|
27
27
|
import { printEnterpriseStatus } from "./stealth/index.js";
|
|
28
28
|
import { runCognitiveJourney, getAnthropicApiKey, setAnthropicApiKey, removeAnthropicApiKey, isApiKeyConfigured, } from "./cognitive/index.js";
|
|
29
|
+
// Lightpanda integration (v18.19.0)
|
|
30
|
+
import { getLightpandaStatus, LIGHTPANDA_SETUP_GUIDE, } from "./lightpanda.js";
|
|
29
31
|
// Version from package.json - single source of truth
|
|
30
32
|
import { VERSION } from "./version.js";
|
|
31
33
|
// Node readline for interactive input
|
|
@@ -403,60 +405,77 @@ A/B VISUAL COMPARISON (v7.3.0)
|
|
|
403
405
|
"options": { "sensitivity": "medium" }
|
|
404
406
|
}
|
|
405
407
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
--url <url> Navigate to URL first
|
|
409
|
-
a11y audit [url] Audit a specific URL
|
|
408
|
+
AI FRIENDLINESS - Audit sites for AI agent compatibility
|
|
409
|
+
══════════════════════════════════════════════════════════════════════════════
|
|
410
410
|
|
|
411
|
-
|
|
412
|
-
|
|
411
|
+
agent-ready-audit <url> Audit site for AI-agent friendliness (A-F grade)
|
|
412
|
+
--headless Run in headless mode (default: true)
|
|
413
413
|
--output <file> Save JSON report to file
|
|
414
414
|
--html Generate HTML report
|
|
415
|
+
Grades sites on: Findability (35%), Stability (30%),
|
|
416
|
+
Accessibility (20%), Semantics (15%)
|
|
415
417
|
Examples:
|
|
416
418
|
cbrowser agent-ready-audit "https://example.com"
|
|
417
419
|
cbrowser agent-ready-audit "https://example.com" --html --output report.json
|
|
418
420
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
--sites <list> Comma-separated site URLs (required)
|
|
422
|
-
--goal <goal> Task goal (required)
|
|
423
|
-
--persona <name> Persona to use (default: first-timer)
|
|
424
|
-
--max-steps <n> Max steps per site (default: 30)
|
|
425
|
-
--max-time <sec> Max time per site in seconds (default: 180)
|
|
421
|
+
ai-benchmark Compare AI-friendliness across multiple sites
|
|
422
|
+
--urls <list> Comma-separated URLs to benchmark (required)
|
|
426
423
|
--output <file> Save JSON report to file
|
|
427
424
|
--html Generate HTML report
|
|
425
|
+
Runs agent-ready-audit on each URL and produces ranked comparison.
|
|
428
426
|
Examples:
|
|
429
|
-
cbrowser
|
|
430
|
-
|
|
431
|
-
--goal "sign up for free trial" \\
|
|
432
|
-
--html
|
|
427
|
+
cbrowser ai-benchmark --urls "https://site1.com,https://site2.com,https://site3.com"
|
|
428
|
+
cbrowser ai-benchmark --urls "https://amazon.com,https://ebay.com" --html
|
|
433
429
|
|
|
434
|
-
ACCESSIBILITY EMPATHY AUDIT (v8.0.0)
|
|
435
430
|
empathy-audit <url> Simulate disability experience on site
|
|
436
431
|
--goal <goal> Task goal (required)
|
|
437
|
-
--
|
|
432
|
+
--personas <list> Disability personas (comma-separated)
|
|
438
433
|
--wcag-level <level> WCAG level: A, AA, AAA (default: AA)
|
|
439
434
|
--output <file> Save JSON report to file
|
|
440
435
|
--html Generate HTML report
|
|
441
|
-
Available
|
|
436
|
+
Available personas:
|
|
442
437
|
motor-impairment-tremor, low-vision-magnified, cognitive-adhd,
|
|
443
438
|
dyslexic-user, deaf-user, elderly-low-vision, color-blind-deuteranopia
|
|
444
439
|
Examples:
|
|
445
440
|
cbrowser empathy-audit "https://example.com" \\
|
|
446
441
|
--goal "complete checkout" \\
|
|
447
|
-
--
|
|
448
|
-
--html
|
|
442
|
+
--personas "motor-impairment-tremor,cognitive-adhd" --html
|
|
449
443
|
|
|
450
|
-
|
|
451
|
-
webmcp-ready <url> Audit MCP server for Claude in Chrome compatibility
|
|
444
|
+
webmcp-ready <url> Audit MCP server for WebMCP compatibility
|
|
452
445
|
--api-key <key> API key for authenticated servers
|
|
453
446
|
--oauth-token <token> OAuth token for OAuth-protected servers
|
|
454
|
-
--timeout <ms> Request timeout
|
|
447
|
+
--timeout <ms> Request timeout (default: 30000)
|
|
455
448
|
--output <file> Save JSON report to file
|
|
456
449
|
--html Generate HTML report
|
|
450
|
+
6-tier evaluation: Server (25%), Tools (20%), Instrumentation (15%),
|
|
451
|
+
Consistency (15%), Agent Opts (15%), Docs (10%)
|
|
457
452
|
Examples:
|
|
458
453
|
cbrowser webmcp-ready "https://demo.cbrowser.ai/mcp"
|
|
459
|
-
cbrowser webmcp-ready "https://your-server.com/mcp" --api-key
|
|
454
|
+
cbrowser webmcp-ready "https://your-server.com/mcp" --api-key KEY --html
|
|
455
|
+
|
|
456
|
+
hunt-bugs <url> Automatically find UX bugs on a page
|
|
457
|
+
--max-pages <n> Max pages to crawl (default: 10)
|
|
458
|
+
--timeout <ms> Timeout in ms (default: 60000)
|
|
459
|
+
Examples:
|
|
460
|
+
cbrowser hunt-bugs "https://example.com"
|
|
461
|
+
|
|
462
|
+
competitive-benchmark Compare UX across competitor sites
|
|
463
|
+
--sites <list> Comma-separated site URLs (required)
|
|
464
|
+
--goal <goal> Task goal (required)
|
|
465
|
+
--persona <name> Persona to use (default: first-timer)
|
|
466
|
+
--max-steps <n> Max steps per site (default: 30)
|
|
467
|
+
--max-time <sec> Max time per site (default: 180)
|
|
468
|
+
--output <file> Save JSON report to file
|
|
469
|
+
--html Generate HTML report
|
|
470
|
+
Examples:
|
|
471
|
+
cbrowser competitive-benchmark \\
|
|
472
|
+
--sites "https://yoursite.com,https://competitor.com" \\
|
|
473
|
+
--goal "sign up for free trial" --html
|
|
474
|
+
|
|
475
|
+
ACCESSIBILITY (v2.5.0)
|
|
476
|
+
a11y audit Run WCAG accessibility audit
|
|
477
|
+
--url <url> Navigate to URL first
|
|
478
|
+
a11y audit [url] Audit a specific URL
|
|
460
479
|
|
|
461
480
|
TEST RECORDING (v2.5.0)
|
|
462
481
|
record start Start recording interactions
|
|
@@ -584,6 +603,18 @@ API CONFIGURATION (v8.0.0)
|
|
|
584
603
|
config remove-api-key Remove stored API key
|
|
585
604
|
config set-model <model> Set Claude model (default: claude-sonnet-4-20250514)
|
|
586
605
|
|
|
606
|
+
LIGHTPANDA (v18.19.0) - High-Performance Headless Browser
|
|
607
|
+
lightpanda-status Check Lightpanda availability and configuration
|
|
608
|
+
lightpanda-setup Show setup instructions for Lightpanda
|
|
609
|
+
Note: Lightpanda is 11x faster and uses 9x less memory than Chrome.
|
|
610
|
+
Set LIGHTPANDA_ENDPOINT or LIGHTPANDA_TOKEN to enable auto-use.
|
|
611
|
+
Environment Variables:
|
|
612
|
+
LIGHTPANDA_ENDPOINT WebSocket endpoint (e.g., ws://127.0.0.1:9222)
|
|
613
|
+
LIGHTPANDA_TOKEN Cloud API token (uses cloud.lightpanda.io)
|
|
614
|
+
Examples:
|
|
615
|
+
cbrowser lightpanda-status
|
|
616
|
+
LIGHTPANDA_ENDPOINT=ws://127.0.0.1:9222 cbrowser screenshot https://example.com
|
|
617
|
+
|
|
587
618
|
DIAGNOSTICS
|
|
588
619
|
version, -v, --version Show version number
|
|
589
620
|
status Show environment status and diagnostics
|
|
@@ -3760,6 +3791,47 @@ Documentation: https://github.com/alexandriashai/cbrowser/wiki
|
|
|
3760
3791
|
break;
|
|
3761
3792
|
}
|
|
3762
3793
|
// =========================================================================
|
|
3794
|
+
// Lightpanda Integration (v18.19.0)
|
|
3795
|
+
// =========================================================================
|
|
3796
|
+
case "lightpanda-status": {
|
|
3797
|
+
console.log("\n🐼 Lightpanda Status\n");
|
|
3798
|
+
const status = await getLightpandaStatus();
|
|
3799
|
+
if (!status.configured) {
|
|
3800
|
+
console.log("❌ Not configured");
|
|
3801
|
+
console.log("");
|
|
3802
|
+
console.log("To enable Lightpanda, set one of these environment variables:");
|
|
3803
|
+
console.log(" LIGHTPANDA_ENDPOINT=ws://127.0.0.1:9222 (local)");
|
|
3804
|
+
console.log(" LIGHTPANDA_TOKEN=your-api-token (cloud)");
|
|
3805
|
+
console.log("");
|
|
3806
|
+
console.log("Run 'cbrowser lightpanda-setup' for full setup instructions.");
|
|
3807
|
+
}
|
|
3808
|
+
else if (status.available) {
|
|
3809
|
+
console.log("✅ Available and connected");
|
|
3810
|
+
console.log(` Endpoint: ${status.endpoint}`);
|
|
3811
|
+
console.log(` Mode: ${status.isCloud ? "Cloud (lightpanda.io)" : "Local"}`);
|
|
3812
|
+
console.log("");
|
|
3813
|
+
console.log("Lightpanda will be used automatically for headless chromium operations.");
|
|
3814
|
+
}
|
|
3815
|
+
else {
|
|
3816
|
+
console.log("⚠️ Configured but unavailable");
|
|
3817
|
+
console.log(` Endpoint: ${status.endpoint}`);
|
|
3818
|
+
console.log(` Error: ${status.error}`);
|
|
3819
|
+
console.log("");
|
|
3820
|
+
if (!status.isCloud) {
|
|
3821
|
+
console.log("Make sure Lightpanda is running:");
|
|
3822
|
+
console.log(" docker run -d -p 9222:9222 lightpanda/browser:nightly");
|
|
3823
|
+
}
|
|
3824
|
+
else {
|
|
3825
|
+
console.log("Check your API token and network connection.");
|
|
3826
|
+
}
|
|
3827
|
+
}
|
|
3828
|
+
break;
|
|
3829
|
+
}
|
|
3830
|
+
case "lightpanda-setup": {
|
|
3831
|
+
console.log(LIGHTPANDA_SETUP_GUIDE);
|
|
3832
|
+
break;
|
|
3833
|
+
}
|
|
3834
|
+
// =========================================================================
|
|
3763
3835
|
// Natural Language Test Suites (Tier 6)
|
|
3764
3836
|
// =========================================================================
|
|
3765
3837
|
case "test-suite": {
|
|
@@ -4578,6 +4650,150 @@ Documentation: https://github.com/alexandriashai/cbrowser/wiki
|
|
|
4578
4650
|
}
|
|
4579
4651
|
break;
|
|
4580
4652
|
}
|
|
4653
|
+
case "ai-benchmark": {
|
|
4654
|
+
const urlsOption = options.urls;
|
|
4655
|
+
if (!urlsOption) {
|
|
4656
|
+
console.error("Error: --urls required");
|
|
4657
|
+
console.error("Usage: cbrowser ai-benchmark --urls <url1,url2,...> [--output <file>] [--html]");
|
|
4658
|
+
process.exit(1);
|
|
4659
|
+
}
|
|
4660
|
+
const urls = urlsOption.split(",").map(u => u.trim());
|
|
4661
|
+
if (urls.length < 2) {
|
|
4662
|
+
console.error("Error: At least 2 URLs required for benchmark comparison");
|
|
4663
|
+
process.exit(1);
|
|
4664
|
+
}
|
|
4665
|
+
console.log(`\n🏁 Running AI Readiness Benchmark on ${urls.length} sites...\n`);
|
|
4666
|
+
const result = await runAIReadinessBenchmark({
|
|
4667
|
+
urls,
|
|
4668
|
+
headless: options.headless !== false,
|
|
4669
|
+
maxConcurrency: options.concurrency ? parseInt(options.concurrency) : 3,
|
|
4670
|
+
});
|
|
4671
|
+
// Print ranking table
|
|
4672
|
+
console.log(`╔══════════════════════════════════════════════════════════════════════════════╗`);
|
|
4673
|
+
console.log(`║ AI Readiness Benchmark Results ║`);
|
|
4674
|
+
console.log(`╠══════════════════════════════════════════════════════════════════════════════╣`);
|
|
4675
|
+
console.log(`║ Rank Site Score Grade Find Stab A11y Sem ║`);
|
|
4676
|
+
console.log(`╠══════════════════════════════════════════════════════════════════════════════╣`);
|
|
4677
|
+
for (const site of result.sites) {
|
|
4678
|
+
const rank = result.ranking.find(r => r.site === site.siteName)?.rank || "-";
|
|
4679
|
+
const score = site.score !== null ? site.score.toString().padStart(3) : "ERR";
|
|
4680
|
+
const grade = site.grade || "-";
|
|
4681
|
+
const find = site.scoreBreakdown?.findability?.toString().padStart(3) || "-";
|
|
4682
|
+
const stab = site.scoreBreakdown?.stability?.toString().padStart(3) || "-";
|
|
4683
|
+
const a11y = site.scoreBreakdown?.accessibility?.toString().padStart(3) || "-";
|
|
4684
|
+
const sem = site.scoreBreakdown?.semantics?.toString().padStart(3) || "-";
|
|
4685
|
+
const siteName = site.siteName.substring(0, 32).padEnd(32);
|
|
4686
|
+
console.log(`║ ${String(rank).padStart(2)} ${siteName} ${score} ${grade.padEnd(2)} ${find} ${stab} ${a11y} ${sem} ║`);
|
|
4687
|
+
}
|
|
4688
|
+
console.log(`╚══════════════════════════════════════════════════════════════════════════════╝`);
|
|
4689
|
+
console.log(`\nDuration: ${result.duration}ms`);
|
|
4690
|
+
// Print best-in-class
|
|
4691
|
+
if (result.comparison.bestOverall) {
|
|
4692
|
+
console.log(`\n🏆 Best Overall: ${result.comparison.bestOverall}`);
|
|
4693
|
+
}
|
|
4694
|
+
if (result.comparison.bestFindability) {
|
|
4695
|
+
console.log(`🔍 Best Findability: ${result.comparison.bestFindability}`);
|
|
4696
|
+
}
|
|
4697
|
+
if (result.comparison.bestStability) {
|
|
4698
|
+
console.log(`🔒 Best Stability: ${result.comparison.bestStability}`);
|
|
4699
|
+
}
|
|
4700
|
+
if (result.comparison.bestAccessibility) {
|
|
4701
|
+
console.log(`♿ Best Accessibility: ${result.comparison.bestAccessibility}`);
|
|
4702
|
+
}
|
|
4703
|
+
if (result.comparison.bestSemantics) {
|
|
4704
|
+
console.log(`📋 Best Semantics: ${result.comparison.bestSemantics}`);
|
|
4705
|
+
}
|
|
4706
|
+
// Print recommendations
|
|
4707
|
+
if (result.recommendations.length > 0) {
|
|
4708
|
+
console.log(`\n📝 Recommendations:`);
|
|
4709
|
+
for (const rec of result.recommendations.slice(0, 5)) {
|
|
4710
|
+
console.log(` • ${rec}`);
|
|
4711
|
+
}
|
|
4712
|
+
}
|
|
4713
|
+
// Save JSON output if requested
|
|
4714
|
+
if (options.output) {
|
|
4715
|
+
const fs = await import("fs");
|
|
4716
|
+
fs.writeFileSync(options.output, JSON.stringify(result, null, 2));
|
|
4717
|
+
console.log(`\n📄 JSON report saved: ${options.output}`);
|
|
4718
|
+
}
|
|
4719
|
+
// Generate HTML report if requested
|
|
4720
|
+
if (options.html) {
|
|
4721
|
+
const fs = await import("fs");
|
|
4722
|
+
const htmlPath = options.output?.replace(".json", ".html") || "ai-benchmark-report.html";
|
|
4723
|
+
// Simple HTML table report
|
|
4724
|
+
const html = `<!DOCTYPE html>
|
|
4725
|
+
<html lang="en">
|
|
4726
|
+
<head>
|
|
4727
|
+
<meta charset="UTF-8">
|
|
4728
|
+
<title>AI Readiness Benchmark Report</title>
|
|
4729
|
+
<style>
|
|
4730
|
+
body { font-family: system-ui, sans-serif; max-width: 1200px; margin: 0 auto; padding: 2rem; }
|
|
4731
|
+
h1 { color: #333; }
|
|
4732
|
+
table { width: 100%; border-collapse: collapse; margin: 2rem 0; }
|
|
4733
|
+
th, td { padding: 0.75rem; text-align: left; border-bottom: 1px solid #ddd; }
|
|
4734
|
+
th { background: #f5f5f5; font-weight: 600; }
|
|
4735
|
+
.grade-A { color: #22c55e; font-weight: bold; }
|
|
4736
|
+
.grade-B { color: #84cc16; font-weight: bold; }
|
|
4737
|
+
.grade-C { color: #eab308; font-weight: bold; }
|
|
4738
|
+
.grade-D { color: #f97316; font-weight: bold; }
|
|
4739
|
+
.grade-F { color: #ef4444; font-weight: bold; }
|
|
4740
|
+
.best { background: #f0fdf4; }
|
|
4741
|
+
.timestamp { color: #666; font-size: 0.875rem; }
|
|
4742
|
+
</style>
|
|
4743
|
+
</head>
|
|
4744
|
+
<body>
|
|
4745
|
+
<h1>🏁 AI Readiness Benchmark Report</h1>
|
|
4746
|
+
<p class="timestamp">Generated: ${result.timestamp} | Duration: ${result.duration}ms</p>
|
|
4747
|
+
|
|
4748
|
+
<h2>Rankings</h2>
|
|
4749
|
+
<table>
|
|
4750
|
+
<thead>
|
|
4751
|
+
<tr><th>Rank</th><th>Site</th><th>Score</th><th>Grade</th><th>Findability</th><th>Stability</th><th>Accessibility</th><th>Semantics</th></tr>
|
|
4752
|
+
</thead>
|
|
4753
|
+
<tbody>
|
|
4754
|
+
${result.sites.map(site => {
|
|
4755
|
+
const rank = result.ranking.find(r => r.site === site.siteName)?.rank || "-";
|
|
4756
|
+
const isBest = result.comparison.bestOverall === site.siteName;
|
|
4757
|
+
return `<tr class="${isBest ? 'best' : ''}">
|
|
4758
|
+
<td>${rank}</td>
|
|
4759
|
+
<td>${site.siteName}</td>
|
|
4760
|
+
<td>${site.score ?? 'ERR'}</td>
|
|
4761
|
+
<td class="grade-${site.grade || 'F'}">${site.grade || '-'}</td>
|
|
4762
|
+
<td>${site.scoreBreakdown?.findability ?? '-'}</td>
|
|
4763
|
+
<td>${site.scoreBreakdown?.stability ?? '-'}</td>
|
|
4764
|
+
<td>${site.scoreBreakdown?.accessibility ?? '-'}</td>
|
|
4765
|
+
<td>${site.scoreBreakdown?.semantics ?? '-'}</td>
|
|
4766
|
+
</tr>`;
|
|
4767
|
+
}).join('')}
|
|
4768
|
+
</tbody>
|
|
4769
|
+
</table>
|
|
4770
|
+
|
|
4771
|
+
<h2>Best in Class</h2>
|
|
4772
|
+
<ul>
|
|
4773
|
+
${result.comparison.bestOverall ? `<li>🏆 Overall: <strong>${result.comparison.bestOverall}</strong></li>` : ''}
|
|
4774
|
+
${result.comparison.bestFindability ? `<li>🔍 Findability: <strong>${result.comparison.bestFindability}</strong></li>` : ''}
|
|
4775
|
+
${result.comparison.bestStability ? `<li>🔒 Stability: <strong>${result.comparison.bestStability}</strong></li>` : ''}
|
|
4776
|
+
${result.comparison.bestAccessibility ? `<li>♿ Accessibility: <strong>${result.comparison.bestAccessibility}</strong></li>` : ''}
|
|
4777
|
+
${result.comparison.bestSemantics ? `<li>📋 Semantics: <strong>${result.comparison.bestSemantics}</strong></li>` : ''}
|
|
4778
|
+
</ul>
|
|
4779
|
+
|
|
4780
|
+
${result.recommendations.length > 0 ? `
|
|
4781
|
+
<h2>Recommendations</h2>
|
|
4782
|
+
<ul>
|
|
4783
|
+
${result.recommendations.map(r => `<li>${r}</li>`).join('')}
|
|
4784
|
+
</ul>
|
|
4785
|
+
` : ''}
|
|
4786
|
+
|
|
4787
|
+
<footer style="margin-top: 3rem; padding-top: 1rem; border-top: 1px solid #ddd; color: #666; font-size: 0.875rem;">
|
|
4788
|
+
Generated by <a href="https://cbrowser.ai">CBrowser</a> v${(await import("./version.js")).VERSION}
|
|
4789
|
+
</footer>
|
|
4790
|
+
</body>
|
|
4791
|
+
</html>`;
|
|
4792
|
+
fs.writeFileSync(htmlPath, html);
|
|
4793
|
+
console.log(`🌐 HTML report saved: ${htmlPath}`);
|
|
4794
|
+
}
|
|
4795
|
+
break;
|
|
4796
|
+
}
|
|
4581
4797
|
case "webmcp-ready": {
|
|
4582
4798
|
const url = args[0];
|
|
4583
4799
|
if (!url) {
|