From 83762a8bbeef0e3d5d778a9d09b8e0ea176ed678 Mon Sep 17 00:00:00 2001 From: cotore-game <102813037+cotore-game@users.noreply.github.com> Date: Sun, 9 Aug 2026 01:55:03 +0900 Subject: [PATCH 1/3] feat: add interactive home dashboard --- .github/workflows/release.yml | 5 +- .github/workflows/shell-tests.yml | 4 +- home-tui.sh | 256 ++++++++++++++++++++++++++++++ install.sh | 1 + locales/en.json | 34 +++- locales/ja.json | 34 +++- mcserver-kit | 19 ++- tests/run-tests.sh | 31 ++++ 8 files changed, 376 insertions(+), 8 deletions(-) create mode 100644 home-tui.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 67fae36..37a49f8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,10 +22,10 @@ jobs: - name: Run checks run: | - bash -n mcserver-kit new-minecraft-server.sh setup.sh reset.sh config-tui.sh server-manager.sh server-properties-tui.sh lang.sh install.sh uninstall.sh tests/run-tests.sh + bash -n mcserver-kit home-tui.sh new-minecraft-server.sh setup.sh reset.sh config-tui.sh server-manager.sh server-properties-tui.sh lang.sh install.sh uninstall.sh tests/run-tests.sh python3 -m py_compile scripts/config-value.py scripts/detect-world-version.py scripts/server-config.py scripts/validate-locales.py python3 scripts/validate-locales.py - shellcheck -x mcserver-kit new-minecraft-server.sh setup.sh reset.sh config-tui.sh server-manager.sh server-properties-tui.sh lang.sh install.sh uninstall.sh tests/run-tests.sh + shellcheck -x mcserver-kit home-tui.sh new-minecraft-server.sh setup.sh reset.sh config-tui.sh server-manager.sh server-properties-tui.sh lang.sh install.sh uninstall.sh tests/run-tests.sh bash tests/run-tests.sh - name: Build release archive @@ -34,6 +34,7 @@ jobs: cp -a \ new-minecraft-server.sh \ mcserver-kit \ + home-tui.sh \ setup.sh \ reset.sh \ config-tui.sh \ diff --git a/.github/workflows/shell-tests.yml b/.github/workflows/shell-tests.yml index 509d9d7..ae90859 100644 --- a/.github/workflows/shell-tests.yml +++ b/.github/workflows/shell-tests.yml @@ -24,7 +24,7 @@ jobs: run: sudo apt-get update && sudo apt-get install --yes shellcheck zip unzip - name: Check Bash syntax - run: bash -n mcserver-kit new-minecraft-server.sh setup.sh reset.sh config-tui.sh server-manager.sh server-properties-tui.sh lang.sh install.sh uninstall.sh tests/run-tests.sh + run: bash -n mcserver-kit home-tui.sh new-minecraft-server.sh setup.sh reset.sh config-tui.sh server-manager.sh server-properties-tui.sh lang.sh install.sh uninstall.sh tests/run-tests.sh - name: Check Python syntax run: python3 -m py_compile scripts/config-value.py scripts/detect-world-version.py scripts/server-config.py scripts/validate-locales.py @@ -33,7 +33,7 @@ jobs: run: python3 scripts/validate-locales.py - name: Run ShellCheck - run: shellcheck -x mcserver-kit new-minecraft-server.sh setup.sh reset.sh config-tui.sh server-manager.sh server-properties-tui.sh lang.sh install.sh uninstall.sh tests/run-tests.sh + run: shellcheck -x mcserver-kit home-tui.sh new-minecraft-server.sh setup.sh reset.sh config-tui.sh server-manager.sh server-properties-tui.sh lang.sh install.sh uninstall.sh tests/run-tests.sh - name: Run specification tests run: bash tests/run-tests.sh diff --git a/home-tui.sh b/home-tui.sh new file mode 100644 index 0000000..c40c768 --- /dev/null +++ b/home-tui.sh @@ -0,0 +1,256 @@ +#!/usr/bin/env bash +# `tr` is the repository translation helper, and load_messages takes no CLI args. +# shellcheck disable=SC2020,SC2119 +set -Eeuo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_FILE="${MCSERVER_KIT_CONFIG:-${HOME}/.config/mcserver-compose-kit/config.yml}" +CONFIG_VALUE="${SCRIPT_DIR}/scripts/config-value.py" +TEMP_FILES=() + +# shellcheck source=scripts/i18n.sh +source "${SCRIPT_DIR}/scripts/i18n.sh" +load_messages + +if [[ -z "${NEWT_COLORS:-}" ]]; then + export NEWT_COLORS="${MCSERVER_KIT_TUI_COLORS:- +root=white,black +window=white,black +border=lightgray,black +title=lightcyan,black +textbox=white,black +listbox=white,black +actlistbox=white,blue +actsellistbox=white,blue +button=black,lightgray +actbutton=white,blue +compactbutton=white,black +entry=white,black +label=white,black +checkbox=white,black +actcheckbox=white,blue +}" +fi + +cleanup() { + local path + for path in "${TEMP_FILES[@]}"; do + [[ -f "$path" ]] && rm -f -- "$path" + done +} +trap cleanup EXIT + +new_temp_file() { + local variable_name="$1" path + path="$(mktemp /tmp/mcserver-kit-tui.XXXXXX)" + TEMP_FILES+=("$path") + printf -v "$variable_name" '%s' "$path" +} + +server_root() { + local configured + configured="$(python3 "$CONFIG_VALUE" get "$CONFIG_FILE" paths server_root 2>/dev/null || printf '%s' "\${HOME}/minecraftServer")" + configured="${configured//\$\{HOME\}/$HOME}" + if [[ "${configured:0:1}" == '~' && "${configured:1:1}" == / ]]; then + configured="${HOME}/${configured#\~/}" + fi + printf '%s' "$configured" +} + +tool_availability() { + if command -v "$1" >/dev/null 2>&1; then + tr home.available + else + tr home.unavailable + fi +} + +server_status() { + local directory="$1" + if (cd "$directory" && docker compose ps --status running --services 2>/dev/null | grep -qx minecraft); then + tr home.running + else + tr home.stopped + fi +} + +logo() { + local columns=80 + columns="$(tput cols 2>/dev/null || printf 80)" + if ((columns < 76)); then + printf '%s\n' 'mcserver-kit' 'Minecraft Server Kit' + else + cat <<'LOGO' + __ __ ____ ____ _____ ______ _______ ____ +| \/ |/ ___/ ___|| ____| _ \ \ / / ____| _ \ +| |\/| | | \___ \| _| | |_) \ \ / /| _| | |_) | +| | | | |___ ___) | |___| _ < \ V / | |___| _ < +|_| |_|\____|____/|_____|_| \_\ \_/ |_____|_| \_\ +LOGO + fi +} + +dashboard_text() { + local root="$1" + local total=0 running=0 directory + if [[ -d "$root" ]]; then + shopt -s nullglob + for directory in "$root"/*; do + [[ -d "$directory" && -f "${directory}/compose.yaml" ]] || continue + total=$((total + 1)) + if (cd "$directory" && docker compose ps --status running --services 2>/dev/null | grep -qx minecraft); then + running=$((running + 1)) + fi + done + shopt -u nullglob + fi + logo + printf '\n%s\n%s\n' "$(tr home.summary "$total" "$running")" "$(tr home.choose)" +} + +pause_for_enter() { + printf '\n%s' "$(tr home.press_enter)" + read -r _ || true +} + +run_and_show() { + local title="$1" + shift + local output + new_temp_file output + if "$@" >"$output" 2>&1; then + whiptail --title "$title" --textbox "$output" 22 84 + else + whiptail --title "$(tr common.error)" --textbox "$output" 22 84 + fi +} + +server_action_menu() { + local id="$1" directory="$2" choice + while true; do + choice="$(whiptail --title "$id" --menu "$(tr home.server_status "$(server_status "$directory")")" 21 78 11 \ + start "$(tr home.start)" \ + stop "$(tr home.stop)" \ + restart "$(tr home.restart)" \ + status "$(tr home.status)" \ + logs "$(tr home.logs)" \ + properties "$(tr home.properties)" \ + down "$(tr home.down)" \ + back "$(tr tui.back)" \ + 3>&1 1>&2 2>&3)" || return + case "$choice" in + start | stop | restart | status) + run_and_show "$id" "${SCRIPT_DIR}/server-manager.sh" server "$id" "$choice" + ;; + logs) + clear + "${SCRIPT_DIR}/server-manager.sh" server "$id" logs || true + pause_for_enter + ;; + properties) + "${SCRIPT_DIR}/server-manager.sh" server "$id" properties || true + ;; + down) + if whiptail --yesno "$(tr home.down_confirm "$id")" 10 72; then + run_and_show "$id" "${SCRIPT_DIR}/server-manager.sh" server "$id" down + fi + ;; + back) return ;; + esac + done +} + +servers_menu() { + local root directory id selected + local items=() + root="$(server_root)" + while true; do + items=() + if [[ -d "$root" ]]; then + shopt -s nullglob + for directory in "$root"/*; do + [[ -d "$directory" && -f "${directory}/compose.yaml" ]] || continue + id="$(basename "$directory")" + items+=("$id" "$(server_status "$directory")") + done + shopt -u nullglob + fi + items+=(__back "$(tr tui.back)") + selected="$(whiptail --title "$(tr home.servers)" --menu "$(tr home.select_server)" 23 82 15 "${items[@]}" 3>&1 1>&2 2>&3)" || return + [[ "$selected" == __back ]] && return + server_action_menu "$selected" "${root}/${selected}" + done +} + +language_menu() { + local current selected + current="${MCSERVER_KIT_ACTIVE_LANG:-en}" + selected="$(whiptail --title "$(tr home.language)" --radiolist "$(tr home.language_choose)" 13 66 2 \ + en English "$([[ "$current" == en ]] && printf ON || printf OFF)" \ + ja '日本語' "$([[ "$current" == ja ]] && printf ON || printf OFF)" \ + 3>&1 1>&2 2>&3)" || return + "${SCRIPT_DIR}/lang.sh" "--${selected}" >/dev/null + I18N_MESSAGES=() + load_messages "$selected" +} + +diagnostics() { + local output root server_count=0 + new_temp_file output + root="$(server_root)" + if [[ -d "$root" ]]; then + server_count="$(find "$root" -mindepth 2 -maxdepth 2 -type f -name compose.yaml -printf . 2>/dev/null | wc -c)" + fi + { + printf '%s\n' "$(tr home.diagnostics_title)" '--------------------------------' + printf '%-24s %s\n' Docker "$(tool_availability docker)" + printf '%-24s %s\n' 'Docker Compose' "$(docker compose version --short 2>/dev/null || tr home.unavailable)" + printf '%-24s %s\n' Python "$(python3 --version 2>&1 || tr home.unavailable)" + printf '%-24s %s\n' whiptail "$(tool_availability whiptail)" + printf '%-24s %s\n' "$(tr home.configuration)" "$CONFIG_FILE" + printf '%-24s %s\n' "$(tr home.server_root)" "$root" + printf '%-24s %s\n' "$(tr home.server_count)" "$server_count" + } >"$output" + whiptail --title "$(tr home.diagnostics)" --textbox "$output" 22 90 +} + +main() { + local root choice + command -v whiptail >/dev/null 2>&1 || { + tr tui.missing >&2 + exit 1 + } + [[ "${MCSERVER_KIT_TUI_TEST:-false}" == true || (-t 0 && -t 1) ]] || { + printf '%s\n' "$(tr home.tty_required)" >&2 + exit 2 + } + root="$(server_root)" + while true; do + choice="$(whiptail --backtitle 'mcserver-kit' --title 'Minecraft Server Kit' --menu "$(dashboard_text "$root")" 27 94 9 \ + servers "$(tr home.servers)" \ + create "$(tr home.create)" \ + config "$(tr home.config)" \ + templates "$(tr home.templates)" \ + language "$(tr home.language)" \ + diagnostics "$(tr home.diagnostics)" \ + help "$(tr home.help)" \ + exit "$(tr home.exit)" \ + 3>&1 1>&2 2>&3)" || return + case "$choice" in + servers) servers_menu ;; + create) + clear + "${SCRIPT_DIR}/new-minecraft-server.sh" || true + pause_for_enter + ;; + config) "${SCRIPT_DIR}/config-tui.sh" || true ;; + templates) "${SCRIPT_DIR}/config-tui.sh" templates || true ;; + language) language_menu ;; + diagnostics) diagnostics ;; + help) run_and_show "$(tr home.help)" "${SCRIPT_DIR}/mcserver-kit" --help ;; + exit) return ;; + esac + done +} + +main "$@" diff --git a/install.sh b/install.sh index b57d402..0fd2cc8 100755 --- a/install.sh +++ b/install.sh @@ -182,6 +182,7 @@ main() { mkdir -p "$INSTALL_DIR" "$CONFIG_DIR" "${CONFIG_DIR}/mcid-templates" "$BIN_DIR" install -m 755 "${source_dir}/new-minecraft-server.sh" "${INSTALL_DIR}/new-minecraft-server.sh" install -m 755 "${source_dir}/mcserver-kit" "${INSTALL_DIR}/mcserver-kit" + install -m 755 "${source_dir}/home-tui.sh" "${INSTALL_DIR}/home-tui.sh" install -m 755 "${source_dir}/setup.sh" "${INSTALL_DIR}/setup.sh" install -m 755 "${source_dir}/reset.sh" "${INSTALL_DIR}/reset.sh" install -m 755 "${source_dir}/config-tui.sh" "${INSTALL_DIR}/config-tui.sh" diff --git a/locales/en.json b/locales/en.json index 02b8355..4cac01d 100644 --- a/locales/en.json +++ b/locales/en.json @@ -2,7 +2,8 @@ "cli.description": "Minecraft Java distribution-world server toolkit", "cli.usage": "Usage:", "cli.commands": "Commands:", - "cli.create": "Create a new server interactively (default command)", + "cli.home": "Open the interactive home dashboard", + "cli.create": "Create a new server interactively", "cli.setup": "Configure Owner, EULA, MCID templates, Playit, and defaults", "cli.config": "Open the interactive settings manager", "cli.templates": "Open MCID template management directly", @@ -12,6 +13,37 @@ "cli.help": "Show this help", "cli.settings": "Settings:", "cli.unknown": "Unknown command: %s\n\n", + "home.running": "running", + "home.stopped": "stopped", + "home.summary": "Servers: %s | Running: %s", + "home.choose": "Choose what you want to do.", + "home.press_enter": "Press Enter to return to the dashboard...", + "home.server_status": "Current status: %s", + "home.servers": "Servers", + "home.select_server": "Select a server", + "home.create": "Create server", + "home.config": "Global settings", + "home.templates": "MCID templates", + "home.language": "Language", + "home.language_choose": "Choose the display language", + "home.diagnostics": "Diagnostics", + "home.help": "Help", + "home.exit": "Exit", + "home.start": "Start", + "home.stop": "Stop", + "home.restart": "Restart", + "home.status": "Show status", + "home.logs": "Follow logs", + "home.properties": "Server settings", + "home.down": "Remove containers", + "home.down_confirm": "Remove containers and networks for %s? World data is preserved.", + "home.diagnostics_title": "Environment diagnostics", + "home.available": "available", + "home.unavailable": "unavailable", + "home.configuration": "Configuration", + "home.server_root": "Server root", + "home.server_count": "Managed servers", + "home.tty_required": "The interactive dashboard requires a terminal. Use mcserver-kit --help for commands.", "setup.title": "Minecraft Server Kit setup", "setup.owner": "Owner Minecraft ID", "setup.eula_url": "Minecraft EULA: https://aka.ms/MinecraftEULA\n", diff --git a/locales/ja.json b/locales/ja.json index c2b4f17..9ce5e68 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -2,7 +2,8 @@ "cli.description": "Minecraft Java配布ワールド用サーバー作成ツール", "cli.usage": "使い方:", "cli.commands": "コマンド:", - "cli.create": "対話形式で新しいサーバーを作成します(省略時の動作)", + "cli.home": "対話式ホーム画面を開きます", + "cli.create": "対話形式で新しいサーバーを作成します", "cli.setup": "Owner、EULA、MCIDテンプレート、Playit等を設定します", "cli.config": "対話式の設定管理画面を開きます", "cli.templates": "MCIDテンプレート管理を直接開きます", @@ -12,6 +13,37 @@ "cli.help": "このヘルプを表示します", "cli.settings": "設定:", "cli.unknown": "不明なコマンドです: %s\n\n", + "home.running": "起動中", + "home.stopped": "停止中", + "home.summary": "サーバー: %s件 | 起動中: %s件", + "home.choose": "操作を選択してください。", + "home.press_enter": "Enterでホーム画面へ戻ります...", + "home.server_status": "現在の状態: %s", + "home.servers": "サーバー管理", + "home.select_server": "サーバーを選択してください", + "home.create": "サーバーを作成", + "home.config": "全体設定", + "home.templates": "MCIDテンプレート", + "home.language": "言語", + "home.language_choose": "表示言語を選択してください", + "home.diagnostics": "動作環境の診断", + "home.help": "ヘルプ", + "home.exit": "終了", + "home.start": "起動", + "home.stop": "停止", + "home.restart": "再起動", + "home.status": "状態を表示", + "home.logs": "ログを表示", + "home.properties": "サーバー設定", + "home.down": "コンテナを削除", + "home.down_confirm": "%sのコンテナとネットワークを削除しますか?ワールドデータは保持されます。", + "home.diagnostics_title": "動作環境の診断", + "home.available": "利用可能", + "home.unavailable": "利用不可", + "home.configuration": "設定ファイル", + "home.server_root": "サーバー保存先", + "home.server_count": "管理対象サーバー数", + "home.tty_required": "対話式ホーム画面にはターミナルが必要です。コマンド一覧はmcserver-kit --helpで確認できます。", "setup.title": "Minecraft Server Kit 初回設定", "setup.owner": "OwnerのMinecraft ID", "setup.eula_url": "Minecraft EULA: https://aka.ms/MinecraftEULA\n", diff --git a/mcserver-kit b/mcserver-kit index 62d6639..0200ded 100755 --- a/mcserver-kit +++ b/mcserver-kit @@ -26,7 +26,9 @@ show_help() { tr cli.usage printf '\n' cat <>> mcserver-kit PATH >>>' "$shell_rc")" 'the installer registers one managed PATH block' @@ -327,6 +328,35 @@ test_local_installation() { assert_equal 'absent' "$(! grep -q 'mcserver-kit PATH' "$shell_rc" && printf absent)" 'the uninstaller removes its managed PATH block' } +test_home_dashboard() { + local temp_dir="$1" + local config_file="${temp_dir}/home/config.yml" + local fake_bin="${temp_dir}/home/bin" + local whiptail_log="${temp_dir}/home/whiptail.log" + local output + + mkdir -p "$fake_bin" + cat >"$config_file" <"${fake_bin}/whiptail" <<'WHIPTAIL' +#!/usr/bin/env bash +printf '%s\n' "$*" >>"$MCSERVER_KIT_TEST_WHIPTAIL_LOG" +printf 'exit' >&2 +WHIPTAIL + chmod +x "${fake_bin}/whiptail" + + output="$(MCSERVER_KIT_LANG=en bash "${REPO_ROOT}/mcserver-kit")" + assert_equal 'present' "$(grep -q 'mcserver-kit home' <<<"$output" && printf present)" 'non-interactive no-argument use shows help instead of starting creation' + + PATH="${fake_bin}:$PATH" MCSERVER_KIT_LANG=en MCSERVER_KIT_CONFIG="$config_file" \ + MCSERVER_KIT_TUI_TEST=true MCSERVER_KIT_TEST_WHIPTAIL_LOG="$whiptail_log" \ + bash "${REPO_ROOT}/mcserver-kit" home + assert_equal 'present' "$(grep -q -- '--backtitle mcserver-kit' "$whiptail_log" && printf present)" 'the home command opens the interactive dashboard' + assert_equal 'present' "$(grep -q 'servers Servers' "$whiptail_log" && printf present)" 'the dashboard exposes server management' +} + test_setup_command() { local temp_dir="$1" local config_file="${temp_dir}/setup/config.yml" @@ -546,6 +576,7 @@ main() { test_config_value_editor "$TEST_TEMP_DIR" test_server_management "$TEST_TEMP_DIR" test_server_property_editor "$TEST_TEMP_DIR" + test_home_dashboard "$TEST_TEMP_DIR" printf 'PASS: %d specification tests, %d skipped\n' "$tests_run" "$tests_skipped" } From a80714a3b367d0d5b4a036b5ecf122feea29b846 Mon Sep 17 00:00:00 2001 From: cotore-game <102813037+cotore-game@users.noreply.github.com> Date: Sun, 9 Aug 2026 01:55:03 +0900 Subject: [PATCH 2/3] docs: document interactive dashboard --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9aa1325..82be9e7 100644 --- a/README.md +++ b/README.md @@ -33,13 +33,16 @@ mcserver-kit 主なサブコマンド: ```bash -mcserver-kit # 新しいサーバーを作成 +mcserver-kit # 対話式ホーム画面を開く +mcserver-kit create # 新しいサーバーを作成 mcserver-kit setup # 初回設定・再設定 mcserver-kit uninstall # 設定を残してアンインストール mcserver-kit uninstall --purge mcserver-kit --help ``` +引数なしで起動すると、ASCIIアートロゴ付きのホーム画面から、サーバー一覧・作成・起動・停止・ログ・設定・言語・診断を選べます。矢印キーで項目を選択し、Enterで決定します。スクリプトや自動化では従来どおり各サブコマンドを直接利用できます。 + ### Language / 言語 The default language is English. Save a persistent language preference with: From c3e9cb5e4568389e4e9b46797996bd9a8fa46e36 Mon Sep 17 00:00:00 2001 From: cotore-game <102813037+cotore-game@users.noreply.github.com> Date: Sun, 9 Aug 2026 01:55:26 +0900 Subject: [PATCH 3/3] fix: preserve home dashboard executable mode --- home-tui.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 home-tui.sh diff --git a/home-tui.sh b/home-tui.sh old mode 100644 new mode 100755