Update Vibe Kanban setup and scripts

- Added new entries to .gitignore for environment files and dynamically generated Docker Compose files.
- Updated documentation to reflect the new path for the Vibe Kanban dev server script.
- Enhanced task composition scripts to extract TASK_SLOT from TASK_ID, ensuring unique Orleans ports and preventing conflicts.
- Removed the old vibe-dev-server script, consolidating functionality into the new structure.
This commit is contained in:
2025-12-31 04:36:20 +07:00
parent 2e0baa45c0
commit ab08e0241b
13 changed files with 1535 additions and 35 deletions

View File

@@ -0,0 +1,126 @@
# Vibe Kanban Scripts
This directory contains all scripts specifically for Vibe Kanban integration.
## Scripts
### `vibe-setup.sh`
**Purpose:** Sets up the database and Docker services for a Vibe Kanban task environment.
**Usage:**
```bash
bash scripts/vibe-kanban/vibe-setup.sh [TASK_ID] [PORT_OFFSET]
```
**What it does:**
- Detects or generates a consistent TASK_ID for the worktree
- Auto-detects available port offset
- Creates Docker Compose file for the task
- Starts PostgreSQL and Redis containers
- Copies database from main repository
- Saves configuration to `.vibe-setup.env`
**Configuration saved:**
- Task ID
- Port offsets
- Database names
- All connection details
**Note:** This script runs in the "setup" section of Vibe Kanban.
---
### `vibe-dev-server.sh`
**Purpose:** Starts the API and Workers processes (assumes database is already set up).
**Usage:**
```bash
bash scripts/vibe-kanban/vibe-dev-server.sh
```
**What it does:**
- Loads configuration from `.vibe-setup.env` (created by vibe-setup.sh)
- Verifies database is ready
- Starts API and Workers using `start-api-and-workers.sh`
- Displays logs with filtered warnings
- Shows API and Workers logs in real-time
**Requirements:**
- Must run `vibe-setup.sh` first to create the database environment
- Configuration file `.vibe-setup.env` must exist
**Note:** This script runs in the "dev server" section of Vibe Kanban.
---
### `cleanup-api-workers.sh`
**Purpose:** Stops API and Workers processes for a specific task.
**Usage:**
```bash
bash scripts/vibe-kanban/cleanup-api-workers.sh <TASK_ID>
```
**What it does:**
- Stops API process (and child processes)
- Stops Workers process (and child processes)
- Kills orphaned processes
- Removes PID files
- Preserves log files for debugging
**Features:**
- Graceful shutdown (SIGTERM) with fallback to force kill (SIGKILL)
- Handles orphaned processes
- Works with Vibe Kanban worktrees
- Supports environment variables for TASK_ID
**Note:** This script is used by Vibe Kanban for cleanup operations.
---
## Workflow
1. **Setup Phase** (Vibe Kanban "setup" section):
```bash
bash scripts/vibe-kanban/vibe-setup.sh
```
- Sets up database and Docker services
- Creates configuration file
2. **Dev Server Phase** (Vibe Kanban "dev server" section):
```bash
bash scripts/vibe-kanban/vibe-dev-server.sh
```
- Starts API and Workers
- Shows logs
3. **Cleanup Phase** (Vibe Kanban cleanup):
```bash
bash scripts/vibe-kanban/cleanup-api-workers.sh <TASK_ID>
```
- Stops all processes
- Cleans up
## Configuration Files
These scripts create/use the following files in the worktree:
- `.vibe-task-id` - Stores the persistent TASK_ID for the worktree
- `.vibe-setup.env` - Stores all setup configuration (ports, database names, etc.)
- `.task-pids/` - Directory containing PID files and logs
## Paths
All paths in these scripts are relative to the main repository:
- Main repo: `/Users/oda/Desktop/Projects/managing-apps`
- Scripts: `scripts/vibe-kanban/`
- Worktree: Detected automatically from current directory
## Environment Variables
These scripts support the following environment variables:
- `VIBE_TASK_ID` - Task ID from Vibe Kanban
- `VIBE_TASK_NAME` - Task name from Vibe Kanban
- `VIBE_WORKTREE_ROOT` - Worktree root path (set automatically)

View File

@@ -0,0 +1,361 @@
#!/bin/bash
# scripts/vibe-kanban/cleanup-api-workers.sh
# Cleanup script for Vibe Kanban - stops API and Workers processes only
# Usage: bash scripts/vibe-kanban/cleanup-api-workers.sh <TASK_ID>
TASK_ID=$1
# Detect worktree root (similar to vibe-setup.sh)
WORKTREE_ROOT="$(pwd)"
# Check if we're in a nested structure (Vibe Kanban worktree)
if [ -d "$WORKTREE_ROOT/managing-apps" ] && [ -d "$WORKTREE_ROOT/managing-apps/src/Managing.Api" ]; then
WORKTREE_PROJECT_ROOT="$WORKTREE_ROOT/managing-apps"
elif [ -d "$WORKTREE_ROOT/src/Managing.Api" ]; then
WORKTREE_PROJECT_ROOT="$WORKTREE_ROOT"
else
WORKTREE_PROJECT_ROOT=""
fi
# Determine project root
if [ -n "$VIBE_WORKTREE_ROOT" ] && [ -d "$VIBE_WORKTREE_ROOT/src/Managing.Api" ]; then
PROJECT_ROOT="$VIBE_WORKTREE_ROOT"
WORKTREE_PROJECT_ROOT="$VIBE_WORKTREE_ROOT"
echo "📁 Using Vibe Kanban worktree: $PROJECT_ROOT"
elif [ -n "$WORKTREE_PROJECT_ROOT" ]; then
PROJECT_ROOT="$WORKTREE_PROJECT_ROOT"
echo "📁 Using Vibe Kanban worktree: $PROJECT_ROOT"
elif [ -d "$(pwd)/scripts" ] && [ -f "$(pwd)/scripts/start-api-and-workers.sh" ]; then
PROJECT_ROOT="$(pwd)"
echo "📁 Using current directory: $PROJECT_ROOT"
else
# Try to find main repo
MAIN_REPO="/Users/oda/Desktop/Projects/managing-apps"
if [ -d "$MAIN_REPO/scripts" ]; then
PROJECT_ROOT="$MAIN_REPO"
echo "📁 Using main repository: $PROJECT_ROOT"
else
echo "❌ Error: Cannot find project root"
exit 1
fi
fi
# TASK_ID file to ensure consistency (same as vibe-setup.sh)
TASK_ID_FILE="$WORKTREE_PROJECT_ROOT/.vibe-task-id"
# Try to get TASK_ID from various sources
if [ -z "$TASK_ID" ]; then
# First, check if we have a stored TASK_ID for this worktree (ensures consistency)
if [ -n "$WORKTREE_PROJECT_ROOT" ] && [ -f "$TASK_ID_FILE" ]; then
STORED_TASK_ID=$(cat "$TASK_ID_FILE" 2>/dev/null | tr -d '[:space:]')
if [ -n "$STORED_TASK_ID" ]; then
TASK_ID="$STORED_TASK_ID"
echo "📋 Using stored TASK_ID from .vibe-task-id: $TASK_ID"
fi
fi
# Try environment variables (Vibe Kanban might set these)
if [ -z "$TASK_ID" ]; then
if [ -n "$VIBE_TASK_ID" ]; then
TASK_ID="$VIBE_TASK_ID"
echo "📋 Found TASK_ID from VIBE_TASK_ID: $TASK_ID"
elif [ -n "$TASK_ID_ENV" ]; then
TASK_ID="$TASK_ID_ENV"
echo "📋 Found TASK_ID from TASK_ID_ENV: $TASK_ID"
elif [ -n "$TASK" ]; then
TASK_ID="$TASK"
echo "📋 Found TASK_ID from TASK: $TASK_ID"
fi
fi
fi
# If TASK_ID still not found, try to detect from worktree path or PID files
if [ -z "$TASK_ID" ]; then
# Try to extract from worktree path (Vibe Kanban worktrees often contain task ID)
WORKTREE_PATH_TO_CHECK="$WORKTREE_ROOT"
if [ -z "$WORKTREE_PATH_TO_CHECK" ] && [ -n "$VIBE_WORKTREE_ROOT" ]; then
WORKTREE_PATH_TO_CHECK="$VIBE_WORKTREE_ROOT"
fi
if [ -n "$WORKTREE_PATH_TO_CHECK" ]; then
# Try UUID format first (Vibe Kanban might use UUIDs)
DETECTED_TASK=$(echo "$WORKTREE_PATH_TO_CHECK" | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | head -1)
# If no UUID, try task ID pattern (e.g., DEV-123, TASK-456)
if [ -z "$DETECTED_TASK" ]; then
DETECTED_TASK=$(echo "$WORKTREE_PATH_TO_CHECK" | grep -oE '[A-Z]+-[0-9]+' | head -1)
fi
# If still no match, try to get the last directory name (might be task name)
if [ -z "$DETECTED_TASK" ]; then
LAST_DIR=$(basename "$WORKTREE_PATH_TO_CHECK")
# Skip common directory names
if [ "$LAST_DIR" != "managing-apps" ] && [ "$LAST_DIR" != "worktrees" ] && [ "$LAST_DIR" != "Projects" ]; then
# Generate a numeric ID from the directory name (hash-based for consistency)
HASH=$(echo -n "$LAST_DIR" | shasum -a 256 | cut -d' ' -f1 | head -c 8)
NUMERIC_ID=$((0x$HASH % 9999 + 1))
DETECTED_TASK="TASK-$NUMERIC_ID"
echo "📋 Generated numeric TASK_ID from worktree directory '$LAST_DIR': $DETECTED_TASK"
fi
fi
if [ -n "$DETECTED_TASK" ]; then
TASK_ID="$DETECTED_TASK"
echo "📋 Detected TASK_ID from worktree path: $TASK_ID"
fi
fi
# Try to find from PID files in worktree
if [ -z "$TASK_ID" ] && [ -n "$WORKTREE_PROJECT_ROOT" ]; then
PID_DIR_CHECK="$WORKTREE_PROJECT_ROOT/.task-pids"
if [ -d "$PID_DIR_CHECK" ]; then
# Find the most recent PID file with a running process
for pid_file in $(ls -t "$PID_DIR_CHECK"/*.pid 2>/dev/null); do
pid=$(cat "$pid_file" 2>/dev/null | tr -d '[:space:]')
if [ -n "$pid" ] && ps -p "$pid" > /dev/null 2>&1; then
# Extract task ID from filename (e.g., api-DEV-123.pid -> DEV-123)
DETECTED_TASK=$(basename "$pid_file" .pid | sed 's/^api-//; s/^workers-//')
if [ -n "$DETECTED_TASK" ]; then
TASK_ID="$DETECTED_TASK"
echo "📋 Detected TASK_ID from running process PID file: $TASK_ID"
break
fi
fi
done
fi
fi
# Try to find from PID files in main repo if still not found
if [ -z "$TASK_ID" ]; then
PID_DIR_CHECK="$PROJECT_ROOT/.task-pids"
if [ -d "$PID_DIR_CHECK" ]; then
# Find the most recent PID file with a running process
for pid_file in $(ls -t "$PID_DIR_CHECK"/*.pid 2>/dev/null); do
pid=$(cat "$pid_file" 2>/dev/null | tr -d '[:space:]')
if [ -n "$pid" ] && ps -p "$pid" > /dev/null 2>&1; then
# Extract task ID from filename (e.g., api-DEV-123.pid -> DEV-123)
DETECTED_TASK=$(basename "$pid_file" .pid | sed 's/^api-//; s/^workers-//')
if [ -n "$DETECTED_TASK" ]; then
TASK_ID="$DETECTED_TASK"
echo "📋 Detected TASK_ID from running process PID file: $TASK_ID"
break
fi
fi
done
fi
fi
# Try to find from current directory if it's a worktree
if [ -z "$TASK_ID" ]; then
CURRENT_DIR="$(pwd)"
# Try UUID format first
DETECTED_TASK=$(echo "$CURRENT_DIR" | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | head -1)
# If no UUID, try task ID pattern
if [ -z "$DETECTED_TASK" ]; then
DETECTED_TASK=$(echo "$CURRENT_DIR" | grep -oE '[A-Z]+-[0-9]+' | head -1)
fi
if [ -n "$DETECTED_TASK" ]; then
TASK_ID="$DETECTED_TASK"
echo "📋 Detected TASK_ID from current directory: $TASK_ID"
fi
fi
fi
PID_DIR="$PROJECT_ROOT/.task-pids"
API_PID_FILE="$PID_DIR/api-${TASK_ID}.pid"
WORKERS_PID_FILE="$PID_DIR/workers-${TASK_ID}.pid"
if [ -z "$TASK_ID" ]; then
echo ""
echo "❌ Error: TASK_ID is required but could not be determined"
echo ""
echo "💡 Usage: $0 <TASK_ID>"
echo "💡 Or set one of these environment variables:"
echo " - VIBE_TASK_ID"
echo " - TASK_ID_ENV"
echo " - TASK"
echo ""
echo "💡 Or ensure you're running from a Vibe Kanban worktree with task ID in the path"
echo ""
echo "🔍 Debug information:"
echo " Current directory: $(pwd)"
echo " WORKTREE_ROOT: ${WORKTREE_ROOT:-not set}"
echo " WORKTREE_PROJECT_ROOT: ${WORKTREE_PROJECT_ROOT:-not set}"
echo " VIBE_WORKTREE_ROOT: ${VIBE_WORKTREE_ROOT:-not set}"
echo " PROJECT_ROOT: $PROJECT_ROOT"
if [ -n "$WORKTREE_PROJECT_ROOT" ]; then
echo " TASK_ID_FILE: $TASK_ID_FILE"
if [ -f "$TASK_ID_FILE" ]; then
echo " Stored TASK_ID: $(cat "$TASK_ID_FILE" 2>/dev/null | tr -d '[:space:]')"
else
echo " TASK_ID_FILE: (not found)"
fi
fi
if [ -d "$PID_DIR" ]; then
echo " Available PID files in $PID_DIR:"
ls -1 "$PID_DIR"/*.pid 2>/dev/null | head -5 | while read file; do
pid=$(cat "$file" 2>/dev/null | tr -d '[:space:]')
task=$(basename "$file" .pid | sed 's/^api-//; s/^workers-//')
if [ -n "$pid" ] && ps -p "$pid" > /dev/null 2>&1; then
echo "$file (PID: $pid, Task: $task) - RUNNING"
else
echo " ⚠️ $file (PID: $pid, Task: $task) - not running"
fi
done || echo " (none found)"
fi
echo ""
echo "💡 To clean up a specific task, run:"
echo " $0 <TASK_ID>"
echo ""
echo "💡 Or set VIBE_TASK_ID environment variable before running the script"
exit 1
fi
echo "🧹 Cleaning up API and Workers for task: $TASK_ID"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Function to kill process and its children
kill_process_tree() {
local pid=$1
local name=$2
if [ -z "$pid" ] || [ "$pid" = "0" ]; then
return 0
fi
if ! ps -p "$pid" > /dev/null 2>&1; then
return 0
fi
echo " 🛑 Stopping $name (PID: $pid)..."
# First, try graceful shutdown
kill "$pid" 2>/dev/null || true
sleep 2
# Check if still running
if ps -p "$pid" > /dev/null 2>&1; then
echo " ⚠️ Process still running, force killing..."
kill -9 "$pid" 2>/dev/null || true
sleep 1
fi
# Kill any child processes
local child_pids=$(pgrep -P "$pid" 2>/dev/null)
if [ -n "$child_pids" ]; then
for child_pid in $child_pids; do
echo " 🛑 Stopping child process (PID: $child_pid)..."
kill "$child_pid" 2>/dev/null || true
sleep 1
if ps -p "$child_pid" > /dev/null 2>&1; then
kill -9 "$child_pid" 2>/dev/null || true
fi
done
fi
# Verify process is stopped
if ps -p "$pid" > /dev/null 2>&1; then
echo " ⚠️ Warning: Process $pid may still be running"
return 1
else
echo "$name stopped"
return 0
fi
}
# Function to find and kill orphaned processes by name
kill_orphaned_processes() {
local task_id=$1
local process_name=$2
local found_any=false
# Find processes that match the executable name and worktree path
local processes=$(ps aux | grep "$process_name" | grep -v grep | grep -E "worktree|$task_id" || true)
if [ -n "$processes" ]; then
echo " 🔍 Found orphaned $process_name processes:"
echo "$processes" | while read line; do
local pid=$(echo "$line" | awk '{print $2}')
if [ -n "$pid" ] && ps -p "$pid" > /dev/null 2>&1; then
echo " 🛑 Killing orphaned process (PID: $pid)..."
kill "$pid" 2>/dev/null || true
sleep 1
if ps -p "$pid" > /dev/null 2>&1; then
kill -9 "$pid" 2>/dev/null || true
fi
found_any=true
fi
done
fi
}
# Stop API process
echo "📊 Stopping API process..."
if [ -f "$API_PID_FILE" ]; then
API_PID=$(cat "$API_PID_FILE" 2>/dev/null | tr -d '[:space:]')
if [ -n "$API_PID" ] && [ "$API_PID" != "0" ]; then
kill_process_tree "$API_PID" "API"
else
echo " ⚠️ Invalid PID in file: $API_PID_FILE"
fi
rm -f "$API_PID_FILE"
else
echo " ⚠️ API PID file not found: $API_PID_FILE"
fi
# Kill orphaned Managing.Api processes
kill_orphaned_processes "$TASK_ID" "Managing.Api"
# Stop Workers process
echo ""
echo "📊 Stopping Workers process..."
if [ -f "$WORKERS_PID_FILE" ]; then
WORKERS_PID=$(cat "$WORKERS_PID_FILE" 2>/dev/null | tr -d '[:space:]')
if [ -n "$WORKERS_PID" ] && [ "$WORKERS_PID" != "0" ]; then
kill_process_tree "$WORKERS_PID" "Workers"
else
echo " ⚠️ Invalid PID in file: $WORKERS_PID_FILE"
fi
rm -f "$WORKERS_PID_FILE"
else
echo " ⚠️ Workers PID file not found: $WORKERS_PID_FILE"
fi
# Kill orphaned Managing.Workers processes
kill_orphaned_processes "$TASK_ID" "Managing.Workers"
# Kill orphaned dotnet run processes that might be related
echo ""
echo "📊 Checking for orphaned dotnet run processes..."
DOTNET_RUN_PIDS=$(ps aux | grep "dotnet run" | grep -v grep | awk '{print $2}' || true)
if [ -n "$DOTNET_RUN_PIDS" ]; then
for pid in $DOTNET_RUN_PIDS; do
# Check if this dotnet run is a parent of Managing.Api or Managing.Workers
local has_api_child=$(pgrep -P "$pid" | xargs ps -p 2>/dev/null | grep -c "Managing.Api" || echo "0")
local has_workers_child=$(pgrep -P "$pid" | xargs ps -p 2>/dev/null | grep -c "Managing.Workers" || echo "0")
if [ "$has_api_child" != "0" ] || [ "$has_workers_child" != "0" ]; then
echo " 🛑 Killing orphaned dotnet run process (PID: $pid)..."
kill "$pid" 2>/dev/null || true
sleep 1
if ps -p "$pid" > /dev/null 2>&1; then
kill -9 "$pid" 2>/dev/null || true
fi
fi
done
fi
# Clean up log files (optional - comment out if you want to keep logs)
# echo ""
# echo "📊 Cleaning up log files..."
# rm -f "$PID_DIR/api-${TASK_ID}.log" "$PID_DIR/workers-${TASK_ID}.log" 2>/dev/null || true
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ Cleanup complete for task: $TASK_ID"
echo ""
echo "💡 Note: Log files are preserved in: $PID_DIR"
echo "💡 To remove log files, uncomment the cleanup section in the script"

View File

@@ -0,0 +1,208 @@
#!/bin/bash
# scripts/vibe-kanban/vibe-dev-server.sh
# Simplified script for Vibe Kanban - starts API and Workers only
# Assumes database setup is already done by vibe-setup.sh
# Detect worktree root
WORKTREE_ROOT="$(pwd)"
# Check if we're in a nested structure (Vibe Kanban worktree)
if [ -d "$WORKTREE_ROOT/managing-apps" ] && [ -d "$WORKTREE_ROOT/managing-apps/src/Managing.Api" ]; then
WORKTREE_PROJECT_ROOT="$WORKTREE_ROOT/managing-apps"
elif [ -d "$WORKTREE_ROOT/src/Managing.Api" ]; then
WORKTREE_PROJECT_ROOT="$WORKTREE_ROOT"
else
echo "❌ Cannot find project structure in worktree"
echo " Current directory: $WORKTREE_ROOT"
exit 1
fi
echo "📁 Worktree project root: $WORKTREE_PROJECT_ROOT"
# TASK_ID file to ensure consistency (same as vibe-setup.sh)
TASK_ID_FILE="$WORKTREE_PROJECT_ROOT/.vibe-task-id"
# Load setup configuration if available
SETUP_CONFIG_FILE="$WORKTREE_PROJECT_ROOT/.vibe-setup.env"
if [ -f "$SETUP_CONFIG_FILE" ]; then
echo "📋 Loading setup configuration from: $SETUP_CONFIG_FILE"
source "$SETUP_CONFIG_FILE"
echo " Task ID: $TASK_ID"
echo " Task Slot: ${TASK_SLOT:-not set}"
echo " Port offset: $PORT_OFFSET"
echo " API Port: $API_PORT"
else
echo "⚠️ Setup configuration not found: $SETUP_CONFIG_FILE"
echo "💡 Run scripts/vibe-kanban/vibe-setup.sh first to set up the database"
# Try to get TASK_ID from stored file (ensures consistency)
if [ -f "$TASK_ID_FILE" ]; then
TASK_ID=$(cat "$TASK_ID_FILE" 2>/dev/null | tr -d '[:space:]')
if [ -n "$TASK_ID" ]; then
echo "📋 Using stored TASK_ID: $TASK_ID"
fi
fi
# Try command line argument
if [ -z "$TASK_ID" ]; then
TASK_ID=${1:-""}
fi
# Try environment variables
if [ -z "$TASK_ID" ]; then
if [ -n "$VIBE_TASK_ID" ]; then
TASK_ID="$VIBE_TASK_ID"
elif [ -n "$VIBE_TASK_NAME" ]; then
TASK_ID="$VIBE_TASK_NAME"
fi
fi
PORT_OFFSET=${2:-0}
if [ -z "$TASK_ID" ]; then
echo "❌ TASK_ID is required"
echo "💡 Usage: $0 <TASK_ID> [PORT_OFFSET]"
echo "💡 Or run scripts/vibe-kanban/vibe-setup.sh first to create setup configuration"
exit 1
fi
API_PORT=$((5000 + PORT_OFFSET))
# Extract TASK_SLOT from TASK_ID if not in config
if [ -z "$TASK_SLOT" ]; then
TASK_SLOT=$(echo "$TASK_ID" | grep -oE '[0-9]+' | head -1)
if [ -z "$TASK_SLOT" ] || [ "$TASK_SLOT" = "0" ]; then
TASK_SLOT=$((PORT_OFFSET / 10 + 1))
fi
fi
echo " Using Task ID: $TASK_ID"
echo " Using Task Slot: $TASK_SLOT"
echo " Using Port offset: $PORT_OFFSET"
fi
# Find main repository
MAIN_REPO_PATHS=(
"/Users/oda/Desktop/Projects/managing-apps"
"$(git -C "$WORKTREE_PROJECT_ROOT" rev-parse --show-toplevel 2>/dev/null || echo '')"
"$(dirname "$WORKTREE_ROOT" 2>/dev/null)/managing-apps"
"${MAIN_REPO:-}"
)
MAIN_REPO=""
for path in "${MAIN_REPO_PATHS[@]}"; do
if [ -n "$path" ] && [ -d "$path" ] && [ -d "$path/scripts" ] && [ -f "$path/scripts/start-api-and-workers.sh" ]; then
MAIN_REPO="$path"
break
fi
done
if [ -z "$MAIN_REPO" ]; then
echo "❌ Cannot find main repository with scripts"
exit 1
fi
echo "📁 Main repository: $MAIN_REPO"
echo "🚀 Starting API and Workers..."
echo " Task ID: $TASK_ID"
echo " Port offset: $PORT_OFFSET"
# Verify database is ready
if [ -n "$POSTGRES_PORT" ]; then
echo "🔍 Verifying database is ready on port $POSTGRES_PORT..."
if ! PGPASSWORD=postgres psql -h localhost -p $POSTGRES_PORT -U postgres -d postgres -c '\q' 2>/dev/null; then
echo "❌ Database is not ready on port $POSTGRES_PORT"
echo "💡 Run scripts/vibe-kanban/vibe-setup.sh first to set up the database"
exit 1
fi
echo "✅ Database is ready"
fi
# Export worktree path so main repo scripts know where to run dotnet from
export VIBE_WORKTREE_ROOT="$WORKTREE_PROJECT_ROOT"
# Start API and Workers only (database setup is already done)
bash "$MAIN_REPO/scripts/start-api-and-workers.sh" "$TASK_ID" "$PORT_OFFSET"
# Determine log file paths (logs are created in the worktree root)
PID_DIR="$WORKTREE_PROJECT_ROOT/.task-pids"
API_LOG="$PID_DIR/api-${TASK_ID}.log"
WORKERS_LOG="$PID_DIR/workers-${TASK_ID}.log"
# Wait for log files to be created
echo ""
echo "⏳ Waiting for services to start and log files to be created..."
for i in {1..30}; do
if [ -f "$API_LOG" ] && [ -f "$WORKERS_LOG" ]; then
echo "✅ Log files found"
break
fi
if [ $i -eq 30 ]; then
echo "⚠️ Log files not found after 30 seconds"
echo " API log: $API_LOG"
echo " Workers log: $WORKERS_LOG"
echo " Continuing anyway..."
fi
sleep 1
done
# Show logs with labels
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📋 Showing API and Workers logs (Press Ctrl+C to stop)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Check if log files exist
if [ ! -f "$API_LOG" ] && [ ! -f "$WORKERS_LOG" ]; then
echo "❌ No log files found"
echo " API log: $API_LOG"
echo " Workers log: $WORKERS_LOG"
echo "💡 Services may still be starting. You can manually view logs with:"
echo " tail -f $API_LOG"
echo " tail -f $WORKERS_LOG"
exit 1
fi
# Use multitail if available for better viewing, otherwise use simple tail
if command -v multitail >/dev/null 2>&1; then
echo "📋 Using multitail for split-screen log viewing..."
if [ -f "$API_LOG" ] && [ -f "$WORKERS_LOG" ]; then
multitail -s 2 \
-ci green -T "API" "$API_LOG" \
-ci yellow -T "Workers" "$WORKERS_LOG"
elif [ -f "$API_LOG" ]; then
tail -f "$API_LOG"
elif [ -f "$WORKERS_LOG" ]; then
tail -f "$WORKERS_LOG"
fi
else
# Simple approach: tail both files with prefixes
# Use a subshell to manage background processes
(
# Start tailing API logs in background (filter out NuGet build warnings)
if [ -f "$API_LOG" ]; then
tail -f "$API_LOG" 2>/dev/null | grep -vE "(warning NU|\.csproj : warning)" | while IFS= read -r line; do
echo "[API] $line"
done &
TAIL_API_PID=$!
fi
# Start tailing Workers logs in background (filter out NuGet build warnings)
if [ -f "$WORKERS_LOG" ]; then
tail -f "$WORKERS_LOG" 2>/dev/null | grep -vE "(warning NU|\.csproj : warning)" | while IFS= read -r line; do
echo "[WORKERS] $line"
done &
TAIL_WORKERS_PID=$!
fi
# Clean up background processes on exit
cleanup() {
[ -n "$TAIL_API_PID" ] && kill "$TAIL_API_PID" 2>/dev/null
[ -n "$TAIL_WORKERS_PID" ] && kill "$TAIL_WORKERS_PID" 2>/dev/null
exit
}
trap cleanup INT TERM EXIT
# Wait for background processes
wait
)
fi

312
scripts/vibe-kanban/vibe-setup.sh Executable file
View File

@@ -0,0 +1,312 @@
#!/bin/bash
# scripts/vibe-kanban/vibe-setup.sh
# Setup script for Vibe Kanban - sets up database and Docker services
# This script runs in the "setup" section of Vibe Kanban
# Usage: bash scripts/vibe-kanban/vibe-setup.sh [TASK_ID] [PORT_OFFSET]
# TASK_ID can also come from environment variables or worktree path
PORT_OFFSET=${2:-0}
# Detect worktree root
WORKTREE_ROOT="$(pwd)"
# Check if we're in a nested structure (Vibe Kanban worktree)
if [ -d "$WORKTREE_ROOT/managing-apps" ] && [ -d "$WORKTREE_ROOT/managing-apps/src/Managing.Api" ]; then
WORKTREE_PROJECT_ROOT="$WORKTREE_ROOT/managing-apps"
elif [ -d "$WORKTREE_ROOT/src/Managing.Api" ]; then
WORKTREE_PROJECT_ROOT="$WORKTREE_ROOT"
else
echo "❌ Cannot find project structure in worktree"
echo " Current directory: $WORKTREE_ROOT"
exit 1
fi
echo "📁 Worktree project root: $WORKTREE_PROJECT_ROOT"
# TASK_ID file to ensure consistency across runs
TASK_ID_FILE="$WORKTREE_PROJECT_ROOT/.vibe-task-id"
# Try to get TASK_ID from various sources
TASK_ID=$1
# First, check if we have a stored TASK_ID for this worktree (ensures consistency)
if [ -z "$TASK_ID" ] && [ -f "$TASK_ID_FILE" ]; then
TASK_ID=$(cat "$TASK_ID_FILE" 2>/dev/null | tr -d '[:space:]')
if [ -n "$TASK_ID" ]; then
echo "📋 Using stored TASK_ID from previous setup: $TASK_ID"
fi
fi
if [ -z "$TASK_ID" ]; then
# Try environment variables (Vibe Kanban might set these)
if [ -n "$VIBE_TASK_ID" ]; then
TASK_ID="$VIBE_TASK_ID"
echo "📋 Found TASK_ID from VIBE_TASK_ID: $TASK_ID"
elif [ -n "$VIBE_TASK_NAME" ]; then
TASK_ID="$VIBE_TASK_NAME"
echo "📋 Found TASK_ID from VIBE_TASK_NAME: $TASK_ID"
elif [ -n "$TASK_ID_ENV" ]; then
TASK_ID="$TASK_ID_ENV"
echo "📋 Found TASK_ID from TASK_ID_ENV: $TASK_ID"
elif [ -n "$TASK" ]; then
TASK_ID="$TASK"
echo "📋 Found TASK_ID from TASK: $TASK_ID"
fi
fi
# Try to extract from worktree path (Vibe Kanban worktrees often contain task ID/name)
if [ -z "$TASK_ID" ]; then
# Extract task ID from worktree path (e.g., /path/to/worktrees/TASK-123/... or /path/to/worktrees/ticket-name/...)
# Try UUID format first (Vibe Kanban might use UUIDs)
DETECTED_TASK=$(echo "$WORKTREE_ROOT" | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | head -1)
# If no UUID, try task ID pattern (e.g., DEV-123, TASK-456)
if [ -z "$DETECTED_TASK" ]; then
DETECTED_TASK=$(echo "$WORKTREE_ROOT" | grep -oE '[A-Z]+-[0-9]+' | head -1)
fi
# If still no match, try to get the last directory name (might be task name)
if [ -z "$DETECTED_TASK" ]; then
LAST_DIR=$(basename "$WORKTREE_ROOT")
# Skip common directory names
if [ "$LAST_DIR" != "managing-apps" ] && [ "$LAST_DIR" != "worktrees" ] && [ "$LAST_DIR" != "Projects" ]; then
# Generate a numeric ID from the directory name (hash-based for consistency)
# This ensures the same ticket name always gets the same numeric ID
HASH=$(echo -n "$LAST_DIR" | shasum -a 256 | cut -d' ' -f1 | head -c 8)
# Convert hex to decimal and take modulo to get a number between 1-9999
NUMERIC_ID=$((0x$HASH % 9999 + 1))
DETECTED_TASK="TASK-$NUMERIC_ID"
echo "📋 Generated numeric TASK_ID from ticket name '$LAST_DIR': $DETECTED_TASK"
fi
fi
if [ -n "$DETECTED_TASK" ]; then
TASK_ID="$DETECTED_TASK"
echo "📋 Detected TASK_ID from worktree path: $TASK_ID"
fi
fi
# Fallback to numeric ID based on worktree path hash (ensures consistency)
if [ -z "$TASK_ID" ]; then
# Generate a consistent numeric ID from worktree path
HASH=$(echo -n "$WORKTREE_ROOT" | shasum -a 256 | cut -d' ' -f1 | head -c 8)
NUMERIC_ID=$((0x$HASH % 9999 + 1))
TASK_ID="TASK-$NUMERIC_ID"
echo "📋 Generated consistent numeric TASK_ID from worktree path: $TASK_ID"
fi
# Store TASK_ID for future use (ensures same worktree always uses same TASK_ID)
echo "$TASK_ID" > "$TASK_ID_FILE"
echo "💾 Stored TASK_ID for future use: $TASK_ID"
# Find main repository (try common locations)
MAIN_REPO_PATHS=(
"/Users/oda/Desktop/Projects/managing-apps"
"$(git -C "$WORKTREE_PROJECT_ROOT" rev-parse --show-toplevel 2>/dev/null || echo '')"
"$(dirname "$WORKTREE_ROOT" 2>/dev/null)/managing-apps"
)
MAIN_REPO=""
for path in "${MAIN_REPO_PATHS[@]}"; do
if [ -n "$path" ] && [ -d "$path" ] && [ -d "$path/scripts" ] && [ -f "$path/scripts/start-task-docker.sh" ]; then
MAIN_REPO="$path"
break
fi
done
if [ -z "$MAIN_REPO" ]; then
echo "❌ Cannot find main repository with scripts"
echo "💡 Tried:"
for path in "${MAIN_REPO_PATHS[@]}"; do
echo " - $path"
done
exit 1
fi
echo "📁 Main repository: $MAIN_REPO"
echo "🔧 Setting up environment for task: $TASK_ID"
SCRIPT_DIR="$MAIN_REPO/scripts"
# Auto-detect port offset if 0 is provided
if [ "$PORT_OFFSET" = "0" ]; then
echo "🔍 Auto-detecting available port offset..."
PORT_OFFSET_FOUND=0
for offset in $(seq 1 100); do
POSTGRES_TEST=$((5432 + offset))
REDIS_TEST=$((6379 + offset))
API_TEST=$((5000 + offset))
ORLEANS_SILO_TEST=$((11111 + offset))
ORLEANS_GATEWAY_TEST=$((30000 + offset))
POSTGRES_FREE=true
REDIS_FREE=true
API_FREE=true
ORLEANS_SILO_FREE=true
ORLEANS_GATEWAY_FREE=true
if command -v lsof >/dev/null 2>&1; then
if lsof -Pi :$POSTGRES_TEST -sTCP:LISTEN -t >/dev/null 2>&1; then
POSTGRES_FREE=false
fi
if lsof -Pi :$REDIS_TEST -sTCP:LISTEN -t >/dev/null 2>&1; then
REDIS_FREE=false
fi
if lsof -Pi :$API_TEST -sTCP:LISTEN -t >/dev/null 2>&1; then
API_FREE=false
fi
if lsof -Pi :$ORLEANS_SILO_TEST -sTCP:LISTEN -t >/dev/null 2>&1; then
ORLEANS_SILO_FREE=false
fi
if lsof -Pi :$ORLEANS_GATEWAY_TEST -sTCP:LISTEN -t >/dev/null 2>&1; then
ORLEANS_GATEWAY_FREE=false
fi
fi
if [ "$POSTGRES_FREE" = "true" ] && [ "$REDIS_FREE" = "true" ] && [ "$API_FREE" = "true" ] && [ "$ORLEANS_SILO_FREE" = "true" ] && [ "$ORLEANS_GATEWAY_FREE" = "true" ]; then
PORT_OFFSET=$offset
PORT_OFFSET_FOUND=1
echo "✅ Found available port offset: $PORT_OFFSET"
break
fi
done
if [ "$PORT_OFFSET_FOUND" = "0" ]; then
echo "❌ Could not find available port offset (checked offsets 1-100)"
exit 1
fi
fi
POSTGRES_PORT=$((5432 + PORT_OFFSET))
API_PORT=$((5000 + PORT_OFFSET))
REDIS_PORT=$((6379 + PORT_OFFSET))
DB_NAME="managing_$(echo "$TASK_ID" | tr '[:upper:]' '[:lower:]')"
ORLEANS_DB_NAME="orleans_$(echo "$TASK_ID" | tr '[:upper:]' '[:lower:]')"
# Extract TASK_SLOT from TASK_ID numeric part (e.g., TASK-5439 -> 5439)
# This ensures unique Orleans ports for each task
TASK_SLOT=$(echo "$TASK_ID" | grep -oE '[0-9]+' | head -1)
if [ -z "$TASK_SLOT" ] || [ "$TASK_SLOT" = "0" ]; then
# Fallback: use a hash-based numeric ID if TASK_ID doesn't contain numbers
HASH=$(echo -n "$TASK_ID" | shasum -a 256 | cut -d' ' -f1 | head -c 8)
TASK_SLOT=$((0x$HASH % 9999 + 1))
echo "⚠️ TASK_ID doesn't contain a number, generated TASK_SLOT: $TASK_SLOT"
else
echo "📊 TASK_SLOT extracted from TASK_ID: $TASK_SLOT"
fi
# Calculate Orleans ports based on TASK_SLOT
ORLEANS_SILO_PORT=$((11111 + (TASK_SLOT - 1) * 10))
ORLEANS_GATEWAY_PORT=$((30000 + (TASK_SLOT - 1) * 10))
ORLEANS_DASHBOARD_PORT=$((9999 + (TASK_SLOT - 1)))
echo "📊 Port offset: $PORT_OFFSET"
echo "📊 PostgreSQL: localhost:$POSTGRES_PORT"
echo "📊 Redis: localhost:$REDIS_PORT"
echo "📊 API: http://localhost:$API_PORT"
echo "💾 Database: $DB_NAME"
# Verify main database is accessible
echo "🔍 Verifying main database connection..."
if ! PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d managing -c '\q' 2>/dev/null; then
echo "❌ Cannot connect to main database at localhost:5432"
echo "💡 Starting main database..."
cd "$MAIN_REPO/src/Managing.Docker"
if command -v docker &> /dev/null && docker compose version &> /dev/null; then
docker compose -f docker-compose.yml -f docker-compose.local.yml up -d postgres
else
docker-compose -f docker-compose.yml -f docker-compose.local.yml up -d postgres
fi
echo "⏳ Waiting for database to start..."
sleep 15
fi
# Create compose file
echo "📝 Creating Docker Compose file..."
bash "$SCRIPT_DIR/create-task-compose.sh" "$TASK_ID" "$PORT_OFFSET"
COMPOSE_FILE="$MAIN_REPO/src/Managing.Docker/docker-compose.task-${TASK_ID}.yml"
# Start services (PostgreSQL and Redis only)
echo "🐳 Starting PostgreSQL and Redis..."
cd "$MAIN_REPO/src/Managing.Docker"
if command -v docker &> /dev/null && docker compose version &> /dev/null; then
docker compose -f "$COMPOSE_FILE" up -d postgres-${TASK_ID} redis-${TASK_ID}
else
docker-compose -f "$COMPOSE_FILE" up -d postgres-${TASK_ID} redis-${TASK_ID}
fi
# Wait for PostgreSQL
echo "⏳ Waiting for PostgreSQL..."
for i in {1..60}; do
if PGPASSWORD=postgres psql -h localhost -p $POSTGRES_PORT -U postgres -d postgres -c '\q' 2>/dev/null; then
echo "✅ PostgreSQL is ready"
break
fi
if [ $i -eq 60 ]; then
echo "❌ PostgreSQL not ready after 60 attempts"
if command -v docker &> /dev/null && docker compose version &> /dev/null; then
docker compose -f "$COMPOSE_FILE" down
else
docker-compose -f "$COMPOSE_FILE" down
fi
exit 1
fi
sleep 2
done
# Copy database
echo "📦 Copying database from main repo..."
bash "$SCRIPT_DIR/copy-database-for-task.sh" "$TASK_ID" "localhost" "5432" "localhost" "$POSTGRES_PORT"
if [ $? -ne 0 ]; then
echo "❌ Database copy failed"
if command -v docker &> /dev/null && docker compose version &> /dev/null; then
docker compose -f "$COMPOSE_FILE" down
else
docker-compose -f "$COMPOSE_FILE" down
fi
exit 1
fi
# Store configuration for later use (in worktree)
SETUP_CONFIG_FILE="$WORKTREE_PROJECT_ROOT/.vibe-setup.env"
echo "💾 Saving setup configuration..."
cat > "$SETUP_CONFIG_FILE" <<EOF
TASK_ID=$TASK_ID
TASK_SLOT=$TASK_SLOT
PORT_OFFSET=$PORT_OFFSET
POSTGRES_PORT=$POSTGRES_PORT
API_PORT=$API_PORT
REDIS_PORT=$REDIS_PORT
ORLEANS_SILO_PORT=$ORLEANS_SILO_PORT
ORLEANS_GATEWAY_PORT=$ORLEANS_GATEWAY_PORT
ORLEANS_DASHBOARD_PORT=$ORLEANS_DASHBOARD_PORT
DB_NAME=$DB_NAME
ORLEANS_DB_NAME=$ORLEANS_DB_NAME
VIBE_WORKTREE_ROOT=$WORKTREE_PROJECT_ROOT
MAIN_REPO=$MAIN_REPO
EOF
echo ""
echo "✅ Setup complete!"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📋 Configuration Details:"
echo " Task ID: $TASK_ID"
echo " Task Slot: $TASK_SLOT (from TASK_ID numeric part)"
echo " Port Offset: $PORT_OFFSET"
echo " PostgreSQL Port: $POSTGRES_PORT"
echo " Redis Port: $REDIS_PORT"
echo " API Port: $API_PORT (will be used when starting API)"
echo " Orleans Silo Port: $ORLEANS_SILO_PORT"
echo " Orleans Gateway Port: $ORLEANS_GATEWAY_PORT"
echo " Orleans Dashboard Port: $ORLEANS_DASHBOARD_PORT"
echo " Database Name: $DB_NAME"
echo " Orleans Database: $ORLEANS_DB_NAME"
echo " Configuration File: $SETUP_CONFIG_FILE"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "💡 Next step: Start API and Workers using scripts/vibe-kanban/vibe-dev-server.sh"
# Explicit exit with success code to signal Vibe Kanban that setup is complete
exit 0