chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
# Sim CLI
|
||||
|
||||
Sim CLI allows you to run [Sim](https://sim.ai) using Docker with a single command.
|
||||
|
||||
## Installation
|
||||
|
||||
To install the Sim CLI globally, use:
|
||||
|
||||
```bash
|
||||
npm install -g simstudio
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
To start Sim, simply run:
|
||||
|
||||
```bash
|
||||
simstudio
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
- `-p, --port <port>`: Specify the port to run Sim on (default: 3000).
|
||||
- `--no-pull`: Skip pulling the latest Docker images.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Docker must be installed and running on your machine.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please open an issue or submit a pull request.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the Apache-2.0 License.
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"name": "simstudio",
|
||||
"version": "0.1.19",
|
||||
"description": "Sim CLI - Run Sim with a single command",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"bin": {
|
||||
"simstudio": "dist/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"type-check": "tsc --noEmit",
|
||||
"lint": "biome check --write --unsafe .",
|
||||
"lint:check": "biome check .",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome format .",
|
||||
"prepublishOnly": "bun run build"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"keywords": [
|
||||
"simstudio",
|
||||
"ai",
|
||||
"workflow",
|
||||
"cli",
|
||||
"agent",
|
||||
"automation",
|
||||
"docker"
|
||||
],
|
||||
"author": "Sim",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.2",
|
||||
"commander": "^11.1.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"inquirer": "^8.2.6",
|
||||
"listr2": "^6.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sim/tsconfig": "workspace:*",
|
||||
"@types/inquirer": "^8.2.6",
|
||||
"@types/node": "^20.5.1",
|
||||
"typescript": "^7.0.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { execSync, spawn } from 'child_process'
|
||||
import { existsSync, mkdirSync } from 'fs'
|
||||
import { homedir } from 'os'
|
||||
import { join } from 'path'
|
||||
import { createInterface } from 'readline'
|
||||
import chalk from 'chalk'
|
||||
import { Command } from 'commander'
|
||||
|
||||
const NETWORK_NAME = 'simstudio-network'
|
||||
const DB_CONTAINER = 'simstudio-db'
|
||||
const MIGRATIONS_CONTAINER = 'simstudio-migrations'
|
||||
const REALTIME_CONTAINER = 'simstudio-realtime'
|
||||
const APP_CONTAINER = 'simstudio-app'
|
||||
const DEFAULT_PORT = '3000'
|
||||
|
||||
const program = new Command()
|
||||
|
||||
program.name('simstudio').description('Run Sim using Docker').version('0.1.0')
|
||||
|
||||
program
|
||||
.option('-p, --port <port>', 'Port to run Sim on', DEFAULT_PORT)
|
||||
.option('-y, --yes', 'Skip interactive prompts and use defaults')
|
||||
.option('--no-pull', 'Skip pulling the latest Docker images')
|
||||
|
||||
function isDockerRunning(): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
const docker = spawn('docker', ['info'])
|
||||
|
||||
docker.on('close', (code) => {
|
||||
resolve(code === 0)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function runCommand(command: string[]): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
const process = spawn(command[0], command.slice(1), { stdio: 'inherit' })
|
||||
process.on('error', () => {
|
||||
resolve(false)
|
||||
})
|
||||
process.on('close', (code) => {
|
||||
resolve(code === 0)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function ensureNetworkExists(): Promise<boolean> {
|
||||
try {
|
||||
const networks = execSync('docker network ls --format "{{.Name}}"').toString()
|
||||
if (!networks.includes(NETWORK_NAME)) {
|
||||
console.log(chalk.blue(`🔄 Creating Docker network '${NETWORK_NAME}'...`))
|
||||
return await runCommand(['docker', 'network', 'create', NETWORK_NAME])
|
||||
}
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('Failed to check networks:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function pullImage(image: string): Promise<boolean> {
|
||||
console.log(chalk.blue(`🔄 Pulling image ${image}...`))
|
||||
return await runCommand(['docker', 'pull', image])
|
||||
}
|
||||
|
||||
async function stopAndRemoveContainer(name: string): Promise<void> {
|
||||
try {
|
||||
execSync(`docker stop ${name} 2>/dev/null || true`)
|
||||
execSync(`docker rm ${name} 2>/dev/null || true`)
|
||||
} catch (_error) {
|
||||
// Ignore errors, container might not exist
|
||||
}
|
||||
}
|
||||
|
||||
async function cleanupExistingContainers(): Promise<void> {
|
||||
console.log(chalk.blue('🧹 Cleaning up any existing containers...'))
|
||||
await stopAndRemoveContainer(APP_CONTAINER)
|
||||
await stopAndRemoveContainer(DB_CONTAINER)
|
||||
await stopAndRemoveContainer(MIGRATIONS_CONTAINER)
|
||||
await stopAndRemoveContainer(REALTIME_CONTAINER)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const options = program.parse().opts()
|
||||
|
||||
console.log(chalk.blue('🚀 Starting Sim...'))
|
||||
|
||||
// Check if Docker is installed and running
|
||||
const dockerRunning = await isDockerRunning()
|
||||
if (!dockerRunning) {
|
||||
console.error(
|
||||
chalk.red('❌ Docker is not running or not installed. Please start Docker and try again.')
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Use port from options, with 3000 as default
|
||||
const port = options.port
|
||||
|
||||
// Pull latest images if not skipped
|
||||
if (options.pull) {
|
||||
await pullImage('ghcr.io/simstudioai/simstudio:latest')
|
||||
await pullImage('ghcr.io/simstudioai/migrations:latest')
|
||||
await pullImage('ghcr.io/simstudioai/realtime:latest')
|
||||
await pullImage('pgvector/pgvector:pg17')
|
||||
}
|
||||
|
||||
// Ensure Docker network exists
|
||||
if (!(await ensureNetworkExists())) {
|
||||
console.error(chalk.red('❌ Failed to create Docker network'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Clean up any existing containers
|
||||
await cleanupExistingContainers()
|
||||
|
||||
// Create data directory
|
||||
const dataDir = join(homedir(), '.simstudio', 'data')
|
||||
if (!existsSync(dataDir)) {
|
||||
try {
|
||||
mkdirSync(dataDir, { recursive: true })
|
||||
} catch (_error) {
|
||||
console.error(chalk.red(`❌ Failed to create data directory: ${dataDir}`))
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Start PostgreSQL container
|
||||
console.log(chalk.blue('🔄 Starting PostgreSQL database...'))
|
||||
const dbSuccess = await runCommand([
|
||||
'docker',
|
||||
'run',
|
||||
'-d',
|
||||
'--name',
|
||||
DB_CONTAINER,
|
||||
'--network',
|
||||
NETWORK_NAME,
|
||||
'-e',
|
||||
'POSTGRES_USER=postgres',
|
||||
'-e',
|
||||
'POSTGRES_PASSWORD=postgres',
|
||||
'-e',
|
||||
'POSTGRES_DB=simstudio',
|
||||
'-v',
|
||||
`${dataDir}/postgres:/var/lib/postgresql/data`,
|
||||
'-p',
|
||||
'5432:5432',
|
||||
'pgvector/pgvector:pg17',
|
||||
])
|
||||
|
||||
if (!dbSuccess) {
|
||||
console.error(chalk.red('❌ Failed to start PostgreSQL'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Wait for PostgreSQL to be ready
|
||||
console.log(chalk.blue('⏳ Waiting for PostgreSQL to be ready...'))
|
||||
let pgReady = false
|
||||
for (let i = 0; i < 30; i++) {
|
||||
try {
|
||||
execSync(`docker exec ${DB_CONTAINER} pg_isready -U postgres`)
|
||||
pgReady = true
|
||||
break
|
||||
} catch (_error) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
}
|
||||
}
|
||||
|
||||
if (!pgReady) {
|
||||
console.error(chalk.red('❌ PostgreSQL failed to become ready'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Run migrations
|
||||
console.log(chalk.blue('🔄 Running database migrations...'))
|
||||
const migrationsSuccess = await runCommand([
|
||||
'docker',
|
||||
'run',
|
||||
'--rm',
|
||||
'--name',
|
||||
MIGRATIONS_CONTAINER,
|
||||
'--network',
|
||||
NETWORK_NAME,
|
||||
'-e',
|
||||
`DATABASE_URL=postgresql://postgres:postgres@${DB_CONTAINER}:5432/simstudio`,
|
||||
'ghcr.io/simstudioai/migrations:latest',
|
||||
'bun',
|
||||
'run',
|
||||
'db:migrate',
|
||||
])
|
||||
|
||||
if (!migrationsSuccess) {
|
||||
console.error(chalk.red('❌ Failed to run migrations'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Start the realtime server
|
||||
console.log(chalk.blue('🔄 Starting Realtime Server...'))
|
||||
const realtimeSuccess = await runCommand([
|
||||
'docker',
|
||||
'run',
|
||||
'-d',
|
||||
'--name',
|
||||
REALTIME_CONTAINER,
|
||||
'--network',
|
||||
NETWORK_NAME,
|
||||
'-p',
|
||||
'3002:3002',
|
||||
'-e',
|
||||
`DATABASE_URL=postgresql://postgres:postgres@${DB_CONTAINER}:5432/simstudio`,
|
||||
'-e',
|
||||
`BETTER_AUTH_URL=http://localhost:${port}`,
|
||||
'-e',
|
||||
`NEXT_PUBLIC_APP_URL=http://localhost:${port}`,
|
||||
'-e',
|
||||
'BETTER_AUTH_SECRET=your_auth_secret_here',
|
||||
'ghcr.io/simstudioai/realtime:latest',
|
||||
])
|
||||
|
||||
if (!realtimeSuccess) {
|
||||
console.error(chalk.red('❌ Failed to start Realtime Server'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Start the main application
|
||||
console.log(chalk.blue('🔄 Starting Sim...'))
|
||||
const appSuccess = await runCommand([
|
||||
'docker',
|
||||
'run',
|
||||
'-d',
|
||||
'--name',
|
||||
APP_CONTAINER,
|
||||
'--network',
|
||||
NETWORK_NAME,
|
||||
'-p',
|
||||
`${port}:3000`,
|
||||
'-e',
|
||||
`DATABASE_URL=postgresql://postgres:postgres@${DB_CONTAINER}:5432/simstudio`,
|
||||
'-e',
|
||||
`BETTER_AUTH_URL=http://localhost:${port}`,
|
||||
'-e',
|
||||
`NEXT_PUBLIC_APP_URL=http://localhost:${port}`,
|
||||
'-e',
|
||||
'BETTER_AUTH_SECRET=your_auth_secret_here',
|
||||
'-e',
|
||||
'ENCRYPTION_KEY=your_encryption_key_here',
|
||||
'ghcr.io/simstudioai/simstudio:latest',
|
||||
])
|
||||
|
||||
if (!appSuccess) {
|
||||
console.error(chalk.red('❌ Failed to start Sim'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log(chalk.green(`✅ Sim is now running at ${chalk.bold(`http://localhost:${port}`)}`))
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
`🛑 To stop all containers, run: ${chalk.bold('docker stop simstudio-app simstudio-db simstudio-realtime')}`
|
||||
)
|
||||
)
|
||||
|
||||
// Handle Ctrl+C
|
||||
const rl = createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
})
|
||||
|
||||
rl.on('SIGINT', async () => {
|
||||
console.log(chalk.yellow('\n🛑 Stopping Sim...'))
|
||||
|
||||
// Stop containers
|
||||
await stopAndRemoveContainer(APP_CONTAINER)
|
||||
await stopAndRemoveContainer(DB_CONTAINER)
|
||||
await stopAndRemoveContainer(REALTIME_CONTAINER)
|
||||
|
||||
console.log(chalk.green('✅ Sim has been stopped'))
|
||||
process.exit(0)
|
||||
})
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(chalk.red('❌ An error occurred:'), error)
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "@sim/tsconfig/library-build.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Reference in New Issue
Block a user