scripts/validate-review-state.mjs
scripts/validate-review-state.mjsBrowse 11 files
621 tokens
2,306 bytes
Token encoding: o200k_base
Snapshot fac8604
← Back to SKILL.md
1#!/usr/bin/env node2 3import { realpathSync } from 'node:fs';4import { readFile } from 'node:fs/promises';5import { resolve } from 'node:path';6import { fileURLToPath } from 'node:url';7 8import { assertReviewStateV2, REVIEW_STATE_VERSION } from './review-artifacts.mjs';9 10const EXIT_SUCCESS = 0;11const EXIT_OPERATIONAL = 1;12const EXIT_CLI = 2;13 14function parseCliArgs(argv) {15 const args = argv.slice(2);16 const result = { inPath: null, help: false };17 if (args.includes('--help')) {18 result.help = true;19 return result;20 }21 22 for (let index = 0; index < args.length; index += 1) {23 const arg = args[index];24 if (arg !== '--in') {25 throw { code: EXIT_CLI, message: `error: unknown flag "${arg}"` };26 }27 index += 1;28 if (index >= args.length) {29 throw { code: EXIT_CLI, message: 'error: --in requires a value' };30 }31 result.inPath = args[index];32 }33 34 if (!result.inPath) {35 throw { code: EXIT_CLI, message: 'error: --in is required' };36 }37 if (!result.inPath.endsWith('.json')) {38 throw { code: EXIT_CLI, message: 'error: --in file path must end with .json' };39 }40 41 return result;42}43 44function getHelpText() {45 return [46 'Usage:',47 ' validate-review-state.mjs --in <review-state.json>',48 '',49 'Purpose:',50 ` Validate canonical review-state.json schema (v${REVIEW_STATE_VERSION}).`,51 ].join('\n');52}53 54async function main() {55 const args = parseCliArgs(process.argv);56 if (args.help) {57 process.stdout.write(`${getHelpText()}\n`);58 process.exit(EXIT_SUCCESS);59 }60 61 const raw = await readFile(args.inPath, 'utf8');62 const parsed = JSON.parse(raw);63 assertReviewStateV2(parsed);64 process.stdout.write(`ok: ${args.inPath}\n`);65}66 67const isMain = (() => {68 try {69 const invokedScriptPath = process.argv[1] ? realpathSync(resolve(process.argv[1])) : null;70 const currentModulePath = realpathSync(fileURLToPath(import.meta.url));71 return invokedScriptPath !== null && invokedScriptPath === currentModulePath;72 } catch {73 return false;74 }75})();76 77if (isMain) {78 main().catch((error) => {79 const code = typeof error?.code === 'number' ? error.code : EXIT_OPERATIONAL;80 const message = error?.message ? String(error.message) : String(error);81 process.stderr.write(`${message}\n`);82 process.exit(code);83 });84}85