#!/bin/bash
# Husky CLI
# Usage:
#   husky --version                              Print Husky CLI version
#   husky init                                   Initialize ~/.husky runtime files
#   husky serve                                  Start the Husky service (foreground)
#   husky tui                                    Connect the TUI to a running service
#   husky tui --server ws://host:port/api/tui    Connect to a remote service
#   husky tui --port 18089                       Connect to localhost:18089
#   husky dev                                    Start service + TUI together
#   husky start                                  Start the service in background
#   husky stop                                   Stop the background service
#   husky status                                 Show background service status
#   husky logs                                   Tail background service logs
#   husky update                                 Upgrade this checkout via install.sh --upgrade
#   husky browser install                         Install Playwright Chromium for browser tools
#   husky install                                Create a symlink in /usr/local/bin for global access

set -e

# Resolve script location (handle symlinks and relative paths)
SOURCE="$0"
while [ -L "$SOURCE" ]; do
    DIR="$(cd "$(dirname "$SOURCE")" && pwd)"
    SOURCE="$(readlink "$SOURCE")"
    [[ "$SOURCE" != /* ]] && SOURCE="$DIR/$SOURCE"
done
SCRIPT_DIR="$(cd "$(dirname "$SOURCE")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
CLI_SCRIPT="$SCRIPT_DIR/husky"
INITIAL_COMMAND="${1:-serve}"

read_version() {
    if [ -f "$PROJECT_DIR/VERSION" ]; then
        tr -d '[:space:]' < "$PROJECT_DIR/VERSION"
        return 0
    fi

    perl -0ne 'if (s|<parent>.*?</parent>||s && m|<project[^>]*>.*?<version>([^<]+)</version>|s) { print $1 }' "$PROJECT_DIR/pom.xml" 2>/dev/null
}

VERSION="$(read_version || true)"
if [ -z "$VERSION" ]; then
    VERSION="unknown"
fi

# Load .env (user config first, then repo-local fallback)
load_env() {
    if [ "$INITIAL_COMMAND" = "init" ]; then
        if [ -f "$HOME/.husky/.env" ]; then
            LOADED_ENV_FILE="$HOME/.husky/.env"
            set -a
            # shellcheck disable=SC1090
            source "$HOME/.husky/.env"
            set +a
            return 0
        fi
        return 1
    fi

    for env_file in "$HOME/.husky/.env" "$PROJECT_DIR/.env"; do
        if [ -f "$env_file" ]; then
            LOADED_ENV_FILE="$env_file"
            set -a
            # shellcheck disable=SC1090
            source "$env_file"
            set +a
            return 0
        fi
    done
    return 1
}
load_env || true

resolve_absolute_path() {
    local path_value="$1"
    local base_dir="$2"

    case "$path_value" in
        "~")
            printf '%s\n' "$HOME"
            ;;
        "~/"*)
            printf '%s\n' "$HOME/${path_value#~/}"
            ;;
        /*)
            printf '%s\n' "$path_value"
            ;;
        *)
            printf '%s/%s\n' "${base_dir%/}" "$path_value"
            ;;
    esac
}

ENV_BASE_DIR="$PROJECT_DIR"
if [ -n "${LOADED_ENV_FILE:-}" ]; then
    ENV_BASE_DIR="$(cd "$(dirname "$LOADED_ENV_FILE")" && pwd)"
fi

DATA_DIR="$(resolve_absolute_path "${HUSKY_DATA_DIR:-$HOME/.husky}" "$ENV_BASE_DIR")"
PID_FILE="$DATA_DIR/husky.pid"
LOG_FILE="$DATA_DIR/logs/husky-serve.log"
HEALTH_PORT="${HUSKY_PORT:-18088}"
HEALTH_URL="http://localhost:${HEALTH_PORT}/actuator/health"
MEMORY_DIR="$DATA_DIR/memory"
ENV_FILE="$(resolve_absolute_path "${HUSKY_ENV_FILE:-$DATA_DIR/.env}" "$ENV_BASE_DIR")"
CONFIG_FILE="$(resolve_absolute_path "${HUSKY_CONFIG_FILE:-$DATA_DIR/config/application.yml}" "$ENV_BASE_DIR")"
SPRING_CONFIG_ARG="--spring.config.additional-location=optional:file:${CONFIG_FILE}"

ensure_runtime_dirs() {
    mkdir -p "$DATA_DIR/config" "$DATA_DIR/skills" "$DATA_DIR/db" "$DATA_DIR/logs" "$MEMORY_DIR"
    touch "$MEMORY_DIR/MEMORY.md" "$MEMORY_DIR/USER.md"
}

initialize_env_file() {
    if [ -f "$ENV_FILE" ]; then
        return 0
    fi

    if [ -f "$PROJECT_DIR/.env.example" ]; then
        cp "$PROJECT_DIR/.env.example" "$ENV_FILE"
    else
        cat > "$ENV_FILE" <<EOF
OPENAI_API_KEY=
OPENAI_BASE_URL=https://api.openai.com
OPENAI_MODEL=gpt-5.4
OPENAI_COMPLETIONS_PATH=/v1/chat/completions
OPENAI_TEMPERATURE=0.7
HUSKY_PORT=${HEALTH_PORT}
HUSKY_DATA_DIR=${DATA_DIR}
AUTH_ENABLED=true
HUSKY_API_KEYS=change-me-generate-a-random-key
BROWSER_ENABLED=false
MCP_ENABLED=false
MCP_CONFIG_PATH=${DATA_DIR}/config/mcp-servers.json
EOF
    fi

    if grep -q '^OPENAI_MODEL=' "$ENV_FILE"; then
        perl -0pi -e 's|^OPENAI_MODEL=.*$|OPENAI_MODEL=gpt-5.4|m' "$ENV_FILE"
    else
        printf '\nOPENAI_MODEL=gpt-5.4\n' >> "$ENV_FILE"
    fi

    if grep -q '^HUSKY_DATA_DIR=' "$ENV_FILE"; then
        perl -0pi -e 's|^HUSKY_DATA_DIR=.*$|HUSKY_DATA_DIR='"$DATA_DIR"'|m' "$ENV_FILE"
    else
        printf '\nHUSKY_DATA_DIR=%s\n' "$DATA_DIR" >> "$ENV_FILE"
    fi

    if grep -q '^MCP_CONFIG_PATH=' "$ENV_FILE"; then
        perl -0pi -e 's|^MCP_CONFIG_PATH=.*$|MCP_CONFIG_PATH='"$DATA_DIR"'/config/mcp-servers.json|m' "$ENV_FILE"
    else
        printf 'MCP_CONFIG_PATH=%s/config/mcp-servers.json\n' "$DATA_DIR" >> "$ENV_FILE"
    fi
}

initialize_config_file() {
    if [ -f "$CONFIG_FILE" ]; then
        return 0
    fi

    cat > "$CONFIG_FILE" <<'EOF'
# Husky runtime configuration.
# This file overrides the defaults packaged inside the application jar.

agent-channel-bindings:
  assistant:
    - feishu:assistant-bot
    - feishu:qa-bot
    - telegram:assistant-bot
    - slack:assistant-bot
    - tui:local
  chatbot:
    - http:chatbot

channels:
  feishu:
    instances:
      assistant-bot:
        enabled: ${FEISHU_ASSISTANT_ENABLED:false}
        transport: ${FEISHU_ASSISTANT_TRANSPORT:websocket}
        app-id: ${FEISHU_ASSISTANT_APP_ID:}
        app-secret: ${FEISHU_ASSISTANT_APP_SECRET:}
        verification-token: ${FEISHU_ASSISTANT_VERIFICATION_TOKEN:}
        encrypt-key: ${FEISHU_ASSISTANT_ENCRYPT_KEY:}
        bot-open-id: ${FEISHU_ASSISTANT_BOT_OPEN_ID:}
        mention-required-in-group: ${FEISHU_ASSISTANT_MENTION_REQUIRED_IN_GROUP:true}
        group-session-scope: ${FEISHU_ASSISTANT_GROUP_SESSION_SCOPE:THREAD}
        show-tool-calls: ${FEISHU_ASSISTANT_SHOW_TOOL_CALLS:true}
        approval-timeout-seconds: ${FEISHU_ASSISTANT_APPROVAL_TIMEOUT_SECONDS:300}

      qa-bot:
        enabled: ${FEISHU_QA_ENABLED:false}
        transport: ${FEISHU_QA_TRANSPORT:websocket}
        app-id: ${FEISHU_QA_APP_ID:}
        app-secret: ${FEISHU_QA_APP_SECRET:}
        verification-token: ${FEISHU_QA_VERIFICATION_TOKEN:}
        encrypt-key: ${FEISHU_QA_ENCRYPT_KEY:}
        bot-open-id: ${FEISHU_QA_BOT_OPEN_ID:}
        mention-required-in-group: ${FEISHU_QA_MENTION_REQUIRED_IN_GROUP:true}
        group-session-scope: ${FEISHU_QA_GROUP_SESSION_SCOPE:THREAD}
        show-tool-calls: ${FEISHU_QA_SHOW_TOOL_CALLS:true}
        approval-timeout-seconds: ${FEISHU_QA_APPROVAL_TIMEOUT_SECONDS:300}

  telegram:
    instances:
      assistant-bot:
        enabled: ${TELEGRAM_ASSISTANT_ENABLED:false}
        token: ${TELEGRAM_ASSISTANT_BOT_TOKEN:}
        bot-username: ${TELEGRAM_ASSISTANT_BOT_USERNAME:}
        mention-required-in-group: ${TELEGRAM_ASSISTANT_MENTION_REQUIRED_IN_GROUP:true}
        group-session-scope: ${TELEGRAM_ASSISTANT_GROUP_SESSION_SCOPE:THREAD}
        show-tool-calls: ${TELEGRAM_ASSISTANT_SHOW_TOOL_CALLS:true}
        approval-timeout-seconds: ${TELEGRAM_ASSISTANT_APPROVAL_TIMEOUT_SECONDS:300}
        long-polling-timeout-seconds: ${TELEGRAM_ASSISTANT_LONG_POLLING_TIMEOUT_SECONDS:50}

  slack:
    instances:
      assistant-bot:
        enabled: ${SLACK_ASSISTANT_ENABLED:false}
        bot-token: ${SLACK_ASSISTANT_BOT_TOKEN:}
        app-token: ${SLACK_ASSISTANT_APP_TOKEN:}
        bot-user-id: ${SLACK_ASSISTANT_BOT_USER_ID:}
        bot-name: ${SLACK_ASSISTANT_BOT_NAME:}
        team-id: ${SLACK_ASSISTANT_TEAM_ID:}
        mention-required-in-channel: ${SLACK_ASSISTANT_MENTION_REQUIRED_IN_CHANNEL:true}
        group-session-scope: ${SLACK_ASSISTANT_GROUP_SESSION_SCOPE:THREAD}
        show-tool-calls: ${SLACK_ASSISTANT_SHOW_TOOL_CALLS:true}
        approval-timeout-seconds: ${SLACK_ASSISTANT_APPROVAL_TIMEOUT_SECONDS:300}
        send-typing-status: ${SLACK_ASSISTANT_SEND_TYPING_STATUS:false}
        reply-broadcast: ${SLACK_ASSISTANT_REPLY_BROADCAST:false}

agents:
  assistant:
    system-prompt: ""
    toolsets: []
    denied-tools: []
    knowledge-sources: []
    allowed-mcp-servers: []
    denied-mcp-servers: []
    approval: required
    backend: local
    working-dir: inherit
    memory:
      scope: session
    prompt-files: []
    prompt-file-policy: override
    audit-enabled: true
    audit-tags: []
    rate-limit-enabled: false

  chatbot:
    system-prompt: |
      You are Husky, an intelligent AI assistant.
      You can use the following tools to help users: web_search for internet search and web_fetch for webpage retrieval.
      Current time: {{currentDateTime}}
    toolsets:
      - CORE
      - SKILLS
      - SEARCH
      - WEB
      - KNOWLEDGE
      - MCP
    allowed-tools: []
    knowledge-sources: []
    denied-tools:
      - read_file
      - write_file
      - edit_file
      - delete_file
      - move_file
      - apply_patch
      - search_files
      - list_files
      - terminal
      - process
      - skill_search
      - skill_install
      - skill_manage
    approval: none
    backend: local
    working-dir: inherit
    memory:
      scope: session
    prompt-files: []
    prompt-file-policy: append
    audit-enabled: true
    audit-tags:
      - chatbot
    rate-limit-enabled: false
EOF
}

print_version() {
    echo "husky $VERSION"
}

run_init() {
    ensure_runtime_dirs
    initialize_env_file
    initialize_config_file
    echo "Initialized Husky runtime files"
    echo "  Data directory: $DATA_DIR"
    echo "  Env file: $ENV_FILE"
    echo "  Runtime config: $CONFIG_FILE"
    echo "  Memory files: $MEMORY_DIR/MEMORY.md, $MEMORY_DIR/USER.md"
    echo ""
    echo "Next steps:"
    echo "  1. Edit $ENV_FILE and set OPENAI_API_KEY at minimum"
    echo "  2. Edit $CONFIG_FILE for agents, channels, and agent-channel-bindings"
    echo "  3. Choose one startup mode: foreground with husky serve"
    echo "  4. Or background with husky start"
    echo "  5. If you use background mode, check status/logs with: husky status && husky logs"
    echo "  6. Optional browser tools: set BROWSER_ENABLED=true, then run husky browser install"
}

service_installed() {
    [ -f /etc/systemd/system/husky-agent.service ]
}

read_pid_file() {
    if [ -f "$PID_FILE" ]; then
        tr -d '[:space:]' < "$PID_FILE"
    fi
}

pid_is_running() {
    local pid="$1"
    [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null
}

clear_stale_pid_file() {
    local pid
    pid="$(read_pid_file)"
    if [ -n "$pid" ] && ! pid_is_running "$pid"; then
        rm -f "$PID_FILE"
    fi
}

background_status() {
    clear_stale_pid_file
    local pid
    pid="$(read_pid_file)"
    if pid_is_running "$pid"; then
        echo "$pid"
        return 0
    fi
    return 1
}

print_systemd_hint() {
    if service_installed; then
        echo "Tip: systemd remains the recommended long-running Linux deployment path."
        echo "     sudo systemctl start husky-agent"
        echo "     sudo systemctl status husky-agent"
        echo "     journalctl -u husky-agent -f"
    fi
}

print_runtime_summary() {
    echo ""
    echo "Husky runtime paths:"
    echo "  Code directory : $PROJECT_DIR"
    echo "  Data directory : $DATA_DIR"
    echo "  Env file       : $ENV_FILE"
    echo "  Runtime config : $CONFIG_FILE"
    echo "  Memory dir     : $MEMORY_DIR"
    if service_installed; then
        echo "  systemd        : /etc/systemd/system/husky-agent.service"
    else
        echo "  systemd        : not installed"
    fi
}

# Helper: wait for service to be ready
wait_for_service() {
    local url="${1:-$HEALTH_URL}"
    local max_wait="${2:-30}"
    local elapsed=0
    echo "  Waiting for service readiness..."
    while [ "$elapsed" -lt "$max_wait" ]; do
        if curl -sf "$url" > /dev/null 2>&1; then
            echo "  Service is ready"
            return 0
        fi
        sleep 1
        elapsed=$((elapsed + 1))
    done
    echo "  Service was not ready within ${max_wait}s; trying to connect..."
    return 1
}

find_packaged_jar() {
    local module_dir="$1"
    local artifact_id="$2"
    local candidate
    local newest=""

    for candidate in "$PROJECT_DIR/$module_dir/target/$artifact_id.jar" "$PROJECT_DIR/target/$artifact_id.jar"; do
        if [ -f "$candidate" ]; then
            printf '%s\n' "$candidate"
            return 0
        fi
    done

    for candidate in "$PROJECT_DIR/$module_dir"/target/"$artifact_id"-*.jar "$PROJECT_DIR"/target/"$artifact_id"-*.jar; do
        [ -f "$candidate" ] || continue
        case "$candidate" in
            *-sources.jar|*-javadoc.jar|*.original) continue ;;
        esac
        if [ -z "$newest" ] || [ "$candidate" -nt "$newest" ]; then
            newest="$candidate"
        fi
    done

    if [ -n "$newest" ]; then
        printf '%s\n' "$newest"
    fi
}

# Find the Husky JARs
JAR="$(find_packaged_jar service husky-agent-service || true)"
CLIENT_JAR="$(find_packaged_jar client husky-agent-client || true)"

MVNW="$PROJECT_DIR/mvnw"
if [ ! -f "$MVNW" ]; then
    MVNW=""
fi

run_browser_install() {
    echo "Installing Playwright Chromium for Husky browser tools..."
    if [ -n "$MVNW" ]; then
        exec "$MVNW" -B -ntp exec:java -pl infra \
            -Dexec.mainClass="com.microsoft.playwright.CLI" \
            -Dexec.args="install chromium"
    fi
    if [ -n "$JAR" ]; then
        exec java -cp "$JAR" com.microsoft.playwright.CLI install chromium
    fi
    echo "Error: Cannot find Husky JAR or mvnw to run Playwright installer"
    exit 1
}

case "${1:-serve}" in
    --version|-v|version)
        print_version
        ;;
    init)
        shift
        run_init
        ;;
    serve)
        ensure_runtime_dirs
        initialize_config_file
        if [ -n "$JAR" ]; then
            exec java -jar "$JAR" "$SPRING_CONFIG_ARG" "${@:2}"
        elif [ -n "$MVNW" ]; then
            exec "$MVNW" spring-boot:run -pl service -Dspring-boot.run.arguments="$SPRING_CONFIG_ARG"
        else
            echo "Error: Cannot find Husky JAR or mvnw"
            exit 1
        fi
        ;;
    tui)
        shift
        SERVER_URL="ws://localhost:18088/api/tui"

        while [[ $# -gt 0 ]]; do
            case $1 in
                --server)
                    SERVER_URL="$2"
                    shift 2
                    ;;
                --port)
                    SERVER_URL="ws://localhost:$2/api/tui"
                    shift 2
                    ;;
                *)
                    shift
                    ;;
            esac
        done

        if [ -n "$CLIENT_JAR" ]; then
            exec java -jar "$CLIENT_JAR" --server "$SERVER_URL"
        elif [ -n "$MVNW" ]; then
            exec "$MVNW" exec:java -pl client \
                -Dexec.mainClass="io.github.huskyagent.tui.AgentTUI" \
                -Dexec.args="--server $SERVER_URL"
        else
            echo "Error: Cannot find Husky client JAR or mvnw"
            exit 1
        fi
        ;;
    dev)
        shift
        SERVER_PORT="18088"
        SERVER_URL="ws://localhost:${SERVER_PORT}/api/tui"

        while [[ $# -gt 0 ]]; do
            case $1 in
                --server)
                    SERVER_URL="$2"
                    shift 2
                    ;;
                --port)
                    SERVER_PORT="$2"
                    SERVER_URL="ws://localhost:${SERVER_PORT}/api/tui"
                    shift 2
                    ;;
                *)
                    shift
                    ;;
            esac
        done

        echo "Starting Husky service..."
        ensure_runtime_dirs
        initialize_config_file
        if [ -n "$JAR" ]; then
            java -jar "$JAR" "$SPRING_CONFIG_ARG" --server.port="$SERVER_PORT" &
        elif [ -n "$MVNW" ]; then
            "$MVNW" spring-boot:run -pl service -Dspring-boot.run.arguments="$SPRING_CONFIG_ARG --server.port=$SERVER_PORT" &
        else
            echo "Error: Cannot find Husky JAR or mvnw"
            exit 1
        fi
        SERVICE_PID=$!
        wait_for_service "http://localhost:${SERVER_PORT}/actuator/health" 30

        echo "Connecting TUI..."
        if [ -n "$CLIENT_JAR" ]; then
            exec java -jar "$CLIENT_JAR" --server "$SERVER_URL"
        elif [ -n "$MVNW" ]; then
            exec "$MVNW" exec:java -pl client \
                -Dexec.mainClass="io.github.huskyagent.tui.AgentTUI" \
                -Dexec.args="--server $SERVER_URL"
        else
            echo "Error: Cannot find Husky client JAR or mvnw"
            kill "$SERVICE_PID" 2>/dev/null
            exit 1
        fi
        ;;
    start)
        shift
        ensure_runtime_dirs

        if pid="$(background_status)"; then
            echo "Husky is already running in background with PID $pid"
            echo "Log file: $LOG_FILE"
            print_systemd_hint
            exit 0
        fi

        echo "Starting Husky in background..."
        nohup "$CLI_SCRIPT" serve "$@" > "$LOG_FILE" 2>&1 &
        pid=$!
        echo "$pid" > "$PID_FILE"

        if wait_for_service "$HEALTH_URL" 30; then
            echo "Husky started in background with PID $pid"
        elif pid_is_running "$pid"; then
            echo "Husky started in background with PID $pid, but readiness is still pending"
            echo "Check logs with: husky logs"
        else
            echo "Husky failed to stay running; showing recent logs"
            rm -f "$PID_FILE"
            if [ -f "$LOG_FILE" ]; then
                tail -20 "$LOG_FILE"
            fi
            exit 1
        fi

        echo "PID file: $PID_FILE"
        echo "Log file: $LOG_FILE"
        print_systemd_hint
        ;;
    stop)
        shift
        if pid="$(background_status)"; then
            echo "Stopping Husky background process $pid..."
            kill "$pid"
            for _ in $(seq 1 20); do
                if ! pid_is_running "$pid"; then
                    rm -f "$PID_FILE"
                    echo "Husky background process stopped"
                    exit 0
                fi
                sleep 1
            done
            echo "Husky process $pid did not exit within 20s"
            exit 1
        fi

        echo "No Husky background process is tracked at $PID_FILE"
        print_systemd_hint
        ;;
    status)
        shift
        if pid="$(background_status)"; then
            echo "Husky background process is running"
            echo "  PID file: $PID_FILE"
            echo "  PID: $pid"
            echo "  Log file: $LOG_FILE"
        else
            echo "Husky background process is not running"
            echo "  PID file: $PID_FILE"
            echo "  Log file: $LOG_FILE"
        fi

        if service_installed && command -v systemctl >/dev/null 2>&1; then
            if systemctl is-active --quiet husky-agent; then
                echo "  systemd: husky-agent is active"
            else
                echo "  systemd: husky-agent is not active"
            fi
        fi
        ;;
    logs)
        shift
        if [ -f "$LOG_FILE" ]; then
            echo "Tailing $LOG_FILE"
            exec tail -f "$LOG_FILE"
        fi

        echo "No background log file found at $LOG_FILE"
        print_systemd_hint
        exit 1
        ;;
    browser)
        shift
        case "${1:-}" in
            install)
                shift
                run_browser_install "$@"
                ;;
            *)
                echo "Usage: husky browser install"
                exit 1
                ;;
        esac
        ;;
    update)
        shift
        if [ ! -d "$PROJECT_DIR/.git" ]; then
            echo "Error: husky update requires a git checkout at $PROJECT_DIR"
            exit 1
        fi
        if [ ! -f "$PROJECT_DIR/install.sh" ]; then
            echo "Error: Cannot find install.sh in $PROJECT_DIR"
            exit 1
        fi
        dirty_status="$(git -C "$PROJECT_DIR" status --porcelain --untracked-files=all | grep -v '^?? build.log$' || true)"
        if [ -n "$dirty_status" ]; then
            echo "Error: Working tree is not clean. Commit, stash, or discard local changes before running husky update."
            echo "$dirty_status"
            exit 1
        fi

        bash "$PROJECT_DIR/install.sh" --upgrade "$@"
        print_runtime_summary
        ;;
    install)
        TARGET="/usr/local/bin/husky"
        if [ -L "$TARGET" ]; then
            existing="$(readlink "$TARGET")"
            if [ "$existing" = "$SCRIPT_DIR/husky" ]; then
                echo "Already installed: $TARGET -> $SCRIPT_DIR/husky"
            else
                echo "$TARGET exists (-> $existing), updating..."
                sudo ln -sf "$SCRIPT_DIR/husky" "$TARGET"
                echo "Updated: $TARGET -> $SCRIPT_DIR/husky"
            fi
        elif [ -e "$TARGET" ]; then
            echo "$TARGET exists and is not a symlink. Remove it first or choose another path."
            exit 1
        else
            sudo ln -s "$SCRIPT_DIR/husky" "$TARGET"
            echo "Installed: $TARGET -> $SCRIPT_DIR/husky"
        fi
        echo ""
        echo "Now you can run 'husky serve' or 'husky tui' from anywhere."
        ;;
    *)
        echo "Usage: husky {init|serve|tui|dev|start|stop|status|logs|update|browser|install|--version}"
        echo ""
        echo "Start here:"
        echo "  husky init                  Create ~/.husky config and runtime directories"
        echo "  husky serve                 Start the service in the current terminal"
        echo "  husky tui                   Open the TUI and connect to localhost"
        echo "  husky start                 Start the service in background"
        echo "  husky status                Check background service status"
        echo "  husky browser install       Install Playwright Chromium for browser tools"
        echo ""
        echo "Commands:"
        echo "  init     Initialize ~/.husky config and runtime files"
        echo "  serve    Start the Husky service (HTTP + WebSocket)"
        echo "  tui      Connect the TUI to a running service"
        echo "  dev      Start service + TUI in one command"
        echo "  start    Start the service in background with nohup"
        echo "  stop     Stop the background service"
        echo "  status   Show background service status"
        echo "  logs     Tail background service logs"
        echo "  update   Run the recommended local upgrade path"
        echo "  browser install  Install Playwright Chromium for browser tools"
        echo "  install  Create a symlink in /usr/local/bin for global access"
        echo "  --version  Print Husky CLI version"
        echo ""
        echo "TUI options:"
        echo "  --server URL   WebSocket URL (default: ws://localhost:18088/api/tui)"
        echo "  --port PORT    Shortcut for ws://localhost:PORT/api/tui"
        echo ""
        print_systemd_hint
        exit 1
        ;;
esac
