chore: add local dev workflow
This commit is contained in:
1 parent
ecf1e51915
commit
f917b71960
3 files changed
+296
No files matched your search
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"name": "Vibe-Trading",
|
||||||
|
"image": "mcr.microsoft.com/devcontainers/python:1-3.11-bookworm",
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/node:1": {
|
||||||
|
"version": "20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"forwardPorts": [
|
||||||
|
8899,
|
||||||
|
5899
|
||||||
|
],
|
||||||
|
"portsAttributes": {
|
||||||
|
"8899": {
|
||||||
|
"label": "Vibe-Trading API",
|
||||||
|
"onAutoForward": "notify",
|
||||||
|
"visibility": "private"
|
||||||
|
},
|
||||||
|
"5899": {
|
||||||
|
"label": "Vibe-Trading Frontend",
|
||||||
|
"onAutoForward": "notify",
|
||||||
|
"visibility": "private"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"postCreateCommand": "python -m pip install --upgrade pip && python -m pip install -e . && cd frontend && npm install",
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"ms-python.python",
|
||||||
|
"ms-python.vscode-pylance",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"esbenp.prettier-vscode"
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"python.defaultInterpreterPath": "/usr/local/bin/python"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,10 @@ agent/tests/*_result.json
|
|||||||
.ruff_cache/
|
.ruff_cache/
|
||||||
frontend/dist/
|
frontend/dist/
|
||||||
frontend/tsconfig.tsbuildinfo
|
frontend/tsconfig.tsbuildinfo
|
||||||
|
.vibe-dev/
|
||||||
|
.vibe-record/
|
||||||
|
.cache/
|
||||||
|
.remotion/
|
||||||
|
|
||||||
# DuckDB data cache
|
# DuckDB data cache
|
||||||
data/*.duckdb
|
data/*.duckdb
|
||||||
@@ -45,6 +49,9 @@ build/
|
|||||||
# Local demo videos (too large for git; link to external host instead)
|
# Local demo videos (too large for git; link to external host instead)
|
||||||
assets/*.mp4
|
assets/*.mp4
|
||||||
|
|
||||||
|
# Local demo / promo production workspace
|
||||||
|
demo/
|
||||||
|
|
||||||
# Manual E2E smoke tests — require live API keys (OpenRouter / yfinance),
|
# Manual E2E smoke tests — require live API keys (OpenRouter / yfinance),
|
||||||
# would break CI if committed. Kept local; run explicitly when validating
|
# would break CI if committed. Kept local; run explicitly when validating
|
||||||
# a release.
|
# a release.
|
||||||
|
|||||||
+250
@@ -0,0 +1,250 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
STATE_DIR="${VIBE_DEV_STATE_DIR:-$ROOT/.vibe-dev}"
|
||||||
|
LOG_DIR="$STATE_DIR/logs"
|
||||||
|
PID_DIR="$STATE_DIR/pids"
|
||||||
|
|
||||||
|
BACKEND_HOST="${VIBE_BACKEND_HOST:-127.0.0.1}"
|
||||||
|
BACKEND_PORT="${VIBE_BACKEND_PORT:-8899}"
|
||||||
|
FRONTEND_HOST="${VIBE_FRONTEND_HOST:-127.0.0.1}"
|
||||||
|
FRONTEND_PORT="${VIBE_FRONTEND_PORT:-5899}"
|
||||||
|
if [[ -n "${PYTHON:-}" ]]; then
|
||||||
|
PYTHON_BIN="$PYTHON"
|
||||||
|
elif [[ -x "$ROOT/.venv/bin/python" ]]; then
|
||||||
|
PYTHON_BIN="$ROOT/.venv/bin/python"
|
||||||
|
elif [[ -x "$ROOT/agent/.venv/bin/python" ]]; then
|
||||||
|
PYTHON_BIN="$ROOT/agent/.venv/bin/python"
|
||||||
|
else
|
||||||
|
PYTHON_BIN="python3"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$LOG_DIR" "$PID_DIR"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<USAGE
|
||||||
|
Usage: scripts/dev <command>
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
up Start backend and frontend dev servers
|
||||||
|
stop Stop dev servers started by this script
|
||||||
|
restart [service] Restart backend, frontend, or all services
|
||||||
|
status Show process status and URLs
|
||||||
|
logs [service] Tail logs for backend, frontend, or all
|
||||||
|
open Open the frontend in the default browser
|
||||||
|
urls Print local dev URLs
|
||||||
|
|
||||||
|
Environment:
|
||||||
|
VIBE_BACKEND_PORT Backend port (default: 8899)
|
||||||
|
VIBE_FRONTEND_PORT Frontend port (default: 5899)
|
||||||
|
PYTHON Python binary (default: local .venv, then python3)
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_file() {
|
||||||
|
printf "%s/%s.pid" "$PID_DIR" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_file() {
|
||||||
|
printf "%s/%s.log" "$LOG_DIR" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
is_running() {
|
||||||
|
local service="$1"
|
||||||
|
local file
|
||||||
|
file="$(pid_file "$service")"
|
||||||
|
[[ -f "$file" ]] && kill -0 "$(cat "$file")" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
start_service() {
|
||||||
|
local service="$1"
|
||||||
|
shift
|
||||||
|
if is_running "$service"; then
|
||||||
|
printf "%s already running (pid %s)\n" "$service" "$(cat "$(pid_file "$service")")"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "starting %s...\n" "$service"
|
||||||
|
nohup "$@" >"$(log_file "$service")" 2>&1 </dev/null &
|
||||||
|
echo "$!" >"$(pid_file "$service")"
|
||||||
|
printf "%s pid %s, log %s\n" "$service" "$(cat "$(pid_file "$service")")" "$(log_file "$service")"
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_service() {
|
||||||
|
local service="$1"
|
||||||
|
local file
|
||||||
|
file="$(pid_file "$service")"
|
||||||
|
if ! [[ -f "$file" ]]; then
|
||||||
|
printf "%s not started by scripts/dev\n" "$service"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local pid
|
||||||
|
pid="$(cat "$file")"
|
||||||
|
if kill -0 "$pid" 2>/dev/null; then
|
||||||
|
printf "stopping %s (pid %s)...\n" "$service" "$pid"
|
||||||
|
pkill -TERM -P "$pid" 2>/dev/null || true
|
||||||
|
kill "$pid" 2>/dev/null || true
|
||||||
|
sleep 0.5
|
||||||
|
pkill -KILL -P "$pid" 2>/dev/null || true
|
||||||
|
kill -KILL "$pid" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
rm -f "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
url_ok() {
|
||||||
|
local url="$1"
|
||||||
|
if command -v curl >/dev/null 2>&1; then
|
||||||
|
curl -fsS --max-time 2 "$url" >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
"$PYTHON_BIN" - "$url" >/dev/null 2>&1 <<'PY'
|
||||||
|
import sys
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
urllib.request.urlopen(sys.argv[1], timeout=2).read(1)
|
||||||
|
PY
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_url() {
|
||||||
|
local service="$1"
|
||||||
|
local url="$2"
|
||||||
|
local attempts="${3:-30}"
|
||||||
|
|
||||||
|
printf "waiting for %s at %s" "$service" "$url"
|
||||||
|
for ((i = 1; i <= attempts; i++)); do
|
||||||
|
if url_ok "$url"; then
|
||||||
|
printf " ready\n"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if ! is_running "$service"; then
|
||||||
|
printf "\n%s exited early; see %s\n" "$service" "$(log_file "$service")" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
printf "."
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
printf "\n%s not ready after %ss; see %s\n" "$service" "$attempts" "$(log_file "$service")" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_up() {
|
||||||
|
start_service backend env PYTHONPATH="$ROOT/agent" "$PYTHON_BIN" "$ROOT/agent/cli.py" serve \
|
||||||
|
--host "$BACKEND_HOST" \
|
||||||
|
--port "$BACKEND_PORT"
|
||||||
|
start_service frontend bash -lc '
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$1"
|
||||||
|
if ! [[ -d node_modules ]]; then
|
||||||
|
npm install
|
||||||
|
fi
|
||||||
|
exec npm run dev -- --host "$2" --port "$3"
|
||||||
|
' bash "$ROOT/frontend" "$FRONTEND_HOST" "$FRONTEND_PORT"
|
||||||
|
if ! wait_for_url backend "http://127.0.0.1:$BACKEND_PORT/health" 30 || \
|
||||||
|
! wait_for_url frontend "http://127.0.0.1:$FRONTEND_PORT" 30; then
|
||||||
|
cmd_stop
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cmd_urls
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_stop() {
|
||||||
|
stop_service frontend
|
||||||
|
stop_service backend
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_restart() {
|
||||||
|
local service="${1:-all}"
|
||||||
|
case "$service" in
|
||||||
|
backend)
|
||||||
|
stop_service backend
|
||||||
|
start_service backend env PYTHONPATH="$ROOT/agent" "$PYTHON_BIN" "$ROOT/agent/cli.py" serve \
|
||||||
|
--host "$BACKEND_HOST" \
|
||||||
|
--port "$BACKEND_PORT"
|
||||||
|
wait_for_url backend "http://127.0.0.1:$BACKEND_PORT/health" 30
|
||||||
|
;;
|
||||||
|
frontend)
|
||||||
|
stop_service frontend
|
||||||
|
start_service frontend bash -lc '
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$1"
|
||||||
|
if ! [[ -d node_modules ]]; then
|
||||||
|
npm install
|
||||||
|
fi
|
||||||
|
exec npm run dev -- --host "$2" --port "$3"
|
||||||
|
' bash "$ROOT/frontend" "$FRONTEND_HOST" "$FRONTEND_PORT"
|
||||||
|
wait_for_url frontend "http://127.0.0.1:$FRONTEND_PORT" 30
|
||||||
|
;;
|
||||||
|
all)
|
||||||
|
cmd_stop
|
||||||
|
cmd_up
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "unknown service: %s\n" "$service" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_status() {
|
||||||
|
for service in backend frontend; do
|
||||||
|
if is_running "$service"; then
|
||||||
|
printf "%-8s running pid=%s log=%s\n" "$service" "$(cat "$(pid_file "$service")")" "$(log_file "$service")"
|
||||||
|
else
|
||||||
|
printf "%-8s stopped\n" "$service"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
cmd_urls
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_logs() {
|
||||||
|
local service="${1:-all}"
|
||||||
|
case "$service" in
|
||||||
|
backend|frontend)
|
||||||
|
touch "$(log_file "$service")"
|
||||||
|
tail -f "$(log_file "$service")"
|
||||||
|
;;
|
||||||
|
all)
|
||||||
|
touch "$(log_file backend)" "$(log_file frontend)"
|
||||||
|
tail -f "$(log_file backend)" "$(log_file frontend)"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "unknown service: %s\n" "$service" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_open() {
|
||||||
|
local url="http://127.0.0.1:$FRONTEND_PORT"
|
||||||
|
if command -v open >/dev/null 2>&1; then
|
||||||
|
open "$url"
|
||||||
|
else
|
||||||
|
printf "%s\n" "$url"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_urls() {
|
||||||
|
cat <<URLS
|
||||||
|
Frontend: http://127.0.0.1:$FRONTEND_PORT
|
||||||
|
Backend: http://127.0.0.1:$BACKEND_PORT
|
||||||
|
API docs: http://127.0.0.1:$BACKEND_PORT/docs
|
||||||
|
URLS
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
up) cmd_up ;;
|
||||||
|
stop) cmd_stop ;;
|
||||||
|
restart) shift; cmd_restart "${1:-all}" ;;
|
||||||
|
status) cmd_status ;;
|
||||||
|
logs) shift; cmd_logs "${1:-all}" ;;
|
||||||
|
open) cmd_open ;;
|
||||||
|
urls) cmd_urls ;;
|
||||||
|
-h|--help|help|"") usage ;;
|
||||||
|
*)
|
||||||
|
printf "unknown command: %s\n\n" "$1" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in new issue
Block a user