thuban 0.3.2 → 0.3.4

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 (59) hide show
  1. package/README.md +137 -102
  2. package/dist/LICENSE +21 -0
  3. package/dist/README.md +185 -0
  4. package/dist/cli.js +2 -0
  5. package/dist/packages/scanner/ai-confidence-scorer.js +1 -0
  6. package/dist/packages/scanner/alert-manager.js +1 -0
  7. package/dist/packages/scanner/baseline-manager.js +1 -0
  8. package/dist/packages/scanner/code-scanner.js +1 -0
  9. package/dist/packages/scanner/codebase-passport.js +1 -0
  10. package/dist/packages/scanner/copy-paste-detector.js +1 -0
  11. package/dist/packages/scanner/dependency-graph.js +1 -0
  12. package/dist/packages/scanner/drift-detector.js +1 -0
  13. package/dist/packages/scanner/executive-report.js +1 -0
  14. package/dist/packages/scanner/file-collector.js +1 -0
  15. package/dist/packages/scanner/file-watcher.js +1 -0
  16. package/dist/packages/scanner/ghost-code-detector.js +1 -0
  17. package/dist/packages/scanner/hallucination-detector.js +1 -0
  18. package/dist/packages/scanner/health-checker.js +1 -0
  19. package/dist/packages/scanner/html-report.js +1 -0
  20. package/dist/packages/scanner/index.js +1 -0
  21. package/dist/packages/scanner/license-manager.js +1 -0
  22. package/dist/packages/scanner/master-health-checker.js +1 -0
  23. package/dist/packages/scanner/monitor-notifier.js +1 -0
  24. package/dist/packages/scanner/monitor-service.js +1 -0
  25. package/dist/packages/scanner/monitor-store.js +1 -0
  26. package/dist/packages/scanner/pre-commit-gate.js +1 -0
  27. package/dist/packages/scanner/scan-diff.js +1 -0
  28. package/dist/packages/scanner/scan-runner.js +1 -0
  29. package/dist/packages/scanner/secret-scanner.js +1 -0
  30. package/dist/packages/scanner/sentinel-core.js +1 -0
  31. package/dist/packages/scanner/sentinel-knowledge.js +1 -0
  32. package/dist/packages/scanner/tech-debt-analyzer.js +1 -0
  33. package/dist/packages/scanner/tech-debt-cost.js +1 -0
  34. package/dist/packages/scanner/widget-generator.js +1 -0
  35. package/package.json +16 -8
  36. package/cli.js +0 -2412
  37. package/packages/scanner/ai-confidence-scorer.js +0 -260
  38. package/packages/scanner/alert-manager.js +0 -398
  39. package/packages/scanner/baseline-manager.js +0 -109
  40. package/packages/scanner/code-scanner.js +0 -713
  41. package/packages/scanner/codebase-passport.js +0 -299
  42. package/packages/scanner/copy-paste-detector.js +0 -250
  43. package/packages/scanner/dependency-graph.js +0 -536
  44. package/packages/scanner/drift-detector.js +0 -423
  45. package/packages/scanner/executive-report.js +0 -774
  46. package/packages/scanner/file-watcher.js +0 -323
  47. package/packages/scanner/ghost-code-detector.js +0 -226
  48. package/packages/scanner/hallucination-detector.js +0 -652
  49. package/packages/scanner/health-checker.js +0 -586
  50. package/packages/scanner/html-report.js +0 -634
  51. package/packages/scanner/index.js +0 -92
  52. package/packages/scanner/license-manager.js +0 -318
  53. package/packages/scanner/master-health-checker.js +0 -513
  54. package/packages/scanner/pre-commit-gate.js +0 -216
  55. package/packages/scanner/sentinel-core.js +0 -608
  56. package/packages/scanner/sentinel-knowledge.js +0 -322
  57. package/packages/scanner/tech-debt-analyzer.js +0 -565
  58. package/packages/scanner/tech-debt-cost.js +0 -194
  59. package/packages/scanner/widget-generator.js +0 -415
@@ -1,513 +0,0 @@
1
- /**
2
- * Master Health Checker
3
- *
4
- * @purpose Comprehensive health monitoring for all 47 Orion failure points
5
- * @module sentinel
6
- * @layer infrastructure
7
- * @imports-from fs, path, child_process, events
8
- * @exports-to server/autonomous/health-scheduler.js
9
- * @side-effects File system reads, Process spawning, Network requests
10
- * @critical-for System reliability and self-healing
11
- */
12
-
13
- const fs = require('fs');
14
- const path = require('path');
15
- const { execSync, exec } = require('child_process');
16
- const EventEmitter = require('events');
17
-
18
- // Paths
19
- const ROOT = path.join(__dirname, '..');
20
- const SERVER = path.join(ROOT, 'server');
21
- const MANIFEST_PATH = path.join(SERVER, 'data', 'health-check-manifest.json');
22
-
23
- class MasterHealthChecker extends EventEmitter {
24
- constructor(config = {}) {
25
- super();
26
- this.config = {
27
- rootPath: config.rootPath || ROOT,
28
- serverPath: config.serverPath || SERVER,
29
- timeout: config.timeout || 5000,
30
- ...config
31
- };
32
-
33
- this.manifest = this._loadManifest();
34
- this.lastResults = null;
35
- this.issueCount = 0;
36
- }
37
-
38
- _loadManifest() {
39
- try {
40
- if (fs.existsSync(MANIFEST_PATH)) {
41
- return JSON.parse(fs.readFileSync(MANIFEST_PATH, 'utf8'));
42
- }
43
- } catch (e) {
44
- console.error('[MASTER-HEALTH] Failed to load manifest:', e.message);
45
- }
46
- return null;
47
- }
48
-
49
- /**
50
- * Run ALL 47 health checks
51
- */
52
- async runFullCheck() {
53
- console.log('[MASTER-HEALTH] Starting full system health check (47 checkpoints)...');
54
- const startTime = Date.now();
55
-
56
- const results = {
57
- timestamp: new Date().toISOString(),
58
- duration: 0,
59
- totalChecks: 0,
60
- passed: 0,
61
- failed: 0,
62
- warnings: 0,
63
- systems: {},
64
- criticalIssues: [],
65
- autoHealAttempted: [],
66
- humanEscalationNeeded: []
67
- };
68
-
69
- // Run checks for each system
70
- const systems = [
71
- { id: 'server', fn: () => this._checkServer() },
72
- { id: 'senate', fn: () => this._checkSenate() },
73
- { id: 'citadel', fn: () => this._checkCitadel() },
74
- { id: 'shadowRealm', fn: () => this._checkShadowRealm() },
75
- { id: 'forge', fn: () => this._checkForge() },
76
- { id: 'ocee', fn: () => this._checkOCEE() },
77
- { id: 'memory', fn: () => this._checkMemory() },
78
- { id: 'external', fn: () => this._checkExternal() }
79
- ];
80
-
81
- for (const system of systems) {
82
- try {
83
- const systemResult = await system.fn();
84
- results.systems[system.id] = systemResult;
85
-
86
- results.totalChecks += systemResult.checks.length;
87
- results.passed += systemResult.checks.filter(c => c.status === 'PASS').length;
88
- results.failed += systemResult.checks.filter(c => c.status === 'FAIL').length;
89
- results.warnings += systemResult.checks.filter(c => c.status === 'WARN').length;
90
-
91
- // Collect critical issues
92
- const critical = systemResult.checks.filter(c => c.status === 'FAIL' && c.criticality === 'CRITICAL');
93
- results.criticalIssues.push(...critical);
94
-
95
- // Collect escalation needs
96
- const needsHuman = systemResult.checks.filter(c => c.needsHumanEscalation);
97
- results.humanEscalationNeeded.push(...needsHuman);
98
-
99
- } catch (error) {
100
- results.systems[system.id] = {
101
- status: 'ERROR',
102
- error: error.message,
103
- checks: []
104
- };
105
- }
106
- }
107
-
108
- results.duration = Date.now() - startTime;
109
- results.overallStatus = this._calculateOverallStatus(results);
110
-
111
- this.lastResults = results;
112
- this.emit('checkComplete', results);
113
-
114
- console.log(`[MASTER-HEALTH] Complete: ${results.passed}/${results.totalChecks} passed (${results.duration}ms)`);
115
-
116
- return results;
117
- }
118
-
119
- /**
120
- * Run quick check (critical systems only)
121
- */
122
- async runQuickCheck() {
123
- console.log('[MASTER-HEALTH] Running quick check (critical systems)...');
124
-
125
- const results = {
126
- timestamp: new Date().toISOString(),
127
- type: 'quick',
128
- checks: []
129
- };
130
-
131
- // SRV-001: Server running
132
- results.checks.push(await this._check('SRV-001', 'Server Process', () => {
133
- return this._fileExists(path.join(this.config.serverPath, 'server.js'));
134
- }));
135
-
136
- // SEN-003: Providers responding (simplified)
137
- results.checks.push(await this._check('SEN-003', 'Model Registry', () => {
138
- const registry = path.join(this.config.serverPath, 'data', 'model-registry.json');
139
- if (!fs.existsSync(registry)) return false;
140
- const data = JSON.parse(fs.readFileSync(registry, 'utf8'));
141
- return Object.keys(data.providers || {}).length >= 3;
142
- }));
143
-
144
- // CIT-001: Constitution loaded
145
- results.checks.push(await this._check('CIT-001', 'Constitution', () => {
146
- const constitution = path.join(this.config.rootPath, 'citadel', 'constitution.json');
147
- return this._fileExists(constitution) && this._isValidJson(constitution);
148
- }));
149
-
150
- // CIT-002: File guard active
151
- results.checks.push(await this._check('CIT-002', 'File Guard', () => {
152
- return this._fileExists(path.join(this.config.rootPath, 'citadel', 'file-guard.js'));
153
- }));
154
-
155
- const passed = results.checks.filter(c => c.status === 'PASS').length;
156
- console.log(`[MASTER-HEALTH] Quick check: ${passed}/${results.checks.length} passed`);
157
-
158
- return results;
159
- }
160
-
161
- // ========== SYSTEM CHECKS ==========
162
-
163
- async _checkServer() {
164
- const checks = [];
165
-
166
- // SRV-001: Server process files exist
167
- checks.push(await this._check('SRV-001', 'Server Files', () => {
168
- return this._fileExists(path.join(this.config.serverPath, 'server.js')) &&
169
- this._fileExists(path.join(this.config.serverPath, 'package.json'));
170
- }, 'CRITICAL'));
171
-
172
- // SRV-002: Memory (check node_modules size as proxy)
173
- checks.push(await this._check('SRV-002', 'Node Modules', () => {
174
- return this._fileExists(path.join(this.config.serverPath, 'node_modules'));
175
- }, 'HIGH', 'npm install'));
176
-
177
- // SRV-003: Package.json valid
178
- checks.push(await this._check('SRV-003', 'Package Valid', () => {
179
- return this._isValidJson(path.join(this.config.serverPath, 'package.json'));
180
- }, 'HIGH'));
181
-
182
- // SRV-004: Data directory exists
183
- checks.push(await this._check('SRV-004', 'Data Directory', () => {
184
- return this._dirExists(path.join(this.config.serverPath, 'data'));
185
- }, 'MEDIUM'));
186
-
187
- // SRV-005: Environment file or vars
188
- checks.push(await this._check('SRV-005', 'Environment', () => {
189
- return this._fileExists(path.join(this.config.rootPath, '.env')) ||
190
- process.env.ANTHROPIC_API_KEY !== undefined;
191
- }, 'HIGH'));
192
-
193
- return { status: this._systemStatus(checks), checks };
194
- }
195
-
196
- async _checkSenate() {
197
- const checks = [];
198
-
199
- // SEN-001: Model registry
200
- checks.push(await this._check('SEN-001', 'Model Registry', () => {
201
- const file = path.join(this.config.serverPath, 'data', 'model-registry.json');
202
- return this._isValidJson(file);
203
- }, 'CRITICAL', 'Restore from snapshot'));
204
-
205
- // SEN-002: Senate weights
206
- checks.push(await this._check('SEN-002', 'Senate Weights', () => {
207
- const file = path.join(this.config.serverPath, 'data', 'senate-weights-v2.json');
208
- return this._isValidJson(file);
209
- }, 'HIGH', 'Reset to defaults'));
210
-
211
- // SEN-003: Providers configured
212
- checks.push(await this._check('SEN-003', 'Providers Configured', () => {
213
- const file = path.join(this.config.serverPath, 'data', 'model-registry.json');
214
- if (!this._isValidJson(file)) return false;
215
- const data = JSON.parse(fs.readFileSync(file, 'utf8'));
216
- return Object.keys(data.providers || {}).length >= 5;
217
- }, 'CRITICAL'));
218
-
219
- // SEN-004: Senate core files
220
- checks.push(await this._check('SEN-004', 'Senate Core', () => {
221
- return this._fileExists(path.join(this.config.serverPath, 'senate-v2.js')) ||
222
- this._fileExists(path.join(this.config.serverPath, 'senate.js'));
223
- }, 'CRITICAL'));
224
-
225
- // SEN-005: Response cache not corrupted
226
- checks.push(await this._check('SEN-005', 'Response Cache', () => {
227
- const file = path.join(this.config.serverPath, 'data', 'response-cache.json');
228
- return !this._fileExists(file) || this._isValidJson(file);
229
- }, 'LOW'));
230
-
231
- return { status: this._systemStatus(checks), checks };
232
- }
233
-
234
- async _checkCitadel() {
235
- const checks = [];
236
-
237
- // CIT-001: Constitution
238
- checks.push(await this._check('CIT-001', 'Constitution', () => {
239
- const file = path.join(this.config.rootPath, 'citadel', 'constitution.json');
240
- return this._isValidJson(file);
241
- }, 'CRITICAL', 'HALT - Safety rules missing'));
242
-
243
- // CIT-002: File guard
244
- checks.push(await this._check('CIT-002', 'File Guard', () => {
245
- return this._fileExists(path.join(this.config.rootPath, 'citadel', 'file-guard.js'));
246
- }, 'CRITICAL'));
247
-
248
- // CIT-003: Enforcer
249
- checks.push(await this._check('CIT-003', 'Enforcer', () => {
250
- return this._fileExists(path.join(this.config.rootPath, 'citadel', 'enforcer.js'));
251
- }, 'CRITICAL'));
252
-
253
- // CIT-004: Watchers
254
- checks.push(await this._check('CIT-004', 'Watchers', () => {
255
- return this._fileExists(path.join(this.config.rootPath, 'citadel', 'watchers.js'));
256
- }, 'HIGH'));
257
-
258
- // CIT-005: Audit directory
259
- checks.push(await this._check('CIT-005', 'Audit Directory', () => {
260
- return this._dirExists(path.join(this.config.rootPath, 'citadel', 'audit'));
261
- }, 'MEDIUM', 'Create directory'));
262
-
263
- return { status: this._systemStatus(checks), checks };
264
- }
265
-
266
- async _checkShadowRealm() {
267
- const checks = [];
268
-
269
- // SHD-001: Shadow realm file
270
- checks.push(await this._check('SHD-001', 'Shadow Realm V2', () => {
271
- return this._fileExists(path.join(this.config.rootPath, 'build-engine', 'orion-core', 'shadow-realm-v2.js'));
272
- }, 'CRITICAL'));
273
-
274
- // SHD-002: Node available
275
- checks.push(await this._check('SHD-002', 'Node Binary', () => {
276
- try {
277
- execSync('node --version', { stdio: 'pipe' });
278
- return true;
279
- } catch { return false; }
280
- }, 'CRITICAL'));
281
-
282
- // SHD-003: Temp directory writable
283
- checks.push(await this._check('SHD-003', 'Temp Writable', () => {
284
- const os = require('os');
285
- const testFile = path.join(os.tmpdir(), 'orion-health-test-' + Date.now());
286
- try {
287
- fs.writeFileSync(testFile, 'test');
288
- fs.unlinkSync(testFile);
289
- return true;
290
- } catch { return false; }
291
- }, 'HIGH'));
292
-
293
- // SHD-004: Healing loop
294
- checks.push(await this._check('SHD-004', 'Healing Loop', () => {
295
- return this._fileExists(path.join(this.config.rootPath, 'build-engine', 'orion-core', 'healing-loop.js'));
296
- }, 'HIGH'));
297
-
298
- return { status: this._systemStatus(checks), checks };
299
- }
300
-
301
- async _checkForge() {
302
- const checks = [];
303
- const forgePath = path.join(this.config.rootPath, 'forge');
304
-
305
- // FRG-001: Forge core
306
- checks.push(await this._check('FRG-001', 'Forge Core', () => {
307
- return this._fileExists(path.join(forgePath, 'forge-core.js'));
308
- }, 'HIGH'));
309
-
310
- // FRG-002: Task decomposer
311
- checks.push(await this._check('FRG-002', 'Task Decomposer', () => {
312
- return this._fileExists(path.join(forgePath, 'task-decomposer.js'));
313
- }, 'MEDIUM'));
314
-
315
- // FRG-003: Intent matcher
316
- checks.push(await this._check('FRG-003', 'Intent Matcher', () => {
317
- return this._fileExists(path.join(forgePath, 'intent-matcher.js'));
318
- }, 'MEDIUM'));
319
-
320
- // FRG-004: Diagnostician
321
- checks.push(await this._check('FRG-004', 'Diagnostician', () => {
322
- return this._fileExists(path.join(forgePath, 'diagnostician-v2.js')) ||
323
- this._fileExists(path.join(forgePath, 'diagnostician.js'));
324
- }, 'MEDIUM'));
325
-
326
- // FRG-005: Foreman
327
- checks.push(await this._check('FRG-005', 'Foreman', () => {
328
- return this._fileExists(path.join(this.config.rootPath, 'build-engine', 'orion-core', 'foreman.js'));
329
- }, 'HIGH'));
330
-
331
- return { status: this._systemStatus(checks), checks };
332
- }
333
-
334
- async _checkOCEE() {
335
- const checks = [];
336
- const oceePath = path.join(this.config.serverPath, 'ocee');
337
-
338
- // OCE-001: OCEE core
339
- checks.push(await this._check('OCE-001', 'OCEE Core', () => {
340
- return this._fileExists(path.join(oceePath, 'ocee-core.js'));
341
- }, 'HIGH'));
342
-
343
- // OCE-002: Persistent task queue
344
- checks.push(await this._check('OCE-002', 'Task Queue', () => {
345
- return this._fileExists(path.join(oceePath, 'persistent-task-queue.js'));
346
- }, 'HIGH'));
347
-
348
- // OCE-003: Checkpoint manager
349
- checks.push(await this._check('OCE-003', 'Checkpoint Manager', () => {
350
- return this._fileExists(path.join(oceePath, 'checkpoint-manager.js'));
351
- }, 'HIGH'));
352
-
353
- // OCE-004: Build sessions valid
354
- checks.push(await this._check('OCE-004', 'Build Sessions', () => {
355
- const file = path.join(this.config.serverPath, 'data', 'build-sessions.json');
356
- return !this._fileExists(file) || this._isValidJson(file);
357
- }, 'MEDIUM'));
358
-
359
- // OCE-005: Executor status
360
- checks.push(await this._check('OCE-005', 'Executor Status', () => {
361
- const file = path.join(this.config.serverPath, 'data', 'executor-status.json');
362
- return this._isValidJson(file);
363
- }, 'MEDIUM'));
364
-
365
- return { status: this._systemStatus(checks), checks };
366
- }
367
-
368
- async _checkMemory() {
369
- const checks = [];
370
-
371
- // MEM-001: orion-knowledge.json
372
- checks.push(await this._check('MEM-001', 'Orion Knowledge', () => {
373
- return this._isValidJson(path.join(this.config.rootPath, 'orion-knowledge.json'));
374
- }, 'MEDIUM', 'Reinitialize'));
375
-
376
- // MEM-002: Memory bank files
377
- checks.push(await this._check('MEM-002', 'Memory Bank', () => {
378
- const mbPath = path.join(this.config.rootPath, 'memory-bank');
379
- return this._fileExists(path.join(mbPath, 'progress.md')) &&
380
- this._fileExists(path.join(mbPath, 'activeContext.md'));
381
- }, 'MEDIUM'));
382
-
383
- // MEM-003: Snapshot manifest
384
- checks.push(await this._check('MEM-003', 'Snapshot Manifest', () => {
385
- const file = path.join(this.config.serverPath, '.orion', 'snapshot-manifest.json');
386
- return !this._fileExists(file) || this._isValidJson(file);
387
- }, 'MEDIUM'));
388
-
389
- // MEM-004: Build logs directory
390
- checks.push(await this._check('MEM-004', 'Build Logs', () => {
391
- return this._dirExists(path.join(this.config.serverPath, 'data', 'build-logs'));
392
- }, 'MEDIUM'));
393
-
394
- // MEM-005: Failure memory service
395
- checks.push(await this._check('MEM-005', 'Failure Memory', () => {
396
- return this._fileExists(path.join(this.config.serverPath, 'services', 'failure-memory.js'));
397
- }, 'MEDIUM'));
398
-
399
- return { status: this._systemStatus(checks), checks };
400
- }
401
-
402
- async _checkExternal() {
403
- const checks = [];
404
-
405
- // EXT-001: Zoho tokens (if configured)
406
- checks.push(await this._check('EXT-001', 'Zoho Tokens', () => {
407
- const file = path.join(this.config.serverPath, 'data', 'zoho-tokens.json');
408
- return !this._fileExists(file) || this._isValidJson(file);
409
- }, 'LOW'));
410
-
411
- // EXT-002: Cartography maps
412
- checks.push(await this._check('EXT-002', 'Cartography', () => {
413
- return this._dirExists(path.join(this.config.rootPath, 'cartography'));
414
- }, 'LOW'));
415
-
416
- // EXT-003: Notification config
417
- checks.push(await this._check('EXT-003', 'Notification Config', () => {
418
- const file = path.join(this.config.serverPath, 'data', 'notification-config.json');
419
- return !this._fileExists(file) || this._isValidJson(file);
420
- }, 'LOW'));
421
-
422
- // EXT-004: Health history
423
- checks.push(await this._check('EXT-004', 'Health History', () => {
424
- const file = path.join(this.config.serverPath, 'data', 'health-history.json');
425
- return !this._fileExists(file) || this._isValidJson(file);
426
- }, 'LOW'));
427
-
428
- return { status: this._systemStatus(checks), checks };
429
- }
430
-
431
- // ========== HELPERS ==========
432
-
433
- async _check(id, name, checkFn, criticality = 'MEDIUM', autoHeal = null) {
434
- const result = {
435
- id,
436
- name,
437
- criticality,
438
- status: 'UNKNOWN',
439
- autoHeal,
440
- needsHumanEscalation: false
441
- };
442
-
443
- try {
444
- const passed = await checkFn();
445
- result.status = passed ? 'PASS' : 'FAIL';
446
-
447
- if (!passed && criticality === 'CRITICAL') {
448
- result.needsHumanEscalation = true;
449
- }
450
- } catch (error) {
451
- result.status = 'ERROR';
452
- result.error = error.message;
453
- result.needsHumanEscalation = true;
454
- }
455
-
456
- return result;
457
- }
458
-
459
- _fileExists(filePath) {
460
- try {
461
- return fs.existsSync(filePath);
462
- } catch { return false; }
463
- }
464
-
465
- _dirExists(dirPath) {
466
- try {
467
- return fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory();
468
- } catch { return false; }
469
- }
470
-
471
- _isValidJson(filePath) {
472
- try {
473
- if (!fs.existsSync(filePath)) return false;
474
- JSON.parse(fs.readFileSync(filePath, 'utf8'));
475
- return true;
476
- } catch { return false; }
477
- }
478
-
479
- _systemStatus(checks) {
480
- const failed = checks.filter(c => c.status === 'FAIL' || c.status === 'ERROR');
481
- const critical = failed.filter(c => c.criticality === 'CRITICAL');
482
-
483
- if (critical.length > 0) return 'CRITICAL';
484
- if (failed.length > 0) return 'DEGRADED';
485
- return 'HEALTHY';
486
- }
487
-
488
- _calculateOverallStatus(results) {
489
- if (results.criticalIssues.length > 0) return 'CRITICAL';
490
- if (results.failed > 0) return 'DEGRADED';
491
- if (results.warnings > 0) return 'WARNING';
492
- return 'HEALTHY';
493
- }
494
-
495
- /**
496
- * Get summary for display
497
- */
498
- getSummary() {
499
- if (!this.lastResults) return { status: 'NO_DATA', message: 'No health check run yet' };
500
-
501
- return {
502
- status: this.lastResults.overallStatus,
503
- passed: this.lastResults.passed,
504
- failed: this.lastResults.failed,
505
- total: this.lastResults.totalChecks,
506
- criticalIssues: this.lastResults.criticalIssues.length,
507
- humanActionNeeded: this.lastResults.humanEscalationNeeded.length,
508
- lastCheck: this.lastResults.timestamp
509
- };
510
- }
511
- }
512
-
513
- module.exports = MasterHealthChecker;