@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.
Files changed (104) hide show
  1. package/README.md +198 -141
  2. package/dist/channels/console.d.ts +6 -0
  3. package/dist/channels/console.d.ts.map +1 -0
  4. package/dist/channels/console.js +10 -0
  5. package/dist/channels/console.js.map +1 -0
  6. package/dist/channels/telegram.d.ts +12 -0
  7. package/dist/channels/telegram.d.ts.map +1 -0
  8. package/dist/channels/telegram.js +28 -0
  9. package/dist/channels/telegram.js.map +1 -0
  10. package/dist/channels/webhook.d.ts +8 -0
  11. package/dist/channels/webhook.d.ts.map +1 -0
  12. package/dist/channels/webhook.js +15 -0
  13. package/dist/channels/webhook.js.map +1 -0
  14. package/dist/cli.d.ts +3 -0
  15. package/dist/cli.d.ts.map +1 -0
  16. package/dist/cli.js +234 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/config.d.ts +51 -0
  19. package/dist/config.d.ts.map +1 -0
  20. package/dist/config.js +86 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/core/alert-channel.d.ts +3 -10
  23. package/dist/core/alert-channel.d.ts.map +1 -0
  24. package/dist/core/alert-channel.js +9 -30
  25. package/dist/core/alert-channel.js.map +1 -0
  26. package/dist/core/bounded-map.d.ts +1 -0
  27. package/dist/core/bounded-map.d.ts.map +1 -0
  28. package/dist/core/bounded-map.js +1 -0
  29. package/dist/core/bounded-map.js.map +1 -0
  30. package/dist/core/engine.d.ts +6 -18
  31. package/dist/core/engine.d.ts.map +1 -0
  32. package/dist/core/engine.js +48 -98
  33. package/dist/core/engine.js.map +1 -0
  34. package/dist/core/evaluator.d.ts +1 -0
  35. package/dist/core/evaluator.d.ts.map +1 -0
  36. package/dist/core/evaluator.js +1 -0
  37. package/dist/core/evaluator.js.map +1 -0
  38. package/dist/core/event-bus.d.ts +1 -0
  39. package/dist/core/event-bus.d.ts.map +1 -0
  40. package/dist/core/event-bus.js +1 -0
  41. package/dist/core/event-bus.js.map +1 -0
  42. package/dist/core/formatter.d.ts +1 -0
  43. package/dist/core/formatter.d.ts.map +1 -0
  44. package/dist/core/formatter.js +1 -0
  45. package/dist/core/formatter.js.map +1 -0
  46. package/dist/core/rules.d.ts +1 -0
  47. package/dist/core/rules.d.ts.map +1 -0
  48. package/dist/core/rules.js +1 -0
  49. package/dist/core/rules.js.map +1 -0
  50. package/dist/core/store.d.ts +6 -9
  51. package/dist/core/store.d.ts.map +1 -0
  52. package/dist/core/store.js +43 -96
  53. package/dist/core/store.js.map +1 -0
  54. package/dist/core/types.d.ts +1 -0
  55. package/dist/core/types.d.ts.map +1 -0
  56. package/dist/core/types.js +1 -0
  57. package/dist/core/types.js.map +1 -0
  58. package/dist/db/index.d.ts +6 -0
  59. package/dist/db/index.d.ts.map +1 -0
  60. package/dist/db/index.js +31 -0
  61. package/dist/db/index.js.map +1 -0
  62. package/dist/db/queries.d.ts +157 -0
  63. package/dist/db/queries.d.ts.map +1 -0
  64. package/dist/db/queries.js +227 -0
  65. package/dist/db/queries.js.map +1 -0
  66. package/dist/db/schema.d.ts +5 -0
  67. package/dist/db/schema.d.ts.map +1 -0
  68. package/dist/db/schema.js +177 -0
  69. package/dist/db/schema.js.map +1 -0
  70. package/dist/readers/openclaw.d.ts +11 -0
  71. package/dist/readers/openclaw.d.ts.map +1 -0
  72. package/dist/readers/openclaw.js +267 -0
  73. package/dist/readers/openclaw.js.map +1 -0
  74. package/dist/server/dashboard.d.ts +2 -0
  75. package/dist/server/dashboard.d.ts.map +1 -0
  76. package/dist/server/dashboard.js +765 -0
  77. package/dist/server/dashboard.js.map +1 -0
  78. package/dist/server/index.d.ts +10 -0
  79. package/dist/server/index.d.ts.map +1 -0
  80. package/dist/server/index.js +28 -0
  81. package/dist/server/index.js.map +1 -0
  82. package/dist/server/routes.d.ts +6 -0
  83. package/dist/server/routes.d.ts.map +1 -0
  84. package/dist/server/routes.js +146 -0
  85. package/dist/server/routes.js.map +1 -0
  86. package/dist/server/sse.d.ts +21 -0
  87. package/dist/server/sse.d.ts.map +1 -0
  88. package/dist/server/sse.js +53 -0
  89. package/dist/server/sse.js.map +1 -0
  90. package/dist/watchers/files.d.ts +19 -0
  91. package/dist/watchers/files.d.ts.map +1 -0
  92. package/dist/watchers/files.js +105 -0
  93. package/dist/watchers/files.js.map +1 -0
  94. package/dist/watchers/gateway-adapter.d.ts +18 -0
  95. package/dist/watchers/gateway-adapter.d.ts.map +1 -0
  96. package/dist/watchers/gateway-adapter.js +274 -0
  97. package/dist/watchers/gateway-adapter.js.map +1 -0
  98. package/dist/watchers/gateway.d.ts +27 -0
  99. package/dist/watchers/gateway.d.ts.map +1 -0
  100. package/dist/watchers/gateway.js +131 -0
  101. package/dist/watchers/gateway.js.map +1 -0
  102. package/package.json +21 -43
  103. package/LICENSE +0 -201
  104. package/openclaw.plugin.json +0 -87
package/README.md CHANGED
@@ -1,195 +1,252 @@
1
- <p align="center">
2
- <h1 align="center">OpenAlerts</h1>
3
- <p align="center">
4
- An alerting layer for agentic frameworks.
5
- </p>
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> &middot;
18
- <a href="#alert-rules">Alert Rules</a> &middot;
19
- <a href="#llm-enriched-alerts">LLM Enrichment</a> &middot;
20
- <a href="#dashboard">Dashboard</a> &middot;
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
- AI agents fail silently. LLM errors, stuck sessions, gateway outages — nobody knows until a user complains.
9
+ ## Install
27
10
 
28
- OpenAlerts watches your agent in real-time and alerts you the moment something goes wrong. A framework-agnostic core with adapter plugins — starting with [OpenClaw](https://github.com/openclaw/openclaw).
11
+ ```bash
12
+ npm install -g @steadwing/openalerts
13
+ ```
29
14
 
30
- ## Quickstart
15
+ > Requires **Node.js ≥ 22.5.0** (uses the built-in `node:sqlite` module — no native builds).
31
16
 
32
- > Currently supports OpenClaw. More framework adapters coming soon.
33
- > This project is under revamp for the next few hours
17
+ ---
34
18
 
35
- ### 1. Install
19
+ ## Quick start
36
20
 
37
21
  ```bash
38
- openclaw plugins install @steadwing/openalerts
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
- ### 2. Configure
32
+ Dashboard at **http://127.0.0.1:4242** — the gateway overlay dismisses automatically once connected.
42
33
 
43
- If you already have a channel paired with OpenClaw (e.g. Telegram via `openclaw pair`), **no config is needed** — OpenAlerts auto-detects where to send alerts.
34
+ ---
44
35
 
45
- Otherwise, set it explicitly in `openclaw.json`:
36
+ ## CLI
46
37
 
47
- ```jsonc
48
- {
49
- "plugins": {
50
- "entries": {
51
- "openalerts": {
52
- "enabled": true,
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
- **Auto-detection priority:** explicit config > static `allowFrom` in channel config > pairing store.
45
+ **Options for `start`:**
64
46
 
65
- ### 3. Restart & verify
47
+ | Flag | Default | Description |
48
+ | ---- | ------- | ----------- |
49
+ | `--port N` | `4242` | HTTP server port |
50
+ | `--config PATH` | `~/.openalerts/config.json` | Config file path |
66
51
 
67
- ```bash
68
- openclaw gateway stop && openclaw gateway run
69
- ```
52
+ ---
70
53
 
71
- Send `/health` to your bot. You should get a live status report back — zero LLM tokens consumed.
54
+ ## Configuration
72
55
 
73
- That's it. OpenAlerts is now watching your agent.
56
+ `~/.openalerts/config.json` (created by `openalerts init`):
74
57
 
75
- ## Demo
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
- https://github.com/user-attachments/assets/0b6ed26e-1eb0-47b2-ae4f-947516f024b4
80
+ **Gateway token** is auto-detected from `gateway.auth.token` in `~/.openclaw/openclaw.json` — no manual copy needed.
78
81
 
79
- ## Dashboard
82
+ **Channels**: configure at least one. Falls back to `console` if none are set.
80
83
 
81
- A real-time web dashboard is embedded in the gateway at:
84
+ ---
82
85
 
83
- ```
84
- http://127.0.0.1:18789/openalerts
85
- ```
86
+ ## What it monitors
86
87
 
87
- - **Activity** Step-by-step execution timeline with tool calls, LLM usage, costs
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
- ## Alert Rules
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
- Ten rules run against every event in real-time. All thresholds and cooldowns are configurable.
101
+ ---
97
102
 
98
- | Rule | Watches for | Severity | Threshold (default) |
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
- Every rule also accepts:
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
- - **`enabled`** `false` to disable the rule (default: `true`)
112
- - **`cooldownMinutes`** minutes before the same rule can fire again (default: `15`)
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
- To tune rules, add a `rules` object in your plugin config:
120
+ Override a rule threshold in config:
115
121
 
116
- ```jsonc
122
+ ```json
117
123
  {
118
- "plugins": {
119
- "entries": {
120
- "openalerts": {
121
- "config": {
122
- "cooldownMinutes": 10,
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
- Set `"quiet": true` at the config level for log-only mode (no messages sent).
132
+ ---
137
133
 
138
- ## LLM-Enriched Alerts
134
+ ## Dashboard
139
135
 
140
- OpenAlerts can optionally use your configured LLM to enrich alerts with a human-friendly summary and an actionable suggestion. **This feature is disabled by default** — opt in by setting `"llmEnriched": true` in your plugin config:
136
+ Open **http://127.0.0.1:4242** after starting.
141
137
 
142
- ```jsonc
143
- {
144
- "plugins": {
145
- "entries": {
146
- "openalerts": {
147
- "config": {
148
- "llmEnriched": true,
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
- When enabled, alerts include an LLM-generated summary and action:
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
- Summary: Your OpenAI API key is invalid or expired — the agent cannot make LLM calls.
162
- Action: Update your API key in ~/.openclaw/.env with a valid key from platform.openai.com/api-keys
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
- - **Model**: reads from `agents.defaults.model.primary` in your `openclaw.json` (e.g. `"openai/gpt-4o-mini"`)
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
- ## Commands
189
+ ## Architecture
171
190
 
172
- Zero-token chat commands available in any connected channel:
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
- | Command | What it does |
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
- ## Roadmap
223
+ **Zero heavy dependencies**: only `ws` (WebSocket client). No Express, no ORM, no native modules.
181
224
 
182
- - [ ] [nanobot](https://github.com/HKUDS/nanobot) adapter
183
- - [ ] [OpenManus](https://github.com/FoundationAgents/OpenManus) adapter
225
+ ---
184
226
 
185
- ## Development
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,6 @@
1
+ import type { AlertChannel, AlertEvent } from "../core/types.js";
2
+ export declare class ConsoleChannel implements AlertChannel {
3
+ readonly name = "console";
4
+ send(alert: AlertEvent, formatted: string): void;
5
+ }
6
+ //# sourceMappingURL=console.d.ts.map
@@ -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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}