#!/usr/bin/env node /** * cli:eslint-validator * Responsibility: orchestrate validation + execution of the 5 SmartStack ESLint rules * Called by Claude Code via skill:eslint-validator * * Usage: * npx --prefer-offline tsx skills/validation/eslint/cli/index.ts --src */ import { parseArgs } from 'node:util' import { resolve } from 'node:path' import { validate } from './validate' import { execute } from './execute' import type { ESLintReport } from './types' // ─── Parse args ─── const { values } = parseArgs({ options: { src: { type: 'string' }, help: { type: 'boolean', short: 'h' }, }, strict: true, }) if (values.help) { console.log(`cli:eslint-validator — SmartStack Studio Static analysis of React/TypeScript files (5 SmartStack rules). Rules: ss/no-direct-fetch — No fetch/axios in components/ and pages/ ss/permission-guard — Sensitive actions wrapped in PermissionGuard ss/dto-naming — Interfaces aligned with the DTO conventions ss/service-hook-structure — Standard useQuery/useMutation hooks ss/feature-folder — features/{module}/{resource}/{layer}/ structure Usage: npx --prefer-offline tsx skills/validation/eslint/cli/index.ts --src Options: --src Directory containing the .tsx/.ts files (required) -h, --help Show this help Exit codes: 0 Success (no errors) 1 Validation error (invalid input) 2 Internal CLI error 3 Violations detected`) process.exit(0) } if (!values.src) { console.error(JSON.stringify({ timestamp: new Date().toISOString(), checks: [], errors: 1, warnings: 0, message: '--src is required', })) process.exit(1) } // ─── Resolve path ─── const srcPath = resolve(values.src) // ─── Validate ─── const validation = validate({ src: srcPath }) if (!validation.valid) { const report: ESLintReport = { timestamp: new Date().toISOString(), checks: validation.blockers.map((b) => ({ code: 'cli/validation', status: 'error' as const, message: b, })), errors: validation.blockers.length, warnings: 0, } console.log(JSON.stringify(report, null, 2)) process.exit(1) } // ─── Execute ─── try { const report = execute(validation.data!) console.log(JSON.stringify(report, null, 2)) // Exit code based on results if (report.errors > 0) { process.exit(3) } process.exit(0) } catch (err) { const message = err instanceof Error ? err.message : String(err) console.error(JSON.stringify({ timestamp: new Date().toISOString(), checks: [{ code: 'cli/internal', status: 'error', message }], errors: 1, warnings: 0, })) process.exit(2) }