diff --git a/manifest.json b/manifest.json
index 40d1838..b518373 100644
--- a/manifest.json
+++ b/manifest.json
@@ -4,7 +4,7 @@
   "name": "LLOneBot",
   "slug": "LLOneBot",
   "description": "实现 OneBot 11 和 Satori 协议,用于 QQ 机器人开发",
-  "version": "4.0.9",
+  "version": "4.0.10",
   "icon": "./icon.webp",
   "authors": [
     {
diff --git a/package.json b/package.json
index 28b726d..4291466 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,7 @@
     "deploy-win": "cmd /c \"xcopy /C /S /Y dist\\* %LITELOADERQQNT_PROFILE%\\plugins\\LLOneBot\\\"",
     "format": "prettier -cw .",
     "check": "tsc",
-    "compile:proto": "pbjs --no-create --no-convert --no-encode --no-verify -t static-module -w es6 -p src/ntqqapi/proto -o src/ntqqapi/proto/compiled.js systemMessage.proto profileLikeTip.proto && pbts -o src/ntqqapi/proto/compiled.d.ts src/ntqqapi/proto/compiled.js"
+    "compile:proto": "pbjs --no-create --no-convert --no-encode --no-verify -t static-module -w es6 -p src/ntqqapi/proto -o src/ntqqapi/proto/compiled.js systemMessage.proto profileLikeTip.proto groupMemberIncrease.proto && pbts -o src/ntqqapi/proto/compiled.d.ts src/ntqqapi/proto/compiled.js"
   },
   "author": "",
   "license": "MIT",
@@ -43,7 +43,7 @@
     "electron-vite": "^2.3.0",
     "protobufjs-cli": "^1.1.3",
     "typescript": "^5.6.3",
-    "vite": "^5.4.8",
+    "vite": "^5.4.9",
     "vite-plugin-cp": "^4.0.8"
   },
   "packageManager": "yarn@4.5.0"
diff --git a/src/common/channels.ts b/src/common/channels.ts
index e183524..2119cd1 100644
--- a/src/common/channels.ts
+++ b/src/common/channels.ts
@@ -1,6 +1,5 @@
 export const CHANNEL_GET_CONFIG = 'llonebot_get_config'
 export const CHANNEL_SET_CONFIG = 'llonebot_set_config'
-export const CHANNEL_SET_CONFIG_CONFIRMED = 'llonebot_set_config_confirmed'
 export const CHANNEL_LOG = 'llonebot_log'
 export const CHANNEL_ERROR = 'llonebot_error'
 export const CHANNEL_UPDATE = 'llonebot_update'
diff --git a/src/common/config.ts b/src/common/config.ts
index 78749de..f7ec98e 100644
--- a/src/common/config.ts
+++ b/src/common/config.ts
@@ -50,7 +50,7 @@ export class ConfigUtil {
       token: '',
       enableLocalFile2Url: false,
       debug: false,
-      log: false,
+      log: true,
       autoDeleteFile: false,
       autoDeleteFileSecond: 60,
       musicSignUrl: '',
diff --git a/src/main/main.ts b/src/main/main.ts
index 3166402..356b81d 100644
--- a/src/main/main.ts
+++ b/src/main/main.ts
@@ -15,8 +15,7 @@ import {
   CHANNEL_LOG,
   CHANNEL_SELECT_FILE,
   CHANNEL_SET_CONFIG,
-  CHANNEL_UPDATE,
-  CHANNEL_SET_CONFIG_CONFIRMED
+  CHANNEL_UPDATE
 } from '../common/channels'
 import { startHook } from '../ntqqapi/hook'
 import { checkNewVersion, upgradeLLOneBot } from '../common/utils/upgrade'
@@ -35,7 +34,6 @@ import {
   NTQQWebApi,
   NTQQWindowApi
 } from '../ntqqapi/api'
-import { mkdir } from 'node:fs/promises'
 import { existsSync, mkdirSync } from 'node:fs'
 
 declare module 'cordis' {
@@ -56,6 +54,29 @@ function onLoad() {
     mkdirSync(LOG_DIR)
   }
 
+  if (!existsSync(TEMP_DIR)) {
+    mkdirSync(TEMP_DIR)
+  }
+
+  const dbDir = path.join(DATA_DIR, 'database')
+  if (!existsSync(dbDir)) {
+    mkdirSync(dbDir)
+  }
+
+  const ctx = new Context()
+
+  ctx.plugin(NTQQFileApi)
+  ctx.plugin(NTQQFileCacheApi)
+  ctx.plugin(NTQQFriendApi)
+  ctx.plugin(NTQQGroupApi)
+  ctx.plugin(NTQQMsgApi)
+  ctx.plugin(NTQQUserApi)
+  ctx.plugin(NTQQWebApi)
+  ctx.plugin(NTQQWindowApi)
+  ctx.plugin(Database)
+
+  let started = false
+
   ipcMain.handle(CHANNEL_CHECK_VERSION, async () => {
     return checkNewVersion()
   })
@@ -114,7 +135,9 @@ function onLoad() {
       if (!ask) {
         getConfigUtil().setConfig(config)
         log('配置已更新', config)
-        checkFfmpeg(config.ffmpeg).then()
+        if (started) {
+          ctx.parallel('llob/config-updated', config)
+        }
         resolve(true)
         return
       }
@@ -131,7 +154,9 @@ function onLoad() {
           if (result.response === 0) {
             getConfigUtil().setConfig(config)
             log('配置已更新', config)
-            checkFfmpeg(config.ffmpeg).then()
+            if (started) {
+              ctx.parallel('llob/config-updated', config)
+            }
             resolve(true)
           }
         })
@@ -146,61 +171,6 @@ function onLoad() {
     log(arg)
   })
 
-  async function start() {
-    log('process pid', process.pid)
-    const config = getConfigUtil().getConfig()
-    if (!existsSync(TEMP_DIR)) {
-      await mkdir(TEMP_DIR)
-    }
-    const dbDir = path.join(DATA_DIR, 'database')
-    if (!existsSync(dbDir)) {
-      await mkdir(dbDir)
-    }
-    const ctx = new Context()
-    ctx.plugin(Log, {
-      enable: config.log!,
-      filename: logFileName
-    })
-    ctx.plugin(NTQQFileApi)
-    ctx.plugin(NTQQFileCacheApi)
-    ctx.plugin(NTQQFriendApi)
-    ctx.plugin(NTQQGroupApi)
-    ctx.plugin(NTQQMsgApi)
-    ctx.plugin(NTQQUserApi)
-    ctx.plugin(NTQQWebApi)
-    ctx.plugin(NTQQWindowApi)
-    ctx.plugin(Core, config)
-    ctx.plugin(Database)
-    ctx.plugin(SQLiteDriver, {
-      path: path.join(dbDir, `${selfInfo.uin}.db`)
-    })
-    ctx.plugin(Store, {
-      msgCacheExpire: config.msgCacheExpire! * 1000
-    })
-    if (config.ob11.enable) {
-      ctx.plugin(OneBot11Adapter, {
-        ...config.ob11,
-        heartInterval: config.heartInterval,
-        token: config.token!,
-        debug: config.debug!,
-        musicSignUrl: config.musicSignUrl,
-        enableLocalFile2Url: config.enableLocalFile2Url!,
-        ffmpeg: config.ffmpeg,
-      })
-    }
-    if (config.satori.enable) {
-      ctx.plugin(SatoriAdapter, {
-        ...config.satori,
-        ffmpeg: config.ffmpeg,
-      })
-    }
-    ctx.start()
-    llonebotError.otherError = ''
-    ipcMain.on(CHANNEL_SET_CONFIG_CONFIRMED, (event, config: LLOBConfig) => {
-      ctx.parallel('llob/config-updated', config)
-    })
-  }
-
   const intervalId = setInterval(() => {
     const self = Object.assign(selfInfo, {
       uin: globalThis.authData?.uin,
@@ -209,7 +179,41 @@ function onLoad() {
     })
     if (self.uin) {
       clearInterval(intervalId)
-      start()
+      log('process pid', process.pid)
+
+      const config = getConfigUtil().getConfig()
+      ctx.plugin(Log, {
+        enable: config.log!,
+        filename: logFileName
+      })
+      ctx.plugin(SQLiteDriver, {
+        path: path.join(dbDir, `${selfInfo.uin}.db`)
+      })
+      ctx.plugin(Store, {
+        msgCacheExpire: config.msgCacheExpire! * 1000
+      })
+      ctx.plugin(Core, config)
+      if (config.ob11.enable) {
+        ctx.plugin(OneBot11Adapter, {
+          ...config.ob11,
+          heartInterval: config.heartInterval,
+          token: config.token!,
+          debug: config.debug!,
+          musicSignUrl: config.musicSignUrl,
+          enableLocalFile2Url: config.enableLocalFile2Url!,
+          ffmpeg: config.ffmpeg,
+        })
+      }
+      if (config.satori.enable) {
+        ctx.plugin(SatoriAdapter, {
+          ...config.satori,
+          ffmpeg: config.ffmpeg,
+        })
+      }
+
+      ctx.start()
+      started = true
+      llonebotError.otherError = ''
     }
   }, 600)
 }
diff --git a/src/ntqqapi/proto/compiled.d.ts b/src/ntqqapi/proto/compiled.d.ts
index ee5b5f7..3d6e972 100644
--- a/src/ntqqapi/proto/compiled.d.ts
+++ b/src/ntqqapi/proto/compiled.d.ts
@@ -64,11 +64,8 @@ export namespace SysMsg {
     /** Properties of a SystemMessageHeader. */
     interface ISystemMessageHeader {
 
-        /** SystemMessageHeader peerNumber */
-        peerNumber?: (number|null);
-
-        /** SystemMessageHeader peerString */
-        peerString?: (string|null);
+        /** SystemMessageHeader peerUin */
+        peerUin?: (number|null);
 
         /** SystemMessageHeader uin */
         uin?: (number|null);
@@ -86,11 +83,8 @@ export namespace SysMsg {
          */
         constructor(properties?: SysMsg.ISystemMessageHeader);
 
-        /** SystemMessageHeader peerNumber. */
-        public peerNumber: number;
-
-        /** SystemMessageHeader peerString. */
-        public peerString: string;
+        /** SystemMessageHeader peerUin. */
+        public peerUin: number;
 
         /** SystemMessageHeader uin. */
         public uin: number;
@@ -160,10 +154,10 @@ export namespace SysMsg {
         public msgType: number;
 
         /** SystemMessageMsgSpec subType. */
-        public subType: number;
+        public subType?: (number|null);
 
         /** SystemMessageMsgSpec subSubType. */
-        public subSubType: number;
+        public subSubType?: (number|null);
 
         /** SystemMessageMsgSpec msgSeq. */
         public msgSeq: number;
@@ -172,7 +166,7 @@ export namespace SysMsg {
         public time: number;
 
         /** SystemMessageMsgSpec other. */
-        public other: number;
+        public other?: (number|null);
 
         /**
          * Decodes a SystemMessageMsgSpec message from the specified reader or buffer.
@@ -466,4 +460,68 @@ export namespace SysMsg {
          */
         public static getTypeUrl(typeUrlPrefix?: string): string;
     }
+
+    /** Properties of a GroupMemberIncrease. */
+    interface IGroupMemberIncrease {
+
+        /** GroupMemberIncrease groupCode */
+        groupCode?: (number|null);
+
+        /** GroupMemberIncrease memberUid */
+        memberUid?: (string|null);
+
+        /** GroupMemberIncrease type */
+        type?: (number|null);
+
+        /** GroupMemberIncrease adminUid */
+        adminUid?: (string|null);
+    }
+
+    /** Represents a GroupMemberIncrease. */
+    class GroupMemberIncrease implements IGroupMemberIncrease {
+
+        /**
+         * Constructs a new GroupMemberIncrease.
+         * @param [properties] Properties to set
+         */
+        constructor(properties?: SysMsg.IGroupMemberIncrease);
+
+        /** GroupMemberIncrease groupCode. */
+        public groupCode: number;
+
+        /** GroupMemberIncrease memberUid. */
+        public memberUid: string;
+
+        /** GroupMemberIncrease type. */
+        public type: number;
+
+        /** GroupMemberIncrease adminUid. */
+        public adminUid: string;
+
+        /**
+         * Decodes a GroupMemberIncrease message from the specified reader or buffer.
+         * @param reader Reader or buffer to decode from
+         * @param [length] Message length if known beforehand
+         * @returns GroupMemberIncrease
+         * @throws {Error} If the payload is not a reader or valid buffer
+         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+         */
+        public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): SysMsg.GroupMemberIncrease;
+
+        /**
+         * Decodes a GroupMemberIncrease message from the specified reader or buffer, length delimited.
+         * @param reader Reader or buffer to decode from
+         * @returns GroupMemberIncrease
+         * @throws {Error} If the payload is not a reader or valid buffer
+         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+         */
+        public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): SysMsg.GroupMemberIncrease;
+
+        /**
+         * Gets the default type url for GroupMemberIncrease
+         * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+         * @returns The default type url
+         */
+        public static getTypeUrl(typeUrlPrefix?: string): string;
+    }
 }
diff --git a/src/ntqqapi/proto/compiled.js b/src/ntqqapi/proto/compiled.js
index 6cbe19c..1f0f50b 100644
--- a/src/ntqqapi/proto/compiled.js
+++ b/src/ntqqapi/proto/compiled.js
@@ -150,8 +150,7 @@ export const SysMsg = $root.SysMsg = (() => {
          * Properties of a SystemMessageHeader.
          * @memberof SysMsg
          * @interface ISystemMessageHeader
-         * @property {number|null} [peerNumber] SystemMessageHeader peerNumber
-         * @property {string|null} [peerString] SystemMessageHeader peerString
+         * @property {number|null} [peerUin] SystemMessageHeader peerUin
          * @property {number|null} [uin] SystemMessageHeader uin
          * @property {string|null} [uid] SystemMessageHeader uid
          */
@@ -172,20 +171,12 @@ export const SysMsg = $root.SysMsg = (() => {
         }
 
         /**
-         * SystemMessageHeader peerNumber.
-         * @member {number} peerNumber
+         * SystemMessageHeader peerUin.
+         * @member {number} peerUin
          * @memberof SysMsg.SystemMessageHeader
          * @instance
          */
-        SystemMessageHeader.prototype.peerNumber = 0;
-
-        /**
-         * SystemMessageHeader peerString.
-         * @member {string} peerString
-         * @memberof SysMsg.SystemMessageHeader
-         * @instance
-         */
-        SystemMessageHeader.prototype.peerString = "";
+        SystemMessageHeader.prototype.peerUin = 0;
 
         /**
          * SystemMessageHeader uin.
@@ -231,11 +222,7 @@ export const SysMsg = $root.SysMsg = (() => {
                 let tag = reader.uint32();
                 switch (tag >>> 3) {
                 case 1: {
-                        message.peerNumber = reader.uint32();
-                        break;
-                    }
-                case 2: {
-                        message.peerString = reader.string();
+                        message.peerUin = reader.uint32();
                         break;
                     }
                 case 5: {
@@ -327,19 +314,19 @@ export const SysMsg = $root.SysMsg = (() => {
 
         /**
          * SystemMessageMsgSpec subType.
-         * @member {number} subType
+         * @member {number|null|undefined} subType
          * @memberof SysMsg.SystemMessageMsgSpec
          * @instance
          */
-        SystemMessageMsgSpec.prototype.subType = 0;
+        SystemMessageMsgSpec.prototype.subType = null;
 
         /**
          * SystemMessageMsgSpec subSubType.
-         * @member {number} subSubType
+         * @member {number|null|undefined} subSubType
          * @memberof SysMsg.SystemMessageMsgSpec
          * @instance
          */
-        SystemMessageMsgSpec.prototype.subSubType = 0;
+        SystemMessageMsgSpec.prototype.subSubType = null;
 
         /**
          * SystemMessageMsgSpec msgSeq.
@@ -359,11 +346,32 @@ export const SysMsg = $root.SysMsg = (() => {
 
         /**
          * SystemMessageMsgSpec other.
-         * @member {number} other
+         * @member {number|null|undefined} other
          * @memberof SysMsg.SystemMessageMsgSpec
          * @instance
          */
-        SystemMessageMsgSpec.prototype.other = 0;
+        SystemMessageMsgSpec.prototype.other = null;
+
+        // OneOf field names bound to virtual getters and setters
+        let $oneOfFields;
+
+        // Virtual OneOf for proto3 optional field
+        Object.defineProperty(SystemMessageMsgSpec.prototype, "_subType", {
+            get: $util.oneOfGetter($oneOfFields = ["subType"]),
+            set: $util.oneOfSetter($oneOfFields)
+        });
+
+        // Virtual OneOf for proto3 optional field
+        Object.defineProperty(SystemMessageMsgSpec.prototype, "_subSubType", {
+            get: $util.oneOfGetter($oneOfFields = ["subSubType"]),
+            set: $util.oneOfSetter($oneOfFields)
+        });
+
+        // Virtual OneOf for proto3 optional field
+        Object.defineProperty(SystemMessageMsgSpec.prototype, "_other", {
+            get: $util.oneOfGetter($oneOfFields = ["other"]),
+            set: $util.oneOfSetter($oneOfFields)
+        });
 
         /**
          * Decodes a SystemMessageMsgSpec message from the specified reader or buffer.
@@ -1007,6 +1015,141 @@ export const SysMsg = $root.SysMsg = (() => {
         return ProfileLikeTip;
     })();
 
+    SysMsg.GroupMemberIncrease = (function() {
+
+        /**
+         * Properties of a GroupMemberIncrease.
+         * @memberof SysMsg
+         * @interface IGroupMemberIncrease
+         * @property {number|null} [groupCode] GroupMemberIncrease groupCode
+         * @property {string|null} [memberUid] GroupMemberIncrease memberUid
+         * @property {number|null} [type] GroupMemberIncrease type
+         * @property {string|null} [adminUid] GroupMemberIncrease adminUid
+         */
+
+        /**
+         * Constructs a new GroupMemberIncrease.
+         * @memberof SysMsg
+         * @classdesc Represents a GroupMemberIncrease.
+         * @implements IGroupMemberIncrease
+         * @constructor
+         * @param {SysMsg.IGroupMemberIncrease=} [properties] Properties to set
+         */
+        function GroupMemberIncrease(properties) {
+            if (properties)
+                for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                    if (properties[keys[i]] != null)
+                        this[keys[i]] = properties[keys[i]];
+        }
+
+        /**
+         * GroupMemberIncrease groupCode.
+         * @member {number} groupCode
+         * @memberof SysMsg.GroupMemberIncrease
+         * @instance
+         */
+        GroupMemberIncrease.prototype.groupCode = 0;
+
+        /**
+         * GroupMemberIncrease memberUid.
+         * @member {string} memberUid
+         * @memberof SysMsg.GroupMemberIncrease
+         * @instance
+         */
+        GroupMemberIncrease.prototype.memberUid = "";
+
+        /**
+         * GroupMemberIncrease type.
+         * @member {number} type
+         * @memberof SysMsg.GroupMemberIncrease
+         * @instance
+         */
+        GroupMemberIncrease.prototype.type = 0;
+
+        /**
+         * GroupMemberIncrease adminUid.
+         * @member {string} adminUid
+         * @memberof SysMsg.GroupMemberIncrease
+         * @instance
+         */
+        GroupMemberIncrease.prototype.adminUid = "";
+
+        /**
+         * Decodes a GroupMemberIncrease message from the specified reader or buffer.
+         * @function decode
+         * @memberof SysMsg.GroupMemberIncrease
+         * @static
+         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+         * @param {number} [length] Message length if known beforehand
+         * @returns {SysMsg.GroupMemberIncrease} GroupMemberIncrease
+         * @throws {Error} If the payload is not a reader or valid buffer
+         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+         */
+        GroupMemberIncrease.decode = function decode(reader, length) {
+            if (!(reader instanceof $Reader))
+                reader = $Reader.create(reader);
+            let end = length === undefined ? reader.len : reader.pos + length, message = new $root.SysMsg.GroupMemberIncrease();
+            while (reader.pos < end) {
+                let tag = reader.uint32();
+                switch (tag >>> 3) {
+                case 1: {
+                        message.groupCode = reader.uint32();
+                        break;
+                    }
+                case 3: {
+                        message.memberUid = reader.string();
+                        break;
+                    }
+                case 4: {
+                        message.type = reader.uint32();
+                        break;
+                    }
+                case 5: {
+                        message.adminUid = reader.string();
+                        break;
+                    }
+                default:
+                    reader.skipType(tag & 7);
+                    break;
+                }
+            }
+            return message;
+        };
+
+        /**
+         * Decodes a GroupMemberIncrease message from the specified reader or buffer, length delimited.
+         * @function decodeDelimited
+         * @memberof SysMsg.GroupMemberIncrease
+         * @static
+         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+         * @returns {SysMsg.GroupMemberIncrease} GroupMemberIncrease
+         * @throws {Error} If the payload is not a reader or valid buffer
+         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+         */
+        GroupMemberIncrease.decodeDelimited = function decodeDelimited(reader) {
+            if (!(reader instanceof $Reader))
+                reader = new $Reader(reader);
+            return this.decode(reader, reader.uint32());
+        };
+
+        /**
+         * Gets the default type url for GroupMemberIncrease
+         * @function getTypeUrl
+         * @memberof SysMsg.GroupMemberIncrease
+         * @static
+         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+         * @returns {string} The default type url
+         */
+        GroupMemberIncrease.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+            if (typeUrlPrefix === undefined) {
+                typeUrlPrefix = "type.googleapis.com";
+            }
+            return typeUrlPrefix + "/SysMsg.GroupMemberIncrease";
+        };
+
+        return GroupMemberIncrease;
+    })();
+
     return SysMsg;
 })();
 
diff --git a/src/ntqqapi/proto/groupMemberIncrease.proto b/src/ntqqapi/proto/groupMemberIncrease.proto
new file mode 100644
index 0000000..8b6a0bc
--- /dev/null
+++ b/src/ntqqapi/proto/groupMemberIncrease.proto
@@ -0,0 +1,10 @@
+syntax = "proto3";
+package SysMsg;
+
+// GroupChange?
+message GroupMemberIncrease {
+  uint32 groupCode = 1;
+  string memberUid = 3;
+  uint32 type = 4;  // 130:主动 131:被邀请
+  string adminUid = 5;
+}
diff --git a/src/ntqqapi/proto/systemMessage.proto b/src/ntqqapi/proto/systemMessage.proto
index 08f9dc3..13cdb9b 100644
--- a/src/ntqqapi/proto/systemMessage.proto
+++ b/src/ntqqapi/proto/systemMessage.proto
@@ -8,23 +8,22 @@ message SystemMessage {
 }
 
 message SystemMessageHeader {
-  uint32 peerNumber = 1;
-  string peerString = 2;
+  uint32 peerUin = 1;
+  //string peerUid = 2;
   uint32 uin = 5;
   optional string uid = 6;
 }
 
 message SystemMessageMsgSpec {
   uint32 msgType = 1;
-  uint32 subType = 2;
-  uint32 subSubType = 3;
+  optional uint32 subType = 2;
+  optional uint32 subSubType = 3;
   uint32 msgSeq = 5;
   uint32 time = 6;
   //uint64 msgId = 12;
-  uint32 other = 13;
+  optional uint32 other = 13;
 }
 
 message SystemMessageBodyWrapper {
   bytes body = 2;
-  // Find the first [08], or ignore the first 7 bytes?
-}
\ No newline at end of file
+}
diff --git a/src/onebot11/action/group/GetGroupMemberInfo.ts b/src/onebot11/action/group/GetGroupMemberInfo.ts
index 261af97..3891780 100644
--- a/src/onebot11/action/group/GetGroupMemberInfo.ts
+++ b/src/onebot11/action/group/GetGroupMemberInfo.ts
@@ -2,25 +2,27 @@ import { BaseAction, Schema } from '../BaseAction'
 import { OB11GroupMember } from '../../types'
 import { OB11Entities } from '../../entities'
 import { ActionName } from '../types'
-import { calcQQLevel } from '@/common/utils/misc'
+import { calcQQLevel, parseBool } from '@/common/utils/misc'
 
 interface Payload {
   group_id: number | string
   user_id: number | string
+  no_cache: boolean
 }
 
 class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
   actionName = ActionName.GetGroupMemberInfo
   payloadSchema = Schema.object({
     group_id: Schema.union([Number, String]).required(),
-    user_id: Schema.union([Number, String]).required()
+    user_id: Schema.union([Number, String]).required(),
+    no_cache: Schema.union([Boolean, Schema.transform(String, parseBool)]).default(false)
   })
 
   protected async _handle(payload: Payload) {
     const groupCode = payload.group_id.toString()
     const uid = await this.ctx.ntUserApi.getUidByUin(payload.user_id.toString())
     if (!uid) throw new Error('无法获取用户信息')
-    const member = await this.ctx.ntGroupApi.getGroupMember(groupCode, uid)
+    const member = await this.ctx.ntGroupApi.getGroupMember(groupCode, uid, payload.no_cache)
     if (member) {
       const ret = OB11Entities.groupMember(groupCode, member)
       const date = Math.round(Date.now() / 1000)
diff --git a/src/onebot11/adapter.ts b/src/onebot11/adapter.ts
index abc0cbb..85d9160 100644
--- a/src/onebot11/adapter.ts
+++ b/src/onebot11/adapter.ts
@@ -23,6 +23,7 @@ import { llonebotError } from '../common/globalVars'
 import { OB11GroupAdminNoticeEvent } from './event/notice/OB11GroupAdminNoticeEvent'
 import { OB11ProfileLikeEvent } from './event/notice/OB11ProfileLikeEvent'
 import { SysMsg } from '@/ntqqapi/proto/compiled'
+import { OB11GroupIncreaseEvent } from './event/notice/OB11GroupIncreaseEvent'
 
 declare module 'cordis' {
   interface Context {
@@ -349,7 +350,7 @@ class OneBot11Adapter extends Service {
     this.ctx.on('nt/friend-request', input => {
       this.handleFriendRequest(input)
     })
-    this.ctx.on('nt/system-message-created', input => {
+    this.ctx.on('nt/system-message-created', async input => {
       const sysMsg = SysMsg.SystemMessage.decode(input)
       const { msgType, subType, subSubType } = sysMsg.msgSpec[0] ?? {}
       if (msgType === 528 && subType === 39 && subSubType === 39) {
@@ -358,8 +359,16 @@ class OneBot11Adapter extends Service {
         const detail = tip.content?.msg?.detail
         if (!detail) return
         const [times] = detail.txt?.match(/\d+/) ?? ['0']
-        const profileLikeEvent = new OB11ProfileLikeEvent(detail.uin!, detail.nickname!, +times)
-        this.dispatch(profileLikeEvent)
+        const event = new OB11ProfileLikeEvent(detail.uin!, detail.nickname!, +times)
+        this.dispatch(event)
+      } else if (msgType === 33) {
+        const tip = SysMsg.GroupMemberIncrease.decode(sysMsg.bodyWrapper!.body!)
+        if (tip.type !== 130) return
+        this.ctx.logger.info('群成员增加', tip)
+        const memberUin = await this.ctx.ntUserApi.getUinByUid(tip.memberUid)
+        const operatorUin = await this.ctx.ntUserApi.getUinByUid(tip.adminUid)
+        const event = new OB11GroupIncreaseEvent(tip.groupCode, +memberUin, +operatorUin)
+        this.dispatch(event)
       }
     })
   }
diff --git a/src/onebot11/connect/http.ts b/src/onebot11/connect/http.ts
index 0a76871..8eeda4f 100644
--- a/src/onebot11/connect/http.ts
+++ b/src/onebot11/connect/http.ts
@@ -134,11 +134,13 @@ namespace OB11Http {
 
 class OB11HttpPost {
   private disposeInterval?: () => void
+  private activated = false
 
   constructor(protected ctx: Context, public config: OB11HttpPost.Config) {
   }
 
   public start() {
+    this.activated = true
     if (this.config.enableHttpHeart && !this.disposeInterval) {
       this.disposeInterval = this.ctx.setInterval(() => {
         // ws的心跳是ws自己维护的
@@ -148,10 +150,14 @@ class OB11HttpPost {
   }
 
   public stop() {
+    this.activated = false
     this.disposeInterval?.()
   }
 
   public async emitEvent(event: OB11BaseEvent | OB11Message) {
+    if (!this.activated) {
+      return
+    }
     const msgStr = JSON.stringify(event)
     const headers: Dict = {
       'Content-Type': 'application/json',
diff --git a/src/onebot11/entities.ts b/src/onebot11/entities.ts
index 6b3d9f8..dd32cd7 100644
--- a/src/onebot11/entities.ts
+++ b/src/onebot11/entities.ts
@@ -423,11 +423,11 @@ export namespace OB11Entities {
       const groupElement = grayTipElement?.groupElement
       if (groupElement) {
         if (groupElement.type === TipGroupElementType.MemberIncrease) {
-          ctx.logger.info('收到群成员增加消息', groupElement)
+          /*ctx.logger.info('收到群成员增加消息', groupElement)
           const { memberUid, adminUid } = groupElement
           const memberUin = await ctx.ntUserApi.getUinByUid(memberUid)
           const operatorUin = adminUid ? await ctx.ntUserApi.getUinByUid(adminUid) : memberUin
-          return new OB11GroupIncreaseEvent(+msg.peerUid, +memberUin, +operatorUin)
+          return new OB11GroupIncreaseEvent(+msg.peerUid, +memberUin, +operatorUin)*/
         }
         else if (groupElement.type === TipGroupElementType.Ban) {
           ctx.logger.info('收到群成员禁言提示', groupElement)
diff --git a/src/preload.ts b/src/preload.ts
index 1f34204..18a6f0a 100644
--- a/src/preload.ts
+++ b/src/preload.ts
@@ -7,11 +7,8 @@ import {
   CHANNEL_SELECT_FILE,
   CHANNEL_SET_CONFIG,
   CHANNEL_UPDATE,
-  CHANNEL_SET_CONFIG_CONFIRMED,
 } from './common/channels'
-
-const { contextBridge } = require('electron')
-const { ipcRenderer } = require('electron')
+import { contextBridge, ipcRenderer } from 'electron'
 
 const llonebot = {
   log: (data: unknown) => {
@@ -24,8 +21,7 @@ const llonebot = {
     return ipcRenderer.invoke(CHANNEL_UPDATE)
   },
   setConfig: async (ask: boolean, config: Config) => {
-    const isSuccess = await ipcRenderer.invoke(CHANNEL_SET_CONFIG, ask, config)
-    if (isSuccess) ipcRenderer.send(CHANNEL_SET_CONFIG_CONFIRMED, config)
+    return ipcRenderer.invoke(CHANNEL_SET_CONFIG, ask, config)
   },
   getConfig: async (): Promise<Config> => {
     return ipcRenderer.invoke(CHANNEL_GET_CONFIG)
diff --git a/src/renderer/index.ts b/src/renderer/index.ts
index b766bb1..c81d889 100644
--- a/src/renderer/index.ts
+++ b/src/renderer/index.ts
@@ -25,9 +25,6 @@ async function onSettingWindowCreated(view: Element) {
       } else {
         Object.assign(config, { [key]: value })
       }
-      if (!['heartInterval', 'token', 'ffmpeg'].includes(key)) {
-        window.llonebot.setConfig(false, config)
-      }
     }
   }
 
diff --git a/src/satori/server.ts b/src/satori/server.ts
index e7105a6..e602135 100644
--- a/src/satori/server.ts
+++ b/src/satori/server.ts
@@ -99,6 +99,15 @@ export class SatoriServer {
   }
 
   public async stop() {
+    if (this.wsClients.length > 0) {
+      for (const socket of this.wsClients) {
+        try {
+          if (socket.readyState === WebSocket.OPEN) {
+            socket.close(1000)
+          }
+        } catch { }
+      }
+    }
     if (this.wsServer) {
       const close = promisify(this.wsServer.close)
       await close.call(this.wsServer)
diff --git a/src/version.ts b/src/version.ts
index 70e4db1..3aeb8a8 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -1 +1 @@
-export const version = '4.0.9'
+export const version = '4.0.10'