chore: add install scripts, doctor command, and AGENTS.md
- Add one-line installer (scripts/install.sh) with platform detection - Add doctor command (scripts/commands/doctor.sh) for environment diagnostics - Add shared libraries: dependencies, docker, platform, validation - Update README with quick-start installer instructions - Add AGENTS.md with codebase patterns for AI agent context Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
552
scripts/commands/doctor.sh
Executable file
552
scripts/commands/doctor.sh
Executable file
@@ -0,0 +1,552 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# ============================================================================
|
||||
# Mosaic Stack Doctor
|
||||
# ============================================================================
|
||||
# Diagnostic and repair tool for Mosaic Stack installations.
|
||||
# Run without arguments for interactive mode, or use flags for CI/CD.
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# Source library files
|
||||
# shellcheck source=../lib/platform.sh
|
||||
source "$SCRIPT_DIR/../lib/platform.sh"
|
||||
# shellcheck source=../lib/dependencies.sh
|
||||
source "$SCRIPT_DIR/../lib/dependencies.sh"
|
||||
# shellcheck source=../lib/docker.sh
|
||||
source "$SCRIPT_DIR/../lib/docker.sh"
|
||||
# shellcheck source=../lib/validation.sh
|
||||
source "$SCRIPT_DIR/../lib/validation.sh"
|
||||
|
||||
# ============================================================================
|
||||
# Configuration
|
||||
# ============================================================================
|
||||
|
||||
FIX_MODE=false
|
||||
JSON_OUTPUT=false
|
||||
VERBOSE=false
|
||||
ENV_FILE="$PROJECT_ROOT/.env"
|
||||
COMPOSE_FILE="$PROJECT_ROOT/docker-compose.yml"
|
||||
MODE=""
|
||||
|
||||
# ============================================================================
|
||||
# Help
|
||||
# ============================================================================
|
||||
|
||||
print_usage() {
|
||||
cat << EOF
|
||||
Mosaic Stack Doctor - Diagnostic and repair tool
|
||||
|
||||
USAGE:
|
||||
./scripts/commands/doctor.sh [OPTIONS]
|
||||
|
||||
OPTIONS:
|
||||
-h, --help Show this help message
|
||||
--fix Attempt to automatically fix issues
|
||||
--json Output results in JSON format
|
||||
--verbose Show detailed output
|
||||
--env FILE Path to .env file (default: .env)
|
||||
--compose FILE Path to docker-compose.yml (default: docker-compose.yml)
|
||||
--mode MODE Deployment mode: docker or native (auto-detected)
|
||||
|
||||
EXIT CODES:
|
||||
0 All checks passed
|
||||
1 Some checks failed
|
||||
2 Critical failure
|
||||
|
||||
EXAMPLES:
|
||||
# Run all checks
|
||||
./scripts/commands/doctor.sh
|
||||
|
||||
# Attempt automatic fixes
|
||||
./scripts/commands/doctor.sh --fix
|
||||
|
||||
# JSON output for CI/CD
|
||||
./scripts/commands/doctor.sh --json
|
||||
|
||||
# Verbose output
|
||||
./scripts/commands/doctor.sh --verbose
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Argument Parsing
|
||||
# ============================================================================
|
||||
|
||||
parse_arguments() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
--fix)
|
||||
FIX_MODE=true
|
||||
shift
|
||||
;;
|
||||
--json)
|
||||
JSON_OUTPUT=true
|
||||
shift
|
||||
;;
|
||||
--verbose)
|
||||
VERBOSE=true
|
||||
shift
|
||||
;;
|
||||
--env)
|
||||
ENV_FILE="$2"
|
||||
shift 2
|
||||
;;
|
||||
--compose)
|
||||
COMPOSE_FILE="$2"
|
||||
shift 2
|
||||
;;
|
||||
--mode)
|
||||
MODE="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Auto-detect mode if not specified
|
||||
if [[ -z "$MODE" ]]; then
|
||||
if [[ -f "$COMPOSE_FILE" ]] && command -v docker &>/dev/null && docker info &>/dev/null; then
|
||||
MODE="docker"
|
||||
else
|
||||
MODE="native"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# JSON Output Helpers
|
||||
# ============================================================================
|
||||
|
||||
json_start() {
|
||||
if [[ "$JSON_OUTPUT" == true ]]; then
|
||||
echo "{"
|
||||
echo ' "timestamp": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'",'
|
||||
echo ' "version": "1.0.0",'
|
||||
echo ' "mode": "'$MODE'",'
|
||||
echo ' "checks": ['
|
||||
fi
|
||||
}
|
||||
|
||||
json_end() {
|
||||
local errors="$1"
|
||||
local warnings="$2"
|
||||
|
||||
if [[ "$JSON_OUTPUT" == true ]]; then
|
||||
echo ""
|
||||
echo " ],"
|
||||
echo ' "summary": {'
|
||||
echo ' "errors": '$errors','
|
||||
echo ' "warnings": '$warnings','
|
||||
echo ' "status": "'$([ "$errors" -gt 0 ] && echo "failed" || ([ "$warnings" -gt 0 ] && echo "warning" || echo "passed"))'"'
|
||||
echo ' }'
|
||||
echo "}"
|
||||
fi
|
||||
}
|
||||
|
||||
json_check() {
|
||||
local name="$1"
|
||||
local status="$2"
|
||||
local message="$3"
|
||||
local first="${4:-true}"
|
||||
|
||||
if [[ "$JSON_OUTPUT" == true ]]; then
|
||||
[[ "$first" != "true" ]] && echo ","
|
||||
echo -n ' {"name": "'$name'", "status": "'$status'", "message": "'$message'"}'
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Fix Functions
|
||||
# ============================================================================
|
||||
|
||||
fix_env_permissions() {
|
||||
echo -e "${WARN}→${NC} Fixing .env permissions..."
|
||||
chmod 600 "$ENV_FILE"
|
||||
echo -e "${SUCCESS}✓${NC} Fixed"
|
||||
}
|
||||
|
||||
fix_docker_permissions() {
|
||||
echo -e "${WARN}→${NC} Adding user to docker group..."
|
||||
maybe_sudo usermod -aG docker "$USER"
|
||||
echo -e "${SUCCESS}✓${NC} User added to docker group"
|
||||
echo -e "${INFO}ℹ${NC} Run 'newgrp docker' or log out/in for changes to take effect"
|
||||
}
|
||||
|
||||
start_docker_daemon() {
|
||||
echo -e "${WARN}→${NC} Starting Docker daemon..."
|
||||
maybe_sudo systemctl start docker
|
||||
sleep 3
|
||||
if docker info &>/dev/null; then
|
||||
echo -e "${SUCCESS}✓${NC} Docker started"
|
||||
else
|
||||
echo -e "${ERROR}✗${NC} Failed to start Docker"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
restart_containers() {
|
||||
echo -e "${WARN}→${NC} Restarting containers..."
|
||||
docker_compose_down "$COMPOSE_FILE" "$ENV_FILE"
|
||||
docker_compose_up "$COMPOSE_FILE" "$ENV_FILE"
|
||||
echo -e "${SUCCESS}✓${NC} Containers restarted"
|
||||
}
|
||||
|
||||
generate_missing_secrets() {
|
||||
echo -e "${WARN}→${NC} Generating missing secrets..."
|
||||
|
||||
# Load existing env
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
set -a
|
||||
# shellcheck source=/dev/null
|
||||
source "$ENV_FILE" 2>/dev/null || true
|
||||
set +a
|
||||
fi
|
||||
|
||||
local updated=false
|
||||
|
||||
# Check each secret
|
||||
if [[ -z "${JWT_SECRET:-}" ]] || is_placeholder "${JWT_SECRET:-}"; then
|
||||
JWT_SECRET=$(openssl rand -base64 32)
|
||||
echo "JWT_SECRET=$JWT_SECRET" >> "$ENV_FILE"
|
||||
updated=true
|
||||
fi
|
||||
|
||||
if [[ -z "${BETTER_AUTH_SECRET:-}" ]] || is_placeholder "${BETTER_AUTH_SECRET:-}"; then
|
||||
BETTER_AUTH_SECRET=$(openssl rand -base64 32)
|
||||
echo "BETTER_AUTH_SECRET=$BETTER_AUTH_SECRET" >> "$ENV_FILE"
|
||||
updated=true
|
||||
fi
|
||||
|
||||
if [[ -z "${ENCRYPTION_KEY:-}" ]] || is_placeholder "${ENCRYPTION_KEY:-}"; then
|
||||
ENCRYPTION_KEY=$(openssl rand -hex 32)
|
||||
echo "ENCRYPTION_KEY=$ENCRYPTION_KEY" >> "$ENV_FILE"
|
||||
updated=true
|
||||
fi
|
||||
|
||||
if [[ -z "${POSTGRES_PASSWORD:-}" ]] || is_placeholder "${POSTGRES_PASSWORD:-}"; then
|
||||
POSTGRES_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=' | head -c 32)
|
||||
# Update DATABASE_URL too
|
||||
DATABASE_URL="postgresql://mosaic:${POSTGRES_PASSWORD}@postgres:5432/mosaic"
|
||||
sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$POSTGRES_PASSWORD|" "$ENV_FILE" 2>/dev/null || \
|
||||
echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> "$ENV_FILE"
|
||||
sed -i "s|^DATABASE_URL=.*|DATABASE_URL=$DATABASE_URL|" "$ENV_FILE" 2>/dev/null || \
|
||||
echo "DATABASE_URL=$DATABASE_URL" >> "$ENV_FILE"
|
||||
updated=true
|
||||
fi
|
||||
|
||||
if [[ "$updated" == true ]]; then
|
||||
echo -e "${SUCCESS}✓${NC} Secrets generated"
|
||||
else
|
||||
echo -e "${INFO}ℹ${NC} All secrets already set"
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Check Functions
|
||||
# ============================================================================
|
||||
|
||||
run_checks() {
|
||||
local errors=0
|
||||
local warnings=0
|
||||
local first=true
|
||||
|
||||
json_start
|
||||
|
||||
# System requirements
|
||||
echo -e "${BOLD}━━━ System Requirements ━━━${NC}"
|
||||
check_system_requirements 2048 10
|
||||
local result=$?
|
||||
[[ $result -eq $CHECK_FAIL ]] && ((errors++))
|
||||
[[ $result -eq $CHECK_WARN ]] && ((warnings++))
|
||||
json_check "system_requirements" "$( [[ $result -eq 0 ]] && echo "pass" || ([[ $result -eq 1 ]] && echo "warn" || echo "fail") )" "RAM and disk check" "$first"
|
||||
first=false
|
||||
echo ""
|
||||
|
||||
# Environment file
|
||||
echo -e "${BOLD}━━━ Environment File ━━━${NC}"
|
||||
check_env_file "$ENV_FILE"
|
||||
result=$?
|
||||
[[ $result -eq $CHECK_FAIL ]] && ((errors++))
|
||||
[[ $result -eq $CHECK_WARN ]] && ((warnings++))
|
||||
json_check "env_file" "$( [[ $result -eq 0 ]] && echo "pass" || ([[ $result -eq 1 ]] && echo "warn" || echo "fail") )" ".env file exists" "$first"
|
||||
echo ""
|
||||
|
||||
# Required variables
|
||||
check_required_env "$ENV_FILE"
|
||||
result=$?
|
||||
[[ $result -eq $CHECK_FAIL ]] && ((errors++))
|
||||
[[ $result -eq $CHECK_WARN ]] && ((warnings++))
|
||||
json_check "required_env" "$( [[ $result -eq 0 ]] && echo "pass" || ([[ $result -eq 1 ]] && echo "warn" || echo "fail") )" "Required environment variables" "$first"
|
||||
echo ""
|
||||
|
||||
# Secret strength
|
||||
check_secrets "$ENV_FILE"
|
||||
result=$?
|
||||
[[ $result -eq $CHECK_FAIL ]] && ((errors++))
|
||||
[[ $result -eq $CHECK_WARN ]] && ((warnings++))
|
||||
json_check "secrets" "$( [[ $result -eq 0 ]] && echo "pass" || ([[ $result -eq 1 ]] && echo "warn" || echo "fail") ")" "Secret strength and validity" "$first"
|
||||
echo ""
|
||||
|
||||
# File permissions
|
||||
check_env_permissions "$ENV_FILE"
|
||||
result=$?
|
||||
[[ $result -eq $CHECK_FAIL ]] && ((errors++))
|
||||
[[ $result -eq $CHECK_WARN ]] && ((warnings++))
|
||||
json_check "env_permissions" "$( [[ $result -eq 0 ]] && echo "pass" || ([[ $result -eq 1 ]] && echo "warn" || echo "fail") ")" ".env file permissions" "$first"
|
||||
echo ""
|
||||
|
||||
if [[ "$MODE" == "docker" ]]; then
|
||||
# Docker checks
|
||||
echo -e "${BOLD}━━━ Docker ━━━${NC}"
|
||||
|
||||
check_docker
|
||||
result=$?
|
||||
[[ $result -ne 0 ]] && ((errors++))
|
||||
json_check "docker" "$( [[ $result -eq 0 ]] && echo "pass" || "fail")" "Docker availability" "$first"
|
||||
echo ""
|
||||
|
||||
if [[ $result -eq 0 ]]; then
|
||||
check_docker_compose
|
||||
result=$?
|
||||
[[ $result -ne 0 ]] && ((errors++))
|
||||
json_check "docker_compose" "$( [[ $result -eq 0 ]] && echo "pass" || "fail")" "Docker Compose availability" "$first"
|
||||
echo ""
|
||||
|
||||
# Container status
|
||||
check_docker_containers "$COMPOSE_FILE"
|
||||
result=$?
|
||||
[[ $result -eq $CHECK_FAIL ]] && ((errors++))
|
||||
[[ $result -eq $CHECK_WARN ]] && ((warnings++))
|
||||
json_check "containers" "$( [[ $result -eq 0 ]] && echo "pass" || ([[ $result -eq 1 ]] && echo "warn" || echo "fail") ")" "Container status" "$first"
|
||||
echo ""
|
||||
|
||||
# Container health
|
||||
check_container_health
|
||||
result=$?
|
||||
[[ $result -eq $CHECK_FAIL ]] && ((errors++))
|
||||
[[ $result -eq $CHECK_WARN ]] && ((warnings++))
|
||||
json_check "container_health" "$( [[ $result -eq 0 ]] && echo "pass" || ([[ $result -eq 1 ]] && echo "warn" || echo "fail") ")" "Container health checks" "$first"
|
||||
echo ""
|
||||
|
||||
# Database
|
||||
check_database_connection
|
||||
result=$?
|
||||
[[ $result -eq $CHECK_FAIL ]] && ((errors++))
|
||||
[[ $result -eq $CHECK_WARN ]] && ((warnings++))
|
||||
json_check "database" "$( [[ $result -eq 0 ]] && echo "pass" || ([[ $result -eq 1 ]] && echo "warn" || echo "fail") ")" "Database connectivity" "$first"
|
||||
echo ""
|
||||
|
||||
# Valkey
|
||||
check_valkey_connection
|
||||
result=$?
|
||||
[[ $result -eq $CHECK_FAIL ]] && ((errors++))
|
||||
[[ $result -eq $CHECK_WARN ]] && ((warnings++))
|
||||
json_check "cache" "$( [[ $result -eq 0 ]] && echo "pass" || ([[ $result -eq 1 ]] && echo "warn" || echo "fail") ")" "Valkey/Redis connectivity" "$first"
|
||||
echo ""
|
||||
|
||||
# API
|
||||
check_api_health
|
||||
result=$?
|
||||
[[ $result -eq $CHECK_FAIL ]] && ((errors++))
|
||||
[[ $result -eq $CHECK_WARN ]] && ((warnings++))
|
||||
json_check "api" "$( [[ $result -eq 0 ]] && echo "pass" || ([[ $result -eq 1 ]] && echo "warn" || echo "fail") ")" "API health endpoint" "$first"
|
||||
echo ""
|
||||
|
||||
# Web
|
||||
check_web_health
|
||||
result=$?
|
||||
[[ $result -eq $CHECK_FAIL ]] && ((errors++))
|
||||
[[ $result -eq $CHECK_WARN ]] && ((warnings++))
|
||||
json_check "web" "$( [[ $result -eq 0 ]] && echo "pass" || ([[ $result -eq 1 ]] && echo "warn" || echo "fail") ")" "Web frontend" "$first"
|
||||
echo ""
|
||||
fi
|
||||
else
|
||||
# Native mode checks
|
||||
echo -e "${BOLD}━━━ Native Dependencies ━━━${NC}"
|
||||
|
||||
check_node
|
||||
result=$?
|
||||
[[ $result -ne 0 ]] && ((errors++))
|
||||
json_check "nodejs" "$( [[ $result -eq 0 ]] && echo "pass" || "fail")" "Node.js" "$first"
|
||||
echo ""
|
||||
|
||||
check_pnpm
|
||||
result=$?
|
||||
[[ $result -ne 0 ]] && ((errors++))
|
||||
json_check "pnpm" "$( [[ $result -eq 0 ]] && echo "pass" || "fail")" "pnpm" "$first"
|
||||
echo ""
|
||||
|
||||
check_postgres
|
||||
result=$?
|
||||
[[ $result -ne 0 ]] && ((warnings++))
|
||||
json_check "postgresql" "$( [[ $result -eq 0 ]] && echo "pass" || "warn")" "PostgreSQL" "$first"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
json_end $errors $warnings
|
||||
|
||||
return $([ $errors -eq 0 ] && echo 0 || echo 1)
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Interactive Fix Mode
|
||||
# ============================================================================
|
||||
|
||||
interactive_fix() {
|
||||
local issues=()
|
||||
|
||||
# Collect issues
|
||||
if [[ ! -f "$ENV_FILE" ]]; then
|
||||
issues+=("env_missing:Missing .env file")
|
||||
fi
|
||||
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
# Check permissions
|
||||
local perms
|
||||
perms=$(stat -c "%a" "$ENV_FILE" 2>/dev/null || stat -f "%OLp" "$ENV_FILE" 2>/dev/null)
|
||||
if [[ "$perms" =~ [0-7][0-7][4-7]$ ]]; then
|
||||
issues+=("env_perms:.env is world-readable")
|
||||
fi
|
||||
|
||||
# Check secrets
|
||||
set -a
|
||||
# shellcheck source=/dev/null
|
||||
source "$ENV_FILE" 2>/dev/null || true
|
||||
set +a
|
||||
|
||||
if [[ -z "${JWT_SECRET:-}" ]] || is_placeholder "${JWT_SECRET:-}"; then
|
||||
issues+=("secrets:Missing or invalid secrets")
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$MODE" == "docker" ]]; then
|
||||
if ! docker info &>/dev/null; then
|
||||
local docker_result
|
||||
docker_result=$(docker info 2>&1)
|
||||
if [[ "$docker_result" =~ "permission denied" ]]; then
|
||||
issues+=("docker_perms:Docker permission denied")
|
||||
elif [[ "$docker_result" =~ "Cannot connect to the Docker daemon" ]]; then
|
||||
issues+=("docker_daemon:Docker daemon not running")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${#issues[@]} -eq 0 ]]; then
|
||||
echo -e "${SUCCESS}✓${NC} No fixable issues found"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${BOLD}Found ${#issues[@]} fixable issue(s):${NC}"
|
||||
echo ""
|
||||
|
||||
for issue in "${issues[@]}"; do
|
||||
local code="${issue%%:*}"
|
||||
local desc="${issue#*:}"
|
||||
echo " - $desc"
|
||||
done
|
||||
|
||||
echo ""
|
||||
read -r -p "Fix these issues? [Y/n]: " fix_them
|
||||
case "$fix_them" in
|
||||
n|N)
|
||||
echo -e "${INFO}ℹ${NC} Skipping fixes"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# Apply fixes
|
||||
for issue in "${issues[@]}"; do
|
||||
local code="${issue%%:*}"
|
||||
|
||||
case "$code" in
|
||||
env_perms)
|
||||
fix_env_permissions
|
||||
;;
|
||||
docker_perms)
|
||||
fix_docker_permissions
|
||||
;;
|
||||
docker_daemon)
|
||||
start_docker_daemon
|
||||
;;
|
||||
secrets)
|
||||
generate_missing_secrets
|
||||
;;
|
||||
*)
|
||||
echo -e "${WARN}⚠${NC} Unknown issue: $code"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo -e "${SUCCESS}✓${NC} Fixes applied"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Main
|
||||
# ============================================================================
|
||||
|
||||
main() {
|
||||
parse_arguments "$@"
|
||||
|
||||
# Configure verbose mode
|
||||
if [[ "$VERBOSE" == true ]]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
# Show banner (unless JSON mode)
|
||||
if [[ "$JSON_OUTPUT" != true ]]; then
|
||||
echo ""
|
||||
echo -e "${BOLD}════════════════════════════════════════════════════════════${NC}"
|
||||
echo -e "${BOLD} Mosaic Stack Doctor${NC}"
|
||||
echo -e "${BOLD}════════════════════════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
echo -e " Mode: ${INFO}$MODE${NC}"
|
||||
echo -e " Env: ${INFO}$ENV_FILE${NC}"
|
||||
echo -e " Compose: ${INFO}$COMPOSE_FILE${NC}"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Run checks
|
||||
run_checks
|
||||
local check_result=$?
|
||||
|
||||
# Fix mode
|
||||
if [[ "$FIX_MODE" == true && "$JSON_OUTPUT" != true && $check_result -ne 0 ]]; then
|
||||
echo ""
|
||||
echo -e "${BOLD}━━━ Fix Mode ━━━${NC}"
|
||||
echo ""
|
||||
interactive_fix
|
||||
fi
|
||||
|
||||
# Summary (unless JSON mode)
|
||||
if [[ "$JSON_OUTPUT" != true ]]; then
|
||||
echo ""
|
||||
echo -e "${BOLD}════════════════════════════════════════════════════════════${NC}"
|
||||
|
||||
if [[ $check_result -eq 0 ]]; then
|
||||
echo -e "${SUCCESS}✓ All checks passed${NC}"
|
||||
else
|
||||
echo -e "${WARN}⚠ Some checks failed${NC}"
|
||||
echo ""
|
||||
echo "Run with --fix to attempt automatic repairs"
|
||||
fi
|
||||
|
||||
echo -e "${BOLD}════════════════════════════════════════════════════════════${NC}"
|
||||
fi
|
||||
|
||||
exit $([ $check_result -eq 0 ] && echo 0 || echo 1)
|
||||
}
|
||||
|
||||
# Run
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user