From a792d29eae26ef4945a2feab245e592517e7edeb Mon Sep 17 00:00:00 2001 From: Arvin <62139570+wnlen@users.noreply.github.com> Date: Sat, 21 Mar 2026 16:23:46 +0800 Subject: [PATCH] refactor --- .env | 6 +- clashctl | 12 +- install.sh | 147 ++++++++++++++---- scripts/generate_config.sh | 76 +++++---- {runtime/ui => ui}/200.html | 0 {runtime/ui => ui}/404.html | 0 {runtime/ui => ui}/_nuxt/27QtE9hq.js | 0 {runtime/ui => ui}/_nuxt/4Us7Cdat.js | 0 {runtime/ui => ui}/_nuxt/83RCacat.js | 0 {runtime/ui => ui}/_nuxt/B3GymFtZ.js | 0 {runtime/ui => ui}/_nuxt/B7rlnwkb.js | 0 {runtime/ui => ui}/_nuxt/BE9s5YKM.js | 0 {runtime/ui => ui}/_nuxt/BEg6euoa.js | 0 {runtime/ui => ui}/_nuxt/BEgqDXY5.js | 0 {runtime/ui => ui}/_nuxt/BLICcaEN.js | 0 {runtime/ui => ui}/_nuxt/BO5M1c2D.js | 0 {runtime/ui => ui}/_nuxt/BaY9ddW5.js | 0 {runtime/ui => ui}/_nuxt/C1Z2nZ_q.js | 0 {runtime/ui => ui}/_nuxt/CAimjrE6.js | 0 {runtime/ui => ui}/_nuxt/CDMImveV.js | 0 {runtime/ui => ui}/_nuxt/CGgL16y1.js | 0 {runtime/ui => ui}/_nuxt/CQh-OLya.js | 0 {runtime/ui => ui}/_nuxt/CXTORPKN.js | 0 {runtime/ui => ui}/_nuxt/CcIdf__h.js | 0 {runtime/ui => ui}/_nuxt/CdlJ_YxQ.js | 0 {runtime/ui => ui}/_nuxt/CtJjAUi2.js | 0 {runtime/ui => ui}/_nuxt/D3q0vhlH.js | 0 {runtime/ui => ui}/_nuxt/DAsfgl9S.js | 0 {runtime/ui => ui}/_nuxt/DQAL75xK.js | 0 {runtime/ui => ui}/_nuxt/DUDTy2Jn.js | 0 {runtime/ui => ui}/_nuxt/DahUvDF2.js | 0 {runtime/ui => ui}/_nuxt/Dd0ap0OJ.js | 0 {runtime/ui => ui}/_nuxt/Du-6i27Y.js | 0 {runtime/ui => ui}/_nuxt/KAQ4TgpA.js | 0 .../_nuxt/TwemojiMozilla-flags.B12sb_Bp.woff2 | Bin {runtime/ui => ui}/_nuxt/ZxKQ9y5G.js | 0 {runtime/ui => ui}/_nuxt/_v7-ePgP.js | 0 {runtime/ui => ui}/_nuxt/builds/latest.json | 0 .../6951ff71-94c6-4cf0-ae64-f6eed15cc18d.json | 0 {runtime/ui => ui}/_nuxt/entry.A2e2demF.css | 0 .../ui => ui}/_nuxt/error-404.ajhBH0J0.css | 0 .../ui => ui}/_nuxt/error-500.CkMssXr1.css | 0 {runtime/ui => ui}/_nuxt/mHCEPkxl.js | 0 {runtime/ui => ui}/_nuxt/vESnrIlh.js | 0 {runtime/ui => ui}/_nuxt/z4Bt3ftW.js | 0 .../ui => ui}/apple-touch-icon-180x180.png | Bin {runtime/ui => ui}/config.js | 0 {runtime/ui => ui}/favicon.ico | Bin {runtime/ui => ui}/favicon.svg | 0 {runtime/ui => ui}/index.html | 0 {runtime/ui => ui}/maskable-icon-512x512.png | Bin {runtime/ui => ui}/pwa-192x192.png | Bin {runtime/ui => ui}/pwa-512x512.png | Bin {runtime/ui => ui}/pwa-64x64.png | Bin 54 files changed, 180 insertions(+), 61 deletions(-) rename {runtime/ui => ui}/200.html (100%) rename {runtime/ui => ui}/404.html (100%) rename {runtime/ui => ui}/_nuxt/27QtE9hq.js (100%) rename {runtime/ui => ui}/_nuxt/4Us7Cdat.js (100%) rename {runtime/ui => ui}/_nuxt/83RCacat.js (100%) rename {runtime/ui => ui}/_nuxt/B3GymFtZ.js (100%) rename {runtime/ui => ui}/_nuxt/B7rlnwkb.js (100%) rename {runtime/ui => ui}/_nuxt/BE9s5YKM.js (100%) rename {runtime/ui => ui}/_nuxt/BEg6euoa.js (100%) rename {runtime/ui => ui}/_nuxt/BEgqDXY5.js (100%) rename {runtime/ui => ui}/_nuxt/BLICcaEN.js (100%) rename {runtime/ui => ui}/_nuxt/BO5M1c2D.js (100%) rename {runtime/ui => ui}/_nuxt/BaY9ddW5.js (100%) rename {runtime/ui => ui}/_nuxt/C1Z2nZ_q.js (100%) rename {runtime/ui => ui}/_nuxt/CAimjrE6.js (100%) rename {runtime/ui => ui}/_nuxt/CDMImveV.js (100%) rename {runtime/ui => ui}/_nuxt/CGgL16y1.js (100%) rename {runtime/ui => ui}/_nuxt/CQh-OLya.js (100%) rename {runtime/ui => ui}/_nuxt/CXTORPKN.js (100%) rename {runtime/ui => ui}/_nuxt/CcIdf__h.js (100%) rename {runtime/ui => ui}/_nuxt/CdlJ_YxQ.js (100%) rename {runtime/ui => ui}/_nuxt/CtJjAUi2.js (100%) rename {runtime/ui => ui}/_nuxt/D3q0vhlH.js (100%) rename {runtime/ui => ui}/_nuxt/DAsfgl9S.js (100%) rename {runtime/ui => ui}/_nuxt/DQAL75xK.js (100%) rename {runtime/ui => ui}/_nuxt/DUDTy2Jn.js (100%) rename {runtime/ui => ui}/_nuxt/DahUvDF2.js (100%) rename {runtime/ui => ui}/_nuxt/Dd0ap0OJ.js (100%) rename {runtime/ui => ui}/_nuxt/Du-6i27Y.js (100%) rename {runtime/ui => ui}/_nuxt/KAQ4TgpA.js (100%) rename {runtime/ui => ui}/_nuxt/TwemojiMozilla-flags.B12sb_Bp.woff2 (100%) rename {runtime/ui => ui}/_nuxt/ZxKQ9y5G.js (100%) rename {runtime/ui => ui}/_nuxt/_v7-ePgP.js (100%) rename {runtime/ui => ui}/_nuxt/builds/latest.json (100%) rename {runtime/ui => ui}/_nuxt/builds/meta/6951ff71-94c6-4cf0-ae64-f6eed15cc18d.json (100%) rename {runtime/ui => ui}/_nuxt/entry.A2e2demF.css (100%) rename {runtime/ui => ui}/_nuxt/error-404.ajhBH0J0.css (100%) rename {runtime/ui => ui}/_nuxt/error-500.CkMssXr1.css (100%) rename {runtime/ui => ui}/_nuxt/mHCEPkxl.js (100%) rename {runtime/ui => ui}/_nuxt/vESnrIlh.js (100%) rename {runtime/ui => ui}/_nuxt/z4Bt3ftW.js (100%) rename {runtime/ui => ui}/apple-touch-icon-180x180.png (100%) rename {runtime/ui => ui}/config.js (100%) rename {runtime/ui => ui}/favicon.ico (100%) rename {runtime/ui => ui}/favicon.svg (100%) rename {runtime/ui => ui}/index.html (100%) rename {runtime/ui => ui}/maskable-icon-512x512.png (100%) rename {runtime/ui => ui}/pwa-192x192.png (100%) rename {runtime/ui => ui}/pwa-512x512.png (100%) rename {runtime/ui => ui}/pwa-64x64.png (100%) diff --git a/.env b/.env index ea8bedd..3d82f0d 100644 --- a/.env +++ b/.env @@ -27,7 +27,7 @@ CLASH_AUTO_DOWNLOAD=auto MIHOMO_VERSION=v1.19.21 # 内核自定义下载地址 -CLASH_DOWNLOAD_URL_TEMPLATE='https://github.com/MetaCubeX/mihomo/releases/download/v1.19.21/mihomo-linux-amd64-v1.19.21.gz' +CLASH_DOWNLOAD_URL_TEMPLATE='https://github.com/MetaCubeX/mihomo/releases/download/{version}/mihomo-{arch}-{version}.gz' # 订阅请求头(可选) # 常见机场需要 User-Agent;如不需要可留空 @@ -73,10 +73,10 @@ export CLASH_REDIR_PORT=7892 # ⚠️ 安全建议: # - 服务器自用推荐:127.0.0.1 # - 需要局域网设备使用再改:0.0.0.0 -export CLASH_LISTEN_IP='127.0.0.1' +export CLASH_LISTEN_IP='0.0.0.0' # 是否允许局域网访问(配合 CLASH_LISTEN_IP 使用) -export CLASH_ALLOW_LAN=false +export CLASH_ALLOW_LAN=true # 是否即使 MMDB 下载失败也继续启动 export CLASH_SKIP_GEOIP_TEST_FAILURE="true" diff --git a/clashctl b/clashctl index d77e463..b6b9cef 100755 --- a/clashctl +++ b/clashctl @@ -286,7 +286,7 @@ cmd_ui() { case "$host" in 0.0.0.0|::|localhost) - host="$(hostname -I 2>/dev/null | awk '{print $1}')" + host="$(curl -fsS --max-time 5 ifconfig.me 2>/dev/null || hostname -I 2>/dev/null | awk '{print $1}')" [ -n "${host:-}" ] || host="127.0.0.1" ;; esac @@ -311,7 +311,7 @@ cmd_secret() { if [ ! -s "$RUNTIME_CONFIG" ]; then err "runtime config not found: $RUNTIME_CONFIG" - echo "Please run: clashctl generate" >&2 + echo "Please run install.sh or clashctl generate" >&2 exit 1 fi @@ -330,7 +330,13 @@ cmd_sub() { case "$subcmd" in show) if [ -f "$ENV_FILE" ]; then - grep -E '^[[:space:]]*(export[[:space:]]+)?CLASH_URL=' "$ENV_FILE" || echo "CLASH_URL=未配置" + local current_url + current_url="$(sed -nE "s/^[[:space:]]*(export[[:space:]]+)?CLASH_URL=['\"]?([^'\"]*)['\"]?$/\2/p" "$ENV_FILE" | head -n 1)" + if [ -n "${current_url:-}" ]; then + echo "[1] $current_url" + else + echo "未配置订阅" + fi else err "未找到 .env" exit 1 diff --git a/install.sh b/install.sh index 9e29a1a..08bfd34 100755 --- a/install.sh +++ b/install.sh @@ -31,7 +31,7 @@ chmod +x "$Install_Dir"/scripts/* 2>/dev/null || true chmod +x "$Install_Dir"/bin/* 2>/dev/null || true # ========================= -# 目录初始化(新结构) +# 目录初始化 # ========================= mkdir -p \ "$Install_Dir/runtime" \ @@ -50,6 +50,120 @@ source "$Install_Dir/scripts/get_cpu_arch.sh" # shellcheck disable=SC1090 source "$Install_Dir/scripts/resolve_clash.sh" +write_env_value() { + local key="$1" + local value="$2" + local env_file="$Install_Dir/.env" + local escaped="${value//\\/\\\\}" + escaped="${escaped//&/\\&}" + escaped="${escaped//|/\\|}" + escaped="${escaped//\'/\'\\\'\'}" + + if grep -qE "^[[:space:]]*(export[[:space:]]+)?${key}=" "$env_file"; then + sed -i -E "s|^[[:space:]]*(export[[:space:]]+)?${key}=.*$|export ${key}='${escaped}'|g" "$env_file" + else + printf "export %s='%s'\n" "$key" "$value" >> "$env_file" + fi +} + +read_env_value() { + local key="$1" + sed -nE "s/^[[:space:]]*(export[[:space:]]+)?${key}=['\"]?([^'\"]*)['\"]?$/\2/p" "$Install_Dir/.env" | head -n 1 +} + +get_public_ip() { + curl -fsS --max-time 5 ifconfig.me 2>/dev/null \ + || curl -fsS --max-time 5 ip.sb 2>/dev/null \ + || curl -fsS --max-time 5 api.ipify.org 2>/dev/null \ + || true +} + +show_dashboard_info() { + local secret="$1" + local public_ip="$2" + local dashboard_port="9090" + local ui_url="" + + if [ -n "${public_ip:-}" ]; then + ui_url="http://${public_ip}:${dashboard_port}/ui/#/setup?hostname=${public_ip}&port=${dashboard_port}&secret=${secret}" + else + ui_url="http://127.0.0.1:${dashboard_port}/ui/#/setup?hostname=127.0.0.1&port=${dashboard_port}&secret=${secret}" + fi + + echo + echo "╔═══════════════════════════════════════════════╗" + echo "║ 😼 Web 控制台 ║" + echo "║═══════════════════════════════════════════════║" + echo "║ ║" + echo "║ 🔓 注意放行端口:9090 ║" + if [ -n "${public_ip:-}" ]; then + printf "║ 🌏 公网:http://%-27s║\n" "${public_ip}:9090/ui" + else + printf "║ 🏠 本地:http://%-27s║\n" "127.0.0.1:9090/ui" + fi + echo "║ ║" + echo "╚═══════════════════════════════════════════════╝" + echo + echo "😼 当前密钥:${secret}" + echo "🎯 面板地址:${ui_url}" +} + +wait_dashboard_ready() { + local host="$1" + local port="${2:-9090}" + local max_retry="${3:-20}" + local i + + for ((i=1; i<=max_retry; i++)); do + if curl -fsS --max-time 2 "http://${host}:${port}/ui/" >/dev/null 2>&1; then + return 0 + fi + sleep 1 + done + + return 1 +} + +prompt_and_apply_subscription() { + local sub_url="" + local secret="" + local public_ip="" + + while true; do + echo + read -r -p "✈️ 请输入要添加的订阅链接:" sub_url + + if [ -z "${sub_url:-}" ]; then + echo "❌ 订阅链接不能为空" + continue + fi + + write_env_value "CLASH_URL" "$sub_url" + + echo "⏳ 正在下载订阅..." + echo "🍃 验证订阅配置..." + if ! "$Install_Dir/scripts/generate_config.sh" >/dev/null 2>&1; then + echo "❌ 订阅不可用或转换失败,请检查链接后重试" + continue + fi + + echo "🎉 订阅已添加:[1] $sub_url" + echo "🔥 订阅已生效" + + if command -v systemctl >/dev/null 2>&1; then + systemctl restart "${Service_Name}.service" + else + "$Install_Dir/scripts/run_clash.sh" --daemon + fi + + secret="$(read_env_value "CLASH_SECRET")" + public_ip="$(get_public_ip)" + + show_dashboard_info "$secret" "$public_ip" + return 0 + done +} + # ========================= # 内核检查 # ========================= @@ -107,9 +221,6 @@ chmod 644 /etc/profile.d/clash-for-linux.sh # ========================= # 安装 systemd # ========================= -Service_Enabled="unknown" -Service_Started="unknown" - if command -v systemctl >/dev/null 2>&1; then CLASH_SERVICE_USER="$Service_User" CLASH_SERVICE_GROUP="$Service_Group" \ "$Install_Dir/scripts/install_systemd.sh" "$Install_Dir" @@ -117,43 +228,25 @@ if command -v systemctl >/dev/null 2>&1; then if [ "${CLASH_ENABLE_SERVICE:-true}" = "true" ]; then systemctl enable "${Service_Name}.service" || true fi - - if [ "${CLASH_START_SERVICE:-true}" = "true" ]; then - systemctl start "${Service_Name}.service" || true - fi - - if systemctl is-enabled --quiet "${Service_Name}.service" 2>/dev/null; then - Service_Enabled="enabled" - else - Service_Enabled="disabled" - fi - - if systemctl is-active --quiet "${Service_Name}.service" 2>/dev/null; then - Service_Started="active" - else - Service_Started="inactive" - fi else echo "[WARN] systemd not found, will use script mode" fi # ========================= -# 输出(全部收敛到 clashctl) +# 输出 + 订阅录入 # ========================= echo echo "=== Install Complete ===" echo "Install Dir : $Install_Dir" echo "clashctl : /usr/local/bin/clashctl" -echo -echo "Next:" -echo " clashctl generate" -echo " clashctl start" -echo " clashctl doctor" +prompt_and_apply_subscription echo echo "Commands:" echo " clashctl status" echo " clashctl logs" echo " clashctl restart" -echo " clashctl stop" \ No newline at end of file +echo " clashctl stop" +echo " clashctl ui" +echo " clashctl secret" \ No newline at end of file diff --git a/scripts/generate_config.sh b/scripts/generate_config.sh index b81aa14..dfb9ee6 100644 --- a/scripts/generate_config.sh +++ b/scripts/generate_config.sh @@ -59,6 +59,24 @@ LAST_GENERATE_AT=$(date -Iseconds) EOF } +write_env_value() { + local key="$1" + local value="$2" + local env_file="$PROJECT_DIR/.env" + local escaped="${value//\\/\\\\}" + escaped="${escaped//&/\\&}" + escaped="${escaped//|/\\|}" + escaped="${escaped//\'/\'\\\'\'}" + + [ -f "$env_file" ] || return 1 + + if grep -qE "^[[:space:]]*(export[[:space:]]+)?${key}=" "$env_file"; then + sed -i -E "s|^[[:space:]]*(export[[:space:]]+)?${key}=.*$|export ${key}='${escaped}'|g" "$env_file" + else + printf "export %s='%s'\n" "$key" "$value" >> "$env_file" + fi +} + generate_secret() { if [ -n "${CLASH_SECRET:-}" ]; then echo "$CLASH_SECRET" @@ -75,13 +93,14 @@ generate_secret() { fi if command -v openssl >/dev/null 2>&1; then - openssl rand -hex 16 + openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 16 else - head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n' + tr -dc 'A-Za-z0-9' &2 + exit 1 fi else remove_yaml_key_local "$file" "external-controller" @@ -129,8 +153,14 @@ download_subscription() { local curl_cmd=(curl -fL -S --retry 2 --connect-timeout 10 -m 30 -o "$TMP_DOWNLOAD") [ "$ALLOW_INSECURE_TLS" = "true" ] && curl_cmd+=(-k) - curl_cmd+=("$CLASH_URL") + if [ -n "${CLASH_HEADERS:-}" ]; then + while IFS= read -r header; do + [ -n "$header" ] && curl_cmd+=(-H "$header") + done < <(printf '%s\n' "$CLASH_HEADERS" | tr ';' '\n') + fi + + curl_cmd+=("$CLASH_URL") "${curl_cmd[@]}" } @@ -140,7 +170,7 @@ is_complete_clash_config() { } cleanup_tmp_files() { - rm -f "$TMP_PROXY_FRAGMENT" "$TMP_CONFIG" + rm -f "$TMP_DOWNLOAD" "$TMP_NORMALIZED" "$TMP_PROXY_FRAGMENT" "$TMP_CONFIG" } build_fragment_config() { @@ -164,14 +194,6 @@ finalize_config() { mv -f "$file" "$RUNTIME_CONFIG" } -remove_yaml_key_local() { - local file="$1" - local key="$2" - - [ -f "$file" ] || return 0 - sed -i -E "/^[[:space:]]*${key}:/d" "$file" -} - main() { local template_file="$CONFIG_DIR/template.yaml" @@ -186,13 +208,14 @@ main() { exit 1 fi - if ! download_subscription; then - if [ -s "$RUNTIME_CONFIG" ]; then - write_state "success" "download_failed_keep_runtime" "runtime_existing" - exit 0 - fi + if [ -z "${CLASH_URL:-}" ]; then + echo "[ERROR] CLASH_URL is empty" >&2 + write_state "failed" "url_missing" "none" + exit 1 + fi - echo "[ERROR] failed to download subscription and runtime config missing" >&2 + if ! download_subscription; then + echo "[ERROR] failed to download subscription" >&2 write_state "failed" "download_failed" "none" exit 1 fi @@ -205,14 +228,12 @@ main() { apply_secret_to_config "$TMP_CONFIG" finalize_config "$TMP_CONFIG" write_state "success" "subscription_full" "subscription_full" - cleanup_tmp_files exit 0 fi if [ ! -s "$template_file" ]; then echo "[ERROR] missing template config file: $template_file" >&2 write_state "failed" "missing_template" "none" - cleanup_tmp_files exit 1 fi @@ -222,7 +243,6 @@ main() { finalize_config "$TMP_CONFIG" write_state "success" "subscription_fragment_merged" "subscription_fragment" - cleanup_tmp_files } trap cleanup_tmp_files EXIT diff --git a/runtime/ui/200.html b/ui/200.html similarity index 100% rename from runtime/ui/200.html rename to ui/200.html diff --git a/runtime/ui/404.html b/ui/404.html similarity index 100% rename from runtime/ui/404.html rename to ui/404.html diff --git a/runtime/ui/_nuxt/27QtE9hq.js b/ui/_nuxt/27QtE9hq.js similarity index 100% rename from runtime/ui/_nuxt/27QtE9hq.js rename to ui/_nuxt/27QtE9hq.js diff --git a/runtime/ui/_nuxt/4Us7Cdat.js b/ui/_nuxt/4Us7Cdat.js similarity index 100% rename from runtime/ui/_nuxt/4Us7Cdat.js rename to ui/_nuxt/4Us7Cdat.js diff --git a/runtime/ui/_nuxt/83RCacat.js b/ui/_nuxt/83RCacat.js similarity index 100% rename from runtime/ui/_nuxt/83RCacat.js rename to ui/_nuxt/83RCacat.js diff --git a/runtime/ui/_nuxt/B3GymFtZ.js b/ui/_nuxt/B3GymFtZ.js similarity index 100% rename from runtime/ui/_nuxt/B3GymFtZ.js rename to ui/_nuxt/B3GymFtZ.js diff --git a/runtime/ui/_nuxt/B7rlnwkb.js b/ui/_nuxt/B7rlnwkb.js similarity index 100% rename from runtime/ui/_nuxt/B7rlnwkb.js rename to ui/_nuxt/B7rlnwkb.js diff --git a/runtime/ui/_nuxt/BE9s5YKM.js b/ui/_nuxt/BE9s5YKM.js similarity index 100% rename from runtime/ui/_nuxt/BE9s5YKM.js rename to ui/_nuxt/BE9s5YKM.js diff --git a/runtime/ui/_nuxt/BEg6euoa.js b/ui/_nuxt/BEg6euoa.js similarity index 100% rename from runtime/ui/_nuxt/BEg6euoa.js rename to ui/_nuxt/BEg6euoa.js diff --git a/runtime/ui/_nuxt/BEgqDXY5.js b/ui/_nuxt/BEgqDXY5.js similarity index 100% rename from runtime/ui/_nuxt/BEgqDXY5.js rename to ui/_nuxt/BEgqDXY5.js diff --git a/runtime/ui/_nuxt/BLICcaEN.js b/ui/_nuxt/BLICcaEN.js similarity index 100% rename from runtime/ui/_nuxt/BLICcaEN.js rename to ui/_nuxt/BLICcaEN.js diff --git a/runtime/ui/_nuxt/BO5M1c2D.js b/ui/_nuxt/BO5M1c2D.js similarity index 100% rename from runtime/ui/_nuxt/BO5M1c2D.js rename to ui/_nuxt/BO5M1c2D.js diff --git a/runtime/ui/_nuxt/BaY9ddW5.js b/ui/_nuxt/BaY9ddW5.js similarity index 100% rename from runtime/ui/_nuxt/BaY9ddW5.js rename to ui/_nuxt/BaY9ddW5.js diff --git a/runtime/ui/_nuxt/C1Z2nZ_q.js b/ui/_nuxt/C1Z2nZ_q.js similarity index 100% rename from runtime/ui/_nuxt/C1Z2nZ_q.js rename to ui/_nuxt/C1Z2nZ_q.js diff --git a/runtime/ui/_nuxt/CAimjrE6.js b/ui/_nuxt/CAimjrE6.js similarity index 100% rename from runtime/ui/_nuxt/CAimjrE6.js rename to ui/_nuxt/CAimjrE6.js diff --git a/runtime/ui/_nuxt/CDMImveV.js b/ui/_nuxt/CDMImveV.js similarity index 100% rename from runtime/ui/_nuxt/CDMImveV.js rename to ui/_nuxt/CDMImveV.js diff --git a/runtime/ui/_nuxt/CGgL16y1.js b/ui/_nuxt/CGgL16y1.js similarity index 100% rename from runtime/ui/_nuxt/CGgL16y1.js rename to ui/_nuxt/CGgL16y1.js diff --git a/runtime/ui/_nuxt/CQh-OLya.js b/ui/_nuxt/CQh-OLya.js similarity index 100% rename from runtime/ui/_nuxt/CQh-OLya.js rename to ui/_nuxt/CQh-OLya.js diff --git a/runtime/ui/_nuxt/CXTORPKN.js b/ui/_nuxt/CXTORPKN.js similarity index 100% rename from runtime/ui/_nuxt/CXTORPKN.js rename to ui/_nuxt/CXTORPKN.js diff --git a/runtime/ui/_nuxt/CcIdf__h.js b/ui/_nuxt/CcIdf__h.js similarity index 100% rename from runtime/ui/_nuxt/CcIdf__h.js rename to ui/_nuxt/CcIdf__h.js diff --git a/runtime/ui/_nuxt/CdlJ_YxQ.js b/ui/_nuxt/CdlJ_YxQ.js similarity index 100% rename from runtime/ui/_nuxt/CdlJ_YxQ.js rename to ui/_nuxt/CdlJ_YxQ.js diff --git a/runtime/ui/_nuxt/CtJjAUi2.js b/ui/_nuxt/CtJjAUi2.js similarity index 100% rename from runtime/ui/_nuxt/CtJjAUi2.js rename to ui/_nuxt/CtJjAUi2.js diff --git a/runtime/ui/_nuxt/D3q0vhlH.js b/ui/_nuxt/D3q0vhlH.js similarity index 100% rename from runtime/ui/_nuxt/D3q0vhlH.js rename to ui/_nuxt/D3q0vhlH.js diff --git a/runtime/ui/_nuxt/DAsfgl9S.js b/ui/_nuxt/DAsfgl9S.js similarity index 100% rename from runtime/ui/_nuxt/DAsfgl9S.js rename to ui/_nuxt/DAsfgl9S.js diff --git a/runtime/ui/_nuxt/DQAL75xK.js b/ui/_nuxt/DQAL75xK.js similarity index 100% rename from runtime/ui/_nuxt/DQAL75xK.js rename to ui/_nuxt/DQAL75xK.js diff --git a/runtime/ui/_nuxt/DUDTy2Jn.js b/ui/_nuxt/DUDTy2Jn.js similarity index 100% rename from runtime/ui/_nuxt/DUDTy2Jn.js rename to ui/_nuxt/DUDTy2Jn.js diff --git a/runtime/ui/_nuxt/DahUvDF2.js b/ui/_nuxt/DahUvDF2.js similarity index 100% rename from runtime/ui/_nuxt/DahUvDF2.js rename to ui/_nuxt/DahUvDF2.js diff --git a/runtime/ui/_nuxt/Dd0ap0OJ.js b/ui/_nuxt/Dd0ap0OJ.js similarity index 100% rename from runtime/ui/_nuxt/Dd0ap0OJ.js rename to ui/_nuxt/Dd0ap0OJ.js diff --git a/runtime/ui/_nuxt/Du-6i27Y.js b/ui/_nuxt/Du-6i27Y.js similarity index 100% rename from runtime/ui/_nuxt/Du-6i27Y.js rename to ui/_nuxt/Du-6i27Y.js diff --git a/runtime/ui/_nuxt/KAQ4TgpA.js b/ui/_nuxt/KAQ4TgpA.js similarity index 100% rename from runtime/ui/_nuxt/KAQ4TgpA.js rename to ui/_nuxt/KAQ4TgpA.js diff --git a/runtime/ui/_nuxt/TwemojiMozilla-flags.B12sb_Bp.woff2 b/ui/_nuxt/TwemojiMozilla-flags.B12sb_Bp.woff2 similarity index 100% rename from runtime/ui/_nuxt/TwemojiMozilla-flags.B12sb_Bp.woff2 rename to ui/_nuxt/TwemojiMozilla-flags.B12sb_Bp.woff2 diff --git a/runtime/ui/_nuxt/ZxKQ9y5G.js b/ui/_nuxt/ZxKQ9y5G.js similarity index 100% rename from runtime/ui/_nuxt/ZxKQ9y5G.js rename to ui/_nuxt/ZxKQ9y5G.js diff --git a/runtime/ui/_nuxt/_v7-ePgP.js b/ui/_nuxt/_v7-ePgP.js similarity index 100% rename from runtime/ui/_nuxt/_v7-ePgP.js rename to ui/_nuxt/_v7-ePgP.js diff --git a/runtime/ui/_nuxt/builds/latest.json b/ui/_nuxt/builds/latest.json similarity index 100% rename from runtime/ui/_nuxt/builds/latest.json rename to ui/_nuxt/builds/latest.json diff --git a/runtime/ui/_nuxt/builds/meta/6951ff71-94c6-4cf0-ae64-f6eed15cc18d.json b/ui/_nuxt/builds/meta/6951ff71-94c6-4cf0-ae64-f6eed15cc18d.json similarity index 100% rename from runtime/ui/_nuxt/builds/meta/6951ff71-94c6-4cf0-ae64-f6eed15cc18d.json rename to ui/_nuxt/builds/meta/6951ff71-94c6-4cf0-ae64-f6eed15cc18d.json diff --git a/runtime/ui/_nuxt/entry.A2e2demF.css b/ui/_nuxt/entry.A2e2demF.css similarity index 100% rename from runtime/ui/_nuxt/entry.A2e2demF.css rename to ui/_nuxt/entry.A2e2demF.css diff --git a/runtime/ui/_nuxt/error-404.ajhBH0J0.css b/ui/_nuxt/error-404.ajhBH0J0.css similarity index 100% rename from runtime/ui/_nuxt/error-404.ajhBH0J0.css rename to ui/_nuxt/error-404.ajhBH0J0.css diff --git a/runtime/ui/_nuxt/error-500.CkMssXr1.css b/ui/_nuxt/error-500.CkMssXr1.css similarity index 100% rename from runtime/ui/_nuxt/error-500.CkMssXr1.css rename to ui/_nuxt/error-500.CkMssXr1.css diff --git a/runtime/ui/_nuxt/mHCEPkxl.js b/ui/_nuxt/mHCEPkxl.js similarity index 100% rename from runtime/ui/_nuxt/mHCEPkxl.js rename to ui/_nuxt/mHCEPkxl.js diff --git a/runtime/ui/_nuxt/vESnrIlh.js b/ui/_nuxt/vESnrIlh.js similarity index 100% rename from runtime/ui/_nuxt/vESnrIlh.js rename to ui/_nuxt/vESnrIlh.js diff --git a/runtime/ui/_nuxt/z4Bt3ftW.js b/ui/_nuxt/z4Bt3ftW.js similarity index 100% rename from runtime/ui/_nuxt/z4Bt3ftW.js rename to ui/_nuxt/z4Bt3ftW.js diff --git a/runtime/ui/apple-touch-icon-180x180.png b/ui/apple-touch-icon-180x180.png similarity index 100% rename from runtime/ui/apple-touch-icon-180x180.png rename to ui/apple-touch-icon-180x180.png diff --git a/runtime/ui/config.js b/ui/config.js similarity index 100% rename from runtime/ui/config.js rename to ui/config.js diff --git a/runtime/ui/favicon.ico b/ui/favicon.ico similarity index 100% rename from runtime/ui/favicon.ico rename to ui/favicon.ico diff --git a/runtime/ui/favicon.svg b/ui/favicon.svg similarity index 100% rename from runtime/ui/favicon.svg rename to ui/favicon.svg diff --git a/runtime/ui/index.html b/ui/index.html similarity index 100% rename from runtime/ui/index.html rename to ui/index.html diff --git a/runtime/ui/maskable-icon-512x512.png b/ui/maskable-icon-512x512.png similarity index 100% rename from runtime/ui/maskable-icon-512x512.png rename to ui/maskable-icon-512x512.png diff --git a/runtime/ui/pwa-192x192.png b/ui/pwa-192x192.png similarity index 100% rename from runtime/ui/pwa-192x192.png rename to ui/pwa-192x192.png diff --git a/runtime/ui/pwa-512x512.png b/ui/pwa-512x512.png similarity index 100% rename from runtime/ui/pwa-512x512.png rename to ui/pwa-512x512.png diff --git a/runtime/ui/pwa-64x64.png b/ui/pwa-64x64.png similarity index 100% rename from runtime/ui/pwa-64x64.png rename to ui/pwa-64x64.png