Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion assessment-log.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ import { fileURLToPath, pathToFileURL } from 'url';
const CAREER_OPS = dirname(fileURLToPath(import.meta.url));
const LOG_PATH = join(CAREER_OPS, 'data/assessments.tsv');

const KNOWN_FLAGS = ['--self-test', '--summary', '--help', '-h'];
const ADD_VALUE_FLAGS = ['--company', '--report', '--platform', '--subject', '--threshold', '--score', '--stale'];

const USAGE = `Usage:
node assessment-log.mjs add --company <name> [--report <num>] --platform <vendor> --subject <topic> [--threshold <pct>] [--score <pct>] [--stale "<note>"]
node assessment-log.mjs # print the assessment log as JSON
node assessment-log.mjs --summary # print a human-readable summary
node assessment-log.mjs --self-test # run the in-memory test suite
node assessment-log.mjs --help # print this usage block and exit (-h is an alias)`;

const HEADER_COMMENT = [
'# assessments.tsv — append-only skills-assessment log (user layer). Never rewrite rows.',
'# {YYYY-MM-DD}\\t{company}\\t{report#|-}\\t{platform}\\t{subject}\\t{threshold%|-}\\t{score%|-}\\t{stale_note}',
Expand Down Expand Up @@ -143,7 +153,7 @@ function addEntry(args) {
row = buildRow(fields, today);
} catch (e) {
console.error(`assessment-log: ${e.message}`);
console.error('Usage: node assessment-log.mjs add --company <name> [--report <num>] --platform <vendor> --subject <topic> [--threshold <pct>] [--score <pct>] [--stale "<note>"]');
console.error(USAGE);
process.exit(1);
}
// Append-only: existing rows are never rewritten. Create with header comment on first use.
Expand Down Expand Up @@ -273,6 +283,33 @@ function printSummary(result) {

function main() {
const args = process.argv.slice(2);

if (args.includes('--help') || args.includes('-h')) {
console.log(USAGE);
process.exit(0);
}

// Values passed to the add subcommand remain positional data even when they
// start with a dash (for example an explicitly unknown "-" percentage).
// Only a leading-dash argument outside those value slots is a CLI flag.
const consumedValueIndices = new Set();
if (args[0] === 'add') {
args.forEach((arg, index) => {
if (ADD_VALUE_FLAGS.includes(arg) && args[index + 1] !== undefined && !args[index + 1].startsWith('--')) {
consumedValueIndices.add(index + 1);
}
});
}

const validFlags = args[0] === 'add' ? [...KNOWN_FLAGS, ...ADD_VALUE_FLAGS] : KNOWN_FLAGS;
const unknownFlags = args.filter((arg, index) =>
arg.startsWith('-') && !consumedValueIndices.has(index) && !validFlags.includes(arg));
if (unknownFlags.length) {
console.error(`assessment-log: unrecognized flag(s): ${unknownFlags.join(', ')}. Valid flags: ${validFlags.join(', ')}`);
console.error(USAGE);
process.exit(1);
}

if (args.includes('--self-test')) { selfTest(); return; }
if (args[0] === 'add') { addEntry(args.slice(1)); return; }

Expand Down
49 changes: 49 additions & 0 deletions test-all.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,55 @@ try {
}
}

// assessment-log.mjs CLI contract (#2797): help aliases print one shared
// usage block, unknown leading-dash arguments fail loudly, and the existing
// add/summary paths still accept ordinary values that merely contain dashes.
{
const assessmentCli = (...argv) => spawnSync(NODE, [join(scriptTmp, 'assessment-log.mjs'), ...argv], {
cwd: scriptTmp,
encoding: 'utf-8',
timeout: 30000,
stdio: ['pipe', 'pipe', 'pipe'],
});

const helpR = assessmentCli('--help');
const hR = assessmentCli('-h');
if (helpR.status === 0 && hR.status === 0 && helpR.stdout.includes('Usage:')
&& helpR.stdout.includes('--self-test') && hR.stdout === helpR.stdout
&& helpR.stderr === '' && hR.stderr === '') {
pass('assessment-log.mjs --help/-h print the shared usage block and exit 0 (#2797)');
} else {
fail(`assessment-log.mjs help handling broken: ${JSON.stringify({ help: { status: helpR.status, stdout: helpR.stdout, stderr: helpR.stderr }, h: { status: hR.status, stdout: hR.stdout, stderr: hR.stderr } })}`);
}

const typoR = assessmentCli('--sumary');
const misplacedAddFlagR = assessmentCli('--company', 'Acme-Co');
if (typoR.status === 1 && typoR.stderr.includes('unrecognized flag')
&& typoR.stderr.includes('--sumary') && typoR.stderr.includes('Valid flags:')
&& typoR.stderr.includes('Usage:') && typoR.stdout === ''
&& misplacedAddFlagR.status === 1 && misplacedAddFlagR.stderr.includes('--company')) {
pass('assessment-log.mjs rejects and names an unrecognized leading-dash flag (#2797)');
} else {
fail(`assessment-log.mjs unknown flag handling broken: ${JSON.stringify({ typo: { status: typoR.status, stdout: typoR.stdout, stderr: typoR.stderr }, misplacedAddFlag: { status: misplacedAddFlagR.status, stdout: misplacedAddFlagR.stdout, stderr: misplacedAddFlagR.stderr } })}`);
}

const addR = assessmentCli(
'add', '--company', 'Acme-Co', '--platform', 'eSkill', '--subject',
'-Data-Analysis', '--threshold', '70', '--score', '85'
);
const summaryR = assessmentCli('--summary');
let added = null;
try { added = JSON.parse(addR.stdout); } catch {}
if (addR.status === 0 && added?.added === true
&& added.row?.[1] === 'Acme-Co' && added.row?.[4] === '-Data-Analysis'
&& summaryR.status === 0 && summaryR.stdout.includes('Acme-Co')
&& summaryR.stdout.includes('Data-Analysis')) {
pass('assessment-log.mjs preserves add/summary flags and dash-containing values (#2797 regression)');
Comment thread
coderabbitai[bot] marked this conversation as resolved.
} else {
fail(`assessment-log.mjs existing CLI behavior regressed: ${JSON.stringify({ add: { status: addR.status, stdout: addR.stdout, stderr: addR.stderr }, summary: { status: summaryR.status, stdout: summaryR.stdout, stderr: summaryR.stderr } })}`);
}
}

// reply-watch.mjs CLI flag validation (#2743). main() used to read
// process.argv[2] purely positionally with no flag checking: `--help` or
// any typo'd flag silently became the "candidates path" argument, and
Expand Down
Loading