intent-cli
Version:
A fully functional CLI built with TypeScript and modern tools
551 lines ⢠20.5 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fileCommand = void 0;
const commander_1 = require("commander");
const chalk_1 = __importDefault(require("chalk"));
const inquirer_1 = __importDefault(require("inquirer"));
const spinner_1 = require("../utils/spinner");
const logger_1 = require("../utils/logger");
const promises_1 = require("fs/promises");
const path_1 = require("path");
exports.fileCommand = new commander_1.Command('file')
.description('File management utilities')
.option('-a, --action <action>', 'Action to perform (create, read, list, search, copy, move, delete, organize)')
.option('-p, --path <path>', 'File or directory path')
.option('-c, --content <content>', 'Content for file creation')
.option('--pattern <pattern>', 'Search pattern for files')
.option('-d, --destination <destination>', 'Destination path for copy/move')
.option('-i, --interactive', 'Interactive mode', false)
.option('-r, --recursive', 'Recursive for directory operations', false)
.action(async (options) => {
try {
const result = await executeFileCommand(options);
handleResult(result);
}
catch (error) {
handleError(error);
}
});
async function executeFileCommand(options) {
logger_1.logger.debug('Executing file command with options:', options);
if (options.interactive || !options.action) {
return await interactiveFileMode();
}
switch (options.action) {
case 'create':
return await createFile(options.path, options.content);
case 'read':
return await readFileContent(options.path);
case 'list':
return await listDirectory(options.path, options.recursive);
case 'search':
return await searchFiles(options.path, options.pattern, options.recursive);
case 'copy':
return await copyFileOrDirectory(options.path, options.destination);
case 'move':
return await moveFileOrDirectory(options.path, options.destination);
case 'delete':
return await deleteFileOrDirectory(options.path);
case 'organize':
return await organizeDirectory(options.path);
default:
return {
success: false,
error: new Error(`Unknown action: ${options.action}`)
};
}
}
async function interactiveFileMode() {
console.log(chalk_1.default.cyan.bold('š File Management Mode'));
console.log(chalk_1.default.dim('Choose a file operation to perform.\n'));
const { action } = await inquirer_1.default.prompt([
{
type: 'list',
name: 'action',
message: 'What would you like to do?',
choices: [
{ name: 'š Create a new file', value: 'create' },
{ name: 'š Read a file', value: 'read' },
{ name: 'š List directory contents', value: 'list' },
{ name: 'š Search for files', value: 'search' },
{ name: 'š Copy file/directory', value: 'copy' },
{ name: 'āļø Move file/directory', value: 'move' },
{ name: 'šļø Delete file/directory', value: 'delete' },
{ name: 'šļø Organize directory', value: 'organize' },
],
},
]);
const answers = await getActionSpecificInputs(action);
const options = {
action,
interactive: true,
...answers,
};
return await executeFileCommand(options);
}
async function getActionSpecificInputs(action) {
const commonQuestions = [];
switch (action) {
case 'create':
return await inquirer_1.default.prompt([
{
type: 'input',
name: 'path',
message: 'Enter file path:',
validate: (input) => {
if (!input.trim()) {
return 'File path is required';
}
return true;
},
},
{
type: 'input',
name: 'content',
message: 'Enter file content (press Enter when done):',
default: '',
},
]);
case 'read':
return await inquirer_1.default.prompt([
{
type: 'input',
name: 'path',
message: 'Enter file path to read:',
validate: (input) => {
if (!input.trim()) {
return 'File path is required';
}
return true;
},
},
]);
case 'list':
return await inquirer_1.default.prompt([
{
type: 'input',
name: 'path',
message: 'Enter directory path:',
default: '.',
},
{
type: 'confirm',
name: 'recursive',
message: 'List recursively?',
default: false,
},
]);
case 'search':
return await inquirer_1.default.prompt([
{
type: 'input',
name: 'path',
message: 'Search directory:',
default: '.',
},
{
type: 'input',
name: 'pattern',
message: 'Search pattern (wildcards supported):',
validate: (input) => {
if (!input.trim()) {
return 'Search pattern is required';
}
return true;
},
},
{
type: 'confirm',
name: 'recursive',
message: 'Search recursively?',
default: true,
},
]);
case 'copy':
case 'move':
return await inquirer_1.default.prompt([
{
type: 'input',
name: 'path',
message: `Enter ${action} source path:`,
validate: (input) => {
if (!input.trim()) {
return 'Source path is required';
}
return true;
},
},
{
type: 'input',
name: 'destination',
message: `Enter ${action} destination path:`,
validate: (input) => {
if (!input.trim()) {
return 'Destination path is required';
}
return true;
},
},
]);
case 'delete':
return await inquirer_1.default.prompt([
{
type: 'input',
name: 'path',
message: 'Enter path to delete:',
validate: (input) => {
if (!input.trim()) {
return 'Path is required';
}
return true;
},
},
{
type: 'confirm',
name: 'confirm',
message: 'Are you sure you want to delete this?',
default: false,
},
]);
case 'organize':
return await inquirer_1.default.prompt([
{
type: 'input',
name: 'path',
message: 'Enter directory path to organize:',
default: '.',
},
]);
default:
return {};
}
}
async function createFile(path, content) {
if (!path) {
return {
success: false,
error: new Error('File path is required'),
};
}
const spinner = (0, spinner_1.createSpinner)();
spinner.start('Creating file...');
try {
// Ensure directory exists
const dir = (0, path_1.dirname)(path);
await (0, promises_1.mkdir)(dir, { recursive: true });
// Write file content
const fileContent = content || '';
await (0, promises_1.writeFile)(path, fileContent, 'utf8');
spinner.succeed(`File created: ${chalk_1.default.cyan(path)}`);
return {
success: true,
message: `File created successfully at ${path}`,
data: { path, content: fileContent, size: fileContent.length },
};
}
catch (error) {
spinner.fail('Failed to create file');
throw error;
}
}
async function readFileContent(path) {
if (!path) {
return {
success: false,
error: new Error('File path is required'),
};
}
const spinner = (0, spinner_1.createSpinner)();
spinner.start('Reading file...');
try {
const stats = await (0, promises_1.stat)(path);
const content = await (0, promises_1.readFile)(path, 'utf8');
spinner.succeed(`File read: ${chalk_1.default.cyan(path)}`);
console.log(chalk_1.default.green.bold('\nš File Content:'));
console.log(chalk_1.default.dim(`Path: ${path}`));
console.log(chalk_1.default.dim(`Size: ${stats.size} bytes`));
console.log(chalk_1.default.dim(`Last modified: ${stats.mtime.toLocaleString()}`));
console.log('');
// Display content with line numbers
const lines = content.split('\n');
const maxLineNum = lines.length.toString().length;
lines.forEach((line, index) => {
const lineNumber = (index + 1).toString().padStart(maxLineNum, ' ');
const code = line || ' ';
console.log(chalk_1.default.dim(`${lineNumber} ā`) + ' ' + code);
});
return {
success: true,
message: `File read successfully (${content.length} characters)`,
data: { path, content, size: stats.size },
};
}
catch (error) {
spinner.fail('Failed to read file');
throw error;
}
}
async function listDirectory(path, recursive = false) {
const dirPath = path || '.';
const spinner = (0, spinner_1.createSpinner)();
spinner.start('Listing directory...');
try {
const items = await (0, promises_1.readdir)(dirPath, { withFileTypes: true });
spinner.succeed(`Directory listed: ${chalk_1.default.cyan(dirPath)}`);
console.log(chalk_1.default.green.bold(`\nš Contents of ${dirPath}:`));
if (items.length === 0) {
console.log(chalk_1.default.yellow(' (empty directory)'));
}
else {
for (const item of items) {
const itemPath = (0, path_1.join)(dirPath, item.name);
const stats = await (0, promises_1.stat)(itemPath);
const isDir = item.isDirectory();
const icon = isDir ? 'š' : 'š';
const name = isDir ? chalk_1.default.blue.bold(item.name) : item.name;
const size = isDir ? '' : ` (${stats.size} bytes)`;
const modified = stats.mtime.toLocaleDateString();
console.log(` ${icon} ${name}${chalk_1.default.dim(size)} ${chalk_1.default.dim(`[${modified}]`)}`);
// If recursive and it's a directory, list its contents
if (recursive && isDir && item.name !== '.' && item.name !== '..') {
const subResult = await listDirectory(itemPath, false);
if (subResult.success && subResult.data) {
console.log(chalk_1.default.dim(' āā ' + '-'.repeat(30)));
}
}
}
}
const stats = await (0, promises_1.stat)(dirPath);
return {
success: true,
message: `Listed ${items.length} items`,
data: { path: dirPath, itemCount: items.length, isDirectory: stats.isDirectory() },
};
}
catch (error) {
spinner.fail('Failed to list directory');
throw error;
}
}
async function searchFiles(path, pattern, recursive = true) {
const searchPath = path || '.';
const searchPattern = pattern || '*';
if (!pattern) {
return {
success: false,
error: new Error('Search pattern is required'),
};
}
const spinner = (0, spinner_1.createSpinner)();
spinner.start('Searching files...');
try {
const results = await searchInDirectory(searchPath, searchPattern, recursive);
spinner.succeed(`Search completed in ${chalk_1.default.cyan(searchPath)}`);
console.log(chalk_1.default.green.bold(`\nš Search Results for "${pattern}":`));
if (results.length === 0) {
console.log(chalk_1.default.yellow(' No files found'));
}
else {
results.forEach((filePath, index) => {
console.log(` ${chalk_1.default.dim(`${index + 1}.`)} ${chalk_1.default.cyan(filePath)}`);
});
}
return {
success: true,
message: `Found ${results.length} matching files`,
data: { pattern, path: searchPath, results, count: results.length },
};
}
catch (error) {
spinner.fail('Search failed');
throw error;
}
}
async function searchInDirectory(dir, pattern, recursive) {
const results = [];
const items = await (0, promises_1.readdir)(dir, { withFileTypes: true });
// Simple wildcard matching (can be enhanced)
const regexPattern = pattern
.replace(/\*/g, '.*')
.replace(/\?/g, '.');
const regex = new RegExp(regexPattern, 'i');
for (const item of items) {
const itemPath = (0, path_1.join)(dir, item.name);
if (regex.test(item.name)) {
results.push(itemPath);
}
if (recursive && item.isDirectory() && item.name !== '.' && item.name !== '..') {
const subResults = await searchInDirectory(itemPath, pattern, recursive);
results.push(...subResults);
}
}
return results;
}
async function copyFileOrDirectory(source, destination) {
if (!source || !destination) {
return {
success: false,
error: new Error('Both source and destination paths are required'),
};
}
const spinner = (0, spinner_1.createSpinner)();
spinner.start('Copying...');
try {
const sourceStats = await (0, promises_1.stat)(source);
if (sourceStats.isDirectory()) {
await copyDirectory(source, destination);
}
else {
await (0, promises_1.copyFile)(source, destination);
}
spinner.succeed(`Copied to ${chalk_1.default.cyan(destination)}`);
return {
success: true,
message: `Successfully copied ${source} to ${destination}`,
data: { source, destination, isDirectory: sourceStats.isDirectory() },
};
}
catch (error) {
spinner.fail('Copy failed');
throw error;
}
}
async function copyDirectory(source, destination) {
await (0, promises_1.mkdir)(destination, { recursive: true });
const items = await (0, promises_1.readdir)(source, { withFileTypes: true });
for (const item of items) {
const sourcePath = (0, path_1.join)(source, item.name);
const destPath = (0, path_1.join)(destination, item.name);
if (item.isDirectory()) {
await copyDirectory(sourcePath, destPath);
}
else {
await (0, promises_1.copyFile)(sourcePath, destPath);
}
}
}
async function moveFileOrDirectory(source, destination) {
if (!source || !destination) {
return {
success: false,
error: new Error('Both source and destination paths are required'),
};
}
const spinner = (0, spinner_1.createSpinner)();
spinner.start('Moving...');
try {
await (0, promises_1.rename)(source, destination);
spinner.succeed(`Moved to ${chalk_1.default.cyan(destination)}`);
return {
success: true,
message: `Successfully moved ${source} to ${destination}`,
data: { source, destination },
};
}
catch (error) {
spinner.fail('Move failed');
throw error;
}
}
async function deleteFileOrDirectory(path) {
if (!path) {
return {
success: false,
error: new Error('Path is required'),
};
}
const spinner = (0, spinner_1.createSpinner)();
spinner.start('Deleting...');
try {
const stats = await (0, promises_1.stat)(path);
if (stats.isDirectory()) {
await deleteDirectory(path);
}
else {
await (0, promises_1.unlink)(path);
}
spinner.succeed(`Deleted: ${chalk_1.default.cyan(path)}`);
return {
success: true,
message: `Successfully deleted ${path}`,
data: { path, wasDirectory: stats.isDirectory() },
};
}
catch (error) {
spinner.fail('Delete failed');
throw error;
}
}
async function deleteDirectory(dirPath) {
const items = await (0, promises_1.readdir)(dirPath, { withFileTypes: true });
for (const item of items) {
const itemPath = (0, path_1.join)(dirPath, item.name);
if (item.isDirectory()) {
await deleteDirectory(itemPath);
}
else {
await (0, promises_1.unlink)(itemPath);
}
}
// Remove the empty directory
await (0, promises_1.unlink)(dirPath);
}
async function organizeDirectory(path) {
const dirPath = path || '.';
const spinner = (0, spinner_1.createSpinner)();
spinner.start('Organizing directory...');
try {
const items = await (0, promises_1.readdir)(dirPath, { withFileTypes: true });
const fileItems = items.filter(item => !item.isDirectory());
let organizedCount = 0;
for (const item of fileItems) {
const filePath = (0, path_1.join)(dirPath, item.name);
const extension = (0, path_1.extname)(item.name).toLowerCase();
if (extension) {
const folderName = extension.substring(1); // Remove the dot
const targetDir = (0, path_1.join)(dirPath, folderName);
// Create folder if it doesn't exist
await (0, promises_1.mkdir)(targetDir, { recursive: true });
// Move file to appropriate folder
const targetPath = (0, path_1.join)(targetDir, item.name);
await (0, promises_1.rename)(filePath, targetPath);
organizedCount++;
}
}
spinner.succeed(`Organized ${organizedCount} files`);
return {
success: true,
message: `Successfully organized ${organizedCount} files in ${dirPath}`,
data: { path: dirPath, organizedCount },
};
}
catch (error) {
spinner.fail('Organization failed');
throw error;
}
}
function handleResult(result) {
if (result.success) {
logger_1.logger.info('File command executed successfully');
if (result.message) {
logger_1.logger.debug(`Result: ${result.message}`);
}
}
else {
handleError(result.error);
}
}
function handleError(error) {
logger_1.logger.error('File command failed:', error);
if (error instanceof Error) {
console.error(chalk_1.default.red('Error:'), error.message);
}
else {
console.error(chalk_1.default.red('An unknown error occurred'));
}
process.exit(1);
}
//# sourceMappingURL=file.js.map