create-claude-cabinet 0.29.8 → 0.29.9
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/lib/site-audit-setup.js +17 -3
- package/package.json +1 -1
- package/templates/site-audit-runtime/package.json +1 -1
- package/templates/site-audit-runtime/src/checks/axe-core.mjs +1 -1
- package/templates/site-audit-runtime/src/checks/unlighthouse.mjs +37 -4
- package/templates/site-audit-runtime/src/report.mjs +13 -2
package/lib/site-audit-setup.js
CHANGED
|
@@ -93,6 +93,20 @@ function extractAndInstall(versionDir, tarballPath, results) {
|
|
|
93
93
|
|
|
94
94
|
// Pa11y needs Puppeteer's Chrome; axe-core needs chromedriver.
|
|
95
95
|
// Both were skipped by --ignore-scripts. Install them now.
|
|
96
|
+
// Clear corrupt Puppeteer cache first (folder exists but binary missing).
|
|
97
|
+
try {
|
|
98
|
+
const cacheBase = path.join(os.homedir(), '.cache', 'puppeteer', 'chrome');
|
|
99
|
+
if (fs.existsSync(cacheBase)) {
|
|
100
|
+
for (const d of fs.readdirSync(cacheBase)) {
|
|
101
|
+
const chromeBin = path.join(cacheBase, d, 'chrome-mac-arm64', 'Google Chrome for Testing.app', 'Contents', 'MacOS', 'Google Chrome for Testing');
|
|
102
|
+
const chromeLinux = path.join(cacheBase, d, 'chrome-linux64', 'chrome');
|
|
103
|
+
if (!fs.existsSync(chromeBin) && !fs.existsSync(chromeLinux)) {
|
|
104
|
+
fs.rmSync(path.join(cacheBase, d), { recursive: true, force: true });
|
|
105
|
+
results.push(` Cleared corrupt Puppeteer cache: ${d}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} catch { /* tolerate */ }
|
|
96
110
|
try {
|
|
97
111
|
execSync('npx puppeteer browsers install chrome', { cwd: pkgDir, encoding: 'utf8', timeout: 120_000 });
|
|
98
112
|
results.push(' Installed Puppeteer Chrome for Pa11y');
|
|
@@ -100,10 +114,10 @@ function extractAndInstall(versionDir, tarballPath, results) {
|
|
|
100
114
|
results.push(' ⚠ Puppeteer Chrome install failed — Pa11y will be unavailable');
|
|
101
115
|
}
|
|
102
116
|
try {
|
|
103
|
-
execSync('
|
|
104
|
-
results.push(' Installed chromedriver for axe-core');
|
|
117
|
+
execSync('npx browser-driver-manager install chrome', { cwd: pkgDir, encoding: 'utf8', timeout: 120_000 });
|
|
118
|
+
results.push(' Installed matching Chrome + chromedriver for axe-core');
|
|
105
119
|
} catch {
|
|
106
|
-
results.push(' ⚠
|
|
120
|
+
results.push(' ⚠ browser-driver-manager install failed — axe-core will be unavailable');
|
|
107
121
|
}
|
|
108
122
|
|
|
109
123
|
const binDir = path.join(versionDir, 'bin');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-cabinet/site-audit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Comprehensive deployed-site quality audit engine for Claude Cabinet. Runs checks across performance, accessibility, security, SEO, content, DNS, and privacy against a deployed URL; single-site and comparison modes; standalone HTML report.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,7 @@ export async function detect(executor) {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export async function run(url, executor) {
|
|
11
|
-
return executor.spawn('axe', [url, '--
|
|
11
|
+
return executor.spawn('axe', [url, '--stdout'], { timeoutMs: 60_000 });
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const IMPACT_TO_SEVERITY = { critical: 'critical', serious: 'serious', moderate: 'moderate', minor: 'info' };
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
// aggregated scores. Heavier than single-page Lighthouse — use for
|
|
3
3
|
// multi-page audit coverage.
|
|
4
4
|
|
|
5
|
+
import { readFileSync, existsSync, readdirSync, rmSync } from 'node:fs';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
|
|
5
8
|
export const checkId = 'unlighthouse';
|
|
6
9
|
export const tool = 'Unlighthouse (full-site crawl)';
|
|
7
10
|
export const whyItMatters = "Runs Lighthouse on every page of your site, not just the homepage — catches performance and accessibility problems hiding on inner pages.";
|
|
@@ -13,14 +16,44 @@ export async function detect(executor) {
|
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
export async function run(url, executor) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
const outDir = join(process.cwd(), '.unlighthouse-tmp');
|
|
20
|
+
try { rmSync(outDir, { recursive: true, force: true }); } catch { /* ok */ }
|
|
21
|
+
|
|
22
|
+
const r = await executor.spawn('unlighthouse-ci', [
|
|
23
|
+
'--site', url,
|
|
24
|
+
'--reporter', 'jsonExpanded',
|
|
25
|
+
'--output-path', outDir,
|
|
26
|
+
'--samples', '5',
|
|
27
|
+
], { timeoutMs: 600_000 });
|
|
28
|
+
|
|
29
|
+
// Read the JSON report from the output directory
|
|
30
|
+
try {
|
|
31
|
+
const reportDir = join(outDir, 'ci-result');
|
|
32
|
+
if (existsSync(reportDir)) {
|
|
33
|
+
const files = readdirSync(reportDir).filter(f => f.endsWith('.json'));
|
|
34
|
+
if (files.length) {
|
|
35
|
+
const json = readFileSync(join(reportDir, files[0]), 'utf8');
|
|
36
|
+
return { code: r.code, stdout: json, stderr: r.stderr, timedOut: r.timedOut };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Fallback: try .unlighthouse directory
|
|
40
|
+
const altDir = join(outDir);
|
|
41
|
+
const altFiles = existsSync(altDir) ? readdirSync(altDir).filter(f => f.endsWith('.json')) : [];
|
|
42
|
+
if (altFiles.length) {
|
|
43
|
+
const json = readFileSync(join(altDir, altFiles[0]), 'utf8');
|
|
44
|
+
return { code: r.code, stdout: json, stderr: r.stderr, timedOut: r.timedOut };
|
|
45
|
+
}
|
|
46
|
+
} catch { /* fall through */ }
|
|
47
|
+
|
|
48
|
+
return r;
|
|
19
49
|
}
|
|
20
50
|
|
|
21
51
|
export function normalize(raw, durationMs) {
|
|
52
|
+
if (raw.timedOut) {
|
|
53
|
+
return { checkId, tool, status: 'error', score: null, grade: null, severity: null, findings: [], durationMs, reason: 'timed out (full-site crawl may need more time)' };
|
|
54
|
+
}
|
|
22
55
|
if (raw.code !== 0 && !raw.stdout) {
|
|
23
|
-
return { checkId, tool, status: 'error', score: null, grade: null, severity: null, findings: [], durationMs, reason: raw.stderr || 'unlighthouse failed' };
|
|
56
|
+
return { checkId, tool, status: 'error', score: null, grade: null, severity: null, findings: [], durationMs, reason: raw.stderr?.slice(0, 200) || 'unlighthouse failed' };
|
|
24
57
|
}
|
|
25
58
|
|
|
26
59
|
let data;
|
|
@@ -40,7 +40,7 @@ h1{font-size:1.75rem;margin-bottom:.25rem}
|
|
|
40
40
|
.sev-info{color:#888}
|
|
41
41
|
.finding-url{font-size:.8rem;color:#06c;word-break:break-all}
|
|
42
42
|
.pass-summary{color:#0a7;font-size:.9rem;font-style:italic;padding:.25rem 0}
|
|
43
|
-
.compare-row{display:grid;grid-template-columns:1fr
|
|
43
|
+
.compare-row{display:grid;grid-template-columns:1fr 150px 150px 80px;gap:.5rem;align-items:center;padding:.75rem 1.25rem;border-bottom:1px solid #f0f0f0;cursor:pointer;text-decoration:none;color:inherit}
|
|
44
44
|
.compare-row:hover{background:#f8f9fc}
|
|
45
45
|
.compare-row:first-child{font-weight:700;background:#f8f9fc;cursor:default}
|
|
46
46
|
.delta-pos{color:#0a7;font-weight:600}
|
|
@@ -260,7 +260,18 @@ function classifyFindings(a, b) {
|
|
|
260
260
|
* @returns {string}
|
|
261
261
|
*/
|
|
262
262
|
function hostnameLabel(url) {
|
|
263
|
-
try {
|
|
263
|
+
try {
|
|
264
|
+
const u = new URL(url);
|
|
265
|
+
const h = u.hostname;
|
|
266
|
+
const platformDomains = ['railway.app', 'herokuapp.com', 'vercel.app', 'netlify.app', 'fly.dev', 'render.com'];
|
|
267
|
+
const isPlat = platformDomains.some(d => h.endsWith(d));
|
|
268
|
+
if (isPlat && u.pathname && u.pathname !== '/') {
|
|
269
|
+
return u.pathname.split('/').filter(Boolean)[0] + ' (staging)';
|
|
270
|
+
}
|
|
271
|
+
if (isPlat) return 'staging';
|
|
272
|
+
if (h.length <= 25) return h;
|
|
273
|
+
return h.slice(0, 22) + '...';
|
|
274
|
+
} catch { return url; }
|
|
264
275
|
}
|
|
265
276
|
|
|
266
277
|
export function renderComparison(delta) {
|