@steadwing/openalerts 0.2.5 → 0.2.7
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.
- package/README.md +198 -141
- package/dist/channels/console.d.ts +6 -0
- package/dist/channels/console.d.ts.map +1 -0
- package/dist/channels/console.js +10 -0
- package/dist/channels/console.js.map +1 -0
- package/dist/channels/telegram.d.ts +12 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js +28 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/webhook.d.ts +8 -0
- package/dist/channels/webhook.d.ts.map +1 -0
- package/dist/channels/webhook.js +15 -0
- package/dist/channels/webhook.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +234 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +51 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +86 -0
- package/dist/config.js.map +1 -0
- package/dist/core/alert-channel.d.ts +3 -10
- package/dist/core/alert-channel.d.ts.map +1 -0
- package/dist/core/alert-channel.js +9 -30
- package/dist/core/alert-channel.js.map +1 -0
- package/dist/core/bounded-map.d.ts +1 -0
- package/dist/core/bounded-map.d.ts.map +1 -0
- package/dist/core/bounded-map.js +1 -0
- package/dist/core/bounded-map.js.map +1 -0
- package/dist/core/engine.d.ts +6 -18
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +48 -98
- package/dist/core/engine.js.map +1 -0
- package/dist/core/evaluator.d.ts +1 -0
- package/dist/core/evaluator.d.ts.map +1 -0
- package/dist/core/evaluator.js +1 -0
- package/dist/core/evaluator.js.map +1 -0
- package/dist/core/event-bus.d.ts +1 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +1 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/formatter.d.ts +1 -0
- package/dist/core/formatter.d.ts.map +1 -0
- package/dist/core/formatter.js +1 -0
- package/dist/core/formatter.js.map +1 -0
- package/dist/core/rules.d.ts +1 -0
- package/dist/core/rules.d.ts.map +1 -0
- package/dist/core/rules.js +1 -0
- package/dist/core/rules.js.map +1 -0
- package/dist/core/store.d.ts +6 -9
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +43 -96
- package/dist/core/store.js.map +1 -0
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +1 -0
- package/dist/core/types.js.map +1 -0
- package/dist/db/index.d.ts +6 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +31 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/queries.d.ts +157 -0
- package/dist/db/queries.d.ts.map +1 -0
- package/dist/db/queries.js +227 -0
- package/dist/db/queries.js.map +1 -0
- package/dist/db/schema.d.ts +5 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +177 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/readers/openclaw.d.ts +11 -0
- package/dist/readers/openclaw.d.ts.map +1 -0
- package/dist/readers/openclaw.js +267 -0
- package/dist/readers/openclaw.js.map +1 -0
- package/dist/server/dashboard.d.ts +2 -0
- package/dist/server/dashboard.d.ts.map +1 -0
- package/dist/server/dashboard.js +765 -0
- package/dist/server/dashboard.js.map +1 -0
- package/dist/server/index.d.ts +10 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +28 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/routes.d.ts +6 -0
- package/dist/server/routes.d.ts.map +1 -0
- package/dist/server/routes.js +146 -0
- package/dist/server/routes.js.map +1 -0
- package/dist/server/sse.d.ts +21 -0
- package/dist/server/sse.d.ts.map +1 -0
- package/dist/server/sse.js +53 -0
- package/dist/server/sse.js.map +1 -0
- package/dist/watchers/files.d.ts +19 -0
- package/dist/watchers/files.d.ts.map +1 -0
- package/dist/watchers/files.js +105 -0
- package/dist/watchers/files.js.map +1 -0
- package/dist/watchers/gateway-adapter.d.ts +18 -0
- package/dist/watchers/gateway-adapter.d.ts.map +1 -0
- package/dist/watchers/gateway-adapter.js +274 -0
- package/dist/watchers/gateway-adapter.js.map +1 -0
- package/dist/watchers/gateway.d.ts +27 -0
- package/dist/watchers/gateway.d.ts.map +1 -0
- package/dist/watchers/gateway.js +131 -0
- package/dist/watchers/gateway.js.map +1 -0
- package/package.json +21 -43
- package/LICENSE +0 -201
- package/openclaw.plugin.json +0 -87
package/README.md
CHANGED
|
@@ -1,195 +1,252 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
</p>
|
|
7
|
-
|
|
8
|
-
<p align="center">
|
|
9
|
-
<a href="https://www.npmjs.com/package/@steadwing/openalerts"><img src="https://img.shields.io/npm/v/@steadwing/openalerts?style=flat&color=blue" alt="npm"></a>
|
|
10
|
-
<a href="https://www.npmjs.com/package/@steadwing/openalerts"><img src="https://img.shields.io/npm/dt/@steadwing/openalerts?style=flat&color=blue" alt="npm"></a>
|
|
11
|
-
<a href="https://github.com/steadwing/openalerts/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-green" alt="License"></a>
|
|
12
|
-
<a href="https://github.com/steadwing/openalerts/stargazers"><img src="https://img.shields.io/github/stars/steadwing/openalerts?style=flat" alt="GitHub stars"></a>
|
|
13
|
-
<a href="https://discord.gg/4rUP86tSXn"><img src="https://img.shields.io/badge/discord-join-5865F2?style=flat" alt="Discord"></a>
|
|
14
|
-
</p>
|
|
15
|
-
|
|
16
|
-
<p align="center">
|
|
17
|
-
<a href="#quickstart">Quickstart</a> ·
|
|
18
|
-
<a href="#alert-rules">Alert Rules</a> ·
|
|
19
|
-
<a href="#llm-enriched-alerts">LLM Enrichment</a> ·
|
|
20
|
-
<a href="#dashboard">Dashboard</a> ·
|
|
21
|
-
<a href="#commands">Commands</a>
|
|
22
|
-
</p>
|
|
1
|
+
# openalerts
|
|
2
|
+
|
|
3
|
+
Standalone monitoring daemon for [OpenClaw](https://openclaw.dev). Connects to your local OpenClaw gateway in real time, fires alerts via Telegram or webhook when something goes wrong, and serves a live dashboard at `http://localhost:4242`.
|
|
4
|
+
|
|
5
|
+
No code changes to OpenClaw needed — runs as a separate process alongside it.
|
|
23
6
|
|
|
24
7
|
---
|
|
25
8
|
|
|
26
|
-
|
|
9
|
+
## Install
|
|
27
10
|
|
|
28
|
-
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g @steadwing/openalerts
|
|
13
|
+
```
|
|
29
14
|
|
|
30
|
-
|
|
15
|
+
> Requires **Node.js ≥ 22.5.0** (uses the built-in `node:sqlite` module — no native builds).
|
|
31
16
|
|
|
32
|
-
|
|
33
|
-
> This project is under revamp for the next few hours
|
|
17
|
+
---
|
|
34
18
|
|
|
35
|
-
|
|
19
|
+
## Quick start
|
|
36
20
|
|
|
37
21
|
```bash
|
|
38
|
-
|
|
22
|
+
# 1. Create default config (auto-detects your OpenClaw gateway token)
|
|
23
|
+
openalerts init
|
|
24
|
+
|
|
25
|
+
# 2. Edit config to add your alert channel
|
|
26
|
+
# ~/.openalerts/config.json
|
|
27
|
+
|
|
28
|
+
# 3. Start monitoring
|
|
29
|
+
openalerts start
|
|
39
30
|
```
|
|
40
31
|
|
|
41
|
-
|
|
32
|
+
Dashboard at **http://127.0.0.1:4242** — the gateway overlay dismisses automatically once connected.
|
|
42
33
|
|
|
43
|
-
|
|
34
|
+
---
|
|
44
35
|
|
|
45
|
-
|
|
36
|
+
## CLI
|
|
46
37
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"config": {
|
|
54
|
-
"alertChannel": "telegram", // telegram | discord | slack | whatsapp | signal
|
|
55
|
-
"alertTo": "YOUR_CHAT_ID",
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
}
|
|
61
|
-
```
|
|
38
|
+
| Command | Description |
|
|
39
|
+
| -------- | --------------------------------------------------------- |
|
|
40
|
+
| `openalerts init` | Create default config at `~/.openalerts/config.json` |
|
|
41
|
+
| `openalerts start` | Start the monitoring daemon |
|
|
42
|
+
| `openalerts status` | Print live engine state (daemon must be running) |
|
|
43
|
+
| `openalerts test` | Fire a test alert through all configured channels |
|
|
62
44
|
|
|
63
|
-
**
|
|
45
|
+
**Options for `start`:**
|
|
64
46
|
|
|
65
|
-
|
|
47
|
+
| Flag | Default | Description |
|
|
48
|
+
| ---- | ------- | ----------- |
|
|
49
|
+
| `--port N` | `4242` | HTTP server port |
|
|
50
|
+
| `--config PATH` | `~/.openalerts/config.json` | Config file path |
|
|
66
51
|
|
|
67
|
-
|
|
68
|
-
openclaw gateway stop && openclaw gateway run
|
|
69
|
-
```
|
|
52
|
+
---
|
|
70
53
|
|
|
71
|
-
|
|
54
|
+
## Configuration
|
|
72
55
|
|
|
73
|
-
|
|
56
|
+
`~/.openalerts/config.json` (created by `openalerts init`):
|
|
74
57
|
|
|
75
|
-
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"gatewayUrl": "ws://127.0.0.1:18789",
|
|
61
|
+
"gatewayToken": "<auto-detected from ~/.openclaw/openclaw.json>",
|
|
62
|
+
"stateDir": "~/.openalerts",
|
|
63
|
+
"watch": {
|
|
64
|
+
"openclawDir": "~/.openclaw",
|
|
65
|
+
"workspaces": ["workspace", "workspace-study"]
|
|
66
|
+
},
|
|
67
|
+
"server": {
|
|
68
|
+
"port": 4242,
|
|
69
|
+
"host": "127.0.0.1"
|
|
70
|
+
},
|
|
71
|
+
"channels": [
|
|
72
|
+
{ "type": "telegram", "token": "BOT_TOKEN", "chatId": "CHAT_ID" },
|
|
73
|
+
{ "type": "webhook", "webhookUrl": "https://your-endpoint" },
|
|
74
|
+
{ "type": "console" }
|
|
75
|
+
],
|
|
76
|
+
"quiet": false
|
|
77
|
+
}
|
|
78
|
+
```
|
|
76
79
|
|
|
77
|
-
|
|
80
|
+
**Gateway token** is auto-detected from `gateway.auth.token` in `~/.openclaw/openclaw.json` — no manual copy needed.
|
|
78
81
|
|
|
79
|
-
|
|
82
|
+
**Channels**: configure at least one. Falls back to `console` if none are set.
|
|
80
83
|
|
|
81
|
-
|
|
84
|
+
---
|
|
82
85
|
|
|
83
|
-
|
|
84
|
-
http://127.0.0.1:18789/openalerts
|
|
85
|
-
```
|
|
86
|
+
## What it monitors
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
- **Sessions** — Active sessions with cost/token aggregation
|
|
89
|
-
- **Execs** — Shell command executions with output capture
|
|
90
|
-
- **System Logs** — Filtered, structured logs with search
|
|
91
|
-
- **Health** — Rule status, alert history, system stats
|
|
92
|
-
- **Debug** — State snapshot for troubleshooting
|
|
88
|
+
Captures everything from the OpenClaw gateway WebSocket in real time:
|
|
93
89
|
|
|
94
|
-
|
|
90
|
+
| Event | What's captured |
|
|
91
|
+
| ----- | --------------- |
|
|
92
|
+
| Agent runs | Start, streaming, complete, error, aborted |
|
|
93
|
+
| Tool calls | Tool name, duration, result |
|
|
94
|
+
| LLM usage | Token counts, cost per call |
|
|
95
|
+
| Shell exec | Command, pid, output, exit code |
|
|
96
|
+
| Heartbeats | Gateway health, active sessions, queue depth |
|
|
97
|
+
| Cron jobs | Schedule, last run, next run, errors |
|
|
98
|
+
| Sessions | Active sessions, costs, message counts |
|
|
99
|
+
| Workspace docs | SOUL.md, HEARTBEAT.md, MEMORY.md per agent |
|
|
95
100
|
|
|
96
|
-
|
|
101
|
+
---
|
|
97
102
|
|
|
98
|
-
|
|
99
|
-
| ----------------- | ------------------------------------- | -------- | ------------------- |
|
|
100
|
-
| `llm-errors` | LLM/agent failures in 1 min window | ERROR | `1` error |
|
|
101
|
-
| `infra-errors` | Infrastructure errors in 1 min window | ERROR | `1` error |
|
|
102
|
-
| `gateway-down` | No heartbeat received | CRITICAL | `30000` ms (30s) |
|
|
103
|
-
| `session-stuck` | Session idle too long | WARN | `120000` ms (2 min) |
|
|
104
|
-
| `high-error-rate` | Message failure rate over last 20 | ERROR | `50`% |
|
|
105
|
-
| `queue-depth` | Queued items piling up | WARN | `10` items |
|
|
106
|
-
| `tool-errors` | Tool failures in 1 min window | WARN | `1` error |
|
|
107
|
-
| `heartbeat-fail` | Consecutive heartbeat failures | ERROR | `3` failures |
|
|
103
|
+
## Alert rules
|
|
108
104
|
|
|
109
|
-
|
|
105
|
+
Ten rules run against every event in real time. All thresholds and cooldowns are configurable via the `rules` key in config.
|
|
110
106
|
|
|
111
|
-
|
|
112
|
-
|
|
107
|
+
| Rule | Triggers when | Threshold | Cooldown |
|
|
108
|
+
| ---- | ------------- | --------- | -------- |
|
|
109
|
+
| `infra-errors` | `infra.error` events in 1 min | 1 | 15 min |
|
|
110
|
+
| `llm-errors` | `llm.error` or `agent.error` in 1 min | 1 | 15 min |
|
|
111
|
+
| `tool-errors` | `tool.error` in 1 min | 1 | 15 min |
|
|
112
|
+
| `heartbeat-fail` | Consecutive heartbeat failures | 3 | 30 min |
|
|
113
|
+
| `session-stuck` | Session idle too long | 120 s | 30 min |
|
|
114
|
+
| `high-error-rate` | Error % of last 20 calls | 50% | 30 min |
|
|
115
|
+
| `queue-depth` | Items in delivery queue | 10 | 15 min |
|
|
116
|
+
| `gateway-down` | No heartbeat from watchdog | 30 s | 60 min |
|
|
117
|
+
| `cost-hourly-spike` | LLM cost per hour | $5 | 30 min |
|
|
118
|
+
| `cost-daily-budget` | LLM cost per day | $20 | 6 h |
|
|
113
119
|
|
|
114
|
-
|
|
120
|
+
Override a rule threshold in config:
|
|
115
121
|
|
|
116
|
-
```
|
|
122
|
+
```json
|
|
117
123
|
{
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
"rules": {
|
|
124
|
-
"llm-errors": { "threshold": 5 },
|
|
125
|
-
"infra-errors": { "cooldownMinutes": 30 },
|
|
126
|
-
"high-error-rate": { "enabled": false },
|
|
127
|
-
"gateway-down": { "threshold": 60000 },
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
},
|
|
124
|
+
"rules": {
|
|
125
|
+
"llm-errors": { "threshold": 5 },
|
|
126
|
+
"gateway-down": { "enabled": false },
|
|
127
|
+
"heartbeat-fail": { "cooldownMinutes": 60 }
|
|
128
|
+
}
|
|
133
129
|
}
|
|
134
130
|
```
|
|
135
131
|
|
|
136
|
-
|
|
132
|
+
---
|
|
137
133
|
|
|
138
|
-
##
|
|
134
|
+
## Dashboard
|
|
139
135
|
|
|
140
|
-
|
|
136
|
+
Open **http://127.0.0.1:4242** after starting.
|
|
141
137
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
},
|
|
153
|
-
}
|
|
154
|
-
```
|
|
138
|
+
| Tab | What's shown |
|
|
139
|
+
| --- | ------------ |
|
|
140
|
+
| **Overview** | Gateway health log, live activity feed, 24h stats, recent alerts |
|
|
141
|
+
| **Workspaces** | Per-agent SOUL.md, HEARTBEAT.md, MEMORY.md, USER.md previews |
|
|
142
|
+
| **Alerts** | Full alert history with severity, rule ID, fingerprint |
|
|
143
|
+
| **Sessions** | Active sessions with status, token counts, cost |
|
|
144
|
+
| **Live Monitor** | Real-time per-run timeline — steps, tool calls, LLM responses, exec |
|
|
145
|
+
| **Cron Jobs** | Scheduled job status, last/next run, consecutive errors |
|
|
146
|
+
| **Diagnostics** | Raw engine event log |
|
|
147
|
+
| **Delivery Queue** | Pending/failed alert delivery items |
|
|
155
148
|
|
|
156
|
-
|
|
149
|
+
Live Monitor sidebar shows sessions colour-coded by status:
|
|
150
|
+
- Green pulse = active (idle, waiting for input)
|
|
151
|
+
- Yellow pulse = thinking (LLM streaming in progress)
|
|
152
|
+
- Grey = no recent activity
|
|
157
153
|
|
|
158
|
-
|
|
159
|
-
1 agent error(s) on unknown in the last minute. Last: 401 Incorrect API key...
|
|
154
|
+
---
|
|
160
155
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
156
|
+
## REST API
|
|
157
|
+
|
|
158
|
+
All endpoints return JSON. CORS enabled.
|
|
159
|
+
|
|
160
|
+
| Method | Path | Description |
|
|
161
|
+
| ------ | ---- | ----------- |
|
|
162
|
+
| `GET` | `/api/state` | Full dashboard snapshot |
|
|
163
|
+
| `GET` | `/api/activity` | Unified activity log (actions + diagnostics merged) |
|
|
164
|
+
| `GET` | `/api/logs` | OpenClaw-style log format (`ts`, `level`, `subsystem`, `message`) |
|
|
165
|
+
| `GET` | `/api/actions` | Raw agent/tool/chat action rows |
|
|
166
|
+
| `GET` | `/api/heartbeats` | Gateway heartbeat history |
|
|
167
|
+
| `GET` | `/api/alerts` | Fired alert history |
|
|
168
|
+
| `GET` | `/api/diagnostics` | Engine diagnostic events |
|
|
169
|
+
| `GET` | `/api/engine` | Engine stats, uptime, gateway connection status |
|
|
170
|
+
| `POST` | `/api/test` | Fire a test alert |
|
|
171
|
+
| `GET` | `/events` | SSE stream (live push to dashboard) |
|
|
172
|
+
| `GET` | `/health` | `{ok, ts, sseClients, gatewayConnected}` |
|
|
173
|
+
|
|
174
|
+
Most list endpoints accept `?limit=N` (default 100, max 500) and `/api/activity`, `/api/actions`, `/api/logs` also accept `?session=KEY`.
|
|
175
|
+
|
|
176
|
+
### SSE events (`GET /events`)
|
|
177
|
+
|
|
178
|
+
| Event | Payload |
|
|
179
|
+
| ----- | ------- |
|
|
180
|
+
| `state` | Full dashboard snapshot — sent on connect and on file changes |
|
|
181
|
+
| `openalerts` | Alert fired: `{rule_id, severity, title, detail, ts, fingerprint}` |
|
|
182
|
+
| `action` | Agent step: `{id, runId, sessionKey, type, toolName, content, ts}` |
|
|
183
|
+
| `health` | Gateway heartbeat: `{queueDepth, activeSessions, sessions, ts}` |
|
|
184
|
+
| `diagnostic` | Engine event: `{event_type, ts, summary, session_key}` |
|
|
185
|
+
| `exec` | Shell command: `{type, runId, pid, command, output, exitCode, ts}` |
|
|
164
186
|
|
|
165
|
-
|
|
166
|
-
- **API key**: reads from the corresponding environment variable (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GROQ_API_KEY`, etc.)
|
|
167
|
-
- **Supported providers**: OpenAI, Anthropic, Groq, Together, DeepSeek (and any OpenAI-compatible API)
|
|
168
|
-
- **Graceful fallback**: if the LLM call fails or times out (10s), the original alert is sent unchanged
|
|
187
|
+
---
|
|
169
188
|
|
|
170
|
-
##
|
|
189
|
+
## Architecture
|
|
171
190
|
|
|
172
|
-
|
|
191
|
+
```
|
|
192
|
+
openalerts
|
|
193
|
+
├── cli.ts Entry point — wires everything together
|
|
194
|
+
├── config.ts Config loading + gateway token auto-detection
|
|
195
|
+
├── core/
|
|
196
|
+
│ ├── engine.ts Alert engine — ingests events, evaluates rules, fires alerts
|
|
197
|
+
│ ├── evaluator.ts Sliding-window + cooldown rule state
|
|
198
|
+
│ ├── rules.ts 10 alert rule definitions
|
|
199
|
+
│ └── types.ts Event and alert type definitions
|
|
200
|
+
├── watchers/
|
|
201
|
+
│ ├── gateway.ts WebSocket client for OpenClaw gateway
|
|
202
|
+
│ ├── gateway-adapter.ts Translates gateway frames → engine events + SSE payloads
|
|
203
|
+
│ └── files.ts node:fs watcher for OpenClaw workspace files
|
|
204
|
+
├── readers/
|
|
205
|
+
│ └── openclaw.ts Reads SOUL.md, cron jobs, sessions, delivery queue, config
|
|
206
|
+
├── channels/
|
|
207
|
+
│ ├── telegram.ts Telegram Bot API (no SDK, direct HTTP)
|
|
208
|
+
│ ├── webhook.ts HTTP POST to any webhook URL
|
|
209
|
+
│ └── console.ts Console fallback
|
|
210
|
+
├── server/
|
|
211
|
+
│ ├── index.ts HTTP server bootstrap
|
|
212
|
+
│ ├── routes.ts All REST + SSE route handlers
|
|
213
|
+
│ ├── sse.ts SSE manager (15s keepalive, broadcast)
|
|
214
|
+
│ └── dashboard.ts Embedded dashboard HTML (vanilla JS, zero framework)
|
|
215
|
+
└── db/
|
|
216
|
+
├── index.ts SQLite open + periodic prune
|
|
217
|
+
├── schema.ts 12 tables: sessions, actions, alerts, heartbeats, cron_jobs…
|
|
218
|
+
└── queries.ts Typed query functions including getActivityLog (UNION query)
|
|
219
|
+
```
|
|
173
220
|
|
|
174
|
-
|
|
175
|
-
| ------------ | ----------------------------------------------------- |
|
|
176
|
-
| `/health` | System health snapshot — uptime, active alerts, stats |
|
|
177
|
-
| `/alerts` | Recent alert history with severity and timestamps |
|
|
178
|
-
| `/dashboard` | Returns the dashboard URL |
|
|
221
|
+
**Storage**: SQLite at `~/.openalerts/openalerts.db` using Node 22's built-in `node:sqlite` — no native build step, no binaries to compile.
|
|
179
222
|
|
|
180
|
-
|
|
223
|
+
**Zero heavy dependencies**: only `ws` (WebSocket client). No Express, no ORM, no native modules.
|
|
181
224
|
|
|
182
|
-
|
|
183
|
-
- [ ] [OpenManus](https://github.com/FoundationAgents/OpenManus) adapter
|
|
225
|
+
---
|
|
184
226
|
|
|
185
|
-
##
|
|
227
|
+
## Data flow
|
|
186
228
|
|
|
187
|
-
```bash
|
|
188
|
-
npm install # install dependencies
|
|
189
|
-
npm run build # compile TypeScript
|
|
190
|
-
npm run typecheck # type-check without emitting
|
|
191
|
-
npm run clean # remove dist/
|
|
192
229
|
```
|
|
230
|
+
OpenClaw gateway (ws://127.0.0.1:18789)
|
|
231
|
+
│ health, agent, chat, exec events
|
|
232
|
+
▼
|
|
233
|
+
gateway-adapter.ts ──► engine.ingest() ──► rule evaluation ──► Telegram / webhook
|
|
234
|
+
│ │
|
|
235
|
+
│ SQLite DB JSONL event store
|
|
236
|
+
│ (actions, alerts, (warm-start rule
|
|
237
|
+
│ heartbeats, sessions) state on restart)
|
|
238
|
+
▼
|
|
239
|
+
SSE broadcast ──► dashboard live updates
|
|
240
|
+
|
|
241
|
+
OpenClaw workspace files (~/.openclaw/)
|
|
242
|
+
│ SOUL.md, HEARTBEAT.md, cron/jobs.json, sessions.json…
|
|
243
|
+
▼
|
|
244
|
+
openclaw.ts reader ──► SQLite (agent_info, cron_jobs, sessions)
|
|
245
|
+
│
|
|
246
|
+
node:fs watcher triggers re-reads on change
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
193
250
|
|
|
194
251
|
## License
|
|
195
252
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/channels/console.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEjE,qBAAa,cAAe,YAAW,YAAY;IACjD,QAAQ,CAAC,IAAI,aAAa;IAC1B,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;CAMjD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export class ConsoleChannel {
|
|
2
|
+
name = "console";
|
|
3
|
+
send(alert, formatted) {
|
|
4
|
+
const prefix = alert.severity === "critical" ? "🚨" :
|
|
5
|
+
alert.severity === "error" ? "❌" :
|
|
6
|
+
alert.severity === "warn" ? "⚠️" : "ℹ️";
|
|
7
|
+
console.log(`\n${prefix} ALERT [${alert.ruleId}]\n${formatted}\n`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=console.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console.js","sourceRoot":"","sources":["../../src/channels/console.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,cAAc;IAChB,IAAI,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,KAAiB,EAAE,SAAiB;QACvC,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACtC,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBAClC,KAAK,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,WAAW,KAAK,CAAC,MAAM,MAAM,SAAS,IAAI,CAAC,CAAC;IACrE,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram alert channel — uses Bot API directly (no OpenClaw dependency).
|
|
3
|
+
*/
|
|
4
|
+
import type { AlertChannel, AlertEvent } from "../core/types.js";
|
|
5
|
+
export declare class TelegramChannel implements AlertChannel {
|
|
6
|
+
readonly name = "telegram";
|
|
7
|
+
private token;
|
|
8
|
+
private chatId;
|
|
9
|
+
constructor(token: string, chatId: string);
|
|
10
|
+
send(_alert: AlertEvent, formatted: string): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=telegram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/channels/telegram.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEjE,qBAAa,eAAgB,YAAW,YAAY;IAClD,QAAQ,CAAC,IAAI,cAAc;IAC3B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAS;gBAEX,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAKnC,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAoBjE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export class TelegramChannel {
|
|
2
|
+
name = "telegram";
|
|
3
|
+
token;
|
|
4
|
+
chatId;
|
|
5
|
+
constructor(token, chatId) {
|
|
6
|
+
this.token = token;
|
|
7
|
+
this.chatId = chatId;
|
|
8
|
+
}
|
|
9
|
+
async send(_alert, formatted) {
|
|
10
|
+
const url = `https://api.telegram.org/bot${this.token}/sendMessage`;
|
|
11
|
+
const body = JSON.stringify({
|
|
12
|
+
chat_id: this.chatId,
|
|
13
|
+
text: formatted,
|
|
14
|
+
parse_mode: "HTML",
|
|
15
|
+
disable_web_page_preview: true,
|
|
16
|
+
});
|
|
17
|
+
const res = await fetch(url, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: { "Content-Type": "application/json" },
|
|
20
|
+
body,
|
|
21
|
+
});
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
const text = await res.text().catch(() => "");
|
|
24
|
+
throw new Error(`Telegram API ${res.status}: ${text.substring(0, 200)}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=telegram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/channels/telegram.ts"],"names":[],"mappings":"AAKA,MAAM,OAAO,eAAe;IACjB,IAAI,GAAG,UAAU,CAAC;IACnB,KAAK,CAAS;IACd,MAAM,CAAS;IAEvB,YAAY,KAAa,EAAE,MAAc;QACvC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAkB,EAAE,SAAiB;QAC9C,MAAM,GAAG,GAAG,+BAA+B,IAAI,CAAC,KAAK,cAAc,CAAC;QACpE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,OAAO,EAAE,IAAI,CAAC,MAAM;YACpB,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,MAAM;YAClB,wBAAwB,EAAE,IAAI;SAC/B,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI;SACL,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,gBAAgB,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AlertChannel, AlertEvent } from "../core/types.js";
|
|
2
|
+
export declare class WebhookChannel implements AlertChannel {
|
|
3
|
+
readonly name = "webhook";
|
|
4
|
+
private url;
|
|
5
|
+
constructor(url: string);
|
|
6
|
+
send(alert: AlertEvent, formatted: string): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=webhook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../src/channels/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEjE,qBAAa,cAAe,YAAW,YAAY;IACjD,QAAQ,CAAC,IAAI,aAAa;IAC1B,OAAO,CAAC,GAAG,CAAS;gBAER,GAAG,EAAE,MAAM;IAEjB,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAQhE"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export class WebhookChannel {
|
|
2
|
+
name = "webhook";
|
|
3
|
+
url;
|
|
4
|
+
constructor(url) { this.url = url; }
|
|
5
|
+
async send(alert, formatted) {
|
|
6
|
+
const res = await fetch(this.url, {
|
|
7
|
+
method: "POST",
|
|
8
|
+
headers: { "Content-Type": "application/json" },
|
|
9
|
+
body: JSON.stringify({ alert, formatted }),
|
|
10
|
+
});
|
|
11
|
+
if (!res.ok)
|
|
12
|
+
throw new Error(`Webhook ${res.status}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/channels/webhook.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,cAAc;IAChB,IAAI,GAAG,SAAS,CAAC;IAClB,GAAG,CAAS;IAEpB,YAAY,GAAW,IAAI,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;IAE5C,KAAK,CAAC,IAAI,CAAC,KAAiB,EAAE,SAAiB;QAC7C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;SAC3C,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,WAAW,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACxD,CAAC;CACF"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|