auto_error_fixer 0.1.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.
@@ -0,0 +1,12 @@
1
+ password: "123456"
2
+ enablePanel: true
3
+ email:
4
+ enabled: false
5
+ host: ""
6
+ port: 587
7
+ secure: false
8
+ user: ""
9
+ pass: ""
10
+ to: ""
11
+ autoRestart: true
12
+ logLevel: info
@@ -0,0 +1,5 @@
1
+ qwen --resume 076143e9-f5d8-461d-a15a-c63e02ff9f9c
2
+
3
+ qwen --resume 82d0a245-483e-49ab-b7b0-8e1046790edd
4
+
5
+ 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
@@ -0,0 +1,640 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AEF - 自动故障修复系统</title>
7
+ <style>
8
+ :root {
9
+ --bg-primary: #1a1a1a;
10
+ --bg-secondary: #252525;
11
+ --bg-tertiary: #2d2d2d;
12
+ --text-primary: #ffffff;
13
+ --text-secondary: #b0b0b0;
14
+ --border-color: #444444;
15
+ --accent-color: #4CAF50;
16
+ --warning-color: #FFC107;
17
+ --error-color: #F44336;
18
+ --success-color: #4CAF50;
19
+ }
20
+
21
+ * {
22
+ margin: 0;
23
+ padding: 0;
24
+ box-sizing: border-box;
25
+ }
26
+
27
+ body {
28
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
29
+ background-color: var(--bg-primary);
30
+ color: var(--text-primary);
31
+ line-height: 1.6;
32
+ }
33
+
34
+ .container {
35
+ max-width: 1200px;
36
+ margin: 0 auto;
37
+ padding: 20px;
38
+ }
39
+
40
+ .header {
41
+ text-align: center;
42
+ margin-bottom: 30px;
43
+ padding-bottom: 20px;
44
+ border-bottom: 1px solid var(--border-color);
45
+ }
46
+
47
+ .title {
48
+ font-size: 2.5rem;
49
+ color: var(--accent-color);
50
+ margin-bottom: 10px;
51
+ }
52
+
53
+ .card {
54
+ background: var(--bg-secondary);
55
+ border-radius: 8px;
56
+ padding: 25px;
57
+ margin-bottom: 25px;
58
+ border: 1px solid var(--border-color);
59
+ }
60
+
61
+ .card h2 {
62
+ margin-top: 0;
63
+ margin-bottom: 20px;
64
+ color: var(--accent-color);
65
+ display: flex;
66
+ align-items: center;
67
+ gap: 10px;
68
+ }
69
+
70
+ .login-container {
71
+ max-width: 400px;
72
+ margin: 100px auto;
73
+ background: var(--bg-secondary);
74
+ padding: 30px;
75
+ border-radius: 8px;
76
+ border: 1px solid var(--border-color);
77
+ text-align: center;
78
+ }
79
+
80
+ .form-group {
81
+ margin-bottom: 20px;
82
+ text-align: left;
83
+ }
84
+
85
+ label {
86
+ display: block;
87
+ margin-bottom: 8px;
88
+ color: var(--text-secondary);
89
+ }
90
+
91
+ input[type="password"], input[type="text"], textarea {
92
+ width: 100%;
93
+ padding: 12px;
94
+ background: var(--bg-tertiary);
95
+ border: 1px solid var(--border-color);
96
+ border-radius: 4px;
97
+ color: var(--text-primary);
98
+ font-size: 16px;
99
+ }
100
+
101
+ input:focus, textarea:focus {
102
+ outline: none;
103
+ border-color: var(--accent-color);
104
+ }
105
+
106
+ .button {
107
+ display: inline-block;
108
+ padding: 12px 24px;
109
+ background: var(--accent-color);
110
+ color: white;
111
+ text-decoration: none;
112
+ border-radius: 4px;
113
+ border: none;
114
+ cursor: pointer;
115
+ font-size: 16px;
116
+ transition: background 0.3s;
117
+ }
118
+
119
+ .button:hover {
120
+ background: #45a049;
121
+ }
122
+
123
+ .button-secondary {
124
+ background: #6c757d;
125
+ }
126
+
127
+ .button-secondary:hover {
128
+ background: #5a6268;
129
+ }
130
+
131
+ .button-warning {
132
+ background: var(--warning-color);
133
+ }
134
+
135
+ .button-warning:hover {
136
+ background: #e0a800;
137
+ }
138
+
139
+ .button-error {
140
+ background: var(--error-color);
141
+ }
142
+
143
+ .button-error:hover {
144
+ background: #d32f2f;
145
+ }
146
+
147
+ .status-indicator {
148
+ display: inline-block;
149
+ width: 12px;
150
+ height: 12px;
151
+ border-radius: 50%;
152
+ margin-right: 8px;
153
+ }
154
+
155
+ .status-active {
156
+ background: var(--success-color);
157
+ }
158
+
159
+ .status-inactive {
160
+ background: var(--error-color);
161
+ }
162
+
163
+ .log-container {
164
+ background: var(--bg-tertiary);
165
+ border: 1px solid var(--border-color);
166
+ border-radius: 4px;
167
+ padding: 15px;
168
+ height: 300px;
169
+ overflow-y: auto;
170
+ font-family: monospace;
171
+ font-size: 14px;
172
+ white-space: pre-wrap;
173
+ }
174
+
175
+ .control-row {
176
+ display: flex;
177
+ gap: 15px;
178
+ margin-bottom: 15px;
179
+ flex-wrap: wrap;
180
+ }
181
+
182
+ .control-item {
183
+ flex: 1;
184
+ min-width: 250px;
185
+ }
186
+
187
+ .stat-card {
188
+ background: var(--bg-tertiary);
189
+ border-radius: 8px;
190
+ padding: 20px;
191
+ text-align: center;
192
+ border: 1px solid var(--border-color);
193
+ }
194
+
195
+ .stat-card h3 {
196
+ margin-top: 0;
197
+ color: var(--text-secondary);
198
+ }
199
+
200
+ .config-editor {
201
+ height: 300px;
202
+ font-family: monospace;
203
+ font-size: 14px;
204
+ }
205
+
206
+ .hidden {
207
+ display: none;
208
+ }
209
+
210
+ .notification {
211
+ position: fixed;
212
+ top: 20px;
213
+ right: 20px;
214
+ padding: 15px 20px;
215
+ border-radius: 4px;
216
+ color: white;
217
+ z-index: 1000;
218
+ opacity: 0;
219
+ transform: translateY(-20px);
220
+ transition: opacity 0.3s, transform 0.3s;
221
+ }
222
+
223
+ .notification.show {
224
+ opacity: 1;
225
+ transform: translateY(0);
226
+ }
227
+
228
+ .notification.success {
229
+ background: var(--success-color);
230
+ }
231
+
232
+ .notification.error {
233
+ background: var(--error-color);
234
+ }
235
+
236
+ .tabs {
237
+ display: flex;
238
+ margin-bottom: 20px;
239
+ border-bottom: 1px solid var(--border-color);
240
+ }
241
+
242
+ .tab {
243
+ padding: 10px 20px;
244
+ cursor: pointer;
245
+ border-bottom: 3px solid transparent;
246
+ }
247
+
248
+ .tab.active {
249
+ border-bottom: 3px solid var(--accent-color);
250
+ color: var(--accent-color);
251
+ }
252
+
253
+ .tab-content {
254
+ display: none;
255
+ }
256
+
257
+ .tab-content.active {
258
+ display: block;
259
+ }
260
+ </style>
261
+ </head>
262
+ <body>
263
+ <!-- 登录页面 -->
264
+ <div id="loginPage" class="login-container">
265
+ <h2>AEF 控制面板</h2>
266
+ <p style="color: var(--text-secondary); margin-bottom: 20px;">请输入密码进入管理面板</p>
267
+ <div class="form-group">
268
+ <label for="password">密码</label>
269
+ <input type="password" id="password" placeholder="输入密码">
270
+ </div>
271
+ <button id="loginBtn" class="button">登录</button>
272
+ <div id="loginError" style="color: var(--error-color); margin-top: 15px; display: none;"></div>
273
+ </div>
274
+
275
+ <!-- 主面板 -->
276
+ <div id="mainPanel" class="container hidden">
277
+ <div class="header">
278
+ <h1 class="title">AEF - 自动故障修复系统</h1>
279
+ <p>实时监控和自动修复服务器错误</p>
280
+ </div>
281
+
282
+ <div class="tabs">
283
+ <div class="tab active" data-tab="dashboard">仪表板</div>
284
+ <div class="tab" data-tab="logs">日志</div>
285
+ <div class="tab" data-tab="config">配置</div>
286
+ <div class="tab" data-tab="controls">控制</div>
287
+ </div>
288
+
289
+ <div id="dashboardTab" class="tab-content active">
290
+ <div class="card">
291
+ <h2>系统状态</h2>
292
+ <div class="control-row">
293
+ <div class="control-item">
294
+ <div class="stat-card">
295
+ <h3>AEF 状态</h3>
296
+ <p>
297
+ <span id="statusIndicator" class="status-indicator status-active"></span>
298
+ <span id="statusText">启用</span>
299
+ </p>
300
+ </div>
301
+ </div>
302
+ <div class="control-item">
303
+ <div class="stat-card">
304
+ <h3>最后错误时间</h3>
305
+ <p id="lastErrorTime">-</p>
306
+ </div>
307
+ </div>
308
+ <div class="control-item">
309
+ <div class="stat-card">
310
+ <h3>修复次数</h3>
311
+ <p id="fixCount">0</p>
312
+ </div>
313
+ </div>
314
+ <div class="control-item">
315
+ <div class="stat-card">
316
+ <h3>重启次数</h3>
317
+ <p id="restartCount">0</p>
318
+ </div>
319
+ </div>
320
+ </div>
321
+ </div>
322
+
323
+ <div class="card">
324
+ <h2>系统概览</h2>
325
+ <div class="control-row">
326
+ <div class="control-item">
327
+ <h3>服务器信息</h3>
328
+ <ul>
329
+ <li>节点版本: <span id="nodeVersion">-</span></li>
330
+ <li>平台: <span id="platform">-</span></li>
331
+ <li>架构: <span id="architecture">-</span></li>
332
+ </ul>
333
+ </div>
334
+ <div class="control-item">
335
+ <h3>内存使用</h3>
336
+ <ul>
337
+ <li>堆使用量: <span id="heapUsed">-</span></li>
338
+ <li>堆总大小: <span id="heapTotal">-</span></li>
339
+ <li>外部内存: <span id="externalMem">-</span></li>
340
+ </ul>
341
+ </div>
342
+ </div>
343
+ </div>
344
+ </div>
345
+
346
+ <div id="logsTab" class="tab-content">
347
+ <div class="card">
348
+ <h2>实时日志</h2>
349
+ <div id="logContainer" class="log-container"></div>
350
+ </div>
351
+ </div>
352
+
353
+ <div id="configTab" class="tab-content">
354
+ <div class="card">
355
+ <h2>配置文件编辑</h2>
356
+ <div class="form-group">
357
+ <label for="configEditor">配置内容 (YAML格式)</label>
358
+ <textarea id="configEditor" class="config-editor"></textarea>
359
+ </div>
360
+ <button id="saveConfigBtn" class="button">保存配置</button>
361
+ <button id="reloadConfigBtn" class="button button-secondary">重新加载配置</button>
362
+ </div>
363
+ </div>
364
+
365
+ <div id="controlsTab" class="tab-content">
366
+ <div class="card">
367
+ <h2>控制选项</h2>
368
+ <div class="control-row">
369
+ <div class="control-item">
370
+ <h3>AEF 状态控制</h3>
371
+ <button id="toggleAefBtn" class="button button-warning">禁用 AEF</button>
372
+ <p style="margin-top: 10px; color: var(--text-secondary);">
373
+ 当AEF禁用时,将不会自动修复错误或重启服务器
374
+ </p>
375
+ </div>
376
+ <div class="control-item">
377
+ <h3>操作</h3>
378
+ <button id="restartServerBtn" class="button button-error">重启服务器</button>
379
+ <button id="downloadLogsBtn" class="button button-secondary" style="margin-left: 10px;">下载日志</button>
380
+ <p style="margin-top: 10px; color: var(--text-secondary);">
381
+ 重启服务器将立即终止当前进程
382
+ </p>
383
+ </div>
384
+ </div>
385
+ </div>
386
+ </div>
387
+ </div>
388
+
389
+ <div id="notification" class="notification"></div>
390
+
391
+ <script>
392
+ // 全局变量
393
+ let isLoggedIn = false;
394
+ let logSocket = null;
395
+ let currentLogContent = '';
396
+
397
+ // DOM元素
398
+ const loginPage = document.getElementById('loginPage');
399
+ const mainPanel = document.getElementById('mainPanel');
400
+ const passwordInput = document.getElementById('password');
401
+ const loginBtn = document.getElementById('loginBtn');
402
+ const loginError = document.getElementById('loginError');
403
+ const tabs = document.querySelectorAll('.tab');
404
+ const tabContents = document.querySelectorAll('.tab-content');
405
+ const statusIndicator = document.getElementById('statusIndicator');
406
+ const statusText = document.getElementById('statusText');
407
+ const toggleAefBtn = document.getElementById('toggleAefBtn');
408
+ const configEditor = document.getElementById('configEditor');
409
+ const saveConfigBtn = document.getElementById('saveConfigBtn');
410
+ const reloadConfigBtn = document.getElementById('reloadConfigBtn');
411
+ const logContainer = document.getElementById('logContainer');
412
+ const notification = document.getElementById('notification');
413
+
414
+ // 显示通知
415
+ function showNotification(message, type = 'success') {
416
+ notification.textContent = message;
417
+ notification.className = `notification ${type} show`;
418
+
419
+ setTimeout(() => {
420
+ notification.classList.remove('show');
421
+ }, 3000);
422
+ }
423
+
424
+ // 切换标签页
425
+ tabs.forEach(tab => {
426
+ tab.addEventListener('click', () => {
427
+ const tabName = tab.getAttribute('data-tab');
428
+
429
+ // 移除所有活动标签
430
+ tabs.forEach(t => t.classList.remove('active'));
431
+ tabContents.forEach(c => c.classList.remove('active'));
432
+
433
+ // 激活选中的标签
434
+ tab.classList.add('active');
435
+ document.getElementById(`${tabName}Tab`).classList.add('active');
436
+ });
437
+ });
438
+
439
+ // 登录功能
440
+ loginBtn.addEventListener('click', async () => {
441
+ const password = passwordInput.value;
442
+
443
+ try {
444
+ const response = await fetch('/panel/AEF/login', {
445
+ method: 'POST',
446
+ headers: {
447
+ 'Content-Type': 'application/json'
448
+ },
449
+ body: JSON.stringify({ password })
450
+ });
451
+
452
+ const data = await response.json();
453
+
454
+ if (data.success) {
455
+ isLoggedIn = true;
456
+ loginPage.classList.add('hidden');
457
+ mainPanel.classList.remove('hidden');
458
+
459
+ // 加载初始数据
460
+ loadStatusData();
461
+ loadConfigData();
462
+
463
+ // 连接WebSocket获取实时日志
464
+ connectWebSocket();
465
+
466
+ showNotification('登录成功!');
467
+ } else {
468
+ loginError.textContent = data.message || '密码错误';
469
+ loginError.style.display = 'block';
470
+ }
471
+ } catch (error) {
472
+ loginError.textContent = '连接错误,请稍后重试';
473
+ loginError.style.display = 'block';
474
+ }
475
+ });
476
+
477
+ // 加载状态数据
478
+ async function loadStatusData() {
479
+ try {
480
+ const response = await fetch('/panel/AEF/status');
481
+ const data = await response.json();
482
+
483
+ // 更新状态指示器
484
+ if (data.isEnabled) {
485
+ statusIndicator.className = 'status-indicator status-active';
486
+ statusText.textContent = '启用';
487
+ toggleAefBtn.textContent = '禁用 AEF';
488
+ } else {
489
+ statusIndicator.className = 'status-indicator status-inactive';
490
+ statusText.textContent = '禁用';
491
+ toggleAefBtn.textContent = '启用 AEF';
492
+ }
493
+
494
+ // 更新系统信息
495
+ document.getElementById('nodeVersion').textContent = process?.version || 'N/A';
496
+ document.getElementById('platform').textContent = navigator.platform;
497
+ document.getElementById('architecture').textContent = 'N/A'; // 需要后端提供
498
+
499
+ // 更新内存信息
500
+ if (data.memoryInfo) {
501
+ document.getElementById('heapUsed').textContent = formatBytes(data.memoryInfo.heapUsed);
502
+ document.getElementById('heapTotal').textContent = formatBytes(data.memoryInfo.heapTotal);
503
+ document.getElementById('externalMem').textContent = formatBytes(data.memoryInfo.external);
504
+ }
505
+
506
+ // 更新计数器
507
+ document.getElementById('fixCount').textContent = data.fixCount || 0;
508
+ document.getElementById('restartCount').textContent = data.restartCount || 0;
509
+ document.getElementById('lastErrorTime').textContent = data.lastErrorTime || '-';
510
+ } catch (error) {
511
+ console.error('加载状态数据失败:', error);
512
+ }
513
+ }
514
+
515
+ // 加载配置数据
516
+ async function loadConfigData() {
517
+ try {
518
+ const response = await fetch('/panel/AEF/config');
519
+ const data = await response.json();
520
+
521
+ if (data.content) {
522
+ configEditor.value = data.content;
523
+ }
524
+ } catch (error) {
525
+ console.error('加载配置数据失败:', error);
526
+ }
527
+ }
528
+
529
+ // 保存配置
530
+ saveConfigBtn.addEventListener('click', async () => {
531
+ try {
532
+ const content = configEditor.value;
533
+
534
+ const response = await fetch('/panel/AEF/config', {
535
+ method: 'POST',
536
+ headers: {
537
+ 'Content-Type': 'application/json'
538
+ },
539
+ body: JSON.stringify({ content })
540
+ });
541
+
542
+ const data = await response.json();
543
+
544
+ if (data.success) {
545
+ showNotification('配置保存成功!');
546
+ } else {
547
+ showNotification(data.error || '保存失败', 'error');
548
+ }
549
+ } catch (error) {
550
+ showNotification('保存配置时发生错误', 'error');
551
+ }
552
+ });
553
+
554
+ // 重新加载配置
555
+ reloadConfigBtn.addEventListener('click', async () => {
556
+ try {
557
+ await loadConfigData();
558
+ showNotification('配置已重新加载!');
559
+ } catch (error) {
560
+ showNotification('重新加载配置失败', 'error');
561
+ }
562
+ });
563
+
564
+ // 切换AEF状态
565
+ toggleAefBtn.addEventListener('click', async () => {
566
+ try {
567
+ const response = await fetch('/panel/AEF/toggle', {
568
+ method: 'POST',
569
+ headers: {
570
+ 'Content-Type': 'application/json'
571
+ }
572
+ });
573
+
574
+ const data = await response.json();
575
+
576
+ if (data.success) {
577
+ // 更新UI状态
578
+ if (data.isEnabled) {
579
+ statusIndicator.className = 'status-indicator status-active';
580
+ statusText.textContent = '启用';
581
+ toggleAefBtn.textContent = '禁用 AEF';
582
+ } else {
583
+ statusIndicator.className = 'status-indicator status-inactive';
584
+ statusText.textContent = '禁用';
585
+ toggleAefBtn.textContent = '启用 AEF';
586
+ }
587
+
588
+ showNotification(data.isEnabled ? 'AEF 已启用' : 'AEF 已禁用');
589
+ } else {
590
+ showNotification('切换状态失败', 'error');
591
+ }
592
+ } catch (error) {
593
+ showNotification('切换状态时发生错误', 'error');
594
+ }
595
+ });
596
+
597
+ // 连接WebSocket获取实时日志
598
+ function connectWebSocket() {
599
+ // 注意:这里需要根据实际的WebSocket服务器地址调整
600
+ // 由于前端不能直接连接到Socket.IO,我们需要使用轮询方式模拟
601
+ pollLogs();
602
+ }
603
+
604
+ // 轮询获取日志
605
+ async function pollLogs() {
606
+ if (!isLoggedIn) return;
607
+
608
+ try {
609
+ const response = await fetch('/panel/AEF/log');
610
+ const data = await response.json();
611
+
612
+ if (data.log !== currentLogContent) {
613
+ currentLogContent = data.log;
614
+ logContainer.textContent = data.log;
615
+ logContainer.scrollTop = logContainer.scrollHeight;
616
+ }
617
+ } catch (error) {
618
+ console.error('获取日志失败:', error);
619
+ }
620
+
621
+ // 每2秒轮询一次
622
+ setTimeout(pollLogs, 2000);
623
+ }
624
+
625
+ // 格式化字节大小
626
+ function formatBytes(bytes) {
627
+ if (bytes === 0) return '0 Bytes';
628
+ const k = 1024;
629
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
630
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
631
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
632
+ }
633
+
634
+ // 页面加载完成后聚焦密码框
635
+ window.onload = () => {
636
+ passwordInput.focus();
637
+ };
638
+ </script>
639
+ </body>
640
+ </html>