diff --git a/src/cli/interactive.js b/src/cli/interactive.js index d0e3e0d9..6b9ef15e 100644 --- a/src/cli/interactive.js +++ b/src/cli/interactive.js @@ -1,8 +1,42 @@ +import readline from 'readline'; + const interactive = () => { - // Write your code here - // Use readline module for interactive CLI - // Support commands: uptime, cwd, date, exit - // Handle Ctrl+C and unknown commands + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + prompt: '> ', + }); + + rl.prompt(); + + rl.on('line', (line) => { + const command = line.trim(); + + switch (command) { + case 'uptime': + console.log(`Uptime: ${process.uptime().toFixed(2)}s`); + break; + case 'cwd': + console.log(process.cwd()); + break; + case 'date': + console.log(new Date().toISOString()); + break; + case 'exit': + console.log('Goodbye!'); + process.exit(0); + break; + default: + console.log('Unknown command'); + } + + rl.prompt(); + }); + + rl.on('close', () => { + console.log('Goodbye!'); + process.exit(0); + }); }; interactive(); diff --git a/src/cli/progress.js b/src/cli/progress.js index 3e060763..05222c54 100644 --- a/src/cli/progress.js +++ b/src/cli/progress.js @@ -1,8 +1,61 @@ +const args = process.argv.slice(2); + +const RESET = '\x1b[0m'; + +const getArg = (name) => { + const index = args.indexOf(name); + if (index === -1 || index + 1 >= args.length) return undefined; + return args[index + 1]; +}; + +const getNumericArg = (name, defaultValue) => { + const raw = getArg(name); + if (raw === undefined) return defaultValue; + const parsed = parseInt(raw, 10); + return Number.isNaN(parsed) ? defaultValue : parsed; +}; + +const parseHexColor = (hex) => { + if (!hex) return null; + const match = hex.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/); + if (!match) return null; + const r = parseInt(match[1], 16); + const g = parseInt(match[2], 16); + const b = parseInt(match[3], 16); + return `\x1b[38;2;${r};${g};${b}m`; +}; + +const renderBar = (percent, length, colorCode) => { + const filled = Math.round((percent / 100) * length); + const empty = length - filled; + + const filledBar = '█'.repeat(filled); + const emptyBar = ' '.repeat(empty); + + const coloredFilled = colorCode ? `${colorCode}${filledBar}${RESET}` : filledBar; + return `[${coloredFilled}${emptyBar}] ${percent}%`; +}; + const progress = () => { - // Write your code here - // Simulate progress bar from 0% to 100% over ~5 seconds - // Update in place using \r every 100ms - // Format: [████████████████████ ] 67% + const duration = getNumericArg('--duration', 5000); + const interval = getNumericArg('--interval', 100); + const length = getNumericArg('--length', 30); + const colorCode = parseHexColor(getArg('--color')); + + const totalSteps = Math.ceil(duration / interval); + let currentStep = 0; + + const timer = setInterval(() => { + currentStep++; + const percent = Math.min(Math.round((currentStep / totalSteps) * 100), 100); + + process.stdout.write(`\r${renderBar(percent, length, colorCode)}`); + + if (currentStep >= totalSteps) { + clearInterval(timer); + process.stdout.write('\nDone!\n'); + } + }, interval); }; progress(); diff --git a/src/fs/snapshot.js b/src/fs/snapshot.js index 050103d3..36e80214 100644 --- a/src/fs/snapshot.js +++ b/src/fs/snapshot.js @@ -1,9 +1,62 @@ +import { promises as fs } from 'fs'; +import path from 'path'; + +async function scanDirectory(dirPath, relativePath = '') { + try { + const entries = []; + const items = await fs.readdir(dirPath); + items.sort(); + + for (const item of items) { + const fullPath = path.join(dirPath, item); + const relPath = path.join(relativePath, item); + const stats = await fs.stat(fullPath); + + if (stats.isDirectory()) { + entries.push({ path: relPath, type: 'directory' }); + const subEntries = await scanDirectory(fullPath, relPath); + entries.push(...subEntries); + } else if (stats.isFile()) { + const buffer = await fs.readFile(fullPath); + entries.push({ + path: relPath, + type: 'file', + size: stats.size, + content: buffer.toString('base64'), + }); + } + } + + return entries; + } catch (error) { + throw new Error(`FS operation failed: ${error.message}`); + } +} + const snapshot = async () => { - // Write your code here - // Recursively scan workspace directory - // Write snapshot.json with: - // - rootPath: absolute path to workspace - // - entries: flat array of relative paths and metadata + const workspacePath = path.join(process.cwd(), 'workspace'); + try { + await fs.access(workspacePath); + } catch (error) { + throw new Error(`FS operation failed: ${error.message}`); + } + + const entries = await scanDirectory(workspacePath); + + const result = { + rootPath: workspacePath, + entries, + }; + + const snapshotPath = path.join(path.dirname(workspacePath), 'snapshot.json'); + try { + await fs.writeFile(snapshotPath, JSON.stringify(result, null, 2)); + } catch (error) { + throw new Error(`FS operation failed: ${error.message}`); + } }; -await snapshot(); +await snapshot().catch((error) => { + console.error(error.message); + process.exit(1); +}); diff --git a/src/modules/dynamic.js b/src/modules/dynamic.js index 008ca387..f8bf276f 100644 --- a/src/modules/dynamic.js +++ b/src/modules/dynamic.js @@ -1,9 +1,13 @@ const dynamic = async () => { - // Write your code here - // Accept plugin name as CLI argument - // Dynamically import plugin from plugins/ directory - // Call run() function and print result - // Handle missing plugin case + const args = process.argv.slice(2); + const pluginName = args.at(-1); + try { + const plugin = await import(`./plugins/${pluginName}.js`); + console.log(plugin.run()); + } catch (error) { + console.error(`Plugin not found`); + process.exit(1); + } }; await dynamic(); diff --git a/src/streams/lineNumberer.js b/src/streams/lineNumberer.js index 579d662e..44d7aa74 100644 --- a/src/streams/lineNumberer.js +++ b/src/streams/lineNumberer.js @@ -1,8 +1,25 @@ +import { Transform } from 'node:stream'; + +const addLineNumbers = (chunk, counter) => + chunk + .toString() + .split('\n') + .map((line, i) => { + if (i === 0 && line === '') return ''; + return `${counter.value++} | ${line}`; + }) + .join('\n'); + +const counter = { value: 1 }; + +const transform = new Transform({ + transform(chunk, enc, cb) { + cb(null, addLineNumbers(chunk, counter)); + }, +}); + const lineNumberer = () => { - // Write your code here - // Read from process.stdin - // Use Transform Stream to prepend line numbers - // Write to process.stdout + process.stdin.pipe(transform).pipe(process.stdout); }; lineNumberer();