@nestbox-ai/cli
Version:
The cli tools that helps developers to build agents
154 lines (123 loc) • 4.36 kB
text/typescript
import path from "path";
import fs from 'fs';
import chalk from "chalk";
import ora from "ora";
import { promisify } from "util";
import { exec } from "child_process";
import AdmZip from "adm-zip";
import * as os from 'os';
import axios from "axios";
const execAsync = promisify(exec);
export async function findProjectRoot(startDir = process.cwd()) {
let currentDir = startDir;
while (currentDir !== path.parse(currentDir).root) {
const nestboxConfigPath = path.join(currentDir, 'nestbox.config.json');
const packageJsonPath = path.join(currentDir, 'package.json');
if (fs.existsSync(nestboxConfigPath) || fs.existsSync(packageJsonPath)) {
return currentDir;
}
currentDir = path.dirname(currentDir);
}
return startDir; // Fallback to current directory if no root markers found
}
// Function to load and parse nestbox.config.json if it exists
export function loadNestboxConfig(projectRoot: any) {
const configPath = path.join(projectRoot, 'nestbox.config.json');
if (fs.existsSync(configPath)) {
try {
const configContent = fs.readFileSync(configPath, 'utf8');
return JSON.parse(configContent);
} catch (error: any) {
console.warn(chalk.yellow(`Warning: Error parsing nestbox.config.json: ${error.message}`));
}
}
return null;
}
// Function to detect if a directory contains TypeScript files
export function isTypeScriptProject(directoryPath: any) {
// Check for tsconfig.json
if (fs.existsSync(path.join(directoryPath, 'tsconfig.json'))) {
return true;
}
// Check for .ts files
try {
const files = fs.readdirSync(directoryPath);
return files.some(file => file.endsWith('.ts') || file.endsWith('.tsx'));
} catch (error) {
return false;
}
}
export async function runPredeployScripts(scripts: any, projectRoot: any) {
if (!scripts || !Array.isArray(scripts) || scripts.length === 0) {
return;
}
const spinner = ora('Running predeploy scripts...').start();
try {
for (const script of scripts) {
spinner.text = `Running: ${script}`;
// Make sure we're running in the correct directory
await execAsync(script, {
cwd: projectRoot,
});
}
spinner.succeed('Predeploy scripts completed successfully');
} catch (error: any) {
spinner.fail(`Predeploy script failed: ${error.message}`);
throw new Error(`Predeploy failed: ${error.message}`);
}
}
export function createZipFromDirectory(dirPath: any, excludePatterns = ['node_modules']) {
const dirName = path.basename(dirPath);
const timestamp = Date.now();
// Create zip in temp directory
const tempZipFilePath = path.join(os.tmpdir(), `${dirName}_${timestamp}.zip`);
const zip = new AdmZip();
// Function to recursively add files to zip
function addFilesToZip(currentPath: any, relativePath = '') {
const items = fs.readdirSync(currentPath);
for (const item of items) {
const itemPath = path.join(currentPath, item);
const itemRelativePath = path.join(relativePath, item);
// Check if item should be excluded
if (excludePatterns.some((pattern: any) =>
typeof pattern === 'string' ? itemRelativePath === pattern || item === pattern :
pattern.test(itemRelativePath)
)) {
continue;
}
const stats = fs.statSync(itemPath);
if (stats.isDirectory()) {
addFilesToZip(itemPath, itemRelativePath);
} else {
zip.addLocalFile(itemPath, path.dirname(itemRelativePath));
}
}
}
addFilesToZip(dirPath);
// Write zip to temp directory (for upload)
zip.writeZip(tempZipFilePath);
// Return the temp path for upload
return tempZipFilePath;
}
export interface TemplateInfo {
name: string;
description: string;
fileId: string;
lang: string;
type: string;
}
export function createNestboxConfig(projectPath: string, isTypeScript: boolean): void {
if (!isTypeScript) return;
const configPath = path.join(projectPath, 'nestbox.config.json');
const config = {
agents: {
predeploy: [
'rm -rf dist',
'npm run lint',
'npm run build'
]
}
};
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
console.log(chalk.green(`Created nestbox.config.json at ${configPath}`));
}