From b6591c6d2cce6e3c422b6d5bad1b870bddffc034 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 2 Sep 2026 12:15:26 +0000 Subject: [PATCH 1/2] chore: add Cloud Agent environment config for nodejs-goof Adds .cursor/environment.json plus idempotent install.sh and start.sh that: - install Docker + fuse-overlayfs (overlayfs snapshotter fails in nested VM) - install npm dependencies - run mongo:3 and mysql:5 containers the app depends on - run the app via a 'goof' terminal, exposing port 3001 Co-authored-by: Dan Shappir --- .cursor/environment.json | 17 ++++++++++++++ .cursor/install.sh | 46 +++++++++++++++++++++++++++++++++++++ .cursor/start.sh | 49 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 .cursor/environment.json create mode 100755 .cursor/install.sh create mode 100755 .cursor/start.sh diff --git a/.cursor/environment.json b/.cursor/environment.json new file mode 100644 index 00000000000..7df7f61ebb4 --- /dev/null +++ b/.cursor/environment.json @@ -0,0 +1,17 @@ +{ + "name": "nodejs-goof", + "install": "bash .cursor/install.sh", + "start": "bash .cursor/start.sh", + "terminals": [ + { + "name": "goof", + "command": "npm start" + } + ], + "ports": [ + { + "name": "web", + "port": 3001 + } + ] +} diff --git a/.cursor/install.sh b/.cursor/install.sh new file mode 100755 index 00000000000..d7bbd20bb38 --- /dev/null +++ b/.cursor/install.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# Idempotent dependency setup for the Goof Cloud Agent environment. +# Installs Docker (used to run the mongo:3 + mysql:5 databases the app needs), +# the fuse-overlayfs storage driver (the default overlayfs snapshotter fails in +# the nested Cloud Agent VM), and the Node.js dependencies. Best-effort pre-pull +# of the database images so a fresh boot starts quickly. +set -euo pipefail + +cd "$(dirname "$0")/.." + +export DEBIAN_FRONTEND=noninteractive + +# --- System packages: Docker + fuse-overlayfs --- +if ! command -v docker >/dev/null 2>&1 || ! command -v fuse-overlayfs >/dev/null 2>&1; then + sudo apt-get update + sudo apt-get install -y docker.io fuse-overlayfs +fi + +# The containerd/overlayfs snapshotter cannot extract images inside the nested +# Cloud Agent VM, so pin the classic graph driver backed by fuse-overlayfs. +sudo mkdir -p /etc/docker +echo '{"features":{"containerd-snapshotter":false},"storage-driver":"fuse-overlayfs"}' \ + | sudo tee /etc/docker/daemon.json >/dev/null + +# --- Node dependencies --- +npm install + +# --- Best-effort pre-pull of database images (cached on disk for fast boots) --- +# Non-fatal: if the daemon cannot run during the build phase, start.sh pulls on boot. +STARTED_DOCKERD=0 +if ! sudo docker info >/dev/null 2>&1; then + sudo rm -f /var/run/docker.pid + sudo setsid dockerd >/tmp/dockerd-install.log 2>&1 & + for _ in $(seq 1 30); do sudo docker info >/dev/null 2>&1 && break; sleep 1; done + STARTED_DOCKERD=1 +fi +if sudo docker info >/dev/null 2>&1; then + sudo docker pull mongo:3 || true + sudo docker pull mysql:5 || true +fi +# Stop the daemon only if this script started it (leave a pre-existing one alone). +if [ "$STARTED_DOCKERD" = "1" ] && [ -f /var/run/docker.pid ]; then + sudo kill "$(cat /var/run/docker.pid)" 2>/dev/null || true +fi + +echo "install.sh complete" diff --git a/.cursor/start.sh b/.cursor/start.sh new file mode 100755 index 00000000000..9ecb2673ef0 --- /dev/null +++ b/.cursor/start.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# Per-boot startup for the Goof Cloud Agent environment. +# Starts the Docker daemon (fuse-overlayfs) and the mongo:3 + mysql:5 database +# containers the app depends on, then waits until they accept connections. +# Idempotent: safe to run repeatedly; it will not create duplicate containers. +set -euo pipefail + +wait_for_port() { + local host="$1" port="$2" name="$3" tries="${4:-60}" + for _ in $(seq 1 "$tries"); do + if (exec 3<>"/dev/tcp/${host}/${port}") 2>/dev/null; then + exec 3>&- 3<&- 2>/dev/null || true + echo "${name} is ready on ${host}:${port}" + return 0 + fi + sleep 1 + done + echo "WARNING: ${name} did not become ready on ${host}:${port}" >&2 + return 1 +} + +# --- Ensure the Docker daemon is running --- +if ! sudo docker info >/dev/null 2>&1; then + sudo rm -f /var/run/docker.pid + sudo setsid dockerd >/tmp/dockerd.log 2>&1 & + for _ in $(seq 1 30); do sudo docker info >/dev/null 2>&1 && break; sleep 1; done +fi + +# --- MongoDB (mongo:3) --- +if ! sudo docker ps --format '{{.Names}}' | grep -qx 'goof-mongo'; then + sudo docker rm -f goof-mongo >/dev/null 2>&1 || true + sudo docker image inspect mongo:3 >/dev/null 2>&1 || sudo docker pull mongo:3 + sudo docker run -d --name goof-mongo -p 27017:27017 mongo:3 >/dev/null +fi + +# --- MySQL (mysql:5, for the TypeORM users table) --- +if ! sudo docker ps --format '{{.Names}}' | grep -qx 'goof-mysql'; then + sudo docker rm -f goof-mysql >/dev/null 2>&1 || true + sudo docker image inspect mysql:5 >/dev/null 2>&1 || sudo docker pull mysql:5 + sudo docker run -d --name goof-mysql \ + -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=acme \ + -p 3306:3306 mysql:5 >/dev/null +fi + +# --- Wait for the databases so the app connects cleanly on first launch --- +wait_for_port 127.0.0.1 27017 "MongoDB" 60 || true +wait_for_port 127.0.0.1 3306 "MySQL" 120 || true + +echo "start.sh complete" From fe1a77a73b9f0795d2852128e9f35eca360f869d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 2 Sep 2026 12:38:13 +0000 Subject: [PATCH 2/2] fix: gate app startup on real MySQL query readiness mysql:5 opens its TCP port while still initializing its data directory on first boot, so the previous bare port check returned prematurely. The app then connected too early, failed to seed the users table, and crashed on the first /users or /login request. Wait on 'mysqladmin ping' until the server can actually answer queries before returning from start.sh. Co-authored-by: Dan Shappir --- .cursor/start.sh | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/.cursor/start.sh b/.cursor/start.sh index 9ecb2673ef0..1e80907a23b 100755 --- a/.cursor/start.sh +++ b/.cursor/start.sh @@ -19,6 +19,23 @@ wait_for_port() { return 1 } +# MySQL opens its TCP port while still initializing its data directory on first +# boot, so a bare port check is not enough. Wait until the server can actually +# answer queries before returning, otherwise the app connects too early, fails +# to seed the users table, and crashes on the first /users or /login request. +wait_for_mysql() { + local tries="${1:-120}" + for _ in $(seq 1 "$tries"); do + if sudo docker exec goof-mysql mysqladmin ping -uroot -proot --silent >/dev/null 2>&1; then + echo "MySQL is ready to serve queries" + return 0 + fi + sleep 1 + done + echo "WARNING: MySQL did not become query-ready in time" >&2 + return 1 +} + # --- Ensure the Docker daemon is running --- if ! sudo docker info >/dev/null 2>&1; then sudo rm -f /var/run/docker.pid @@ -44,6 +61,7 @@ fi # --- Wait for the databases so the app connects cleanly on first launch --- wait_for_port 127.0.0.1 27017 "MongoDB" 60 || true -wait_for_port 127.0.0.1 3306 "MySQL" 120 || true +wait_for_port 127.0.0.1 3306 "MySQL (port)" 120 || true +wait_for_mysql 180 || true echo "start.sh complete"