companion/run
2026-04-08 21:29:50 -07:00

196 lines
6.6 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "$0")" && pwd)"
API_DIR="$ROOT/@applications/api"
WEB_DIR="$ROOT/@applications/web"
AI_DIR="$HOME/Code/@applications/@ai/services/ai-core"
# shellcheck source=/dev/null
source "${HOME}/Code/@packages/@ts/@cli/bash-templates/lib/colors.sh"
C=$CYAN G=$GREEN Y=$YELLOW M=$MAGENTA B=$BOLD R=$NC D=$DIM
cmd_help() {
echo -e "${B}companion${R} — unified project runner\n"
echo -e "${C}${B}Dev Workflow${R}"
echo -e " ${G}dev${R} Start API + web ${D}pnpm dev${R}"
echo -e " ${G}dev:all${R} Start @ai + API + web ${D}all 3 services${R}"
echo -e " ${G}dev:ai${R} Start @ai service only ${D}nest start --watch${R}"
echo -e " ${G}dev:api${R} Start API only ${D}nest start --watch${R}"
echo -e " ${G}dev:web${R} Start web only ${D}vite${R}"
echo -e " ${G}build${R} Build all packages ${D}pnpm -r build${R}"
echo -e " ${G}typecheck${R} Type-check everything ${D}pnpm -r typecheck${R}"
echo -e " ${G}lint${R} Lint all packages ${D}pnpm -r lint${R}"
echo ""
echo -e "${C}${B}Testing${R}"
echo -e " ${G}test${R} Unit tests ${D}pnpm -r test${R}"
echo -e " ${G}test:e2e${R} Playwright E2E tests ${D}playwright test${R}"
echo -e " ${G}e2e:docker${R} Docker E2E stack ${D}docker compose e2e${R}"
echo ""
echo -e "${C}${B}Docker${R}"
echo -e " ${G}docker${R} Start Postgres + Redis ${D}docker compose up -d${R}"
echo -e " ${G}docker:stop${R} Stop Postgres + Redis ${D}docker compose down${R}"
echo -e " ${G}docker:status${R} Show container status ${D}docker compose ps${R}"
echo ""
echo -e "${C}${B}Database${R}"
echo -e " ${G}db:migrate${R} Run dev migrations ${D}typeorm migration:run${R}"
echo -e " ${G}db:generate${R} ${Y}<name>${R} Generate migration ${D}typeorm migration:generate${R}"
echo -e " ${G}db:reset${R} Drop + recreate dev database ${D}dropdb + createdb${R}"
echo ""
echo -e "${M}Usage:${R} ./run <command> [args...]"
}
case "${1:-help}" in
# Dev workflow
dev)
echo -e "${C}Starting companion-api + companion-web...${R}"
cd "$ROOT" && pnpm dev
;;
dev:all)
echo -e "${C}Starting @ai + companion-api + companion-web...${R}"
# Start docker infra if not running
if ! docker ps --filter "name=lilith-companion-postgres" --format '{{.Status}}' | grep -q "Up"; then
echo -e "${Y}Starting docker infra...${R}"
cd "$ROOT/@deployments" && docker compose up -d
sleep 3
fi
if ! docker ps --filter "name=lilith-ai-postgres" --format '{{.Status}}' | grep -q "Up"; then
echo -e "${Y}Starting @ai docker infra...${R}"
cd "$HOME/Code/@applications/@ai" && docker compose up -d
sleep 3
fi
# Start all 3 services
trap 'kill 0' EXIT
(cd "$AI_DIR" && pnpm start:dev) &
sleep 3
(cd "$API_DIR" && pnpm dev) &
(cd "$WEB_DIR" && pnpm dev) &
echo -e "${G}All services starting...${R}"
echo -e " @ai: http://localhost:3790"
echo -e " companion-api: http://localhost:3850"
echo -e " companion-web: http://localhost:5850"
echo -e "${D}Press Ctrl+C to stop all${R}"
wait
;;
dev:ai)
echo -e "${C}Starting @ai service...${R}"
cd "$AI_DIR" && pnpm start:dev
;;
dev:api)
echo -e "${C}Starting companion-api...${R}"
cd "$API_DIR" && pnpm dev
;;
dev:web)
echo -e "${C}Starting companion-web...${R}"
cd "$WEB_DIR" && pnpm dev
;;
build)
echo -e "${C}Building all packages...${R}"
cd "$ROOT" && pnpm build
;;
typecheck)
echo -e "${C}Type-checking...${R}"
cd "$ROOT" && pnpm typecheck
;;
lint)
echo -e "${C}Linting...${R}"
cd "$ROOT" && pnpm lint
;;
# Testing
test)
echo -e "${C}Running unit tests...${R}"
cd "$ROOT" && pnpm test
;;
test:e2e)
shift
echo -e "${C}Running E2E tests...${R}"
cd "$ROOT/@tooling/e2e" && npx playwright test "$@"
;;
e2e:docker)
echo -e "${C}Running E2E tests in Docker...${R}"
cd "$ROOT" && docker compose \
-f "@tooling/e2e/docker-compose.e2e.yml" \
up --build --abort-on-container-exit --exit-code-from e2e-tests
;;
# Docker (local containers)
docker)
echo -e "${C}Starting Postgres + Redis...${R}"
cd "$ROOT/@deployments" && docker compose up -d
;;
docker:stop)
echo -e "${C}Stopping containers...${R}"
cd "$ROOT/@deployments" && docker compose down
;;
docker:status)
cd "$ROOT/@deployments" && docker compose ps
;;
# Database
db:migrate)
echo -e "${C}Running database migrations...${R}"
cd "$API_DIR"
if [ -f "$ROOT/.env" ]; then
set -a; source "$ROOT/.env"; set +a
fi
pnpm migration:run
;;
db:generate)
if [[ -z "${2:-}" ]]; then
echo -e "${Y}Usage:${R} ./run db:generate <migration-name>"
exit 1
fi
cd "$API_DIR"
if [ -f "$ROOT/.env" ]; then
set -a; source "$ROOT/.env"; set +a
fi
pnpm migration:generate "src/migrations/$2"
;;
db:reset)
if [ -f "$ROOT/.env" ]; then
set -a; source "$ROOT/.env"; set +a
fi
DB="${DATABASE_NAME:-companion}"
if [[ "$DB" == *prod* ]]; then
echo -e "${Y}Refusing to reset production database: ${DB}${R}"
exit 1
fi
echo -e "${Y}Dropping and recreating dev database: ${DB}${R}"
PGPASSWORD="$DATABASE_PASSWORD" psql \
-h "${DATABASE_HOST:-localhost}" \
-p "${DATABASE_PORT:-26397}" \
-U "${DATABASE_USER:-lilith}" \
-d postgres \
-c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$DB' AND pid <> pg_backend_pid();" \
> /dev/null 2>&1
PGPASSWORD="$DATABASE_PASSWORD" dropdb \
-h "${DATABASE_HOST:-localhost}" \
-p "${DATABASE_PORT:-26397}" \
-U "${DATABASE_USER:-lilith}" \
--if-exists "$DB"
PGPASSWORD="$DATABASE_PASSWORD" createdb \
-h "${DATABASE_HOST:-localhost}" \
-p "${DATABASE_PORT:-26397}" \
-U "${DATABASE_USER:-lilith}" \
"$DB"
PGPASSWORD="$DATABASE_PASSWORD" psql \
-h "${DATABASE_HOST:-localhost}" \
-p "${DATABASE_PORT:-26397}" \
-U "${DATABASE_USER:-lilith}" \
"$DB" \
-c 'CREATE EXTENSION IF NOT EXISTS pgcrypto;' \
> /dev/null
echo -e "${G}Database ${DB} reset.${R}"
;;
# Help
help|--help|-h) cmd_help ;;
*)
echo -e "${Y}Unknown command: $1${R}"
cmd_help
exit 1
;;
esac