levix-bot 3.3.0-rc.2 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -9
- package/app.cjs +49 -46
- package/package.json +9 -1
- package/public/dashboard/assets/index-BBBXWzM0.js +391 -0
- package/public/dashboard/assets/index-pYaivHON.css +1 -0
- package/public/dashboard/index.html +19 -0
- package/public/dashboard.css +391 -66
- package/public/dashboard.js +593 -42
- package/scheduler.cjs +9 -14
- package/src/auth/use-database-auth-state.js +2 -4
- package/src/bootstrap/core.js +2 -5
- package/src/bootstrap/panel.js +10 -5
- package/src/cli.js +3 -5
- package/src/commands/autoschedule.cjs +1 -4
- package/src/commands/blacklist.cjs +22 -20
- package/src/commands/block.cjs +2 -4
- package/src/commands/calc.cjs +9 -16
- package/src/commands/digit.cjs +97 -0
- package/src/commands/gemini.cjs +147 -161
- package/src/commands/group/add.cjs +7 -16
- package/src/commands/group/antiSpam.cjs +5 -11
- package/src/commands/group/antilink.cjs +34 -28
- package/src/commands/group/approveall.cjs +3 -11
- package/src/commands/group/clearwarns.cjs +2 -5
- package/src/commands/group/demote.cjs +3 -8
- package/src/commands/group/kick.cjs +12 -15
- package/src/commands/group/media.cjs +17 -24
- package/src/commands/group/members.cjs +1 -2
- package/src/commands/group/promote.cjs +4 -12
- package/src/commands/group/removeall.cjs +2 -5
- package/src/commands/group/setpp.cjs +1 -1
- package/src/commands/group/setrules.cjs +2 -8
- package/src/commands/group/setwarn.cjs +4 -2
- package/src/commands/group/tagadmins.cjs +2 -5
- package/src/commands/group/warn.cjs +26 -24
- package/src/commands/group/warns.cjs +1 -2
- package/src/commands/group/welcome.cjs +13 -17
- package/src/commands/group.cjs +7 -10
- package/src/commands/help.cjs +6 -12
- package/src/commands/lang.cjs +104 -0
- package/src/commands/listschedules.cjs +2 -6
- package/src/commands/loop.cjs +6 -13
- package/src/commands/memory.cjs +19 -32
- package/src/commands/mod.cjs +97 -35
- package/src/commands/perm.cjs +18 -56
- package/src/commands/ping.cjs +1 -5
- package/src/commands/poll.cjs +1 -1
- package/src/commands/rand.cjs +2 -5
- package/src/commands/schedule.cjs +4 -8
- package/src/commands/score.cjs +8 -2
- package/src/commands/setprefix.cjs +2 -2
- package/src/commands/shortlink.cjs +7 -15
- package/src/commands/shutdown.cjs +1 -1
- package/src/commands/sticker.cjs +222 -0
- package/src/commands/stt.cjs +136 -68
- package/src/commands/todo.cjs +9 -15
- package/src/commands/tts.cjs +10 -16
- package/src/commands/unblock.cjs +2 -6
- package/src/commands/weather.cjs +5 -12
- package/src/config/ai-persona.md +5 -3
- package/src/config/available-models.json +1156 -0
- package/src/config/baileys.config.js +2 -1
- package/src/config/brand.esm.js +1 -10
- package/src/config/constants.js +1 -1
- package/src/config/defaults.cjs +66 -66
- package/src/config/lock.cjs +2 -2
- package/src/config/modelCapabilities.cjs +172 -0
- package/src/config/runtime-config.cjs +8 -13
- package/src/config/secrets.cjs +18 -10
- package/src/config/settings.cjs +94 -10
- package/src/config/vault.cjs +107 -0
- package/src/core/connection.js +13 -12
- package/src/core/events.js +41 -23
- package/src/core/proxy.js +7 -7
- package/src/core/session.js +91 -48
- package/src/core/socket.js +12 -15
- package/src/db/db.cjs +14 -6
- package/src/db/store.cjs +221 -87
- package/src/domain/caddy.js +1 -1
- package/src/domain/command.js +40 -19
- package/src/domain/detect.js +1 -1
- package/src/domain/system.js +2 -5
- package/src/handlers/command.handler.js +22 -43
- package/src/handlers/group.handler.js +13 -13
- package/src/handlers/message.handler.js +11 -21
- package/src/index.js +8 -4
- package/src/middleware/antispam.middleware.js +46 -23
- package/src/middleware/blacklist.middleware.js +14 -9
- package/src/middleware/forward-tracking.middleware.js +3 -2
- package/src/middleware/permissions.middleware.js +7 -10
- package/src/panel/login-throttle.cjs +43 -0
- package/src/panel/session-auth.cjs +17 -0
- package/src/routes/dashboard.api.esm.js +394 -72
- package/src/services/aiAgent.cjs +136 -49
- package/src/services/aiProviders.cjs +193 -47
- package/src/services/aiRouter.cjs +137 -0
- package/src/services/aiTools.cjs +305 -128
- package/src/services/llmDiscovery.cjs +481 -0
- package/src/services/modelRegistry.cjs +412 -0
- package/src/utils/datetime.cjs +2 -2
- package/src/utils/lid-helper.esm.js +7 -7
- package/src/utils/logger.cjs +1 -1
- package/src/utils/markdownParser.cjs +159 -0
- package/src/utils/memory.cjs +43 -13
- package/src/utils/messageContent.cjs +40 -0
- package/src/utils/normalizeJid.esm.js +7 -7
- package/src/utils/numerals.cjs +75 -0
- package/src/utils/permissions.esm.js +10 -15
- package/src/utils/providerUrl.cjs +281 -0
- package/src/utils/recurrence.cjs +7 -11
- package/src/utils/sendBotMessage.esm.js +4 -14
- package/src/utils/statusMessage.cjs +5 -13
- package/src/utils/storage.cjs +10 -0
- package/src/utils/storage.esm.js +11 -0
- package/src/utils/textDecode.cjs +4 -9
- package/src/utils/thumbnail.cjs +8 -14
- package/src/utils/typing.esm.js +12 -12
- package/views/dashboard.ejs +134 -106
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// file: /commands/warn.js (Corrected Logic Flow)
|
|
2
2
|
const { getGroupSettings } = require("../../utils/storage.cjs"); // <-- 1. Import getGroupSettings
|
|
3
|
-
const {
|
|
4
|
-
getUserWarnings,
|
|
5
|
-
saveUserWarnings,
|
|
6
|
-
clearUserWarnings,
|
|
7
|
-
} = require("../../utils/storage.cjs");
|
|
3
|
+
const { getUserWarnings, saveUserWarnings, clearUserWarnings } = require("../../utils/storage.cjs");
|
|
8
4
|
const logger = require("../../utils/logger.cjs");
|
|
5
|
+
const {
|
|
6
|
+
hasBotPrivilegesSync,
|
|
7
|
+
isAdminInGroupSync,
|
|
8
|
+
sameUserSync,
|
|
9
|
+
} = require("../../utils/permissions.cjs");
|
|
9
10
|
|
|
10
11
|
module.exports = {
|
|
11
12
|
name: "warn",
|
|
@@ -14,12 +15,11 @@ module.exports = {
|
|
|
14
15
|
chat: "group",
|
|
15
16
|
userAdminRequired: true,
|
|
16
17
|
|
|
17
|
-
async execute(sock, msg, args) {
|
|
18
|
+
async execute(sock, msg, args, _body, groupMetadata) {
|
|
18
19
|
try {
|
|
19
20
|
const groupId = msg.key.remoteJid;
|
|
20
21
|
const senderId = msg.key.participant;
|
|
21
|
-
const mentionedJid =
|
|
22
|
-
msg.message?.extendedTextMessage?.contextInfo?.mentionedJid?.[0];
|
|
22
|
+
const mentionedJid = msg.message?.extendedTextMessage?.contextInfo?.mentionedJid?.[0];
|
|
23
23
|
const reason = args.slice(1).join(" ");
|
|
24
24
|
|
|
25
25
|
// --- 1. Validate Inputs ---
|
|
@@ -33,6 +33,18 @@ module.exports = {
|
|
|
33
33
|
text: "يجب كتابة سبب التحذير.",
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
|
+
const isBot = [sock.user?.id, sock.user?.lid]
|
|
37
|
+
.filter(Boolean)
|
|
38
|
+
.some((id) => sameUserSync(id, mentionedJid));
|
|
39
|
+
if (
|
|
40
|
+
isBot ||
|
|
41
|
+
hasBotPrivilegesSync(mentionedJid) ||
|
|
42
|
+
isAdminInGroupSync(groupMetadata, mentionedJid)
|
|
43
|
+
) {
|
|
44
|
+
return await sock.sendMessage(groupId, {
|
|
45
|
+
text: "لا يمكن تحذير أو طرد البوت أو مالكه أو أحد المشرفين بهذه الطريقة.",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
36
48
|
|
|
37
49
|
// --- 2. Add the New Warning ---
|
|
38
50
|
const userWarnings = getUserWarnings(groupId, mentionedJid);
|
|
@@ -46,9 +58,8 @@ module.exports = {
|
|
|
46
58
|
const newWarnCount = userWarnings.length;
|
|
47
59
|
|
|
48
60
|
// --- 3. Send Confirmation & Check for Action ---
|
|
49
|
-
|
|
50
|
-
`✅ تم توجيه تحذير إلى @${mentionedJid.split("@")[0]}.\n` +
|
|
51
|
-
`*السبب:* ${reason}`;
|
|
61
|
+
const replyText =
|
|
62
|
+
`✅ تم توجيه تحذير إلى @${mentionedJid.split("@")[0]}.\n` + `*السبب:* ${reason}`;
|
|
52
63
|
|
|
53
64
|
await sock.sendMessage(groupId, {
|
|
54
65
|
text: replyText,
|
|
@@ -57,17 +68,11 @@ module.exports = {
|
|
|
57
68
|
|
|
58
69
|
const warnConfig = getGroupSettings(groupId)?.warn_system;
|
|
59
70
|
|
|
60
|
-
if (
|
|
61
|
-
warnConfig &&
|
|
62
|
-
warnConfig.action === "KICK" &&
|
|
63
|
-
newWarnCount >= warnConfig.max_warnings
|
|
64
|
-
) {
|
|
71
|
+
if (warnConfig && warnConfig.action === "KICK" && newWarnCount >= warnConfig.max_warnings) {
|
|
65
72
|
await sock.sendMessage(groupId, {
|
|
66
73
|
text: `🚫 لقد وصل العضو @${
|
|
67
74
|
mentionedJid.split("@")[0]
|
|
68
|
-
} إلى الحد الأقصى للتحذيرات (${newWarnCount}/${
|
|
69
|
-
warnConfig.max_warnings
|
|
70
|
-
}). سيتم حذفه.`,
|
|
75
|
+
} إلى الحد الأقصى للتحذيرات (${newWarnCount}/${warnConfig.max_warnings}). سيتم حذفه.`,
|
|
71
76
|
mentions: [mentionedJid],
|
|
72
77
|
});
|
|
73
78
|
|
|
@@ -76,13 +81,10 @@ module.exports = {
|
|
|
76
81
|
await sock.groupParticipantsUpdate(groupId, [mentionedJid], "remove");
|
|
77
82
|
clearUserWarnings(groupId, mentionedJid);
|
|
78
83
|
logger.info(
|
|
79
|
-
`[Warn Kick] Kicked and cleared warnings for ${mentionedJid} from ${groupId}
|
|
84
|
+
`[Warn Kick] Kicked and cleared warnings for ${mentionedJid} from ${groupId}`,
|
|
80
85
|
);
|
|
81
86
|
} catch (kickError) {
|
|
82
|
-
logger.error(
|
|
83
|
-
{ err: kickError },
|
|
84
|
-
"Failed to kick user after max warnings"
|
|
85
|
-
);
|
|
87
|
+
logger.error({ err: kickError }, "Failed to kick user after max warnings");
|
|
86
88
|
await sock.sendMessage(groupId, {
|
|
87
89
|
text: "حاولت حذف العضو ولكني لا أملك صلاحية كافية لذلك.",
|
|
88
90
|
});
|
|
@@ -12,8 +12,7 @@ module.exports = {
|
|
|
12
12
|
async execute(sock, msg) {
|
|
13
13
|
try {
|
|
14
14
|
const groupId = msg.key.remoteJid;
|
|
15
|
-
const mentionedJid =
|
|
16
|
-
msg.message?.extendedTextMessage?.contextInfo?.mentionedJid?.[0];
|
|
15
|
+
const mentionedJid = msg.message?.extendedTextMessage?.contextInfo?.mentionedJid?.[0];
|
|
17
16
|
|
|
18
17
|
if (!mentionedJid) {
|
|
19
18
|
return await sock.sendMessage(groupId, {
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
// file: /commands/welcome.js
|
|
2
|
-
const {
|
|
3
|
-
getGroupSettings,
|
|
4
|
-
saveGroupSettings,
|
|
5
|
-
} = require("../../utils/storage.cjs");
|
|
2
|
+
const { getGroupSettings, saveGroupSettings } = require("../../utils/storage.cjs");
|
|
6
3
|
const logger = require("../../utils/logger.cjs");
|
|
7
4
|
|
|
8
5
|
module.exports = {
|
|
9
6
|
name: "welcome",
|
|
10
7
|
description: "Manages the group's welcome message system.",
|
|
11
|
-
usage:
|
|
8
|
+
usage:
|
|
9
|
+
"welcome [status]\nwelcome <on|off>\nwelcome add <نص الترحيب>\nwelcome list\nwelcome delete <رقم>",
|
|
12
10
|
chat: "group",
|
|
13
11
|
userAdminRequired: true,
|
|
14
12
|
|
|
@@ -40,7 +38,7 @@ module.exports = {
|
|
|
40
38
|
});
|
|
41
39
|
break;
|
|
42
40
|
|
|
43
|
-
case "add":
|
|
41
|
+
case "add": {
|
|
44
42
|
const messageToAdd = args.slice(1).join(" ");
|
|
45
43
|
if (!messageToAdd || !messageToAdd.includes("${user}")) {
|
|
46
44
|
return await sock.sendMessage(groupId, {
|
|
@@ -52,8 +50,9 @@ module.exports = {
|
|
|
52
50
|
text: "✅ تم إضافة رسالة الترحيب بنجاح.",
|
|
53
51
|
});
|
|
54
52
|
break;
|
|
53
|
+
}
|
|
55
54
|
|
|
56
|
-
case "list":
|
|
55
|
+
case "list": {
|
|
57
56
|
if (welcomeConfig.messages.length === 0) {
|
|
58
57
|
return await sock.sendMessage(groupId, {
|
|
59
58
|
text: "لا توجد رسائل ترحيب محفوظة.",
|
|
@@ -65,8 +64,9 @@ module.exports = {
|
|
|
65
64
|
});
|
|
66
65
|
await sock.sendMessage(groupId, { text: listReply });
|
|
67
66
|
break;
|
|
67
|
+
}
|
|
68
68
|
|
|
69
|
-
case "delete":
|
|
69
|
+
case "delete": {
|
|
70
70
|
const indexToDelete = parseInt(args[1]?.replace("#", ""), 10) - 1;
|
|
71
71
|
if (
|
|
72
72
|
isNaN(indexToDelete) ||
|
|
@@ -77,32 +77,28 @@ module.exports = {
|
|
|
77
77
|
text: "رقم الرسالة غير صالح. استخدم `!welcome list` لمعرفة الأرقام.",
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
|
-
const deletedMessage = welcomeConfig.messages.splice(
|
|
81
|
-
indexToDelete,
|
|
82
|
-
1
|
|
83
|
-
);
|
|
80
|
+
const deletedMessage = welcomeConfig.messages.splice(indexToDelete, 1);
|
|
84
81
|
await sock.sendMessage(groupId, {
|
|
85
82
|
text: `☑️ تم حذف الرسالة بنجاح:\n*${deletedMessage[0]}*`,
|
|
86
83
|
});
|
|
87
84
|
break;
|
|
85
|
+
}
|
|
88
86
|
|
|
89
87
|
case "status":
|
|
90
|
-
default:
|
|
88
|
+
default: {
|
|
91
89
|
const statusReply =
|
|
92
90
|
`*상태 نظام الترحيب:*\n\n` +
|
|
93
91
|
`الحالة: ${welcomeConfig.enabled ? "مفعل ✅" : "معطل ☑️"}\n` +
|
|
94
92
|
`عدد الرسائل المحفوظة: ${welcomeConfig.messages.length}`;
|
|
95
93
|
await sock.sendMessage(groupId, { text: statusReply });
|
|
96
94
|
break;
|
|
95
|
+
}
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
// Save the updated settings back to the database
|
|
100
99
|
saveGroupSettings(groupId, settings);
|
|
101
100
|
} catch (error) {
|
|
102
|
-
logger.error(
|
|
103
|
-
{ err: error, command: "welcome" },
|
|
104
|
-
"Error in !welcome command"
|
|
105
|
-
);
|
|
101
|
+
logger.error({ err: error, command: "welcome" }, "Error in !welcome command");
|
|
106
102
|
await sock.sendMessage(groupId, { text: "حدث خطأ." });
|
|
107
103
|
}
|
|
108
104
|
},
|
package/src/commands/group.cjs
CHANGED
|
@@ -28,7 +28,9 @@ function register(command, label) {
|
|
|
28
28
|
if (!command?.name) return;
|
|
29
29
|
subCommands.set(command.name, command);
|
|
30
30
|
if (Array.isArray(command.aliases)) {
|
|
31
|
-
command.aliases.forEach((alias) =>
|
|
31
|
+
command.aliases.forEach((alias) => {
|
|
32
|
+
subCommands.set(alias, command);
|
|
33
|
+
});
|
|
32
34
|
}
|
|
33
35
|
} catch (error) {
|
|
34
36
|
logger.error({ err: error, file: label }, `Failed to load group sub-command from ${label}`);
|
|
@@ -54,10 +56,7 @@ if (manifest) {
|
|
|
54
56
|
try {
|
|
55
57
|
register(require(path.join(subCommandsPath, file)), file);
|
|
56
58
|
} catch (error) {
|
|
57
|
-
logger.error(
|
|
58
|
-
{ err: error, file },
|
|
59
|
-
`Failed to load group sub-command from ${file}`
|
|
60
|
-
);
|
|
59
|
+
logger.error({ err: error, file }, `Failed to load group sub-command from ${file}`);
|
|
61
60
|
}
|
|
62
61
|
}
|
|
63
62
|
}
|
|
@@ -100,9 +99,7 @@ module.exports = {
|
|
|
100
99
|
|
|
101
100
|
// "group:kick" — the flat key runtime-config uses for sub-commands, so a
|
|
102
101
|
// level changed from the dashboard applies here too.
|
|
103
|
-
const permissionLevel = runtimeConfig.getPermission(
|
|
104
|
-
`group:${subCommand.name}`
|
|
105
|
-
);
|
|
102
|
+
const permissionLevel = runtimeConfig.getPermission(`group:${subCommand.name}`);
|
|
106
103
|
|
|
107
104
|
let hasPermission = false;
|
|
108
105
|
switch (permissionLevel) {
|
|
@@ -121,7 +118,7 @@ module.exports = {
|
|
|
121
118
|
break;
|
|
122
119
|
default:
|
|
123
120
|
logger.warn(
|
|
124
|
-
`[group] Unknown permission level "${permissionLevel}" for sub-command "${subCommand.name}"
|
|
121
|
+
`[group] Unknown permission level "${permissionLevel}" for sub-command "${subCommand.name}"`,
|
|
125
122
|
);
|
|
126
123
|
}
|
|
127
124
|
|
|
@@ -148,7 +145,7 @@ module.exports = {
|
|
|
148
145
|
} catch (error) {
|
|
149
146
|
logger.error(
|
|
150
147
|
{ err: error, subCommand: subCommandName },
|
|
151
|
-
"Error executing a group sub-command"
|
|
148
|
+
"Error executing a group sub-command",
|
|
152
149
|
);
|
|
153
150
|
await sock.sendMessage(msg.key.remoteJid, {
|
|
154
151
|
text: `❌ *فشل تنفيذ الأمر الفرعي* (\`${error.name || "Error"}\`): ${
|
package/src/commands/help.cjs
CHANGED
|
@@ -27,8 +27,7 @@ function loadAllCommands() {
|
|
|
27
27
|
if (cached) return cached;
|
|
28
28
|
const commandsPath = path.join(__dirname);
|
|
29
29
|
const files = getAllCommandFiles(commandsPath).filter(
|
|
30
|
-
(file) =>
|
|
31
|
-
path.basename(file) !== "help.cjs" && path.basename(file) !== "help.js"
|
|
30
|
+
(file) => path.basename(file) !== "help.cjs" && path.basename(file) !== "help.js",
|
|
32
31
|
);
|
|
33
32
|
|
|
34
33
|
const commands = { general: [], group: [] };
|
|
@@ -110,7 +109,7 @@ const PERMISSION_LABELS = {
|
|
|
110
109
|
|
|
111
110
|
function permissionFor(command, isGroupCommand) {
|
|
112
111
|
const level = runtimeConfig.getPermission(
|
|
113
|
-
isGroupCommand ? `group:${command.name}` : command.name
|
|
112
|
+
isGroupCommand ? `group:${command.name}` : command.name,
|
|
114
113
|
);
|
|
115
114
|
return PERMISSION_LABELS[level] || level;
|
|
116
115
|
}
|
|
@@ -152,8 +151,7 @@ module.exports = {
|
|
|
152
151
|
|
|
153
152
|
// A command switched off from the dashboard can't run, so it has no
|
|
154
153
|
// business in the menu.
|
|
155
|
-
const live = (list) =>
|
|
156
|
-
list.filter((cmd) => !runtimeConfig.isDisabled(cmd.name));
|
|
154
|
+
const live = (list) => list.filter((cmd) => !runtimeConfig.isDisabled(cmd.name));
|
|
157
155
|
|
|
158
156
|
const general = live(commands.general);
|
|
159
157
|
const group = live(commands.group);
|
|
@@ -177,11 +175,9 @@ module.exports = {
|
|
|
177
175
|
sock,
|
|
178
176
|
msg.key.remoteJid,
|
|
179
177
|
{
|
|
180
|
-
text:
|
|
181
|
-
`❌ الأمر "*${args[0]}*" غير موجود.\n` +
|
|
182
|
-
`اكتب \`${prefix}help\` لعرض كل الأوامر.`,
|
|
178
|
+
text: `❌ الأمر "*${args[0]}*" غير موجود.\n` + `اكتب \`${prefix}help\` لعرض كل الأوامر.`,
|
|
183
179
|
},
|
|
184
|
-
{ replyTo: msg }
|
|
180
|
+
{ replyTo: msg },
|
|
185
181
|
);
|
|
186
182
|
}
|
|
187
183
|
|
|
@@ -190,9 +186,7 @@ module.exports = {
|
|
|
190
186
|
|
|
191
187
|
const commandAliases = aliasesOf(command);
|
|
192
188
|
if (commandAliases.length) {
|
|
193
|
-
usageText += `├─ *اختصارات:* ${commandAliases
|
|
194
|
-
.map((a) => `${prefix}${a}`)
|
|
195
|
-
.join(", ")}\n`;
|
|
189
|
+
usageText += `├─ *اختصارات:* ${commandAliases.map((a) => `${prefix}${a}`).join(", ")}\n`;
|
|
196
190
|
}
|
|
197
191
|
|
|
198
192
|
if (command.description) {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// file: src/commands/lang.cjs
|
|
2
|
+
const logger = require("../utils/logger.cjs");
|
|
3
|
+
const settings = require("../config/settings.cjs");
|
|
4
|
+
const runtimeConfig = require("../config/runtime-config.cjs");
|
|
5
|
+
const { isOwnerJidSync, isBotAdminUserSync } = require("../utils/permissions.cjs");
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
name: "lang",
|
|
9
|
+
aliases: ["language", "لغة"],
|
|
10
|
+
description: "View or change the bot response language",
|
|
11
|
+
usage: "lang [en|ar|auto]",
|
|
12
|
+
chat: "all",
|
|
13
|
+
|
|
14
|
+
async execute(sock, msg, args) {
|
|
15
|
+
const chatId = msg.key.remoteJid;
|
|
16
|
+
const sender = msg.key.participant || msg.key.remoteJid;
|
|
17
|
+
const prefix = runtimeConfig.getPrefix();
|
|
18
|
+
const currentLang = settings.get("bot_language") || "auto";
|
|
19
|
+
|
|
20
|
+
const firstArg = args?.[0] ? String(args[0]).toLowerCase().trim() : "";
|
|
21
|
+
|
|
22
|
+
if (!args || args.length === 0) {
|
|
23
|
+
const labels = {
|
|
24
|
+
auto: "تلقائي (حسب لغة رسالتك) / Auto-detect",
|
|
25
|
+
ar: "العربية الفصحى (Modern Standard Arabic)",
|
|
26
|
+
en: "English (الإنجليزية)",
|
|
27
|
+
};
|
|
28
|
+
const text = `🌐 *لغة البوت / Bot language*
|
|
29
|
+
|
|
30
|
+
⚙️ *اللغة الحالية:* \`${labels[currentLang] || currentLang}\`
|
|
31
|
+
• \`${prefix}lang ar\` — العربية الفصحى دائماً
|
|
32
|
+
• \`${prefix}lang en\` — English always
|
|
33
|
+
• \`${prefix}lang auto\` — تلقائي حسب لغة الرسالة
|
|
34
|
+
|
|
35
|
+
🔢 *لتحويل الأرقام* استخدم \`${prefix}digit\` — مثال: \`${prefix}digit 12345\``;
|
|
36
|
+
await sock.sendMessage(chatId, { text }, { quoted: msg });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (firstArg === "ar" || firstArg === "en" || firstArg === "auto") {
|
|
41
|
+
if (args.length > 1) {
|
|
42
|
+
await sock.sendMessage(
|
|
43
|
+
chatId,
|
|
44
|
+
{
|
|
45
|
+
text: `🔢 لتحويل الأرقام استخدم \`${prefix}digit\`:\n• \`${prefix}digit ${firstArg} ${args.slice(1).join(" ")}\`\n• أو \`${prefix}digit ${args.slice(1).join(" ")}\` للتحويل التلقائي.\nTo convert digits, use \`${prefix}digit\`.`,
|
|
46
|
+
},
|
|
47
|
+
{ quoted: msg },
|
|
48
|
+
);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const isOwner = isOwnerJidSync(sender);
|
|
53
|
+
const isAdmin = isBotAdminUserSync(sender);
|
|
54
|
+
if (!isOwner && !isAdmin) {
|
|
55
|
+
await sock.sendMessage(
|
|
56
|
+
chatId,
|
|
57
|
+
{
|
|
58
|
+
text: `⚠️ عذراً، تغيير لغة البوت متاح لمالك البوت والمسؤولين فقط.\nSorry, only bot owner and admins can change bot language.\n_لتحويل الأرقام استخدم \`${prefix}digit\`._`,
|
|
59
|
+
},
|
|
60
|
+
{ quoted: msg },
|
|
61
|
+
);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
settings.set("bot_language", firstArg);
|
|
66
|
+
logger.info(`[Language] Bot response language set to: ${firstArg}`);
|
|
67
|
+
|
|
68
|
+
if (firstArg === "ar") {
|
|
69
|
+
await sock.sendMessage(
|
|
70
|
+
chatId,
|
|
71
|
+
{
|
|
72
|
+
text: "✅ تم ضبط لغة البوت على *العربية الفصحى*. سيتحدث الذكاء الاصطناعي بالعربية الفصحى دائماً.",
|
|
73
|
+
},
|
|
74
|
+
{ quoted: msg },
|
|
75
|
+
);
|
|
76
|
+
} else if (firstArg === "en") {
|
|
77
|
+
await sock.sendMessage(
|
|
78
|
+
chatId,
|
|
79
|
+
{
|
|
80
|
+
text: "✅ Bot language set to *English*. The AI assistant will now always respond in English.",
|
|
81
|
+
},
|
|
82
|
+
{ quoted: msg },
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
await sock.sendMessage(
|
|
86
|
+
chatId,
|
|
87
|
+
{
|
|
88
|
+
text: "✅ تم ضبط اللغة على *التلقائي (Auto)*. سيرد البوت بحسب لغة كل رسالة ترسلها له تلقائياً.",
|
|
89
|
+
},
|
|
90
|
+
{ quoted: msg },
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await sock.sendMessage(
|
|
97
|
+
chatId,
|
|
98
|
+
{
|
|
99
|
+
text: `❌ خيار غير صحيح.\nاستخدم:\n• \`${prefix}lang ar\` / \`${prefix}lang en\` / \`${prefix}lang auto\` للغة البوت\n• \`${prefix}digit 12345\` لتحويل الأرقام`,
|
|
100
|
+
},
|
|
101
|
+
{ quoted: msg },
|
|
102
|
+
);
|
|
103
|
+
},
|
|
104
|
+
};
|
|
@@ -10,9 +10,7 @@ module.exports = {
|
|
|
10
10
|
|
|
11
11
|
async execute(sock, msg) {
|
|
12
12
|
const jobs = getScheduledJobs();
|
|
13
|
-
const activeJobs = jobs.filter(
|
|
14
|
-
(job) => job.status === "pending" || job.status === "active"
|
|
15
|
-
);
|
|
13
|
+
const activeJobs = jobs.filter((job) => job.status === "pending" || job.status === "active");
|
|
16
14
|
|
|
17
15
|
if (activeJobs.length === 0) {
|
|
18
16
|
return await sock.sendMessage(msg.key.remoteJid, {
|
|
@@ -35,9 +33,7 @@ module.exports = {
|
|
|
35
33
|
});
|
|
36
34
|
reply += `*الوقت المحدد:* ${jobDate}\n`;
|
|
37
35
|
}
|
|
38
|
-
reply += `*الوجهة:* ${
|
|
39
|
-
job.targetJid.endsWith("@g.us") ? "هذا الجروب" : "محادثة خاصة"
|
|
40
|
-
}\n\n`;
|
|
36
|
+
reply += `*الوجهة:* ${job.targetJid.endsWith("@g.us") ? "هذا الجروب" : "محادثة خاصة"}\n\n`;
|
|
41
37
|
});
|
|
42
38
|
|
|
43
39
|
reply += "*لحذف مهمة، استخدم:*\n`!deleteschedule <ID>`";
|
package/src/commands/loop.cjs
CHANGED
|
@@ -85,17 +85,14 @@ function buildNumbers({ from, to, step }, limit) {
|
|
|
85
85
|
|
|
86
86
|
function renderLine(template, number, index) {
|
|
87
87
|
if (!template) return String(number);
|
|
88
|
-
return template
|
|
89
|
-
.replace(/\{n\}/gi, String(number))
|
|
90
|
-
.replace(/\{i\}/gi, String(index));
|
|
88
|
+
return template.replace(/\{n\}/gi, String(number)).replace(/\{i\}/gi, String(index));
|
|
91
89
|
}
|
|
92
90
|
|
|
93
91
|
module.exports = {
|
|
94
92
|
name: "loop",
|
|
95
93
|
aliases: ["repeat", "كرر", "تكرار"],
|
|
96
94
|
description: "يكرر نص أو أرقام — في رسالة واحدة أو رسائل منفصلة.",
|
|
97
|
-
usage:
|
|
98
|
-
"loop <عدد|من-إلى[:خطوة]> [النص] [-s رسائل منفصلة] [-n بدون ترقيم]",
|
|
95
|
+
usage: "loop <عدد|من-إلى[:خطوة]> [النص] [-s رسائل منفصلة] [-n بدون ترقيم]",
|
|
99
96
|
chat: "all",
|
|
100
97
|
|
|
101
98
|
async execute(sock, msg, args) {
|
|
@@ -124,7 +121,7 @@ module.exports = {
|
|
|
124
121
|
if (requested > limit) {
|
|
125
122
|
return reply(
|
|
126
123
|
`❌ ${requested} تكرار كتير أوي.\n` +
|
|
127
|
-
`الحد الأقصى ${limit} ${split ? "رسالة منفصلة" : "تكرار في الرسالة الواحدة"}
|
|
124
|
+
`الحد الأقصى ${limit} ${split ? "رسالة منفصلة" : "تكرار في الرسالة الواحدة"}.`,
|
|
128
125
|
);
|
|
129
126
|
}
|
|
130
127
|
|
|
@@ -133,9 +130,7 @@ module.exports = {
|
|
|
133
130
|
|
|
134
131
|
// A bare count with text repeats the text; a range without text prints the
|
|
135
132
|
// numbers. Either way {n}/{i} are substituted per line.
|
|
136
|
-
const lines = numbers.map((number, index) =>
|
|
137
|
-
renderLine(template, number, index + 1)
|
|
138
|
-
);
|
|
133
|
+
const lines = numbers.map((number, index) => renderLine(template, number, index + 1));
|
|
139
134
|
|
|
140
135
|
if (split) {
|
|
141
136
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -144,15 +139,13 @@ module.exports = {
|
|
|
144
139
|
sock,
|
|
145
140
|
chatId,
|
|
146
141
|
{ text: body },
|
|
147
|
-
{ replyTo: i === 0 ? msg : null, typing: false, delayMs: SPLIT_GAP_MS }
|
|
142
|
+
{ replyTo: i === 0 ? msg : null, typing: false, delayMs: SPLIT_GAP_MS },
|
|
148
143
|
);
|
|
149
144
|
}
|
|
150
145
|
return;
|
|
151
146
|
}
|
|
152
147
|
|
|
153
|
-
let text = lines
|
|
154
|
-
.map((line, i) => (numbered ? `${i + 1}. ${line}` : line))
|
|
155
|
-
.join("\n");
|
|
148
|
+
let text = lines.map((line, i) => (numbered ? `${i + 1}. ${line}` : line)).join("\n");
|
|
156
149
|
|
|
157
150
|
if (text.length > MAX_OUTPUT_CHARS) {
|
|
158
151
|
text = `${text.slice(0, MAX_OUTPUT_CHARS)}\n…\n_(اتقصت عشان طولها)_`;
|
package/src/commands/memory.cjs
CHANGED
|
@@ -48,16 +48,13 @@ function formatEntries(entries, { limit = 30 } = {}) {
|
|
|
48
48
|
return `*${number}.* ${entry.content}${meta}`;
|
|
49
49
|
});
|
|
50
50
|
const skipped = entries.length - shown.length;
|
|
51
|
-
return (
|
|
52
|
-
(skipped > 0 ? `_(+${skipped} أقدم مش معروضين)_\n\n` : "") + lines.join("\n")
|
|
53
|
-
);
|
|
51
|
+
return (skipped > 0 ? `_(+${skipped} أقدم مش معروضين)_\n\n` : "") + lines.join("\n");
|
|
54
52
|
}
|
|
55
53
|
|
|
56
54
|
module.exports = {
|
|
57
55
|
name: "memory",
|
|
58
56
|
aliases: ["mem", "ذاكرة", "remember"],
|
|
59
|
-
description:
|
|
60
|
-
"الذاكرة الدائمة للبوت (ملفات .md): إضافة، عرض، بحث، حذف، أو تصدير الملف.",
|
|
57
|
+
description: "الذاكرة الدائمة للبوت (ملفات .md): إضافة، عرض، بحث، حذف، أو تصدير الملف.",
|
|
61
58
|
usage:
|
|
62
59
|
"memory\nmemory add <المعلومة>\nmemory add global <المعلومة>\nmemory search <كلمة>\nmemory forget <رقم|جزء من النص>\nmemory clear [global]\nmemory file [global]",
|
|
63
60
|
chat: "all",
|
|
@@ -68,10 +65,8 @@ module.exports = {
|
|
|
68
65
|
const senderId = isGroup ? msg.key.participant : msg.key.remoteJid;
|
|
69
66
|
|
|
70
67
|
const isOwner = msg.key.fromMe || isOwnerJidSync(senderId);
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
isBotAdminUserSync(senderId) ||
|
|
74
|
-
(isGroup && isAdminInGroupSync(groupMetadata, senderId));
|
|
68
|
+
const botPrivileged = isOwner || isBotAdminUserSync(senderId);
|
|
69
|
+
const groupAdmin = Boolean(isGroup && isAdminInGroupSync(groupMetadata, senderId));
|
|
75
70
|
|
|
76
71
|
const action = String(args[0] || "").toLowerCase();
|
|
77
72
|
const { scope, rest } = extractScope(args.slice(1));
|
|
@@ -79,19 +74,16 @@ module.exports = {
|
|
|
79
74
|
const reply = (text, extra = {}) =>
|
|
80
75
|
sendBotMessage(sock, chatId, { text, ...extra }, { replyTo: msg });
|
|
81
76
|
|
|
82
|
-
const denied = () =>
|
|
83
|
-
reply("🚫 ده للمشرفين والمالك بس. تقدر تضيف معلومة لذاكرة الشات عادي.");
|
|
77
|
+
const denied = () => reply("🚫 ده للمشرفين والمالك بس. تقدر تضيف معلومة لذاكرة الشات عادي.");
|
|
84
78
|
|
|
85
79
|
try {
|
|
86
80
|
// ---------------------------------------------------------------- add
|
|
87
81
|
if (["add", "save", "احفظ", "ضيف", "اضف"].includes(action)) {
|
|
88
82
|
const content = rest.join(" ").trim();
|
|
89
83
|
if (!content) {
|
|
90
|
-
return reply(
|
|
91
|
-
"اكتب المعلومة بعد الأمر.\nمثال: `!memory add الاجتماع كل تلات الساعة ٩`"
|
|
92
|
-
);
|
|
84
|
+
return reply("اكتب المعلومة بعد الأمر.\nمثال: `!memory add الاجتماع كل تلات الساعة ٩`");
|
|
93
85
|
}
|
|
94
|
-
if (scope === "global" && !
|
|
86
|
+
if (scope === "global" && !botPrivileged) return denied();
|
|
95
87
|
|
|
96
88
|
const entry = memory.addMemory({
|
|
97
89
|
scope,
|
|
@@ -103,7 +95,7 @@ module.exports = {
|
|
|
103
95
|
|
|
104
96
|
return reply(
|
|
105
97
|
`🧠 اتحفظت في *${scope === "global" ? "الذاكرة العامة" : "ذاكرة الشات"}*.\n` +
|
|
106
|
-
`\`${entry.id}\` — ${content.length > 80 ? content.slice(0, 80) + "…" : content}
|
|
98
|
+
`\`${entry.id}\` — ${content.length > 80 ? content.slice(0, 80) + "…" : content}`,
|
|
107
99
|
);
|
|
108
100
|
}
|
|
109
101
|
|
|
@@ -120,18 +112,17 @@ module.exports = {
|
|
|
120
112
|
return reply(
|
|
121
113
|
`🔍 *نتايج البحث عن* "${query}"\n\n` +
|
|
122
114
|
`*ذاكرة الشات (${chatHits.length}):*\n${formatEntries(chatHits, { limit: 10 })}\n\n` +
|
|
123
|
-
`*الذاكرة العامة (${globalHits.length}):*\n${formatEntries(globalHits, { limit: 10 })}
|
|
115
|
+
`*الذاكرة العامة (${globalHits.length}):*\n${formatEntries(globalHits, { limit: 10 })}`,
|
|
124
116
|
);
|
|
125
117
|
}
|
|
126
118
|
|
|
127
119
|
// ------------------------------------------------------------- forget
|
|
128
120
|
if (["forget", "del", "delete", "remove", "امسح", "انسى"].includes(action)) {
|
|
129
|
-
if (!
|
|
121
|
+
if (scope === "global" ? !botPrivileged : !botPrivileged && !groupAdmin) return denied();
|
|
130
122
|
const ref = rest.join(" ").trim();
|
|
131
123
|
if (!ref) {
|
|
132
124
|
return reply(
|
|
133
|
-
"حدد اللي عايز تمسحه: رقمه من `!memory` أو جزء من نصه.\n" +
|
|
134
|
-
"مثال: `!memory forget 3`"
|
|
125
|
+
"حدد اللي عايز تمسحه: رقمه من `!memory` أو جزء من نصه.\n" + "مثال: `!memory forget 3`",
|
|
135
126
|
);
|
|
136
127
|
}
|
|
137
128
|
const removed = memory.removeMemory({ scope, chatId, ref });
|
|
@@ -140,26 +131,26 @@ module.exports = {
|
|
|
140
131
|
? `🗑️ اتمسحت: ${removed.content.slice(0, 120)}`
|
|
141
132
|
: `مالقيتش حاجة تطابق "${ref}" في ${
|
|
142
133
|
scope === "global" ? "الذاكرة العامة" : "ذاكرة الشات"
|
|
143
|
-
}
|
|
134
|
+
}.`,
|
|
144
135
|
);
|
|
145
136
|
}
|
|
146
137
|
|
|
147
138
|
// -------------------------------------------------------------- clear
|
|
148
139
|
if (["clear", "reset", "wipe", "تصفير"].includes(action)) {
|
|
149
|
-
if (!
|
|
140
|
+
if (scope === "global" ? !botPrivileged : !botPrivileged && !groupAdmin) return denied();
|
|
150
141
|
const count = memory.clearMemory({ scope, chatId });
|
|
151
142
|
return reply(
|
|
152
143
|
count
|
|
153
144
|
? `🧹 اتمسحت *${count}* معلومة من ${
|
|
154
145
|
scope === "global" ? "الذاكرة العامة" : "ذاكرة الشات"
|
|
155
146
|
}.`
|
|
156
|
-
: "الذاكرة كانت فاضية أصلاً."
|
|
147
|
+
: "الذاكرة كانت فاضية أصلاً.",
|
|
157
148
|
);
|
|
158
149
|
}
|
|
159
150
|
|
|
160
151
|
// --------------------------------------------------------------- file
|
|
161
152
|
if (["file", "export", "md", "ملف"].includes(action)) {
|
|
162
|
-
if (!
|
|
153
|
+
if (scope === "global" ? !botPrivileged : !botPrivileged && !groupAdmin) return denied();
|
|
163
154
|
const filePath = memory.memoryFilePath(scope, chatId);
|
|
164
155
|
if (!fs.existsSync(filePath)) {
|
|
165
156
|
return reply("مفيش ملف ذاكرة لسه — ابدأ بـ `!memory add ...`.");
|
|
@@ -171,11 +162,9 @@ module.exports = {
|
|
|
171
162
|
document: fs.readFileSync(filePath),
|
|
172
163
|
mimetype: "text/markdown",
|
|
173
164
|
fileName: scope === "global" ? "global.md" : `${chatId}.md`,
|
|
174
|
-
caption: `🧠 ملف ${
|
|
175
|
-
scope === "global" ? "الذاكرة العامة" : "ذاكرة الشات"
|
|
176
|
-
}`,
|
|
165
|
+
caption: `🧠 ملف ${scope === "global" ? "الذاكرة العامة" : "ذاكرة الشات"}`,
|
|
177
166
|
},
|
|
178
|
-
{ replyTo: msg }
|
|
167
|
+
{ replyTo: msg },
|
|
179
168
|
);
|
|
180
169
|
}
|
|
181
170
|
|
|
@@ -189,13 +178,11 @@ module.exports = {
|
|
|
189
178
|
`(${entries.length} معلومة)\n\n` +
|
|
190
179
|
`${formatEntries(entries)}\n\n` +
|
|
191
180
|
`_الشات: ${stats.chatCount} · العام: ${stats.globalCount}_\n` +
|
|
192
|
-
"`!memory add <معلومة>` · `!memory add global <معلومة>` · `!memory forget <رقم>` · `!memory file`"
|
|
181
|
+
"`!memory add <معلومة>` · `!memory add global <معلومة>` · `!memory forget <رقم>` · `!memory file`",
|
|
193
182
|
);
|
|
194
183
|
} catch (error) {
|
|
195
184
|
logger.error({ err: error }, "[memory] command failed");
|
|
196
|
-
return reply(
|
|
197
|
-
`❌ *مشكلة في الذاكرة*\n\n*التفاصيل:* ${error.message || error}`
|
|
198
|
-
);
|
|
185
|
+
return reply(`❌ *مشكلة في الذاكرة*\n\n*التفاصيل:* ${error.message || error}`);
|
|
199
186
|
}
|
|
200
187
|
},
|
|
201
188
|
};
|