@agentics.org/sparc2
Version:
SPARC 2.0 - Autonomous Vector Coding Agent + MCP. SPARC 2.0, vectorized AI code analysis, is an intelligent coding agent framework built to automate and streamline software development. It combines secure execution environments, and version control into a
401 lines (344 loc) • 12.5 kB
JavaScript
/**
* SPARC2 CLI Wrapper Script
*
* This script provides a more robust way to run the SPARC2 CLI,
* with better error handling and diagnostics.
*/
import { spawn, execSync } from 'child_process';
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
// Get the directory of this script
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// ANSI color codes for terminal output
const colors = {
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
reset: '\x1b[0m'
};
/**
* Check if Deno is installed
* @returns {boolean} True if Deno is installed, false otherwise
*/
function isDenoInstalled() {
try {
execSync('deno --version', { stdio: 'ignore' });
return true;
} catch (error) {
return false;
}
}
/**
* Print Deno installation instructions
*/
function printDenoInstallInstructions() {
console.log(`${colors.red}Error: Deno is required but not installed.${colors.reset}`);
console.log(`${colors.yellow}Please install Deno using one of the following methods:${colors.reset}`);
console.log(`\n${colors.blue}Linux/macOS:${colors.reset}`);
console.log(` curl -fsSL https://deno.land/install.sh | sh`);
console.log(`\n${colors.blue}Windows (PowerShell):${colors.reset}`);
console.log(` irm https://deno.land/install.ps1 | iex`);
// Check if the install script exists
const installScriptPath = path.join(__dirname, 'install-deno.sh');
if (fs.existsSync(installScriptPath)) {
console.log(`\n${colors.green}Or run the included installation script:${colors.reset}`);
console.log(` ${installScriptPath}`);
}
console.log(`\n${colors.yellow}For more information, visit: https://deno.land/#installation${colors.reset}`);
console.log(`\n${colors.cyan}After installing Deno, you may need to restart your terminal or add Deno to your PATH.${colors.reset}`);
}
/**
* Check if we're running from a global installation (node_modules)
* @returns {boolean} True if running from node_modules, false otherwise
*/
function isRunningFromNodeModules() {
// More robust check for node_modules
return __dirname.includes('node_modules') ||
__dirname.includes('/usr/local/') ||
__dirname.includes('/usr/lib/') ||
__dirname.includes('/usr/share/');
}
/**
* Find the CLI TypeScript source file
* @returns {string|null} Path to the CLI TypeScript file if found, null otherwise
*/
function findCliSourceFile() {
// Possible locations for the CLI TypeScript source file
const possiblePaths = [
// Local source directory
path.join(__dirname, 'src', 'cli', 'cli.ts'),
// Current directory
path.join(process.cwd(), 'src', 'cli', 'cli.ts')
];
for (const p of possiblePaths) {
if (fs.existsSync(p)) {
return p;
}
}
return null;
}
/**
* Find the CLI script (JS)
* @returns {string|null} Path to the CLI script if found, null otherwise
*/
function findCliScript() {
// Possible locations for the CLI script
const possiblePaths = [
// Local build directory
path.join(__dirname, 'build', 'cli', 'cli.js'),
// Global installation
path.join(__dirname, 'build', 'cli', 'cli.js')
];
for (const p of possiblePaths) {
if (fs.existsSync(p)) {
return p;
}
}
return null;
}
/**
* Run the CLI using Deno directly with the TypeScript source
*/
function runCliWithDeno() {
const cliSourcePath = findCliSourceFile();
if (!cliSourcePath) {
console.log(`${colors.yellow}No TypeScript source found, trying JavaScript...${colors.reset}`);
runCliFallback();
return;
}
console.log(`${colors.green}Found CLI TypeScript source at: ${cliSourcePath}${colors.reset}`);
// Run the CLI using Deno
const denoArgs = [
'run',
'--allow-read',
'--allow-write',
'--allow-env',
'--allow-net',
'--allow-run',
cliSourcePath,
...process.argv.slice(2)
];
console.log(`${colors.blue}Running: deno ${denoArgs.join(' ')}${colors.reset}`);
// Spawn the Deno process
const denoProcess = spawn('deno', denoArgs, {
stdio: 'inherit',
env: process.env
});
// Handle process exit
denoProcess.on('exit', (code) => {
if (code !== 0) {
console.log(`${colors.red}CLI exited with code ${code}${colors.reset}`);
process.exit(code);
}
});
// Forward signals to the child process
['SIGINT', 'SIGTERM'].forEach(signal => {
process.on(signal, () => {
denoProcess.kill(signal);
});
});
}
/**
* Fallback to running the CLI using Node.js
*/
function runCliFallback() {
const cliPath = findCliScript();
if (!cliPath) {
console.log(`${colors.red}Error: Could not find any SPARC2 CLI script.${colors.reset}`);
console.log(`${colors.yellow}This could be due to an incomplete installation or build.${colors.reset}`);
console.log(`${colors.yellow}Try running 'npm run build' in the SPARC2 directory.${colors.reset}`);
process.exit(1);
}
console.log(`${colors.green}Found CLI at: ${cliPath}${colors.reset}`);
// Run the CLI using Node
const nodeArgs = [cliPath, ...process.argv.slice(2)];
console.log(`${colors.blue}Running: node ${nodeArgs.join(' ')}${colors.reset}`);
// Spawn the Node process
const nodeProcess = spawn('node', nodeArgs, {
stdio: 'inherit',
env: process.env
});
// Handle process exit
nodeProcess.on('exit', (code) => {
if (code !== 0) {
console.log(`${colors.red}CLI exited with code ${code}${colors.reset}`);
process.exit(code);
}
});
// Forward signals to the child process
['SIGINT', 'SIGTERM'].forEach(signal => {
process.on(signal, () => {
nodeProcess.kill(signal);
});
});
}
/**
* Run a simplified version of the CLI directly
*/
function runSimplifiedCli() {
console.log("OpenAI client initialized");
const args = process.argv.slice(2);
// Handle help and version flags
if (args.includes('--help') || args.includes('-h') || args.length === 0) {
printHelp();
return;
}
if (args.includes('--version') || args.includes('-v')) {
printVersion();
return;
}
// Handle supported commands with wrappers
if (['mcp', 'analyze', 'modify'].includes(args[0])) {
const wrapperName = `sparc2-${args[0]}-wrapper.js`;
const wrapperPath = path.join(__dirname, wrapperName);
if (fs.existsSync(wrapperPath)) {
console.log(`${colors.green}Found ${args[0]} wrapper at: ${wrapperPath}${colors.reset}`);
console.log(`${colors.blue}Running ${args[0]} command...${colors.reset}`);
// Spawn the process
const childProcess = spawn('node', [wrapperPath, ...args.slice(1)], {
stdio: 'inherit',
env: process.env
});
// Handle process exit
childProcess.on('exit', (code) => {
if (code !== 0) {
console.log(`${colors.red}Command exited with code ${code}${colors.reset}`);
process.exit(code);
}
});
// Forward signals to the child process
['SIGINT', 'SIGTERM'].forEach(signal => {
process.on(signal, () => {
childProcess.kill(signal);
});
});
return;
}
}
// For all other commands, print a message explaining the situation
console.log(`${colors.yellow}This is a simplified version of the SPARC2 CLI.${colors.reset}`);
console.log(`${colors.yellow}For full functionality, please run SPARC2 from a local installation.${colors.reset}`);
console.log(`${colors.yellow}You can clone the repository and run it locally:${colors.reset}`);
console.log(`${colors.blue}git clone https://github.com/agentics-org/sparc2.git${colors.reset}`);
console.log(`${colors.blue}cd sparc2${colors.reset}`);
console.log(`${colors.blue}npm install${colors.reset}`);
console.log(`${colors.blue}npm run build${colors.reset}`);
console.log(`${colors.blue}./sparc2 ${args.join(' ')}${colors.reset}`);
// Print help as a fallback
console.log("");
printHelp();
}
/**
* Print the CLI help message
*/
function printHelp() {
console.log("SPARC 2.0 CLI v2.0.24");
console.log("");
console.log("Usage: sparc2 <command> [options]");
console.log("");
console.log("Commands:");
console.log(" analyze Analyze code files for issues and improvements");
console.log(" modify Apply suggested modifications to code files");
console.log(" execute Execute code in a sandbox");
console.log(" search Search for similar code changes");
console.log(" checkpoint Create a git checkpoint");
console.log(" rollback Rollback to a previous checkpoint");
console.log(" config Manage configuration");
console.log(" api Start a Model Context Protocol (MCP) HTTP API server");
console.log(" mcp Start a Model Context Protocol (MCP) server using stdio transport");
console.log("");
console.log("Options:");
console.log(" --help, -h Show help");
console.log(" --version, -v Show version");
console.log("");
console.log("For command-specific help, run: sparc2 <command> --help");
}
/**
* Print the CLI version
*/
function printVersion() {
console.log("SPARC 2.0 CLI v2.0.24");
}
/**
* Display diagnostic information
*/
function showDiagnostics() {
console.log(`${colors.magenta}=== SPARC2 CLI Diagnostics ===${colors.reset}`);
// Check Node.js version
try {
const nodeVersion = execSync('node --version').toString().trim();
console.log(`${colors.green}Node.js version: ${nodeVersion}${colors.reset}`);
} catch (error) {
console.log(`${colors.red}Failed to get Node.js version: ${error.message}${colors.reset}`);
}
// Check Deno version
try {
const denoVersion = execSync('deno --version').toString().trim().split('\n')[0];
console.log(`${colors.green}Deno version: ${denoVersion}${colors.reset}`);
} catch (error) {
console.log(`${colors.red}Deno is not installed or not in PATH${colors.reset}`);
}
// Check npm version
try {
const npmVersion = execSync('npm --version').toString().trim();
console.log(`${colors.green}npm version: ${npmVersion}${colors.reset}`);
} catch (error) {
console.log(`${colors.red}Failed to get npm version: ${error.message}${colors.reset}`);
}
// Check SPARC2 package version
try {
const packageJsonPath = path.join(__dirname, 'package.json');
if (fs.existsSync(packageJsonPath)) {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
console.log(`${colors.green}SPARC2 package version: ${packageJson.version}${colors.reset}`);
} else {
console.log(`${colors.yellow}Could not find package.json${colors.reset}`);
}
} catch (error) {
console.log(`${colors.red}Failed to read package.json: ${error.message}${colors.reset}`);
}
// Check if running from node_modules
const isGlobal = isRunningFromNodeModules();
console.log(`${colors.green}Running from node_modules: ${isGlobal}${colors.reset}`);
// Check for CLI TypeScript source
const cliSourcePath = findCliSourceFile();
if (cliSourcePath) {
console.log(`${colors.green}Found CLI TypeScript source at: ${cliSourcePath}${colors.reset}`);
} else {
console.log(`${colors.yellow}Could not find CLI TypeScript source${colors.reset}`);
}
// Check for CLI script
const cliPath = findCliScript();
if (cliPath) {
console.log(`${colors.green}Found CLI script at: ${cliPath}${colors.reset}`);
} else {
console.log(`${colors.red}Could not find CLI script${colors.reset}`);
}
// Check current directory
console.log(`${colors.green}Current directory: ${process.cwd()}${colors.reset}`);
console.log(`${colors.green}Script directory: ${__dirname}${colors.reset}`);
console.log(`${colors.magenta}=== End of Diagnostics ===${colors.reset}`);
}
// Main execution
if (process.argv.includes('--diagnostics')) {
showDiagnostics();
process.exit(0);
}
if (!isDenoInstalled()) {
printDenoInstallInstructions();
process.exit(1);
}
// If running from node_modules, use the simplified CLI
if (isRunningFromNodeModules()) {
console.log(`${colors.yellow}Running from global installation, using simplified CLI${colors.reset}`);
runSimplifiedCli();
} else {
// Otherwise, try to run with Deno first (directly from TypeScript)
runCliWithDeno();
}