From 63186161ea7a4b99af300475821d03cefa37f9f7 Mon Sep 17 00:00:00 2001 From: Noah Stevens Date: Mon, 11 May 2026 18:32:26 -0400 Subject: [PATCH] Improve fresh local setup flow --- README.md | 26 +++++- package.json | 1 + packages/app/control/scripts/setup.sh | 81 ++++++++++++++----- .../sdk/examples/next-402-chat/package.json | 2 +- 4 files changed, 88 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 54d3f0c7b..0b05197ad 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,27 @@ Or run `npx echo-start my-app` to choose interactively. # Development -Fill out `packages/app/control/.env` and `packages/app/server/.env`. Then... +Prerequisites: -- `pnpm i` -- `pnpm dev` +- Node.js 18 or newer +- pnpm 10.11.0 or newer +- Docker with Docker Compose + +From a fresh clone: + +```bash +pnpm i +pnpm dev +``` + +`pnpm dev` runs the local setup step automatically. It creates +`packages/app/control/.env` from `.env.example` when needed, generates a local +`AUTH_SECRET`, sets the local PostgreSQL `DATABASE_URL`, starts the Docker +PostgreSQL container, applies Prisma migrations, and starts the control app plus +router server. + +If `pnpm` is not available yet, install the pinned version first: + +```bash +npm install -g pnpm@10.11.0 +``` diff --git a/package.json b/package.json index 48b012f52..16d2420f8 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "private": true, "packageManager": "pnpm@10.11.0", "scripts": { + "predev": "pnpm run local-setup", "dev": "turbo run dev --filter=echo-control --filter=echo-server", "local-setup": "turbo run local-setup --filter=echo-control", "build": "turbo run build --env-mode=loose", diff --git a/packages/app/control/scripts/setup.sh b/packages/app/control/scripts/setup.sh index c7e3e89b7..3e02c1ac7 100755 --- a/packages/app/control/scripts/setup.sh +++ b/packages/app/control/scripts/setup.sh @@ -1,20 +1,65 @@ #!/bin/bash -# Check if .env file exists and if AUTH_SECRET is already set -if [ -f .env ] && grep -q "^AUTH_SECRET=" .env; then - echo "AUTH_SECRET already exists in .env file. Skipping generation." -else - echo "Generating AUTH_SECRET..." - AUTH_SECRET=$(node -e "console.log('AUTH_SECRET=' + require('crypto').randomBytes(32).toString('base64'))") - echo $AUTH_SECRET - echo $AUTH_SECRET >> .env -fi - -# Check if DATABASE_URL is already set -if [ -f .env ] && grep -q "^DATABASE_URL=" .env; then - echo "DATABASE_URL already exists in .env file. Skipping." -else - echo "DATABASE_URL='postgresql://echo_user:echo_password@localhost:5469/echo_control_v2?schema=public'" >> .env -fi - -echo "Setup complete! You can now run 'pnpm dev' to start the development server." +set -euo pipefail + +ENV_FILE=".env" +DATABASE_URL_VALUE='"postgresql://echo_user:echo_password@localhost:5469/echo_control_v2?schema=public"' + +ensure_env_file() { + if [ -f "$ENV_FILE" ]; then + return + fi + + if [ -f ".env.example" ]; then + cp ".env.example" "$ENV_FILE" + echo "Created $ENV_FILE from .env.example." + else + touch "$ENV_FILE" + echo "Created empty $ENV_FILE." + fi +} + +env_value() { + local key="$1" + grep -E "^${key}=" "$ENV_FILE" | tail -n 1 | cut -d= -f2- | tr -d "\"'" +} + +set_env_value() { + local key="$1" + local value="$2" + local current + + current="$(env_value "$key" || true)" + if [ -n "$current" ]; then + echo "$key already exists in $ENV_FILE. Skipping." + return + fi + + if grep -qE "^${key}=" "$ENV_FILE"; then + local temp_file + temp_file="$(mktemp)" + awk -v key="$key" -v replacement="${key}=${value}" ' + BEGIN { replaced = 0 } + $0 ~ "^" key "=" && replaced == 0 { + print replacement + replaced = 1 + next + } + { print } + ' "$ENV_FILE" > "$temp_file" + mv "$temp_file" "$ENV_FILE" + else + printf "%s=%s\n" "$key" "$value" >> "$ENV_FILE" + fi + + echo "Set $key in $ENV_FILE." +} + +ensure_env_file + +AUTH_SECRET_VALUE="\"$(node -e "process.stdout.write(require('crypto').randomBytes(32).toString('base64'))")\"" + +set_env_value "AUTH_SECRET" "$AUTH_SECRET_VALUE" +set_env_value "DATABASE_URL" "$DATABASE_URL_VALUE" + +echo "Setup complete. You can now run 'pnpm dev' to start the development server." diff --git a/packages/sdk/examples/next-402-chat/package.json b/packages/sdk/examples/next-402-chat/package.json index 15446d707..28b73334b 100644 --- a/packages/sdk/examples/next-402-chat/package.json +++ b/packages/sdk/examples/next-402-chat/package.json @@ -7,7 +7,7 @@ "build": "next build --turbopack", "start": "next start", "lint": "biome check --write", - "postinstall": "npm dedupe || true" + "postinstall": "node -e \"if (!(process.env.npm_config_user_agent || '').includes('pnpm')) require('child_process').execSync('npm dedupe', { stdio: 'inherit' })\" || true" }, "dependencies": { "@ai-sdk/openai": "2.0.16",