@neurolint/cli
Version:
NeuroLint CLI - Deterministic code fixing for TypeScript, JavaScript, React, and Next.js with 8-layer architecture including Security Forensics, Next.js 16, React Compiler, and Turbopack support
153 lines (122 loc) • 5.22 kB
JavaScript
/**
* Copyright (c) 2025 NeuroLint
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
const DEMO_PROJECT = path.join(__dirname, '..', 'demo-project');
const OUTPUT_FILE = path.join(__dirname, '..', 'landing', 'public', 'demo.cast');
const header = {
version: 2,
width: 100,
height: 30,
timestamp: Math.floor(Date.now() / 1000),
title: "NeuroLint CLI - CVE-2025-55182 Security Fix Demo",
env: { SHELL: "/bin/bash", TERM: "xterm-256color" }
};
const events = [];
let currentTime = 0;
function addOutput(text, delay = 0.05) {
currentTime += delay;
events.push([currentTime, "o", text]);
}
function addTyping(text, charDelay = 0.04) {
for (const char of text) {
currentTime += charDelay;
events.push([currentTime, "o", char]);
}
}
function addLine(text, delay = 0.02) {
addOutput(text + "\r\n", delay);
}
function addPrompt() {
addOutput("\u001b[32m$\u001b[0m ", 0.3);
}
function typeCommand(cmd) {
addPrompt();
addTyping(cmd);
addOutput("\r\n", 0.1);
}
async function runCommand(cmd, args, cwd) {
return new Promise((resolve) => {
const proc = spawn(cmd, args, { cwd, env: { ...process.env, FORCE_COLOR: '1' } });
let output = '';
proc.stdout.on('data', (data) => { output += data.toString(); });
proc.stderr.on('data', (data) => { output += data.toString(); });
proc.on('close', () => resolve(output));
});
}
async function generateDemo() {
console.log('[+] Generating demo recording...');
addOutput("\u001b[2J\u001b[H", 0);
addLine("\u001b[1;36m========================================\u001b[0m", 0.1);
addLine("\u001b[1;36m NeuroLint CLI - Security Demo\u001b[0m", 0.05);
addLine("\u001b[1;36m========================================\u001b[0m", 0.05);
addLine("", 0.5);
addLine("\u001b[1;33m[1/4] Checking package.json for vulnerable dependencies...\u001b[0m", 0.3);
addLine("", 0.2);
typeCommand("cat package.json | grep -A6 dependencies");
currentTime += 0.3;
const pkgJson = JSON.parse(fs.readFileSync(path.join(DEMO_PROJECT, 'package.json'), 'utf8'));
addLine(' "dependencies": {', 0.05);
addLine(` "next": "${pkgJson.dependencies.next}",`, 0.03);
addLine(` "react": "${pkgJson.dependencies.react}",`, 0.03);
addLine(` "react-dom": "${pkgJson.dependencies['react-dom']}"`, 0.03);
addLine(' },', 0.03);
addLine("", 0.5);
addLine("\u001b[1;33m[2/4] Scanning for CVE-2025-55182 vulnerability...\u001b[0m", 0.3);
addLine("", 0.2);
typeCommand("npx @neurolint/cli security:cve-2025-55182 . --dry-run");
currentTime += 0.5;
const dryRunOutput = await runCommand('node', [path.join(__dirname, '..', 'cli.js'), 'security:cve-2025-55182', DEMO_PROJECT, '--dry-run']);
for (const line of dryRunOutput.split('\n')) {
if (line.trim()) {
addLine(line, 0.04);
}
}
addLine("", 0.8);
addLine("\u001b[1;33m[3/4] Applying security fix...\u001b[0m", 0.3);
addLine("", 0.2);
typeCommand("npx @neurolint/cli security:cve-2025-55182 . --fix");
currentTime += 0.5;
const fixOutput = await runCommand('node', [path.join(__dirname, '..', 'cli.js'), 'security:cve-2025-55182', DEMO_PROJECT, '--fix']);
for (const line of fixOutput.split('\n')) {
if (line.trim()) {
addLine(line, 0.04);
}
}
addLine("", 0.8);
addLine("\u001b[1;33m[4/4] Verifying fix was applied...\u001b[0m", 0.3);
addLine("", 0.2);
typeCommand("cat package.json | grep -A6 dependencies");
currentTime += 0.3;
const updatedPkgJson = JSON.parse(fs.readFileSync(path.join(DEMO_PROJECT, 'package.json'), 'utf8'));
addLine(' "dependencies": {', 0.05);
addLine(` "next": "\u001b[32m${updatedPkgJson.dependencies.next}\u001b[0m",`, 0.03);
addLine(` "react": "\u001b[32m${updatedPkgJson.dependencies.react}\u001b[0m",`, 0.03);
addLine(` "react-dom": "\u001b[32m${updatedPkgJson.dependencies['react-dom']}\u001b[0m"`, 0.03);
addLine(' },', 0.03);
addLine("", 0.5);
addLine("\u001b[1;32m========================================\u001b[0m", 0.1);
addLine("\u001b[1;32m Security vulnerability PATCHED!\u001b[0m", 0.05);
addLine("\u001b[1;32m========================================\u001b[0m", 0.05);
addLine("", 1);
const castContent = JSON.stringify(header) + '\n' + events.map(e => JSON.stringify(e)).join('\n');
fs.mkdirSync(path.dirname(OUTPUT_FILE), { recursive: true });
fs.writeFileSync(OUTPUT_FILE, castContent);
console.log(`[OK] Demo recording saved to: ${OUTPUT_FILE}`);
console.log(`[i] Duration: ${currentTime.toFixed(2)}s, Events: ${events.length}`);
}
generateDemo().catch(console.error);