From 1ecb889aeb20315b3fa4a613048a2790f58bf8ed Mon Sep 17 00:00:00 2001
From: mzdluo123 <mzdluo123@foxmail.com>
Date: Wed, 6 May 2020 12:38:02 +0800
Subject: [PATCH 1/7] Update README.md

---
 README.md | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 7342f0af8..477286111 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,9 @@ Mirai 是一个在全平台下运行,提供 QQ Android 和 TIM PC 协议支持
 **[下载(download)](https://github.com/mamoe/mirai-console/releases)**  
 请下载最新的 `mirai-console-wrapper-x.x.x-all.jar`
 
-你也可以下载这里的一键安装包来快速启动mirai-console **[下载地址](https://suihou-my.sharepoint.com/:f:/g/personal/user18_5tb_site/ErWGr97FpPVDjkboIDmDAJkBID-23ZMNbTPggGajf1zvGw?e=51NZWM)**
+#### 对于Windows用户
+
+你可以下载这里的一键安装包来快速启动mirai-console,这是最简单的方法 **[下载地址](https://suihou-my.sharepoint.com/:f:/g/personal/user18_5tb_site/ErWGr97FpPVDjkboIDmDAJkBID-23ZMNbTPggGajf1zvGw?e=51NZWM)**
 
 **请注意**
 * 使用时请留意安装包里的说明文字
@@ -36,6 +38,10 @@ Mirai 是一个在全平台下运行,提供 QQ Android 和 TIM PC 协议支持
 * 关于安装包本身的一切问题请到QQ群内反馈
 * 如果上面的链接下载过慢,你可以到QQ群内高速下载
 
+#### 对于Linux用户
+
+运行本软件需要openjdk11,请在上面的链接下载`mirai-console-wrapper-x.x.x-all.jar`直接运行即可
+
 #### 如何启动
 如果是打包好的软件, 双击<br>
 如果是命令行运行, 请注意运行目录, 推荐cd到jar的文件夹下运行, 运行目录与Console的全部配置文件储存位置有关

From fa8eb466e7dd768a77e435063f29250a0c4ed885 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Wed, 6 May 2020 14:40:53 +0800
Subject: [PATCH 2/7] Rework core/console updating, implement command args

---
 buildSrc/src/main/kotlin/versions.kt          |   4 +-
 mirai-console-wrapper/build.gradle.kts        |  26 ++-
 .../mirai/console/wrapper/ConsoleUpdater.kt   | 141 +++++++++++-----
 .../mirai/console/wrapper/CoreUpdater.kt      |  44 ++---
 .../console/wrapper/JCenterDownloader.kt      |   9 +-
 .../mirai/console/wrapper/MiraiDownloader.kt  |   9 ++
 .../mirai/console/wrapper/WrapperMain.kt      | 152 +++++++++++-------
 .../console/wrapper/ConsoleUpdaterKtTest.kt   |  28 ++++
 8 files changed, 272 insertions(+), 141 deletions(-)
 create mode 100644 mirai-console-wrapper/src/test/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdaterKtTest.kt

diff --git a/buildSrc/src/main/kotlin/versions.kt b/buildSrc/src/main/kotlin/versions.kt
index f2ecc7d46..e457291f9 100644
--- a/buildSrc/src/main/kotlin/versions.kt
+++ b/buildSrc/src/main/kotlin/versions.kt
@@ -11,10 +11,10 @@ import org.gradle.kotlin.dsl.DependencyHandlerScope
 
 object Versions {
     object Mirai {
-        const val core = "0.39.1"
+        const val core = "1.0-RC"
         const val console = "0.4.11"
         const val consoleGraphical = "0.0.7"
-        const val consoleWrapper = "0.2.0"
+        const val consoleWrapper = "1.0.0"
     }
 
     object Kotlin {
diff --git a/mirai-console-wrapper/build.gradle.kts b/mirai-console-wrapper/build.gradle.kts
index cb324ebf8..1ceaaacfd 100644
--- a/mirai-console-wrapper/build.gradle.kts
+++ b/mirai-console-wrapper/build.gradle.kts
@@ -28,13 +28,35 @@ dependencies {
     api(kotlin("reflect", Versions.Kotlin.stdlib))
 
     api(kotlinx("coroutines-core", Versions.Kotlin.coroutines))
-    api(kotlinx("coroutines-swing",Versions.Kotlin.coroutines))
+    api(kotlinx("coroutines-swing", Versions.Kotlin.coroutines))
 
     api(ktor("client-cio", Versions.Kotlin.ktor))
     api(ktor("client-core", Versions.Kotlin.ktor))
     api(ktor("network", Versions.Kotlin.ktor))
+
+    api("com.github.ajalt:clikt:2.6.0")
+
+    testApi(kotlin("stdlib", Versions.Kotlin.stdlib))
+    testApi(kotlin("test-junit5"))
 }
 
 version = Versions.Mirai.consoleWrapper
 
-description = "Console with plugin support for mirai"
\ No newline at end of file
+description = "Console with plugin support for mirai"
+
+
+val compileKotlin: org.jetbrains.kotlin.gradle.tasks.KotlinCompile by tasks
+compileKotlin.kotlinOptions {
+    jvmTarget = "1.8"
+}
+val compileTestKotlin: org.jetbrains.kotlin.gradle.tasks.KotlinCompile by tasks
+compileTestKotlin.kotlinOptions {
+    jvmTarget = "1.8"
+}
+java {
+    sourceCompatibility = JavaVersion.VERSION_1_8
+    targetCompatibility = JavaVersion.VERSION_1_8
+}
+tasks.withType(JavaCompile::class.java) {
+    options.encoding = "UTF8"
+}
diff --git a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt
index 70ea86de7..8b8ee8ee1 100644
--- a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt
+++ b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt
@@ -1,3 +1,11 @@
+/*
+ * Copyright 2020 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
 package net.mamoe.mirai.console.wrapper
 
 import io.ktor.client.request.get
@@ -14,15 +22,15 @@ const val CONSOLE_GRAPHICAL = "Graphical"
 internal object ConsoleUpdater {
 
     @Suppress("SpellCheckingInspection")
-    private object Links : HashMap<String, Map<String, String>>() {
+    private object Links : HashMap<ConsoleType, Map<String, String>>() {
         init {
             put(
-                CONSOLE_PURE, mapOf(
+                ConsoleType.Pure, mapOf(
                     "version" to "/net/mamoe/mirai-console/"
                 )
             )
             put(
-                CONSOLE_GRAPHICAL, mapOf(
+                ConsoleType.Graphical, mapOf(
                     "version" to "/net/mamoe/mirai-console-graphical/"
                 )
             )
@@ -30,23 +38,26 @@ internal object ConsoleUpdater {
     }
 
 
-    var consoleType = CONSOLE_PURE
+    var consoleType = ConsoleType.Pure
 
     fun getFile(): File? {
         contentPath.listFiles()?.forEach { file ->
             if (file != null && file.extension == "jar") {
                 if (file.name.contains("mirai-console")) {
                     when (consoleType) {
-                        CONSOLE_PURE -> {
-                            if(!file.name.contains("graphical")) {
+                        ConsoleType.Pure -> {
+                            if (!file.name.contains("graphical")) {
                                 return file
                             }
                         }
-                        CONSOLE_GRAPHICAL -> {
-                            if(file.name.contains("graphical")) {
+                        ConsoleType.Graphical -> {
+                            if (file.name.contains("graphical")) {
                                 return file
                             }
                         }
+                        else -> {
+
+                        }
                     }
                 }
             }
@@ -54,52 +65,35 @@ internal object ConsoleUpdater {
         return null
     }
 
-    suspend fun versionCheck(type: String) {
+    suspend fun versionCheck(type: ConsoleType, strategy: VersionUpdateStrategy) {
         this.consoleType = type
         println("Fetching Newest Console Version of $type")
-        val newest = getNewestVersion()
-        val current = getCurrentVersion()
-        println("Local Console-$type Version: $current | Newest Console-$type Version: $newest")
+        val current = CoreUpdater.getCurrentVersion()
+        if (current != "0.0.0" && strategy == VersionUpdateStrategy.KEEP) {
+            println("Stay on current version.")
+            return
+        }
+
+        val newest = getNewestVersion(
+            strategy,
+            Links[consoleType]!!["version"] ?: error("Unknown Console Type")
+        )
+        println("Local Console-$type Version: $current | Newest $strategy Console-$type Version: $newest")
         if (current != newest) {
-            println("Updating Console-$type from V$current -> V$newest, this is a force update")
+            println("Updating Console-$type from V$current -> V$newest")
             this.getFile()?.delete()
             /**
             MiraiDownloader.addTask(
-                "https://raw.githubusercontent.com/mamoe/mirai-repo/master/shadow/${getProjectName()}/${getProjectName()}-$newest.jar",getContent("${getProjectName()}-$newest.jar")
+            "https://raw.githubusercontent.com/mamoe/mirai-repo/master/shadow/${getProjectName()}/${getProjectName()}-$newest.jar",getContent("${getProjectName()}-$newest.jar")
             )
-            */
+             */
             MiraiDownloader.addTask(
-                "https://pan.jasonczc.cn/?/mirai/${getProjectName()}/${getProjectName()}-$newest.mp4", getContent("${getProjectName()}-$newest.jar")
+                "https://pan.jasonczc.cn/?/mirai/${getProjectName()}/${getProjectName()}-$newest.mp4",
+                getContent("${getProjectName()}-$newest.jar")
             )
         }
     }
 
-
-    private suspend fun getNewestVersion(): String {
-        try {
-            return """>([0-9])*\.([0-9])*\.([0-9])*/""".toRegex().findAll(
-                    Http.get<String> {
-                        url {
-                            protocol = URLProtocol.HTTPS
-                            host = "jcenter.bintray.com"
-                            path(Links[consoleType]!!["version"] ?: error("Unknown Console Type"))
-                        }
-                    }
-                ).asSequence()
-                .map { it.value.drop(1).dropLast(1) }
-                .maxBy {
-                    it.split('.').foldRightIndexed(0) { index: Int, s: String, acc: Int ->
-                        acc + 100.0.pow(2 - index).toInt() * (s.toIntOrNull() ?: 0)
-                    }
-                }!!
-        } catch (e: Exception) {
-            println("Failed to fetch newest Console version, please seek for help")
-            e.printStackTrace()
-            println("Failed to fetch newest Console version, please seek for help")
-            exitProcess(1)
-        }
-    }
-
     fun getCurrentVersion(): String {
         val file = getFile()
         if (file != null) {
@@ -112,11 +106,70 @@ internal object ConsoleUpdater {
     }
 
     private fun getProjectName(): String {
-        return if (consoleType == CONSOLE_PURE) {
+        return if (consoleType == ConsoleType.Pure) {
             "mirai-console"
         } else {
-            "mirai-console-${consoleType.toLowerCase()}"
+            "mirai-console-${consoleType.toString().toLowerCase()}"
         }
     }
 
+}
+
+
+suspend fun getNewestVersion(strategy: VersionUpdateStrategy, path: String): String {
+    try {
+        return Regex("""rel="nofollow">[0-9][0-9]*(\.[0-9]*)*.*/<""", RegexOption.IGNORE_CASE).findAll(
+                Http.get<String> {
+                    url {
+                        protocol = URLProtocol.HTTPS
+                        host = "jcenter.bintray.com"
+                        path(path)
+                    }
+                })
+            .asSequence()
+            .map { it.value.substringAfter('>').substringBefore('/') }
+            .toList()
+            .let { list ->
+                if (list.filter { it.startsWith("1.") }.takeIf { it.isNotEmpty() }?.all { it.contains("-") } == true) {
+                    // 只有 1.xxx-EA 版本, 那么也将他看作是正式版
+                    list.filter { it.startsWith("1.") }
+                } else when (strategy) {
+                    VersionUpdateStrategy.KEEP,
+                    VersionUpdateStrategy.STABLE
+                    -> {
+                        list.filterNot { it.contains("-") } // e.g. "-EA"
+                    }
+                    VersionUpdateStrategy.EA -> {
+                        list
+                    }
+                }
+            }
+            .latestVersion()
+    } catch (e: Exception) {
+        println("Failed to fetch newest Console version, please seek for help")
+        e.printStackTrace()
+        println("Failed to fetch newest Console version, please seek for help")
+        exitProcess(1)
+    }
+}
+
+internal fun List<String>.latestVersion(): String {
+    return sortByVersion().first()
+}
+
+internal fun List<String>.sortByVersion(): List<String> {
+    return sortedByDescending { version ->
+        version.split('.').let {
+            if (it.size == 2) it + "0"
+            else it
+        }.reversed().foldIndexed(0.0) { index: Int, acc: Double, s: String ->
+            acc + 1000.0.pow(index) * s.convertPatchVersionToWeight()
+        }
+    }
+}
+
+internal fun String.convertPatchVersionToWeight(): Double {
+    return this.split('-').reversed().foldIndexed(0.0) { index: Int, acc: Double, s: String ->
+        acc + 10.0.pow(index) * (s.toIntOrNull()?.toDouble() ?: -0.5)
+    }
 }
\ No newline at end of file
diff --git a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/CoreUpdater.kt b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/CoreUpdater.kt
index a6ec7b4bd..e9a1ac92c 100644
--- a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/CoreUpdater.kt
+++ b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/CoreUpdater.kt
@@ -11,11 +11,7 @@
 
 package net.mamoe.mirai.console.wrapper
 
-import io.ktor.client.request.get
-import io.ktor.http.URLProtocol
 import java.io.File
-import kotlin.math.pow
-import kotlin.system.exitProcess
 
 internal object CoreUpdater {
 
@@ -29,13 +25,18 @@ internal object CoreUpdater {
     }
 
 
-    suspend fun versionCheck() {
+    suspend fun versionCheck(strategy: VersionUpdateStrategy) {
         println("Fetching Newest Core Version .. ")
-        val newest = getNewestVersion()
         val current = getCurrentVersion()
-        println("Local Core Version: $current | Newest Core Version: $newest")
+        if (current != "0.0.0" && strategy == VersionUpdateStrategy.KEEP) {
+            println("Stay on current version.")
+            return
+        }
+
+        val newest = getNewestVersion(strategy, "net/mamoe/mirai-core-qqandroid/")
+        println("Local Core Version: $current | Newest $strategy Core Version: $newest")
         if (current != newest) {
-            println("Updating shadowed-core from V$current -> V$newest, this is a force update")
+            println("Updating shadowed-core from V$current -> V$newest")
             this.getProtocolLib()?.delete()
             MiraiDownloader
                 .addTask(
@@ -47,33 +48,6 @@ internal object CoreUpdater {
         }
     }
 
-    /**
-     * 判断最新版本
-     * */
-    private suspend fun getNewestVersion(): String {
-        try {
-            return """>([0-9])*\.([0-9])*\.([0-9])*/""".toRegex().findAll(
-                    Http.get<String> {
-                        url {
-                            protocol = URLProtocol.HTTPS
-                            host = "jcenter.bintray.com"
-                            path("net/mamoe/mirai-core-qqandroid/")
-                        }
-                    }).asSequence()
-                .map { it.value.drop(1).dropLast(1) }
-                .maxBy {
-                    it.split('.').foldRightIndexed(0) { index: Int, s: String, acc: Int ->
-                        acc + 100.0.pow(2 - index).toInt() * (s.toIntOrNull() ?: 0)
-                    }
-                }!!
-        } catch (e: Exception) {
-            println("Failed to fetch newest Core version, please seek for help")
-            e.printStackTrace()
-            println("Failed to fetch newest Core version, please seek for help")
-            exitProcess(1)
-        }
-    }
-
     /**
      * 判断当前版本
      * 默认返回 "0.0.0"
diff --git a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/JCenterDownloader.kt b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/JCenterDownloader.kt
index 639527e5d..8e5a78214 100644
--- a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/JCenterDownloader.kt
+++ b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/JCenterDownloader.kt
@@ -1,3 +1,11 @@
+/*
+ * Copyright 2020 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
 @file:Suppress("EXPERIMENTAL_API_USAGE")
 
 package net.mamoe.mirai.console.wrapper
@@ -137,7 +145,6 @@ internal suspend fun ByteReadChannel.saveToContent(filepath: String) {
 }
 
 
-
 internal fun getContent(filepath: String):File{
     return File(contentPath, filepath)
 }
diff --git a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/MiraiDownloader.kt b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/MiraiDownloader.kt
index 51a622e1b..a3f8f6ea7 100644
--- a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/MiraiDownloader.kt
+++ b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/MiraiDownloader.kt
@@ -1,3 +1,11 @@
+/*
+ * Copyright 2020 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
 package net.mamoe.mirai.console.wrapper
 
 import kotlinx.coroutines.*
@@ -146,6 +154,7 @@ class MiraiDownloaderProgressBarInUI(): MiraiDownloadProgressBar{
     override fun ad(){
         WrapperMain.uiLog("[Mirai国内镜像] 感谢崔Cloud慷慨提供更新服务器")
     }
+
     private val barLen = 20
 
     override fun update(rate: Float, message: String) {
diff --git a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/WrapperMain.kt b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/WrapperMain.kt
index 270a0b793..1ae00ffdb 100644
--- a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/WrapperMain.kt
+++ b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/WrapperMain.kt
@@ -10,11 +10,15 @@
 
 package net.mamoe.mirai.console.wrapper
 
+import com.github.ajalt.clikt.core.CliktCommand
+import com.github.ajalt.clikt.parameters.options.default
+import com.github.ajalt.clikt.parameters.options.flag
+import com.github.ajalt.clikt.parameters.options.option
+import com.github.ajalt.clikt.parameters.types.enum
 import kotlinx.coroutines.*
 import java.awt.TextArea
 import java.io.File
 import java.net.URLClassLoader
-import java.util.*
 import java.util.jar.JarFile
 import javax.swing.JFrame
 import javax.swing.JPanel
@@ -34,19 +38,43 @@ val extendedLibraries by lazy {
     file.also { if (!it.exists()) it.mkdirs() }
 }
 
-object WrapperMain {
-    internal var uiBarOutput = StringBuilder()
-    private val uilog = StringBuilder()
-    internal fun uiLog(any: Any?) {
-        if (any != null) {
-            uilog.append(any)
-        }
-    }
+object WrapperCli : CliktCommand(name = "mirai-warpper") {
+    private val native by option(
+        help = """
+        Start in GRAPHICAL mode without command line outputs
+        ------------------------------------------
+        以图形界面模式启动
+    """.trimIndent(),
+        envvar = "mirai.wrapper.native"
+    ).flag("-n", default = false)
 
-    @JvmStatic
-    fun main(args: Array<String>) {
-        gc()
-        if (args.contains("native") || args.contains("-native")) {
+    private val update: VersionUpdateStrategy by option(
+        help = """
+        Strategy to automatic updates. 
+        "KEEP" to stay on the current version;
+        "STABLE" to update to the latest stable versions;
+        "EA" to update to use the newest features but might not be stable.
+        ------------------------------------------
+        版本升级策略. "KEEP" 为停留在当前版本; "STABLE" 为更新到最新稳定版; "EA" 为更新到最新预览版.
+    """.trimIndent(),
+        envvar = "mirai.wrapper.update"
+    ).enum<VersionUpdateStrategy>().default(VersionUpdateStrategy.STABLE)
+
+    private val console: ConsoleType by option(
+        help = """
+        The type of the console to be started. 
+        "GRAPHICAL" to use JavaFX graphical UI;
+        "TERMINAL" to use terminal UI for Unix;
+        "PURE" to use pure CLI.
+         ------------------------------------------
+         UI 类型. "GRAPHICAL" 为 JavaFX 图形界面; "TERMINAL" 为 Unix 终端界面; "PURE" 为纯命令行.
+   """.trimIndent(),
+        envvar = "mirai.wrapper.console"
+    ).enum<ConsoleType>().default(ConsoleType.Pure)
+
+    override fun run() {
+
+        if (native) {
             val f = JFrame("Mirai-Console Version Check")
             f.setSize(500, 200)
             f.setLocationRelativeTo(null)
@@ -60,29 +88,29 @@ object WrapperMain {
 
             f.isVisible = true
 
-            uiLog("正在进行版本检查\n")
+            WrapperMain.uiLog("正在进行版本检查\n")
             val dic = System.getProperty("user.dir")
-            uiLog("工作目录: ${dic}\n")
-            uiLog("扩展库目录: ${extendedLibraries}\n")
-            uiLog("若无法启动, 请尝试清除工作目录下/content/文件夹\n")
+            WrapperMain.uiLog("工作目录: ${dic}\n")
+            WrapperMain.uiLog("扩展库目录: ${extendedLibraries}\n")
+            WrapperMain.uiLog("若无法启动, 请尝试清除工作目录下/content/文件夹\n")
             var uiOpen = true
             GlobalScope.launch {
                 while (isActive && uiOpen) {
                     delay(16)//60 fps
                     withContext(Dispatchers.Main) {
-                        textArea.text = uilog.toString() + "\n" + uiBarOutput.toString()
+                        textArea.text = WrapperMain.uiLog.toString() + "\n" + WrapperMain.uiBarOutput.toString()
                     }
                 }
             }
             runBlocking {
                 launch {
-                    CoreUpdater.versionCheck()
+                    CoreUpdater.versionCheck(update)
                 }
                 launch {
-                    ConsoleUpdater.versionCheck(CONSOLE_GRAPHICAL)
+                    ConsoleUpdater.versionCheck(ConsoleType.Graphical, update)
                 }
             }
-            uiLog("版本检查完成, 启动中\n")
+            WrapperMain.uiLog("版本检查完成, 启动中\n")
 
             runBlocking {
                 MiraiDownloader.downloadIfNeed(true)
@@ -93,41 +121,61 @@ object WrapperMain {
                 f.isVisible = false
             }
 
-            start(CONSOLE_GRAPHICAL)
+            WrapperMain.start(ConsoleType.Graphical)
         } else {
-            preStartInNonNative()
+            WrapperMain.preStartInNonNative(console, update)
+        }
+    }
+}
+
+enum class ConsoleType {
+    Graphical,
+    Terminal,
+    Pure
+}
+
+enum class VersionUpdateStrategy {
+    KEEP,
+    STABLE,
+    EA
+}
+
+object WrapperMain {
+    internal var uiBarOutput = StringBuilder()
+    internal val uiLog = StringBuilder()
+
+    internal fun uiLog(any: Any?) {
+        if (any != null) {
+            uiLog.append(any)
         }
     }
 
+    @JvmStatic
+    fun main(args: Array<String>) {
+        gc()
+        WrapperCli.main(args)
+    }
 
-    private fun preStartInNonNative() {
+
+    internal fun preStartInNonNative(defaultType: ConsoleType, strategy: VersionUpdateStrategy) {
         println("You are running Mirai-Console-Wrapper under " + System.getProperty("user.dir"))
         println("All additional libraries are located at $extendedLibraries")
-        var type = WrapperProperties.determineConsoleType(WrapperProperties.content)
+
+        var type = ConsoleType.values().firstOrNull { it.name.equals(WrapperProperties.content, ignoreCase = true) }
         if (type != null) {
             println("Starting Mirai Console $type, reset by clear /content/")
         } else {
-            println("Please select Console Type")
-            println("请选择 Console 版本")
-            println("=> Pure       : pure console")
-            println("=> Graphical  : graphical UI except unix")
-            println("=> Terminal   : [Not Supported Yet] console in unix")
-            val scanner = Scanner(System.`in`)
-            while (type == null) {
-                var input = scanner.next()
-                input = input.toUpperCase()[0] + input.toLowerCase().substring(1)
-                println("Selecting $input")
-                type = WrapperProperties.determineConsoleType(input)
-            }
-            WrapperProperties.content = type
+            WrapperProperties.content = defaultType.toString()
+            type = defaultType
         }
+
         println("Starting version check...")
         runBlocking {
             launch {
-                CoreUpdater.versionCheck()
+                CoreUpdater.versionCheck(strategy)
             }
             launch {
-                ConsoleUpdater.versionCheck(type)
+                ConsoleUpdater.versionCheck(type, strategy)
             }
         }
 
@@ -143,7 +191,7 @@ object WrapperMain {
         start(type)
     }
 
-    private fun start(type: String) {
+    internal fun start(type: ConsoleType) {
         val loader = MiraiClassLoader(
             CoreUpdater.getProtocolLib()!!,
             ConsoleUpdater.getFile()!!,
@@ -152,12 +200,12 @@ object WrapperMain {
 
         loader.loadClass("net.mamoe.mirai.BotFactoryJvm")
         loader.loadClass(
-            when (type) {
-                CONSOLE_PURE -> "net.mamoe.mirai.console.pure.MiraiConsolePureLoader"
-                CONSOLE_GRAPHICAL -> "net.mamoe.mirai.console.graphical.MiraiConsoleGraphicalLoader"
-                else -> return
-            }
-        ).getMethod("load", String::class.java, String::class.java)
+                when (type) {
+                    ConsoleType.Pure -> "net.mamoe.mirai.console.pure.MiraiConsolePureLoader"
+                    ConsoleType.Graphical -> "net.mamoe.mirai.console.graphical.MiraiConsoleGraphicalLoader"
+                    else -> return
+                }
+            ).getMethod("load", String::class.java, String::class.java)
             .invoke(null, CoreUpdater.getCurrentVersion(), ConsoleUpdater.getCurrentVersion())
 
     }
@@ -211,16 +259,6 @@ private object WrapperProperties {
     var content
         get() = contentFile.readText()
         set(value) = contentFile.writeText(value)
-
-
-    fun determineConsoleType(
-        type: String
-    ): String? {
-        if (type == CONSOLE_PURE || type == CONSOLE_GRAPHICAL || type == CONSOLE_TERMINAL) {
-            return type
-        }
-        return null
-    }
 }
 
 private fun gc() {
diff --git a/mirai-console-wrapper/src/test/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdaterKtTest.kt b/mirai-console-wrapper/src/test/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdaterKtTest.kt
new file mode 100644
index 000000000..ad3c64fb6
--- /dev/null
+++ b/mirai-console-wrapper/src/test/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdaterKtTest.kt
@@ -0,0 +1,28 @@
+package net.mamoe.mirai.console.wrapper
+
+import org.junit.jupiter.api.Test
+import kotlin.test.assertEquals
+
+internal class ConsoleUpdaterKtTest {
+    @Test
+    fun testVersionCompare() {
+        assertEquals(
+            listOf(
+                "1.0.0",
+                "1.0-EA-2",
+                "1.0-EA",
+                "0.40.0"
+            ),
+            listOf(
+                "1.0.0",
+                "0.40.0",
+                "1.0-EA",
+                "1.0-EA-2"
+            ).sortByVersion()
+        )
+    }
+}
+
+fun main() {
+    ConsoleUpdaterKtTest().testVersionCompare()
+}
\ No newline at end of file

From a35bbbb7d0fd2d6cffe6dd5c672feca0987db2dc Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Wed, 6 May 2020 14:45:06 +0800
Subject: [PATCH 3/7] Update core to 1.0-RC

---
 buildSrc/src/main/kotlin/versions.kt                         | 4 ++--
 .../kotlin/net/mamoe/mirai/console/command/CommandSender.kt  | 1 -
 .../net/mamoe/mirai/console/command/DefaultCommands.kt       | 5 ++---
 .../kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt  | 2 +-
 4 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/buildSrc/src/main/kotlin/versions.kt b/buildSrc/src/main/kotlin/versions.kt
index 18d4400a6..b9bd5fe0b 100644
--- a/buildSrc/src/main/kotlin/versions.kt
+++ b/buildSrc/src/main/kotlin/versions.kt
@@ -12,9 +12,9 @@ import org.gradle.kotlin.dsl.DependencyHandlerScope
 object Versions {
     object Mirai {
         const val core = "1.0-RC"
-        const val console = "0.5.0"
+        const val console = "0.5.1"
         const val consoleGraphical = "0.0.7"
-        const val consoleWrapper = "1.0.0"
+        const val consoleWrapper = "1.0."
     }
 
     object Kotlin {
diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt
index dae6e56ad..206c01890 100644
--- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt
+++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt
@@ -13,7 +13,6 @@ import kotlinx.coroutines.runBlocking
 import net.mamoe.mirai.console.MiraiConsole
 import net.mamoe.mirai.contact.Contact
 import net.mamoe.mirai.contact.Member
-import net.mamoe.mirai.contact.sendMessage
 import net.mamoe.mirai.message.data.Message
 
 /**
diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt
index 1af0a57fd..692bdab84 100644
--- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt
+++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt
@@ -20,10 +20,9 @@ import net.mamoe.mirai.console.utils.addManager
 import net.mamoe.mirai.console.utils.checkManager
 import net.mamoe.mirai.console.utils.managers
 import net.mamoe.mirai.console.utils.removeManager
-import net.mamoe.mirai.contact.sendMessage
 import net.mamoe.mirai.event.subscribeMessages
 import net.mamoe.mirai.getFriendOrNull
-import net.mamoe.mirai.message.GroupMessage
+import net.mamoe.mirai.message.GroupMessageEvent
 import net.mamoe.mirai.utils.SimpleLogger
 import java.util.*
 
@@ -62,7 +61,7 @@ object DefaultCommands {
             bot.subscribeMessages {
                 startsWith(commandPrefix) { message ->
                     if (bot.checkManager(this.sender.id)) {
-                        val sender = if (this is GroupMessage) {
+                        val sender = if (this is GroupMessageEvent) {
                             GroupContactCommandSender(this.sender, this.subject)
                         } else {
                             ContactCommandSender(this.subject)
diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt
index 85de85b75..6719184ae 100644
--- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt
+++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt
@@ -7,7 +7,7 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-@file:Suppress("unused", "unused")
+@file:Suppress("unused", "unused", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
 
 package net.mamoe.mirai.console.plugins
 

From 56181e7341d56091a8b290b60a84b2eb49f6b898 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Wed, 6 May 2020 14:45:27 +0800
Subject: [PATCH 4/7] Fix version

---
 buildSrc/src/main/kotlin/versions.kt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/buildSrc/src/main/kotlin/versions.kt b/buildSrc/src/main/kotlin/versions.kt
index b9bd5fe0b..ce4102bf0 100644
--- a/buildSrc/src/main/kotlin/versions.kt
+++ b/buildSrc/src/main/kotlin/versions.kt
@@ -14,7 +14,7 @@ object Versions {
         const val core = "1.0-RC"
         const val console = "0.5.1"
         const val consoleGraphical = "0.0.7"
-        const val consoleWrapper = "1.0."
+        const val consoleWrapper = "1.0.0"
     }
 
     object Kotlin {

From b732b9731a9ddd6b5c0ff00bca750f84f09a588c Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Wed, 6 May 2020 15:10:01 +0800
Subject: [PATCH 5/7] Fix version determine

---
 .../kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt
index 8b8ee8ee1..edadf26a5 100644
--- a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt
+++ b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt
@@ -46,7 +46,7 @@ internal object ConsoleUpdater {
                 if (file.name.contains("mirai-console")) {
                     when (consoleType) {
                         ConsoleType.Pure -> {
-                            if (!file.name.contains("graphical")) {
+                            if (!file.name.contains("pure")) {
                                 return file
                             }
                         }

From 8721c604939973c1797e82163bda451f1c2f88e8 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Wed, 6 May 2020 15:51:34 +0800
Subject: [PATCH 6/7] Fix version checking, add file validation

---
 .../mirai/console/wrapper/ConsoleUpdater.kt   |  9 ++---
 .../mirai/console/wrapper/CoreUpdater.kt      |  7 +---
 .../mirai/console/wrapper/WrapperMain.kt      | 35 ++++++++++++++-----
 3 files changed, 30 insertions(+), 21 deletions(-)

diff --git a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt
index edadf26a5..0223b26cb 100644
--- a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt
+++ b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt
@@ -46,7 +46,7 @@ internal object ConsoleUpdater {
                 if (file.name.contains("mirai-console")) {
                     when (consoleType) {
                         ConsoleType.Pure -> {
-                            if (!file.name.contains("pure")) {
+                            if (!file.name.contains("graphical")) {
                                 return file
                             }
                         }
@@ -68,7 +68,7 @@ internal object ConsoleUpdater {
     suspend fun versionCheck(type: ConsoleType, strategy: VersionUpdateStrategy) {
         this.consoleType = type
         println("Fetching Newest Console Version of $type")
-        val current = CoreUpdater.getCurrentVersion()
+        val current = getCurrentVersion()
         if (current != "0.0.0" && strategy == VersionUpdateStrategy.KEEP) {
             println("Stay on current version.")
             return
@@ -97,10 +97,7 @@ internal object ConsoleUpdater {
     fun getCurrentVersion(): String {
         val file = getFile()
         if (file != null) {
-            val numberVersion = """([0-9])*\.([0-9])*\.([0-9])*""".toRegex().find(file.name)?.value
-            if (numberVersion != null) {
-                return numberVersion + file.name.substringAfter(numberVersion).substringBefore(".jar")
-            }
+            return file.name.substringAfter(getProjectName() + "-").substringBefore(".jar")
         }
         return "0.0.0"
     }
diff --git a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/CoreUpdater.kt b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/CoreUpdater.kt
index e9a1ac92c..e6247c5cb 100644
--- a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/CoreUpdater.kt
+++ b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/CoreUpdater.kt
@@ -44,7 +44,6 @@ internal object CoreUpdater {
                     getContent("mirai-core-qqandroid-jvm-$newest.jar")
                 )
             //.addTask("https://raw.githubusercontent.com/mamoe/mirai-repo/master/shadow/mirai-core-qqandroid/mirai-core-qqandroid-$newest.jar", getContent("mirai-core-qqandroid-jvm-$newest.jar"))
-
         }
     }
 
@@ -54,11 +53,7 @@ internal object CoreUpdater {
      */
     fun getCurrentVersion(): String {
         val file = getProtocolLib() ?: return "0.0.0"
-        val numberVersion = """([0-9])*\.([0-9])*\.([0-9])*""".toRegex().find(file.name)?.value
-        if (numberVersion != null) {
-            return numberVersion + file.name.substringAfter(numberVersion).substringBefore(".jar")
-        }
-        return "0.0.0"
+        return file.name.substringBefore(".jar").substringAfter("mirai-core-qqandroid-jvm-")
     }
 
 
diff --git a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/WrapperMain.kt b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/WrapperMain.kt
index 1ae00ffdb..297eb3e06 100644
--- a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/WrapperMain.kt
+++ b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/WrapperMain.kt
@@ -122,6 +122,7 @@ object WrapperCli : CliktCommand(name = "mirai-warpper") {
             }
 
             WrapperMain.start(ConsoleType.Graphical)
+
         } else {
             WrapperMain.preStartInNonNative(console, update)
         }
@@ -192,22 +193,38 @@ object WrapperMain {
     }
 
     internal fun start(type: ConsoleType) {
+
         val loader = MiraiClassLoader(
             CoreUpdater.getProtocolLib()!!,
             ConsoleUpdater.getFile()!!,
             WrapperMain::class.java.classLoader
         )
 
-        loader.loadClass("net.mamoe.mirai.BotFactoryJvm")
-        loader.loadClass(
-                when (type) {
-                    ConsoleType.Pure -> "net.mamoe.mirai.console.pure.MiraiConsolePureLoader"
-                    ConsoleType.Graphical -> "net.mamoe.mirai.console.graphical.MiraiConsoleGraphicalLoader"
-                    else -> return
-                }
-            ).getMethod("load", String::class.java, String::class.java)
-            .invoke(null, CoreUpdater.getCurrentVersion(), ConsoleUpdater.getCurrentVersion())
+        try {
+            loader.loadClass("net.mamoe.mirai.BotFactoryJvm")
+        } catch (e: ClassNotFoundException) {
+            System.err.println("Found mirai-core file broken, re-downloading...")
+            loader.close()
+            CoreUpdater.getProtocolLib()?.delete()
+            WrapperCli.run()
+            return
+        }
 
+        try {
+            loader.loadClass(
+                    when (type) {
+                        ConsoleType.Pure -> "net.mamoe.mirai.console.pure.MiraiConsolePureLoader"
+                        ConsoleType.Graphical -> "net.mamoe.mirai.console.graphical.MiraiConsoleGraphicalLoader"
+                        else -> return
+                    }
+                ).getMethod("load", String::class.java, String::class.java)
+                .invoke(null, CoreUpdater.getCurrentVersion(), ConsoleUpdater.getCurrentVersion())
+        } catch (e: ClassNotFoundException) {
+            System.err.println("Found mirai-console file broken, re-downloading...")
+            loader.close()
+            ConsoleUpdater.getFile()?.delete()
+            WrapperCli.run()
+        }
     }
 }
 

From 1b3d60882b8c9a3e60edb44de2fcb99ac67b49e2 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Wed, 6 May 2020 15:52:03 +0800
Subject: [PATCH 7/7] wrapper 1.1.0 released

---
 README.md                            | 16 +++++++++++++++-
 buildSrc/src/main/kotlin/versions.kt |  2 +-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 477286111..37e2389a7 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,21 @@ Mirai 是一个在全平台下运行,提供 QQ Android 和 TIM PC 协议支持
 
 ### 使用
 **[下载(download)](https://github.com/mamoe/mirai-console/releases)**  
-请下载最新的 `mirai-console-wrapper-x.x.x-all.jar`
+请下载最新的 `mirai-console-wrapper-x.x.x.jar`
+
+参数
+```
+--native / -n                    以图形界面模式启动
+                                 
+--update [KEEP|STABLE|EA]        版本升级策略. "KEEP" 为停留在当前版本; "STABLE"
+                                 为更新到最新稳定版; "EA" 为更新到最新预览版.
+                                 
+--console [Graphical|Terminal|Pure]
+                                 UI 类型. "GRAPHICAL" 为 JavaFX 图形界面;
+                                 "TERMINAL" 为 Unix 终端界面; "PURE" 为纯命令行.
+                                 
+-h, --help                       显示这个帮主
+```
 
 #### 对于Windows用户
 
diff --git a/buildSrc/src/main/kotlin/versions.kt b/buildSrc/src/main/kotlin/versions.kt
index ce4102bf0..64eeb3ec6 100644
--- a/buildSrc/src/main/kotlin/versions.kt
+++ b/buildSrc/src/main/kotlin/versions.kt
@@ -14,7 +14,7 @@ object Versions {
         const val core = "1.0-RC"
         const val console = "0.5.1"
         const val consoleGraphical = "0.0.7"
-        const val consoleWrapper = "1.0.0"
+        const val consoleWrapper = "1.1.0"
     }
 
     object Kotlin {