Files
homeai/start.sh
Aodhan Collins 3c0d905e64 feat: unified HomeAI dashboard — merge character + desktop into single app
Combines homeai-character (service status, character profiles, editor) and
homeai-desktop (chat with voice I/O) into homeai-dashboard on port 5173.

- 4-page sidebar layout: Dashboard, Chat, Characters, Editor
- Merged Vite middleware: health checks, service restart, bridge proxy
- Bridge upgraded to ThreadingHTTPServer (fixes LAN request queuing)
- TTS strips emojis before synthesis
- Updated start.sh with new launchd service names
- Added preload-models to startup sequence

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 18:40:04 +00:00

222 lines
6.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# start.sh — Start all HomeAI services on LINDBLUM
#
# Usage:
# ./start.sh # start everything
# ./start.sh status # show what's running
# ./start.sh stop # stop everything
# ./start.sh restart # stop then start everything
set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${REPO_DIR}/scripts/common.sh"
DOCKER_DIR="${HOME}/server/docker"
# ─── Service definitions ──────────────────────────────────────────────────────
LAUNCHD_SERVICES=(
com.homeai.ollama
com.homeai.wyoming-stt
com.homeai.wyoming-tts
com.homeai.wyoming-satellite
com.homeai.openclaw
com.homeai.openclaw-bridge
com.homeai.preload-models
com.homeai.dashboard
)
DOCKER_COMPOSE_DIRS=(
"${DOCKER_DIR}/open-webui"
"${DOCKER_DIR}/uptime-kuma"
"${DOCKER_DIR}/n8n"
"${DOCKER_DIR}/code-server"
)
# ─── Helpers ──────────────────────────────────────────────────────────────────
launchd_running() {
local label="$1"
local pid
pid=$(launchctl list "$label" 2>/dev/null | grep '"PID"' | sed 's/[^0-9]//g' || true)
[[ -n "$pid" && "$pid" -gt 0 ]] 2>/dev/null
}
start_launchd() {
local label="$1"
local plist="${HOME}/Library/LaunchAgents/${label}.plist"
if [[ ! -f "$plist" ]]; then
log_warn "Plist not found: $plist — skipping"
return
fi
if launchd_running "$label"; then
log_info "Already running: $label"
return
fi
log_step "Starting $label"
# bootstrap loads + starts the agent
launchctl bootstrap "gui/$(id -u)" "$plist" 2>/dev/null \
|| launchctl kickstart -k "gui/$(id -u)/$label" 2>/dev/null \
|| true
sleep 0.5
if launchd_running "$label"; then
log_success "$label started"
else
log_warn "$label may not have started — check logs"
fi
}
stop_launchd() {
local label="$1"
local plist="${HOME}/Library/LaunchAgents/${label}.plist"
if [[ ! -f "$plist" ]]; then
return
fi
if ! launchd_running "$label"; then
log_info "Already stopped: $label"
return
fi
log_step "Stopping $label"
launchctl bootout "gui/$(id -u)/$label" 2>/dev/null || true
log_success "$label stopped"
}
start_docker_services() {
ensure_docker_running
for dir in "${DOCKER_COMPOSE_DIRS[@]}"; do
if [[ ! -d "$dir" ]]; then
log_warn "Docker compose dir not found: $dir — skipping"
continue
fi
local name
name=$(basename "$dir")
log_step "Starting Docker stack: $name"
docker_compose -f "${dir}/docker-compose.yml" up -d 2>/dev/null \
|| docker_compose -f "${dir}/compose.yml" up -d 2>/dev/null \
|| log_warn "No compose file found in $dir"
done
}
stop_docker_services() {
for dir in "${DOCKER_COMPOSE_DIRS[@]}"; do
if [[ ! -d "$dir" ]]; then
continue
fi
local name
name=$(basename "$dir")
log_step "Stopping Docker stack: $name"
docker_compose -f "${dir}/docker-compose.yml" down 2>/dev/null \
|| docker_compose -f "${dir}/compose.yml" down 2>/dev/null \
|| true
done
}
# ─── Commands ─────────────────────────────────────────────────────────────────
do_start() {
log_section "Starting HomeAI Services"
echo ""
log_info "── LaunchD services ──"
for svc in "${LAUNCHD_SERVICES[@]}"; do
start_launchd "$svc"
done
echo ""
log_info "── Docker services ──"
start_docker_services
echo ""
log_success "All services started."
echo ""
do_status
}
do_stop() {
log_section "Stopping HomeAI Services"
echo ""
log_info "── LaunchD services ──"
for svc in "${LAUNCHD_SERVICES[@]}"; do
stop_launchd "$svc"
done
echo ""
log_info "── Docker services ──"
stop_docker_services
echo ""
log_success "All services stopped."
}
do_status() {
log_section "HomeAI Service Status"
# LaunchD services
printf "\n ${BOLD}%-34s %-10s %s${RESET}\n" "SERVICE" "STATUS" "PID"
printf " %-34s %-10s %s\n" "─────────────────────────────────" "────────" "─────"
for svc in "${LAUNCHD_SERVICES[@]}"; do
local pid
pid=$(launchctl list "$svc" 2>/dev/null | grep '"PID"' | sed 's/[^0-9]//g' || true)
if [[ -n "$pid" && "$pid" -gt 0 ]] 2>/dev/null; then
printf " ${GREEN}${RESET} %-32s ${GREEN}%-10s${RESET} %s\n" "$svc" "running" "$pid"
else
printf " ${RED}${RESET} %-32s ${RED}%-10s${RESET} %s\n" "$svc" "stopped" "-"
fi
done
# Docker services
echo ""
local containers=("homeai-open-webui" "homeai-uptime-kuma" "homeai-n8n" "homeai-code-server")
for c in "${containers[@]}"; do
local state
state=$(docker inspect -f '{{.State.Status}}' "$c" 2>/dev/null || echo "not found")
if [[ "$state" == "running" ]]; then
printf " ${GREEN}${RESET} %-32s ${GREEN}%-10s${RESET}\n" "$c" "$state"
else
printf " ${RED}${RESET} %-32s ${RED}%-10s${RESET}\n" "$c" "$state"
fi
done
echo ""
}
# ─── Main ─────────────────────────────────────────────────────────────────────
main() {
local cmd="${1:-start}"
case "$cmd" in
start) do_start ;;
stop) do_stop ;;
restart) do_stop; echo ""; do_start ;;
status) do_status ;;
-h|--help|help)
echo ""
echo " Usage: $0 [start|stop|restart|status]"
echo ""
echo " Commands:"
echo " start Start all HomeAI services (default)"
echo " stop Stop all HomeAI services"
echo " restart Stop then start all services"
echo " status Show current service status"
echo ""
;;
*) die "Unknown command: $cmd. Run '$0 help' for usage." ;;
esac
}
main "$@"