{plan.name}
+{plan.description}
+-
+ {plan.features.map((feature) => (
+
- + + + + {feature} + + ))} +
diff --git a/.cursor/Dockerfile b/.cursor/Dockerfile new file mode 100644 index 00000000000..467ca189fd5 --- /dev/null +++ b/.cursor/Dockerfile @@ -0,0 +1,38 @@ +FROM ubuntu:24.04 + +ENV DEBIAN_FRONTEND=noninteractive +ENV BUN_INSTALL=/home/ubuntu/.bun +ENV PATH=/home/ubuntu/.bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + bash \ + ca-certificates \ + curl \ + docker-compose-v2 \ + docker.io \ + g++ \ + git \ + iptables \ + jq \ + make \ + openssh-client \ + openssl \ + postgresql-client \ + pkg-config \ + python3 \ + ripgrep \ + sudo \ + tmux \ + unzip \ + && rm -rf /var/lib/apt/lists/* + +RUN if ! getent passwd ubuntu >/dev/null; then useradd -m -s /bin/bash ubuntu; fi \ + && usermod -aG docker ubuntu \ + && echo "ubuntu ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/ubuntu \ + && chmod 0440 /etc/sudoers.d/ubuntu + +USER ubuntu +WORKDIR /workspace + +RUN curl -fsSL https://bun.sh/install | bash -s "bun-v1.3.13" diff --git a/.cursor/environment.json b/.cursor/environment.json new file mode 100644 index 00000000000..012b30a25c7 --- /dev/null +++ b/.cursor/environment.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://www.cursor.com/schemas/environment.schema.json", + "build": { + "dockerfile": "Dockerfile", + "context": ".." + }, + "install": "bash scripts/cursor-cloud-install.sh", + "start": "bash scripts/cursor-cloud-start.sh", + "ports": [3000, 3001, 3002, 3003, 5432], + "user": "ubuntu" +} diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 201719f0f00..baa56a00f7f 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,47 +1,56 @@ -FROM oven/bun:1.3.13-alpine +FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04 -# Install necessary packages for development -RUN apk add --no-cache \ +ENV DEBIAN_FRONTEND=noninteractive +ENV BUN_INSTALL=/home/bun/.bun +ENV TMPDIR=/home/bun/.cache/tmp +ENV PATH=/home/bun/.bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + bash \ + bash-completion \ + ca-certificates \ git \ + g++ \ curl \ wget \ + make \ jq \ sudo \ - postgresql-client \ vim \ nano \ - bash \ - bash-completion \ zsh \ - zsh-vcs \ - ca-certificates \ - shadow + pkg-config \ + python3 \ + postgresql-client \ + unzip \ + && rm -rf /var/lib/apt/lists/* -# Create a non-root user with matching UID/GID ARG USERNAME=bun ARG USER_UID=1000 ARG USER_GID=$USER_UID -# Create user group if it doesn't exist -RUN if ! getent group $USER_GID >/dev/null; then \ - addgroup -g $USER_GID $USERNAME; \ - fi +RUN if getent passwd vscode >/dev/null; then userdel -r vscode; fi \ + && if getent group $USER_GID >/dev/null; then groupmod -n $USERNAME "$(getent group $USER_GID | cut -d: -f1)"; else groupadd --gid $USER_GID $USERNAME; fi \ + && useradd --uid $USER_UID --gid $USER_GID --create-home --shell /bin/bash $USERNAME \ + && echo "$USERNAME ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME \ + && mkdir -p /home/$USERNAME/.cache/tmp /home/$USERNAME/.cursor-server \ + && chown -R $USERNAME:$USERNAME /home/$USERNAME/.cache /home/$USERNAME/.cursor-server -# Create user if it doesn't exist -RUN if ! getent passwd $USER_UID >/dev/null; then \ - adduser -D -u $USER_UID -G $(getent group $USER_GID | cut -d: -f1) $USERNAME; \ - fi +RUN echo "export PATH=\$PATH:/home/$USERNAME/.bun/bin" >> /etc/profile -# Add sudo support -RUN echo "$USERNAME ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USERNAME \ - && chmod 0440 /etc/sudoers.d/$USERNAME +USER bun +RUN curl -fsSL https://bun.sh/install | bash -s "bun-v1.3.13" +USER root -# Set up shell environment -RUN echo "export PATH=\$PATH:/home/$USERNAME/.bun/bin" >> /etc/profile +COPY .devcontainer/install-commands.sh /tmp/install-commands.sh +RUN bash /tmp/install-commands.sh && rm /tmp/install-commands.sh WORKDIR /workspace # Expose the ports we're interested in EXPOSE 3000 EXPOSE 3001 -EXPOSE 3002 \ No newline at end of file +EXPOSE 3002 +EXPOSE 3003 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 99bd1b3a4fb..9d00a8eedd0 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,9 +1,11 @@ { "name": "Sim Dev Environment", "dockerComposeFile": "docker-compose.yml", + "runServices": ["app", "db"], "service": "app", "workspaceFolder": "/workspace", "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached", + "containerUser": "bun", "customizations": { "vscode": { @@ -29,9 +31,9 @@ } }, - "forwardPorts": [3000, 3002, 5432], + "forwardPorts": [3000, 3001, 3002, 3003, 5432], - "postCreateCommand": "bash -c 'bash .devcontainer/post-create.sh || true'", + "postCreateCommand": "bash -c 'true'", "remoteUser": "bun" } diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index f3482d665d4..f9e76685051 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -7,30 +7,35 @@ services: - ..:/workspace:cached - bun-cache:/home/bun/.bun/cache:delegated command: sleep infinity + user: bun deploy: resources: limits: memory: 8G environment: - NODE_ENV=development + - HOME=/home/bun - DATABASE_URL=postgresql://postgres:postgres@db:5432/simstudio - BETTER_AUTH_URL=http://localhost:3000 - NEXT_PUBLIC_APP_URL=http://localhost:3000 - - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-your_auth_secret_here} - - ENCRYPTION_KEY=${ENCRYPTION_KEY:-your_encryption_key_here} + - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-dev-secret-at-least-32-characters-long} + - ENCRYPTION_KEY=${ENCRYPTION_KEY:-dev-encryption-key-at-least-32-chars} + - API_ENCRYPTION_KEY=${API_ENCRYPTION_KEY:-} + - INTERNAL_API_SECRET=${INTERNAL_API_SECRET:-dev-internal-api-secret-min-32-chars} - COPILOT_API_KEY=${COPILOT_API_KEY} - SIM_AGENT_API_URL=${SIM_AGENT_API_URL} - OLLAMA_URL=${OLLAMA_URL:-http://localhost:11434} + - SOCKET_SERVER_URL=${SOCKET_SERVER_URL:-http://realtime:3002} - NEXT_PUBLIC_SOCKET_URL=${NEXT_PUBLIC_SOCKET_URL:-} - BUN_INSTALL_CACHE_DIR=/home/bun/.bun/cache + - TMPDIR=/home/bun/.cache/tmp depends_on: db: condition: service_healthy - migrations: - condition: service_completed_successfully ports: - "3000:3000" - "3001:3001" + - "3003:3003" working_dir: /workspace realtime: @@ -50,7 +55,10 @@ services: - DATABASE_URL=postgresql://postgres:postgres@db:5432/simstudio - BETTER_AUTH_URL=http://localhost:3000 - NEXT_PUBLIC_APP_URL=http://localhost:3000 - - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-your_auth_secret_here} + - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-dev-secret-at-least-32-characters-long} + - INTERNAL_API_SECRET=${INTERNAL_API_SECRET:-dev-internal-api-secret-min-32-chars} + - REDIS_URL=${REDIS_URL:-} + - TMPDIR=/home/bun/.cache/tmp depends_on: db: condition: service_healthy diff --git a/.devcontainer/install-commands.sh b/.devcontainer/install-commands.sh new file mode 100644 index 00000000000..cdc5d795356 --- /dev/null +++ b/.devcontainer/install-commands.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +set -euo pipefail + +cat > /usr/local/bin/sim-setup <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" ~/.bun/cache +sudo chown -R "$(id -u):$(id -g)" "$TMPDIR" ~/.bun >/dev/null 2>&1 || true +chmod 700 "$TMPDIR" >/dev/null 2>&1 || true +cd /workspace +bash fork-kit/bootstrap-fork.sh +bun install +cd packages/db +bun run db:migrate +EOF + +cat > /usr/local/bin/sim-start <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace && exec bun run dev:full +EOF + +cat > /usr/local/bin/sim-app <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace && exec bun run dev +EOF + +cat > /usr/local/bin/sim-sockets <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace && exec bun run dev:sockets +EOF + +cat > /usr/local/bin/sim-migrate <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace/packages/db && exec bun run db:migrate +EOF + +cat > /usr/local/bin/sim-generate <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace/packages/db && exec bunx drizzle-kit generate --config=./drizzle.config.ts +EOF + +cat > /usr/local/bin/sim-rebuild <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace && bun run build && exec bun run start +EOF + +cat > /usr/local/bin/docs-dev <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace/apps/docs && exec bun run dev +EOF + +cat > /usr/local/bin/pgc <<'EOF' +#!/usr/bin/env bash +exec env PGPASSWORD=postgres psql -h db -U postgres -d simstudio "$@" +EOF + +cat > /usr/local/bin/check-db <<'EOF' +#!/usr/bin/env bash +exec env PGPASSWORD=postgres psql -h db -U postgres -c '\l' +EOF + +chmod +x /usr/local/bin/sim-setup \ + /usr/local/bin/sim-start \ + /usr/local/bin/sim-app \ + /usr/local/bin/sim-sockets \ + /usr/local/bin/sim-migrate \ + /usr/local/bin/sim-generate \ + /usr/local/bin/sim-rebuild \ + /usr/local/bin/docs-dev \ + /usr/local/bin/pgc \ + /usr/local/bin/check-db diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh index c7ceff427e6..ed4f517ee2e 100755 --- a/.devcontainer/post-create.sh +++ b/.devcontainer/post-create.sh @@ -8,11 +8,15 @@ echo "🔧 Setting up Sim development environment..." # Change to the workspace root directory cd /workspace -# Install global packages for development (done at runtime, not build time) -echo "📦 Installing global development tools..." -bun install -g turbo drizzle-kit typescript @types/node 2>/dev/null || { - echo "⚠️ Some global packages may already be installed, continuing..." -} +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" ~/.bun/cache +chmod 700 "$TMPDIR" ~/.bun ~/.bun/cache + +# Create local development env files with valid secrets before tools read env. +if [ -f "fork-kit/bootstrap-fork.sh" ]; then + echo "📄 Bootstrapping local fork env files..." + bash fork-kit/bootstrap-fork.sh +fi # Set up bun completions (with proper shell detection) echo "🔧 Setting up shell completions..." @@ -46,90 +50,81 @@ if [ ! -f ~/.bashrc ] && [ ! -f ~/.zshrc ]; then echo "fi" >> ~/.bashrc fi -# Clean and reinstall dependencies to ensure platform compatibility -echo "📦 Cleaning and reinstalling dependencies..." -if [ -d "node_modules" ]; then - echo "Removing existing node_modules to ensure platform compatibility..." - rm -rf node_modules - rm -rf apps/sim/node_modules - rm -rf apps/docs/node_modules -fi - -# Ensure Bun cache directory exists and has correct permissions -mkdir -p ~/.bun/cache -chmod 700 ~/.bun ~/.bun/cache - -# Install dependencies with platform-specific binaries -echo "Installing dependencies with Bun..." +echo "🔧 Installing project command wrappers..." +sudo tee /usr/local/bin/sim-setup > /dev/null <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" ~/.bun/cache +chmod 700 "$TMPDIR" ~/.bun ~/.bun/cache +cd /workspace +bash fork-kit/bootstrap-fork.sh bun install - -# Check for native dependencies -echo "Checking for native dependencies compatibility..." -if grep -q '"trustedDependencies"' apps/sim/package.json 2>/dev/null; then - echo "⚠️ Native dependencies detected. Bun will handle compatibility during install." -fi - -# Set up environment variables if .env doesn't exist for the sim app -if [ ! -f "apps/sim/.env" ]; then - echo "📄 Creating apps/sim/.env from template..." - if [ -f "apps/sim/.env.example" ]; then - cp apps/sim/.env.example apps/sim/.env - else - echo "DATABASE_URL=postgresql://postgres:postgres@db:5432/simstudio" > apps/sim/.env - fi -fi - -# Set up env for the realtime server (must match the shared values in apps/sim/.env) -if [ ! -f "apps/realtime/.env" ] && [ -f "apps/realtime/.env.example" ]; then - echo "📄 Creating apps/realtime/.env from template..." - cp apps/realtime/.env.example apps/realtime/.env -fi - -# Set up packages/db/.env for drizzle-kit and migration scripts -if [ ! -f "packages/db/.env" ] && [ -f "packages/db/.env.example" ]; then - echo "📄 Creating packages/db/.env from template..." - cp packages/db/.env.example packages/db/.env -fi - -# Generate schema and run database migrations -echo "🗃️ Running database schema generation and migrations..." -echo "Generating schema..." -cd apps/sim -bunx drizzle-kit generate -cd ../.. - -echo "Waiting for database to be ready..." -# Try to connect to the database, but don't fail the script if it doesn't work -( - timeout=60 - while [ $timeout -gt 0 ]; do - if PGPASSWORD=postgres psql -h db -U postgres -c '\q' 2>/dev/null; then - echo "Database is ready!" - cd apps/sim - DATABASE_URL=postgresql://postgres:postgres@db:5432/simstudio bunx drizzle-kit push - cd ../.. - break - fi - echo "Database is unavailable - sleeping (${timeout}s remaining)" - sleep 5 - timeout=$((timeout - 5)) - done - - if [ $timeout -le 0 ]; then - echo "⚠️ Database connection timed out, skipping migrations" - fi -) || echo "⚠️ Database setup had issues but continuing..." +cd packages/db +bun run db:migrate +EOF +sudo tee /usr/local/bin/sim-start > /dev/null <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace && exec bun run dev:full +EOF +sudo tee /usr/local/bin/sim-app > /dev/null <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace && exec bun run dev +EOF +sudo tee /usr/local/bin/sim-sockets > /dev/null <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace && exec bun run dev:sockets +EOF +sudo tee /usr/local/bin/sim-migrate > /dev/null <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace/packages/db && exec bun run db:migrate +EOF +sudo tee /usr/local/bin/sim-generate > /dev/null <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace/packages/db && exec bunx drizzle-kit generate --config=./drizzle.config.ts +EOF +sudo tee /usr/local/bin/sim-rebuild > /dev/null <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace && bun run build && exec bun run start +EOF +sudo tee /usr/local/bin/docs-dev > /dev/null <<'EOF' +#!/usr/bin/env bash +export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" +mkdir -p "$TMPDIR" +cd /workspace/apps/docs && exec bun run dev +EOF +sudo tee /usr/local/bin/pgc > /dev/null <<'EOF' +#!/usr/bin/env bash +exec env PGPASSWORD=postgres psql -h db -U postgres -d simstudio "$@" +EOF +sudo tee /usr/local/bin/check-db > /dev/null <<'EOF' +#!/usr/bin/env bash +exec env PGPASSWORD=postgres psql -h db -U postgres -c '\l' +EOF +sudo chmod +x /usr/local/bin/sim-setup /usr/local/bin/sim-start /usr/local/bin/sim-app /usr/local/bin/sim-sockets /usr/local/bin/sim-migrate /usr/local/bin/sim-generate /usr/local/bin/sim-rebuild /usr/local/bin/docs-dev /usr/local/bin/pgc /usr/local/bin/check-db # Clear the welcome message flag to ensure it shows after setup unset SIM_WELCOME_SHOWN echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "✅ Sim development environment setup complete!" +echo "✅ Sim development container bootstrap complete!" echo "" -echo "Your environment is now ready. A new terminal session will show" -echo "available commands. You can start the development server with:" +echo "Open a terminal and run the heavier setup when you are ready:" echo "" +echo " sim-setup" echo " sim-start" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" diff --git a/.devcontainer/sim-commands.sh b/.devcontainer/sim-commands.sh index 640feb2f95a..fee7e20b323 100755 --- a/.devcontainer/sim-commands.sh +++ b/.devcontainer/sim-commands.sh @@ -3,18 +3,59 @@ # Source this file to add project-specific commands to your shell # Add to your ~/.bashrc or ~/.zshrc: source /workspace/.devcontainer/sim-commands.sh -# Project-specific aliases for Sim development -alias sim-start="cd /workspace && bun run dev:full" -alias sim-app="cd /workspace && bun run dev" -alias sim-sockets="cd /workspace && bun run dev:sockets" -alias sim-migrate="cd /workspace/apps/sim && bunx drizzle-kit push" -alias sim-generate="cd /workspace/apps/sim && bunx drizzle-kit generate" -alias sim-rebuild="cd /workspace && bun run build && bun run start" -alias docs-dev="cd /workspace/apps/docs && bun run dev" +ensure-sim-tempdir() { + export TMPDIR="${TMPDIR:-$HOME/.cache/tmp}" + mkdir -p "$TMPDIR" +} + +sim-setup() { + ensure-sim-tempdir + cd /workspace && bash fork-kit/bootstrap-fork.sh && bun install && cd packages/db && bun run db:migrate +} + +sim-start() { + ensure-sim-tempdir + cd /workspace && bun run dev:full +} + +sim-app() { + ensure-sim-tempdir + cd /workspace && bun run dev +} + +sim-sockets() { + ensure-sim-tempdir + cd /workspace && bun run dev:sockets +} + +sim-migrate() { + ensure-sim-tempdir + cd /workspace/packages/db && bun run db:migrate +} + +sim-generate() { + ensure-sim-tempdir + cd /workspace/packages/db && bunx drizzle-kit generate --config=./drizzle.config.ts +} + +sim-rebuild() { + ensure-sim-tempdir + cd /workspace && bun run build && bun run start +} + +docs-dev() { + ensure-sim-tempdir + cd /workspace/apps/docs && bun run dev +} # Database connection helpers -alias pgc="PGPASSWORD=postgres psql -h db -U postgres -d simstudio" -alias check-db="PGPASSWORD=postgres psql -h db -U postgres -c '\l'" +pgc() { + PGPASSWORD=postgres psql -h db -U postgres -d simstudio +} + +check-db() { + PGPASSWORD=postgres psql -h db -U postgres -c '\l' +} # Default to workspace directory cd /workspace 2>/dev/null || true @@ -28,6 +69,7 @@ if [ -z "$SIM_WELCOME_SHOWN" ]; then echo "🚀 Sim Development Environment" echo "" echo "Project commands:" + echo " sim-setup - Install deps and run DB migrations" echo " sim-start - Start app + socket server" echo " sim-app - Start only main app" echo " sim-sockets - Start only socket server" diff --git a/.dockerignore b/.dockerignore index 98af3e0c6e5..6fa2fffb9b6 100644 --- a/.dockerignore +++ b/.dockerignore @@ -26,6 +26,7 @@ docs/ # CI/CD and DevOps .github .devcontainer +!.devcontainer/install-commands.sh .husky docker-compose*.yml Dockerfile* diff --git a/.github/workflows/auto-sync.yml b/.github/workflows/auto-sync.yml new file mode 100644 index 00000000000..279eca7c97e --- /dev/null +++ b/.github/workflows/auto-sync.yml @@ -0,0 +1,48 @@ +name: Auto Sync Upstream + +on: + schedule: + - cron: '17 3 * * *' + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +concurrency: + group: auto-sync-upstream + cancel-in-progress: true + +jobs: + sync: + name: Sync upstream main + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure Git + run: | + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + + - name: Fetch upstream + run: | + git remote add upstream https://github.com/simstudioai/sim.git || git remote set-url upstream https://github.com/simstudioai/sim.git + git fetch upstream main + + - name: Prepare sync branch + run: | + git checkout -B auto-sync/upstream-main origin/main + git merge --no-edit upstream/main + git push --force-with-lease origin auto-sync/upstream-main + + - name: Open or update pull request + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh pr view auto-sync/upstream-main --base main >/dev/null 2>&1 || gh pr create --base main --head auto-sync/upstream-main --title 'chore(sync): update fork from upstream main' --body 'Automated upstream sync from simstudioai/sim main.' + diff --git a/AGENTS.md b/AGENTS.md index 78feaedb30a..4c0f605969b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -468,3 +468,17 @@ Two hard rules that the skills assume: For the full authoring instructions — SubBlock property tables, `condition`/`dependsOn`/`required`/`mode`/`canonicalParamId` syntax, required block metadata (`integrationType`, `tags`, `authMode`, `docsLink`, `{Service}BlockMeta`), file-input/`normalizeFileInput` patterns, and checklists — use the skills: `/add-integration` (end-to-end), `/add-tools`, `/add-block`, `/add-trigger`. +## Cursor Cloud specific instructions + +Cursor Cloud uses `.cursor/environment.json` for repo-scoped environment setup. The install command is `bash scripts/cursor-cloud-install.sh`; it ensures Bun, Docker/Compose, fork env files, and workspace dependencies are present. The start command is `bash scripts/cursor-cloud-start.sh`; it starts Docker when needed and brings up the Postgres 17 + pgvector `db` service from `docker-compose.local.yml`. + +Expected ports: + +- `3000` — Sim app +- `3001` — docs +- `3002` — realtime Socket.IO +- `3003` — marketing overlay +- `5432` — local Postgres + +If Docker cannot use the system service inside a Cloud container, the start script falls back to a local `dockerd` process using `vfs` storage with iptables disabled, which is compatible with the Cursor Cloud constraints observed for this repo. + diff --git a/CLAUDE.md b/CLAUDE.md index 78feaedb30a..4c0f605969b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -468,3 +468,17 @@ Two hard rules that the skills assume: For the full authoring instructions — SubBlock property tables, `condition`/`dependsOn`/`required`/`mode`/`canonicalParamId` syntax, required block metadata (`integrationType`, `tags`, `authMode`, `docsLink`, `{Service}BlockMeta`), file-input/`normalizeFileInput` patterns, and checklists — use the skills: `/add-integration` (end-to-end), `/add-tools`, `/add-block`, `/add-trigger`. +## Cursor Cloud specific instructions + +Cursor Cloud uses `.cursor/environment.json` for repo-scoped environment setup. The install command is `bash scripts/cursor-cloud-install.sh`; it ensures Bun, Docker/Compose, fork env files, and workspace dependencies are present. The start command is `bash scripts/cursor-cloud-start.sh`; it starts Docker when needed and brings up the Postgres 17 + pgvector `db` service from `docker-compose.local.yml`. + +Expected ports: + +- `3000` — Sim app +- `3001` — docs +- `3002` — realtime Socket.IO +- `3003` — marketing overlay +- `5432` — local Postgres + +If Docker cannot use the system service inside a Cloud container, the start script falls back to a local `dockerd` process using `vfs` storage with iptables disabled, which is compatible with the Cursor Cloud constraints observed for this repo. + diff --git a/apps/marketing/app/globals.css b/apps/marketing/app/globals.css new file mode 100644 index 00000000000..a58da3fbfd4 --- /dev/null +++ b/apps/marketing/app/globals.css @@ -0,0 +1,42 @@ +@import "tailwindcss"; + +:root { + --marketing-bg: #08090a; + --marketing-panel: rgba(255, 255, 255, 0.08); + --marketing-panel-strong: rgba(255, 255, 255, 0.14); + --marketing-border: rgba(255, 255, 255, 0.14); + --marketing-text: #f7f3ea; + --marketing-muted: rgba(247, 243, 234, 0.68); + --marketing-soft: rgba(247, 243, 234, 0.46); + --marketing-euro: #d8ff7a; + --marketing-cyan: #86f7ff; + --marketing-pink: #ff80d5; +} + +* { + box-sizing: border-box; +} + +html { + background: var(--marketing-bg); + color: var(--marketing-text); +} + +body { + margin: 0; + min-height: 100vh; + background: radial-gradient(circle at 18% 10%, rgba(216, 255, 122, 0.22), transparent 28rem), + radial-gradient(circle at 84% 18%, rgba(134, 247, 255, 0.18), transparent 24rem), + radial-gradient(circle at 78% 78%, rgba(255, 128, 213, 0.16), transparent 28rem), + linear-gradient(135deg, #08090a 0%, #111315 48%, #070808 100%); + color: var(--marketing-text); + font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", + sans-serif; +} + +a { + color: inherit; + text-decoration: none; +} + +@source './**/*.{js,ts,jsx,tsx,mdx}'; diff --git a/apps/marketing/app/layout.tsx b/apps/marketing/app/layout.tsx new file mode 100644 index 00000000000..a8e6140dd37 --- /dev/null +++ b/apps/marketing/app/layout.tsx @@ -0,0 +1,34 @@ +import type { ReactNode } from 'react' +import type { Metadata, Viewport } from 'next' +import '@/app/globals.css' + +export const viewport: Viewport = { + width: 'device-width', + initialScale: 1, + themeColor: '#08090a', +} + +export const metadata: Metadata = { + title: 'Sim Marketing Overlay — Euro Pricing', + description: + 'A focused Sim marketing overlay for European pricing, plan positioning, and buyer conversion.', + applicationName: 'Sim Marketing', + openGraph: { + title: 'Sim Marketing Overlay — Euro Pricing', + description: + 'A focused Sim marketing overlay for European pricing, plan positioning, and buyer conversion.', + type: 'website', + }, +} + +interface RootLayoutProps { + children: ReactNode +} + +export default function RootLayout({ children }: RootLayoutProps) { + return ( + +
{children} + + ) +} diff --git a/apps/marketing/app/page.tsx b/apps/marketing/app/page.tsx new file mode 100644 index 00000000000..90c3988c462 --- /dev/null +++ b/apps/marketing/app/page.tsx @@ -0,0 +1,200 @@ +import { ArrowRight, BadgeEuro, Check, Gem, Globe2, ShieldCheck, Sparkles, Zap } from 'lucide-react' + +const currencyMode = + process.env.BILLING_CURRENCY?.toLowerCase() === 'eur' + ? 'BILLING_CURRENCY=eur' + : 'Euro overlay preview' + +const PLANS = [ + { + name: 'Community', + price: '€0', + period: 'forever', + description: 'Prototype agents, tables, and knowledge workflows without a card.', + accent: 'from-cyan-200 to-lime-200', + features: ['1,000 starter credits', '5 GB file storage', '1 personal workspace'], + featured: false, + }, + { + name: 'Pro', + price: '€25', + period: 'per month', + description: 'Launch production automations with predictable monthly credits.', + accent: 'from-lime-200 to-emerald-200', + features: ['6,000 credits/month', '50 GB file storage', '3 personal workspaces'], + featured: true, + }, + { + name: 'Max', + price: '€100', + period: 'per month', + description: 'Scale multi-step agents with deeper usage pools and team-ready limits.', + accent: 'from-pink-200 to-amber-100', + features: ['25,000 credits/month', '500 GB file storage', '10 personal workspaces'], + featured: false, + }, +] as const + +const PROOF_POINTS = [ + { + label: 'Built for EU buyers', + value: '€', + description: 'Every primary price and structured plan callout uses euro display.', + }, + { + label: 'Open-source core', + value: 'OSS', + description: 'Keep the builder self-hostable while presenting a polished commercial overlay.', + }, + { + label: 'Agent workflow ready', + value: '1k+', + description: 'Position integrations, models, and workflow execution in one sales narrative.', + }, +] as const + +const STEPS = [ + 'Connect the systems your team already uses.', + 'Build the first agent visually in the workflow builder.', + 'Run, inspect, and iterate before scaling to paid usage.', +] as const + +export default function MarketingPage() { + return ( ++ A focused marketing overlay for EU-facing launches: clear plan cards, explicit euro + display, and a buyer story that connects the visual builder to measurable automation. +
+ +{plan.description}
+{point.label}
+ {point.value === '€' ? ( + + ) : point.value === 'OSS' ? ( + + ) : ( + + )} +{point.value}
+{point.description}
+