From bedacfb0c9785d4a9ca59d8aba6d004bfd0b0d77 Mon Sep 17 00:00:00 2001 From: andreitsylko Date: Sun, 8 Mar 2026 20:39:11 +0100 Subject: [PATCH 1/3] feat: implement CLI --- src/cli/interactive.js | 37 +++++++++++++++++++++++++++++++++---- src/cli/progress.js | 22 ++++++++++++++++++---- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/cli/interactive.js b/src/cli/interactive.js index d0e3e0d9..145e5d92 100644 --- a/src/cli/interactive.js +++ b/src/cli/interactive.js @@ -1,8 +1,37 @@ +import readline from 'readline'; + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdoutdate +}); + +const commands = { + uptime: () => process.stdout.write(`${process.uptime()}\n`), + cwd: () => process.stdout.write(`${process.cwd()}\n`), + date: () => process.stdout.write(`${new Date()}\n`), + exit: () => { + process.stdout.write('\nGoodbye!\n'); + rl.close(); + process.exit(); + }, +}; + const interactive = () => { - // Write your code here - // Use readline module for interactive CLI - // Support commands: uptime, cwd, date, exit - // Handle Ctrl+C and unknown commands + rl.question('> ', (answer) => { + if (commands[answer]) { + commands[answer](); + } else { + process.stdout.write(`Unknown command\n`); + } + if (answer !== 'exit') { + interactive(); + } + }); }; +rl.on('SIGINT', () => { + process.stdout.write('\nGoodbye!\n'); + process.exit(); +}); + interactive(); diff --git a/src/cli/progress.js b/src/cli/progress.js index 3e060763..d3475bb2 100644 --- a/src/cli/progress.js +++ b/src/cli/progress.js @@ -1,8 +1,22 @@ +const printBar = (percent) => { + const total = 20; + const filled = Math.floor(total * percent / 100); + const empty = total - filled; + const bar = '█'.repeat(filled) + '░'.repeat(empty); + process.stdout.write(`\r[${bar}] ${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% + let percent = 0; + let fiveSecondsLimitThreshold = 2; + const interval = setInterval(() => { + printBar(percent); + percent += fiveSecondsLimitThreshold; + if (percent > 100) { + clearInterval(interval); + process.stdout.write('\n'); + } + }, 100); }; progress(); From 1d53c90cba3eca8d026edc0ae4a85f7bf168a677 Mon Sep 17 00:00:00 2001 From: andreitsylko Date: Sun, 8 Mar 2026 21:00:00 +0100 Subject: [PATCH 2/3] fix: update progress logic --- src/cli/progress.js | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/cli/progress.js b/src/cli/progress.js index d3475bb2..858d3955 100644 --- a/src/cli/progress.js +++ b/src/cli/progress.js @@ -1,5 +1,16 @@ +const args = process.argv.slice(2); + +const getArg = (name) => { + const idx = args.indexOf(`--${name}`); + return idx !== -1 ? args[idx + 1] : undefined; +}; + +const duration = parseInt(getArg('duration') ?? '5000'); +const interval = parseInt(getArg('interval') ?? '100'); +const length = parseInt(getArg('length') ?? '30'); + const printBar = (percent) => { - const total = 20; + const total = 30; const filled = Math.floor(total * percent / 100); const empty = total - filled; const bar = '█'.repeat(filled) + '░'.repeat(empty); @@ -7,14 +18,17 @@ const printBar = (percent) => { }; const progress = () => { - let percent = 0; - let fiveSecondsLimitThreshold = 2; - const interval = setInterval(() => { + const steps = Math.floor(duration / interval); + const stepPercent = 100 / steps; + let elapsed = 0; + + const intervalId = setInterval(() => { + elapsed++; + const percent = Math.min(Math.round(elapsed * stepPercent), 100); printBar(percent); - percent += fiveSecondsLimitThreshold; - if (percent > 100) { - clearInterval(interval); - process.stdout.write('\n'); + if (percent >= 100) { + clearInterval(intervalId); + process.stdout.write('\nDone!\n'); } }, 100); }; From d22868f81f73b3eabf9863c3e6cab17b73fc8d9a Mon Sep 17 00:00:00 2001 From: andreitsylko Date: Sun, 8 Mar 2026 21:21:04 +0100 Subject: [PATCH 3/3] feat: add hash --- src/cli/progress.js | 5 ++--- src/hash/verify.js | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/cli/progress.js b/src/cli/progress.js index 858d3955..f4c44f7b 100644 --- a/src/cli/progress.js +++ b/src/cli/progress.js @@ -10,9 +10,8 @@ const interval = parseInt(getArg('interval') ?? '100'); const length = parseInt(getArg('length') ?? '30'); const printBar = (percent) => { - const total = 30; - const filled = Math.floor(total * percent / 100); - const empty = total - filled; + const filled = Math.floor(length * percent / 100); + const empty = length - filled; const bar = '█'.repeat(filled) + '░'.repeat(empty); process.stdout.write(`\r[${bar}] ${percent}%`); }; diff --git a/src/hash/verify.js b/src/hash/verify.js index 7f1e8961..1400086a 100644 --- a/src/hash/verify.js +++ b/src/hash/verify.js @@ -1,8 +1,33 @@ -const verify = async () => { - // Write your code here - // Read checksums.json - // Calculate SHA256 hash using Streams API - // Print result: filename — OK/FAIL +import crypto from 'node:crypto'; +import fs from 'node:fs'; +import { pipeline } from 'node:stream/promises'; +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; + +export const verify = async () => { + const __dirname = path.dirname(fileURLToPath(import.meta.url)); + const file = path.join(__dirname, 'checksums.json'); + if (!fs.existsSync(file)) { + throw new Error('FS operation failed'); + } + + const checksums = JSON.parse(fs.readFileSync(file, 'utf8')); + + for (const [filename, storedHash] of Object.entries(checksums)) { + const relativePath = path.join(__dirname, filename); + if (!fs.existsSync(relativePath)) { + throw new Error('FS operation failed'); + } + + const stream = fs.createReadStream(relativePath); + const hash = crypto.createHash('sha256'); + + await pipeline(stream, hash); + + const result = hash.digest('hex'); + const status = result === storedHash ? 'OK' : 'FAIL'; + console.log(`${filename} — ${status}`); + } }; await verify();