From 2001c816869801591ffbb8bb8964cb0ae08ee354 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Wed, 2 Sep 2026 18:48:43 -0700 Subject: [PATCH] Fix local target failure exit codes AI assistance disclosure: Codex implemented and tested this fix under maintainer direction. --- cli/engine/cli/main.mjs | 6 +++++- tests/detect-url-launch.test.mjs | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cli/engine/cli/main.mjs b/cli/engine/cli/main.mjs index b77281e7d..e54887323 100644 --- a/cli/engine/cli/main.mjs +++ b/cli/engine/cli/main.mjs @@ -364,7 +364,11 @@ async function detectCli() { const resolved = path.resolve(target); let stat; try { stat = fs.statSync(resolved); } - catch { process.stderr.write(`Warning: cannot access ${target}\n`); continue; } + catch { + hadOperationalFailure = true; + process.stderr.write(`Warning: cannot access ${target}\n`); + continue; + } if (stat.isDirectory()) { // Check for framework dev server config (skip in JSON/quiet modes to avoid polluting output) diff --git a/tests/detect-url-launch.test.mjs b/tests/detect-url-launch.test.mjs index 75200c3e6..18119e96c 100644 --- a/tests/detect-url-launch.test.mjs +++ b/tests/detect-url-launch.test.mjs @@ -138,6 +138,26 @@ describe('detect CLI browser failures', () => { expect(findings.some(finding => finding.antipattern === 'bounce-easing')).toBe(true); expect(result.stderr).toContain('puppeteer is required for URL scanning'); }); + + test('exits 1 when an explicitly requested local target cannot be accessed', () => { + const result = runWithoutPuppeteer(['missing.css']); + + expect(result.status).toBe(1); + expect(result.stdout).toBe('[]\n'); + expect(result.stderr).toContain('Warning: cannot access missing.css'); + }); + + test('missing local target takes precedence over findings from another target', () => { + const result = runWithoutPuppeteer( + ['missing.css', 'page.css'], + { 'page.css': '.hero { animation: bounce 1s linear infinite; }\n' }, + ); + const findings = JSON.parse(result.stdout); + + expect(result.status).toBe(1); + expect(findings.some(finding => finding.antipattern === 'bounce-easing')).toBe(true); + expect(result.stderr).toContain('Warning: cannot access missing.css'); + }); }); describe('splitScanUrl', () => {