From d0f0f479a2f5d0f53244af79ec60b2866f02c6ab Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 4 Mar 2025 11:53:10 -0800 Subject: [PATCH] fix(npx): remove dependency on ora and test command, runs smooth --- packages/@sim/cli/dist/commands/start.js | 88 +++++----------- packages/@sim/cli/dist/index.js | 4 +- packages/@sim/cli/dist/utils/spinner.d.ts | 52 +++++++++ packages/@sim/cli/dist/utils/spinner.js | 110 +++++++++++++++++++ packages/@sim/cli/package.json | 1 - packages/@sim/cli/src/commands/start.ts | 27 ++--- packages/@sim/cli/src/utils/spinner.ts | 122 ++++++++++++++++++++++ 7 files changed, 325 insertions(+), 79 deletions(-) create mode 100644 packages/@sim/cli/dist/utils/spinner.d.ts create mode 100644 packages/@sim/cli/dist/utils/spinner.js create mode 100644 packages/@sim/cli/src/utils/spinner.ts diff --git a/packages/@sim/cli/dist/commands/start.js b/packages/@sim/cli/dist/commands/start.js index ba8bdbcb1..29085b97b 100644 --- a/packages/@sim/cli/dist/commands/start.js +++ b/packages/@sim/cli/dist/commands/start.js @@ -1,52 +1,20 @@ "use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.start = start; -const child_process_1 = require("child_process"); const chalk_1 = __importDefault(require("chalk")); -const config_1 = require("../utils/config"); -const path_1 = __importDefault(require("path")); -const fs_1 = __importDefault(require("fs")); -const os_1 = __importDefault(require("os")); -const tar_1 = require("tar"); -const https_1 = __importDefault(require("https")); -const fs_2 = require("fs"); +const child_process_1 = require("child_process"); const child_process_2 = require("child_process"); +const fs_1 = __importDefault(require("fs")); +const fs_2 = require("fs"); +const https_1 = __importDefault(require("https")); +const os_1 = __importDefault(require("os")); +const path_1 = __importDefault(require("path")); +const tar_1 = require("tar"); +const config_1 = require("../utils/config"); +const spinner_1 = require("../utils/spinner"); // Constants for standalone app const SIM_HOME_DIR = path_1.default.join(os_1.default.homedir(), '.sim-studio'); const SIM_STANDALONE_DIR = path_1.default.join(SIM_HOME_DIR, 'standalone'); @@ -63,11 +31,8 @@ async function start(options) { config_1.config.set('lastRun', new Date().toISOString()); const port = options.port || '3000'; const debug = options.debug || false; - // Dynamically import ora - const oraModule = await Promise.resolve().then(() => __importStar(require('ora'))); - const ora = oraModule.default; // Show starting message - const spinner = ora(`Starting Sim Studio on port ${port}...`).start(); + const spinner = (0, spinner_1.createSpinner)(`Starting Sim Studio on port ${port}...`).start(); try { // Set environment variables for using local storage const env = { @@ -88,7 +53,7 @@ async function start(options) { simProcess = (0, child_process_1.spawn)('npm', ['run', 'dev'], { env, stdio: 'inherit', - shell: true + shell: true, }); } else { @@ -132,7 +97,8 @@ async function start(options) { // Start the standalone app spinner.text = 'Starting Sim Studio standalone...'; // Make sure the standalone directory exists - if (!fs_1.default.existsSync(SIM_STANDALONE_DIR) || !fs_1.default.existsSync(path_1.default.join(SIM_STANDALONE_DIR, 'server.js'))) { + if (!fs_1.default.existsSync(SIM_STANDALONE_DIR) || + !fs_1.default.existsSync(path_1.default.join(SIM_STANDALONE_DIR, 'server.js'))) { spinner.fail('Standalone app files are missing. Re-run to download again.'); // Force a fresh download next time if (fs_1.default.existsSync(SIM_VERSION_FILE)) { @@ -149,7 +115,7 @@ async function start(options) { cwd: SIM_STANDALONE_DIR, env: standaloneEnv, stdio: 'inherit', - shell: true + shell: true, }); } // Successful start @@ -215,7 +181,8 @@ async function downloadStandaloneApp(spinner) { const file = (0, fs_2.createWriteStream)(tarballPath); spinner.text = 'Downloading Sim Studio...'; // Download the tarball - https_1.default.get(DOWNLOAD_URL, (response) => { + https_1.default + .get(DOWNLOAD_URL, (response) => { if (response.statusCode !== 200) { spinner.fail(`Failed to download: ${response.statusCode}`); return reject(new Error(`Download failed with status code: ${response.statusCode}`)); @@ -233,8 +200,9 @@ async function downloadStandaloneApp(spinner) { // Extract the tarball (0, tar_1.extract)({ file: tarballPath, - cwd: SIM_STANDALONE_DIR - }).then(() => { + cwd: SIM_STANDALONE_DIR, + }) + .then(() => { // Clean up fs_1.default.rmSync(tmpDir, { recursive: true, force: true }); // Install dependencies if needed @@ -243,24 +211,26 @@ async function downloadStandaloneApp(spinner) { try { (0, child_process_2.execSync)('npm install --production', { cwd: SIM_STANDALONE_DIR, - stdio: 'ignore' + stdio: 'ignore', }); } catch (error) { spinner.warn('Error installing dependencies, but trying to continue...'); } } - // Save version info - fs_1.default.writeFileSync(SIM_VERSION_FILE, JSON.stringify({ version: STANDALONE_VERSION, installedAt: new Date().toISOString() })); + // Write version file + fs_1.default.writeFileSync(SIM_VERSION_FILE, JSON.stringify({ version: STANDALONE_VERSION, date: new Date().toISOString() })); + spinner.succeed('Sim Studio downloaded successfully'); resolve(); - }).catch((err) => { - spinner.fail('Extraction failed'); + }) + .catch((err) => { + spinner.fail('Failed to extract Sim Studio'); reject(err); }); }); - }).on('error', (err) => { - fs_1.default.unlink(tarballPath, () => { }); - spinner.fail('Download failed'); + }) + .on('error', (err) => { + spinner.fail('Network error'); reject(err); }); }); diff --git a/packages/@sim/cli/dist/index.js b/packages/@sim/cli/dist/index.js index 73318164b..01c6cb636 100644 --- a/packages/@sim/cli/dist/index.js +++ b/packages/@sim/cli/dist/index.js @@ -7,11 +7,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); const chalk_1 = __importDefault(require("chalk")); const commander_1 = require("commander"); const update_notifier_1 = __importDefault(require("update-notifier")); -const start_1 = require("./commands/start"); const help_1 = require("./commands/help"); +const start_1 = require("./commands/start"); const version_1 = require("./commands/version"); -const logo_1 = require("./utils/logo"); const config_1 = require("./utils/config"); +const logo_1 = require("./utils/logo"); // Package info for version checking const pkg = require('../package.json'); // Check for updates diff --git a/packages/@sim/cli/dist/utils/spinner.d.ts b/packages/@sim/cli/dist/utils/spinner.d.ts new file mode 100644 index 000000000..714866b20 --- /dev/null +++ b/packages/@sim/cli/dist/utils/spinner.d.ts @@ -0,0 +1,52 @@ +/** + * A simple spinner implementation that doesn't rely on external packages + */ +export declare class SimpleSpinner { + private interval; + private frames; + private frameIndex; + private isSpinning; + private lastOutput; + private _text; + constructor(text?: string); + /** + * Start the spinner + */ + start(text?: string): SimpleSpinner; + /** + * Stop the spinner + */ + stop(): SimpleSpinner; + /** + * Update the spinner text + */ + set text(value: string); + /** + * Get the spinner text + */ + get text(): string; + /** + * Show a success message + */ + succeed(text?: string): SimpleSpinner; + /** + * Show a failure message + */ + fail(text?: string): SimpleSpinner; + /** + * Show a warning message + */ + warn(text?: string): SimpleSpinner; + /** + * Show an info message + */ + info(text?: string): SimpleSpinner; + /** + * Stop the spinner and show a symbol with text + */ + private stopWithSymbol; +} +/** + * Create a new spinner + */ +export declare function createSpinner(text?: string): SimpleSpinner; diff --git a/packages/@sim/cli/dist/utils/spinner.js b/packages/@sim/cli/dist/utils/spinner.js new file mode 100644 index 000000000..bf5130cbb --- /dev/null +++ b/packages/@sim/cli/dist/utils/spinner.js @@ -0,0 +1,110 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SimpleSpinner = void 0; +exports.createSpinner = createSpinner; +const chalk_1 = __importDefault(require("chalk")); +/** + * A simple spinner implementation that doesn't rely on external packages + */ +class SimpleSpinner { + constructor(text = '') { + this.interval = null; + this.frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; + this.frameIndex = 0; + this.isSpinning = false; + this.lastOutput = ''; + this._text = ''; + this._text = text; + } + /** + * Start the spinner + */ + start(text) { + if (text) { + this._text = text; + } + if (!this.isSpinning) { + this.isSpinning = true; + this.frameIndex = 0; + // Clear any previous output + if (this.lastOutput) { + process.stdout.write('\r' + ' '.repeat(this.lastOutput.length) + '\r'); + } + this.interval = setInterval(() => { + const frame = this.frames[this.frameIndex]; + const output = `${chalk_1.default.cyan(frame)} ${this._text}`; + process.stdout.write('\r' + output); + this.lastOutput = output; + this.frameIndex = (this.frameIndex + 1) % this.frames.length; + }, 80); + } + return this; + } + /** + * Stop the spinner + */ + stop() { + if (this.isSpinning && this.interval) { + clearInterval(this.interval); + this.interval = null; + this.isSpinning = false; + // Clear the spinner line + process.stdout.write('\r' + ' '.repeat(this.lastOutput.length) + '\r'); + } + return this; + } + /** + * Update the spinner text + */ + set text(value) { + this._text = value; + } + /** + * Get the spinner text + */ + get text() { + return this._text; + } + /** + * Show a success message + */ + succeed(text) { + return this.stopWithSymbol(chalk_1.default.green('✓'), text || this._text); + } + /** + * Show a failure message + */ + fail(text) { + return this.stopWithSymbol(chalk_1.default.red('✗'), text || this._text); + } + /** + * Show a warning message + */ + warn(text) { + return this.stopWithSymbol(chalk_1.default.yellow('⚠'), text || this._text); + } + /** + * Show an info message + */ + info(text) { + return this.stopWithSymbol(chalk_1.default.blue('ℹ'), text || this._text); + } + /** + * Stop the spinner and show a symbol with text + */ + stopWithSymbol(symbol, text) { + this.stop(); + console.log(`${symbol} ${text}`); + return this; + } +} +exports.SimpleSpinner = SimpleSpinner; +/** + * Create a new spinner + */ +function createSpinner(text) { + return new SimpleSpinner(text); +} diff --git a/packages/@sim/cli/package.json b/packages/@sim/cli/package.json index b8103c95c..a37317844 100644 --- a/packages/@sim/cli/package.json +++ b/packages/@sim/cli/package.json @@ -35,7 +35,6 @@ "conf": "^10.2.0", "dotenv": "^16.4.7", "inquirer": "^8.2.6", - "ora": "^8.2.0", "tar": "^6.2.1", "update-notifier": "^5.1.0" }, diff --git a/packages/@sim/cli/src/commands/start.ts b/packages/@sim/cli/src/commands/start.ts index 181c6cc22..acccc17e6 100644 --- a/packages/@sim/cli/src/commands/start.ts +++ b/packages/@sim/cli/src/commands/start.ts @@ -4,11 +4,11 @@ import { execSync } from 'child_process' import fs from 'fs' import { createWriteStream } from 'fs' import https from 'https' -import type { Ora } from 'ora' import os from 'os' import path from 'path' import { extract } from 'tar' import { config } from '../utils/config' +import { SimpleSpinner, createSpinner } from '../utils/spinner' interface StartOptions { port: string @@ -35,12 +35,8 @@ export async function start(options: StartOptions) { const port = options.port || '3000' const debug = options.debug || false - // Dynamically import ora - const oraModule = await import('ora') - const ora = oraModule.default - // Show starting message - const spinner = ora(`Starting Sim Studio on port ${port}...`).start() + const spinner = createSpinner(`Starting Sim Studio on port ${port}...`).start() try { // Set environment variables for using local storage @@ -203,7 +199,7 @@ function checkIfInProjectDirectory(): boolean { /** * Downloads and extracts the standalone app */ -async function downloadStandaloneApp(spinner: Ora): Promise { +async function downloadStandaloneApp(spinner: SimpleSpinner): Promise { return new Promise((resolve, reject) => { // Create temp directory const tmpDir = path.join(os.tmpdir(), `sim-download-${Date.now()}`) @@ -260,26 +256,23 @@ async function downloadStandaloneApp(spinner: Ora): Promise { } } - // Save version info + // Write version file fs.writeFileSync( SIM_VERSION_FILE, - JSON.stringify({ - version: STANDALONE_VERSION, - installedAt: new Date().toISOString(), - }) + JSON.stringify({ version: STANDALONE_VERSION, date: new Date().toISOString() }) ) + spinner.succeed('Sim Studio downloaded successfully') resolve() }) - .catch((err: Error) => { - spinner.fail('Extraction failed') + .catch((err) => { + spinner.fail('Failed to extract Sim Studio') reject(err) }) }) }) - .on('error', (err: Error) => { - fs.unlink(tarballPath, () => {}) - spinner.fail('Download failed') + .on('error', (err) => { + spinner.fail('Network error') reject(err) }) }) diff --git a/packages/@sim/cli/src/utils/spinner.ts b/packages/@sim/cli/src/utils/spinner.ts new file mode 100644 index 000000000..d52496187 --- /dev/null +++ b/packages/@sim/cli/src/utils/spinner.ts @@ -0,0 +1,122 @@ +import chalk from 'chalk' + +/** + * A simple spinner implementation that doesn't rely on external packages + */ +export class SimpleSpinner { + private interval: NodeJS.Timeout | null = null + private frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] + private frameIndex = 0 + private isSpinning = false + private lastOutput = '' + private _text: string = '' + + constructor(text: string = '') { + this._text = text + } + + /** + * Start the spinner + */ + start(text?: string): SimpleSpinner { + if (text) { + this._text = text + } + + if (!this.isSpinning) { + this.isSpinning = true + this.frameIndex = 0 + + // Clear any previous output + if (this.lastOutput) { + process.stdout.write('\r' + ' '.repeat(this.lastOutput.length) + '\r') + } + + this.interval = setInterval(() => { + const frame = this.frames[this.frameIndex] + const output = `${chalk.cyan(frame)} ${this._text}` + + process.stdout.write('\r' + output) + this.lastOutput = output + + this.frameIndex = (this.frameIndex + 1) % this.frames.length + }, 80) + } + + return this + } + + /** + * Stop the spinner + */ + stop(): SimpleSpinner { + if (this.isSpinning && this.interval) { + clearInterval(this.interval) + this.interval = null + this.isSpinning = false + + // Clear the spinner line + process.stdout.write('\r' + ' '.repeat(this.lastOutput.length) + '\r') + } + + return this + } + + /** + * Update the spinner text + */ + set text(value: string) { + this._text = value + } + + /** + * Get the spinner text + */ + get text(): string { + return this._text + } + + /** + * Show a success message + */ + succeed(text?: string): SimpleSpinner { + return this.stopWithSymbol(chalk.green('✓'), text || this._text) + } + + /** + * Show a failure message + */ + fail(text?: string): SimpleSpinner { + return this.stopWithSymbol(chalk.red('✗'), text || this._text) + } + + /** + * Show a warning message + */ + warn(text?: string): SimpleSpinner { + return this.stopWithSymbol(chalk.yellow('⚠'), text || this._text) + } + + /** + * Show an info message + */ + info(text?: string): SimpleSpinner { + return this.stopWithSymbol(chalk.blue('ℹ'), text || this._text) + } + + /** + * Stop the spinner and show a symbol with text + */ + private stopWithSymbol(symbol: string, text: string): SimpleSpinner { + this.stop() + console.log(`${symbol} ${text}`) + return this + } +} + +/** + * Create a new spinner + */ +export function createSpinner(text?: string): SimpleSpinner { + return new SimpleSpinner(text) +}