diff --git a/packages/plugins/docs/MiaoLink.md b/packages/plugins/docs/MiaoLink.md
new file mode 100644
index 00000000..3eb952b1
--- /dev/null
+++ b/packages/plugins/docs/MiaoLink.md
@@ -0,0 +1,35 @@
+ [综合|前置]MiaoLink —— 喵式映射 用于无公网环境的自动化端口映射[1.7.10+全版本] 
+# MiaoLink
+
+## 插件介绍
+
+> 自动化端口公网映射
+
+## 图片展示
+
+- 
+
+## 使用方式
+
+- 本插件依赖于 `MiaoScript` 请前往 [站内帖子](https://www.mcbbs.net/thread-774401-1-1.html) 完成安装
+- 执行 `/mspm install MiaoLink` 安装 MiaoLink 脚本插件
+- 访问 [圈云映射](https://nps.yumc.pw) 申请一键映射指令
+- 
+- 执行网页上提供的指令 等待客户端上线
+- 
+- 使用访问地址即可链接服务器
+- 
+
+### Roadmap
+
+- 支持Bukkit端自动化映射(已完成)
+- 支持Bungee端自动化映射(开发中)
+- 支持Sponge端自动化映射(开发中)
+
+### 感谢
+
+- [NPS](https://github.com/ehang-io/nps) 开源项目
+- [蓝科数据](https://www.lankodata.com/aff.php?aff=32) 提供的映射节点
+- [AkkoCloud](https://www.akkocloud.com/aff.php?aff=698) 提供的映射节点
+
+#### 本插件所用所有代码均为原创,不存在借用/抄袭等行为
diff --git a/packages/plugins/docs/MiaoPlugin.md b/packages/plugins/docs/MiaoPlugin.md
index d31d5801..5ddb7672 100644
--- a/packages/plugins/docs/MiaoPlugin.md
+++ b/packages/plugins/docs/MiaoPlugin.md
@@ -1,5 +1,6 @@
 ### Miao系列插件
 
+- [[综合|前置]MiaoLink —— 喵式映射 用于无公网环境的自动化端口映射[全版本]](https://www.mcbbs.net/thread-1121423-1-1.html)
 - [[经济]MiaoReward —— 喵式奖励 让玩家看广告为服务器提供收入吧[1.7.10+全版本]](https://www.mcbbs.net/thread-1121423-1-1.html)
 - [[编程]MiaoBlockly —— 喵式积木 用简单的积木来写插件吧[1.12.2+全版本]](https://www.mcbbs.net/thread-1129411-1-1.html)
 - [[编程]MiaoConsole —— 喵式终端 通过MC端口直接控制服务器 调试插件[1.12.2+全版本]](https://www.mcbbs.net/thread-1129227-1-1.html)
diff --git a/packages/plugins/src/MiaoLink.ts b/packages/plugins/src/MiaoLink.ts
new file mode 100644
index 00000000..d8a8a17c
--- /dev/null
+++ b/packages/plugins/src/MiaoLink.ts
@@ -0,0 +1,155 @@
+/// 
+/// 
+/// 
+
+import { server, task } from '@ccms/api'
+import { Autowired } from '@ccms/container'
+import { Cmd, JSPlugin, Tab, interfaces, PluginConfig, Config } from '@ccms/plugin'
+
+import * as fs from '@ccms/common/dist/fs'
+import http from '@ccms/common/dist/http'
+
+import * as base64 from 'base64-js'
+
+const Runtime: typeof java.lang.Runtime = Java.type('java.lang.Runtime')
+const Thread = Java.type('java.lang.Thread')
+
+const defaultConfig = {
+    id: 0,
+    vkey: ''
+}
+
+@JSPlugin({ name: 'MiaoLink', version: '1.0.2', author: 'MiaoWoo', source: __filename })
+export class MiaoLink extends interfaces.Plugin {
+    @Autowired(task.TaskManager)
+    private task: task.TaskManager
+    @Autowired(server.Server)
+    private server: server.Server
+
+    @Config()
+    private config: PluginConfig & typeof defaultConfig = defaultConfig
+
+    private isWindows = false
+    private clientName: string = 'npc'
+    private client: string = ''
+    private port: number = 0
+    private npc: any
+
+    load() {
+        this.isWindows = process.platform == 'win32' || process.platform.toLowerCase().startsWith('windows')
+        if (this.isWindows) {
+            this.logger.console('§a当前运行于Windows服务器...')
+            this.clientName = "npc.exe"
+        } else {
+            this.logger.console('§a当前运行于Linux服务器...')
+        }
+    }
+
+    bukkitload() {
+        this.port = org.bukkit.Bukkit.getPort()
+    }
+
+    spongeload() {
+        this.logger.console('§4Sponge暂不支持端口映射!')
+    }
+
+    bungeeload() {
+        let server: net.md_5.bungee.api.ProxyServer = base.getInstance().getProxyServer()
+        this.port = server.getConfig().getListeners()[0].getQueryPort()
+    }
+
+    enable() {
+        if (!this.config.vkey) {
+            return this.logger.console('§4服务器尚未绑定 取消自动映射!')
+        }
+        this.cmdconnect(this.server.getConsoleSender())
+    }
+
+    disable() {
+        this.cmddisconnect(this.server.getConsoleSender())
+    }
+
+    @Cmd({ autoMain: true })
+    mlink() { }
+
+    cmdconnect(sender: any, secret?: string) {
+        if (secret) {
+            let configStr = String.fromCharCode(...Array.from(base64.toByteArray(secret)))
+            let config = JSON.parse(configStr)
+            this.config.id = config.id
+            this.config.vkey = config.vkey
+            this.config.save()
+        }
+        this.startClient(sender)
+    }
+
+    cmddisconnect(sender: any) {
+        if (!this.npc || !this.npc.isAlive()) {
+            return this.logger.sender(sender, '§4客户端尚未运行 跳过关闭流程...')
+        }
+        this.logger.sender(sender, '§6已发送关闭客户端指令...')
+        this.npc.destroy()
+    }
+
+    @Tab()
+    tabmlink(_sender: any, _command: string, _args: string[]) {
+    }
+
+    startClient(sender: any, id: number = this.config.id, vkey: string = this.config.vkey) {
+        if (!this.port) {
+            return this.logger.sender(sender, '§4服务器端口获取失败 取消自动映射!')
+        }
+        if (!id || !vkey) {
+            return this.logger.sender(sender, '§4服务器尚未配置 取消自动映射!')
+        }
+        if (this.npc && this.npc.isAlive()) {
+            this.npc.destroy()
+        }
+        this.task.create(() => {
+            this.logger.sender(sender, `§6获取到服务器端口: §3${this.port} §a开始映射端口!`)
+            let client = this.query(id, vkey, this.port)
+            let node = client.node
+            let tunnel = client.tunnel
+            this.client = fs.concat(__dirname, 'MiaoLink', this.clientName)
+            this.download(sender)
+            try {
+                this.npc = Runtime.getRuntime().exec(`${this.client} -server=${node.bridge} -vkey=${vkey} -type=tcp`)
+                this.logger.sender(sender, `§a服务器端口映射成功! §6访问地址: §3${node.address}:${tunnel.port}`)
+                return this.logger.console(`§4客户端已结束运行 退出代码: ${this.npc.waitFor()} 映射关闭!`)
+            } catch (error) {
+                this.logger.sender(sender, `§c服务器端口映射失败! §4ERROR: ${error}`)
+                console.ex(error)
+            }
+        }, this).async().later(5).submit()
+    }
+
+    download(sender: any) {
+        try {
+            if (!fs.exists(this.client)) {
+                this.logger.sender(sender, '§c客户端文件不存在 开始下载客户端...')
+                let temp = this.client + '.tmp'
+                http.download("https://static.c5mc.cn/" + this.clientName, temp)
+                fs.move(temp, this.client, true)
+                if (!this.isWindows) {
+                    this.logger.sender(sender, '§a当前处于Linux环境 赋予可执行权限...')
+                    Runtime.getRuntime().exec(`chmod +x ${this.client}`)
+                }
+            }
+        } catch (error) {
+            Thread.sleep(500)
+            this.download(sender)
+        }
+    }
+
+    query(id: number, vkey: string, target: number) {
+        let result = this.post(`/client?id=${id}&vkey=${vkey}&target=${target}`)
+        if (result.code != 200) {
+            throw new Error('§4客户端查询失败: ' + result.msg)
+        }
+        return result.data
+    }
+
+    post(path, data = {}) {
+        return http.post("https://nps.yumc.pw/api" + path, data)
+    }
+}
diff --git a/packages/plugins/src/MiaoPay.ts b/packages/plugins/src/MiaoPay.ts
index 0a6467cd..6d9e3736 100644
--- a/packages/plugins/src/MiaoPay.ts
+++ b/packages/plugins/src/MiaoPay.ts
@@ -73,7 +73,7 @@ const defaultConfig = {
     }
 }
 
-@JSPlugin({ version: '1.6.3', author: 'MiaoWoo', source: __filename, servers: [constants.ServerType.Bukkit], depends: ['MiaoReward'], nativeDepends: ['PlaceholderAPI', 'ProtocolLib'] })
+@JSPlugin({ version: '1.6.6', author: 'MiaoWoo', source: __filename, servers: [constants.ServerType.Bukkit], depends: ['MiaoReward'], nativeDepends: ['PlaceholderAPI', 'ProtocolLib'] })
 export class MiaoPay extends interfaces.Plugin {
     @Autowired()
     private server: server.Server
@@ -104,7 +104,11 @@ export class MiaoPay extends interfaces.Plugin {
     enable() {
         if (!this.MiaoReward) { return this.logger.error('当前脚本插件需要 MiaoReward 作为前置脚本插件!') }
         if (!this.config.id || !this.config.secret) { return this.logger.console('§4尚未配置商户信息 将无法正常收款!') }
-        let info = this.httpPost('/apps', { id: this.config.id })
+        this.initAppInfo()
+    }
+
+    private initAppInfo() {
+        let info = this.httpPost('/apps', { id: this.config.id }, 10)
         if (info.code == 200) {
             this.appInfo = info.data
             this.config.ratio = this.appInfo.ratio
@@ -114,8 +118,8 @@ export class MiaoPay extends interfaces.Plugin {
                 this.config.save()
             }
         } else {
-            this.logger.console('§4初始化支付系统失败 请检查配置是否正确!')
-            this.logger.console('§c服务器返回异常: §4' + info.msg)
+            this.logger.console('§4初始化支付系统失败 请检查配置或网络是否正常!')
+            this.logger.console('§c返回异常: §4' + info.msg)
         }
     }
 
@@ -131,14 +135,17 @@ export class MiaoPay extends interfaces.Plugin {
 
     cmdpay(sender: org.bukkit.entity.Player, amount: number = 0) {
         if (!sender.getItemInHand) { return this.logger.sender(sender, '§4控制台无法执行此命令!') }
-        if (!this.appInfo) {
-            return this.logger.sender(sender, '§4当前服务器尚未配置 请联系管理员配置MiaoPay!')
-        }
         if (!this.config.id || !this.config.secret) { return this.logger.sender(sender, '§c当前服务器尚未配置 请联系管理员配置支付密钥!') }
+        if (!this.appInfo) {
+            this.initAppInfo()
+            return this.logger.sender(sender, '§6支付系统初始化中 请稍候重试...')
+        }
         if (this.cacheMap.has(sender.getName())) {
             this.logger.sender(sender, '§c您有一笔订单尚未完成 请完成支付或等待订单超时!')
             let sync = this.cacheSyncMap.get(sender.getName())
-            if (!sync.cancelled) { return this.cacheMap.delete(sender.getName()) }
+            if (sync.scaned) { return }
+            sync.scaned = true
+            Thread.sleep(1100)
             sync.scaned = false
             sync.left = (sync.paying ? 100 : 55) - (Math.round(Date.now() / 1000) - sync.start)
             let order = this.cacheMap.get(sender.getName())
@@ -146,7 +153,7 @@ export class MiaoPay extends interfaces.Plugin {
             return
         }
         if (amount < 1) { return this.logger.sender(sender, `§c充值异常 §4充值金额不得小于 1 ${this.config.coinName}!`) }
-        if (amount / this.config.ratio > 5000) { return this.logger.sender(sender, `§c充值异常 §4充值金额不得大于 ${this.config.ratio * 5000} ${this.config.coinName}!`) }
+        if (amount / this.config.ratio > 5000) { return this.logger.sender(sender, `§c充值异常 §4充值金额不得大于 ${this.config.ratio * 3000} ${this.config.coinName}!`) }
         if (amount != Math.round(amount)) { return this.logger.sender(sender, `§c充值异常 §4充值金额必须为整数!`) }
         try {
             this.getPlayerAmount(sender)
@@ -341,15 +348,15 @@ export class MiaoPay extends interfaces.Plugin {
     }
 
     private preFinishOrder(id: string) {
-        return this.httpPost('/preFinish', { id }, true)
+        return this.httpPost('/preFinish', { id }, 3)
     }
 
     private errorOrder(id: string, error: string) {
-        return this.httpPost('/error', { id, error }, true)
+        return this.httpPost('/error', { id, error }, 3)
     }
 
     private finishOrder(id: string) {
-        return this.httpPost('/finish', { id }, true)
+        return this.httpPost('/finish', { id }, 3)
     }
 
     private createOrder(sender: org.bukkit.entity.Player, amount: number): Order {
@@ -368,14 +375,14 @@ export class MiaoPay extends interfaces.Plugin {
     }
 
     private queryOrder(id: string, username: string, uuid: string) {
-        return this.httpPost('/query', { id, username, uuid })
+        return this.httpPost('/query', { id, username, uuid }, 2)
     }
 
     private queryUnconverted(username: string, force: number) {
-        return this.httpPost('/unconverted', { username, force })
+        return this.httpPost('/unconverted', { username, force }, 2)
     }
 
-    private httpPost(method: string, data: any, retry = false) {
+    private httpPost(method: string, data: any, retry = 0) {
         let startTime = Date.now()
         data.appid = this.config.id
         data.timestamp = Math.round(Date.now() / 1000)
@@ -393,11 +400,12 @@ CAST TIME   : ${Date.now() - startTime}`)
             return result
         } catch (error) {
             if (retry) {
-                return this.httpPost(method, data)
-            } else {
-                console.console('§4请求支付中心发生异常 请联系管理员处理此问题!')
-                console.ex(error)
+                Thread.sleep(retry * 10)
+                return this.httpPost(method, data, --retry)
             }
+            console.console('§4请求支付中心发生异常 请联系管理员处理此问题!')
+            console.ex(error)
+            return { code: 500, msg: '本地网络错误: ' + error.message, data: error }
         }
     }
 
diff --git a/packages/plugins/src/MiaoReward.ts b/packages/plugins/src/MiaoReward.ts
index 4cda0f5f..773ca781 100644
--- a/packages/plugins/src/MiaoReward.ts
+++ b/packages/plugins/src/MiaoReward.ts
@@ -663,6 +663,7 @@ export class MiaoReward extends interfaces.Plugin {
             sync.cancelled = false
             let task = this.taskManager.create(() => {
                 try {
+                    console.log(JSON.stringify(sync))
                     if (sync.scaned || !sender.isOnline() || !this.isHoldQrCodeItem(sender) || --sync.left < 0) {
                         if (sync.left < 0) {
                             this.logger.sender(sender, '§c二维码已过期 请重新获取 如已扫码请忽略!')
diff --git a/packages/plugins/src/MiaoRobot.ts b/packages/plugins/src/MiaoRobot.ts
index 6612333b..0abdd1f0 100644
--- a/packages/plugins/src/MiaoRobot.ts
+++ b/packages/plugins/src/MiaoRobot.ts
@@ -1,41 +1,152 @@
 /// 
 /// 
 /// 
-/// 
-// @ts-ignore
-require.clear('websocket/client')
-import { server } from '@ccms/api'
-import { Autowired, Container, ContainerInstance } from '@ccms/container'
-import { Cmd, JSPlugin, Tab, interfaces, PluginConfig, Config } from '@ccms/plugin'
+
+import { EventEmitter } from 'events'
+
+import { constants, server } from '@ccms/api'
+import { Autowired, JSClass } from '@ccms/container'
+import { Cmd, JSPlugin, Tab, interfaces, PluginConfig, Config, Listener } from '@ccms/plugin'
 import { WebSocket } from '@ccms/websocket'
 
+const Thread = Java.type('java.lang.Thread')
+const ChatColor = Java.type('org.bukkit.ChatColor')
+
 const defaultConfig = {
+    version: 1,
     address: '',
-    token: ''
+    token: '',
+    group_id: '',
+    admin_id: '',
+    message: {
+        join: "玩家: %player_name% 加入了服务器!",
+        quit: "玩家: %player_name% 退出了服务器!",
+        chat: "%player_name%: ",
+        group: "&6[&c服务器群&6] &b%sender_nickname%&6(&a%sender_user_id%&6)&r: "
+    }
 }
-//https://github3.mk-proxy.ml/-----https://github.com/Mrs4s/go-cqhttp/releases/download/v0.9.34/go-cqhttp-v0.9.34-linux-amd64
-@JSPlugin({ version: '1.0.0', author: 'MiaoWoo', source: __filename })
+
+interface RobotConfig {
+    address: string,
+    token: string,
+    timeout: number
+}
+
+interface PlaceholderAPI {
+    registerPlaceholderHook: (key: string, onPlaceholderRequest: (player, s) => string) => void
+    unregisterPlaceholderHook: (key: string) => void
+    setPlaceholders: (player: any, str: string) => string
+}
+
+class Robot extends EventEmitter {
+    private config: RobotConfig
+
+    private websocket: WebSocket
+
+    private invokeCount = 1;
+    private apiResultCache = [];
+
+    constructor(config: RobotConfig) {
+        super()
+        this.config = config
+    }
+
+    sleep(ms) {
+        Thread.sleep(ms)
+    }
+
+    invoke(action, params) {
+        if (this.websocket.readyState != WebSocket.OPEN) { throw new Error('client not connect!') }
+        let startTime: number = new Date().getTime()
+        let request = { action, params, echo: this.invokeCount++ }
+        this.websocket.send(JSON.stringify(request))
+        while (startTime + this.config.timeout > new Date().getTime()) {
+            if (this.apiResultCache[request.echo]) {
+                let result = this.apiResultCache[request.echo]
+                delete this.apiResultCache[request.echo]
+                if ((result.status === "ok" && result.retcode !== 0) && (result.status === "async" && result !== 1)) {
+                    throw Error(`Invoke API Error! Response ${JSON.stringify(result)}`)
+                }
+                return result.data
+            }
+            this.sleep(50)
+        }
+        throw Error(`Invoke API Timeout! Request ${JSON.stringify(request)}`)
+    }
+
+    connect() {
+        this.websocket = new WebSocket(this.config.address, '', { Authorization: `Bearer ${this.config.token}` })
+        this.websocket.onopen = () => {
+            this.emit('connect')
+        }
+        this.websocket.onmessage = (event) => {
+            let robotEvent = JSON.parse(event.data)
+            if (robotEvent.post_type == "meta_event") { return }
+            if (robotEvent.post_type) {
+                this.emit(robotEvent.post_type, robotEvent)
+            }
+        }
+        this.websocket.onclose = (event) => {
+            this.emit('close', event)
+        }
+        this.websocket.onerror = (event) => {
+            this.emit('error', event)
+        }
+    }
+
+    disconnect(reason = '') {
+        if (this.websocket) {
+            this.websocket.close(0, reason)
+        }
+    }
+
+    sendGroupMessage(group_id, message) {
+        this.websocket.send(JSON.stringify({
+            action: "send_msg",
+            params: { group_id, message }
+        }))
+    }
+
+    sendPrivateMessage(user_id, message) {
+        this.websocket.send(JSON.stringify({
+            action: "send_msg",
+            params: { user_id, message }
+        }))
+    }
+}
+
+@JSPlugin({ version: '1.0.0', author: 'MiaoWoo', servers: [constants.ServerType.Bukkit], source: __filename, nativeDepends: ['PlaceholderAPI'] })
 export class MiaoRobot extends interfaces.Plugin {
     @Autowired()
     private server: server.Server
 
-    private client: WebSocket
+    @JSClass('me.clip.placeholderapi.PlaceholderAPI')
+    private PlaceholderAPI: PlaceholderAPI
+
+    private robot: Robot
 
     @Config()
     private config: PluginConfig & typeof defaultConfig = defaultConfig
 
     load() {
-    }
-
-    private downloadRobot() {
-        //https://api.github.com/repos/Mrs4s/go-cqhttp/releases?per_page=1&page=1
+        this.logger.prefix = ''
     }
 
     enable() {
+        if (this.config.address && this.config.token) {
+            this.cmdconnect(this.server.getConsoleSender())
+            if (!this.config.group_id) {
+                this.logger.console('§c机器人尚未配置绑定服务器群 部分功能将无法使用!')
+            }
+        } else {
+            this.logger.console('§c机器人尚未配置 请参照帖子内容配置机器人!')
+        }
     }
 
     disable() {
-        this.cmdclose(this.server.getConsoleSender())
+        if (this.robot) {
+            this.cmdclose(this.server.getConsoleSender())
+        }
     }
 
     @Cmd({ autoMain: true })
@@ -46,50 +157,64 @@ export class MiaoRobot extends interfaces.Plugin {
             return this.logger.sender(sender, '§4错误 请配置服务器地址和Token!')
         }
         this.cmdclose(sender)
-        try {
-            this.client = new WebSocket(address, '', { Authorization: `Bearer ${token}` })
-            this.initRobot(this.client)
-        } catch (error) {
-            console.ex(error)
-        }
+        this.initRobot(sender)
     }
 
-    private initRobot(client: WebSocket) {
-        client.onopen = () => {
-            this.logger.console(`§3连接到 §b${client.url} §a成功!`)
-        }
-        client.onmessage = (event) => {
-            let messageEvent = JSON.parse(event.data)
-            switch (messageEvent.post_type) {
-                case "message":
-                    this.logger.console(`§6接收到 §3群 §b${messageEvent.group_id} §2成员 §a${messageEvent.sender.nickname} §6的消息: §r${messageEvent.message}`)
-                    break
+    initRobot(sender) {
+        this.robot = new Robot({ ...this.config, timeout: 60 })
+        this.robot.on('connect', () => {
+            this.logger.sender(sender, '§a机器人链接成功!')
+        })
+        this.robot.on('message', (event) => {
+            if (event.message_type == "group" && event.group_id == this.config.group_id) {
+                let message: string = event.message
+                message = message.replace(/.*\[CQ:image\,file=(.*),url=(.*),.*]/g, '[图片]')
+                message = this.config.message.group
+                    .replace(/%sender_nickname%/g, event.sender.nickname)
+                    .replace(/%sender_card%/g, event.sender.card)
+                    .replace(/%sender_title%/g, event.sender.title)
+                    .replace(/%sender_user_id%/g, event.sender.user_id) + message
+                message = ChatColor.translateAlternateColorCodes('&', message)
+                this.server.getOnlinePlayers().forEach(p => this.logger.sender(p, message))
+                this.logger.console(message)
             }
-        }
-        client.onclose = (event) => {
-            this.logger.console(`§4连接已断开 §6Code: §3${event.code} §6原因: §c${event.reason}!`)
-        }
-        client.onerror = (event) => {
-            this.logger.console(`§4发生错误: §r${event.error}`)
-            console.ex(event.error)
-        }
+        })
+        this.robot.connect()
     }
 
     cmdclose(sender: org.bukkit.entity.Player) {
-        if (this.client && this.client.readyState != WebSocket.CLOSED) {
-            this.client.close(0, 'plugin close socket')
+        if (this.robot) {
+            this.robot.disconnect()
+            this.logger.sender(sender, '§c机器人已断开链接!')
         }
     }
 
     cmdsend(sender: org.bukkit.entity.Player, text: string) {
-        if (this.client) {
-            this.client.send(text)
-            this.logger.sender(sender, '§a发送成功!')
-        }
+        this?.robot.sendGroupMessage(this.config.group_id, text)
+        this.logger.sender(sender, '§a发送成功!')
     }
 
     @Tab()
     tabmbot(_sender: any, _command: string, _args: string[]) {
         return []
     }
+
+    @Listener()
+    private PlayerJoinEvent(event: org.bukkit.event.player.PlayerJoinEvent) {
+        if (this.robot && this.config.group_id) {
+            this.robot.sendGroupMessage(this.config.group_id, this.PlaceholderAPI.setPlaceholders(event.getPlayer(), this.config.message.join))
+        }
+    }
+    @Listener()
+    private PlayerQuitEvent(event: org.bukkit.event.player.PlayerQuitEvent) {
+        if (this.robot && this.config.group_id) {
+            this.robot.sendGroupMessage(this.config.group_id, this.PlaceholderAPI.setPlaceholders(event.getPlayer(), this.config.message.quit))
+        }
+    }
+    @Listener()
+    private AsyncPlayerChatEvent(event: org.bukkit.event.player.AsyncPlayerChatEvent) {
+        if (this.robot && this.config.group_id) {
+            this.robot.sendGroupMessage(this.config.group_id, this.PlaceholderAPI.setPlaceholders(event.getPlayer(), this.config.message.chat) + event.getMessage())
+        }
+    }
 }
diff --git a/packages/plugins/src/MiaoScriptPackageManager.ts b/packages/plugins/src/MiaoScriptPackageManager.ts
index 00e938df..b827b857 100644
--- a/packages/plugins/src/MiaoScriptPackageManager.ts
+++ b/packages/plugins/src/MiaoScriptPackageManager.ts
@@ -479,7 +479,7 @@ return eval(${JSON.stringify(code)});`)
         return tfunc.apply(_this, params)
     }
 
-    cmddeploy(sender: string, name: string, changelog: string) {
+    cmddeploy(sender: string, name: string, changelog: string = '') {
         if (!process.env.AccessToken) { return this.i18n(sender, 'deploy.token.not.exists') }
         this.taskManager.create(() => {
             if (this.checkPlugin(sender, name)) {
@@ -544,9 +544,9 @@ return eval(${JSON.stringify(code)});`)
             for (const pl of result.data) { this.packageCache[pl.name] = pl }
             this.packageNameCache = Object.keys(this.packageCache)
             this.i18n(sender, 'cloud.update.finish', { length: this.packageNameCache.length })
+            let updateCount = 0
             this.pluginManager.getPlugins().forEach(p => {
                 let cloudPlugin = this.packageCache[p.description.name]
-                let updateCount = 0
                 //§6插件名称: §b{name}\n§6版本: §a{version}\n§6作者: §3{author}\§6更新时间: §9{updated_at}
                 if (cloudPlugin && cloudPlugin.version != p.description.version) {
                     this.i18n(sender, 'cloud.update.exists', {
@@ -557,10 +557,10 @@ return eval(${JSON.stringify(code)});`)
                     })
                     updateCount++
                 }
-                if (updateCount) {
-                    this.i18n(sender, 'cloud.update.tip', { count: updateCount })
-                }
             })
+            if (updateCount) {
+                this.i18n(sender, 'cloud.update.tip', { count: updateCount })
+            }
         }).async().submit()
     }
 
@@ -570,7 +570,7 @@ return eval(${JSON.stringify(code)});`)
             this.i18n(sender, 'download.start', { name, version: pluginPkg.version })
             this.i18n(sender, 'download.url', { url: pluginPkg.url })
             let pluginFile = update ? fs.concat(root, this.pluginFolder, 'update', name + '.js') : fs.concat(root, this.pluginFolder, name + '.js')
-            http.download(pluginPkg.url, pluginFile)
+            http.download(pluginPkg.url + '?t=' + Date.now(), pluginFile)
             this.i18n(sender, 'download.finish', { name, version: pluginPkg.version })
             callback?.()
         }).async().submit()