@aiassesstech/mighty-mark 0.1.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 (121) hide show
  1. package/agent/AGENTS.md +61 -0
  2. package/agent/IDENTITY.md +18 -0
  3. package/agent/SOUL.md +56 -0
  4. package/dist/checks/agent-verify.d.ts +15 -0
  5. package/dist/checks/agent-verify.d.ts.map +1 -0
  6. package/dist/checks/agent-verify.js +100 -0
  7. package/dist/checks/agent-verify.js.map +1 -0
  8. package/dist/checks/api-connectivity.d.ts +14 -0
  9. package/dist/checks/api-connectivity.d.ts.map +1 -0
  10. package/dist/checks/api-connectivity.js +77 -0
  11. package/dist/checks/api-connectivity.js.map +1 -0
  12. package/dist/checks/check-context.d.ts +36 -0
  13. package/dist/checks/check-context.d.ts.map +1 -0
  14. package/dist/checks/check-context.js +42 -0
  15. package/dist/checks/check-context.js.map +1 -0
  16. package/dist/checks/check-runner.d.ts +18 -0
  17. package/dist/checks/check-runner.d.ts.map +1 -0
  18. package/dist/checks/check-runner.js +109 -0
  19. package/dist/checks/check-runner.js.map +1 -0
  20. package/dist/checks/data-integrity.d.ts +16 -0
  21. package/dist/checks/data-integrity.d.ts.map +1 -0
  22. package/dist/checks/data-integrity.js +152 -0
  23. package/dist/checks/data-integrity.js.map +1 -0
  24. package/dist/checks/gateway-health.d.ts +17 -0
  25. package/dist/checks/gateway-health.d.ts.map +1 -0
  26. package/dist/checks/gateway-health.js +208 -0
  27. package/dist/checks/gateway-health.js.map +1 -0
  28. package/dist/checks/system-resources.d.ts +21 -0
  29. package/dist/checks/system-resources.d.ts.map +1 -0
  30. package/dist/checks/system-resources.js +136 -0
  31. package/dist/checks/system-resources.js.map +1 -0
  32. package/dist/cli/bin.d.ts +8 -0
  33. package/dist/cli/bin.d.ts.map +1 -0
  34. package/dist/cli/bin.js +12 -0
  35. package/dist/cli/bin.js.map +1 -0
  36. package/dist/cli/runner.d.ts +11 -0
  37. package/dist/cli/runner.d.ts.map +1 -0
  38. package/dist/cli/runner.js +99 -0
  39. package/dist/cli/runner.js.map +1 -0
  40. package/dist/cli/setup.d.ts +28 -0
  41. package/dist/cli/setup.d.ts.map +1 -0
  42. package/dist/cli/setup.js +238 -0
  43. package/dist/cli/setup.js.map +1 -0
  44. package/dist/config/config-schema.d.ts +56 -0
  45. package/dist/config/config-schema.d.ts.map +1 -0
  46. package/dist/config/config-schema.js +34 -0
  47. package/dist/config/config-schema.js.map +1 -0
  48. package/dist/config/defaults.d.ts +31 -0
  49. package/dist/config/defaults.d.ts.map +1 -0
  50. package/dist/config/defaults.js +31 -0
  51. package/dist/config/defaults.js.map +1 -0
  52. package/dist/config/fleet-topology.d.ts +22 -0
  53. package/dist/config/fleet-topology.d.ts.map +1 -0
  54. package/dist/config/fleet-topology.js +81 -0
  55. package/dist/config/fleet-topology.js.map +1 -0
  56. package/dist/history/incident-log.d.ts +19 -0
  57. package/dist/history/incident-log.d.ts.map +1 -0
  58. package/dist/history/incident-log.js +50 -0
  59. package/dist/history/incident-log.js.map +1 -0
  60. package/dist/history/trend-analyzer.d.ts +18 -0
  61. package/dist/history/trend-analyzer.d.ts.map +1 -0
  62. package/dist/history/trend-analyzer.js +80 -0
  63. package/dist/history/trend-analyzer.js.map +1 -0
  64. package/dist/history/uptime-tracker.d.ts +15 -0
  65. package/dist/history/uptime-tracker.d.ts.map +1 -0
  66. package/dist/history/uptime-tracker.js +56 -0
  67. package/dist/history/uptime-tracker.js.map +1 -0
  68. package/dist/index.d.ts +49 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +124 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/notify/alert-classifier.d.ts +19 -0
  73. package/dist/notify/alert-classifier.d.ts.map +1 -0
  74. package/dist/notify/alert-classifier.js +45 -0
  75. package/dist/notify/alert-classifier.js.map +1 -0
  76. package/dist/notify/report-formatter.d.ts +21 -0
  77. package/dist/notify/report-formatter.d.ts.map +1 -0
  78. package/dist/notify/report-formatter.js +139 -0
  79. package/dist/notify/report-formatter.js.map +1 -0
  80. package/dist/notify/telegram-notifier.d.ts +28 -0
  81. package/dist/notify/telegram-notifier.d.ts.map +1 -0
  82. package/dist/notify/telegram-notifier.js +69 -0
  83. package/dist/notify/telegram-notifier.js.map +1 -0
  84. package/dist/plugin.d.ts +18 -0
  85. package/dist/plugin.d.ts.map +1 -0
  86. package/dist/plugin.js +289 -0
  87. package/dist/plugin.js.map +1 -0
  88. package/dist/store/json-store.d.ts +22 -0
  89. package/dist/store/json-store.d.ts.map +1 -0
  90. package/dist/store/json-store.js +128 -0
  91. package/dist/store/json-store.js.map +1 -0
  92. package/dist/store/types.d.ts +19 -0
  93. package/dist/store/types.d.ts.map +1 -0
  94. package/dist/store/types.js +5 -0
  95. package/dist/store/types.js.map +1 -0
  96. package/dist/types/events.d.ts +33 -0
  97. package/dist/types/events.d.ts.map +1 -0
  98. package/dist/types/events.js +5 -0
  99. package/dist/types/events.js.map +1 -0
  100. package/dist/types/fleet.d.ts +27 -0
  101. package/dist/types/fleet.d.ts.map +1 -0
  102. package/dist/types/fleet.js +6 -0
  103. package/dist/types/fleet.js.map +1 -0
  104. package/dist/types/health.d.ts +58 -0
  105. package/dist/types/health.d.ts.map +1 -0
  106. package/dist/types/health.js +5 -0
  107. package/dist/types/health.js.map +1 -0
  108. package/dist/types/incident.d.ts +35 -0
  109. package/dist/types/incident.d.ts.map +1 -0
  110. package/dist/types/incident.js +5 -0
  111. package/dist/types/incident.js.map +1 -0
  112. package/openclaw.plugin.json +56 -0
  113. package/package.json +71 -0
  114. package/src/watchdog/README.md +123 -0
  115. package/src/watchdog/install.sh +244 -0
  116. package/src/watchdog/lib/config.sh +44 -0
  117. package/src/watchdog/lib/logging.sh +29 -0
  118. package/src/watchdog/lib/notify.sh +46 -0
  119. package/src/watchdog/morning-check.sh +107 -0
  120. package/src/watchdog/openclaw-gateway.service +43 -0
  121. package/src/watchdog/watchdog.sh +124 -0
@@ -0,0 +1,128 @@
1
+ /**
2
+ * JSON file-based store for Mighty Mark — Phase 1 persistence.
3
+ * Same proven pattern used by Grillo and Noah.
4
+ */
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ export class JsonStore {
8
+ dataDir;
9
+ constructor(dataDir) {
10
+ this.dataDir = dataDir;
11
+ }
12
+ async initialize() {
13
+ const dirs = [
14
+ this.dataDir,
15
+ path.join(this.dataDir, 'state'),
16
+ path.join(this.dataDir, 'history', 'daily'),
17
+ path.join(this.dataDir, 'incidents'),
18
+ path.join(this.dataDir, 'config'),
19
+ ];
20
+ for (const dir of dirs) {
21
+ if (!fs.existsSync(dir)) {
22
+ fs.mkdirSync(dir, { recursive: true });
23
+ }
24
+ }
25
+ }
26
+ async isWritable() {
27
+ const testFile = path.join(this.dataDir, '.write-test');
28
+ try {
29
+ fs.writeFileSync(testFile, 'mark-self-check');
30
+ fs.unlinkSync(testFile);
31
+ return true;
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
37
+ // ── Last Check ──
38
+ async saveLastCheck(report) {
39
+ const filePath = path.join(this.dataDir, 'state', 'last-check.json');
40
+ fs.writeFileSync(filePath, JSON.stringify(report, null, 2) + '\n');
41
+ }
42
+ async getLastCheck() {
43
+ const filePath = path.join(this.dataDir, 'state', 'last-check.json');
44
+ if (!fs.existsSync(filePath))
45
+ return null;
46
+ try {
47
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ // ── Daily History ──
54
+ async saveDailyHealth(entry) {
55
+ const filePath = path.join(this.dataDir, 'history', 'daily', `${entry.date}.json`);
56
+ fs.writeFileSync(filePath, JSON.stringify(entry, null, 2) + '\n');
57
+ }
58
+ async getDailyHistory(days) {
59
+ const dir = path.join(this.dataDir, 'history', 'daily');
60
+ if (!fs.existsSync(dir))
61
+ return [];
62
+ const cutoff = new Date();
63
+ cutoff.setDate(cutoff.getDate() - days);
64
+ const cutoffStr = cutoff.toISOString().slice(0, 10);
65
+ const files = fs.readdirSync(dir)
66
+ .filter(f => f.endsWith('.json'))
67
+ .filter(f => f.replace('.json', '') >= cutoffStr)
68
+ .sort();
69
+ const results = [];
70
+ for (const file of files) {
71
+ try {
72
+ const data = JSON.parse(fs.readFileSync(path.join(dir, file), 'utf-8'));
73
+ results.push(data);
74
+ }
75
+ catch {
76
+ // Skip corrupted files
77
+ }
78
+ }
79
+ return results;
80
+ }
81
+ // ── Incidents ──
82
+ async saveIncident(incident) {
83
+ const filePath = path.join(this.dataDir, 'incidents', `${incident.id}.json`);
84
+ fs.writeFileSync(filePath, JSON.stringify(incident, null, 2) + '\n');
85
+ }
86
+ async getIncident(id) {
87
+ const filePath = path.join(this.dataDir, 'incidents', `${id}.json`);
88
+ if (!fs.existsSync(filePath))
89
+ return null;
90
+ try {
91
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ }
97
+ async getIncidents(days) {
98
+ const dir = path.join(this.dataDir, 'incidents');
99
+ if (!fs.existsSync(dir))
100
+ return [];
101
+ const cutoff = new Date();
102
+ cutoff.setDate(cutoff.getDate() - days);
103
+ const files = fs.readdirSync(dir).filter(f => f.endsWith('.json'));
104
+ const results = [];
105
+ for (const file of files) {
106
+ try {
107
+ const data = JSON.parse(fs.readFileSync(path.join(dir, file), 'utf-8'));
108
+ if (new Date(data.timestamp) >= cutoff) {
109
+ results.push(data);
110
+ }
111
+ }
112
+ catch {
113
+ // Skip corrupted files
114
+ }
115
+ }
116
+ return results.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
117
+ }
118
+ async resolveIncident(id, resolution) {
119
+ const incident = await this.getIncident(id);
120
+ if (!incident)
121
+ return;
122
+ incident.resolved = true;
123
+ incident.resolvedAt = new Date().toISOString();
124
+ incident.resolution = resolution;
125
+ await this.saveIncident(incident);
126
+ }
127
+ }
128
+ //# sourceMappingURL=json-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-store.js","sourceRoot":"","sources":["../../src/store/json-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Store interface types for Mighty Mark persistence.
3
+ */
4
+ import type { MorningReport } from '../types/health.js';
5
+ import type { Incident, DailyHealth } from '../types/incident.js';
6
+ /** Abstract store interface — Phase 1 uses JSON files, Phase 2 could use Postgres. */
7
+ export interface MarkStore {
8
+ saveLastCheck(report: MorningReport): Promise<void>;
9
+ getLastCheck(): Promise<MorningReport | null>;
10
+ saveDailyHealth(entry: DailyHealth): Promise<void>;
11
+ getDailyHistory(days: number): Promise<DailyHealth[]>;
12
+ saveIncident(incident: Incident): Promise<void>;
13
+ getIncident(id: string): Promise<Incident | null>;
14
+ getIncidents(days: number): Promise<Incident[]>;
15
+ resolveIncident(id: string, resolution: string): Promise<void>;
16
+ initialize(): Promise<void>;
17
+ isWritable(): Promise<boolean>;
18
+ }
19
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAElE,sFAAsF;AACtF,MAAM,WAAW,SAAS;IAExB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,YAAY,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAG9C,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAGtD,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAClD,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAChD,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG/D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAChC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Store interface types for Mighty Mark persistence.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Event types emitted by Mighty Mark during health checks.
3
+ */
4
+ import type { HealthStatus, CheckResult } from './health.js';
5
+ import type { Incident } from './incident.js';
6
+ /** Emitted after a full health check completes. */
7
+ export interface HealthCheckEvent {
8
+ type: 'health-check-complete';
9
+ timestamp: string;
10
+ status: HealthStatus;
11
+ passedChecks: number;
12
+ totalChecks: number;
13
+ failures: CheckResult[];
14
+ }
15
+ /** Emitted when a new incident is created. */
16
+ export interface IncidentEvent {
17
+ type: 'incident-created';
18
+ incident: Incident;
19
+ }
20
+ /** Emitted when an incident is resolved. */
21
+ export interface IncidentResolvedEvent {
22
+ type: 'incident-resolved';
23
+ incidentId: string;
24
+ resolution: string;
25
+ resolvedAt: string;
26
+ }
27
+ /** Emitted when the watchdog restarts the gateway. */
28
+ export interface WatchdogRecoveryEvent {
29
+ type: 'watchdog-recovery';
30
+ timestamp: string;
31
+ restartCount: number;
32
+ }
33
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/types/events.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAiB,MAAM,aAAa,CAAC;AAC5E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,mDAAmD;AACnD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,uBAAuB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,4CAA4C;AAC5C,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,sDAAsD;AACtD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Event types emitted by Mighty Mark during health checks.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/types/events.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Fleet topology types for Mighty Mark.
3
+ * The fleet topology is loaded from an external JSON file (BB-editable, no rebuild).
4
+ */
5
+ /** Definition of a single agent in the fleet. */
6
+ export interface FleetAgent {
7
+ id: string;
8
+ name: string;
9
+ role: string;
10
+ model: string;
11
+ hasPlugin: boolean;
12
+ pluginId?: string;
13
+ requiredPromptFiles: string[];
14
+ requiredKnowledge: boolean;
15
+ dataChecks: string[];
16
+ }
17
+ /** The full fleet topology — loaded from fleet-topology.json at runtime. */
18
+ export interface FleetTopology {
19
+ version: string;
20
+ lastUpdated?: string;
21
+ updatedBy?: string;
22
+ agents: FleetAgent[];
23
+ plugins: string[];
24
+ expectedMinToolCount: number;
25
+ notes?: string;
26
+ }
27
+ //# sourceMappingURL=fleet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet.d.ts","sourceRoot":"","sources":["../../src/types/fleet.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iDAAiD;AACjD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Fleet topology types for Mighty Mark.
3
+ * The fleet topology is loaded from an external JSON file (BB-editable, no rebuild).
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=fleet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet.js","sourceRoot":"","sources":["../../src/types/fleet.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Core health status types for Mighty Mark.
3
+ */
4
+ /** Overall system health classification. */
5
+ export type HealthStatus = 'GREEN' | 'YELLOW' | 'RED';
6
+ /** Check category — the five pillars of health monitoring. */
7
+ export type CheckCategory = 'gateway' | 'agents' | 'system' | 'api' | 'data';
8
+ /** Severity level for individual checks and incidents. */
9
+ export type Severity = 'critical' | 'high' | 'medium' | 'low';
10
+ /** Status of an individual check. */
11
+ export type CheckStatus = 'pass' | 'fail' | 'warn';
12
+ /** Result of a single health check. */
13
+ export interface CheckResult {
14
+ name: string;
15
+ category: CheckCategory;
16
+ status: CheckStatus;
17
+ message?: string;
18
+ timestamp: string;
19
+ durationMs: number;
20
+ }
21
+ /** Aggregated morning report. */
22
+ export interface MorningReport {
23
+ timestamp: string;
24
+ status: HealthStatus;
25
+ summary: {
26
+ total: number;
27
+ passed: number;
28
+ failed: number;
29
+ warnings: number;
30
+ };
31
+ checks: CheckResult[];
32
+ hostname: string;
33
+ uptime: string;
34
+ durationMs: number;
35
+ }
36
+ /** Quick status snapshot (returned by mark_status). */
37
+ export interface StatusSnapshot {
38
+ status: HealthStatus;
39
+ lastCheck: string | null;
40
+ lastCheckStatus: HealthStatus | null;
41
+ activeIncidents: number;
42
+ uptimePercent7d: number | null;
43
+ hostname: string;
44
+ }
45
+ /** Category-scoped check results (returned by mark_check). */
46
+ export interface CategoryResults {
47
+ category: CheckCategory;
48
+ checks: CheckResult[];
49
+ summary: {
50
+ total: number;
51
+ passed: number;
52
+ failed: number;
53
+ warnings: number;
54
+ };
55
+ timestamp: string;
56
+ durationMs: number;
57
+ }
58
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/types/health.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,4CAA4C;AAC5C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEtD,8DAA8D;AAC9D,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAE7E,0DAA0D;AAC1D,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE9D,qCAAqC;AACrC,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEnD,uCAAuC;AACvC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,iCAAiC;AACjC,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,EAAE,YAAY,GAAG,IAAI,CAAC;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,8DAA8D;AAC9D,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Core health status types for Mighty Mark.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/types/health.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Incident types for Mighty Mark.
3
+ */
4
+ import type { CheckCategory, CheckResult, Severity } from './health.js';
5
+ /** A recorded incident — created when checks fail. */
6
+ export interface Incident {
7
+ id: string;
8
+ timestamp: string;
9
+ severity: Severity;
10
+ category: CheckCategory;
11
+ description: string;
12
+ checkResults: CheckResult[];
13
+ resolved: boolean;
14
+ resolvedAt?: string;
15
+ resolution?: string;
16
+ }
17
+ /** Daily health summary for uptime tracking. */
18
+ export interface DailyHealth {
19
+ date: string;
20
+ status: 'GREEN' | 'YELLOW' | 'RED';
21
+ passedChecks: number;
22
+ totalChecks: number;
23
+ incidents: number;
24
+ }
25
+ /** Uptime data (returned by mark_uptime). */
26
+ export interface UptimeData {
27
+ days: number;
28
+ percentage: number;
29
+ totalChecks: number;
30
+ greenDays: number;
31
+ yellowDays: number;
32
+ redDays: number;
33
+ history: DailyHealth[];
34
+ }
35
+ //# sourceMappingURL=incident.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incident.d.ts","sourceRoot":"","sources":["../../src/types/incident.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAExE,sDAAsD;AACtD,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,aAAa,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,6CAA6C;AAC7C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Incident types for Mighty Mark.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=incident.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incident.js","sourceRoot":"","sources":["../../src/types/incident.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,56 @@
1
+ {
2
+ "id": "mighty-mark",
3
+ "name": "Mighty Mark — System Health Sentinel",
4
+ "description": "System health monitoring for the AI Assess Tech fleet. Runs 26 health checks across 5 categories (gateway, agents, system, api, data), sends daily morning reports via Telegram, tracks uptime SLA, and logs incidents.",
5
+ "configSchema": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "healthCheckKey": {
10
+ "type": "string",
11
+ "description": "CompSi Health Check Key from AI Assess platform (hck_...)"
12
+ },
13
+ "telegramToken": {
14
+ "type": "string",
15
+ "description": "@MightyMarkBot Telegram bot token"
16
+ },
17
+ "telegramChatId": {
18
+ "type": "string",
19
+ "description": "Telegram chat ID for morning reports and alerts"
20
+ },
21
+ "morningCheckHourCt": {
22
+ "type": "number",
23
+ "description": "Hour (0-23) for the morning check in America/Chicago time (default: 6 for 6 AM CT)",
24
+ "default": 6
25
+ },
26
+ "diskThresholdPercent": {
27
+ "type": "number",
28
+ "description": "Minimum % disk space free before warning (default: 20)",
29
+ "default": 20
30
+ },
31
+ "memoryThresholdMb": {
32
+ "type": "number",
33
+ "description": "Minimum MB memory available before warning (default: 256)",
34
+ "default": 256
35
+ },
36
+ "cpuThreshold": {
37
+ "type": "number",
38
+ "description": "Maximum 5-min CPU load average before warning (default: 3.0)",
39
+ "default": 3.0
40
+ },
41
+ "dataDir": {
42
+ "type": "string",
43
+ "description": "Directory for Mark's data storage (default: .mighty-mark-data)",
44
+ "default": ".mighty-mark-data"
45
+ }
46
+ },
47
+ "required": []
48
+ },
49
+ "uiHints": {
50
+ "healthCheckKey": { "label": "Health Check Key", "sensitive": true },
51
+ "telegramToken": { "label": "Telegram Bot Token", "sensitive": true },
52
+ "telegramChatId": { "label": "Telegram Chat ID" },
53
+ "morningCheckHourCt": { "label": "Morning Check Hour (CT)", "placeholder": "6" },
54
+ "dataDir": { "label": "Data Directory", "placeholder": ".mighty-mark-data" }
55
+ }
56
+ }
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@aiassesstech/mighty-mark",
3
+ "version": "0.1.0",
4
+ "description": "System Health Sentinel for AI Assess Tech Fleet — autonomous monitoring, watchdog recovery, and fleet infrastructure oversight.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "openclaw": {
9
+ "extensions": [
10
+ "./dist/plugin.js"
11
+ ]
12
+ },
13
+ "bin": {
14
+ "mighty-mark": "./dist/cli/bin.js"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "agent",
19
+ "openclaw.plugin.json",
20
+ "src/watchdog",
21
+ "README.md",
22
+ "LICENSE",
23
+ "CHANGELOG.md"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsc",
27
+ "dev": "tsc --watch",
28
+ "test": "vitest run",
29
+ "test:watch": "vitest",
30
+ "test:coverage": "vitest run --coverage",
31
+ "typecheck": "tsc --noEmit",
32
+ "lint": "tsc --noEmit",
33
+ "prepublishOnly": "npm run typecheck && npm run test && npm run build"
34
+ },
35
+ "keywords": [
36
+ "mighty-mark",
37
+ "system-health",
38
+ "watchdog",
39
+ "monitoring",
40
+ "ai-fleet",
41
+ "openclaw-plugin",
42
+ "health-check",
43
+ "telegram-alerts",
44
+ "infrastructure"
45
+ ],
46
+ "author": "GiDanc AI LLC",
47
+ "license": "Proprietary",
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "https://github.com/spar65/compsi.git",
51
+ "directory": "packages/mighty-mark"
52
+ },
53
+ "homepage": "https://www.aiassesstech.com",
54
+ "bugs": {
55
+ "url": "https://github.com/spar65/compsi/issues"
56
+ },
57
+ "dependencies": {
58
+ "zod": "^3.22.0"
59
+ },
60
+ "devDependencies": {
61
+ "@types/node": "^20.0.0",
62
+ "typescript": "^5.3.3",
63
+ "vitest": "^1.2.0"
64
+ },
65
+ "engines": {
66
+ "node": ">=18.0.0"
67
+ },
68
+ "publishConfig": {
69
+ "access": "public"
70
+ }
71
+ }
@@ -0,0 +1,123 @@
1
+ # Mighty Mark — Watchdog Deployment
2
+
3
+ Pure bash watchdog and morning check scripts for the Hetzner VPS.
4
+
5
+ ## Prerequisites
6
+
7
+ - Ubuntu 24 on Hetzner VPS
8
+ - OpenClaw gateway installed and configured
9
+ - `@MightyMarkBot` created on Telegram (token required)
10
+ - `jq` installed (`apt install jq`)
11
+ - `curl` installed (usually pre-installed)
12
+
13
+ ## Quick Install
14
+
15
+ ```bash
16
+ # After npm install of @aiassesstech/mighty-mark:
17
+ npx @aiassesstech/mighty-mark install-watchdog \
18
+ --telegram-token "YOUR_BOT_TOKEN" \
19
+ --telegram-chat-id "YOUR_CHAT_ID"
20
+ ```
21
+
22
+ Or run the installer directly:
23
+
24
+ ```bash
25
+ sudo bash src/watchdog/install.sh \
26
+ --telegram-token "YOUR_BOT_TOKEN" \
27
+ --telegram-chat-id "YOUR_CHAT_ID"
28
+ ```
29
+
30
+ ## What Gets Installed
31
+
32
+ ```
33
+ /opt/mighty-mark/
34
+ ├── watchdog.sh # Cron: every 5 min — gateway heartbeat
35
+ ├── morning-check.sh # Cron: daily 6:00 AM CT — full health check
36
+ ├── lib/
37
+ │ ├── config.sh # Shared configuration
38
+ │ ├── logging.sh # Structured logging functions
39
+ │ └── notify.sh # Telegram notification functions
40
+ ├── logs/
41
+ │ ├── watchdog.log # Watchdog heartbeats + incidents
42
+ │ ├── morning-check.log # Daily check results
43
+ │ ├── watchdog-cron.log # Cron stdout/stderr capture
44
+ │ └── morning-cron.log # Cron stdout/stderr capture
45
+ ├── state/
46
+ │ └── incident-count.json # Daily restart counter
47
+ └── .env # Telegram credentials (chmod 600)
48
+
49
+ /etc/cron.d/mighty-mark # Cron schedule (CRON_TZ=America/Chicago)
50
+ /etc/logrotate.d/mighty-mark # 14-day log rotation
51
+ ```
52
+
53
+ ## Cron Schedule
54
+
55
+ ```cron
56
+ CRON_TZ=America/Chicago
57
+
58
+ # Watchdog: every 5 minutes
59
+ */5 * * * * root /opt/mighty-mark/watchdog.sh
60
+
61
+ # Morning Check: daily at 6:00 AM CT (auto-adjusts for CDT/CST)
62
+ 0 6 * * * root /opt/mighty-mark/morning-check.sh
63
+ ```
64
+
65
+ `CRON_TZ=America/Chicago` ensures 6:00 AM stays 6:00 AM regardless of Daylight Saving Time.
66
+
67
+ ## Watchdog Behavior
68
+
69
+ 1. Runs every 5 minutes via cron
70
+ 2. Checks `pgrep -f openclaw-gateway`
71
+ 3. **Alive**: Log heartbeat, exit
72
+ 4. **Dead**: Attempt restart via `systemctl restart openclaw-gateway`
73
+ 5. **Restart succeeds**: Notify Greg via Telegram, log recovery
74
+ 6. **Restart fails**: Notify Greg with escalation alert
75
+ 7. **Max 3 restarts/day**: After that, manual intervention required
76
+
77
+ ## Systemd Service (Optional)
78
+
79
+ Belt-and-suspenders with the watchdog:
80
+
81
+ ```bash
82
+ sudo cp src/watchdog/openclaw-gateway.service /etc/systemd/system/
83
+ sudo systemctl daemon-reload
84
+ sudo systemctl enable openclaw-gateway
85
+ sudo systemctl start openclaw-gateway
86
+ ```
87
+
88
+ Systemd handles fast restarts (30s). The watchdog handles the case where systemd gives up after 5 failures.
89
+
90
+ ## Configuration
91
+
92
+ Edit `/opt/mighty-mark/.env`:
93
+
94
+ ```bash
95
+ MIGHTY_MARK_TELEGRAM_TOKEN="your-bot-token"
96
+ MIGHTY_MARK_TELEGRAM_CHAT_ID="your-chat-id"
97
+ MAX_RESTART_ATTEMPTS=3
98
+ DISK_WARN_PERCENT=20
99
+ MEMORY_WARN_MB=256
100
+ ```
101
+
102
+ ## Manual Testing
103
+
104
+ ```bash
105
+ # Test watchdog
106
+ bash /opt/mighty-mark/watchdog.sh
107
+
108
+ # Test morning check
109
+ bash /opt/mighty-mark/morning-check.sh
110
+
111
+ # View logs
112
+ tail -f /opt/mighty-mark/logs/watchdog.log
113
+ tail -f /opt/mighty-mark/logs/morning-check.log
114
+ ```
115
+
116
+ ## Troubleshooting
117
+
118
+ | Symptom | Cause | Fix |
119
+ |---------|-------|-----|
120
+ | No Telegram alerts | Token/chat ID not set | Edit `.env` |
121
+ | Watchdog not running | Cron not installed | Check `/etc/cron.d/mighty-mark` |
122
+ | Morning check fails | Node.js not in PATH | Falls back to bash-only checks |
123
+ | Max restarts reached | Gateway keeps crashing | Check `journalctl -u openclaw-gateway` |