blockmine 1.22.0 → 1.23.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/.claude/settings.json +5 -1
- package/.claude/settings.local.json +10 -1
- package/CHANGELOG.md +27 -3
- package/CLAUDE.md +284 -0
- package/README.md +302 -152
- package/backend/package-lock.json +681 -9
- package/backend/package.json +8 -0
- package/backend/prisma/migrations/20251116111851_add_execution_trace/migration.sql +22 -0
- package/backend/prisma/migrations/20251120154914_add_panel_api_keys/migration.sql +21 -0
- package/backend/prisma/migrations/20251121110241_add_proxy_table/migration.sql +45 -0
- package/backend/prisma/migrations/migration_lock.toml +2 -2
- package/backend/prisma/schema.prisma +70 -1
- package/backend/src/__tests__/services/BotLifecycleService.test.js +9 -4
- package/backend/src/ai/plugin-assistant-system-prompt.md +788 -0
- package/backend/src/api/middleware/auth.js +27 -0
- package/backend/src/api/middleware/botAccess.js +7 -3
- package/backend/src/api/middleware/panelApiAuth.js +135 -0
- package/backend/src/api/routes/aiAssistant.js +995 -0
- package/backend/src/api/routes/auth.js +669 -633
- package/backend/src/api/routes/botCommands.js +107 -0
- package/backend/src/api/routes/botGroups.js +165 -0
- package/backend/src/api/routes/botHistory.js +108 -0
- package/backend/src/api/routes/botPermissions.js +99 -0
- package/backend/src/api/routes/botStatus.js +36 -0
- package/backend/src/api/routes/botUsers.js +162 -0
- package/backend/src/api/routes/bots.js +2451 -2402
- package/backend/src/api/routes/eventGraphs.js +4 -1
- package/backend/src/api/routes/logs.js +13 -3
- package/backend/src/api/routes/panel.js +66 -66
- package/backend/src/api/routes/panelApiKeys.js +179 -0
- package/backend/src/api/routes/pluginIde.js +1715 -135
- package/backend/src/api/routes/plugins.js +376 -219
- package/backend/src/api/routes/proxies.js +130 -0
- package/backend/src/api/routes/search.js +4 -0
- package/backend/src/api/routes/servers.js +20 -3
- package/backend/src/api/routes/settings.js +5 -0
- package/backend/src/api/routes/system.js +174 -174
- package/backend/src/api/routes/traces.js +131 -0
- package/backend/src/config/debug.config.js +36 -0
- package/backend/src/core/BotHistoryStore.js +180 -0
- package/backend/src/core/BotManager.js +14 -4
- package/backend/src/core/BotProcess.js +1517 -1092
- package/backend/src/core/EventGraphManager.js +37 -123
- package/backend/src/core/GraphExecutionEngine.js +977 -321
- package/backend/src/core/MessageQueue.js +12 -6
- package/backend/src/core/PluginLoader.js +99 -5
- package/backend/src/core/PluginManager.js +74 -13
- package/backend/src/core/TaskScheduler.js +1 -1
- package/backend/src/core/commands/whois.js +1 -1
- package/backend/src/core/node-registries/actions.js +70 -0
- package/backend/src/core/node-registries/arrays.js +18 -0
- package/backend/src/core/node-registries/data.js +1 -1
- package/backend/src/core/node-registries/events.js +14 -0
- package/backend/src/core/node-registries/logic.js +17 -0
- package/backend/src/core/node-registries/strings.js +34 -0
- package/backend/src/core/node-registries/type.js +25 -0
- package/backend/src/core/nodes/actions/bot_look_at.js +1 -1
- package/backend/src/core/nodes/actions/create_command.js +189 -0
- package/backend/src/core/nodes/actions/delete_command.js +92 -0
- package/backend/src/core/nodes/actions/update_command.js +133 -0
- package/backend/src/core/nodes/arrays/join.js +28 -0
- package/backend/src/core/nodes/data/cast.js +2 -1
- package/backend/src/core/nodes/logic/not.js +22 -0
- package/backend/src/core/nodes/strings/starts_with.js +1 -1
- package/backend/src/core/nodes/strings/to_lower.js +22 -0
- package/backend/src/core/nodes/strings/to_upper.js +22 -0
- package/backend/src/core/nodes/type/to_string.js +32 -0
- package/backend/src/core/services/BotLifecycleService.js +255 -16
- package/backend/src/core/services/CommandExecutionService.js +430 -351
- package/backend/src/core/services/DebugSessionManager.js +347 -0
- package/backend/src/core/services/GraphCollaborationManager.js +501 -0
- package/backend/src/core/services/MinecraftBotManager.js +259 -0
- package/backend/src/core/services/MinecraftViewerService.js +216 -0
- package/backend/src/core/services/TraceCollectorService.js +545 -0
- package/backend/src/core/system/RuntimeCommandRegistry.js +116 -0
- package/backend/src/core/system/Transport.js +0 -4
- package/backend/src/core/validation/nodeSchemas.js +6 -6
- package/backend/src/real-time/botApi/handlers/graphHandlers.js +2 -2
- package/backend/src/real-time/botApi/handlers/graphWebSocketHandlers.js +1 -1
- package/backend/src/real-time/botApi/utils.js +11 -0
- package/backend/src/real-time/panelNamespace.js +387 -0
- package/backend/src/real-time/presence.js +7 -2
- package/backend/src/real-time/socketHandler.js +395 -4
- package/backend/src/server.js +18 -0
- package/frontend/dist/assets/index-B1serztM.js +11210 -0
- package/frontend/dist/assets/index-t6K1u4OV.css +32 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package-lock.json +9437 -0
- package/frontend/package.json +8 -0
- package/package.json +2 -2
- package/screen/console.png +0 -0
- package/screen/dashboard.png +0 -0
- package/screen/graph_collabe.png +0 -0
- package/screen/graph_live_debug.png +0 -0
- package/screen/management_command.png +0 -0
- package/screen/node_debug_trace.png +0 -0
- package/screen/plugin_/320/276/320/261/320/267/320/276/321/200.png +0 -0
- package/screen/websocket.png +0 -0
- package/screen//320/275/320/260/321/201/321/202/321/200/320/276/320/271/320/272/320/270_/320/276/321/202/320/264/320/265/320/273/321/214/320/275/321/213/321/205_/320/272/320/276/320/274/320/260/320/275/320/264_/320/272/320/260/320/266/320/264/321/203_/320/272/320/276/320/274/320/260/320/275/320/273/320/264/321/203_/320/274/320/276/320/266/320/275/320/276_/320/275/320/260/321/201/321/202/321/200/320/260/320/270/320/262/320/260/321/202/321/214.png +0 -0
- package/screen//320/277/320/273/320/260/320/275/320/270/321/200/320/276/320/262/321/211/320/270/320/272_/320/274/320/276/320/266/320/275/320/276_/320/267/320/260/320/264/320/260/320/262/320/260/321/202/321/214_/320/264/320/265/320/271/321/201/321/202/320/262/320/270/321/217_/320/277/320/276_/320/262/321/200/320/265/320/274/320/265/320/275/320/270.png +0 -0
- package/frontend/dist/assets/index-CfTo92bP.css +0 -1
- package/frontend/dist/assets/index-CiFD5X9Z.js +0 -8344
|
@@ -109,15 +109,21 @@ class MessageQueue {
|
|
|
109
109
|
await this._handleWaitableTask(task);
|
|
110
110
|
} else {
|
|
111
111
|
let fullMessage;
|
|
112
|
-
|
|
112
|
+
const typeConfig = this.chatTypes[task.chatType];
|
|
113
|
+
|
|
114
|
+
// Для private/whisper добавляем username
|
|
115
|
+
if ((task.chatType === 'private' || task.chatType === 'whisper') && task.username) {
|
|
113
116
|
fullMessage = `/msg ${task.username} ${task.message}`;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
fullMessage =
|
|
118
|
-
}
|
|
117
|
+
}
|
|
118
|
+
// Для остальных типов используем prefix из конфига
|
|
119
|
+
else if (typeConfig && typeConfig.prefix) {
|
|
120
|
+
fullMessage = `${typeConfig.prefix}${task.message}`;
|
|
121
|
+
}
|
|
122
|
+
// Если нет prefix (command, chat) - отправляем как есть
|
|
123
|
+
else {
|
|
119
124
|
fullMessage = task.message;
|
|
120
125
|
}
|
|
126
|
+
|
|
121
127
|
this.bot.chat(fullMessage);
|
|
122
128
|
}
|
|
123
129
|
} catch (error) {
|
|
@@ -10,7 +10,72 @@ const { execSync: execSyncRaw } = require('child_process');
|
|
|
10
10
|
|
|
11
11
|
const projectRoot = path.resolve(__dirname, '..');
|
|
12
12
|
|
|
13
|
+
// Создаёт обёрнутый console для перехвата логов плагина
|
|
14
|
+
function createPluginConsole(botId, pluginName, originalConsole) {
|
|
15
|
+
const emitLog = (level, args) => {
|
|
16
|
+
try {
|
|
17
|
+
const message = args.map(arg =>
|
|
18
|
+
typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
|
|
19
|
+
).join(' ');
|
|
13
20
|
|
|
21
|
+
// Фильтруем системные логи (не отправляем в IDE)
|
|
22
|
+
const systemLogPatterns = [
|
|
23
|
+
/^\[Config\]/, // [Config] сообщения
|
|
24
|
+
/^\[System\]/, // [System] сообщения
|
|
25
|
+
/^\[Internal\]/, // [Internal] сообщения
|
|
26
|
+
/^\[Graph\]/, // [Graph] логи от визуальных графов
|
|
27
|
+
/\[Graph Log\]/, // [Graph Log] логи от нод графов
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const isSystemLog = systemLogPatterns.some(pattern => pattern.test(message));
|
|
31
|
+
if (isSystemLog) {
|
|
32
|
+
return; // Не отправляем системные логи в IDE
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const logData = {
|
|
36
|
+
botId,
|
|
37
|
+
pluginName,
|
|
38
|
+
level,
|
|
39
|
+
message,
|
|
40
|
+
source: 'plugin',
|
|
41
|
+
timestamp: Date.now()
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Отправляем лог в parent process через IPC
|
|
45
|
+
if (process.send) {
|
|
46
|
+
process.send({
|
|
47
|
+
type: 'plugin-log',
|
|
48
|
+
log: logData
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
originalConsole.error(`[PluginLog] Error emitting log:`, error);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
log: (...args) => {
|
|
58
|
+
originalConsole.log(`[${pluginName}]`, ...args);
|
|
59
|
+
emitLog('info', args);
|
|
60
|
+
},
|
|
61
|
+
info: (...args) => {
|
|
62
|
+
originalConsole.info(`[${pluginName}]`, ...args);
|
|
63
|
+
emitLog('info', args);
|
|
64
|
+
},
|
|
65
|
+
warn: (...args) => {
|
|
66
|
+
originalConsole.warn(`[${pluginName}]`, ...args);
|
|
67
|
+
emitLog('warn', args);
|
|
68
|
+
},
|
|
69
|
+
error: (...args) => {
|
|
70
|
+
originalConsole.error(`[${pluginName}]`, ...args);
|
|
71
|
+
emitLog('error', args);
|
|
72
|
+
},
|
|
73
|
+
debug: (...args) => {
|
|
74
|
+
originalConsole.debug(`[${pluginName}]`, ...args);
|
|
75
|
+
emitLog('debug', args);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
14
79
|
|
|
15
80
|
async function initializePlugins(bot, installedPlugins = [], prisma) {
|
|
16
81
|
if (!installedPlugins || installedPlugins.length === 0) return;
|
|
@@ -70,23 +135,52 @@ async function initializePlugins(bot, installedPlugins = [], prisma) {
|
|
|
70
135
|
}
|
|
71
136
|
}
|
|
72
137
|
|
|
138
|
+
// Создаём обёрнутый console для перехвата логов плагина
|
|
139
|
+
const originalConsole = global.console;
|
|
140
|
+
const pluginConsole = createPluginConsole(bot.config.id, plugin.name, originalConsole);
|
|
141
|
+
|
|
142
|
+
// Добавляем кастомный console в bot объект для использования плагинами
|
|
143
|
+
bot.console = pluginConsole;
|
|
144
|
+
|
|
145
|
+
// Опции плагина с кастомным console
|
|
146
|
+
const pluginOptions = {
|
|
147
|
+
settings: finalSettings,
|
|
148
|
+
store,
|
|
149
|
+
console: pluginConsole // Передаём обёрнутый console в опциях
|
|
150
|
+
};
|
|
151
|
+
|
|
73
152
|
if (typeof pluginModule === 'function') {
|
|
74
|
-
pluginModule(bot,
|
|
153
|
+
pluginModule(bot, pluginOptions);
|
|
75
154
|
} else if (pluginModule && typeof pluginModule.onLoad === 'function') {
|
|
76
|
-
pluginModule.onLoad(bot,
|
|
155
|
+
pluginModule.onLoad(bot, pluginOptions);
|
|
77
156
|
} else if (pluginModule && pluginModule.default && typeof pluginModule.default === 'function') {
|
|
78
|
-
pluginModule.default(bot,
|
|
157
|
+
pluginModule.default(bot, pluginOptions);
|
|
79
158
|
} else if (pluginModule && pluginModule.default && typeof pluginModule.default.onLoad === 'function') {
|
|
80
|
-
pluginModule.default.onLoad(bot,
|
|
159
|
+
pluginModule.default.onLoad(bot, pluginOptions);
|
|
81
160
|
} else {
|
|
82
161
|
sendLog(`[PluginLoader] [ERROR] ${plugin.name} не экспортирует функцию или объект с методом onLoad.`);
|
|
83
162
|
}
|
|
84
163
|
};
|
|
85
164
|
|
|
86
165
|
sendLog(`[PluginLoader] Загрузка: ${plugin.name} (v${plugin.version}) из ${normalizedPath}`);
|
|
87
|
-
|
|
166
|
+
|
|
88
167
|
try {
|
|
89
168
|
await loadAndInit();
|
|
169
|
+
|
|
170
|
+
// Отправляем сообщение об успешной загрузке в IDE console
|
|
171
|
+
const { getIOSafe } = require('../real-time/socketHandler');
|
|
172
|
+
const io = getIOSafe();
|
|
173
|
+
if (io) {
|
|
174
|
+
const room = `plugin-logs:${bot.config.id}:${plugin.name}`;
|
|
175
|
+
io.to(room).emit('plugin-log', {
|
|
176
|
+
botId: bot.config.id,
|
|
177
|
+
pluginName: plugin.name,
|
|
178
|
+
level: 'success',
|
|
179
|
+
message: `✓ Плагин ${plugin.name} v${plugin.version} успешно загружен`,
|
|
180
|
+
source: 'system',
|
|
181
|
+
timestamp: Date.now()
|
|
182
|
+
});
|
|
183
|
+
}
|
|
90
184
|
} catch (error) {
|
|
91
185
|
let handled = false;
|
|
92
186
|
let lastError = error;
|
|
@@ -360,28 +360,34 @@ class PluginManager {
|
|
|
360
360
|
}
|
|
361
361
|
|
|
362
362
|
console.log(`[PluginManager] Начало обновления плагина ${plugin.name}${targetTag ? ` до версии ${targetTag}` : ''}...`);
|
|
363
|
-
|
|
363
|
+
|
|
364
364
|
const repoUrl = plugin.sourceUri;
|
|
365
365
|
const botId = plugin.botId;
|
|
366
|
-
|
|
367
|
-
|
|
366
|
+
const oldVersion = plugin.version;
|
|
367
|
+
|
|
368
368
|
const backupData = {
|
|
369
369
|
name: plugin.name,
|
|
370
370
|
settings: plugin.settings,
|
|
371
371
|
isEnabled: plugin.isEnabled,
|
|
372
|
-
// PluginDataStore сохранятся автоматически (привязаны к pluginName + botId)
|
|
373
372
|
};
|
|
374
373
|
console.log(`[PluginManager] Настройки плагина ${plugin.name} сохранены для миграции.`);
|
|
375
|
-
|
|
376
|
-
// Удаляем старую версию
|
|
374
|
+
|
|
377
375
|
await this.deletePlugin(pluginId);
|
|
378
376
|
console.log(`[PluginManager] Старая версия ${plugin.name} удалена, устанавливаем новую...`);
|
|
379
|
-
|
|
380
|
-
// Устанавливаем новую версию с конкретным тегом (если указан)
|
|
377
|
+
|
|
381
378
|
const newPlugin = await this.installFromGithub(botId, repoUrl, prisma, true, targetTag);
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
379
|
+
|
|
380
|
+
const oldMajor = semver.major(semver.coerce(oldVersion) || '0.0.0');
|
|
381
|
+
const newMajor = semver.major(semver.coerce(newPlugin.version) || '0.0.0');
|
|
382
|
+
const isMajorUpdate = newMajor > oldMajor;
|
|
383
|
+
|
|
384
|
+
if (isMajorUpdate) {
|
|
385
|
+
console.log(`[PluginManager] Мажорное обновление ${oldVersion} → ${newPlugin.version}. Настройки сброшены к дефолтным.`);
|
|
386
|
+
await prisma.installedPlugin.update({
|
|
387
|
+
where: { id: newPlugin.id },
|
|
388
|
+
data: { isEnabled: backupData.isEnabled },
|
|
389
|
+
});
|
|
390
|
+
} else if (backupData.settings && newPlugin) {
|
|
385
391
|
try {
|
|
386
392
|
await prisma.installedPlugin.update({
|
|
387
393
|
where: { id: newPlugin.id },
|
|
@@ -393,10 +399,9 @@ class PluginManager {
|
|
|
393
399
|
console.log(`[PluginManager] Настройки успешно восстановлены для ${plugin.name}`);
|
|
394
400
|
} catch (settingsError) {
|
|
395
401
|
console.error(`[PluginManager] Не удалось восстановить настройки для ${plugin.name}:`, settingsError);
|
|
396
|
-
// Не бросаем ошибку, т.к. плагин уже установлен
|
|
397
402
|
}
|
|
398
403
|
}
|
|
399
|
-
|
|
404
|
+
|
|
400
405
|
return newPlugin;
|
|
401
406
|
}
|
|
402
407
|
|
|
@@ -511,6 +516,62 @@ class PluginManager {
|
|
|
511
516
|
console.log(`[PluginManager] Удалено ${count} записей из хранилища.`);
|
|
512
517
|
return { count };
|
|
513
518
|
}
|
|
519
|
+
|
|
520
|
+
async reloadLocalPlugin(pluginId) {
|
|
521
|
+
const plugin = await prisma.installedPlugin.findUnique({ where: { id: pluginId } });
|
|
522
|
+
if (!plugin) {
|
|
523
|
+
throw new Error('Плагин не найден.');
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
if (plugin.sourceType !== 'LOCAL' && plugin.sourceType !== 'LOCAL_IDE') {
|
|
527
|
+
throw new Error('Перезагрузка доступна только для локальных плагинов.');
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const pluginPath = plugin.path;
|
|
531
|
+
const packageJsonPath = path.join(pluginPath, 'package.json');
|
|
532
|
+
|
|
533
|
+
if (!await fse.pathExists(packageJsonPath)) {
|
|
534
|
+
throw new Error(`package.json не найден: ${packageJsonPath}`);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
console.log(`[PluginManager] Перезагрузка локального плагина ${plugin.name} из ${pluginPath}`);
|
|
538
|
+
|
|
539
|
+
let packageJson;
|
|
540
|
+
try {
|
|
541
|
+
packageJson = JSON.parse(await fse.readFile(packageJsonPath, 'utf-8'));
|
|
542
|
+
} catch (e) {
|
|
543
|
+
throw new Error(`Не удалось прочитать package.json: ${e.message}`);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const manifest = packageJson.botpanel || {};
|
|
547
|
+
const defaultSettings = {};
|
|
548
|
+
|
|
549
|
+
if (manifest.settings) {
|
|
550
|
+
for (const [key, config] of Object.entries(manifest.settings)) {
|
|
551
|
+
if (config.default !== undefined) {
|
|
552
|
+
defaultSettings[key] = config.default;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const updatedPlugin = await prisma.installedPlugin.update({
|
|
558
|
+
where: { id: pluginId },
|
|
559
|
+
data: {
|
|
560
|
+
version: packageJson.version,
|
|
561
|
+
description: packageJson.description || '',
|
|
562
|
+
manifest: JSON.stringify(manifest),
|
|
563
|
+
settings: JSON.stringify(defaultSettings),
|
|
564
|
+
},
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
console.log(`[PluginManager] Плагин ${plugin.name} перезагружен. Версия: ${packageJson.version}, настройки сброшены.`);
|
|
568
|
+
|
|
569
|
+
if (this.botManager) {
|
|
570
|
+
await this.botManager.reloadPlugins(plugin.botId);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
return updatedPlugin;
|
|
574
|
+
}
|
|
514
575
|
}
|
|
515
576
|
|
|
516
577
|
module.exports = PluginManager;
|
|
@@ -51,7 +51,7 @@ class TaskScheduler {
|
|
|
51
51
|
|
|
52
52
|
for (const botId of botIds) {
|
|
53
53
|
try {
|
|
54
|
-
const botConfig = await prisma.bot.findUnique({ where: { id: botId }, include: { server: true } });
|
|
54
|
+
const botConfig = await prisma.bot.findUnique({ where: { id: botId }, include: { server: true, proxy: true } });
|
|
55
55
|
if (!botConfig) continue;
|
|
56
56
|
|
|
57
57
|
switch (task.action) {
|
|
@@ -33,7 +33,7 @@ class WhoisCommand extends Command {
|
|
|
33
33
|
.join(', ') || 'Нет групп';
|
|
34
34
|
|
|
35
35
|
// Статус
|
|
36
|
-
const status = targetUser.isBlacklisted ? '⛔ В черном списке' : '✅
|
|
36
|
+
const status = targetUser.isBlacklisted ? '⛔ В черном списке' : '✅ Не в чс';
|
|
37
37
|
|
|
38
38
|
// Форматируем вывод в зависимости от транспорта
|
|
39
39
|
let message;
|
|
@@ -127,6 +127,76 @@ function registerNodes(registry) {
|
|
|
127
127
|
]
|
|
128
128
|
}
|
|
129
129
|
});
|
|
130
|
+
|
|
131
|
+
registry.registerNodeType({
|
|
132
|
+
type: 'action:create_command',
|
|
133
|
+
label: '➕ Создать команду',
|
|
134
|
+
category: 'Действия',
|
|
135
|
+
description: 'Создает новую команду (временную или постоянную)',
|
|
136
|
+
graphType: GRAPH_TYPES.ALL,
|
|
137
|
+
executor: require('../nodes/actions/create_command').execute,
|
|
138
|
+
pins: {
|
|
139
|
+
inputs: [
|
|
140
|
+
{ id: 'exec', name: 'Выполнить', type: 'Exec', required: true },
|
|
141
|
+
{ id: 'name', name: 'Имя команды', type: 'String', required: true },
|
|
142
|
+
{ id: 'description', name: 'Описание', type: 'String', required: false },
|
|
143
|
+
{ id: 'aliases', name: 'Алиасы', type: 'Array', required: false },
|
|
144
|
+
{ id: 'cooldown', name: 'Кулдаун (сек)', type: 'Number', required: false },
|
|
145
|
+
{ id: 'allowedChatTypes', name: 'Типы чата', type: 'Array', required: false },
|
|
146
|
+
{ id: 'permissionName', name: 'Название права', type: 'String', required: false },
|
|
147
|
+
{ id: 'temporary', name: 'Временная?', type: 'Boolean', required: false }
|
|
148
|
+
],
|
|
149
|
+
outputs: [
|
|
150
|
+
{ id: 'exec', name: 'Выполнено', type: 'Exec' },
|
|
151
|
+
{ id: 'commandId', name: 'ID команды', type: 'Number' },
|
|
152
|
+
{ id: 'success', name: 'Успешно', type: 'Boolean' }
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
registry.registerNodeType({
|
|
158
|
+
type: 'action:update_command',
|
|
159
|
+
label: '✏️ Редактировать команду',
|
|
160
|
+
category: 'Действия',
|
|
161
|
+
description: 'Изменяет параметры существующей команды',
|
|
162
|
+
graphType: GRAPH_TYPES.ALL,
|
|
163
|
+
executor: require('../nodes/actions/update_command').execute,
|
|
164
|
+
pins: {
|
|
165
|
+
inputs: [
|
|
166
|
+
{ id: 'exec', name: 'Выполнить', type: 'Exec', required: true },
|
|
167
|
+
{ id: 'commandName', name: 'Имя команды', type: 'String', required: true },
|
|
168
|
+
{ id: 'newName', name: 'Новое имя', type: 'String', required: false },
|
|
169
|
+
{ id: 'description', name: 'Описание', type: 'String', required: false },
|
|
170
|
+
{ id: 'aliases', name: 'Алиасы', type: 'Array', required: false },
|
|
171
|
+
{ id: 'cooldown', name: 'Кулдаун (сек)', type: 'Number', required: false },
|
|
172
|
+
{ id: 'allowedChatTypes', name: 'Типы чата', type: 'Array', required: false },
|
|
173
|
+
{ id: 'permissionName', name: 'Название права', type: 'String', required: false }
|
|
174
|
+
],
|
|
175
|
+
outputs: [
|
|
176
|
+
{ id: 'exec', name: 'Выполнено', type: 'Exec' },
|
|
177
|
+
{ id: 'success', name: 'Успешно', type: 'Boolean' }
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
registry.registerNodeType({
|
|
183
|
+
type: 'action:delete_command',
|
|
184
|
+
label: '🗑️ Удалить команду',
|
|
185
|
+
category: 'Действия',
|
|
186
|
+
description: 'Удаляет существующую команду бота',
|
|
187
|
+
graphType: GRAPH_TYPES.ALL,
|
|
188
|
+
executor: require('../nodes/actions/delete_command').execute,
|
|
189
|
+
pins: {
|
|
190
|
+
inputs: [
|
|
191
|
+
{ id: 'exec', name: 'Выполнить', type: 'Exec', required: true },
|
|
192
|
+
{ id: 'commandName', name: 'Имя команды', type: 'String', required: true }
|
|
193
|
+
],
|
|
194
|
+
outputs: [
|
|
195
|
+
{ id: 'exec', name: 'Выполнено', type: 'Exec' },
|
|
196
|
+
{ id: 'success', name: 'Успешно', type: 'Boolean' }
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
});
|
|
130
200
|
}
|
|
131
201
|
|
|
132
202
|
module.exports = { registerNodes };
|
|
@@ -132,6 +132,24 @@ function registerNodes(registry) {
|
|
|
132
132
|
]
|
|
133
133
|
}
|
|
134
134
|
});
|
|
135
|
+
|
|
136
|
+
registry.registerNodeType({
|
|
137
|
+
type: 'array:join',
|
|
138
|
+
label: '🔗 Объединить в строку',
|
|
139
|
+
category: 'Массив',
|
|
140
|
+
description: 'Объединяет элементы массива в строку с разделителем.',
|
|
141
|
+
graphType: GRAPH_TYPES.ALL,
|
|
142
|
+
evaluator: require('../nodes/arrays/join').evaluate,
|
|
143
|
+
pins: {
|
|
144
|
+
inputs: [
|
|
145
|
+
{ id: 'array', name: 'Массив', type: 'Array', required: false },
|
|
146
|
+
{ id: 'separator', name: 'Разделитель', type: 'String', required: false }
|
|
147
|
+
],
|
|
148
|
+
outputs: [
|
|
149
|
+
{ id: 'result', name: 'Result', type: 'String' }
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
});
|
|
135
153
|
}
|
|
136
154
|
|
|
137
155
|
module.exports = { registerNodes };
|
|
@@ -139,7 +139,7 @@ function registerNodes(registry) {
|
|
|
139
139
|
{ id: 'value', name: 'Значение', type: 'Wildcard', required: true }
|
|
140
140
|
],
|
|
141
141
|
outputs: [
|
|
142
|
-
{ id: '
|
|
142
|
+
{ id: 'result', name: 'Результат', type: 'Wildcard' }
|
|
143
143
|
]
|
|
144
144
|
}
|
|
145
145
|
});
|
|
@@ -148,6 +148,20 @@ function registerNodes(registry) {
|
|
|
148
148
|
}
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
+
registry.registerNodeType({
|
|
152
|
+
type: 'event:botStartup',
|
|
153
|
+
label: '🚀 При запуске бота',
|
|
154
|
+
category: 'События',
|
|
155
|
+
description: 'Срабатывает один раз при запуске бота.',
|
|
156
|
+
graphType: GRAPH_TYPES.EVENT,
|
|
157
|
+
pins: {
|
|
158
|
+
inputs: [],
|
|
159
|
+
outputs: [
|
|
160
|
+
{ id: 'exec', name: 'Выполнить', type: 'Exec' },
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
151
165
|
registry.registerNodeType({
|
|
152
166
|
type: 'event:health',
|
|
153
167
|
label: '❤️ Здоровье/Голод изменилось',
|
|
@@ -40,6 +40,23 @@ function registerNodes(registry) {
|
|
|
40
40
|
]
|
|
41
41
|
}
|
|
42
42
|
});
|
|
43
|
+
|
|
44
|
+
registry.registerNodeType({
|
|
45
|
+
type: 'logic:not',
|
|
46
|
+
label: '! НЕ',
|
|
47
|
+
category: 'Логика',
|
|
48
|
+
description: 'Инвертирует boolean значение (NOT).',
|
|
49
|
+
graphType: GRAPH_TYPES.ALL,
|
|
50
|
+
evaluator: require('../nodes/logic/not').evaluate,
|
|
51
|
+
pins: {
|
|
52
|
+
inputs: [
|
|
53
|
+
{ id: 'value', name: 'Значение', type: 'Boolean', required: false }
|
|
54
|
+
],
|
|
55
|
+
outputs: [
|
|
56
|
+
{ id: 'result', name: 'Результат', type: 'Boolean' }
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
});
|
|
43
60
|
}
|
|
44
61
|
|
|
45
62
|
module.exports = { registerNodes };
|
|
@@ -148,6 +148,40 @@ function registerNodes(registry) {
|
|
|
148
148
|
]
|
|
149
149
|
}
|
|
150
150
|
});
|
|
151
|
+
|
|
152
|
+
registry.registerNodeType({
|
|
153
|
+
type: 'string:to_upper',
|
|
154
|
+
label: '⬆️ В верхний регистр',
|
|
155
|
+
category: 'Строки',
|
|
156
|
+
description: 'Преобразует строку в верхний регистр (UPPERCASE).',
|
|
157
|
+
graphType: GRAPH_TYPES.ALL,
|
|
158
|
+
evaluator: require('../nodes/strings/to_upper').evaluate,
|
|
159
|
+
pins: {
|
|
160
|
+
inputs: [
|
|
161
|
+
{ id: 'text', name: 'Текст', type: 'String', required: false }
|
|
162
|
+
],
|
|
163
|
+
outputs: [
|
|
164
|
+
{ id: 'result', name: 'Result', type: 'String' }
|
|
165
|
+
]
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
registry.registerNodeType({
|
|
170
|
+
type: 'string:to_lower',
|
|
171
|
+
label: '⬇️ В нижний регистр',
|
|
172
|
+
category: 'Строки',
|
|
173
|
+
description: 'Преобразует строку в нижний регистр (lowercase).',
|
|
174
|
+
graphType: GRAPH_TYPES.ALL,
|
|
175
|
+
evaluator: require('../nodes/strings/to_lower').evaluate,
|
|
176
|
+
pins: {
|
|
177
|
+
inputs: [
|
|
178
|
+
{ id: 'text', name: 'Текст', type: 'String', required: false }
|
|
179
|
+
],
|
|
180
|
+
outputs: [
|
|
181
|
+
{ id: 'result', name: 'Result', type: 'String' }
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
});
|
|
151
185
|
}
|
|
152
186
|
|
|
153
187
|
module.exports = { registerNodes };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const { GRAPH_TYPES } = require('../constants/graphTypes');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Регистрация нод категории "Преобразование типов"
|
|
5
|
+
*/
|
|
6
|
+
function registerNodes(registry) {
|
|
7
|
+
registry.registerNodeType({
|
|
8
|
+
type: 'type:to_string',
|
|
9
|
+
label: '📝 В строку',
|
|
10
|
+
category: 'Типы',
|
|
11
|
+
description: 'Преобразует любое значение в строку (toString).',
|
|
12
|
+
graphType: GRAPH_TYPES.ALL,
|
|
13
|
+
evaluator: require('../nodes/type/to_string').evaluate,
|
|
14
|
+
pins: {
|
|
15
|
+
inputs: [
|
|
16
|
+
{ id: 'value', name: 'Значение', type: 'Wildcard', required: false }
|
|
17
|
+
],
|
|
18
|
+
outputs: [
|
|
19
|
+
{ id: 'result', name: 'Result', type: 'String' }
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = { registerNodes };
|