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.
Files changed (102) hide show
  1. package/.claude/settings.json +5 -1
  2. package/.claude/settings.local.json +10 -1
  3. package/CHANGELOG.md +27 -3
  4. package/CLAUDE.md +284 -0
  5. package/README.md +302 -152
  6. package/backend/package-lock.json +681 -9
  7. package/backend/package.json +8 -0
  8. package/backend/prisma/migrations/20251116111851_add_execution_trace/migration.sql +22 -0
  9. package/backend/prisma/migrations/20251120154914_add_panel_api_keys/migration.sql +21 -0
  10. package/backend/prisma/migrations/20251121110241_add_proxy_table/migration.sql +45 -0
  11. package/backend/prisma/migrations/migration_lock.toml +2 -2
  12. package/backend/prisma/schema.prisma +70 -1
  13. package/backend/src/__tests__/services/BotLifecycleService.test.js +9 -4
  14. package/backend/src/ai/plugin-assistant-system-prompt.md +788 -0
  15. package/backend/src/api/middleware/auth.js +27 -0
  16. package/backend/src/api/middleware/botAccess.js +7 -3
  17. package/backend/src/api/middleware/panelApiAuth.js +135 -0
  18. package/backend/src/api/routes/aiAssistant.js +995 -0
  19. package/backend/src/api/routes/auth.js +669 -633
  20. package/backend/src/api/routes/botCommands.js +107 -0
  21. package/backend/src/api/routes/botGroups.js +165 -0
  22. package/backend/src/api/routes/botHistory.js +108 -0
  23. package/backend/src/api/routes/botPermissions.js +99 -0
  24. package/backend/src/api/routes/botStatus.js +36 -0
  25. package/backend/src/api/routes/botUsers.js +162 -0
  26. package/backend/src/api/routes/bots.js +2451 -2402
  27. package/backend/src/api/routes/eventGraphs.js +4 -1
  28. package/backend/src/api/routes/logs.js +13 -3
  29. package/backend/src/api/routes/panel.js +66 -66
  30. package/backend/src/api/routes/panelApiKeys.js +179 -0
  31. package/backend/src/api/routes/pluginIde.js +1715 -135
  32. package/backend/src/api/routes/plugins.js +376 -219
  33. package/backend/src/api/routes/proxies.js +130 -0
  34. package/backend/src/api/routes/search.js +4 -0
  35. package/backend/src/api/routes/servers.js +20 -3
  36. package/backend/src/api/routes/settings.js +5 -0
  37. package/backend/src/api/routes/system.js +174 -174
  38. package/backend/src/api/routes/traces.js +131 -0
  39. package/backend/src/config/debug.config.js +36 -0
  40. package/backend/src/core/BotHistoryStore.js +180 -0
  41. package/backend/src/core/BotManager.js +14 -4
  42. package/backend/src/core/BotProcess.js +1517 -1092
  43. package/backend/src/core/EventGraphManager.js +37 -123
  44. package/backend/src/core/GraphExecutionEngine.js +977 -321
  45. package/backend/src/core/MessageQueue.js +12 -6
  46. package/backend/src/core/PluginLoader.js +99 -5
  47. package/backend/src/core/PluginManager.js +74 -13
  48. package/backend/src/core/TaskScheduler.js +1 -1
  49. package/backend/src/core/commands/whois.js +1 -1
  50. package/backend/src/core/node-registries/actions.js +70 -0
  51. package/backend/src/core/node-registries/arrays.js +18 -0
  52. package/backend/src/core/node-registries/data.js +1 -1
  53. package/backend/src/core/node-registries/events.js +14 -0
  54. package/backend/src/core/node-registries/logic.js +17 -0
  55. package/backend/src/core/node-registries/strings.js +34 -0
  56. package/backend/src/core/node-registries/type.js +25 -0
  57. package/backend/src/core/nodes/actions/bot_look_at.js +1 -1
  58. package/backend/src/core/nodes/actions/create_command.js +189 -0
  59. package/backend/src/core/nodes/actions/delete_command.js +92 -0
  60. package/backend/src/core/nodes/actions/update_command.js +133 -0
  61. package/backend/src/core/nodes/arrays/join.js +28 -0
  62. package/backend/src/core/nodes/data/cast.js +2 -1
  63. package/backend/src/core/nodes/logic/not.js +22 -0
  64. package/backend/src/core/nodes/strings/starts_with.js +1 -1
  65. package/backend/src/core/nodes/strings/to_lower.js +22 -0
  66. package/backend/src/core/nodes/strings/to_upper.js +22 -0
  67. package/backend/src/core/nodes/type/to_string.js +32 -0
  68. package/backend/src/core/services/BotLifecycleService.js +255 -16
  69. package/backend/src/core/services/CommandExecutionService.js +430 -351
  70. package/backend/src/core/services/DebugSessionManager.js +347 -0
  71. package/backend/src/core/services/GraphCollaborationManager.js +501 -0
  72. package/backend/src/core/services/MinecraftBotManager.js +259 -0
  73. package/backend/src/core/services/MinecraftViewerService.js +216 -0
  74. package/backend/src/core/services/TraceCollectorService.js +545 -0
  75. package/backend/src/core/system/RuntimeCommandRegistry.js +116 -0
  76. package/backend/src/core/system/Transport.js +0 -4
  77. package/backend/src/core/validation/nodeSchemas.js +6 -6
  78. package/backend/src/real-time/botApi/handlers/graphHandlers.js +2 -2
  79. package/backend/src/real-time/botApi/handlers/graphWebSocketHandlers.js +1 -1
  80. package/backend/src/real-time/botApi/utils.js +11 -0
  81. package/backend/src/real-time/panelNamespace.js +387 -0
  82. package/backend/src/real-time/presence.js +7 -2
  83. package/backend/src/real-time/socketHandler.js +395 -4
  84. package/backend/src/server.js +18 -0
  85. package/frontend/dist/assets/index-B1serztM.js +11210 -0
  86. package/frontend/dist/assets/index-t6K1u4OV.css +32 -0
  87. package/frontend/dist/index.html +2 -2
  88. package/frontend/package-lock.json +9437 -0
  89. package/frontend/package.json +8 -0
  90. package/package.json +2 -2
  91. package/screen/console.png +0 -0
  92. package/screen/dashboard.png +0 -0
  93. package/screen/graph_collabe.png +0 -0
  94. package/screen/graph_live_debug.png +0 -0
  95. package/screen/management_command.png +0 -0
  96. package/screen/node_debug_trace.png +0 -0
  97. package/screen/plugin_/320/276/320/261/320/267/320/276/321/200.png +0 -0
  98. package/screen/websocket.png +0 -0
  99. 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
  100. 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
  101. package/frontend/dist/assets/index-CfTo92bP.css +0 -1
  102. package/frontend/dist/assets/index-CiFD5X9Z.js +0 -8344
@@ -0,0 +1,131 @@
1
+ const express = require('express');
2
+ const { authenticate, authorize } = require('../middleware/auth');
3
+ const router = express.Router();
4
+ const { getTraceCollector } = require('../../core/services/TraceCollectorService');
5
+
6
+ router.use(authenticate);
7
+
8
+ /**
9
+ * GET /api/traces/:botId
10
+ * Получить трассировки для бота
11
+ */
12
+ router.get('/:botId', authorize('management:view'), async (req, res) => {
13
+ try {
14
+ const botId = parseInt(req.params.botId);
15
+ const { limit, status, graphId } = req.query;
16
+
17
+ const options = {
18
+ limit: limit ? parseInt(limit) : 150,
19
+ status: status || null,
20
+ graphId: graphId ? parseInt(graphId) : null,
21
+ };
22
+
23
+ const traceCollector = getTraceCollector();
24
+ const traces = traceCollector.getTracesForBot(botId, options);
25
+
26
+ res.json({
27
+ success: true,
28
+ traces,
29
+ });
30
+ } catch (error) {
31
+ console.error('[API /traces/:botId] Ошибка:', error);
32
+ res.status(500).json({
33
+ success: false,
34
+ error: error.message,
35
+ });
36
+ }
37
+ });
38
+
39
+ /**
40
+ * GET /api/traces/:botId/:traceId
41
+ * Получить конкретную трассировку по ID
42
+ */
43
+ router.get('/:botId/:traceId', authorize('management:view'), async (req, res) => {
44
+ try {
45
+ const { traceId } = req.params;
46
+
47
+ const traceCollector = getTraceCollector();
48
+ let trace = traceCollector.getTrace(traceId);
49
+
50
+ // Если не нашли в памяти, пытаемся загрузить из БД
51
+ if (!trace) {
52
+ trace = await traceCollector.loadTraceFromDb(traceId);
53
+ }
54
+
55
+ if (!trace) {
56
+ return res.status(404).json({
57
+ success: false,
58
+ error: 'Трассировка не найдена',
59
+ });
60
+ }
61
+
62
+ res.json({
63
+ success: true,
64
+ trace,
65
+ });
66
+ } catch (error) {
67
+ console.error('[API /traces/:botId/:traceId] Ошибка:', error);
68
+ res.status(500).json({
69
+ success: false,
70
+ error: error.message,
71
+ });
72
+ }
73
+ });
74
+
75
+ /**
76
+ * GET /api/traces/:botId/graph/:graphId/last
77
+ * Получить последнюю трассировку для графа
78
+ * Query params: eventType (опционально) - фильтр по типу события
79
+ */
80
+ router.get('/:botId/graph/:graphId/last', authorize('management:view'), async (req, res) => {
81
+ try {
82
+ const botId = parseInt(req.params.botId);
83
+ const graphId = parseInt(req.params.graphId);
84
+ const { eventType } = req.query;
85
+
86
+ const traceCollector = getTraceCollector();
87
+ const trace = await traceCollector.getLastTraceForGraph(botId, graphId, eventType);
88
+
89
+ if (!trace) {
90
+ return res.status(404).json({
91
+ success: false,
92
+ error: 'Трассировка не найдена',
93
+ });
94
+ }
95
+
96
+ res.json({
97
+ success: true,
98
+ trace,
99
+ });
100
+ } catch (error) {
101
+ console.error('[API /traces/:botId/graph/:graphId/last] Ошибка:', error);
102
+ res.status(500).json({
103
+ success: false,
104
+ error: error.message,
105
+ });
106
+ }
107
+ });
108
+
109
+ /**
110
+ * GET /api/traces/stats
111
+ * Получить статистику трассировок
112
+ */
113
+ router.get('/stats', authorize('management:view'), async (req, res) => {
114
+ try {
115
+ const traceCollector = getTraceCollector();
116
+ const stats = traceCollector.getStats();
117
+
118
+ res.json({
119
+ success: true,
120
+ stats,
121
+ });
122
+ } catch (error) {
123
+ console.error('[API /traces/stats] Ошибка:', error);
124
+ res.status(500).json({
125
+ success: false,
126
+ error: error.message,
127
+ });
128
+ }
129
+ });
130
+
131
+ module.exports = router;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Конфигурация для Live Debug системы
3
+ */
4
+
5
+ module.exports = {
6
+ // Таймауты (в миллисекундах)
7
+ BREAKPOINT_TIMEOUT: 30000, // 30 секунд - максимальное время ожидания breakpoint response
8
+ STEP_MODE_TIMEOUT: 30000, // 30 секунд - максимальное время ожидания step mode response
9
+ TRACE_CLEANUP_DELAY: 5000, // 5 секунд - задержка перед удалением completed trace
10
+
11
+ // Лимиты
12
+ MAX_TRACE_STEPS: 10000, // Максимальное количество шагов в одном trace
13
+ MAX_COMPLETED_TRACES: 100, // Максимальное количество хранимых completed traces
14
+ MAX_OUTPUT_LENGTH: 30000, // Максимальная длина output при передаче через IPC
15
+
16
+ // IPC Message Types (для type safety)
17
+ IPC_TYPES: {
18
+ EXECUTE_EVENT_GRAPH: 'execute_event_graph',
19
+ EXECUTE_HANDLER: 'execute_handler',
20
+ EXECUTE_COMMAND_REQUEST: 'execute_command_request',
21
+
22
+ DEBUG_CHECK_BREAKPOINT: 'debug:check_breakpoint',
23
+ DEBUG_CHECK_STEP_MODE: 'debug:check_step_mode',
24
+ DEBUG_BREAKPOINT_RESPONSE: 'debug:breakpoint_response',
25
+
26
+ TRACE_COMPLETED: 'trace:completed',
27
+ TRACE_ERROR: 'trace:error',
28
+ },
29
+
30
+ // Debug Session
31
+ DEBUG_SESSION_IDLE_TIMEOUT: 300000, // 5 минут - таймаут неактивной debug сессии
32
+
33
+ // Trace Storage
34
+ TRACE_RETENTION_TIME: 3600000, // 1 час - время хранения completed traces
35
+ ACTIVE_TRACE_MAX_AGE: 600000, // 10 минут - максимальный возраст active trace
36
+ };
@@ -0,0 +1,180 @@
1
+ /**
2
+ * In-memory хранилище истории чатов и команд ботов
3
+ * Хранит последние N сообщений/команд для каждого бота
4
+ */
5
+
6
+ class BotHistoryStore {
7
+ constructor() {
8
+ this.chatHistory = new Map();
9
+ this.commandLogs = new Map();
10
+
11
+ this.MAX_CHAT_MESSAGES = 1000;
12
+ this.MAX_COMMAND_LOGS = 500;
13
+ }
14
+
15
+ /**
16
+ * Добавить сообщение чата
17
+ */
18
+ addChatMessage(botId, data) {
19
+ if (!this.chatHistory.has(botId)) {
20
+ this.chatHistory.set(botId, []);
21
+ }
22
+
23
+ const messages = this.chatHistory.get(botId);
24
+
25
+ const entry = {
26
+ type: data.type || 'chat',
27
+ username: data.username,
28
+ message: data.message,
29
+ timestamp: data.timestamp || new Date().toISOString()
30
+ };
31
+
32
+ messages.push(entry);
33
+
34
+ if (messages.length > this.MAX_CHAT_MESSAGES) {
35
+ messages.shift();
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Получить историю чата с фильтрами
41
+ */
42
+ getChatHistory(botId, filters = {}) {
43
+ const messages = this.chatHistory.get(botId) || [];
44
+
45
+ let filtered = [...messages];
46
+
47
+ if (filters.type) {
48
+ filtered = filtered.filter(m => m.type === filters.type);
49
+ }
50
+
51
+ if (filters.username) {
52
+ filtered = filtered.filter(m => m.username.toLowerCase() === filters.username.toLowerCase());
53
+ }
54
+
55
+ if (filters.search) {
56
+ const searchLower = filters.search.toLowerCase();
57
+ filtered = filtered.filter(m => m.message.toLowerCase().includes(searchLower));
58
+ }
59
+
60
+ if (filters.from) {
61
+ const fromDate = new Date(filters.from);
62
+ filtered = filtered.filter(m => new Date(m.timestamp) >= fromDate);
63
+ }
64
+
65
+ if (filters.to) {
66
+ const toDate = new Date(filters.to);
67
+ filtered = filtered.filter(m => new Date(m.timestamp) <= toDate);
68
+ }
69
+
70
+ const limit = parseInt(filters.limit) || 100;
71
+ const offset = parseInt(filters.offset) || 0;
72
+
73
+ return {
74
+ messages: filtered.slice(offset, offset + limit).reverse(),
75
+ total: filtered.length
76
+ };
77
+ }
78
+
79
+ /**
80
+ * Добавить лог команды
81
+ */
82
+ addCommandLog(botId, data) {
83
+ if (!this.commandLogs.has(botId)) {
84
+ this.commandLogs.set(botId, []);
85
+ }
86
+
87
+ const logs = this.commandLogs.get(botId);
88
+
89
+ const entry = {
90
+ username: data.username,
91
+ command: data.command,
92
+ args: data.args || [],
93
+ success: data.success !== undefined ? data.success : true,
94
+ error: data.error || null,
95
+ timestamp: data.timestamp || new Date().toISOString()
96
+ };
97
+
98
+ logs.push(entry);
99
+
100
+ if (logs.length > this.MAX_COMMAND_LOGS) {
101
+ logs.shift();
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Получить логи команд с фильтрами
107
+ */
108
+ getCommandLogs(botId, filters = {}) {
109
+ const logs = this.commandLogs.get(botId) || [];
110
+
111
+ let filtered = [...logs];
112
+
113
+ if (filters.username) {
114
+ filtered = filtered.filter(l => l.username.toLowerCase() === filters.username.toLowerCase());
115
+ }
116
+
117
+ if (filters.command) {
118
+ filtered = filtered.filter(l => l.command === filters.command);
119
+ }
120
+
121
+ if (filters.success !== undefined) {
122
+ const successValue = filters.success === 'true' || filters.success === true;
123
+ filtered = filtered.filter(l => l.success === successValue);
124
+ }
125
+
126
+ if (filters.from) {
127
+ const fromDate = new Date(filters.from);
128
+ filtered = filtered.filter(l => new Date(l.timestamp) >= fromDate);
129
+ }
130
+
131
+ if (filters.to) {
132
+ const toDate = new Date(filters.to);
133
+ filtered = filtered.filter(l => new Date(l.timestamp) <= toDate);
134
+ }
135
+
136
+ const limit = parseInt(filters.limit) || 100;
137
+ const offset = parseInt(filters.offset) || 0;
138
+
139
+ return {
140
+ logs: filtered.slice(offset, offset + limit).reverse(),
141
+ total: filtered.length
142
+ };
143
+ }
144
+
145
+ /**
146
+ * Очистить историю бота
147
+ */
148
+ clearBot(botId) {
149
+ this.chatHistory.delete(botId);
150
+ this.commandLogs.delete(botId);
151
+ }
152
+
153
+ /**
154
+ * Получить статистику
155
+ */
156
+ getStats(botId) {
157
+ const chatMessages = this.chatHistory.get(botId) || [];
158
+ const commandLogs = this.commandLogs.get(botId) || [];
159
+
160
+ const byType = {};
161
+ chatMessages.forEach(msg => {
162
+ const type = msg.type || 'unknown';
163
+ byType[type] = (byType[type] || 0) + 1;
164
+ });
165
+
166
+ return {
167
+ chat: {
168
+ total: chatMessages.length,
169
+ byType
170
+ },
171
+ commands: {
172
+ total: commandLogs.length,
173
+ successful: commandLogs.filter(l => l.success).length,
174
+ failed: commandLogs.filter(l => !l.success).length
175
+ }
176
+ };
177
+ }
178
+ }
179
+
180
+ module.exports = new BotHistoryStore();
@@ -159,8 +159,11 @@ class BotManager {
159
159
  // === Resource monitoring ===
160
160
  async updateAllResourceUsage() {
161
161
  const usageData = await this.resourceMonitor.updateAllResourceUsage();
162
- const { getIO } = require('../real-time/socketHandler');
163
- getIO().emit('bots:usage', usageData);
162
+ const { getIOSafe } = require('../real-time/socketHandler');
163
+ const io = getIOSafe();
164
+ if (io) {
165
+ io.emit('bots:usage', usageData);
166
+ }
164
167
  }
165
168
 
166
169
  getBotIdByPid(pid) {
@@ -195,11 +198,14 @@ class BotManager {
195
198
 
196
199
  syncBotStatuses() {
197
200
  const processes = this.processManager.getAllProcesses();
198
- const { getIO } = require('../real-time/socketHandler');
201
+ const { getIOSafe } = require('../real-time/socketHandler');
202
+ const io = getIOSafe();
203
+
204
+ if (!io) return;
199
205
 
200
206
  for (const [botId, child] of processes.entries()) {
201
207
  const actualStatus = child.killed ? 'stopped' : 'running';
202
- getIO().emit('bot:status', { botId, status: actualStatus });
208
+ io.emit('bot:status', { botId, status: actualStatus });
203
209
  }
204
210
  }
205
211
 
@@ -209,6 +215,10 @@ class BotManager {
209
215
  this.lifecycleService.eventGraphManager = manager;
210
216
  }
211
217
 
218
+ getChildProcess(botId) {
219
+ return this.lifecycleService.getChildProcess(botId);
220
+ }
221
+
212
222
  // === Legacy async methods для migration ===
213
223
  async _syncSystemPermissions(botId) {
214
224
  return this.lifecycleService._syncSystemPermissions(botId);