@pompeii-labs/cli
Version:
Magma CLI
188 lines (186 loc) • 5.15 kB
JavaScript
import chalk from "chalk";
const MAGMA_COLOR = "#FF7500";
class Spinner {
constructor(message) {
this.frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
this.i = 0;
this.message = message;
}
start() {
this.intervalId = setInterval(() => {
const frame = this.frames[this.i];
process.stdout.write(`\r${UI.colors.white}${frame}${UI.colors.reset} ${this.message}`);
this.i = (this.i + 1) % this.frames.length;
}, 80);
return this;
}
stop() {
if (this.intervalId) {
clearInterval(this.intervalId);
process.stdout.write("\r\x1B[K");
}
return this;
}
succeed(finalMessage) {
this.stop();
process.stdout.write(
`\r${UI.colors.green}\u2713${UI.colors.reset} ${finalMessage || this.message}
`
);
return this;
}
fail(finalMessage) {
this.stop();
process.stdout.write(
`\r${UI.colors.red}\u2716${UI.colors.reset} ${finalMessage || this.message}
`
);
return this;
}
}
class ThinkingSpinner {
constructor() {
this.interval = null;
this.frames = ["thinking", "thinking.", "thinking..", "thinking..."];
this.currentFrame = 0;
}
start() {
this.interval = setInterval(() => {
process.stdout.write("\r\x1B[K");
process.stdout.write(chalk.dim(this.frames[this.currentFrame]));
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
}, 500);
}
stop() {
if (this.interval) {
clearInterval(this.interval);
process.stdout.write("\r\x1B[K");
}
}
}
class ProgressBar {
constructor(total, options) {
this.current = 0;
this.total = total;
this.width = options?.width || 30;
this.message = options?.message;
}
render() {
const percent = Math.round(this.current / this.total * 100);
const filled = Math.round(this.current / this.total * this.width);
const empty = this.width - filled;
const filledBar = "\u2588".repeat(filled);
const emptyBar = "\u2591".repeat(empty);
const bar = `${UI.colors.cyan}${filledBar}${UI.colors.dim}${emptyBar}${UI.colors.reset}`;
const percentage = `${percent}%`;
const message = this.message ? ` ${this.message}` : "";
process.stdout.write(`\r${bar} ${percentage}${message}`);
}
update(n) {
this.current = n;
this.render();
if (this.current === this.total) {
process.stdout.write("\n");
}
return this;
}
increment(n = 1) {
this.current = Math.min(this.current + n, this.total);
this.render();
if (this.current === this.total) {
process.stdout.write("\n");
}
return this;
}
}
class UI {
static {
this.colors = {
reset: "\x1B[0m",
cyan: "\x1B[36m",
green: "\x1B[32m",
red: "\x1B[31m",
dim: "\x1B[2m",
blue: "\x1B[34m",
white: "\x1B[37m",
orange: "\x1B[38;5;208m"
};
}
static spinner(message) {
return new Spinner(message);
}
static thinkingSpinner() {
return new ThinkingSpinner();
}
static progress(total, options) {
return new ProgressBar(total, options);
}
}
const magma = (text, bold = true) => chalk.hex(MAGMA_COLOR)(bold ? chalk.bold(text) : text);
class MagmaFlow {
// How many frames to complete a full cycle
constructor(asciiArt, staticContent) {
this.interval = null;
this.position = 0;
this.CYCLE_LENGTH = 200;
this.text = asciiArt.split("\n");
this.staticContent = staticContent;
}
getColorGradient(position, charPosition) {
const offset = (-charPosition + position) % this.CYCLE_LENGTH;
const baseR = 255;
const baseG = 140;
const baseB = 0;
const wave1 = Math.sin(offset * 0.1) * 0.2;
const wave2 = Math.sin(offset * 0.05) * 0.1;
const brightness = 0.7 + wave1 + wave2;
const r = Math.floor(baseR * Math.min(Math.max(brightness, 0.4), 1));
const g = Math.floor(baseG * Math.min(Math.max(brightness, 0.4), 1));
const b = Math.floor(baseB * Math.min(Math.max(brightness, 0.4), 1));
return `\x1B[38;2;${r};${g};${b}m`;
}
renderFrame(position) {
const animatedLogo = this.text.map((line) => {
let coloredLine = "";
for (let i = 0; i < line.length; i++) {
const char = line[i];
if (char === " ") {
coloredLine += char;
} else {
const color = this.getColorGradient(position, i);
coloredLine += `${color}${char}\x1B[0m`;
}
}
return coloredLine;
}).join("\n");
return `${animatedLogo}
${this.staticContent}`;
}
start() {
console.clear();
process.stdout.write("\x1B[?25l");
this.interval = setInterval(() => {
process.stdout.write("\x1B[H");
process.stdout.write(this.renderFrame(this.position));
this.position = (this.position + 1) % this.CYCLE_LENGTH;
}, 40);
process.on("SIGINT", () => {
this.stop();
process.exit(0);
});
}
stop() {
if (this.interval) {
clearInterval(this.interval);
process.stdout.write("\x1B[?25h");
}
}
}
export {
MagmaFlow,
ProgressBar,
Spinner,
ThinkingSpinner,
UI,
magma
};