blockmine 1.22.0 → 1.23.1

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.
Files changed (108) hide show
  1. package/.claude/agents/code-architect.md +34 -0
  2. package/.claude/agents/code-explorer.md +51 -0
  3. package/.claude/agents/code-reviewer.md +46 -0
  4. package/.claude/commands/feature-dev.md +125 -0
  5. package/.claude/settings.json +5 -1
  6. package/.claude/settings.local.json +12 -1
  7. package/.claude/skills/frontend-design/SKILL.md +42 -0
  8. package/CHANGELOG.md +32 -1
  9. package/README.md +302 -152
  10. package/backend/package-lock.json +681 -9
  11. package/backend/package.json +8 -0
  12. package/backend/prisma/migrations/20251116111851_add_execution_trace/migration.sql +22 -0
  13. package/backend/prisma/migrations/20251120154914_add_panel_api_keys/migration.sql +21 -0
  14. package/backend/prisma/migrations/20251121110241_add_proxy_table/migration.sql +45 -0
  15. package/backend/prisma/schema.prisma +70 -1
  16. package/backend/src/__tests__/services/BotLifecycleService.test.js +9 -4
  17. package/backend/src/ai/plugin-assistant-system-prompt.md +788 -0
  18. package/backend/src/api/middleware/auth.js +27 -0
  19. package/backend/src/api/middleware/botAccess.js +7 -3
  20. package/backend/src/api/middleware/panelApiAuth.js +135 -0
  21. package/backend/src/api/routes/aiAssistant.js +995 -0
  22. package/backend/src/api/routes/auth.js +90 -54
  23. package/backend/src/api/routes/botCommands.js +107 -0
  24. package/backend/src/api/routes/botGroups.js +165 -0
  25. package/backend/src/api/routes/botHistory.js +108 -0
  26. package/backend/src/api/routes/botPermissions.js +99 -0
  27. package/backend/src/api/routes/botStatus.js +36 -0
  28. package/backend/src/api/routes/botUsers.js +162 -0
  29. package/backend/src/api/routes/bots.js +108 -59
  30. package/backend/src/api/routes/eventGraphs.js +4 -1
  31. package/backend/src/api/routes/logs.js +13 -3
  32. package/backend/src/api/routes/panel.js +3 -3
  33. package/backend/src/api/routes/panelApiKeys.js +179 -0
  34. package/backend/src/api/routes/pluginIde.js +1715 -135
  35. package/backend/src/api/routes/plugins.js +170 -13
  36. package/backend/src/api/routes/proxies.js +130 -0
  37. package/backend/src/api/routes/search.js +4 -0
  38. package/backend/src/api/routes/servers.js +20 -3
  39. package/backend/src/api/routes/settings.js +5 -0
  40. package/backend/src/api/routes/system.js +3 -3
  41. package/backend/src/api/routes/traces.js +131 -0
  42. package/backend/src/config/debug.config.js +36 -0
  43. package/backend/src/core/BotHistoryStore.js +180 -0
  44. package/backend/src/core/BotManager.js +14 -4
  45. package/backend/src/core/BotProcess.js +1517 -1092
  46. package/backend/src/core/EventGraphManager.js +194 -280
  47. package/backend/src/core/GraphExecutionEngine.js +1004 -321
  48. package/backend/src/core/MessageQueue.js +12 -6
  49. package/backend/src/core/PluginLoader.js +99 -5
  50. package/backend/src/core/PluginManager.js +74 -13
  51. package/backend/src/core/TaskScheduler.js +1 -1
  52. package/backend/src/core/commands/whois.js +1 -1
  53. package/backend/src/core/node-registries/actions.js +72 -2
  54. package/backend/src/core/node-registries/arrays.js +18 -0
  55. package/backend/src/core/node-registries/data.js +1 -1
  56. package/backend/src/core/node-registries/events.js +14 -0
  57. package/backend/src/core/node-registries/logic.js +17 -0
  58. package/backend/src/core/node-registries/strings.js +34 -0
  59. package/backend/src/core/node-registries/type.js +25 -0
  60. package/backend/src/core/nodes/actions/bot_look_at.js +1 -1
  61. package/backend/src/core/nodes/actions/create_command.js +189 -0
  62. package/backend/src/core/nodes/actions/delete_command.js +92 -0
  63. package/backend/src/core/nodes/actions/http_request.js +23 -4
  64. package/backend/src/core/nodes/actions/send_message.js +2 -12
  65. package/backend/src/core/nodes/actions/update_command.js +133 -0
  66. package/backend/src/core/nodes/arrays/join.js +28 -0
  67. package/backend/src/core/nodes/data/cast.js +2 -1
  68. package/backend/src/core/nodes/data/string_literal.js +2 -13
  69. package/backend/src/core/nodes/logic/not.js +22 -0
  70. package/backend/src/core/nodes/strings/starts_with.js +1 -1
  71. package/backend/src/core/nodes/strings/to_lower.js +22 -0
  72. package/backend/src/core/nodes/strings/to_upper.js +22 -0
  73. package/backend/src/core/nodes/type/to_string.js +32 -0
  74. package/backend/src/core/services/BotLifecycleService.js +835 -596
  75. package/backend/src/core/services/CommandExecutionService.js +430 -351
  76. package/backend/src/core/services/DebugSessionManager.js +347 -0
  77. package/backend/src/core/services/GraphCollaborationManager.js +501 -0
  78. package/backend/src/core/services/MinecraftBotManager.js +259 -0
  79. package/backend/src/core/services/MinecraftViewerService.js +216 -0
  80. package/backend/src/core/services/TraceCollectorService.js +545 -0
  81. package/backend/src/core/system/RuntimeCommandRegistry.js +116 -0
  82. package/backend/src/core/system/Transport.js +0 -4
  83. package/backend/src/core/validation/nodeSchemas.js +6 -6
  84. package/backend/src/real-time/botApi/handlers/graphHandlers.js +2 -2
  85. package/backend/src/real-time/botApi/handlers/graphWebSocketHandlers.js +1 -1
  86. package/backend/src/real-time/botApi/utils.js +11 -0
  87. package/backend/src/real-time/panelNamespace.js +387 -0
  88. package/backend/src/real-time/presence.js +7 -2
  89. package/backend/src/real-time/socketHandler.js +395 -4
  90. package/backend/src/server.js +18 -0
  91. package/frontend/dist/assets/index-DqzDkFsP.js +11210 -0
  92. package/frontend/dist/assets/index-t6K1u4OV.css +32 -0
  93. package/frontend/dist/index.html +2 -2
  94. package/frontend/package-lock.json +9437 -0
  95. package/frontend/package.json +8 -0
  96. package/package.json +2 -2
  97. package/screen/console.png +0 -0
  98. package/screen/dashboard.png +0 -0
  99. package/screen/graph_collabe.png +0 -0
  100. package/screen/graph_live_debug.png +0 -0
  101. package/screen/management_command.png +0 -0
  102. package/screen/node_debug_trace.png +0 -0
  103. package/screen/plugin_/320/276/320/261/320/267/320/276/321/200.png +0 -0
  104. package/screen/websocket.png +0 -0
  105. 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
  106. 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
  107. package/frontend/dist/assets/index-CfTo92bP.css +0 -1
  108. package/frontend/dist/assets/index-CiFD5X9Z.js +0 -8344
@@ -0,0 +1,189 @@
1
+ const prismaService = require('../../PrismaService');
2
+ const prisma = prismaService.getClient();
3
+ const { getRuntimeCommandRegistry } = require('../../system/RuntimeCommandRegistry');
4
+ const Command = require('../../system/Command');
5
+
6
+ /**
7
+ * Создает новую команду (временную или постоянную)
8
+ * @param {object} node - Экземпляр узла из графа
9
+ * @param {object} context - Контекст выполнения графа
10
+ * @param {object} helpers - Вспомогательные функции движка
11
+ */
12
+ async function execute(node, context, helpers) {
13
+ const { resolvePinValue, traverse, memo } = helpers;
14
+ const { botId, botManager } = context;
15
+
16
+ try {
17
+ const name = await resolvePinValue(node, 'name');
18
+ const description = await resolvePinValue(node, 'description', '');
19
+ let aliases = await resolvePinValue(node, 'aliases', []);
20
+ const cooldown = await resolvePinValue(node, 'cooldown', 0);
21
+ let allowedChatTypes = await resolvePinValue(node, 'allowedChatTypes', ['chat', 'private']);
22
+ const permissionName = await resolvePinValue(node, 'permissionName', null);
23
+ const temporary = await resolvePinValue(node, 'temporary', false);
24
+
25
+ if (typeof aliases === 'string') {
26
+ try {
27
+ const normalizedString = aliases.replace(/'/g, '"');
28
+ aliases = JSON.parse(normalizedString);
29
+ } catch (e) {
30
+ console.warn('[create_command] Не удалось распарсить aliases:', e);
31
+ aliases = [];
32
+ }
33
+ }
34
+
35
+ if (typeof allowedChatTypes === 'string') {
36
+ try {
37
+ const normalizedString = allowedChatTypes.replace(/'/g, '"');
38
+ allowedChatTypes = JSON.parse(normalizedString);
39
+ } catch (e) {
40
+ console.warn('[create_command] Не удалось распарсить allowedChatTypes:', e);
41
+ allowedChatTypes = ['chat', 'private'];
42
+ }
43
+ }
44
+
45
+ if (!name) {
46
+ console.error('[create_command] Имя команды обязательно');
47
+ memo.set(`${node.id}:success`, false);
48
+ memo.set(`${node.id}:commandId`, null);
49
+ await traverse(node, 'exec');
50
+ return;
51
+ }
52
+
53
+ let commandId = null;
54
+
55
+ if (temporary) {
56
+ commandId = `temp_${Date.now()}`;
57
+
58
+ let permissionId = null;
59
+
60
+ if (permissionName) {
61
+ const permission = await prisma.permission.findFirst({
62
+ where: {
63
+ botId,
64
+ name: permissionName
65
+ }
66
+ });
67
+
68
+ if (permission) {
69
+ permissionId = permission.id;
70
+ }
71
+ }
72
+
73
+ const tempCommand = new Command({
74
+ name,
75
+ description: description || '',
76
+ aliases: Array.isArray(aliases) ? aliases : [],
77
+ cooldown: cooldown || 0,
78
+ allowedChatTypes: Array.isArray(allowedChatTypes) ? allowedChatTypes : ['chat', 'private'],
79
+ args: [],
80
+ owner: 'runtime',
81
+ });
82
+
83
+ tempCommand.permissionId = permissionId;
84
+ tempCommand.isTemporary = true;
85
+ tempCommand.tempId = commandId;
86
+ tempCommand.isVisual = false;
87
+
88
+ tempCommand.handler = () => {
89
+ // Handler будет вызван через validate_and_run_command в BotProcess
90
+ };
91
+
92
+ // Регистрируем в runtime registry (для главного процесса)
93
+ const runtimeRegistry = getRuntimeCommandRegistry();
94
+ runtimeRegistry.register(botId, name, tempCommand);
95
+
96
+ // Также регистрируем алиасы в runtime registry
97
+ if (Array.isArray(aliases)) {
98
+ for (const alias of aliases) {
99
+ runtimeRegistry.register(botId, alias, tempCommand);
100
+ }
101
+ }
102
+
103
+ // Отправляем IPC сообщение в child process для регистрации команды
104
+ if (botManager && botManager.processManager) {
105
+ botManager.processManager.sendMessage(botId, {
106
+ type: 'register_temp_command',
107
+ commandData: {
108
+ name,
109
+ description: description || '',
110
+ aliases: Array.isArray(aliases) ? aliases : [],
111
+ cooldown: cooldown || 0,
112
+ allowedChatTypes: Array.isArray(allowedChatTypes) ? allowedChatTypes : ['chat', 'private'],
113
+ permissionId,
114
+ tempId: commandId,
115
+ }
116
+ });
117
+ }
118
+
119
+ console.log(`[create_command] Временная команда "${name}" создана с ID ${commandId}`);
120
+ } else {
121
+ const existingCommand = await prisma.command.findFirst({
122
+ where: { botId, name }
123
+ });
124
+
125
+ if (existingCommand) {
126
+ console.error(`[create_command] Команда "${name}" уже существует`);
127
+ memo.set(`${node.id}:success`, false);
128
+ memo.set(`${node.id}:commandId`, null);
129
+ await traverse(node, 'exec');
130
+ return;
131
+ }
132
+
133
+ let permissionId = null;
134
+ if (permissionName) {
135
+ const permission = await prisma.permission.findFirst({
136
+ where: {
137
+ botId,
138
+ name: permissionName
139
+ }
140
+ });
141
+
142
+ if (permission) {
143
+ permissionId = permission.id;
144
+ } else {
145
+ console.warn(`[create_command] Право "${permissionName}" не найдено, команда будет создана без права`);
146
+ }
147
+ }
148
+
149
+ const newCommand = await prisma.command.create({
150
+ data: {
151
+ botId,
152
+ name,
153
+ description: description || '',
154
+ aliases: JSON.stringify(Array.isArray(aliases) ? aliases : []),
155
+ permissionId: permissionId || null,
156
+ cooldown: cooldown || 0,
157
+ allowedChatTypes: JSON.stringify(Array.isArray(allowedChatTypes) ? allowedChatTypes : ['chat', 'private']),
158
+ isVisual: true,
159
+ argumentsJson: '[]',
160
+ graphJson: JSON.stringify({
161
+ nodes: [],
162
+ edges: []
163
+ }),
164
+ pluginOwnerId: null
165
+ }
166
+ });
167
+
168
+ commandId = newCommand.id;
169
+ console.log(`[create_command] Постоянная команда "${name}" создана с ID ${commandId}`);
170
+
171
+ if (botManager && botManager.reloadBotConfigInRealTime) {
172
+ botManager.reloadBotConfigInRealTime(botId);
173
+ }
174
+ }
175
+
176
+ memo.set(`${node.id}:commandId`, commandId);
177
+ memo.set(`${node.id}:success`, true);
178
+ } catch (error) {
179
+ console.error('[create_command] Ошибка создания команды:', error);
180
+ memo.set(`${node.id}:success`, false);
181
+ memo.set(`${node.id}:commandId`, null);
182
+ }
183
+
184
+ await traverse(node, 'exec');
185
+ }
186
+
187
+ module.exports = {
188
+ execute,
189
+ };
@@ -0,0 +1,92 @@
1
+ const prismaService = require('../../PrismaService');
2
+ const prisma = prismaService.getClient();
3
+ const { getRuntimeCommandRegistry } = require('../../system/RuntimeCommandRegistry');
4
+
5
+ /**
6
+ * Удаляет существующую команду
7
+ * @param {object} node - Экземпляр узла из графа
8
+ * @param {object} context - Контекст выполнения графа
9
+ * @param {object} helpers - Вспомогательные функции движка
10
+ */
11
+ async function execute(node, context, helpers) {
12
+ const { resolvePinValue, traverse, memo } = helpers;
13
+ const { botId, botManager } = context;
14
+
15
+ try {
16
+ const commandName = await resolvePinValue(node, 'commandName');
17
+
18
+ if (!commandName) {
19
+ console.error('[delete_command] Имя команды обязательно');
20
+ memo.set(`${node.id}:success`, false);
21
+ await traverse(node, 'exec');
22
+ return;
23
+ }
24
+
25
+ const runtimeRegistry = getRuntimeCommandRegistry();
26
+
27
+ if (runtimeRegistry.has(botId, commandName)) {
28
+ const tempCommand = runtimeRegistry.get(botId, commandName);
29
+ const aliases = tempCommand && tempCommand.aliases ? tempCommand.aliases : [];
30
+
31
+ runtimeRegistry.unregister(botId, commandName);
32
+
33
+ if (Array.isArray(aliases)) {
34
+ for (const alias of aliases) {
35
+ runtimeRegistry.unregister(botId, alias);
36
+ }
37
+ }
38
+
39
+ if (botManager && botManager.processManager) {
40
+ botManager.processManager.sendMessage(botId, {
41
+ type: 'unregister_temp_command',
42
+ commandName,
43
+ aliases
44
+ });
45
+ }
46
+
47
+ console.log(`[delete_command] Временная команда "${commandName}" успешно удалена`);
48
+ memo.set(`${node.id}:success`, true);
49
+ await traverse(node, 'exec');
50
+ return;
51
+ }
52
+
53
+ const existingCommand = await prisma.command.findFirst({
54
+ where: { name: commandName, botId }
55
+ });
56
+
57
+ if (!existingCommand) {
58
+ console.error(`[delete_command] Команда "${commandName}" не найдена`);
59
+ memo.set(`${node.id}:success`, false);
60
+ await traverse(node, 'exec');
61
+ return;
62
+ }
63
+
64
+ if (!existingCommand.isVisual) {
65
+ console.error(`[delete_command] Команда "${commandName}" является системной и не может быть удалена`);
66
+ memo.set(`${node.id}:success`, false);
67
+ await traverse(node, 'exec');
68
+ return;
69
+ }
70
+
71
+ await prisma.command.delete({
72
+ where: { id: existingCommand.id }
73
+ });
74
+
75
+ console.log(`[delete_command] Команда "${commandName}" успешно удалена`);
76
+
77
+ if (botManager && botManager.reloadBotConfigInRealTime) {
78
+ botManager.reloadBotConfigInRealTime(botId);
79
+ }
80
+
81
+ memo.set(`${node.id}:success`, true);
82
+ } catch (error) {
83
+ console.error('[delete_command] Ошибка удаления команды:', error);
84
+ memo.set(`${node.id}:success`, false);
85
+ }
86
+
87
+ await traverse(node, 'exec');
88
+ }
89
+
90
+ module.exports = {
91
+ execute,
92
+ };
@@ -9,16 +9,35 @@
9
9
  async function execute(node, context, helpers) {
10
10
  const { resolvePinValue, traverse, memo } = helpers;
11
11
 
12
- const url = await resolvePinValue(node, 'url', '');
12
+ let url = await resolvePinValue(node, 'url', '');
13
13
  const method = await resolvePinValue(node, 'method', node.data?.method || 'GET');
14
- const headersStr = await resolvePinValue(node, 'headers', '');
14
+ const headersInput = await resolvePinValue(node, 'headers', null);
15
+ const queryParamsInput = await resolvePinValue(node, 'queryParams', null);
15
16
  const body = await resolvePinValue(node, 'body', '');
16
17
  const timeout = await resolvePinValue(node, 'timeout', 5000);
17
18
 
19
+ if (queryParamsInput) {
20
+ try {
21
+ const params = typeof queryParamsInput === 'string'
22
+ ? JSON.parse(queryParamsInput)
23
+ : queryParamsInput;
24
+
25
+ const urlObj = new URL(url);
26
+ Object.entries(params).forEach(([key, value]) => {
27
+ urlObj.searchParams.append(key, value);
28
+ });
29
+ url = urlObj.toString();
30
+ } catch (e) {
31
+ console.error('[HTTP Request] Ошибка обработки query params:', e);
32
+ }
33
+ }
34
+
18
35
  let headers = {};
19
- if (headersStr) {
36
+ if (headersInput) {
20
37
  try {
21
- headers = JSON.parse(headersStr);
38
+ headers = typeof headersInput === 'string'
39
+ ? JSON.parse(headersInput)
40
+ : headersInput;
22
41
  } catch (e) {
23
42
  console.error('[HTTP Request] Ошибка парсинга headers:', e);
24
43
  headers = {};
@@ -8,21 +8,11 @@
8
8
  async function execute(node, context, helpers) {
9
9
  const { resolvePinValue, traverse } = helpers;
10
10
 
11
- let message = String(await resolvePinValue(node, 'message', ''));
11
+ // resolvePinValue теперь автоматически заменяет {varName} на значения
12
+ const message = String(await resolvePinValue(node, 'message', ''));
12
13
  const chatType = await resolvePinValue(node, 'chat_type', context.typeChat);
13
14
  const recipient = await resolvePinValue(node, 'recipient', context.user?.username);
14
15
 
15
- // Парсим и заменяем переменные в формате {varName}
16
- const variablePattern = /\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
17
- const matches = [...message.matchAll(variablePattern)];
18
-
19
- for (const match of matches) {
20
- const varName = match[1];
21
- // Для динамических пинов, созданных на фронтенде, значение нужно будет получить, используя resolvePinValue
22
- const varValue = await resolvePinValue(node, `var_${varName}`, '');
23
- message = message.replace(match[0], String(varValue));
24
- }
25
-
26
16
  context.bot.sendMessage(chatType, message, recipient);
27
17
  await traverse(node, 'exec');
28
18
  }
@@ -0,0 +1,133 @@
1
+ const prismaService = require('../../PrismaService');
2
+ const prisma = prismaService.getClient();
3
+
4
+ /**
5
+ * Обновляет существующую команду
6
+ * @param {object} node - Экземпляр узла из графа
7
+ * @param {object} context - Контекст выполнения графа
8
+ * @param {object} helpers - Вспомогательные функции движка
9
+ */
10
+ async function execute(node, context, helpers) {
11
+ const { resolvePinValue, traverse, memo } = helpers;
12
+ const { botId, botManager } = context;
13
+
14
+ try {
15
+ const commandName = await resolvePinValue(node, 'commandName');
16
+ const newName = await resolvePinValue(node, 'newName', null);
17
+ const description = await resolvePinValue(node, 'description', null);
18
+ let aliases = await resolvePinValue(node, 'aliases', null);
19
+ const cooldown = await resolvePinValue(node, 'cooldown', null);
20
+ let allowedChatTypes = await resolvePinValue(node, 'allowedChatTypes', null);
21
+ const permissionName = await resolvePinValue(node, 'permissionName', null);
22
+
23
+ if (aliases !== null && typeof aliases === 'string') {
24
+ try {
25
+ const normalizedString = aliases.replace(/'/g, '"');
26
+ aliases = JSON.parse(normalizedString);
27
+ } catch (e) {
28
+ console.warn('[update_command] Не удалось распарсить aliases:', e);
29
+ aliases = null;
30
+ }
31
+ }
32
+
33
+ if (allowedChatTypes !== null && typeof allowedChatTypes === 'string') {
34
+ try {
35
+ const normalizedString = allowedChatTypes.replace(/'/g, '"');
36
+ allowedChatTypes = JSON.parse(normalizedString);
37
+ } catch (e) {
38
+ console.warn('[update_command] Не удалось распарсить allowedChatTypes:', e);
39
+ allowedChatTypes = null;
40
+ }
41
+ }
42
+
43
+ if (!commandName) {
44
+ console.error('[update_command] Имя команды обязательно');
45
+ memo.set(`${node.id}:success`, false);
46
+ await traverse(node, 'exec');
47
+ return;
48
+ }
49
+
50
+ const existingCommand = await prisma.command.findFirst({
51
+ where: { name: commandName, botId }
52
+ });
53
+
54
+ if (!existingCommand) {
55
+ console.error(`[update_command] Команда "${commandName}" не найдена`);
56
+ memo.set(`${node.id}:success`, false);
57
+ await traverse(node, 'exec');
58
+ return;
59
+ }
60
+
61
+ if (newName && newName !== existingCommand.name) {
62
+ const duplicateCommand = await prisma.command.findFirst({
63
+ where: {
64
+ botId,
65
+ name: newName,
66
+ id: { not: existingCommand.id }
67
+ }
68
+ });
69
+
70
+ if (duplicateCommand) {
71
+ console.error(`[update_command] Команда с именем "${newName}" уже существует`);
72
+ memo.set(`${node.id}:success`, false);
73
+ await traverse(node, 'exec');
74
+ return;
75
+ }
76
+ }
77
+
78
+ const updateData = {};
79
+
80
+ if (newName !== null) updateData.name = newName;
81
+ if (description !== null) updateData.description = description;
82
+ if (aliases !== null) {
83
+ updateData.aliases = JSON.stringify(Array.isArray(aliases) ? aliases : []);
84
+ }
85
+ if (cooldown !== null) updateData.cooldown = cooldown;
86
+ if (allowedChatTypes !== null) {
87
+ updateData.allowedChatTypes = JSON.stringify(
88
+ Array.isArray(allowedChatTypes) ? allowedChatTypes : ['chat', 'private']
89
+ );
90
+ }
91
+
92
+ if (permissionName !== null) {
93
+ if (permissionName === '') {
94
+ updateData.permissionId = null;
95
+ } else {
96
+ const permission = await prisma.permission.findFirst({
97
+ where: {
98
+ botId,
99
+ name: permissionName
100
+ }
101
+ });
102
+
103
+ if (permission) {
104
+ updateData.permissionId = permission.id;
105
+ } else {
106
+ console.warn(`[update_command] Право "${permissionName}" не найдено, поле не будет обновлено`);
107
+ }
108
+ }
109
+ }
110
+
111
+ await prisma.command.update({
112
+ where: { id: existingCommand.id },
113
+ data: updateData
114
+ });
115
+
116
+ console.log(`[update_command] Команда "${commandName}" успешно обновлена`);
117
+
118
+ if (botManager && botManager.reloadBotConfigInRealTime) {
119
+ botManager.reloadBotConfigInRealTime(botId);
120
+ }
121
+
122
+ memo.set(`${node.id}:success`, true);
123
+ } catch (error) {
124
+ console.error('[update_command] Ошибка обновления команды:', error);
125
+ memo.set(`${node.id}:success`, false);
126
+ }
127
+
128
+ await traverse(node, 'exec');
129
+ }
130
+
131
+ module.exports = {
132
+ execute,
133
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @param {object} node - Экземпляр узла из графа.
3
+ * @param {string} pinId - Идентификатор выходного пина.
4
+ * @param {object} context - Контекст выполнения графа.
5
+ * @param {object} helpers - Вспомогательные функции движка.
6
+ * @param {function} helpers.resolvePinValue - Функция для получения значения с входного пина.
7
+ * @returns {Promise<any>} - Вычисленное значение для выходного пина.
8
+ */
9
+ async function evaluate(node, pinId, context, helpers) {
10
+ const { resolvePinValue } = helpers;
11
+
12
+ if (pinId === 'result') {
13
+ const array = await resolvePinValue(node, 'array', []);
14
+ const separator = String(await resolvePinValue(node, 'separator', ', '));
15
+
16
+ if (!Array.isArray(array)) {
17
+ return '';
18
+ }
19
+
20
+ return array.join(separator);
21
+ }
22
+
23
+ return '';
24
+ }
25
+
26
+ module.exports = {
27
+ evaluate,
28
+ };
@@ -9,7 +9,8 @@
9
9
  async function evaluate(node, pinId, context, helpers) {
10
10
  const { resolvePinValue } = helpers;
11
11
 
12
- if (pinId === 'value') {
12
+ // Поддерживаем оба варианта: 'result' (новая версия) и 'value' (старая версия для обратной совместимости)
13
+ if (pinId === 'result' || pinId === 'value') {
13
14
  const value = await resolvePinValue(node, 'value');
14
15
  const targetType = node.data?.targetType || 'String';
15
16
 
@@ -10,19 +10,8 @@ async function evaluate(node, pinId, context, helpers) {
10
10
  const { resolvePinValue } = helpers;
11
11
 
12
12
  if (pinId === 'value') {
13
- let text = String(node.data?.value || '');
14
-
15
- // Парсим и заменяем переменные в формате {varName}
16
- const variablePattern = /\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
17
- const matches = [...text.matchAll(variablePattern)];
18
-
19
- for (const match of matches) {
20
- const varName = match[1];
21
- // Получаем значение из динамического пина
22
- const varValue = await resolvePinValue(node, `var_${varName}`, '');
23
- text = text.replace(match[0], String(varValue));
24
- }
25
-
13
+ // resolvePinValue автоматически заменит переменные {varName}
14
+ const text = String(await resolvePinValue(node, 'value', ''));
26
15
  return text;
27
16
  }
28
17
 
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @param {object} node - Экземпляр узла из графа.
3
+ * @param {string} pinId - Идентификатор выходного пина, значение которого нужно вычислить.
4
+ * @param {object} context - Контекст выполнения графа.
5
+ * @param {object} helpers - Вспомогательные функции движка.
6
+ * @param {function} helpers.resolvePinValue - Функция для получения значения с входного пина.
7
+ * @returns {Promise<any>} - Вычисленное значение для выходного пина.
8
+ */
9
+ async function evaluate(node, pinId, context, helpers) {
10
+ const { resolvePinValue } = helpers;
11
+
12
+ if (pinId === 'result') {
13
+ const value = await resolvePinValue(node, 'value', false);
14
+ return !value;
15
+ }
16
+
17
+ return false;
18
+ }
19
+
20
+ module.exports = {
21
+ evaluate,
22
+ };
@@ -23,7 +23,7 @@ async function evaluate(node, pinId, context, helpers) {
23
23
  const { resolvePinValue } = helpers;
24
24
 
25
25
  if (pinId === 'result') {
26
- const str = String(await resolvePinValue(node, 'string', ''));
26
+ const str = String(await resolvePinValue(node, 'text', ''));
27
27
  const prefix = String(await resolvePinValue(node, 'prefix', ''));
28
28
  const caseSensitive = await resolvePinValue(node, 'case_sensitive', false);
29
29
 
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @param {object} node - Экземпляр узла из графа.
3
+ * @param {string} pinId - Идентификатор выходного пина.
4
+ * @param {object} context - Контекст выполнения графа.
5
+ * @param {object} helpers - Вспомогательные функции движка.
6
+ * @param {function} helpers.resolvePinValue - Функция для получения значения с входного пина.
7
+ * @returns {Promise<any>} - Вычисленное значение для выходного пина.
8
+ */
9
+ async function evaluate(node, pinId, context, helpers) {
10
+ const { resolvePinValue } = helpers;
11
+
12
+ if (pinId === 'result') {
13
+ const text = String(await resolvePinValue(node, 'text', ''));
14
+ return text.toLowerCase();
15
+ }
16
+
17
+ return '';
18
+ }
19
+
20
+ module.exports = {
21
+ evaluate,
22
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @param {object} node - Экземпляр узла из графа.
3
+ * @param {string} pinId - Идентификатор выходного пина.
4
+ * @param {object} context - Контекст выполнения графа.
5
+ * @param {object} helpers - Вспомогательные функции движка.
6
+ * @param {function} helpers.resolvePinValue - Функция для получения значения с входного пина.
7
+ * @returns {Promise<any>} - Вычисленное значение для выходного пина.
8
+ */
9
+ async function evaluate(node, pinId, context, helpers) {
10
+ const { resolvePinValue } = helpers;
11
+
12
+ if (pinId === 'result') {
13
+ const text = String(await resolvePinValue(node, 'text', ''));
14
+ return text.toUpperCase();
15
+ }
16
+
17
+ return '';
18
+ }
19
+
20
+ module.exports = {
21
+ evaluate,
22
+ };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @param {object} node - Экземпляр узла из графа.
3
+ * @param {string} pinId - Идентификатор выходного пина.
4
+ * @param {object} context - Контекст выполнения графа.
5
+ * @param {object} helpers - Вспомогательные функции движка.
6
+ * @param {function} helpers.resolvePinValue - Функция для получения значения с входного пина.
7
+ * @returns {Promise<any>} - Вычисленное значение для выходного пина.
8
+ */
9
+ async function evaluate(node, pinId, context, helpers) {
10
+ const { resolvePinValue } = helpers;
11
+
12
+ if (pinId === 'result') {
13
+ const value = await resolvePinValue(node, 'value', '');
14
+
15
+ // Преобразуем в строку
16
+ if (value === null || value === undefined) {
17
+ return '';
18
+ }
19
+
20
+ if (typeof value === 'object') {
21
+ return JSON.stringify(value);
22
+ }
23
+
24
+ return String(value);
25
+ }
26
+
27
+ return '';
28
+ }
29
+
30
+ module.exports = {
31
+ evaluate,
32
+ };