@kernel.chat/kbot 3.30.1 → 3.31.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.
- package/dist/briefing.d.ts +2 -0
- package/dist/briefing.d.ts.map +1 -0
- package/dist/briefing.js +218 -0
- package/dist/briefing.js.map +1 -0
- package/dist/cli.js +85 -0
- package/dist/cli.js.map +1 -1
- package/dist/daemon.d.ts +26 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +351 -0
- package/dist/daemon.js.map +1 -0
- package/dist/notifications.d.ts +13 -0
- package/dist/notifications.d.ts.map +1 -0
- package/dist/notifications.js +133 -0
- package/dist/notifications.js.map +1 -0
- package/package.json +1 -1
package/dist/daemon.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface DaemonState {
|
|
2
|
+
pid: number;
|
|
3
|
+
startedAt: string;
|
|
4
|
+
lastHeartbeat: string;
|
|
5
|
+
cycles: number;
|
|
6
|
+
subsystems: Record<string, {
|
|
7
|
+
lastRun: string;
|
|
8
|
+
nextRun: string;
|
|
9
|
+
status: 'ok' | 'error' | 'running' | 'idle';
|
|
10
|
+
lastError?: string;
|
|
11
|
+
runCount: number;
|
|
12
|
+
}>;
|
|
13
|
+
notifications: number;
|
|
14
|
+
alerts: string[];
|
|
15
|
+
}
|
|
16
|
+
/** Start the daemon — runs all subsystems on their intervals */
|
|
17
|
+
export declare function startDaemon(): Promise<void>;
|
|
18
|
+
/** Stop the daemon */
|
|
19
|
+
export declare function stopDaemon(): boolean;
|
|
20
|
+
/** Get daemon status */
|
|
21
|
+
export declare function getDaemonStatus(): DaemonState & {
|
|
22
|
+
running: boolean;
|
|
23
|
+
};
|
|
24
|
+
/** Get recent daemon log lines */
|
|
25
|
+
export declare function getDaemonLog(lines?: number): string[];
|
|
26
|
+
//# sourceMappingURL=daemon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAmCA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QACzB,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,EAAE,IAAI,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;QAC3C,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAC,CAAA;IACF,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAwND,gEAAgE;AAChE,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAwFjD;AAED,sBAAsB;AACtB,wBAAgB,UAAU,IAAI,OAAO,CAYpC;AAED,wBAAwB;AACxB,wBAAgB,eAAe,IAAI,WAAW,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAuBpE;AAED,kCAAkC;AAClC,wBAAgB,YAAY,CAAC,KAAK,SAAK,GAAG,MAAM,EAAE,CAGjD"}
|
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
// kbot Daemon — The Unified Background Intelligence
|
|
2
|
+
//
|
|
3
|
+
// One process. Always on. Orchestrates everything kbot does when you're not talking to it.
|
|
4
|
+
//
|
|
5
|
+
// Subsystems (each runs on its own interval):
|
|
6
|
+
// 1. MARKET WATCH — check price alerts, scan sentiment (every 15 min)
|
|
7
|
+
// 2. SECURITY PATROL — memory integrity, dep audit on active projects (every 1 hour)
|
|
8
|
+
// 3. SYNTHESIS — consolidate patterns, evolve, cross-pollinate (every 2 hours)
|
|
9
|
+
// 4. DISCOVERY — scan HN/GitHub/Reddit for relevant conversations (every 1 hour)
|
|
10
|
+
// 5. HEALTH CHECK — autopoietic viability, provider health (every 30 min)
|
|
11
|
+
// 6. EPISODIC DIGEST — consolidate today's episodes into daily summary (every 6 hours)
|
|
12
|
+
//
|
|
13
|
+
// Run: kbot daemon start
|
|
14
|
+
// Stop: kbot daemon stop (writes PID file for management)
|
|
15
|
+
// Status: kbot daemon status
|
|
16
|
+
//
|
|
17
|
+
// The daemon is kbot's heartbeat. It's what makes kbot alive between sessions.
|
|
18
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync, mkdirSync } from 'node:fs';
|
|
19
|
+
import { join } from 'node:path';
|
|
20
|
+
import { homedir } from 'node:os';
|
|
21
|
+
import { notify } from './notifications.js';
|
|
22
|
+
const KBOT_DIR = join(homedir(), '.kbot');
|
|
23
|
+
const DAEMON_DIR = join(KBOT_DIR, 'daemon');
|
|
24
|
+
const PID_FILE = join(DAEMON_DIR, 'daemon.pid');
|
|
25
|
+
const STATE_FILE = join(DAEMON_DIR, 'state.json');
|
|
26
|
+
const LOG_FILE = join(DAEMON_DIR, 'daemon.log');
|
|
27
|
+
function ensureDir() {
|
|
28
|
+
if (!existsSync(DAEMON_DIR))
|
|
29
|
+
mkdirSync(DAEMON_DIR, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
function loadState() {
|
|
32
|
+
if (!existsSync(STATE_FILE))
|
|
33
|
+
return null;
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(readFileSync(STATE_FILE, 'utf-8'));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function saveState(state) {
|
|
42
|
+
ensureDir();
|
|
43
|
+
writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
44
|
+
}
|
|
45
|
+
function log(msg) {
|
|
46
|
+
ensureDir();
|
|
47
|
+
const line = `${new Date().toISOString()} ${msg}\n`;
|
|
48
|
+
try {
|
|
49
|
+
const { appendFileSync } = require('node:fs');
|
|
50
|
+
appendFileSync(LOG_FILE, line);
|
|
51
|
+
}
|
|
52
|
+
catch { /* best effort */ }
|
|
53
|
+
if (process.env.KBOT_DAEMON_VERBOSE)
|
|
54
|
+
console.log(line.trim());
|
|
55
|
+
}
|
|
56
|
+
// ── Subsystem Runners ──
|
|
57
|
+
async function runMarketWatch(state) {
|
|
58
|
+
const sub = state.subsystems['market-watch'];
|
|
59
|
+
sub.status = 'running';
|
|
60
|
+
sub.lastRun = new Date().toISOString();
|
|
61
|
+
saveState(state);
|
|
62
|
+
try {
|
|
63
|
+
// Check price alerts
|
|
64
|
+
const alertPath = join(KBOT_DIR, 'price-alerts.json');
|
|
65
|
+
if (existsSync(alertPath)) {
|
|
66
|
+
const alerts = JSON.parse(readFileSync(alertPath, 'utf-8'));
|
|
67
|
+
if (alerts.length > 0) {
|
|
68
|
+
const symbolMap = {
|
|
69
|
+
btc: 'bitcoin', eth: 'ethereum', sol: 'solana', bnb: 'binancecoin',
|
|
70
|
+
ada: 'cardano', doge: 'dogecoin', xrp: 'ripple',
|
|
71
|
+
};
|
|
72
|
+
const symbols = [...new Set(alerts.map(a => a.symbol))];
|
|
73
|
+
const ids = symbols.map(s => symbolMap[s] || s).join(',');
|
|
74
|
+
const res = await fetch(`https://api.coingecko.com/api/v3/simple/price?ids=${ids}&vs_currencies=usd`, { signal: AbortSignal.timeout(10_000) });
|
|
75
|
+
const prices = await res.json();
|
|
76
|
+
const triggered = [];
|
|
77
|
+
const remaining = alerts.filter(alert => {
|
|
78
|
+
const cgId = symbolMap[alert.symbol] || alert.symbol;
|
|
79
|
+
const price = prices[cgId]?.usd;
|
|
80
|
+
if (!price)
|
|
81
|
+
return true; // keep if can't check
|
|
82
|
+
if (alert.above && price >= alert.above) {
|
|
83
|
+
const msg = `${alert.symbol.toUpperCase()} hit $${price.toFixed(2)} (above $${alert.above})`;
|
|
84
|
+
triggered.push(msg);
|
|
85
|
+
return false; // remove triggered alert
|
|
86
|
+
}
|
|
87
|
+
if (alert.below && price <= alert.below) {
|
|
88
|
+
const msg = `${alert.symbol.toUpperCase()} hit $${price.toFixed(2)} (below $${alert.below})`;
|
|
89
|
+
triggered.push(msg);
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
return true;
|
|
93
|
+
});
|
|
94
|
+
if (triggered.length > 0) {
|
|
95
|
+
writeFileSync(alertPath, JSON.stringify(remaining, null, 2));
|
|
96
|
+
for (const msg of triggered) {
|
|
97
|
+
log(`ALERT: ${msg}`);
|
|
98
|
+
await notify({ title: 'kbot Price Alert', body: msg, channel: 'system' });
|
|
99
|
+
state.notifications++;
|
|
100
|
+
state.alerts.push(msg);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
sub.status = 'ok';
|
|
106
|
+
sub.runCount++;
|
|
107
|
+
log('market-watch: completed');
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
sub.status = 'error';
|
|
111
|
+
sub.lastError = err instanceof Error ? err.message : String(err);
|
|
112
|
+
log(`market-watch: error — ${sub.lastError}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async function runSecurityPatrol(state) {
|
|
116
|
+
const sub = state.subsystems['security-patrol'];
|
|
117
|
+
sub.status = 'running';
|
|
118
|
+
sub.lastRun = new Date().toISOString();
|
|
119
|
+
saveState(state);
|
|
120
|
+
try {
|
|
121
|
+
// Memory integrity check
|
|
122
|
+
const { verifyMemoryIntegrity } = await import('./self-defense.js');
|
|
123
|
+
const integrity = verifyMemoryIntegrity();
|
|
124
|
+
const tampered = integrity.filter(m => m.status === 'tampered');
|
|
125
|
+
if (tampered.length > 0) {
|
|
126
|
+
const msg = `SECURITY: ${tampered.length} memory file(s) tampered — ${tampered.map(t => t.file).join(', ')}`;
|
|
127
|
+
log(msg);
|
|
128
|
+
await notify({ title: 'kbot Security Alert', body: msg, channel: 'system', urgency: 'critical' });
|
|
129
|
+
state.notifications++;
|
|
130
|
+
state.alerts.push(msg);
|
|
131
|
+
// Log incident
|
|
132
|
+
const { logIncident } = await import('./self-defense.js');
|
|
133
|
+
logIncident('memory-tampering', 'critical', msg, 'logged');
|
|
134
|
+
}
|
|
135
|
+
sub.status = 'ok';
|
|
136
|
+
sub.runCount++;
|
|
137
|
+
log('security-patrol: completed');
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
sub.status = 'error';
|
|
141
|
+
sub.lastError = err instanceof Error ? err.message : String(err);
|
|
142
|
+
log(`security-patrol: error — ${sub.lastError}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async function runSynthesis(state) {
|
|
146
|
+
const sub = state.subsystems['synthesis'];
|
|
147
|
+
sub.status = 'running';
|
|
148
|
+
sub.lastRun = new Date().toISOString();
|
|
149
|
+
saveState(state);
|
|
150
|
+
try {
|
|
151
|
+
const { maybeSynthesize } = await import('./memory-synthesis.js');
|
|
152
|
+
await maybeSynthesize();
|
|
153
|
+
// Sign memory files after synthesis (integrity baseline)
|
|
154
|
+
const { signMemoryFiles } = await import('./self-defense.js');
|
|
155
|
+
signMemoryFiles();
|
|
156
|
+
sub.status = 'ok';
|
|
157
|
+
sub.runCount++;
|
|
158
|
+
log('synthesis: completed');
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
sub.status = 'error';
|
|
162
|
+
sub.lastError = err instanceof Error ? err.message : String(err);
|
|
163
|
+
log(`synthesis: error — ${sub.lastError}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async function runHealthCheck(state) {
|
|
167
|
+
const sub = state.subsystems['health-check'];
|
|
168
|
+
sub.status = 'running';
|
|
169
|
+
sub.lastRun = new Date().toISOString();
|
|
170
|
+
saveState(state);
|
|
171
|
+
try {
|
|
172
|
+
// Check provider health
|
|
173
|
+
const { getProviderHealth } = await import('./provider-fallback.js');
|
|
174
|
+
const health = getProviderHealth();
|
|
175
|
+
const unhealthy = Object.entries(health).filter(([, h]) => !h.healthy);
|
|
176
|
+
if (unhealthy.length > 0) {
|
|
177
|
+
log(`health-check: ${unhealthy.length} unhealthy provider(s): ${unhealthy.map(([p]) => p).join(', ')}`);
|
|
178
|
+
}
|
|
179
|
+
sub.status = 'ok';
|
|
180
|
+
sub.runCount++;
|
|
181
|
+
log('health-check: completed');
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
sub.status = 'error';
|
|
185
|
+
sub.lastError = err instanceof Error ? err.message : String(err);
|
|
186
|
+
log(`health-check: error — ${sub.lastError}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async function runEpisodicDigest(state) {
|
|
190
|
+
const sub = state.subsystems['episodic-digest'];
|
|
191
|
+
sub.status = 'running';
|
|
192
|
+
sub.lastRun = new Date().toISOString();
|
|
193
|
+
saveState(state);
|
|
194
|
+
try {
|
|
195
|
+
const { getEpisodeStats } = await import('./episodic-memory.js');
|
|
196
|
+
const stats = getEpisodeStats();
|
|
197
|
+
log(`episodic-digest: ${stats.total} episodes, ${stats.totalMinutes}min total, ${stats.totalMessages} messages`);
|
|
198
|
+
sub.status = 'ok';
|
|
199
|
+
sub.runCount++;
|
|
200
|
+
log('episodic-digest: completed');
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
sub.status = 'error';
|
|
204
|
+
sub.lastError = err instanceof Error ? err.message : String(err);
|
|
205
|
+
log(`episodic-digest: error — ${sub.lastError}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// ── Daemon Lifecycle ──
|
|
209
|
+
const INTERVALS = {
|
|
210
|
+
'market-watch': 15 * 60 * 1000, // 15 minutes
|
|
211
|
+
'health-check': 30 * 60 * 1000, // 30 minutes
|
|
212
|
+
'security-patrol': 60 * 60 * 1000, // 1 hour
|
|
213
|
+
'synthesis': 2 * 60 * 60 * 1000, // 2 hours
|
|
214
|
+
'episodic-digest': 6 * 60 * 60 * 1000, // 6 hours
|
|
215
|
+
};
|
|
216
|
+
const RUNNERS = {
|
|
217
|
+
'market-watch': runMarketWatch,
|
|
218
|
+
'security-patrol': runSecurityPatrol,
|
|
219
|
+
'synthesis': runSynthesis,
|
|
220
|
+
'health-check': runHealthCheck,
|
|
221
|
+
'episodic-digest': runEpisodicDigest,
|
|
222
|
+
};
|
|
223
|
+
/** Start the daemon — runs all subsystems on their intervals */
|
|
224
|
+
export async function startDaemon() {
|
|
225
|
+
ensureDir();
|
|
226
|
+
// Check if already running
|
|
227
|
+
if (existsSync(PID_FILE)) {
|
|
228
|
+
const existingPid = parseInt(readFileSync(PID_FILE, 'utf-8').trim(), 10);
|
|
229
|
+
try {
|
|
230
|
+
process.kill(existingPid, 0); // Check if process exists
|
|
231
|
+
console.error(`Daemon already running (PID ${existingPid}). Use 'kbot daemon stop' first.`);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// Process doesn't exist, clean up stale PID
|
|
236
|
+
unlinkSync(PID_FILE);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Write PID
|
|
240
|
+
writeFileSync(PID_FILE, String(process.pid));
|
|
241
|
+
const state = {
|
|
242
|
+
pid: process.pid,
|
|
243
|
+
startedAt: new Date().toISOString(),
|
|
244
|
+
lastHeartbeat: new Date().toISOString(),
|
|
245
|
+
cycles: 0,
|
|
246
|
+
subsystems: {},
|
|
247
|
+
notifications: 0,
|
|
248
|
+
alerts: [],
|
|
249
|
+
};
|
|
250
|
+
// Initialize subsystems
|
|
251
|
+
for (const [name, interval] of Object.entries(INTERVALS)) {
|
|
252
|
+
const now = new Date();
|
|
253
|
+
state.subsystems[name] = {
|
|
254
|
+
lastRun: '',
|
|
255
|
+
nextRun: new Date(now.getTime() + 5000).toISOString(), // First run in 5 seconds
|
|
256
|
+
status: 'idle',
|
|
257
|
+
runCount: 0,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
saveState(state);
|
|
261
|
+
log('daemon: started');
|
|
262
|
+
await notify({ title: 'kbot Daemon', body: 'Background intelligence active.', channel: 'system' });
|
|
263
|
+
// Main loop
|
|
264
|
+
const tick = async () => {
|
|
265
|
+
state.lastHeartbeat = new Date().toISOString();
|
|
266
|
+
state.cycles++;
|
|
267
|
+
const now = Date.now();
|
|
268
|
+
for (const [name, interval] of Object.entries(INTERVALS)) {
|
|
269
|
+
const sub = state.subsystems[name];
|
|
270
|
+
const nextRun = new Date(sub.nextRun).getTime();
|
|
271
|
+
if (now >= nextRun && sub.status !== 'running') {
|
|
272
|
+
const runner = RUNNERS[name];
|
|
273
|
+
if (runner) {
|
|
274
|
+
try {
|
|
275
|
+
await runner(state);
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
log(`daemon: ${name} crashed — ${err}`);
|
|
279
|
+
}
|
|
280
|
+
sub.nextRun = new Date(now + interval).toISOString();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
saveState(state);
|
|
285
|
+
};
|
|
286
|
+
// Run immediately then every 60 seconds
|
|
287
|
+
await tick();
|
|
288
|
+
setInterval(tick, 60_000);
|
|
289
|
+
// Handle shutdown
|
|
290
|
+
const cleanup = () => {
|
|
291
|
+
log('daemon: shutting down');
|
|
292
|
+
if (existsSync(PID_FILE))
|
|
293
|
+
unlinkSync(PID_FILE);
|
|
294
|
+
saveState(state);
|
|
295
|
+
process.exit(0);
|
|
296
|
+
};
|
|
297
|
+
process.on('SIGTERM', cleanup);
|
|
298
|
+
process.on('SIGINT', cleanup);
|
|
299
|
+
// Keep alive
|
|
300
|
+
log(`daemon: running (PID ${process.pid}), ${Object.keys(INTERVALS).length} subsystems`);
|
|
301
|
+
}
|
|
302
|
+
/** Stop the daemon */
|
|
303
|
+
export function stopDaemon() {
|
|
304
|
+
if (!existsSync(PID_FILE))
|
|
305
|
+
return false;
|
|
306
|
+
const pid = parseInt(readFileSync(PID_FILE, 'utf-8').trim(), 10);
|
|
307
|
+
try {
|
|
308
|
+
process.kill(pid, 'SIGTERM');
|
|
309
|
+
unlinkSync(PID_FILE);
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
// Process already dead
|
|
314
|
+
unlinkSync(PID_FILE);
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/** Get daemon status */
|
|
319
|
+
export function getDaemonStatus() {
|
|
320
|
+
const state = loadState();
|
|
321
|
+
if (!state) {
|
|
322
|
+
return {
|
|
323
|
+
running: false,
|
|
324
|
+
pid: 0,
|
|
325
|
+
startedAt: '',
|
|
326
|
+
lastHeartbeat: '',
|
|
327
|
+
cycles: 0,
|
|
328
|
+
subsystems: {},
|
|
329
|
+
notifications: 0,
|
|
330
|
+
alerts: [],
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
// Check if PID is alive
|
|
334
|
+
let running = false;
|
|
335
|
+
if (existsSync(PID_FILE)) {
|
|
336
|
+
const pid = parseInt(readFileSync(PID_FILE, 'utf-8').trim(), 10);
|
|
337
|
+
try {
|
|
338
|
+
process.kill(pid, 0);
|
|
339
|
+
running = true;
|
|
340
|
+
}
|
|
341
|
+
catch { /* dead */ }
|
|
342
|
+
}
|
|
343
|
+
return { ...state, running };
|
|
344
|
+
}
|
|
345
|
+
/** Get recent daemon log lines */
|
|
346
|
+
export function getDaemonLog(lines = 30) {
|
|
347
|
+
if (!existsSync(LOG_FILE))
|
|
348
|
+
return [];
|
|
349
|
+
return readFileSync(LOG_FILE, 'utf-8').split('\n').filter(Boolean).slice(-lines);
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,EAAE;AACF,2FAA2F;AAC3F,EAAE;AACF,8CAA8C;AAC9C,2EAA2E;AAC3E,uFAAuF;AACvF,wFAAwF;AACxF,0FAA0F;AAC1F,gFAAgF;AAChF,0FAA0F;AAC1F,EAAE;AACF,yBAAyB;AACzB,0DAA0D;AAC1D,6BAA6B;AAC7B,EAAE;AACF,+EAA+E;AAE/E,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACxF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,MAAM,EAA4B,MAAM,oBAAoB,CAAA;AAErE,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAA;AACzC,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;AAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA;AAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA;AACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA;AAE/C,SAAS,SAAS;IAChB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;AACzE,CAAC;AAoBD,SAAS,SAAS;IAChB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAA;IACxC,IAAI,CAAC;QAAC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAA;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAA;IAAC,CAAC;AACpF,CAAC;AAED,SAAS,SAAS,CAAC,KAAkB;IACnC,SAAS,EAAE,CAAA;IACX,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;AAC3D,CAAC;AAED,SAAS,GAAG,CAAC,GAAW;IACtB,SAAS,EAAE,CAAA;IACX,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,GAAG,IAAI,CAAA;IACnD,IAAI,CAAC;QACH,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;QAC7C,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IAChC,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC7B,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB;QAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;AAC/D,CAAC;AAED,0BAA0B;AAE1B,KAAK,UAAU,cAAc,CAAC,KAAkB;IAC9C,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,CAAA;IAC5C,GAAG,CAAC,MAAM,GAAG,SAAS,CAAA;IACtB,GAAG,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACtC,SAAS,CAAC,KAAK,CAAC,CAAA;IAEhB,IAAI,CAAC;QACH,qBAAqB;QACrB,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAA;QACrD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAExD,CAAA;YAEF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,SAAS,GAA2B;oBACxC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,aAAa;oBAClE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ;iBAChD,CAAA;gBACD,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;gBACvD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;gBAEzD,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,qDAAqD,GAAG,oBAAoB,EAC5E,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CACxC,CAAA;gBACD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAqC,CAAA;gBAElE,MAAM,SAAS,GAAa,EAAE,CAAA;gBAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;oBACtC,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAA;oBACpD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,CAAA;oBAC/B,IAAI,CAAC,KAAK;wBAAE,OAAO,IAAI,CAAA,CAAC,sBAAsB;oBAE9C,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;wBACxC,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,KAAK,GAAG,CAAA;wBAC5F,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;wBACnB,OAAO,KAAK,CAAA,CAAC,yBAAyB;oBACxC,CAAC;oBACD,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;wBACxC,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,KAAK,GAAG,CAAA;wBAC5F,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;wBACnB,OAAO,KAAK,CAAA;oBACd,CAAC;oBACD,OAAO,IAAI,CAAA;gBACb,CAAC,CAAC,CAAA;gBAEF,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACzB,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;oBAC5D,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;wBAC5B,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC,CAAA;wBACpB,MAAM,MAAM,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAA;wBACzE,KAAK,CAAC,aAAa,EAAE,CAAA;wBACrB,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;oBACxB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,GAAG,CAAC,MAAM,GAAG,IAAI,CAAA;QACjB,GAAG,CAAC,QAAQ,EAAE,CAAA;QACd,GAAG,CAAC,yBAAyB,CAAC,CAAA;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,GAAG,OAAO,CAAA;QACpB,GAAG,CAAC,SAAS,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAChE,GAAG,CAAC,yBAAyB,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;IAC/C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,KAAkB;IACjD,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAA;IAC/C,GAAG,CAAC,MAAM,GAAG,SAAS,CAAA;IACtB,GAAG,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACtC,SAAS,CAAC,KAAK,CAAC,CAAA;IAEhB,IAAI,CAAC;QACH,yBAAyB;QACzB,MAAM,EAAE,qBAAqB,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAA;QACnE,MAAM,SAAS,GAAG,qBAAqB,EAAE,CAAA;QACzC,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAA;QAE/D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,aAAa,QAAQ,CAAC,MAAM,8BAA8B,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;YAC5G,GAAG,CAAC,GAAG,CAAC,CAAA;YACR,MAAM,MAAM,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAA;YACjG,KAAK,CAAC,aAAa,EAAE,CAAA;YACrB,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAEtB,eAAe;YACf,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAA;YACzD,WAAW,CAAC,kBAAkB,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAA;QAC5D,CAAC;QAED,GAAG,CAAC,MAAM,GAAG,IAAI,CAAA;QACjB,GAAG,CAAC,QAAQ,EAAE,CAAA;QACd,GAAG,CAAC,4BAA4B,CAAC,CAAA;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,GAAG,OAAO,CAAA;QACpB,GAAG,CAAC,SAAS,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAChE,GAAG,CAAC,4BAA4B,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;IAClD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,KAAkB;IAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;IACzC,GAAG,CAAC,MAAM,GAAG,SAAS,CAAA;IACtB,GAAG,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACtC,SAAS,CAAC,KAAK,CAAC,CAAA;IAEhB,IAAI,CAAC;QACH,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAA;QACjE,MAAM,eAAe,EAAE,CAAA;QAEvB,yDAAyD;QACzD,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAA;QAC7D,eAAe,EAAE,CAAA;QAEjB,GAAG,CAAC,MAAM,GAAG,IAAI,CAAA;QACjB,GAAG,CAAC,QAAQ,EAAE,CAAA;QACd,GAAG,CAAC,sBAAsB,CAAC,CAAA;IAC7B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,GAAG,OAAO,CAAA;QACpB,GAAG,CAAC,SAAS,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAChE,GAAG,CAAC,sBAAsB,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;IAC5C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,KAAkB;IAC9C,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,CAAA;IAC5C,GAAG,CAAC,MAAM,GAAG,SAAS,CAAA;IACtB,GAAG,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACtC,SAAS,CAAC,KAAK,CAAC,CAAA;IAEhB,IAAI,CAAC;QACH,wBAAwB;QACxB,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAA;QACpE,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAA;QAClC,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAE,CAAS,CAAC,OAAO,CAAC,CAAA;QAE/E,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,GAAG,CAAC,iBAAiB,SAAS,CAAC,MAAM,2BAA2B,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACzG,CAAC;QAED,GAAG,CAAC,MAAM,GAAG,IAAI,CAAA;QACjB,GAAG,CAAC,QAAQ,EAAE,CAAA;QACd,GAAG,CAAC,yBAAyB,CAAC,CAAA;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,GAAG,OAAO,CAAA;QACpB,GAAG,CAAC,SAAS,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAChE,GAAG,CAAC,yBAAyB,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;IAC/C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,KAAkB;IACjD,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAA;IAC/C,GAAG,CAAC,MAAM,GAAG,SAAS,CAAA;IACtB,GAAG,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACtC,SAAS,CAAC,KAAK,CAAC,CAAA;IAEhB,IAAI,CAAC;QACH,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAA;QAChE,MAAM,KAAK,GAAG,eAAe,EAAE,CAAA;QAC/B,GAAG,CAAC,oBAAoB,KAAK,CAAC,KAAK,cAAc,KAAK,CAAC,YAAY,cAAc,KAAK,CAAC,aAAa,WAAW,CAAC,CAAA;QAEhH,GAAG,CAAC,MAAM,GAAG,IAAI,CAAA;QACjB,GAAG,CAAC,QAAQ,EAAE,CAAA;QACd,GAAG,CAAC,4BAA4B,CAAC,CAAA;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,GAAG,OAAO,CAAA;QACpB,GAAG,CAAC,SAAS,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAChE,GAAG,CAAC,4BAA4B,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;IAClD,CAAC;AACH,CAAC;AAED,yBAAyB;AAEzB,MAAM,SAAS,GAA2B;IACxC,cAAc,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAO,aAAa;IAClD,cAAc,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAO,aAAa;IAClD,iBAAiB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAI,SAAS;IAC9C,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAM,UAAU;IAC/C,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,UAAU;CAClD,CAAA;AAED,MAAM,OAAO,GAA0D;IACrE,cAAc,EAAE,cAAc;IAC9B,iBAAiB,EAAE,iBAAiB;IACpC,WAAW,EAAE,YAAY;IACzB,cAAc,EAAE,cAAc;IAC9B,iBAAiB,EAAE,iBAAiB;CACrC,CAAA;AAED,gEAAgE;AAChE,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,SAAS,EAAE,CAAA;IAEX,2BAA2B;IAC3B,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;QACxE,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA,CAAC,0BAA0B;YACvD,OAAO,CAAC,KAAK,CAAC,+BAA+B,WAAW,kCAAkC,CAAC,CAAA;YAC3F,OAAM;QACR,CAAC;QAAC,MAAM,CAAC;YACP,4CAA4C;YAC5C,UAAU,CAAC,QAAQ,CAAC,CAAA;QACtB,CAAC;IACH,CAAC;IAED,YAAY;IACZ,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;IAE5C,MAAM,KAAK,GAAgB;QACzB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,aAAa,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACvC,MAAM,EAAE,CAAC;QACT,UAAU,EAAE,EAAE;QACd,aAAa,EAAE,CAAC;QAChB,MAAM,EAAE,EAAE;KACX,CAAA;IAED,wBAAwB;IACxB,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACzD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;QACtB,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG;YACvB,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,yBAAyB;YAChF,MAAM,EAAE,MAAM;YACd,QAAQ,EAAE,CAAC;SACZ,CAAA;IACH,CAAC;IAED,SAAS,CAAC,KAAK,CAAC,CAAA;IAChB,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAEtB,MAAM,MAAM,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,iCAAiC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAA;IAElG,YAAY;IACZ,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;QACtB,KAAK,CAAC,aAAa,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QAC9C,KAAK,CAAC,MAAM,EAAE,CAAA;QACd,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAEtB,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACzD,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YAClC,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAA;YAE/C,IAAI,GAAG,IAAI,OAAO,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;gBAC5B,IAAI,MAAM,EAAE,CAAC;oBACX,IAAI,CAAC;wBACH,MAAM,MAAM,CAAC,KAAK,CAAC,CAAA;oBACrB,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,GAAG,CAAC,WAAW,IAAI,cAAc,GAAG,EAAE,CAAC,CAAA;oBACzC,CAAC;oBACD,GAAG,CAAC,OAAO,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAA;gBACtD,CAAC;YACH,CAAC;QACH,CAAC;QAED,SAAS,CAAC,KAAK,CAAC,CAAA;IAClB,CAAC,CAAA;IAED,wCAAwC;IACxC,MAAM,IAAI,EAAE,CAAA;IACZ,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAEzB,kBAAkB;IAClB,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,GAAG,CAAC,uBAAuB,CAAC,CAAA;QAC5B,IAAI,UAAU,CAAC,QAAQ,CAAC;YAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;QAC9C,SAAS,CAAC,KAAK,CAAC,CAAA;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,CAAA;IAED,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAC9B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAE7B,aAAa;IACb,GAAG,CAAC,wBAAwB,OAAO,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,aAAa,CAAC,CAAA;AAC1F,CAAC;AAED,sBAAsB;AACtB,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAA;IACvC,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;IAChE,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QAC5B,UAAU,CAAC,QAAQ,CAAC,CAAA;QACpB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;QACvB,UAAU,CAAC,QAAQ,CAAC,CAAA;QACpB,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,wBAAwB;AACxB,MAAM,UAAU,eAAe;IAC7B,MAAM,KAAK,GAAG,SAAS,EAAE,CAAA;IACzB,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;YACL,OAAO,EAAE,KAAK;YACd,GAAG,EAAE,CAAC;YACN,SAAS,EAAE,EAAE;YACb,aAAa,EAAE,EAAE;YACjB,MAAM,EAAE,CAAC;YACT,UAAU,EAAE,EAAE;YACd,aAAa,EAAE,CAAC;YAChB,MAAM,EAAE,EAAE;SACX,CAAA;IACH,CAAC;IAED,wBAAwB;IACxB,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;QAChE,IAAI,CAAC;YAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAAC,OAAO,GAAG,IAAI,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,CAAA;AAC9B,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,YAAY,CAAC,KAAK,GAAG,EAAE;IACrC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAA;IACpC,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAA;AAClF,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type NotificationChannel = 'system' | 'terminal' | 'discord' | 'log';
|
|
2
|
+
export interface NotificationOptions {
|
|
3
|
+
title: string;
|
|
4
|
+
body: string;
|
|
5
|
+
channel?: NotificationChannel;
|
|
6
|
+
urgency?: 'low' | 'normal' | 'critical';
|
|
7
|
+
sound?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/** Send a notification through the specified channel */
|
|
10
|
+
export declare function notify(opts: NotificationOptions): Promise<boolean>;
|
|
11
|
+
/** Send notification on all available channels */
|
|
12
|
+
export declare function notifyAll(opts: NotificationOptions): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=notifications.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"AAmBA,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,KAAK,CAAA;AAE3E,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,mBAAmB,CAAA;IAC7B,OAAO,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,UAAU,CAAA;IACvC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,wDAAwD;AACxD,wBAAsB,MAAM,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CA0BxE;AAkFD,kDAAkD;AAClD,wBAAsB,SAAS,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAKxE"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// kbot Notification System — Proactive alerts from the daemon
|
|
2
|
+
//
|
|
3
|
+
// Channels:
|
|
4
|
+
// - system: macOS Notification Center (osascript) / Linux (notify-send)
|
|
5
|
+
// - terminal: bell character to active terminal
|
|
6
|
+
// - discord: webhook to configured channel
|
|
7
|
+
// - log: always writes to daemon log
|
|
8
|
+
//
|
|
9
|
+
// The daemon triggers notifications when:
|
|
10
|
+
// - Price alerts fire
|
|
11
|
+
// - Security incidents detected (memory tampering, injection attempts)
|
|
12
|
+
// - Provider outages
|
|
13
|
+
// - Dependency vulnerabilities discovered
|
|
14
|
+
import { execSync } from 'node:child_process';
|
|
15
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { homedir, platform } from 'node:os';
|
|
18
|
+
/** Send a notification through the specified channel */
|
|
19
|
+
export async function notify(opts) {
|
|
20
|
+
const channel = opts.channel || 'system';
|
|
21
|
+
try {
|
|
22
|
+
switch (channel) {
|
|
23
|
+
case 'system':
|
|
24
|
+
return sendSystemNotification(opts);
|
|
25
|
+
case 'terminal':
|
|
26
|
+
// Bell character — works in any terminal
|
|
27
|
+
process.stdout.write('\x07');
|
|
28
|
+
return true;
|
|
29
|
+
case 'discord':
|
|
30
|
+
return await sendDiscordNotification(opts);
|
|
31
|
+
case 'log':
|
|
32
|
+
// Log-only — handled by caller
|
|
33
|
+
return true;
|
|
34
|
+
default:
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** macOS Notification Center or Linux notify-send */
|
|
43
|
+
function sendSystemNotification(opts) {
|
|
44
|
+
const os = platform();
|
|
45
|
+
if (os === 'darwin') {
|
|
46
|
+
// macOS — use osascript for Notification Center
|
|
47
|
+
const title = opts.title.replace(/"/g, '\\"');
|
|
48
|
+
const body = opts.body.replace(/"/g, '\\"');
|
|
49
|
+
const sound = opts.urgency === 'critical' ? ' sound name "Funk"' : opts.sound ? ' sound name "default"' : '';
|
|
50
|
+
try {
|
|
51
|
+
execSync(`osascript -e 'display notification "${body}" with title "${title}"${sound}'`, { timeout: 5000 });
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (os === 'linux') {
|
|
59
|
+
// Linux — use notify-send
|
|
60
|
+
const urgency = opts.urgency || 'normal';
|
|
61
|
+
try {
|
|
62
|
+
execSync(`notify-send -u ${urgency} "${opts.title}" "${opts.body}"`, { timeout: 5000 });
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Windows — use PowerShell toast
|
|
70
|
+
if (os === 'win32') {
|
|
71
|
+
try {
|
|
72
|
+
const ps = `
|
|
73
|
+
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
|
|
74
|
+
$template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)
|
|
75
|
+
$textNodes = $template.GetElementsByTagName('text')
|
|
76
|
+
$textNodes.Item(0).AppendChild($template.CreateTextNode('${opts.title}')) | Out-Null
|
|
77
|
+
$textNodes.Item(1).AppendChild($template.CreateTextNode('${opts.body}')) | Out-Null
|
|
78
|
+
$toast = [Windows.UI.Notifications.ToastNotification]::new($template)
|
|
79
|
+
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('kbot').Show($toast)
|
|
80
|
+
`;
|
|
81
|
+
execSync(`powershell -command "${ps.replace(/\n/g, ';')}"`, { timeout: 5000 });
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
/** Send notification to Discord webhook */
|
|
91
|
+
async function sendDiscordNotification(opts) {
|
|
92
|
+
// Check for configured webhook
|
|
93
|
+
const configPath = join(homedir(), '.kbot', 'config.json');
|
|
94
|
+
let webhookUrl = process.env.DISCORD_WEBHOOK_URL || '';
|
|
95
|
+
if (!webhookUrl && existsSync(configPath)) {
|
|
96
|
+
try {
|
|
97
|
+
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
98
|
+
webhookUrl = config.discord_webhook || '';
|
|
99
|
+
}
|
|
100
|
+
catch { /* no config */ }
|
|
101
|
+
}
|
|
102
|
+
if (!webhookUrl)
|
|
103
|
+
return false;
|
|
104
|
+
const color = opts.urgency === 'critical' ? 0xFF0000 : opts.urgency === 'low' ? 0x888888 : 0x6B5B95;
|
|
105
|
+
try {
|
|
106
|
+
const res = await fetch(webhookUrl, {
|
|
107
|
+
method: 'POST',
|
|
108
|
+
headers: { 'Content-Type': 'application/json' },
|
|
109
|
+
body: JSON.stringify({
|
|
110
|
+
embeds: [{
|
|
111
|
+
title: opts.title,
|
|
112
|
+
description: opts.body,
|
|
113
|
+
color,
|
|
114
|
+
timestamp: new Date().toISOString(),
|
|
115
|
+
footer: { text: 'kbot daemon' },
|
|
116
|
+
}],
|
|
117
|
+
}),
|
|
118
|
+
signal: AbortSignal.timeout(5000),
|
|
119
|
+
});
|
|
120
|
+
return res.ok;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** Send notification on all available channels */
|
|
127
|
+
export async function notifyAll(opts) {
|
|
128
|
+
await Promise.allSettled([
|
|
129
|
+
notify({ ...opts, channel: 'system' }),
|
|
130
|
+
notify({ ...opts, channel: 'discord' }),
|
|
131
|
+
]);
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=notifications.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kernel.chat/kbot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.31.0",
|
|
4
4
|
"description": "The only AI agent that builds its own tools — and defends itself. Self-Defense System: HMAC memory integrity, prompt injection detection, knowledge sanitization, forge verification, anomaly detection, incident logging. Cybersecurity tools: dep_audit, secret_scan, ssl_check, headers_check, cve_lookup, port_scan, owasp_check. Machine-aware situated intelligence: full hardware profiling (CPU, GPU, RAM, display, battery, dev tools), resource-adaptive tool pipeline, memory-pressure throttling, GPU-accelerated model routing. Multi-channel cognitive engine: email agent, iMessage agent, consultation pipeline, Trader agent with paper trading & DeFi, 26 specialist agents, 345+ tools, 20 providers. Finance stack: 31 tools across market data, wallet & swaps, stocks, and sentiment. Synthesis Engine: closed-loop intelligence compounding. Runtime tool forging, Forge Registry, autopoietic health, immune self-audit. Cost-aware model routing, fallback chains, Bayesian skill routing. 11 local models (Llama 3.3, Qwen 3, DeepSeek R1, Codestral 22B). Embedded llama.cpp, MCP server, SDK. MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|