From d0d01e9a8ebcdea12a2292e773788b1564268758 Mon Sep 17 00:00:00 2001 From: Will Pfleger Date: Fri, 29 May 2026 17:12:51 -0400 Subject: [PATCH 1/3] feat: add shared infra recipes and `just mobile-dev` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `just relay` previously assumed Docker services were already running, requiring manual `docker compose up` first. The desktop and mobile workflows had the same gap — multiple manual steps across terminals. Adds `_ensure-services` and `_ensure-migrations` private recipes that idempotently start Docker services and wait for health. Wires `relay` to depend on `_ensure-migrations` so it works from a cold start. Adds `mobile-dev` that handles the full stack: Docker, relay (background), iOS simulator, and `flutter run` — all in one command. --- justfile | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/justfile b/justfile index 53d96c944..991916d7a 100644 --- a/justfile +++ b/justfile @@ -122,6 +122,40 @@ _ensure-sidecar-stubs: touch "desktop/src-tauri/binaries/${bin}-${TARGET}" done +# Ensure Docker dev services (Postgres, Redis, etc.) are running and healthy +_ensure-services: + #!/usr/bin/env bash + set -euo pipefail + pg=$(docker inspect --format '{{"{{"}}.State.Health.Status{{"}}"}}' sprout-postgres 2>/dev/null || echo "not_found") + redis=$(docker inspect --format '{{"{{"}}.State.Health.Status{{"}}"}}' sprout-redis 2>/dev/null || echo "not_found") + if [[ "$pg" == "healthy" && "$redis" == "healthy" ]]; then + echo "Services already healthy" + exit 0 + fi + echo "Starting services..." + docker compose up -d || true + echo -n "Waiting for services" + for i in $(seq 1 40); do + pg=$(docker inspect --format '{{"{{"}}.State.Health.Status{{"}}"}}' sprout-postgres 2>/dev/null || echo "not_found") + redis=$(docker inspect --format '{{"{{"}}.State.Health.Status{{"}}"}}' sprout-redis 2>/dev/null || echo "not_found") + if [[ "$pg" == "healthy" && "$redis" == "healthy" ]]; then + echo " ready" + exit 0 + fi + echo -n "." + sleep 3 + done + echo " timed out" + exit 1 + +# Apply database migrations if pgschema is available +_ensure-migrations: _ensure-services + #!/usr/bin/env bash + set -euo pipefail + if [[ -x bin/pgschema && -f schema/schema.sql ]]; then + bin/pgschema apply --file schema/schema.sql --auto-approve 2>/dev/null || true + fi + # Run clippy on the desktop Tauri Rust crate desktop-tauri-clippy: _ensure-sidecar-stubs cargo clippy --manifest-path {{desktop_tauri_manifest}} --all-targets -- -D warnings @@ -188,8 +222,8 @@ test-integration: # ─── Run ────────────────────────────────────────────────────────────────────── -# Start the relay server -relay: +# Start the relay server (auto-starts Docker services if needed) +relay: _ensure-migrations cargo run -p sprout-relay # Start the relay with the built web UI served from it @@ -318,6 +352,29 @@ mobile-check: mobile-test: unset GIT_DIR GIT_WORK_TREE; cd {{mobile_dir}} && flutter test +# Run the mobile app on iOS simulator (starts infra + relay automatically) +mobile-dev: + #!/usr/bin/env bash + set -euo pipefail + just _ensure-migrations + # Start relay in background if not already running + if ! lsof -i :3000 -sTCP:LISTEN -t &>/dev/null; then + echo "Starting relay in background (log: /tmp/sprout-relay.log)..." + cargo run -p sprout-relay &>/tmp/sprout-relay.log & + sleep 3 + else + echo "Relay already running on :3000" + fi + # Open iOS simulator if not already running + if ! pgrep -x Simulator &>/dev/null; then + open -a Simulator + sleep 3 + fi + # Run Flutter + cd {{mobile_dir}} + unset GIT_DIR GIT_WORK_TREE + flutter run + # ─── Database ───────────────────────────────────────────────────────────────── # Apply schema migrations via pgschema From e9f8b548856ffcc607797ee615a8d7b8f7375d5c Mon Sep 17 00:00:00 2001 From: Will Pfleger Date: Fri, 29 May 2026 17:58:20 -0400 Subject: [PATCH 2/3] refactor: consolidate Docker infra management into justfile recipes Three places duplicated Docker health-check and migration logic: justfile, dev-setup.sh, and run-tests.sh. Make the justfile's _ensure-services and _ensure-migrations recipes the single source of truth and have scripts delegate to them via hermit-managed just. Also wires all relay/e2e/migrate recipes to auto-start infra, removes dead recipes (web-install, web-install-ci, desktop-app), and adds a mobile-dev recipe for one-command iOS development. --- justfile | 35 +++++++++++++-------------- scripts/dev-setup.sh | 52 +++------------------------------------- scripts/run-tests.sh | 56 +++----------------------------------------- 3 files changed, 22 insertions(+), 121 deletions(-) diff --git a/justfile b/justfile index 991916d7a..c4f051e15 100644 --- a/justfile +++ b/justfile @@ -153,7 +153,7 @@ _ensure-migrations: _ensure-services #!/usr/bin/env bash set -euo pipefail if [[ -x bin/pgschema && -f schema/schema.sql ]]; then - bin/pgschema apply --file schema/schema.sql --auto-approve 2>/dev/null || true + bin/pgschema apply --file schema/schema.sql --auto-approve || true fi # Run clippy on the desktop Tauri Rust crate @@ -187,7 +187,7 @@ desktop-release-build target="aarch64-apple-darwin": desktop-ci: desktop-check desktop-test desktop-tauri-fmt-check desktop-build desktop-tauri-check desktop-tauri-test # Seed deterministic channel data for desktop Playwright tests -desktop-e2e-seed: +desktop-e2e-seed: _ensure-migrations ./scripts/setup-desktop-test-data.sh # Run desktop browser smoke tests @@ -195,7 +195,7 @@ desktop-e2e-smoke: cd {{desktop_dir}} && pnpm test:e2e:smoke # Run desktop relay-backed e2e tests -desktop-e2e-integration: +desktop-e2e-integration: _ensure-migrations cd {{desktop_dir}} && pnpm test:e2e:integration # Run all checks suitable for CI / pre-push (no infra needed) @@ -227,7 +227,7 @@ relay: _ensure-migrations cargo run -p sprout-relay # Start the relay with the built web UI served from it -relay-web: +relay-web: _ensure-migrations #!/usr/bin/env bash set -euo pipefail [[ -d node_modules ]] || pnpm install @@ -235,7 +235,7 @@ relay-web: SPROUT_WEB_DIR=./web/dist cargo run -p sprout-relay # Start the relay server in release mode -relay-release: +relay-release: _ensure-migrations cargo run -p sprout-relay --release # Start sprout-proxy (dev mode) @@ -282,10 +282,6 @@ desktop-dev: echo "Starting frontend dev server on Vite port ${SPROUT_VITE_PORT}, relay ${SPROUT_RELAY_URL}" pnpm exec vite --port "${SPROUT_VITE_PORT}" --strictPort -# Run the desktop Tauri app (alias for dev) -desktop-app *ARGS: - just dev {{ARGS}} - # ─── Web ───────────────────────────────────────────────────────────────────── # Run the web frontend dev server (port derived from worktree to avoid collisions) @@ -300,14 +296,6 @@ web: cd {{web_dir}} pnpm exec vite --port "${VITE_PORT}" --strictPort -# Install web JS dependencies (pnpm workspace — installs all packages from root) -web-install: - pnpm install - -# Install web JS dependencies reproducibly for CI (pnpm workspace) -web-install-ci: - pnpm install --frozen-lockfile - # Run web lint and format checks web-check: cd {{web_dir}} && pnpm check @@ -358,10 +346,19 @@ mobile-dev: set -euo pipefail just _ensure-migrations # Start relay in background if not already running + RELAY_PID="" if ! lsof -i :3000 -sTCP:LISTEN -t &>/dev/null; then echo "Starting relay in background (log: /tmp/sprout-relay.log)..." cargo run -p sprout-relay &>/tmp/sprout-relay.log & - sleep 3 + RELAY_PID=$! + trap 'if [[ -n "$RELAY_PID" ]]; then kill "$RELAY_PID" 2>/dev/null || true; fi' EXIT + echo -n "Waiting for relay" + for _ in $(seq 1 30); do + lsof -i :3000 -sTCP:LISTEN -t &>/dev/null && break + echo -n "." + sleep 3 + done + echo " ready" else echo "Relay already running on :3000" fi @@ -378,7 +375,7 @@ mobile-dev: # ─── Database ───────────────────────────────────────────────────────────────── # Apply schema migrations via pgschema -migrate: +migrate: _ensure-services ./bin/pgschema apply --file schema/schema.sql --auto-approve # ─── Utilities ──────────────────────────────────────────────────────────────── diff --git a/scripts/dev-setup.sh b/scripts/dev-setup.sh index 5d27e3fc9..a6ea6277a 100755 --- a/scripts/dev-setup.sh +++ b/scripts/dev-setup.sh @@ -11,7 +11,6 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" -TIMEOUT=120 # seconds to wait for services to become healthy # Colors RED='\033[0;31m' @@ -71,53 +70,8 @@ load_env # ---- Start services --------------------------------------------------------- -log "Starting services..." -docker compose up -d - -# ---- Wait for healthy ------------------------------------------------------- - -wait_healthy() { - local service="$1" - local container="$2" - local elapsed=0 - local interval=3 - - log "Waiting for ${service} to be healthy..." - while true; do - local status - status=$(docker inspect --format='{{.State.Health.Status}}' "${container}" 2>/dev/null || echo "not_found") - - case "${status}" in - healthy) - success "${service} is healthy" - return 0 - ;; - unhealthy) - error "${service} is unhealthy. Check logs: docker logs ${container}" - return 1 - ;; - not_found) - error "Container ${container} not found" - return 1 - ;; - esac - - if [[ ${elapsed} -ge ${TIMEOUT} ]]; then - error "Timed out waiting for ${service} (${TIMEOUT}s). Check: docker logs ${container}" - return 1 - fi - - sleep "${interval}" - elapsed=$((elapsed + interval)) - echo -n "." - done -} - -echo "" -wait_healthy "Postgres" "sprout-postgres" -wait_healthy "Redis" "sprout-redis" -wait_healthy "Typesense" "sprout-typesense" -echo "" +log "Starting services and waiting for health..." +"${REPO_ROOT}/bin/just" _ensure-services # ---- Run migrations --------------------------------------------------------- @@ -204,7 +158,7 @@ if [[ -d "${WEB_DIR}" ]]; then success "Web dependencies installed" else warn "pnpm not found — skipping web dependency install." - warn "Run '. ./bin/activate-hermit' to get pnpm, then 'just web-install'." + warn "Run '. ./bin/activate-hermit' to get pnpm, then 'just desktop-install'." fi else warn "Web directory not found at ${WEB_DIR} — skipping." diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh index ed6921698..31ae61f05 100755 --- a/scripts/run-tests.sh +++ b/scripts/run-tests.sh @@ -13,7 +13,6 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" MODE="${1:-all}" -TIMEOUT=60 # seconds to wait for services if starting them # Colors RED='\033[0;31m' @@ -72,57 +71,8 @@ run_test_step() { # ---- Check / start infra (for integration tests) ---------------------------- -services_healthy() { - local pg_ok redis_ok - pg_ok=$(docker inspect --format='{{.State.Health.Status}}' sprout-postgres 2>/dev/null || echo "not_found") - redis_ok=$(docker inspect --format='{{.State.Health.Status}}' sprout-redis 2>/dev/null || echo "not_found") - [[ "${pg_ok}" == "healthy" && "${redis_ok}" == "healthy" ]] -} - -ensure_services() { - if services_healthy; then - success "Services already healthy" - return 0 - fi - - warn "Services not running — starting them..." - docker compose up -d - - local elapsed=0 - local interval=3 - while ! services_healthy; do - if [[ ${elapsed} -ge ${TIMEOUT} ]]; then - error "Timed out waiting for services (${TIMEOUT}s)" - return 1 - fi - sleep "${interval}" - elapsed=$((elapsed + interval)) - echo -n "." - done - echo "" - success "Services healthy" - - # Ensure migrations are current - ensure_migrations -} - -ensure_migrations() { - log "Ensuring migrations are current..." - local pgschema="${REPO_ROOT}/bin/pgschema" - local schema_file="${REPO_ROOT}/schema/schema.sql" - - if [[ ! -f "${schema_file}" ]]; then - warn "No schema.sql. Skipping." - return 0 - fi - - if [[ -x "${pgschema}" ]]; then - "${pgschema}" apply --file "${schema_file}" --auto-approve 2>/dev/null \ - && success "Migrations current" \ - || warn "pgschema apply failed — DB may be out of date" - else - warn "pgschema not found at ${pgschema}. Schema may be out of date." - fi +ensure_infra() { + "${REPO_ROOT}/bin/just" _ensure-migrations } # ---- Unit tests (no infra needed) ------------------------------------------- @@ -142,7 +92,7 @@ run_unit_tests() { run_integration_tests() { section "Integration Tests (requires running services)" - ensure_services + ensure_infra run_test_step "sprout-db tests" \ cargo test -p sprout-db -- --nocapture From f67cb4f58af4e7be8be5b47af288ef5cb69974fc Mon Sep 17 00:00:00 2001 From: Will Pfleger Date: Fri, 29 May 2026 18:10:35 -0400 Subject: [PATCH 3/3] docs: update references to match justfile infra consolidation Several docs referenced removed recipes (desktop-app), manual docker compose steps that are now auto-handled by just relay, or script internals that now delegate to justfile recipes. --- AGENTS.md | 8 +++++++- NOSTR.md | 11 ++++------- TESTING.md | 4 ++-- crates/sprout-acp/README.md | 3 +-- crates/sprout-cli/TESTING.md | 2 +- crates/sprout-proxy/README.md | 3 +-- mobile/README.md | 6 +++++- 7 files changed, 21 insertions(+), 16 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 515467ebe..17101c3e9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -219,7 +219,7 @@ organized under `desktop/src/features/`. Biome handles linting and formatting. ```bash just desktop-dev # web-only dev server (faster iteration) -just desktop-app # full Tauri app with native shell +just dev # full Tauri app with native shell ``` ### Workspace Switching @@ -291,6 +291,12 @@ flutter test Or from repo root: `just mobile-fmt` (auto-fix), `just mobile-check` (lint + fmt check), `just mobile-test` (tests). +To run the app locally (starts Docker, relay, iOS simulator automatically): + +```bash +just mobile-dev +``` + ### Testing Conventions - Prefer **widget tests** over unit tests for UI components — test the diff --git a/NOSTR.md b/NOSTR.md index 9f87f3903..0b1188a74 100644 --- a/NOSTR.md +++ b/NOSTR.md @@ -23,16 +23,13 @@ Connect any NIP-29 client straight to the relay. ### Quick Start ```bash -# 1. Start infrastructure -docker compose up -d - -# 2. (Optional) Enable pubkey allowlist — must be set BEFORE relay startup +# 1. (Optional) Enable pubkey allowlist — must be set BEFORE relay startup export SPROUT_PUBKEY_ALLOWLIST=true -# 3. Start the relay (runs migrations automatically) -cargo run -p sprout-relay & # relay on :3000 +# 2. Start the relay (auto-starts Docker services and runs migrations) +just relay & # relay on :3000 -# 4. Add a pubkey to the allowlist (if enabled) +# 3. Add a pubkey to the allowlist (if enabled) # Insert directly — there is no CLI command for this yet. PGPASSWORD=sprout_dev psql -h localhost -U sprout -d sprout -c \ "INSERT INTO pubkey_allowlist (pubkey) VALUES (decode('<64-char-hex-pubkey>', 'hex'))" diff --git a/TESTING.md b/TESTING.md index ce480ecf6..df26c27bc 100644 --- a/TESTING.md +++ b/TESTING.md @@ -8,7 +8,7 @@ just test # unit + integration (starts Docker if needed) ``` `just test` runs unit tests plus integration tests against Postgres and Redis -(started via `docker compose`). Neither task runs the E2E suites in +(started automatically if not already running). Neither task runs the E2E suites in `sprout-test-client` — those are marked `#[ignore]` and require a running relay: ```bash @@ -264,7 +264,7 @@ Replies are kind:9 in the same channel; `sprout messages thread --channel ## Configuration reference The relay reads all configuration from environment variables. Defaults work -out of the box with `docker compose up`. Common overrides: +out of the box with `just setup` or `just relay`. Common overrides: | Variable | Default | Notes | |-----------------------------------|-----------------------------|-------| diff --git a/crates/sprout-acp/README.md b/crates/sprout-acp/README.md index b72c2f6ad..fdc0b8210 100644 --- a/crates/sprout-acp/README.md +++ b/crates/sprout-acp/README.md @@ -13,8 +13,7 @@ Supports any agent that speaks [ACP](https://agentclientprotocol.com/) over stdi ## Prerequisites -- A running Sprout relay (`just relay` or a hosted instance) -- Docker services up (`docker compose up -d`) if running locally +- A running Sprout relay (`just relay` starts Docker services automatically, or use a hosted instance) - A Nostr keypair for the agent (see [Generating Keys](#generating-keys)) Build: diff --git a/crates/sprout-cli/TESTING.md b/crates/sprout-cli/TESTING.md index fbc5fce69..2341b2160 100644 --- a/crates/sprout-cli/TESTING.md +++ b/crates/sprout-cli/TESTING.md @@ -17,7 +17,7 @@ docker compose ps # sprout-typesense healthy ``` -If not running: `./scripts/dev-setup.sh` from the repo root. +If not running: `just setup` from the repo root. Tools: `jq`, `curl`, Rust toolchain. diff --git a/crates/sprout-proxy/README.md b/crates/sprout-proxy/README.md index 54426791d..7ef7844f6 100644 --- a/crates/sprout-proxy/README.md +++ b/crates/sprout-proxy/README.md @@ -17,8 +17,7 @@ Client (NIP-28) ←→ sprout-proxy :4869 ←→ sprout-relay :3000 ### 1. Start infrastructure and relay ```bash -just setup # Docker: Postgres + Redis -just relay # Relay on :3000 +just relay # starts Docker services + migrations automatically ``` ### 2. Mint a proxy API token diff --git a/mobile/README.md b/mobile/README.md index a8cc0394e..ff85049ac 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -12,7 +12,11 @@ flutter pub get ## Run ```bash -flutter run +# From repo root (recommended — starts Docker, relay, and simulator): +just mobile-dev + +# Direct (requires services and relay already running): +cd mobile && flutter run ``` ## Checks