alvin-bot 5.7.0 → 5.8.1
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/CHANGELOG.md +25 -0
- package/README.md +25 -31
- package/dist/claude.js +1 -102
- package/dist/config.js +1 -96
- package/dist/engine.js +1 -90
- package/dist/find-claude-binary.js +1 -98
- package/dist/handlers/async-agent-chunk-handler.js +1 -50
- package/dist/handlers/background-bypass.js +1 -75
- package/dist/handlers/commands.js +1 -2336
- package/dist/handlers/cron-progress.js +1 -52
- package/dist/handlers/document.js +1 -194
- package/dist/handlers/message.js +1 -959
- package/dist/handlers/photo.js +1 -154
- package/dist/handlers/platform-message.js +1 -360
- package/dist/handlers/stuck-timer.js +1 -54
- package/dist/handlers/video.js +1 -237
- package/dist/handlers/voice.js +1 -148
- package/dist/i18n.js +1 -805
- package/dist/index.js +1 -697
- package/dist/init-data-dir.js +1 -98
- package/dist/middleware/auth.js +1 -233
- package/dist/migrate.js +1 -162
- package/dist/paths.js +1 -146
- package/dist/platforms/discord.js +1 -175
- package/dist/platforms/index.js +1 -130
- package/dist/platforms/signal.js +1 -205
- package/dist/platforms/slack-slash-parser.js +1 -32
- package/dist/platforms/slack.js +1 -501
- package/dist/platforms/telegram.js +1 -111
- package/dist/platforms/types.js +1 -8
- package/dist/platforms/whatsapp-auth-helpers.js +1 -53
- package/dist/platforms/whatsapp.js +1 -707
- package/dist/providers/claude-sdk-provider.js +1 -565
- package/dist/providers/codex-cli-provider.js +1 -134
- package/dist/providers/index.js +1 -7
- package/dist/providers/ollama-provider.js +1 -32
- package/dist/providers/openai-compatible.js +1 -406
- package/dist/providers/registry.js +1 -352
- package/dist/providers/runtime-header.js +1 -45
- package/dist/providers/tool-executor.js +1 -475
- package/dist/providers/types.js +1 -227
- package/dist/services/access.js +1 -144
- package/dist/services/allowed-users-gate.js +1 -56
- package/dist/services/alvin-dispatch.js +1 -174
- package/dist/services/alvin-mcp-tools.js +1 -104
- package/dist/services/asset-index.js +1 -224
- package/dist/services/async-agent-parser.js +1 -418
- package/dist/services/async-agent-watcher.js +1 -583
- package/dist/services/auto-diagnostic.js +1 -228
- package/dist/services/broadcast.js +1 -52
- package/dist/services/browser-manager.js +1 -562
- package/dist/services/browser-webfetch.js +1 -127
- package/dist/services/browser.js +1 -121
- package/dist/services/cdp-bootstrap.js +1 -357
- package/dist/services/compaction.js +1 -144
- package/dist/services/critical-notify.js +1 -203
- package/dist/services/cron-resolver.js +1 -58
- package/dist/services/cron-scheduling.js +1 -310
- package/dist/services/cron.js +1 -861
- package/dist/services/custom-tools.js +1 -317
- package/dist/services/delivery-queue.js +1 -173
- package/dist/services/delivery-registry.js +1 -21
- package/dist/services/disk-cleanup.js +1 -203
- package/dist/services/elevenlabs.js +1 -58
- package/dist/services/embeddings/auto-detect.js +1 -74
- package/dist/services/embeddings/fts5.js +1 -108
- package/dist/services/embeddings/gemini.js +1 -65
- package/dist/services/embeddings/index.js +1 -496
- package/dist/services/embeddings/ollama.js +1 -78
- package/dist/services/embeddings/openai.js +1 -49
- package/dist/services/embeddings/provider.js +1 -22
- package/dist/services/embeddings/vector-base.js +1 -113
- package/dist/services/embeddings-migration.js +1 -193
- package/dist/services/embeddings.js +1 -9
- package/dist/services/env-file.js +1 -50
- package/dist/services/exec-guard.js +1 -71
- package/dist/services/fallback-order.js +1 -154
- package/dist/services/file-permissions.js +1 -93
- package/dist/services/heartbeat-file.js +1 -65
- package/dist/services/heartbeat.js +1 -313
- package/dist/services/hooks.js +1 -44
- package/dist/services/imagegen.js +1 -72
- package/dist/services/language-detect.js +1 -154
- package/dist/services/markdown.js +1 -63
- package/dist/services/mcp.js +1 -263
- package/dist/services/memory-extractor.js +1 -178
- package/dist/services/memory-inject-mode.js +1 -43
- package/dist/services/memory-layers.js +1 -156
- package/dist/services/memory.js +1 -146
- package/dist/services/ollama-manager.js +1 -339
- package/dist/services/permissions-wizard.js +1 -291
- package/dist/services/personality.js +1 -376
- package/dist/services/plugins.js +1 -171
- package/dist/services/preflight.js +1 -292
- package/dist/services/process-manager.js +1 -291
- package/dist/services/release-highlights.js +1 -79
- package/dist/services/reminders.js +1 -97
- package/dist/services/restart.js +1 -48
- package/dist/services/security-audit.js +1 -74
- package/dist/services/self-diagnosis.js +1 -272
- package/dist/services/self-search.js +1 -129
- package/dist/services/session-persistence.js +1 -237
- package/dist/services/session.js +1 -282
- package/dist/services/skills.js +1 -290
- package/dist/services/ssrf-guard.js +1 -162
- package/dist/services/standing-orders.js +1 -29
- package/dist/services/steer-channel.js +1 -46
- package/dist/services/stop-controller.js +1 -52
- package/dist/services/subagent-dedup.js +1 -86
- package/dist/services/subagent-delivery.js +1 -452
- package/dist/services/subagent-stats.js +1 -123
- package/dist/services/subagents.js +1 -814
- package/dist/services/sudo.js +1 -329
- package/dist/services/telegram.js +1 -158
- package/dist/services/timing-safe-bearer.js +1 -51
- package/dist/services/tool-discovery.js +1 -214
- package/dist/services/trends.js +1 -580
- package/dist/services/updater.js +1 -291
- package/dist/services/usage-tracker.js +1 -144
- package/dist/services/users.js +1 -271
- package/dist/services/voice.js +1 -104
- package/dist/services/watchdog-brake.js +1 -154
- package/dist/services/watchdog.js +1 -311
- package/dist/services/workspaces.js +1 -276
- package/dist/tui/index.js +1 -667
- package/dist/util/console-formatter.js +1 -109
- package/dist/util/debounce.js +1 -24
- package/dist/util/telegram-error-filter.js +1 -62
- package/dist/version.js +1 -24
- package/dist/web/bind-strategy.js +1 -42
- package/dist/web/canvas.js +1 -30
- package/dist/web/doctor-api.js +1 -604
- package/dist/web/openai-compat.js +1 -252
- package/dist/web/server.js +1 -1902
- package/dist/web/setup-api.js +1 -1101
- package/package.json +5 -2
- package/dist/.metadata_never_index +0 -0
package/dist/services/trends.js
CHANGED
|
@@ -1,580 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Predictive Maintenance via Trends (Self-Preservation Phase 2, 3J).
|
|
3
|
-
*
|
|
4
|
-
* Mechanism:
|
|
5
|
-
* 1. Once every 24 h: snapshot lightweight health metrics and append
|
|
6
|
-
* one JSON line to ~/.alvin-bot/state/trends.jsonl
|
|
7
|
-
* 2. After the file has ≥ 7 days of data: also run a daily AI
|
|
8
|
-
* "anomaly detection" pass over the last 30 days of snapshots
|
|
9
|
-
* 3. If the AI flags a concerning trend → DM operator via 1D
|
|
10
|
-
*
|
|
11
|
-
* Why daily and not continuous: trends are about slow degradation
|
|
12
|
-
* (memory growth, error-rate increase, crash-frequency drift). A
|
|
13
|
-
* 24-hour sampling cadence is right for these timescales and keeps
|
|
14
|
-
* the storage + AI-call cost near zero.
|
|
15
|
-
*
|
|
16
|
-
* Storage format — JSONL, one line per day:
|
|
17
|
-
*
|
|
18
|
-
* {"ts": "2026-05-13T04:00:00Z", "uptime_s": 86400, "rss_mb": 105,
|
|
19
|
-
* "crashes_24h": 0, "diag_24h": 0, "errors_24h": 3,
|
|
20
|
-
* "provider": "claude-sdk", "version": "5.0.0"}
|
|
21
|
-
*
|
|
22
|
-
* The JSONL design is deliberate: easy to inspect with tail/head/awk,
|
|
23
|
-
* easy to truncate to last N days, no parsing pitfalls. The AI gets
|
|
24
|
-
* the whole tail as plain text — works with small-context models.
|
|
25
|
-
*
|
|
26
|
-
* Provider-agnostic — same engine.query() pipeline as 3I.
|
|
27
|
-
*
|
|
28
|
-
* Opt-out:
|
|
29
|
-
* ALVIN_DISABLE_TRENDS=true → skip 3J entirely
|
|
30
|
-
* ALVIN_DISABLE_SELF_PRESERVATION=true → skip all Phase-1/2
|
|
31
|
-
*
|
|
32
|
-
* Tunable for testing:
|
|
33
|
-
* ALVIN_TRENDS_INTERVAL_HOURS=24 → snapshot cadence
|
|
34
|
-
* ALVIN_TRENDS_AI_AFTER_DAYS=7 → days of data before AI analysis kicks in
|
|
35
|
-
*/
|
|
36
|
-
import { appendFileSync, existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
37
|
-
import { join, dirname } from "path";
|
|
38
|
-
import { homedir } from "os";
|
|
39
|
-
import { BOT_VERSION } from "../version.js";
|
|
40
|
-
import { emitCritical } from "./critical-notify.js";
|
|
41
|
-
const TRENDS_PATH = join(homedir(), ".alvin-bot", "state", "trends.jsonl");
|
|
42
|
-
/**
|
|
43
|
-
* B2 — peak-uptime high-water mark. The trends collector takes its FIRST
|
|
44
|
-
* snapshot ~60s after every boot (startTrendsCollector schedules it at
|
|
45
|
-
* 60_000ms). takeSnapshot() records uptime_s = process.uptime(), so the
|
|
46
|
-
* first post-restart sample is structurally ≈ 62s. With deliberate
|
|
47
|
-
* restarts (/update, launchctl reload) those ~62s samples dominate
|
|
48
|
-
* trends.jsonl, so the 30-day AI pass perpetually concludes "restart
|
|
49
|
-
* loop, never lives past ~62s" even when the process has actually been
|
|
50
|
-
* continuously up for hours by the time the daily snapshot fires.
|
|
51
|
-
*
|
|
52
|
-
* Fix: persist the MAXIMUM real uptime this bot has ever observed (across
|
|
53
|
-
* process generations) and record it on every snapshot as uptime_peak_s.
|
|
54
|
-
* The peak only ever derives from process.uptime() — it is never
|
|
55
|
-
* fabricated or extrapolated. The anomaly evaluation then keys on the
|
|
56
|
-
* peak (hasRepresentativeUptime), so a process that genuinely lived for
|
|
57
|
-
* hours is not flagged as a ~62s loop, while a genuine fast-restart loop
|
|
58
|
-
* (peak never climbs past the startup transient) still fires.
|
|
59
|
-
*
|
|
60
|
-
* Stored next to trends.jsonl (state/), honoring ALVIN_DATA_DIR so tests
|
|
61
|
-
* and non-default installs work. Survives restarts by design — that is
|
|
62
|
-
* the whole point of a high-water mark.
|
|
63
|
-
*/
|
|
64
|
-
function trendsStateDir() {
|
|
65
|
-
const base = process.env.ALVIN_DATA_DIR || join(homedir(), ".alvin-bot");
|
|
66
|
-
return join(base, "state");
|
|
67
|
-
}
|
|
68
|
-
function uptimePeakPath() {
|
|
69
|
-
return join(trendsStateDir(), "uptime-peak.json");
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* The startup transient: takeSnapshot's first sample is taken ~60s after
|
|
73
|
-
* boot, so any uptime at/under this is indistinguishable from "just
|
|
74
|
-
* restarted". An uptime ABOVE this proves the process actually lived past
|
|
75
|
-
* the post-restart sampling window. 600s (10 min) is comfortably above
|
|
76
|
-
* the 60s first-sample delay + scheduling jitter and far below the 24h
|
|
77
|
-
* cron cadence, so a healthy bot trivially clears it while a real
|
|
78
|
-
* crash-loop (exits within seconds/a couple minutes) never does.
|
|
79
|
-
*/
|
|
80
|
-
export const STARTUP_TRANSIENT_S = 600;
|
|
81
|
-
/**
|
|
82
|
-
* Read the persisted peak uptime, fold in the CURRENT real uptime, persist
|
|
83
|
-
* the (possibly larger) high-water mark, and return it. Pure w.r.t. time
|
|
84
|
-
* sources: the only uptime input is process.uptime() — nothing invented.
|
|
85
|
-
* Disk failures degrade gracefully to the current real uptime.
|
|
86
|
-
*/
|
|
87
|
-
function bumpAndReadUptimePeak() {
|
|
88
|
-
const currentReal = Math.round(process.uptime());
|
|
89
|
-
let stored = 0;
|
|
90
|
-
try {
|
|
91
|
-
const raw = readFileSync(uptimePeakPath(), "utf-8");
|
|
92
|
-
const parsed = JSON.parse(raw);
|
|
93
|
-
if (typeof parsed.peak_s === "number" && Number.isFinite(parsed.peak_s) && parsed.peak_s > 0) {
|
|
94
|
-
stored = parsed.peak_s;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
catch {
|
|
98
|
-
// No file yet / unreadable — start the high-water mark from the
|
|
99
|
-
// current real uptime. Not an error.
|
|
100
|
-
}
|
|
101
|
-
const peak = Math.max(stored, currentReal);
|
|
102
|
-
try {
|
|
103
|
-
mkdirSync(trendsStateDir(), { recursive: true });
|
|
104
|
-
writeFileSync(uptimePeakPath(), JSON.stringify({ peak_s: peak }), "utf-8");
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
// Disk full / permissions — non-fatal; we still return the in-memory peak.
|
|
108
|
-
}
|
|
109
|
-
return peak;
|
|
110
|
-
}
|
|
111
|
-
const DEFAULT_INTERVAL_HOURS = 24;
|
|
112
|
-
const DEFAULT_AI_THRESHOLD_DAYS = 7;
|
|
113
|
-
const MAX_RETAIN_DAYS = 90;
|
|
114
|
-
/**
|
|
115
|
-
* What counts as an "error" line in alvin-bot.err.log for the
|
|
116
|
-
* errors_24h metric.
|
|
117
|
-
*
|
|
118
|
-
* stderr IS the bot's error channel, so the default is: count every
|
|
119
|
-
* timestamped line. But a few subsystems deliberately write *benign*
|
|
120
|
-
* operational diagnostics to stderr:
|
|
121
|
-
*
|
|
122
|
-
* - subagent-delivery's self-healing Markdown→plaintext retry
|
|
123
|
-
* (a successful, expected fallback — not an error)
|
|
124
|
-
* - critical-notify's own delivery-outcome line, kept on stderr on
|
|
125
|
-
* purpose so it stays visible even in brake/crash context
|
|
126
|
-
* - B3: subagent-delivery's "send failed … chat not found" line for a
|
|
127
|
-
* stale/test async-agent whose delivery target chat no longer exists
|
|
128
|
-
* (e.g. the recurring chat_id:1 test agent). This is benign noise,
|
|
129
|
-
* not a real fault: the target chat is invalid, the watcher now
|
|
130
|
-
* abandons such agents (see async-agent-watcher.ts), and counting it
|
|
131
|
-
* made errors_24h creep upward indefinitely on every poll cycle.
|
|
132
|
-
* The match is DELIBERATELY narrow — it requires BOTH the
|
|
133
|
-
* `[subagent-delivery] send failed` prefix AND a `chat not found`
|
|
134
|
-
* cause on the same line. A subagent-delivery failure for ANY other
|
|
135
|
-
* reason (network, rate-limit, parse) is still counted, and a
|
|
136
|
-
* `chat not found` from ANY OTHER subsystem (a real misconfigured
|
|
137
|
-
* target) is still counted.
|
|
138
|
-
*
|
|
139
|
-
* Counting those turned this very monitor into a false-alarm generator:
|
|
140
|
-
* it flagged its OWN log lines plus every release's restart churn, so
|
|
141
|
-
* the alert kept firing even after the underlying issue was fixed.
|
|
142
|
-
*
|
|
143
|
-
* This is a BLACKLIST (count everything except the known benign
|
|
144
|
-
* emitters), not a whitelist of error signatures — a health monitor
|
|
145
|
-
* must never silently miss a novel real error. New benign emitters, if
|
|
146
|
-
* any, get added here in one place instead of being chased across the
|
|
147
|
-
* codebase.
|
|
148
|
-
*/
|
|
149
|
-
export const ERR_LOG_PATTERN = /^(?!.*(?:\[critical-notify\]|\[subagent-delivery\] Markdown parse failed|\[subagent-delivery\] send failed.*chat not found)).+/;
|
|
150
|
-
let trendsTimer = null;
|
|
151
|
-
function isDisabled() {
|
|
152
|
-
return (process.env.ALVIN_DISABLE_TRENDS === "true" ||
|
|
153
|
-
process.env.ALVIN_DISABLE_SELF_PRESERVATION === "true");
|
|
154
|
-
}
|
|
155
|
-
function countLogLinesLast24h(filename, pattern) {
|
|
156
|
-
const path = join(homedir(), ".alvin-bot", "logs", filename);
|
|
157
|
-
if (!existsSync(path))
|
|
158
|
-
return 0;
|
|
159
|
-
try {
|
|
160
|
-
const content = readFileSync(path, "utf-8");
|
|
161
|
-
const cutoff = Date.now() - 24 * 60 * 60 * 1000;
|
|
162
|
-
let count = 0;
|
|
163
|
-
for (const line of content.split("\n")) {
|
|
164
|
-
const tsMatch = line.match(/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z)/);
|
|
165
|
-
if (!tsMatch)
|
|
166
|
-
continue;
|
|
167
|
-
const lineTs = new Date(tsMatch[1]).getTime();
|
|
168
|
-
if (Number.isFinite(lineTs) && lineTs >= cutoff) {
|
|
169
|
-
if (!pattern || pattern.test(line))
|
|
170
|
-
count++;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return count;
|
|
174
|
-
}
|
|
175
|
-
catch {
|
|
176
|
-
return 0;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
function readWatchdogCrashes24h() {
|
|
180
|
-
try {
|
|
181
|
-
const path = join(homedir(), ".alvin-bot", "state", "watchdog.json");
|
|
182
|
-
if (!existsSync(path))
|
|
183
|
-
return 0;
|
|
184
|
-
const data = JSON.parse(readFileSync(path, "utf-8"));
|
|
185
|
-
return data.dailyCrashCount ?? 0;
|
|
186
|
-
}
|
|
187
|
-
catch {
|
|
188
|
-
return 0;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
function countDiagnosticBundlesLast24h() {
|
|
192
|
-
try {
|
|
193
|
-
const dir = join(homedir(), ".alvin-bot", "diagnostics");
|
|
194
|
-
if (!existsSync(dir))
|
|
195
|
-
return 0;
|
|
196
|
-
const { readdirSync, statSync } = require("fs");
|
|
197
|
-
const cutoff = Date.now() - 24 * 60 * 60 * 1000;
|
|
198
|
-
return readdirSync(dir)
|
|
199
|
-
.filter((f) => f.endsWith(".md") && !f.endsWith(".analysis.md"))
|
|
200
|
-
.filter((f) => {
|
|
201
|
-
try {
|
|
202
|
-
return statSync(join(dir, f)).mtimeMs >= cutoff;
|
|
203
|
-
}
|
|
204
|
-
catch {
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
}).length;
|
|
208
|
-
}
|
|
209
|
-
catch {
|
|
210
|
-
return 0;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
function takeSnapshot(activeProvider) {
|
|
214
|
-
const mem = process.memoryUsage();
|
|
215
|
-
return {
|
|
216
|
-
ts: new Date().toISOString(),
|
|
217
|
-
uptime_s: Math.round(process.uptime()),
|
|
218
|
-
uptime_peak_s: bumpAndReadUptimePeak(),
|
|
219
|
-
rss_mb: Math.round(mem.rss / 1024 / 1024),
|
|
220
|
-
heap_mb: Math.round(mem.heapUsed / 1024 / 1024),
|
|
221
|
-
crashes_24h: readWatchdogCrashes24h(),
|
|
222
|
-
diag_24h: countDiagnosticBundlesLast24h(),
|
|
223
|
-
errors_24h: countLogLinesLast24h("alvin-bot.err.log", ERR_LOG_PATTERN),
|
|
224
|
-
provider: activeProvider,
|
|
225
|
-
version: BOT_VERSION,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
function appendSnapshot(snap) {
|
|
229
|
-
try {
|
|
230
|
-
mkdirSync(dirname(TRENDS_PATH), { recursive: true });
|
|
231
|
-
appendFileSync(TRENDS_PATH, JSON.stringify(snap) + "\n");
|
|
232
|
-
}
|
|
233
|
-
catch {
|
|
234
|
-
// Disk full / permissions — non-fatal
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
function readSnapshots(lastN = 30) {
|
|
238
|
-
if (!existsSync(TRENDS_PATH))
|
|
239
|
-
return [];
|
|
240
|
-
try {
|
|
241
|
-
const content = readFileSync(TRENDS_PATH, "utf-8");
|
|
242
|
-
const lines = content.split("\n").filter((l) => l.trim());
|
|
243
|
-
const recent = lines.slice(-lastN);
|
|
244
|
-
return recent
|
|
245
|
-
.map((l) => {
|
|
246
|
-
try {
|
|
247
|
-
return JSON.parse(l);
|
|
248
|
-
}
|
|
249
|
-
catch {
|
|
250
|
-
return null;
|
|
251
|
-
}
|
|
252
|
-
})
|
|
253
|
-
.filter((s) => s !== null);
|
|
254
|
-
}
|
|
255
|
-
catch {
|
|
256
|
-
return [];
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
const TREND_PROMPT_TEMPLATE = `You are an SRE monitoring an Alvin Bot instance over the last days.
|
|
260
|
-
Below is one JSON line per day with the bot's daily health metrics.
|
|
261
|
-
|
|
262
|
-
Detect any CONCERNING trend that suggests slow degradation — like:
|
|
263
|
-
- Memory (rss_mb / heap_mb) growing day over day
|
|
264
|
-
- Error rate (errors_24h) climbing
|
|
265
|
-
- Crashes (crashes_24h) above 0 for multiple days
|
|
266
|
-
- Diagnostic bundles (diag_24h) > 0 repeatedly
|
|
267
|
-
|
|
268
|
-
If there is NO concerning trend, respond with EXACTLY this one line:
|
|
269
|
-
ANOMALY: NONE
|
|
270
|
-
|
|
271
|
-
If there IS a concerning trend, respond in this 3-line format — nothing else:
|
|
272
|
-
|
|
273
|
-
ANOMALY: <one short sentence — what trend you noticed>
|
|
274
|
-
SEVERITY: <warn | critical>
|
|
275
|
-
SUGGESTION: <one shell command OR observation for the operator>
|
|
276
|
-
|
|
277
|
-
--- LAST {N} DAYS OF SNAPSHOTS ---
|
|
278
|
-
{SNAPSHOTS}
|
|
279
|
-
--- END ---`;
|
|
280
|
-
/**
|
|
281
|
-
* V56 — Recent crash-evidence window.
|
|
282
|
-
*
|
|
283
|
-
* hasRealCrashEvidence keys the WARN-suppression gate on whether ANY
|
|
284
|
-
* persisted snapshot recorded a real crash. Snapshots persist for up to
|
|
285
|
-
* MAX_RETAIN_DAYS and the AI pass reads the last 30 (≈30 days at the 24h
|
|
286
|
-
* cadence). If the WHOLE 30-day history is considered, a history briefly
|
|
287
|
-
* poisoned by miscounted deliberate restarts (pre-v5.5.0 accounting bug,
|
|
288
|
-
* fixed in v5.5.0 for NEW snapshots but the bad lines persist ~30 days)
|
|
289
|
-
* keeps crash-evidence "true" — so the B2/B4 gate never suppresses and the
|
|
290
|
-
* false WARN fires for ~a month instead of self-healing.
|
|
291
|
-
*
|
|
292
|
-
* Restricting the evidence check to the most recent ~48h means: once
|
|
293
|
-
* v5.5.0's correct accounting produces clean recent snapshots
|
|
294
|
-
* (crashes_24h=0), the false WARN clears within ~a day — while a GENUINE
|
|
295
|
-
* crash loop (real crashes in the recent window) still returns true and
|
|
296
|
-
* the WARN still fires (the protective purpose is intact).
|
|
297
|
-
*
|
|
298
|
-
* 48h (not 24h) is chosen because the snapshot cadence is ~24h
|
|
299
|
-
* (DEFAULT_INTERVAL_HOURS): a 48h window reliably retains the last 1–2
|
|
300
|
-
* daily snapshots even across day-boundary jitter / a skipped cron tick,
|
|
301
|
-
* so a genuine recent crash loop is never missed, while crash evidence
|
|
302
|
-
* older than ~2 days (the poisoned history) ages out and self-heals. A
|
|
303
|
-
* timestamp window (not "last N snapshots") is used so self-healing keys
|
|
304
|
-
* on real wall-clock time and is robust to cadence changes / test-tuned
|
|
305
|
-
* ALVIN_TRENDS_INTERVAL_HOURS.
|
|
306
|
-
*/
|
|
307
|
-
export const RECENT_CRASH_WINDOW_MS = 48 * 60 * 60 * 1000;
|
|
308
|
-
/**
|
|
309
|
-
* Returns true if at least one snapshot WITHIN THE RECENT WINDOW has a
|
|
310
|
-
* non-zero crashes_24h value, meaning a REAL crash (not an
|
|
311
|
-
* expected/deliberate restart) was recorded recently.
|
|
312
|
-
*
|
|
313
|
-
* After the B1 fix, deliberate restarts (SIGTERM / launchctl reload /
|
|
314
|
-
* /restart / /update) write the expectedRestart beacon flag and are NOT
|
|
315
|
-
* counted in dailyCrashCount. So crashes_24h === 0 across the recent
|
|
316
|
-
* snapshots means the bot was only restarted intentionally — no real
|
|
317
|
-
* crash evidence — even if OLDER snapshots were poisoned by the
|
|
318
|
-
* pre-v5.5.0 miscount (those age out of the window and the false WARN
|
|
319
|
-
* self-heals; see RECENT_CRASH_WINDOW_MS).
|
|
320
|
-
*
|
|
321
|
-
* Recency is determined from each snapshot's `ts` (ISO 8601, written by
|
|
322
|
-
* takeSnapshot via new Date().toISOString()). FAIL-SAFE: a snapshot whose
|
|
323
|
-
* `ts` is missing or unparseable is treated as in-window (counted) — a
|
|
324
|
-
* health monitor must fail toward "visible", never go blind on bad data.
|
|
325
|
-
*
|
|
326
|
-
* Pure function, exported for unit testing.
|
|
327
|
-
*/
|
|
328
|
-
export function hasRealCrashEvidence(snaps, nowMs = Date.now()) {
|
|
329
|
-
const cutoff = nowMs - RECENT_CRASH_WINDOW_MS;
|
|
330
|
-
return snaps.some((s) => {
|
|
331
|
-
if (!(typeof s.crashes_24h === "number" && s.crashes_24h > 0))
|
|
332
|
-
return false;
|
|
333
|
-
// FAIL-SAFE: no/garbage ts → treat as recent (never silence on bad data).
|
|
334
|
-
if (typeof s.ts !== "string")
|
|
335
|
-
return true;
|
|
336
|
-
const t = Date.parse(s.ts);
|
|
337
|
-
if (!Number.isFinite(t))
|
|
338
|
-
return true;
|
|
339
|
-
return t >= cutoff;
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* B2 — Returns true if AT LEAST ONE snapshot proves the bot process
|
|
344
|
-
* genuinely lived past the startup transient (i.e. it is NOT a ~62s
|
|
345
|
-
* restart loop).
|
|
346
|
-
*
|
|
347
|
-
* The first per-boot snapshot is structurally taken ~60s after boot, so
|
|
348
|
-
* its raw uptime_s is always ≈ 62 regardless of how long the process
|
|
349
|
-
* subsequently runs. uptime_peak_s is the high-water mark of REAL
|
|
350
|
-
* process.uptime() carried across process generations, so a single
|
|
351
|
-
* snapshot whose peak exceeds STARTUP_TRANSIENT_S is hard evidence the
|
|
352
|
-
* process did live for a representative duration. Legacy pre-B2 lines
|
|
353
|
-
* have no uptime_peak_s — we fall back to their raw uptime_s, so a legacy
|
|
354
|
-
* 24h cron snapshot still counts as representative on its own.
|
|
355
|
-
*
|
|
356
|
-
* A genuine fast-restart loop never lets the peak climb past the
|
|
357
|
-
* transient, so it correctly returns false and the WARN still fires.
|
|
358
|
-
*
|
|
359
|
-
* Pure function, exported for unit testing.
|
|
360
|
-
*/
|
|
361
|
-
export function hasRepresentativeUptime(snaps) {
|
|
362
|
-
return snaps.some((s) => {
|
|
363
|
-
const peak = typeof s.uptime_peak_s === "number" && Number.isFinite(s.uptime_peak_s)
|
|
364
|
-
? s.uptime_peak_s
|
|
365
|
-
: typeof s.uptime_s === "number" && Number.isFinite(s.uptime_s)
|
|
366
|
-
? s.uptime_s
|
|
367
|
-
: 0;
|
|
368
|
-
return peak > STARTUP_TRANSIENT_S;
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* B2/B4 — Pure crash/restart WARN suppression decision.
|
|
373
|
-
*
|
|
374
|
-
* Encodes the SAME two gates, in the SAME precedence, that dailyTask
|
|
375
|
-
* applies inline (B2 before B4). Extracted as a pure function purely so
|
|
376
|
-
* the gate COMPOSITION (not just each helper in isolation) is unit
|
|
377
|
-
* testable — the helpers are individually correct but the interaction
|
|
378
|
-
* is where the real-crash-loop-after-a-healthy-period regression lives.
|
|
379
|
-
*
|
|
380
|
-
* Returns the suppression reason, or "none" when the WARN must fire.
|
|
381
|
-
*
|
|
382
|
-
* - "representative-uptime" (B2): a deliberate-restart / sampling
|
|
383
|
-
* artifact — the AI saw ~62s uptimes but a snapshot peak proves the
|
|
384
|
-
* process actually lived past the startup transient. ONLY applies
|
|
385
|
-
* when there is no real crash evidence: a genuine crash loop after a
|
|
386
|
-
* prior healthy period still carries the persisted high peak, so
|
|
387
|
-
* without the crash-evidence guard B2 would permanently and silently
|
|
388
|
-
* swallow it. With the guard, crashes_24h>0 falls through to B4.
|
|
389
|
-
* - "no-crash-evidence" (B4): crash/restart pattern but crashes_24h===0
|
|
390
|
-
* everywhere (deliberate-restart-only, not a real crash loop).
|
|
391
|
-
* - "none": the WARN is real and must be emitted.
|
|
392
|
-
*
|
|
393
|
-
* Pure function, exported for unit testing.
|
|
394
|
-
*/
|
|
395
|
-
export function evaluateCrashRestartSuppression(isCrashRestartPattern, snaps) {
|
|
396
|
-
if (!isCrashRestartPattern)
|
|
397
|
-
return "none";
|
|
398
|
-
const realCrash = hasRealCrashEvidence(snaps);
|
|
399
|
-
// B2: only the deliberate-restart / sampling-artifact case. A real
|
|
400
|
-
// crash loop (crashes_24h>0) must NOT be suppressed here even though
|
|
401
|
-
// the persisted uptime high-water mark still reads representative.
|
|
402
|
-
if (!realCrash && hasRepresentativeUptime(snaps))
|
|
403
|
-
return "representative-uptime";
|
|
404
|
-
// B4: crash/restart pattern with zero real crash evidence.
|
|
405
|
-
if (!realCrash)
|
|
406
|
-
return "no-crash-evidence";
|
|
407
|
-
return "none";
|
|
408
|
-
}
|
|
409
|
-
/** Test-only: take a snapshot without writing to trends.jsonl. */
|
|
410
|
-
export function __takeSnapshotForTest(activeProvider) {
|
|
411
|
-
return takeSnapshot(activeProvider);
|
|
412
|
-
}
|
|
413
|
-
function parseTrendResponse(text) {
|
|
414
|
-
if (/^ANOMALY:\s*NONE/im.test(text)) {
|
|
415
|
-
return {
|
|
416
|
-
anomalyDetected: false,
|
|
417
|
-
description: "no concerning trend detected",
|
|
418
|
-
severity: "none",
|
|
419
|
-
suggestion: "",
|
|
420
|
-
raw: text,
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
const get = (key) => {
|
|
424
|
-
const m = text.match(new RegExp(`^${key}:\\s*(.+?)$`, "m"));
|
|
425
|
-
return m ? m[1].trim() : "";
|
|
426
|
-
};
|
|
427
|
-
const sevRaw = get("SEVERITY").toLowerCase();
|
|
428
|
-
const sev = sevRaw === "critical" ? "critical" : "warn";
|
|
429
|
-
return {
|
|
430
|
-
anomalyDetected: true,
|
|
431
|
-
description: get("ANOMALY") || "(no description)",
|
|
432
|
-
severity: sev,
|
|
433
|
-
suggestion: get("SUGGESTION") || "(no suggestion)",
|
|
434
|
-
raw: text,
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
export async function analyzeTrends(registry) {
|
|
438
|
-
if (isDisabled())
|
|
439
|
-
return null;
|
|
440
|
-
if (!registry)
|
|
441
|
-
return null;
|
|
442
|
-
const snaps = readSnapshots(30);
|
|
443
|
-
const threshold = parseInt(process.env.ALVIN_TRENDS_AI_AFTER_DAYS || "", 10) || DEFAULT_AI_THRESHOLD_DAYS;
|
|
444
|
-
if (snaps.length < threshold)
|
|
445
|
-
return null;
|
|
446
|
-
let provider;
|
|
447
|
-
try {
|
|
448
|
-
provider = registry.getActive();
|
|
449
|
-
}
|
|
450
|
-
catch {
|
|
451
|
-
return null;
|
|
452
|
-
}
|
|
453
|
-
if (!provider)
|
|
454
|
-
return null;
|
|
455
|
-
const snapsBlock = snaps.map((s) => JSON.stringify(s)).join("\n");
|
|
456
|
-
const prompt = TREND_PROMPT_TEMPLATE.replace("{N}", String(snaps.length)).replace("{SNAPSHOTS}", snapsBlock);
|
|
457
|
-
const abortController = new AbortController();
|
|
458
|
-
const timer = setTimeout(() => abortController.abort(), 60_000);
|
|
459
|
-
let fullText = "";
|
|
460
|
-
try {
|
|
461
|
-
for await (const chunk of provider.query({
|
|
462
|
-
prompt,
|
|
463
|
-
systemPrompt: "You are a precise SRE assistant. Reply ONLY in the requested format.",
|
|
464
|
-
abortSignal: abortController.signal,
|
|
465
|
-
})) {
|
|
466
|
-
if (chunk.type === "text") {
|
|
467
|
-
if (chunk.delta)
|
|
468
|
-
fullText += chunk.delta;
|
|
469
|
-
else if (chunk.text)
|
|
470
|
-
fullText = chunk.text;
|
|
471
|
-
}
|
|
472
|
-
else if (chunk.type === "error") {
|
|
473
|
-
clearTimeout(timer);
|
|
474
|
-
return null;
|
|
475
|
-
}
|
|
476
|
-
else if (chunk.type === "done") {
|
|
477
|
-
if (chunk.text)
|
|
478
|
-
fullText = chunk.text;
|
|
479
|
-
break;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
catch {
|
|
484
|
-
clearTimeout(timer);
|
|
485
|
-
return null;
|
|
486
|
-
}
|
|
487
|
-
clearTimeout(timer);
|
|
488
|
-
if (!fullText.trim())
|
|
489
|
-
return null;
|
|
490
|
-
return parseTrendResponse(fullText);
|
|
491
|
-
}
|
|
492
|
-
async function dailyTask(registry) {
|
|
493
|
-
try {
|
|
494
|
-
// Snapshot first — always, regardless of AI being available
|
|
495
|
-
const activeProviderKey = (() => {
|
|
496
|
-
try {
|
|
497
|
-
return registry?.getActiveKey() || "none";
|
|
498
|
-
}
|
|
499
|
-
catch {
|
|
500
|
-
return "none";
|
|
501
|
-
}
|
|
502
|
-
})();
|
|
503
|
-
const snap = takeSnapshot(activeProviderKey);
|
|
504
|
-
appendSnapshot(snap);
|
|
505
|
-
console.log(`📊 Trends snapshot taken: rss=${snap.rss_mb}MB errors=${snap.errors_24h} crashes=${snap.crashes_24h}`);
|
|
506
|
-
// Then attempt AI analysis if we have enough history
|
|
507
|
-
const result = await analyzeTrends(registry);
|
|
508
|
-
if (!result)
|
|
509
|
-
return;
|
|
510
|
-
if (!result.anomalyDetected) {
|
|
511
|
-
console.log(`📊 Trends AI: no anomaly detected`);
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
const recentSnaps = readSnapshots(30);
|
|
515
|
-
const isCrashRestartPattern = /crash|restart|loop|uptime/i.test(result.description);
|
|
516
|
-
// B2 gate: suppress an "uptime stuck at ~62s / restart loop" WARN when
|
|
517
|
-
// the snapshots PROVE the process actually lived past the startup
|
|
518
|
-
// transient. The first per-boot snapshot is structurally sampled ~60s
|
|
519
|
-
// after boot, so raw uptime_s reads ≈62 even for a perfectly healthy
|
|
520
|
-
// bot that has been up for hours by the time the daily snapshot fires.
|
|
521
|
-
// uptime_peak_s is the high-water mark of real process.uptime() across
|
|
522
|
-
// process generations: if ANY snapshot's peak exceeds the transient,
|
|
523
|
-
// the "~62s loop" conclusion is factually false. A genuine fast-restart
|
|
524
|
-
// loop never lets the peak climb, so it is NOT suppressed here.
|
|
525
|
-
if (isCrashRestartPattern && !hasRealCrashEvidence(recentSnaps) && hasRepresentativeUptime(recentSnaps)) {
|
|
526
|
-
console.log(`📊 Trends AI: suppressed WARN "${result.description}" — ` +
|
|
527
|
-
`uptime/restart pattern flagged but at least one snapshot shows a ` +
|
|
528
|
-
`representative peak uptime (>${STARTUP_TRANSIENT_S}s); the process ` +
|
|
529
|
-
`did live well past the post-restart sampling window, not a ~62s loop`);
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
// B4 gate: suppress WARN when the AI flags a crash/restart-loop pattern
|
|
533
|
-
// but the historical snapshots contain ZERO real crash evidence
|
|
534
|
-
// (crashes_24h === 0 across the board). This happens when the bot was
|
|
535
|
-
// restarted deliberately (launchctl reload / /update / /restart) — those
|
|
536
|
-
// produce low uptimes that the AI reads as "restart loop", but the
|
|
537
|
-
// crash counter stays at 0 because markExpectedRestart() was written
|
|
538
|
-
// on each clean shutdown. A real crash loop WILL have crashes_24h > 0
|
|
539
|
-
// in at least one snapshot and will still fire the WARN.
|
|
540
|
-
if (isCrashRestartPattern && !hasRealCrashEvidence(recentSnaps)) {
|
|
541
|
-
console.log(`📊 Trends AI: suppressed WARN "${result.description}" — ` +
|
|
542
|
-
`crash/restart pattern detected but crashes_24h=0 across all snapshots ` +
|
|
543
|
-
`(deliberate-restart-only, not a real crash loop)`);
|
|
544
|
-
return;
|
|
545
|
-
}
|
|
546
|
-
console.log(`📊 Trends AI: ANOMALY (${result.severity}) — ${result.description}`);
|
|
547
|
-
emitCritical({
|
|
548
|
-
category: "custom",
|
|
549
|
-
severity: result.severity === "critical" ? "critical" : "warn",
|
|
550
|
-
title: `Trend anomaly detected: ${result.description}`,
|
|
551
|
-
detail: `30-day trend analysis flagged a concerning pattern.\n\n` +
|
|
552
|
-
`Suggestion: ${result.suggestion}\n\n` +
|
|
553
|
-
`Trend data: ${TRENDS_PATH}`,
|
|
554
|
-
suggestedAction: result.suggestion,
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
catch (err) {
|
|
558
|
-
console.warn(`📊 Trends daily task threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
export function startTrendsCollector(registry) {
|
|
562
|
-
if (isDisabled())
|
|
563
|
-
return;
|
|
564
|
-
const intervalH = parseInt(process.env.ALVIN_TRENDS_INTERVAL_HOURS || "", 10) || DEFAULT_INTERVAL_HOURS;
|
|
565
|
-
const intervalMs = intervalH * 60 * 60 * 1000;
|
|
566
|
-
// Initial: take a first snapshot after 60 s to avoid measuring the
|
|
567
|
-
// startup transient. Subsequent snapshots every intervalMs.
|
|
568
|
-
setTimeout(() => {
|
|
569
|
-
void dailyTask(registry);
|
|
570
|
-
trendsTimer = setInterval(() => void dailyTask(registry), intervalMs);
|
|
571
|
-
if (trendsTimer.unref)
|
|
572
|
-
trendsTimer.unref();
|
|
573
|
-
}, 60_000);
|
|
574
|
-
}
|
|
575
|
-
export function stopTrendsCollector() {
|
|
576
|
-
if (trendsTimer) {
|
|
577
|
-
clearInterval(trendsTimer);
|
|
578
|
-
trendsTimer = null;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
1
|
+
const _0x1e479d=_0x1e32,_0x257576=_0x1e32;(function(_0x5a52ec,_0x5312d9){const _0x242304=_0x1e32,_0x238cd7=_0x1e32,_0x3360f3=_0x5a52ec();while(!![]){try{const _0x235f85=-parseInt(_0x242304(0x19c))/(0x7be*-0x3+0x2*0xb6c+0x3*0x21)+-parseInt(_0x238cd7(0x230))/(0xc5b*0x1+-0x1d4e+-0x1*-0x10f5)*(parseInt(_0x242304(0x19f))/(-0x98a*0x2+-0x9*0x63+0x1692))+parseInt(_0x238cd7(0x233))/(-0x1*-0x151+-0x253e+-0x23f1*-0x1)*(-parseInt(_0x242304(0x1dd))/(0x1d9e+0x181a*0x1+-0x35b3))+-parseInt(_0x242304(0x1fa))/(0x23c3*-0x1+0x6*-0x1c+0x2471)*(-parseInt(_0x238cd7(0x20a))/(-0x177d+-0x1af*0x3+0x1c91))+parseInt(_0x238cd7(0x187))/(0x6*0x535+-0x180f+-0x1*0x727)+parseInt(_0x242304(0x1cf))/(-0x1f77+0x6*-0x55f+0x3fba)+-parseInt(_0x238cd7(0x1ee))/(-0x1*0x224+-0x4bd*-0x1+-0x28f*0x1);if(_0x235f85===_0x5312d9)break;else _0x3360f3['push'](_0x3360f3['shift']());}catch(_0xa89556){_0x3360f3['push'](_0x3360f3['shift']());}}}(_0x2e5e,0x8e31a+0x2f27b*0x5+-0xd41c8));const _0x549aea=(function(){let _0x3d6a62=!![];return function(_0x584c95,_0x23e3f2){const _0x3ffecc=_0x3d6a62?function(){const _0x1a96f0=_0x1e32;if(_0x23e3f2){const _0x375d22=_0x23e3f2[_0x1a96f0(0x1bc)](_0x584c95,arguments);return _0x23e3f2=null,_0x375d22;}}:function(){};return _0x3d6a62=![],_0x3ffecc;};}()),_0x2bfbf8=_0x549aea(this,function(){const _0x556863=_0x1e32,_0xbe3eaf=_0x1e32;return _0x2bfbf8['toString']()[_0x556863(0x1b6)](_0xbe3eaf(0x166)+'+$')[_0x556863(0x235)]()[_0xbe3eaf(0x1af)+'r'](_0x2bfbf8)[_0xbe3eaf(0x1b6)]('(((.+)+)+)'+'+$');});function _0x2e5e(){const _0x2335ea=['vhjLBMqGzgf0yq','C29U','CNnZx21I','oIa8B25LihnOzq','zgfPBhLdCMfZAa','rfnFquLFquzurq','DhjLBMrZlMPZBW','CgvHA19Z','CMvWBgfJzq','BwfW','zwXSihbHC3qGDa','iePtt04GBgLUzq','ndiWnvrxD2nvzq','DgfYDcbWyxr0zq','DgHLig9WzxjHDa','vhjLBMqGyw5VBq','mcbYzxbLyxrLza','E059','AM9PBG','BMCGCgf0DgvYBG','AxrOihrOzsbIBW','DgvUy2uG4OcuihDO','B2nLC3mG','C2XPy2u','Bg93igLZig9Uzq','zgvSDge','4Ocuig5VDgHPBMCG','zxnFmJrOksbHyG','y3jPDgLJywW','ode1ota5meX6yMLVsW','ifnsrsbTB25PDa','rvHbq1rmwsb0Aa','DMLKzw5Jzq','E1noqvbtse9uuW','BgLUzYb3Aw5KBW','Aw5NihrYzw5Kia','ie9sig9IC2vYDG','zgLHz25VC3rPyW','ysbYzwfSignYyq','CMvZCg9UzcbPBG','D2fYBG','mJi3nen3uvjkva','Dw5Yzwy','zYbKyxKGB3zLCG','yxLZcIaGlsbeAq','zw5KC1DPDgG','BIbKzxrLy3rLza','yxrPB24G4OcuigXP','Bwf0y2G','qKXfx1nftezFua','Bg9N','ksdIGjqG','ChjLy2LZzsbtuG','AY5QC29U','ztOkqu5ptufmwq','yxj0ihbHDhrLCG','CNnZ','mti2nZD0D0nZrLC','C3rYAw5NAwz5','BhKkcKLMihrOzq','tKXzigLUihrOzq','lMfSDMLUlwjVDa','rsbHC3nPC3rHBG','AgvHBhrOig1LDa','A2u6cIaGlsbnzq','q291BNq','pGPtrvzfuKLuwq','ywDUB3n0AwmGyG','kgrLBgLIzxjHDa','zwn0zwq','B3i+cGOTls0Gta','tufmwtOGpg9Uzq','BMfWC2HVDcb0yq','stOGBM8Gyw5VBq','lM1K','BwiPigDYB3DPBG','ywDFmJrOksa+ia','C2vKifDbuK4GiG','igrHEqOGic0Grq','DcDZigrHAwX5ia','A2vUoIbYC3m9','BxrPBwvnCW','z2v0vgLTzq','DhjPBq','BNvTyMvY','B3zLidaGzM9Yia','C3bSAxq','BwiGlYbOzwfWxW','ysbJB25JzxjUAq','Dxb0Aw1LicG+','C3rHDgu','Dgv4Da','B25SEsWGBM90ia','qvnuihToFsbeqq','8j+tIIbuCMvUzhmGza','ohjpzhfuEq','AgvZicHJCMfZAa','CgfYC2u','ndm5mMnQtgvluG','y3jHC2GVCMvZDa','Dg9tDhjPBMC','stOGC3vWChjLCW','Bg93igrLz3jHza','8j+tIIbuCMvUzhmGqq','Bw9YEsaOCNnZxW','DgHYzxC6ia','stOGqu5ptufmwq','oIbot05fcGPjzG','iIdIGjqG','igj1DcbHDcbSzq','AgvHCfvZzwq','qKXfx1rsru5euW','igzVCM1HDc4','Dxb0Aw1Lx3m','kcGOlISPkYKRkq','lMfUywX5C2LZlG','ihjLCxvLC3rLza','Cg9Uzcb3AxrOia','A19Z','C3rYAw5N','ywLSEsb0yxnRia','ihnOB3j0ihnLBG','C2GGBg9VCcK','z2v0qwn0AxzLsW','wvmGt0yGu05bua','C29Tzq','DhLWzq','zxnFmJrOptaGyq','quXwsu5FreLtqq','kg5Vihn1z2DLCW','zwn0igfUEsbdtW','Bg9NCW','CM4GzMXHz2DLza','zMLSDgvY','zwXZztOkcKfotW','uKvtrvjwqvrjtW','BgvUz3rO','y3jHC2HLC18Yna','AxmGB25LigXPBG','Dxb0Aw1Ll3jLCW','tuiGzxjYB3jZpq','CM91BMq','D2f0y2HKB2CUAG','ywjVCNq','ihbLCIbKyxKGDW','BwvZC2fNzq','FqOTls0Gru5eia','otm3ndy0meTtv3HJqq','AcKGy2XPBwjPBG','uL9eqvLt','BM93','BxvSDgLWBguGza','C2LNBMfS','y3jPDgLJywW+cG','yxn0ig9UzsbZBG','BMqGyw5HBhLZAq','AguGCg9ZDc1Yzq','ww91igfYzsbHBG','zxjYlMXVzW','ww91igfYzsbHia','B3uGBM90AwnLza','Dxb0Aw1LlxbLyq','zw52','u0vwrvjjvfK','zwq6ia','C3rHCNqGC2fTCa','tKnfuK5jtKCGDa','DgL2zsbWzwfRia','nda4mJa4AMHhCfz3','quXwsu5FvfjftG','Bwf4','mZG1mJnkvunduuy','BwvTB3j5vxnHzW','tf9it1vsuW','igj1DcbJCMfZAa','Dxb0Aw1Lx3bLyq','kg5VigrLC2nYAq','nJjZigXVB3a','zg9Uzq','ywX5igrLDgvJDa','ignYyxnOzxm9','lGOk','CNjVCIbYyxrLia','DxrMltG','BgWGy29TBwfUza','x0rjuG','yw5VBwfSEurLDa','y29UC3rYDwn0BW','Dhj1zq','CMvWCMvZzw50yq','zxiGDgHLigXHCW','Dg9ju09tDhjPBG','CMLJCY4kcKrLDa','D3mGysa','C2vHCMnO','BM9Uzq','ywX2Aw4TyM90lG','u1vhr0vtveLptG','BMCGDhjLBMqSia','CMvUzcb0Agf0ia','yxbWBhK','qu5ptufmwq','CYbMBgfNz2vKia','DhjLBMqSihjLCW','C25HChnOB3rZia','BNn0yw5JzsbVDG','zxjYB3jZxZi0Aa','z2v0qwn0AxzL','yxqGDhjLBMqGEq','C3vNz2vZDhmGCW','ihrOAxmGmY1SAq','AxngAw5PDgu','ihrOzxjLieLtia','zgvZy3jPChrPBW','DgvZDa','y3vZDg9T','u3vNz2vZDgLVBG','yxrPB24GzM9Yia','C3vNz2vZDgLVBG','ote4mdq3n3r4EuzhzG','DgLVBIK'];_0x2e5e=function(){return _0x2335ea;};return _0x2e5e();}_0x2bfbf8();import{appendFileSync,existsSync,readFileSync,writeFileSync,mkdirSync}from'fs';import{join,dirname}from'path';import{homedir}from'os';import{BOT_VERSION}from'../version.js';import{emitCritical}from'./critical-notify.js';const TRENDS_PATH=join(homedir(),_0x1e479d(0x20e),'state',_0x1e479d(0x1d7)+'nl');function trendsStateDir(){const _0xe4a75a=_0x257576,_0x5252ed=_0x1e479d,_0x421c42=process[_0xe4a75a(0x196)]['ALVIN_DATA'+_0x5252ed(0x1ad)]||join(homedir(),'.alvin-bot');return join(_0x421c42,_0x5252ed(0x22b));}function uptimePeakPath(){const _0x249cbe=_0x257576,_0x1a436c=_0x1e479d;return join(trendsStateDir(),_0x249cbe(0x195)+_0x249cbe(0x206));}export const STARTUP_TRANSIENT_S=-0x3*-0x4ab+-0x11*-0x43+-0x101c;function bumpAndReadUptimePeak(){const _0x1fb009=_0x1e479d,_0x2f3f3f=_0x257576,_0x1215f9=Math['round'](process['uptime']());let _0x1d5232=-0x154d+0x5fb+0x25*0x6a;try{const _0x4fb8d1=readFileSync(uptimePeakPath(),_0x1fb009(0x1ab)),_0x1067f9=JSON['parse'](_0x4fb8d1);typeof _0x1067f9['peak_s']===_0x1fb009(0x225)&&Number[_0x2f3f3f(0x1c7)](_0x1067f9[_0x1fb009(0x1d8)])&&_0x1067f9[_0x2f3f3f(0x1d8)]>-0xa81+0x228b+-0x180a&&(_0x1d5232=_0x1067f9[_0x2f3f3f(0x1d8)]);}catch{}const _0x492fda=Math[_0x2f3f3f(0x19e)](_0x1d5232,_0x1215f9);try{mkdirSync(trendsStateDir(),{'recursive':!![]}),writeFileSync(uptimePeakPath(),JSON[_0x1fb009(0x20b)]({'peak_s':_0x492fda}),_0x1fb009(0x1ab));}catch{}return _0x492fda;}const DEFAULT_INTERVAL_HOURS=-0xfd+0x83*0x21+-0xfce,DEFAULT_AI_THRESHOLD_DAYS=-0x143a+-0x18ca+-0x1*-0x2d0b,MAX_RETAIN_DAYS=0xd*-0x6c+0x1e*-0x49+0xe64*0x1;export const ERR_LOG_PATTERN=/^(?!.*(?:\[critical-notify\]|\[subagent-delivery\] Markdown parse failed|\[subagent-delivery\] send failed.*chat not found)).+/;let trendsTimer=null;function isDisabled(){const _0x387f1a=_0x1e479d,_0x39c6e1=_0x1e479d;return process[_0x387f1a(0x196)]['ALVIN_DISA'+_0x39c6e1(0x163)]===_0x387f1a(0x1b0)||process[_0x39c6e1(0x196)][_0x387f1a(0x174)+_0x387f1a(0x202)+_0x387f1a(0x17b)+'N']===_0x39c6e1(0x1b0);}function countLogLinesLast24h(_0x2587dc,_0x2a3516){const _0xb07988=_0x257576,_0x160e25=_0x257576,_0x4b6562=join(homedir(),_0xb07988(0x20e),_0xb07988(0x177),_0x2587dc);if(!existsSync(_0x4b6562))return-0xa2*0x1+0x2495+0x1*-0x23f3;try{const _0x4e3edf=readFileSync(_0x4b6562,_0xb07988(0x1ab)),_0x375fea=Date[_0xb07988(0x18a)]()-(-0x2709+-0xd5*-0x25+0x18*0x59)*(0x1da+0x2373+-0x2511*0x1)*(-0x14bb+-0x126c+-0x2763*-0x1)*(0xd*-0x6b+0xc95+-0x33e);let _0x38b3b6=-0xcb*-0x31+0x51*-0x3d+-0x138e;for(const _0xf431b6 of _0x4e3edf[_0x160e25(0x227)]('\x0a')){const _0x397eb5=_0xf431b6[_0xb07988(0x201)](/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z)/);if(!_0x397eb5)continue;const _0x50acb0=new Date(_0x397eb5[-0x931+-0x175e+0x4*0x824])[_0x160e25(0x223)]();if(Number[_0xb07988(0x1c7)](_0x50acb0)&&_0x50acb0>=_0x375fea){if(!_0x2a3516||_0x2a3516['test'](_0xf431b6))_0x38b3b6++;}}return _0x38b3b6;}catch{return-0x12ce+0x2a6*0x9+-0x142*0x4;}}function readWatchdogCrashes24h(){const _0x3d9334=_0x257576,_0x3bf3b7=_0x257576;try{const _0x2caceb=join(homedir(),_0x3d9334(0x20e),_0x3bf3b7(0x22b),_0x3d9334(0x182)+_0x3bf3b7(0x1d2));if(!existsSync(_0x2caceb))return 0x7*-0x2f9+-0x14b0+-0x1*-0x297f;const _0x29c6da=JSON[_0x3d9334(0x232)](readFileSync(_0x2caceb,_0x3d9334(0x1ab)));return _0x29c6da[_0x3bf3b7(0x1d5)+_0x3bf3b7(0x212)]??-0x1*0x18a6+-0x17d+0x1a23;}catch{return 0x931+-0x1*0x821+-0x110;}}function countDiagnosticBundlesLast24h(){const _0x51ac81=_0x1e479d,_0x2108d2=_0x257576;try{const _0x5cc1dd=join(homedir(),_0x51ac81(0x20e),_0x51ac81(0x1f6)+'s');if(!existsSync(_0x5cc1dd))return 0x60*-0x49+0xed8+0x1*0xc88;const {readdirSync:_0x35f912,statSync:_0x37b987}=require('fs'),_0x4b68c4=Date['now']()-(-0x1*-0x252a+-0x4*-0x957+0x2537*-0x2)*(0x1e4a*-0x1+0x1*0x40f+0x19*0x10f)*(-0x1*0x1bab+-0x23a3+0x3f8a)*(-0x9*-0x192+0x2e6+-0xd20);return _0x35f912(_0x5cc1dd)[_0x2108d2(0x179)](_0x462796=>_0x462796['endsWith'](_0x51ac81(0x21b))&&!_0x462796[_0x51ac81(0x1fe)](_0x51ac81(0x167)+'md'))['filter'](_0xe611e4=>{const _0x5b03ad=_0x2108d2;try{return _0x37b987(join(_0x5cc1dd,_0xe611e4))[_0x5b03ad(0x222)]>=_0x4b68c4;}catch{return![];}})[_0x51ac81(0x17c)];}catch{return 0x1af7+-0x1b3+0x6*-0x436;}}function takeSnapshot(_0xb2d94b){const _0x2ca228=_0x1e479d,_0x52b9c6=_0x257576,_0x495738=process[_0x2ca228(0x1a0)+'e']();return{'ts':new Date()[_0x52b9c6(0x1b3)+'g'](),'uptime_s':Math[_0x2ca228(0x181)](process['uptime']()),'uptime_peak_s':bumpAndReadUptimePeak(),'rss_mb':Math[_0x2ca228(0x181)](_0x495738[_0x52b9c6(0x209)]/(0x1716+-0xb9e*0x2+0x426)/(-0x5*-0x3a5+-0x31a+0xd*-0xdb)),'heap_mb':Math[_0x2ca228(0x181)](_0x495738[_0x52b9c6(0x162)]/(0x948+-0x2*0x9f7+0x1*0xea6)/(-0x12f5+0x17b*-0xd+0x2a34*0x1)),'crashes_24h':readWatchdogCrashes24h(),'diag_24h':countDiagnosticBundlesLast24h(),'errors_24h':countLogLinesLast24h(_0x2ca228(0x1b8)+_0x2ca228(0x192),ERR_LOG_PATTERN),'provider':_0xb2d94b,'version':BOT_VERSION};}function appendSnapshot(_0xb42e6a){const _0x1f63dc=_0x1e479d;try{mkdirSync(dirname(TRENDS_PATH),{'recursive':!![]}),appendFileSync(TRENDS_PATH,JSON[_0x1f63dc(0x20b)](_0xb42e6a)+'\x0a');}catch{}}function readSnapshots(_0x465aaa=-0x3b3*-0x5+-0x15e7+0x386){const _0x4267c5=_0x257576,_0x4c522d=_0x257576;if(!existsSync(TRENDS_PATH))return[];try{const _0x8562ce=readFileSync(TRENDS_PATH,_0x4267c5(0x1ab)),_0x1fa4a3=_0x8562ce[_0x4c522d(0x227)]('\x0a')['filter'](_0x1e1212=>_0x1e1212[_0x4c522d(0x224)]()),_0x1a9bc6=_0x1fa4a3[_0x4c522d(0x1e8)](-_0x465aaa);return _0x1a9bc6[_0x4267c5(0x1da)](_0x393796=>{try{return JSON['parse'](_0x393796);}catch{return null;}})[_0x4c522d(0x179)](_0x55e3c1=>_0x55e3c1!==null);}catch{return[];}}const TREND_PROMPT_TEMPLATE=_0x1e479d(0x191)+_0x257576(0x1ef)+'oring\x20an\x20A'+'lvin\x20Bot\x20i'+_0x257576(0x1c1)+_0x1e479d(0x1b2)+'t\x20days.\x0aBe'+_0x257576(0x1e9)+_0x1e479d(0x1dc)+_0x1e479d(0x184)+_0x257576(0x1e5)+_0x257576(0x220)+_0x1e479d(0x210)+_0x1e479d(0x1b4)+_0x257576(0x176)+_0x257576(0x19a)+_0x257576(0x1bb)+_0x257576(0x1c5)+_0x257576(0x237)+_0x1e479d(0x200)+_0x1e479d(0x211)+_0x257576(0x239)+_0x1e479d(0x228)+_0x257576(0x21c)+_0x257576(0x1fc)+_0x257576(0x21f)+_0x257576(0x1aa)+'(errors_24'+_0x257576(0x188)+'g\x0a\x20\x20-\x20Cras'+_0x1e479d(0x231)+_0x257576(0x1ec)+_0x257576(0x226)+_0x1e479d(0x18b)+_0x1e479d(0x1fd)+_0x257576(0x214)+'undles\x20(di'+_0x257576(0x21d)+_0x1e479d(0x1e1)+_0x257576(0x20c)+'re\x20is\x20NO\x20c'+'oncerning\x20'+_0x257576(0x1bf)+_0x1e479d(0x169)+_0x1e479d(0x1f0)+_0x257576(0x17e)+_0x257576(0x207)+_0x1e479d(0x15f)+_0x257576(0x1c8)+_0x1e479d(0x229)+_0x1e479d(0x1ba)+_0x1e479d(0x1f8)+_0x1e479d(0x1c6)+'ne\x20format\x20'+_0x1e479d(0x1eb)+_0x257576(0x17a)+_0x1e479d(0x218)+_0x257576(0x16d)+_0x1e479d(0x1e6)+_0x257576(0x1c4)+_0x1e479d(0x194)+_0x257576(0x213)+':\x20<warn\x20|\x20'+_0x1e479d(0x18d)+_0x1e479d(0x1b9)+_0x1e479d(0x1d4)+_0x1e479d(0x1ac)+_0x257576(0x1f5)+_0x1e479d(0x1cd)+_0x1e479d(0x1df)+_0x257576(0x217)+_0x257576(0x22e)+_0x257576(0x170)+'SHOTS\x20---\x0a'+_0x1e479d(0x1f2)+_0x257576(0x186)+'---';export const RECENT_CRASH_WINDOW_MS=(0x1ee4+0x13ab+-0xa13*0x5)*(-0x1*-0xcde+0x1950+-0x25f2)*(-0x2*0xee2+-0x232b+-0x43*-0xf9)*(-0x19d9+0x263f+0x87e*-0x1);function _0x1e32(_0x509a16,_0x2d9d0d){_0x509a16=_0x509a16-(-0x1*-0xa7+-0x8fb*-0x1+-0x843);const _0x14a9d8=_0x2e5e();let _0x11dea0=_0x14a9d8[_0x509a16];if(_0x1e32['wKgJQd']===undefined){var _0x5880ac=function(_0x13e9a9){const _0x5ab175='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x975a72='',_0x13a109='',_0x45edb5=_0x975a72+_0x5880ac;for(let _0x2be6c1=-0x1e25+0x5d3*-0x3+0x2e*0x109,_0x4ca144,_0x20c97e,_0xa59104=0x473+-0x9*-0x2e7+-0x1e92;_0x20c97e=_0x13e9a9['charAt'](_0xa59104++);~_0x20c97e&&(_0x4ca144=_0x2be6c1%(-0x154d+0x5fb+0xd*0x12e)?_0x4ca144*(-0xa81+0x228b+-0x17ca)+_0x20c97e:_0x20c97e,_0x2be6c1++%(-0xfd+0x83*0x21+-0xfe2))?_0x975a72+=_0x45edb5['charCodeAt'](_0xa59104+(-0x143a+-0x18ca+-0x1*-0x2d0e))-(0xd*-0x6c+0x1e*-0x49+0xe14*0x1)!==-0xa2*0x1+0x2495+0x1*-0x23f3?String['fromCharCode'](-0x2709+-0xd5*-0x25+0x9*0x107&_0x4ca144>>(-(0x1da+0x2373+-0x254b*0x1)*_0x2be6c1&-0x14bb+-0x126c+-0x272d*-0x1)):_0x2be6c1:0xd*-0x6b+0xc95+-0x726){_0x20c97e=_0x5ab175['indexOf'](_0x20c97e);}for(let _0x4a4e8e=-0xcb*-0x31+0x51*-0x3d+-0x138e,_0x3dcdec=_0x975a72['length'];_0x4a4e8e<_0x3dcdec;_0x4a4e8e++){_0x13a109+='%'+('00'+_0x975a72['charCodeAt'](_0x4a4e8e)['toString'](-0x931+-0x175e+0x1*0x209f))['slice'](-(-0x12ce+0x2a6*0x9+-0x506*0x1));}return decodeURIComponent(_0x13a109);};_0x1e32['pjYgXj']=_0x5880ac,_0x1e32['gmiHgt']={},_0x1e32['wKgJQd']=!![];}const _0x350cb5=_0x14a9d8[0x7*-0x2f9+-0x14b0+-0x1*-0x297f],_0x4bddaf=_0x509a16+_0x350cb5,_0x135414=_0x1e32['gmiHgt'][_0x4bddaf];if(!_0x135414){const _0x3b04a2=function(_0x175ccb){this['WMCLKZ']=_0x175ccb,this['uxpxkJ']=[-0x1*0x18a6+-0x17d+0x1a24,0x931+-0x1*0x821+-0x110,0x60*-0x49+0xed8+0x1*0xc88],this['CtXDPq']=function(){return'newState';},this['JxDgrI']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['zPWqMN']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x3b04a2['prototype']['QesoLA']=function(){const _0xf94901=new RegExp(this['JxDgrI']+this['zPWqMN']),_0x53b0e2=_0xf94901['test'](this['CtXDPq']['toString']())?--this['uxpxkJ'][-0x1*-0x252a+-0x4*-0x957+0x4a85*-0x1]:--this['uxpxkJ'][0x1e4a*-0x1+0x1*0x40f+0x4f*0x55];return this['VpqoBQ'](_0x53b0e2);},_0x3b04a2['prototype']['VpqoBQ']=function(_0x18ef84){if(!Boolean(~_0x18ef84))return _0x18ef84;return this['HeVJja'](this['WMCLKZ']);},_0x3b04a2['prototype']['HeVJja']=function(_0x426e2b){for(let _0x3007a4=-0x1*0x1bab+-0x23a3+0x3f4e,_0x188da4=this['uxpxkJ']['length'];_0x3007a4<_0x188da4;_0x3007a4++){this['uxpxkJ']['push'](Math['round'](Math['random']())),_0x188da4=this['uxpxkJ']['length'];}return _0x426e2b(this['uxpxkJ'][-0x9*-0x192+0x2e6+-0x1108]);},new _0x3b04a2(_0x1e32)['QesoLA'](),_0x11dea0=_0x1e32['pjYgXj'](_0x11dea0),_0x1e32['gmiHgt'][_0x4bddaf]=_0x11dea0;}else _0x11dea0=_0x135414;return _0x11dea0;}export function hasRealCrashEvidence(_0x5bfb15,_0x5ccd2d=Date[_0x257576(0x18a)]()){const _0x1c6861=_0x257576,_0x1b41f0=_0x5ccd2d-RECENT_CRASH_WINDOW_MS;return _0x5bfb15[_0x1c6861(0x171)](_0x5523f8=>{const _0x120c56=_0x1c6861,_0x1a032f=_0x1c6861;if(!(typeof _0x5523f8[_0x120c56(0x17d)+'h']===_0x120c56(0x225)&&_0x5523f8[_0x1a032f(0x17d)+'h']>0x748+-0xe32+0x1e*0x3b))return![];if(typeof _0x5523f8['ts']!==_0x1a032f(0x16b))return!![];const _0x1725fa=Date[_0x120c56(0x232)](_0x5523f8['ts']);if(!Number[_0x1a032f(0x1c7)](_0x1725fa))return!![];return _0x1725fa>=_0x1b41f0;});}export function hasRepresentativeUptime(_0x2e197e){const _0x254986=_0x257576;return _0x2e197e[_0x254986(0x171)](_0x2994ab=>{const _0x4c518=_0x254986,_0x49597b=_0x254986,_0x29a06=typeof _0x2994ab[_0x4c518(0x1a3)+_0x4c518(0x16a)]===_0x49597b(0x225)&&Number[_0x49597b(0x1c7)](_0x2994ab[_0x49597b(0x1a3)+_0x49597b(0x16a)])?_0x2994ab[_0x4c518(0x1a3)+_0x4c518(0x16a)]:typeof _0x2994ab['uptime_s']===_0x4c518(0x225)&&Number[_0x4c518(0x1c7)](_0x2994ab[_0x49597b(0x165)])?_0x2994ab[_0x4c518(0x165)]:-0xa92+0x34+-0x1*-0xa5e;return _0x29a06>STARTUP_TRANSIENT_S;});}export function evaluateCrashRestartSuppression(_0x5214df,_0x1cfc3d){const _0xf37f38=_0x257576,_0x21074a=_0x257576;if(!_0x5214df)return _0xf37f38(0x1b7);const _0x43adfe=hasRealCrashEvidence(_0x1cfc3d);if(!_0x43adfe&&hasRepresentativeUptime(_0x1cfc3d))return'representa'+'tive-uptim'+'e';if(!_0x43adfe)return'no-crash-e'+_0xf37f38(0x1f1);return _0xf37f38(0x1b7);}export function __takeSnapshotForTest(_0x5ca45c){return takeSnapshot(_0x5ca45c);}function parseTrendResponse(_0x295f4e){const _0x1d423e=_0x257576,_0x4f5524=_0x257576;if(/^ANOMALY:\s*NONE/im['test'](_0x295f4e))return{'anomalyDetected':![],'description':'no\x20concern'+_0x1d423e(0x1f4)+'detected','severity':_0x4f5524(0x1b7),'suggestion':'','raw':_0x295f4e};const _0x34e377=_0x5a8e9f=>{const _0x23ef68=_0x4f5524,_0x2155c1=_0x1d423e,_0x3e742a=_0x295f4e[_0x23ef68(0x201)](new RegExp('^'+_0x5a8e9f+':\x5cs*(.+?)$','m'));return _0x3e742a?_0x3e742a[0x2*0x106f+-0x1*0x84+0xa9*-0x31][_0x2155c1(0x224)]():'';},_0x51fe0a=_0x34e377(_0x1d423e(0x197))['toLowerCas'+'e'](),_0x5a25be=_0x51fe0a===_0x1d423e(0x1ed)?_0x1d423e(0x1ed):_0x4f5524(0x1f9);return{'anomalyDetected':!![],'description':_0x34e377(_0x1d423e(0x1bd))||_0x1d423e(0x1a4)+'ption)','severity':_0x5a25be,'suggestion':_0x34e377(_0x1d423e(0x1b9))||_0x4f5524(0x175)+_0x1d423e(0x1d0),'raw':_0x295f4e};}export async function analyzeTrends(_0x385d63){const _0x3343f0=_0x1e479d,_0x251b8d=_0x1e479d;if(isDisabled())return null;if(!_0x385d63)return null;const _0x42a5c6=readSnapshots(-0x3*0xcfa+0x19b8+0xd54),_0x310197=parseInt(process[_0x3343f0(0x196)]['ALVIN_TREN'+_0x3343f0(0x1d6)+_0x3343f0(0x189)]||'',0xaf0+-0xb*0x57+0xd*-0x8d)||DEFAULT_AI_THRESHOLD_DAYS;if(_0x42a5c6['length']<_0x310197)return null;let _0x4eef18;try{_0x4eef18=_0x385d63[_0x3343f0(0x1c3)]();}catch{return null;}if(!_0x4eef18)return null;const _0x1d2231=_0x42a5c6[_0x3343f0(0x1da)](_0x5322c2=>JSON[_0x251b8d(0x20b)](_0x5322c2))[_0x3343f0(0x1e3)]('\x0a'),_0xd59b69=TREND_PROMPT_TEMPLATE['replace'](_0x251b8d(0x1e2),String(_0x42a5c6['length']))[_0x251b8d(0x1d9)](_0x251b8d(0x1f2)+'}',_0x1d2231),_0x224380=new AbortController(),_0x15fd72=setTimeout(()=>_0x224380[_0x3343f0(0x183)](),0x8597*0x1+-0x19b72+0x2003b);let _0x4f4992='';try{for await(const _0x1e76cd of _0x4eef18['query']({'prompt':_0xd59b69,'systemPrompt':_0x3343f0(0x193)+_0x251b8d(0x205)+_0x3343f0(0x20f)+'t.\x20Reply\x20O'+_0x3343f0(0x20d)+_0x251b8d(0x168)+_0x251b8d(0x164),'abortSignal':_0x224380[_0x251b8d(0x18c)]})){if(_0x1e76cd[_0x3343f0(0x172)]===_0x251b8d(0x22c)){if(_0x1e76cd[_0x251b8d(0x1ea)])_0x4f4992+=_0x1e76cd[_0x3343f0(0x1ea)];else{if(_0x1e76cd['text'])_0x4f4992=_0x1e76cd[_0x251b8d(0x22c)];}}else{if(_0x1e76cd['type']==='error')return clearTimeout(_0x15fd72),null;else{if(_0x1e76cd[_0x251b8d(0x172)]===_0x3343f0(0x1a6)){if(_0x1e76cd[_0x251b8d(0x22c)])_0x4f4992=_0x1e76cd[_0x251b8d(0x22c)];break;}}}}}catch{return clearTimeout(_0x15fd72),null;}clearTimeout(_0x15fd72);if(!_0x4f4992[_0x3343f0(0x224)]())return null;return parseTrendResponse(_0x4f4992);}async function dailyTask(_0x47fefc){const _0x2f093c=_0x257576,_0x4e092e=_0x1e479d;try{const _0x2551c8=((()=>{const _0x5dc46c=_0x1e32,_0x19dab7=_0x1e32;try{return _0x47fefc?.[_0x5dc46c(0x16f)+'ey']()||_0x19dab7(0x1b7);}catch{return _0x19dab7(0x1b7);}})()),_0x5d8663=takeSnapshot(_0x2551c8);appendSnapshot(_0x5d8663),console[_0x2f093c(0x203)]('📊\x20Trends\x20s'+_0x4e092e(0x219)+_0x4e092e(0x221)+_0x5d8663[_0x2f093c(0x1d3)]+_0x4e092e(0x180)+_0x5d8663[_0x4e092e(0x1c2)]+_0x4e092e(0x1a8)+_0x5d8663['crashes_24'+'h']);const _0x5d885c=await analyzeTrends(_0x47fefc);if(!_0x5d885c)return;if(!_0x5d885c[_0x4e092e(0x1ae)+_0x2f093c(0x216)]){console[_0x4e092e(0x203)](_0x2f093c(0x238)+_0x4e092e(0x21a)+_0x2f093c(0x1a7)+'ed');return;}const _0x4d2d30=readSnapshots(0x261e+-0x73d+0x627*-0x5),_0xbadc62=/crash|restart|loop|uptime/i[_0x4e092e(0x1ca)](_0x5d885c[_0x4e092e(0x1c9)+'n']);if(_0xbadc62&&!hasRealCrashEvidence(_0x4d2d30)&&hasRepresentativeUptime(_0x4d2d30)){console[_0x4e092e(0x203)](_0x4e092e(0x238)+_0x4e092e(0x236)+_0x4e092e(0x21e)+_0x5d885c[_0x2f093c(0x1c9)+'n']+_0x2f093c(0x160)+(_0x2f093c(0x17f)+_0x2f093c(0x1de)+_0x4e092e(0x178)+_0x2f093c(0x161)+_0x4e092e(0x18e)+'apshot\x20sho'+_0x2f093c(0x1b5))+(_0x4e092e(0x1b1)+_0x2f093c(0x19b)+_0x4e092e(0x22a)+STARTUP_TRANSIENT_S+('s);\x20the\x20pr'+_0x2f093c(0x1e7)))+('did\x20live\x20w'+_0x4e092e(0x1db)+_0x4e092e(0x190)+_0x2f093c(0x199)+_0x2f093c(0x1f3)+'w,\x20not\x20a\x20~'+_0x2f093c(0x1a5)));return;}if(_0xbadc62&&!hasRealCrashEvidence(_0x4d2d30)){console[_0x2f093c(0x203)](_0x4e092e(0x238)+_0x2f093c(0x236)+'sed\x20WARN\x20\x22'+_0x5d885c[_0x4e092e(0x1c9)+'n']+_0x2f093c(0x160)+(_0x2f093c(0x234)+_0x2f093c(0x208)+_0x4e092e(0x1ff)+_0x4e092e(0x1a2)+_0x2f093c(0x173)+'cross\x20all\x20'+_0x4e092e(0x1c0))+(_0x2f093c(0x215)+'e-restart-'+_0x4e092e(0x22d)+_0x2f093c(0x1f7)+_0x2f093c(0x16e)));return;}console[_0x4e092e(0x203)]('📊\x20Trends\x20A'+_0x2f093c(0x23b)+'\x20('+_0x5d885c['severity']+_0x4e092e(0x204)+_0x5d885c[_0x4e092e(0x1c9)+'n']),emitCritical({'category':_0x2f093c(0x1cb),'severity':_0x5d885c['severity']===_0x2f093c(0x1ed)?_0x4e092e(0x1ed):'warn','title':_0x2f093c(0x1e0)+'aly\x20detect'+_0x4e092e(0x198)+_0x5d885c['descriptio'+'n'],'detail':'30-day\x20tre'+_0x2f093c(0x18f)+_0x2f093c(0x1be)+'a\x20concerni'+_0x2f093c(0x1e4)+_0x2f093c(0x1a9)+(_0x2f093c(0x1cc)+':\x20'+_0x5d885c[_0x2f093c(0x1ce)]+'\x0a\x0a')+(_0x4e092e(0x1d1)+':\x20'+TRENDS_PATH),'suggestedAction':_0x5d885c['suggestion']});}catch(_0x35638a){console['warn'](_0x2f093c(0x22f)+_0x4e092e(0x16c)+_0x4e092e(0x23a)+(_0x35638a instanceof Error?_0x35638a[_0x2f093c(0x185)]:String(_0x35638a)));}}export function startTrendsCollector(_0x5f47e4){const _0x56907b=_0x1e479d,_0xeb1a0=_0x257576;if(isDisabled())return;const _0x40d6f9=parseInt(process[_0x56907b(0x196)][_0x56907b(0x19d)+'DS_INTERVA'+_0x56907b(0x1a1)]||'',0x1*0x25e3+0x19c3+0x3f9c*-0x1)||DEFAULT_INTERVAL_HOURS,_0x52366b=_0x40d6f9*(-0x220+0xe17+-0xbbb)*(0x10*0x10b+-0x9f*0x10+0x2*-0x342)*(0x4f*-0x59+0x591+-0x3*-0x89a);setTimeout(()=>{const _0x2ba069=_0xeb1a0,_0x13382e=_0xeb1a0;void dailyTask(_0x5f47e4),trendsTimer=setInterval(()=>void dailyTask(_0x5f47e4),_0x52366b);if(trendsTimer[_0x2ba069(0x1fb)])trendsTimer[_0x2ba069(0x1fb)]();},-0xe7*-0x66+0x16e1e+0x37f2*-0x4);}export function stopTrendsCollector(){trendsTimer&&(clearInterval(trendsTimer),trendsTimer=null);}
|