From 926b768543cc3b8c28674f0ea8612cea22be4c57 Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Tue, 30 Jun 2026 09:48:28 +0200 Subject: [PATCH] fix(validators): brief-validator CLI no-flag invocation bailed to Usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The documented `brief-validator.mjs ` invocation (no flags) always bailed to Usage/exit 2. Root cause: when --min-version is absent, minIdx is -1, so the skip index minIdx+1 was 0 — excluding argv index 0, exactly where the file positional sits in the no-flag case. Any leading flag (--soft, --json) pushed the file to index >=1 and masked the bug, so the function-level tests never caught it. Guard the skip index to -1 when --min-version is absent. Add two CLI regression tests (execFileSync, matching the next-session-prompt-validator pattern): no-flag invocation reaches validation, and --min-version still skips its value token to find the file. Suite 822 -> 824 (822/0/2). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01WH1krHamUehZh6JqVqs85t --- lib/validators/brief-validator.mjs | 6 +++- tests/validators/brief-validator.test.mjs | 39 +++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/validators/brief-validator.mjs b/lib/validators/brief-validator.mjs index f93d2e2..7f25d90 100644 --- a/lib/validators/brief-validator.mjs +++ b/lib/validators/brief-validator.mjs @@ -252,7 +252,11 @@ if (import.meta.url === `file://${process.argv[1]}`) { const minIdx = args.indexOf('--min-version'); const minBriefVersion = minIdx >= 0 ? args[minIdx + 1] : undefined; // filePath is the first positional, skipping the --min-version value token. - const filePath = args.find((a, i) => !a.startsWith('--') && i !== minIdx + 1); + // Guard: when --min-version is absent (minIdx === -1) the skip index must be -1, + // not 0 — otherwise the no-flag invocation `brief-validator.mjs ` drops + // the file (which sits at index 0) and bails to Usage. + const skipIdx = minIdx >= 0 ? minIdx + 1 : -1; + const filePath = args.find((a, i) => !a.startsWith('--') && i !== skipIdx); if (!filePath) { process.stderr.write('Usage: brief-validator.mjs [--soft] [--min-version ] \n'); process.exit(2); diff --git a/tests/validators/brief-validator.test.mjs b/tests/validators/brief-validator.test.mjs index a24d9d4..3a05928 100644 --- a/tests/validators/brief-validator.test.mjs +++ b/tests/validators/brief-validator.test.mjs @@ -1,5 +1,9 @@ import { test } from 'node:test'; import { strict as assert } from 'node:assert'; +import { execFileSync } from 'node:child_process'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; import { validateBriefContent } from '../../lib/validators/brief-validator.mjs'; const GOOD_BRIEF = `--- @@ -393,3 +397,38 @@ test('validateBrief — S18 min-version: trekreview brief is exempt (no framing const r = validateBriefContent(REVIEW_AS_BRIEF, { minBriefVersion: '2.2' }); assert.ok(!r.warnings.find(w => w.code === 'BRIEF_VERSION_BELOW_MINIMUM')); }); + +// S56 — CLI arg-parsing regression. The no-flag invocation `brief-validator.mjs ` +// used to bail to Usage/exit 2 because the --min-version skip index was 0 when the flag +// was absent, dropping the file positional (which sits at argv index 0). +test('CLI — no-flag invocation reaches validation, does not bail to Usage (S56 regression)', () => { + const dir = mkdtempSync(join(tmpdir(), 'brief-cli-')); + try { + const file = join(dir, 'brief.md'); + writeFileSync(file, GOOD_BRIEF); + // execFileSync throws on non-zero exit; pre-fix this bailed to Usage (exit 2). + const out = execFileSync(process.execPath, [ + 'lib/validators/brief-validator.mjs', + file, + ], { encoding: 'utf-8' }); + assert.match(out, /PASS/); + } finally { + rmSync(dir, { recursive: true, force: true }); + } +}); + +test('CLI — --min-version still locates the file positional after the value token (S56)', () => { + const dir = mkdtempSync(join(tmpdir(), 'brief-cli-')); + try { + const file = join(dir, 'brief.md'); + writeFileSync(file, GOOD_BRIEF); + const out = execFileSync(process.execPath, [ + 'lib/validators/brief-validator.mjs', + '--min-version', '2.0', + file, + ], { encoding: 'utf-8' }); + assert.match(out, /PASS/); + } finally { + rmSync(dir, { recursive: true, force: true }); + } +});