chore: cleanup root of repo by removing unused cli pacakge

This commit is contained in:
Waleed Latif
2025-03-14 18:13:04 -07:00
parent 95ce00f51d
commit c3f666383f
14 changed files with 1 additions and 3653 deletions
-2
View File
@@ -1,2 +0,0 @@
# Exclude CLI package from Vercel builds
packages/@simstudio/cli/
-79
View File
@@ -1,79 +0,0 @@
# Sim Studio
A command-line interface for Sim Studio - a powerful, user-friendly platform for building, testing, and optimizing agentic workflows.
## Installation
```bash
npm install -g simstudio
```
Or run directly with npx:
```bash
npx simstudio
```
## Quick Start
The fastest way to get started is to run:
```bash
npx simstudio start
```
This will download and start a standalone version of Sim Studio, with all data stored in your browser's localStorage. No database or authentication required!
## Usage
### Start Sim Studio
Start a local instance of Sim Studio:
```bash
simstudio start
```
Options:
- `--port <port>` - Specify the port to run on (default: 3000)
- `--debug` - Run in debug mode
### Help
Get help with available commands:
```bash
simstudio --help
```
## Features
- **Local Storage Mode**: All your workflows and settings are stored in your browser's localStorage, no database required
- **Workflow Builder**: Create and edit workflows with a visual editor
- **Workflow Execution**: Run workflows and see the results in real-time
- **Environment Variables**: Manage environment variables for your workflows
## How It Works
When you run `simstudio start`, the CLI will:
1. Check if you're in a Sim Studio project directory
2. If not, download and extract a standalone version of Sim Studio
3. Start a local server with the standalone app
4. Open a browser window to the Sim Studio UI
All your data is stored in your browser's localStorage, so you can close the app and come back later without losing your work.
## Development
To contribute to the development of Sim Studio:
1. Clone the repository
2. Install dependencies with `npm install`
3. Build the CLI with `npm run build`
4. Link the CLI for local development with `npm link`
## License
MIT
-14
View File
@@ -1,14 +0,0 @@
#!/usr/bin/env node
// This file is the entry point for the 'simstudio' command
try {
require('../dist/index.js')
} catch (error) {
if (error.code === 'MODULE_NOT_FOUND') {
console.error('Sim Studio CLI has not been built. Please run npm run build first.')
process.exit(1)
} else {
console.error('An error occurred while starting Sim Studio CLI:', error)
process.exit(1)
}
}
File diff suppressed because it is too large Load Diff
-65
View File
@@ -1,65 +0,0 @@
{
"name": "simstudio",
"version": "0.1.4",
"description": "CLI tool for Sim Studio - easily start, build and test agent workflows",
"license": "MIT",
"author": "Sim Studio Team",
"main": "dist/index.js",
"type": "commonjs",
"bin": {
"simstudio": "./bin/sim.js"
},
"files": [
"bin",
"dist",
"README.md"
],
"scripts": {
"build": "tsc",
"start": "node bin/sim.js",
"dev": "ts-node src/index.ts",
"clean": "rimraf dist",
"prepublishOnly": "npm run clean && npm run build && npm run prepare-standalone && echo 'Checking for sensitive files...' && (! find . -name '.env*' -not -path '*/node_modules/*' -not -path '*/standalone/*' | grep -q .)",
"prepare-standalone": "node ../../scripts/build-standalone.js"
},
"keywords": [
"sim",
"sim-studio",
"workflow",
"automation",
"cli",
"agent",
"ai",
"workflow-automation"
],
"dependencies": {
"chalk": "^4.1.2",
"commander": "^11.1.0",
"conf": "^10.2.0",
"dotenv": "^16.4.7",
"inquirer": "^8.2.6",
"open": "^10.1.0",
"tar": "^6.2.1",
"update-notifier": "^5.1.0"
},
"devDependencies": {
"@types/inquirer": "^8.2.10",
"@types/node": "^20.11.30",
"@types/tar": "^6.1.11",
"@types/update-notifier": "^5.1.0",
"rimraf": "^5.0.5",
"ts-node": "^10.9.2",
"typescript": "^5.7.3"
},
"engines": {
"node": ">=16.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/simstudioai/sim"
},
"bugs": {
"url": "https://github.com/simstudioai/sim/issues"
},
"homepage": "https://github.com/simstudioai/sim#readme"
}
-39
View File
@@ -1,39 +0,0 @@
import chalk from 'chalk'
import { logo } from '../utils/logo'
/**
* Help command displays the logo and usage information
*/
export function help() {
// Display logo
console.log(logo)
// Display help text
console.log(`
${chalk.bold('USAGE')}
${chalk.cyan('simstudio')} Start Sim Studio with default settings
${chalk.cyan('simstudio start')} Start Sim Studio with options
${chalk.cyan('simstudio version')} Display version information
${chalk.cyan('simstudio help')} Show this help information
${chalk.bold('OPTIONS')}
${chalk.cyan('-p, --port <port>')} Specify port (default: 3000)
${chalk.cyan('-d, --debug')} Enable debug mode
${chalk.cyan('-v, --version')} Show version information
${chalk.cyan('-h, --help')} Show help information
${chalk.bold('EXAMPLES')}
${chalk.gray('# Start with default settings')}
${chalk.cyan('$ simstudio')}
${chalk.gray('# Start on a specific port')}
${chalk.cyan('$ simstudio start --port 8080')}
${chalk.gray('# Start with debug logging')}
${chalk.cyan('$ simstudio start --debug')}
${chalk.bold('DOCUMENTATION')}
${chalk.gray('For more information:')}
https://github.com/simstudioai/sim
`)
}
-501
View File
@@ -1,501 +0,0 @@
import chalk from 'chalk'
import { spawn } from 'child_process'
import { execSync } from 'child_process'
import fs from 'fs'
import { createWriteStream } from 'fs'
import https from 'https'
import os from 'os'
import path from 'path'
import { config } from '../utils/config'
import { SimpleSpinner, createSpinner } from '../utils/spinner'
interface StartOptions {
port: string
debug: boolean
noOpen?: boolean // Add option to not open browser
}
// Constants for standalone app
const SIM_HOME_DIR = path.join(os.homedir(), '.sim-studio')
const SIM_STANDALONE_DIR = path.join(SIM_HOME_DIR, 'standalone')
const SIM_VERSION_FILE = path.join(SIM_HOME_DIR, 'version.json')
const STANDALONE_VERSION = '0.1.4'
const DOWNLOAD_URL =
'https://github.com/simstudioai/sim/releases/latest/download/sim-standalone.tar.gz'
// Add a custom user agent to avoid GitHub API rate limiting
const USER_AGENT = 'SimStudio-CLI'
/**
* Start command that launches Sim Studio using local storage
*/
export async function start(options: StartOptions) {
// Update config with provided options
config.set('port', options.port)
config.set('debug', options.debug)
config.set('lastRun', new Date().toISOString())
const port = options.port || '3000'
const debug = options.debug || false
// Show starting message
const spinner = createSpinner(`Starting Sim Studio on port ${port}...`).start()
try {
// Set environment variables for using local storage
const env = {
...process.env,
PORT: port,
USE_LOCAL_STORAGE: 'true', // Key environment variable to switch to local storage
NEXT_PUBLIC_USE_LOCAL_STORAGE: 'true', // For client-side code
DISABLE_DB_SYNC: 'true', // Disable database sync
DISABLE_AUTH: 'true', // Disable authentication
NEXT_PUBLIC_DISABLE_AUTH: 'true', // For client-side authentication check
NODE_ENV: debug ? 'development' : ('production' as const),
DEBUG: debug ? '*' : undefined,
}
// Try to find the main package.json to determine if we're running from within the repo
// or as an installed npm package
const isInProjectDirectory = checkIfInProjectDirectory()
let simProcess
if (isInProjectDirectory) {
// Running from within the project directory - we'll use the existing
// Next.js setup directly
spinner.text = 'Detected Sim Studio project, starting with local configuration...'
// When running in dev mode, we need to make sure we're not trying to use static export
// as it will fail with API routes
if (debug) {
spinner.text = 'Starting in development mode with local storage...'
simProcess = spawn('npm', ['run', 'dev'], {
env: env as NodeJS.ProcessEnv,
stdio: 'inherit',
shell: true,
})
} else {
// In production mode, we'll use the start command which uses the built app
spinner.text = 'Starting in production mode with local storage...'
// Build first if needed
if (!fs.existsSync(path.join(process.cwd(), '.next'))) {
spinner.text = 'Building Next.js app first...'
try {
execSync('npm run build', {
env: env as NodeJS.ProcessEnv,
stdio: 'inherit',
})
} catch (error) {
spinner.fail('Build failed')
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error)
process.exit(1)
}
}
simProcess = spawn('npm', ['run', 'start'], {
env: env as NodeJS.ProcessEnv,
stdio: 'inherit',
shell: true,
})
}
} else {
// Running from outside the project via npx - we'll download and start a standalone version
spinner.text = 'Setting up Sim Studio...'
// Create the .sim-studio directory if it doesn't exist
if (!fs.existsSync(SIM_HOME_DIR)) {
fs.mkdirSync(SIM_HOME_DIR, { recursive: true })
}
// Check if we already have the standalone version
let needsDownload = true
if (fs.existsSync(SIM_VERSION_FILE)) {
try {
const versionInfo = JSON.parse(fs.readFileSync(SIM_VERSION_FILE, 'utf8'))
if (versionInfo.version === STANDALONE_VERSION) {
needsDownload = false
}
} catch (error) {
// If there's an error reading the version file, download again
needsDownload = true
}
}
// Download and extract if needed
if (needsDownload) {
try {
console.log(`\n${chalk.blue('ℹ')} Downloading Sim Studio...`)
await downloadStandaloneApp(spinner, options)
} catch (error) {
spinner.fail('Download failed')
console.log(`\n${chalk.yellow('⚠️')} If you're having network issues, you can try:
1. Check your internet connection
2. Try again later
3. Run Sim Studio directly from a cloned repository`)
process.exit(1)
}
} else {
spinner.text = 'Using cached version...'
}
// Start the standalone app
spinner.text = 'Starting Sim Studio...'
// Make sure the standalone directory exists
if (
!fs.existsSync(SIM_STANDALONE_DIR) ||
!fs.existsSync(path.join(SIM_STANDALONE_DIR, 'server.js'))
) {
spinner.fail('Setup incomplete')
// Force a fresh download next time
if (fs.existsSync(SIM_VERSION_FILE)) {
fs.unlinkSync(SIM_VERSION_FILE)
}
process.exit(1)
}
// Start the standalone Node.js server
const standaloneEnv = {
...env,
SIM_STUDIO_PORT: port,
}
simProcess = spawn('node', ['server.js'], {
cwd: SIM_STANDALONE_DIR,
env: standaloneEnv as NodeJS.ProcessEnv,
stdio: 'inherit',
shell: true,
})
}
// Successful start
spinner.succeed(`Sim Studio started on ${chalk.cyan(`http://localhost:${port}`)}`)
console.log(`
${chalk.green('✓')} Local storage mode enabled
${chalk.green('✓')} Changes persist between sessions
${chalk.green('✓')} Authentication disabled
${chalk.blue('ℹ')} Create a workflow at ${chalk.cyan(`http://localhost:${port}/w`)}
${chalk.blue('ℹ')} Press ${chalk.bold('Ctrl+C')} to stop the server
`)
// Auto-open browser to workflow page
if (!options.noOpen) {
try {
// Dynamically import open to avoid adding it as a dependency for production builds
const open = await import('open').then((m) => m.default)
// Wait a short time for the server to fully start
setTimeout(() => {
open(`http://localhost:${port}/w`)
console.log(`${chalk.green('✓')} Browser opened to workflow canvas`)
}, 1000)
} catch (error) {
console.log(
`${chalk.blue('ℹ')} Please navigate to ${chalk.cyan(`http://localhost:${port}/w`)} in your browser`
)
}
}
// Handle process termination
process.on('SIGINT', () => {
console.log(`\n${chalk.blue('ℹ')} Shutting down Sim Studio...`)
simProcess.kill('SIGINT')
process.exit(0)
})
// Return the process for testing purposes
return simProcess
} catch (error) {
spinner.fail('Failed to start')
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error)
process.exit(1)
}
}
/**
* Checks if we're running in a Sim Studio project directory
*/
function checkIfInProjectDirectory(): boolean {
// Check if we have package.json that looks like a Sim Studio project
try {
const packageJsonPath = path.join(process.cwd(), 'package.json')
if (fs.existsSync(packageJsonPath)) {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
// Check if it looks like our project
if (
packageJson.name === 'sim' ||
packageJson.name === 'sim-studio' ||
(packageJson.dependencies &&
(packageJson.dependencies['next'] ||
packageJson.dependencies['@simstudio/cli'] ||
packageJson.dependencies['sim-studio-cli']))
) {
return true
}
}
// Also check for Next.js app files
const nextConfigPath = path.join(process.cwd(), 'next.config.js')
const nextTsConfigPath = path.join(process.cwd(), 'next.config.ts')
if (fs.existsSync(nextConfigPath) || fs.existsSync(nextTsConfigPath)) {
return true
}
} catch (error) {
// If we can't read/parse package.json, assume we're not in a project directory
}
return false
}
/**
* Downloads and extracts the standalone app
*/
async function downloadStandaloneApp(spinner: SimpleSpinner, options: StartOptions): Promise<void> {
return new Promise((resolve, reject) => {
// Create temp directory
const tmpDir = path.join(os.tmpdir(), `sim-download-${Date.now()}`)
fs.mkdirSync(tmpDir, { recursive: true })
const tarballPath = path.join(tmpDir, 'sim-standalone.tar.gz')
// Track retry attempts
let retryCount = 0
const maxRetries = 3
// Function to start a fresh download attempt
const startDownload = (url: string) => {
// Create a new file stream for each attempt
const file = createWriteStream(tarballPath)
if (retryCount > 0) {
spinner.text = `Downloading Sim Studio... (Attempt ${retryCount + 1}/${maxRetries + 1})`
} else {
spinner.text = 'Downloading Sim Studio...'
}
// Function to handle the download
downloadFile(url, 0, file)
}
// Function to handle the download
const downloadFile = (url: string, redirectCount = 0, file: fs.WriteStream) => {
// Prevent infinite redirects
if (redirectCount > 5) {
spinner.fail('Download failed')
if (options.debug) {
console.error('Redirect chain exceeded maximum depth')
}
return handleError(new Error('Too many redirects'))
}
// Set a timeout for the request (15 seconds)
const request = https
.get(
url,
{
timeout: 15000,
headers: {
'User-Agent': USER_AGENT,
},
},
(response) => {
// Handle redirects (302, 301, 307, etc.)
if (
response.statusCode &&
response.statusCode >= 300 &&
response.statusCode < 400 &&
response.headers.location
) {
// Close the current file stream before following the redirect
file.close()
const redirectUrl = response.headers.location.startsWith('http')
? response.headers.location
: new URL(response.headers.location, url).toString()
// Only show "Following redirects" on the first redirect
if (redirectCount === 0 && !options.debug) {
spinner.text = 'Following redirects...'
}
// Only log redirect details in debug mode
if (options.debug) {
console.log(`Redirect ${redirectCount + 1}: ${url} -> ${redirectUrl}`)
}
// Follow the redirect with incremented counter
downloadFile(redirectUrl, redirectCount + 1, createWriteStream(tarballPath))
return
}
if (response.statusCode !== 200) {
spinner.fail('Download failed')
if (options.debug) {
console.error(`Server returned status code: ${response.statusCode}`)
console.error('URL that failed:', url)
console.error('Response headers:', JSON.stringify(response.headers, null, 2))
}
file.close()
return handleError(new Error(`Server returned ${response.statusCode}`))
}
// Get content length for progress tracking
const totalSize = parseInt(response.headers['content-length'] || '0', 10)
let downloadedSize = 0
let lastProgressUpdate = Date.now()
let lastDataReceived = Date.now()
const startTime = Date.now()
if (totalSize > 0) {
spinner.text = `Downloading Sim Studio... (${(totalSize / 1024 / 1024).toFixed(1)} MB)`
} else {
spinner.text = 'Downloading Sim Studio...'
}
// Track download progress
response.on('data', (chunk) => {
downloadedSize += chunk.length
lastDataReceived = Date.now()
// Only update the spinner text every 500ms to avoid excessive updates
const now = Date.now()
if (now - lastProgressUpdate > 500) {
lastProgressUpdate = now
const elapsedSeconds = (now - startTime) / 1000
const downloadSpeed = downloadedSize / elapsedSeconds / 1024 / 1024 // MB/s
if (totalSize > 0) {
const percent = Math.round((downloadedSize / totalSize) * 100)
spinner.text = `Downloading Sim Studio... ${percent}% (${(downloadedSize / 1024 / 1024).toFixed(1)}/${(totalSize / 1024 / 1024).toFixed(1)} MB)`
} else {
spinner.text = `Downloading Sim Studio... ${(downloadedSize / 1024 / 1024).toFixed(1)} MB downloaded`
}
}
})
// Set up a progress check interval to detect stalled downloads
const progressInterval = setInterval(() => {
const timeSinceLastData = Date.now() - lastDataReceived
if (timeSinceLastData > 10000) {
// 10 seconds with no data
clearInterval(progressInterval)
request.destroy()
spinner.fail('Download failed')
handleError(new Error('Download stalled - no data received for 10 seconds'))
}
}, 2000)
response.pipe(file)
file.on('finish', () => {
clearInterval(progressInterval)
file.close()
// Clear the standalone directory if it exists
if (fs.existsSync(SIM_STANDALONE_DIR)) {
fs.rmSync(SIM_STANDALONE_DIR, { recursive: true, force: true })
}
// Create the directory
fs.mkdirSync(SIM_STANDALONE_DIR, { recursive: true })
spinner.text = 'Extracting files...'
// Dynamically import tar only when needed
import('tar')
.then(({ extract }) => {
// Extract the tarball
extract({
file: tarballPath,
cwd: SIM_STANDALONE_DIR,
})
.then(() => {
// Clean up
fs.rmSync(tmpDir, { recursive: true, force: true })
// Install dependencies if needed
if (fs.existsSync(path.join(SIM_STANDALONE_DIR, 'package.json'))) {
spinner.text = 'Installing dependencies...'
try {
execSync('npm install --production', {
cwd: SIM_STANDALONE_DIR,
stdio: 'ignore',
})
} catch (error) {
spinner.warn('Error installing dependencies, but trying to continue...')
}
}
// Write version file
fs.writeFileSync(
SIM_VERSION_FILE,
JSON.stringify({
version: STANDALONE_VERSION,
date: new Date().toISOString(),
})
)
spinner.succeed('Setup complete')
resolve()
})
.catch((err) => {
spinner.fail('Extraction failed')
handleError(err)
})
})
.catch((err) => {
spinner.fail('Extraction failed')
handleError(err)
})
})
file.on('error', (err) => {
clearInterval(progressInterval)
spinner.fail('File error')
handleError(err)
})
}
)
.on('error', (err) => {
spinner.fail('Network error')
handleError(err)
})
.on('timeout', () => {
request.destroy()
spinner.fail('Download timed out')
handleError(new Error('Download timed out after 15 seconds'))
})
}
// Error handler with retry logic
const handleError = (err: Error) => {
if (retryCount < maxRetries) {
retryCount++
spinner.text = `Retrying download (${retryCount}/${maxRetries})...`
// Use the same URL but with a delay
setTimeout(() => startDownload(DOWNLOAD_URL), 1000)
} else {
// Clean up
if (fs.existsSync(tarballPath)) {
fs.unlinkSync(tarballPath)
}
if (fs.existsSync(tmpDir)) {
fs.rmSync(tmpDir, { recursive: true, force: true })
}
reject(err)
}
}
// Start the download process
startDownload(DOWNLOAD_URL)
})
}
@@ -1,15 +0,0 @@
import chalk from 'chalk'
/**
* Version command displays the current version of the CLI
*/
export function version() {
const pkg = require('../../package.json')
console.log(`
${chalk.bold('Sim Studio CLI')} ${chalk.green(`v${pkg.version}`)}
${chalk.gray('Platform:')} ${process.platform}
${chalk.gray('Node Version:')} ${process.version}
${chalk.gray('CLI Path:')} ${__dirname}
`)
}
-81
View File
@@ -1,81 +0,0 @@
#!/usr/bin/env node
import chalk from 'chalk'
import { Command } from 'commander'
import updateNotifier from 'update-notifier'
import { help } from './commands/help'
import { start } from './commands/start'
import { version } from './commands/version'
import { config } from './utils/config'
import { logo } from './utils/logo'
// Package info for version checking
const pkg = require('../package.json')
// Check for updates
updateNotifier({ pkg }).notify()
// Create program
const program = new Command()
// Initialize CLI
async function main() {
// Configure the CLI
program
.name('simstudio')
.description('Sim Studio CLI')
.version(pkg.version, '-v, --version', 'Output the current version')
.helpOption('-h, --help', 'Display help for command')
.on('--help', () => help())
.action(() => {
// Default command (no args) runs start with default options
start({
port: config.get('port'),
debug: config.get('debug'),
})
})
// Start command
program
.command('start')
.description('Start Sim Studio with local storage')
.option('-p, --port <port>', 'Port to run on', config.get('port'))
.option('-d, --debug', 'Enable debug mode', config.get('debug'))
.option('--no-open', 'Do not automatically open browser')
.action((options) => {
start({
port: options.port,
debug: options.debug,
noOpen: !options.open,
})
})
// Version command
program
.command('version')
.description('Show detailed version information')
.action(() => {
version()
})
// Help command
program
.command('help')
.description('Display help information')
.action(() => {
help()
})
// Display logo if not in help mode
if (!process.argv.includes('--help') && !process.argv.includes('-h')) {
console.log(logo)
}
// Parse arguments
program.parse(process.argv)
}
// Run the CLI
main().catch((error) => {
console.error(chalk.red('Error:'), error)
process.exit(1)
})
-18
View File
@@ -1,18 +0,0 @@
import Conf from 'conf'
// Config schema definition
interface ConfigSchema {
port: string
debug: boolean
lastRun: string
}
// Create a config instance with default values
export const config = new Conf<ConfigSchema>({
projectName: 'sim-studio',
defaults: {
port: '3000',
debug: false,
lastRun: new Date().toISOString(),
},
})
-19
View File
@@ -1,19 +0,0 @@
import chalk from 'chalk'
/**
* ASCII art logo for Sim Studio
*/
export const logo = `
${chalk.bold(
chalk.magenta(`
███████╗██╗███╗ ███╗ ███████╗████████╗██╗ ██╗██████╗ ██╗ ██████╗
██╔════╝██║████╗ ████║ ██╔════╝╚══██╔══╝██║ ██║██╔══██╗██║██╔═══██╗
███████╗██║██╔████╔██║ ███████╗ ██║ ██║ ██║██║ ██║██║██║ ██║
╚════██║██║██║╚██╔╝██║ ╚════██║ ██║ ██║ ██║██║ ██║██║██║ ██║
███████║██║██║ ╚═╝ ██║ ███████║ ██║ ╚██████╔╝██████╔╝██║╚██████╔╝
╚══════╝╚═╝╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝
`)
)}
${chalk.cyan('Build, optimize, and test agent workflows with a powerful visual interface')}
`
-122
View File
@@ -1,122 +0,0 @@
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)
}
-16
View File
@@ -1,16 +0,0 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"moduleResolution": "Node",
"esModuleInterop": true,
"declaration": true,
"outDir": "./dist",
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
+1 -1
View File
@@ -5,7 +5,7 @@ DATABASE_URL="postgresql://postgres:password@localhost:5432/postgres"
BETTER_AUTH_SECRET=your_secret_key # Use `openssl rand -hex 32` to generate, or visit https://www.better-auth.com/docs/installation
BETTER_AUTH_URL=http://localhost:3000
# Email Provider (Required)
# Email Provider (Optional)
RESEND_API_KEY=your_resend_api_key # Get from https://resend.com
# App URL (Required)