alvin-bot 5.6.2 → 5.8.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/CHANGELOG.md +29 -0
- package/README.md +1 -1
- 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 -130
- 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 -443
- 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 -0
- 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 -1831
- 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 _0x1a279d=_0x5b7b,_0xe19cfe=_0x5b7b;(function(_0x55b561,_0x4c8558){const _0xd15737=_0x5b7b,_0x434edb=_0x5b7b,_0x67d8b0=_0x55b561();while(!![]){try{const _0x63b41b=parseInt(_0xd15737(0x14a))/(-0xef2+0x1b62+-0xc6f)*(parseInt(_0x434edb(0x163))/(-0x3a5+0x3c3+-0x1c))+-parseInt(_0xd15737(0x1bb))/(0x72*-0x8+-0x62*0x3b+0x1a29)+parseInt(_0x434edb(0x13e))/(-0x1a9e+-0x598+-0x113*-0x1e)*(parseInt(_0xd15737(0x1be))/(0x2*-0xdf9+0x1481*-0x1+-0xc1e*-0x4))+-parseInt(_0x434edb(0x118))/(0x27b+-0x1*-0x24a0+-0x2715)*(parseInt(_0xd15737(0x178))/(0x1*0x1a61+0x3*-0x95c+-0xdd*-0x2))+-parseInt(_0x434edb(0x18e))/(-0x19+0x6bf+-0x69e)+-parseInt(_0xd15737(0x1d0))/(-0xb1e+0x19*0xf4+-0x1*0xcad)*(-parseInt(_0xd15737(0x135))/(-0x2f9*-0x4+-0x463+-0x777*0x1))+parseInt(_0xd15737(0x1a1))/(-0x14d6+0x1c87+-0x7a6)*(parseInt(_0xd15737(0x1c2))/(0x5cb*0x1+-0x1*0x117d+0xbbe));if(_0x63b41b===_0x4c8558)break;else _0x67d8b0['push'](_0x67d8b0['shift']());}catch(_0x17485d){_0x67d8b0['push'](_0x67d8b0['shift']());}}}(_0x378c,-0xa1c11*-0x1+0x17dd8+-0x18290));const _0x5849d1=(function(){let _0x53b997=!![];return function(_0x26b15,_0x55d6f4){const _0xe20e7a=_0x53b997?function(){const _0x15e755=_0x5b7b;if(_0x55d6f4){const _0x48863d=_0x55d6f4[_0x15e755(0x13c)](_0x26b15,arguments);return _0x55d6f4=null,_0x48863d;}}:function(){};return _0x53b997=![],_0xe20e7a;};}()),_0x1701a4=_0x5849d1(this,function(){const _0x344090=_0x5b7b,_0x46d778=_0x5b7b;return _0x1701a4[_0x344090(0x1c4)]()[_0x344090(0x196)](_0x46d778(0x13d)+'+$')['toString']()[_0x46d778(0x15a)+'r'](_0x1701a4)[_0x46d778(0x196)](_0x46d778(0x13d)+'+$');});_0x1701a4();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(),_0x1a279d(0x12a),_0x1a279d(0x127),_0xe19cfe(0x1d6)+'nl');function trendsStateDir(){const _0x3489cb=_0xe19cfe,_0x13a317=_0x1a279d,_0x2c6c9e=process[_0x3489cb(0x1af)][_0x3489cb(0x142)+'_DIR']||join(homedir(),_0x3489cb(0x12a));return join(_0x2c6c9e,_0x3489cb(0x127));}function uptimePeakPath(){const _0x2340e5=_0xe19cfe,_0x2ae018=_0xe19cfe;return join(trendsStateDir(),_0x2340e5(0x1bf)+_0x2340e5(0x154));}function _0x5b7b(_0x4ccbc3,_0x2d63bf){_0x4ccbc3=_0x4ccbc3-(-0xfe9*-0x2+0x1*-0x24a6+-0x1f9*-0x3);const _0x37736e=_0x378c();let _0x151773=_0x37736e[_0x4ccbc3];if(_0x5b7b['EYXVLV']===undefined){var _0x5229d6=function(_0x989e78){const _0x41b4ec='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x12ae4a='',_0x110a5e='',_0x5d9f64=_0x12ae4a+_0x5229d6;for(let _0x423e60=0x19d7+-0x3*-0x33+-0x1a70,_0x296c30,_0x52ea41,_0x316bcc=-0x1*-0x17db+-0x26*0xa8+0x115;_0x52ea41=_0x989e78['charAt'](_0x316bcc++);~_0x52ea41&&(_0x296c30=_0x423e60%(-0x1c48+-0xde6+0x2a32)?_0x296c30*(0x248b*-0x1+0x1*-0x1177+0x1cf*0x1e)+_0x52ea41:_0x52ea41,_0x423e60++%(0x71*0x35+-0x527*0x2+-0xd13))?_0x12ae4a+=_0x5d9f64['charCodeAt'](_0x316bcc+(-0x2f9*0x5+-0x1631+-0x946*-0x4))-(-0x53*0x37+0xaf3+-0x1*-0x6ec)!==-0xc12+0x2c*0xd0+-0x17ae?String['fromCharCode'](-0x215b+-0xa*-0x377+-0x4c&_0x296c30>>(-(0x15ba+-0x71*-0x1e+-0x32*0xb3)*_0x423e60&0x14b+-0x13c0+0xf9*0x13)):_0x423e60:-0x93c+0x20db+-0x179f*0x1){_0x52ea41=_0x41b4ec['indexOf'](_0x52ea41);}for(let _0x488c4c=0xcb3+0x1*-0x89+-0xc2a,_0x7d882c=_0x12ae4a['length'];_0x488c4c<_0x7d882c;_0x488c4c++){_0x110a5e+='%'+('00'+_0x12ae4a['charCodeAt'](_0x488c4c)['toString'](0x170a*0x1+-0x2035+0x93b*0x1))['slice'](-(-0x101*0x21+0x1e10+-0x1*-0x313));}return decodeURIComponent(_0x110a5e);};_0x5b7b['cyXwFS']=_0x5229d6,_0x5b7b['fnXcNe']={},_0x5b7b['EYXVLV']=!![];}const _0xd7cd2e=_0x37736e[0x545+-0x3*0x607+0x28*0x52],_0xca22cd=_0x4ccbc3+_0xd7cd2e,_0x55109b=_0x5b7b['fnXcNe'][_0xca22cd];if(!_0x55109b){const _0x4bec3a=function(_0x3250e1){this['WAVLMg']=_0x3250e1,this['hjSxEV']=[-0x1009+-0xb5*0x27+-0x3f7*-0xb,-0x15f8+-0xe7f+-0x2477*-0x1,-0xa5e+0x15db+-0xb7d],this['CGESJP']=function(){return'newState';},this['BLUeJc']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['RSDWMH']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x4bec3a['prototype']['bLDQXe']=function(){const _0x47597d=new RegExp(this['BLUeJc']+this['RSDWMH']),_0x2d2369=_0x47597d['test'](this['CGESJP']['toString']())?--this['hjSxEV'][-0x1ba2+0x95c+0x1247]:--this['hjSxEV'][0x3e3+-0x1556*-0x1+-0x1939];return this['rzAIRs'](_0x2d2369);},_0x4bec3a['prototype']['rzAIRs']=function(_0x333d04){if(!Boolean(~_0x333d04))return _0x333d04;return this['GTtVAI'](this['WAVLMg']);},_0x4bec3a['prototype']['GTtVAI']=function(_0x4d2eb3){for(let _0xa6ee38=0x1640+0x225*0x3+-0x1caf,_0x29662e=this['hjSxEV']['length'];_0xa6ee38<_0x29662e;_0xa6ee38++){this['hjSxEV']['push'](Math['round'](Math['random']())),_0x29662e=this['hjSxEV']['length'];}return _0x4d2eb3(this['hjSxEV'][-0x249f+0x12e*-0x13+-0x7f*-0x77]);},new _0x4bec3a(_0x5b7b)['bLDQXe'](),_0x151773=_0x5b7b['cyXwFS'](_0x151773),_0x5b7b['fnXcNe'][_0xca22cd]=_0x151773;}else _0x151773=_0x55109b;return _0x151773;}export const STARTUP_TRANSIENT_S=-0x1e73+-0x1*-0x17db+-0x16*-0x68;function bumpAndReadUptimePeak(){const _0x325b72=_0x1a279d,_0xbf0e8d=_0x1a279d,_0x537087=Math['round'](process[_0x325b72(0x14f)]());let _0x1c9d2d=-0x12f7+-0x1c48+0x2f3f;try{const _0x355228=readFileSync(uptimePeakPath(),_0xbf0e8d(0x14e)),_0x27f3ba=JSON['parse'](_0x355228);typeof _0x27f3ba[_0x325b72(0x1cd)]===_0x325b72(0x173)&&Number['isFinite'](_0x27f3ba[_0xbf0e8d(0x1cd)])&&_0x27f3ba[_0xbf0e8d(0x1cd)]>-0x10dc+0x248b*-0x1+0x3*0x11cd&&(_0x1c9d2d=_0x27f3ba[_0x325b72(0x1cd)]);}catch{}const _0x5753a4=Math[_0x325b72(0x199)](_0x1c9d2d,_0x537087);try{mkdirSync(trendsStateDir(),{'recursive':!![]}),writeFileSync(uptimePeakPath(),JSON['stringify']({'peak_s':_0x5753a4}),_0xbf0e8d(0x14e));}catch{}return _0x5753a4;}const DEFAULT_INTERVAL_HOURS=-0x7*-0x4e5+0x1d7*0xb+-0x6cd*0x8,DEFAULT_AI_THRESHOLD_DAYS=-0x138b+-0x2f9*0x5+0x226f,MAX_RETAIN_DAYS=0x1cc5+0x1*-0x18bc+-0x3af;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 _0x220ab2=_0xe19cfe,_0x152b9f=_0x1a279d;return process['env'][_0x220ab2(0x17d)+_0x220ab2(0x150)]===_0x220ab2(0x153)||process[_0x220ab2(0x1af)]['ALVIN_DISA'+'BLE_SELF_P'+'RESERVATIO'+'N']===_0x220ab2(0x153);}function countLogLinesLast24h(_0x10cf3c,_0x546e88){const _0x525cc7=_0xe19cfe,_0x2fdd75=_0xe19cfe,_0x15c35c=join(homedir(),'.alvin-bot',_0x525cc7(0x12e),_0x10cf3c);if(!existsSync(_0x15c35c))return-0x176e+0x2436+-0x8*0x199;try{const _0x3c3e73=readFileSync(_0x15c35c,'utf-8'),_0x29e88d=Date[_0x2fdd75(0x164)]()-(0x1e57+0xed7+-0x168b*0x2)*(0x76d+0x2*-0x871+0x9b1)*(-0x61*-0x67+-0x6d*0x2f+-0x12c8)*(-0xb*0x1ea+-0x1*-0xae7+0xe0f);let _0x2252f1=-0x1*-0x1c0e+-0x225d+0x11*0x5f;for(const _0x81b0e3 of _0x3c3e73[_0x525cc7(0x158)]('\x0a')){const _0x361890=_0x81b0e3[_0x2fdd75(0x15d)](/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z)/);if(!_0x361890)continue;const _0x428df4=new Date(_0x361890[-0x572+0x170a*0x1+-0x1197])[_0x525cc7(0x11d)]();if(Number['isFinite'](_0x428df4)&&_0x428df4>=_0x29e88d){if(!_0x546e88||_0x546e88[_0x525cc7(0x19f)](_0x81b0e3))_0x2252f1++;}}return _0x2252f1;}catch{return 0xf91+0x24ac*0x1+-0x343d;}}function readWatchdogCrashes24h(){const _0x14fad5=_0x1a279d,_0xa9fabd=_0xe19cfe;try{const _0x30b4da=join(homedir(),_0x14fad5(0x12a),_0xa9fabd(0x127),'watchdog.j'+_0x14fad5(0x128));if(!existsSync(_0x30b4da))return-0x22a8+-0x2*-0x12cd+-0x2f2;const _0x5b3e62=JSON[_0x14fad5(0x1d9)](readFileSync(_0x30b4da,'utf-8'));return _0x5b3e62['dailyCrash'+'Count']??0x1*0xa61+-0x1185+0x724;}catch{return-0xa3e+-0x3d6*-0x2+0x292;}}function countDiagnosticBundlesLast24h(){const _0x1586b6=_0x1a279d,_0x5a7a35=_0xe19cfe;try{const _0x3a60b5=join(homedir(),_0x1586b6(0x12a),'diagnostic'+'s');if(!existsSync(_0x3a60b5))return-0xe7f+-0xb89*0x1+0x1a08;const {readdirSync:_0x47d1d1,statSync:_0x281364}=require('fs'),_0x2ef247=Date[_0x1586b6(0x164)]()-(0x15db+-0x17bc+0x1f9)*(0x95c+-0x1c07+0x64d*0x3)*(-0xb7c+0x18d2+0x3*-0x45e)*(-0xb*0x15f+0x19d3+-0x6d6);return _0x47d1d1(_0x3a60b5)[_0x5a7a35(0x197)](_0x2ceb4f=>_0x2ceb4f[_0x5a7a35(0x1ac)](_0x5a7a35(0x162))&&!_0x2ceb4f[_0x1586b6(0x1ac)](_0x1586b6(0x11a)+'md'))[_0x1586b6(0x197)](_0x2d1ea5=>{try{return _0x281364(join(_0x3a60b5,_0x2d1ea5))['mtimeMs']>=_0x2ef247;}catch{return![];}})['length'];}catch{return 0x49*-0x6c+0x13c7+-0x1*-0xb05;}}function takeSnapshot(_0x37dcba){const _0x476162=_0xe19cfe,_0x3d4bbc=_0x1a279d,_0x159157=process[_0x476162(0x151)+'e']();return{'ts':new Date()[_0x3d4bbc(0x16d)+'g'](),'uptime_s':Math[_0x476162(0x152)](process[_0x476162(0x14f)]()),'uptime_peak_s':bumpAndReadUptimePeak(),'rss_mb':Math[_0x3d4bbc(0x152)](_0x159157[_0x3d4bbc(0x1a3)]/(-0x90f*0x4+-0x15cb+-0x14ad*-0x3)/(0xec3+-0x17c4+-0x1*-0xd01)),'heap_mb':Math[_0x3d4bbc(0x152)](_0x159157[_0x476162(0x125)]/(-0x1cdd*-0x1+0x1*0x16b+-0x1*0x1a48)/(0x2e9+0x182a+-0x1713)),'crashes_24h':readWatchdogCrashes24h(),'diag_24h':countDiagnosticBundlesLast24h(),'errors_24h':countLogLinesLast24h(_0x3d4bbc(0x11c)+_0x476162(0x119),ERR_LOG_PATTERN),'provider':_0x37dcba,'version':BOT_VERSION};}function appendSnapshot(_0x160bfe){const _0x1293be=_0x1a279d;try{mkdirSync(dirname(TRENDS_PATH),{'recursive':!![]}),appendFileSync(TRENDS_PATH,JSON[_0x1293be(0x1b1)](_0x160bfe)+'\x0a');}catch{}}function readSnapshots(_0x38003d=-0x10d6+-0x1e83*-0x1+0x1*-0xd8f){const _0x204c13=_0xe19cfe,_0x54e105=_0x1a279d;if(!existsSync(TRENDS_PATH))return[];try{const _0xabe21a=readFileSync(TRENDS_PATH,_0x204c13(0x14e)),_0x59bcca=_0xabe21a['split']('\x0a')[_0x204c13(0x197)](_0x57cfc5=>_0x57cfc5[_0x54e105(0x11e)]()),_0x4cb2c0=_0x59bcca['slice'](-_0x38003d);return _0x4cb2c0['map'](_0x1ed5d1=>{const _0x4ddfa8=_0x54e105;try{return JSON[_0x4ddfa8(0x1d9)](_0x1ed5d1);}catch{return null;}})[_0x54e105(0x197)](_0x598f75=>_0x598f75!==null);}catch{return[];}}const TREND_PROMPT_TEMPLATE=_0xe19cfe(0x120)+_0xe19cfe(0x1b7)+'oring\x20an\x20A'+'lvin\x20Bot\x20i'+_0xe19cfe(0x156)+_0xe19cfe(0x160)+_0xe19cfe(0x1c9)+_0xe19cfe(0x15c)+_0xe19cfe(0x123)+_0xe19cfe(0x13b)+_0xe19cfe(0x1b9)+_0x1a279d(0x1a4)+_0xe19cfe(0x11f)+_0x1a279d(0x18a)+_0x1a279d(0x145)+_0x1a279d(0x19c)+_0x1a279d(0x16a)+_0xe19cfe(0x15b)+_0xe19cfe(0x188)+_0x1a279d(0x1bd)+'ke:\x0a\x20\x20-\x20Me'+'mory\x20(rss_'+_0xe19cfe(0x17a)+_0xe19cfe(0x1b2)+_0x1a279d(0x159)+_0x1a279d(0x1dc)+_0xe19cfe(0x143)+'(errors_24'+'h)\x20climbin'+_0x1a279d(0x136)+_0xe19cfe(0x1a7)+_0x1a279d(0x1cb)+'ove\x200\x20for\x20'+_0xe19cfe(0x1c0)+'ays\x0a\x20\x20-\x20Di'+_0xe19cfe(0x1b6)+_0x1a279d(0x190)+_0x1a279d(0x137)+_0xe19cfe(0x186)+_0x1a279d(0x165)+_0x1a279d(0x1ba)+_0xe19cfe(0x141)+_0xe19cfe(0x1d7)+_0x1a279d(0x130)+'EXACTLY\x20th'+_0x1a279d(0x182)+'e:\x0aANOMALY'+_0xe19cfe(0x1a2)+'\x20there\x20IS\x20'+_0xe19cfe(0x192)+_0xe19cfe(0x1b5)+'respond\x20in'+'\x20this\x203-li'+_0xe19cfe(0x155)+'—\x20nothing\x20'+_0x1a279d(0x16b)+_0xe19cfe(0x198)+_0xe19cfe(0x144)+_0xe19cfe(0x1a8)+_0xe19cfe(0x122)+'ou\x20noticed'+_0x1a279d(0x18d)+':\x20<warn\x20|\x20'+_0x1a279d(0x18c)+'SUGGESTION'+_0xe19cfe(0x1b8)+_0x1a279d(0x195)+_0x1a279d(0x1b4)+_0x1a279d(0x1c8)+_0x1a279d(0x134)+_0xe19cfe(0x1ad)+'AST\x20{N}\x20DA'+_0x1a279d(0x129)+_0xe19cfe(0x146)+_0xe19cfe(0x1a9)+'}\x0a---\x20END\x20'+_0xe19cfe(0x15f);function _0x378c(){const _0x10e861=['DgHLig9WzxjHDa','mtbwCNnyEwy','zWOGic0Gq3jHCW','ywDFmJrOksa+ia','BMCGCgf0DgvYBG','zg9Uzq','oLXZkIGUkZ8Pja','ihbLCIbKyxKGDW','yxbWBhK','kcGOlISPkYKRkq','mZuYAgjNwM1Y','ywjVCNq','C3rHCNqGC2fTCa','B25JzxjUAw5Nia','quXwsu5Frefuqq','CNjVCIbYyxrLia','ihnOB3j0ihnLBG','zwn0igfUEsbdtW','u0HpvfmGls0TcG','BM8Gy29Uy2vYBG','C3rYAw5N','zwq6ia','nJy3ugTXvLD3','8j+tIIbuCMvUzhmGqq','lGOk','uL9eqvLt','DxrMltG','Dxb0Aw1L','qKXfx1rsru5euW','BwvTB3j5vxnHzW','CM91BMq','Dhj1zq','AY5QC29U','BMuGzM9YBwf0ia','BNn0yw5JzsbVDG','rsbHC3nPC3rHBG','C3bSAxq','zYbKyxKGB3zLCG','y29UC3rYDwn0BW','C3vNz2vZDhmGCW','Bg93igLZig9Uzq','Bwf0y2G','DgHYzxC6ia','ls0T','zxiGDgHLigXHCW','yxj0ihbHDhrLCG','lM1K','mJa4ne1qDKvlDq','BM93','BhKkcKLMihrOzq','kg5Vihn1z2DLCW','Dxb0Aw1LicG+','ChjLy2LZzsbtuG','Dxb0Aw1Ll3jLCW','CMvUzcb0Agf0ia','zwXZztOkcKfotW','tKXzigLUihrOzq','Dg9ju09tDhjPBG','stOGC3vWChjLCW','Dxb0Aw1Lx3m','vhjLBMqGyw5VBq','z2v0qwn0AxzLsW','B2nLC3mG','BNvTyMvY','zs1Yzxn0yxj0lq','C3vNz2vZDgLVBG','y3jPDgLJywW','u3vNz2vZDgLVBG','mtrLEMrryuW','BM9Uzq','BwiGlYbOzwfWxW','nJjZigXVB3a','Dxb0Aw1Lx3bLyq','quXwsu5FreLtqq','u1vhr0vtveLptG','AxngAw5PDgu','BwvZC2fNzq','zgvZy3jPChrPBW','AxmGB25LigXPBG','CYbMBgfNz2vKia','C2GGBg9VCcK','zxjYB3jZxZi0Aa','mcbYzxbLyxrLza','C25HChnOB3rZia','Bg93igrLz3jHza','CMvWCMvZzw50yq','CMLJCY4kcKrLDa','Dg9mB3DLCKnHCW','y3jPDgLJywW+cG','pGPtrvzfuKLuwq','ntC4mtqXnNL5yujLyW','8j+tIIbuCMvUzhmGCW','Dw5KBgvZicHKAq','Dw5Yzwy','ysbJB25JzxjUAq','y3jHC2GVCMvZDa','Bg9N','BgWGy29TBwfUza','C2vHCMnO','zMLSDgvY','tufmwtOGpg9Uzq','Bwf4','C29Tzq','CM4GzMXHz2DLza','tKnfuK5jtKCGDa','zxjYB3i','BwfW','DgvZDa','C2vKifDbuK4GiG','oti1nZq0nKLpu3z2wq','oIbot05fcGPjzG','CNnZ','DcDZigrHAwX5ia','zgv0zwn0zwq','yw5VBwfSEurLDa','AgvZicHJCMfZAa','DgvUy2uG4OcuihDO','E1noqvbtse9uuW','CMvWBgfJzq','D2fYBG','zw5KC1DPDgG','B3i+cGOTls0Gta','ww91igfYzsbHia','zw52','DhLWzq','C3rYAw5NAwz5','BwiPigDYB3DPBG','stOGBM8Gyw5VBq','ie9sig9IC2vYDG','BMCGDhjLBMqSia','ywDUB3n0AwmGyG','ifnsrsbTB25PDa','oIa8B25LihnOzq','AxrOihrOzsbIBW','CMuGAxmGtK8GyW','mZeWnZeXnw5kBfH5BG','C2LNBMfS','yxrPB24G4OcuigXP','mZG3nJvwy0zTr0i','Dxb0Aw1LlxbLyq','BxvSDgLWBguGza','tuiGzxjYB3jZpq','mtjdC3DXz3K','A19Z','Dg9tDhjPBMC','BMfWC2HVDcb0yq','ywX5igrLDgvJDa','D3mGysa','yxrPB24GzM9Yia','DcbKyxLZlGPczq','Aw5NihrYzw5Kia','zxnFmJrOksbHyG','y3jVC3mGywXSia','CgvHA19Z','ywLSEsb0yxnRia','rfnFquLFquzurq','nZGXnda0m0PoCe9VvW','vhjLBMqGzgf0yq','yxn0ig9UzsbZBG','tf9it1vsuW','iIdIGjqG','ChrPB24P','DhjLBMrZlMPZBW','DhjLBMqSihjLCW','BM8Ty3jHC2GTzq','CgfYC2u','quXwsu5FvfjftG','BgvUz3rO','igrHEqOGic0Grq','CNnZx21I','igj1DcbHDcbSzq','mJaWmJeXnLvTuuzAtq','zxjYlMXVzW','lMfUywX5C2LZlG','zgLKigXPDMuGDW','ywX2Aw4TyM90lG','z2v0vgLTzq','DhjPBq','AgvHBhrOig1LDa','ww91igfYzsbHBG','u0vwrvjjvfK','yxqGDhjLBMqGEq','iePtt04GBgLUzq','AM9PBG','AgvHCfvZzwq','DYWGBM90igeGFG','C3rHDgu','C29U','wvmGt0yGu05bua','lMfSDMLUlwjVDa','Dgv4Da','BIbKzxrLy3rLza','zwn0zwq','Bg9NCW','BgLUzYb3Aw5KBW','Cg9Uzcb3AxrOia','ihjLCxvLC3rLza','y3vZDg9T','y3jHC2HLC18Yna'];_0x378c=function(){return _0x10e861;};return _0x378c();}export const RECENT_CRASH_WINDOW_MS=(-0x2a*-0x77+-0x15d3+0x27d)*(0x1*-0x14f1+-0xaeb+0x2018)*(0x1*0x25c6+0x24d*0x7+-0x35a5)*(-0x9b1+0x1f18+-0x117f);export function hasRealCrashEvidence(_0x3126cd,_0x1b1069=Date['now']()){const _0x281f26=_0x1a279d,_0x276d78=_0x1b1069-RECENT_CRASH_WINDOW_MS;return _0x3126cd[_0x281f26(0x19a)](_0x3d8686=>{const _0x24f65b=_0x281f26,_0x528649=_0x281f26;if(!(typeof _0x3d8686[_0x24f65b(0x133)+'h']===_0x24f65b(0x173)&&_0x3d8686['crashes_24'+'h']>-0x116e+0x1535*0x1+0x3c7*-0x1))return![];if(typeof _0x3d8686['ts']!==_0x24f65b(0x148))return!![];const _0xded71d=Date[_0x528649(0x1d9)](_0x3d8686['ts']);if(!Number['isFinite'](_0xded71d))return!![];return _0xded71d>=_0x276d78;});}export function hasRepresentativeUptime(_0x1c2e1d){const _0x433d4f=_0x1a279d;return _0x1c2e1d[_0x433d4f(0x19a)](_0x3c7938=>{const _0x38f3af=_0x433d4f,_0x5c027e=_0x433d4f,_0x486b16=typeof _0x3c7938[_0x38f3af(0x17c)+_0x38f3af(0x1c3)]===_0x38f3af(0x173)&&Number[_0x38f3af(0x17f)](_0x3c7938[_0x38f3af(0x17c)+_0x5c027e(0x1c3)])?_0x3c7938[_0x5c027e(0x17c)+_0x5c027e(0x1c3)]:typeof _0x3c7938[_0x5c027e(0x16f)]===_0x38f3af(0x173)&&Number[_0x5c027e(0x17f)](_0x3c7938['uptime_s'])?_0x3c7938[_0x38f3af(0x16f)]:0x1fc2+0x3fe*-0x7+-0x3d0;return _0x486b16>STARTUP_TRANSIENT_S;});}export function evaluateCrashRestartSuppression(_0x1cb76e,_0x6b664f){const _0x178414=_0x1a279d,_0x566607=_0xe19cfe;if(!_0x1cb76e)return _0x178414(0x179);const _0x3bfab2=hasRealCrashEvidence(_0x6b664f);if(!_0x3bfab2&&hasRepresentativeUptime(_0x6b664f))return _0x178414(0x189)+'tive-uptim'+'e';if(!_0x3bfab2)return _0x566607(0x1d8)+'vidence';return _0x178414(0x179);}export function __takeSnapshotForTest(_0x1682a8){return takeSnapshot(_0x1682a8);}function parseTrendResponse(_0x136023){const _0x15d8bb=_0x1a279d,_0x59b044=_0x1a279d;if(/^ANOMALY:\s*NONE/im[_0x15d8bb(0x19f)](_0x136023))return{'anomalyDetected':![],'description':_0x15d8bb(0x147)+_0x15d8bb(0x1ca)+_0x59b044(0x1a5),'severity':'none','suggestion':'','raw':_0x136023};const _0x18b7cb=_0x23458d=>{const _0x33bc8f=_0x59b044,_0x4dfa04=_0x15d8bb,_0x17b34d=_0x136023['match'](new RegExp('^'+_0x23458d+_0x33bc8f(0x13a),'m'));return _0x17b34d?_0x17b34d[-0x4*0xb9+-0x3*-0xab9+-0x2*0xea3][_0x33bc8f(0x11e)]():'';},_0xb28436=_0x18b7cb(_0x15d8bb(0x121))[_0x15d8bb(0x18b)+'e'](),_0x16fb89=_0xb28436==='critical'?_0x59b044(0x176):'warn';return{'anomalyDetected':!![],'description':_0x18b7cb('ANOMALY')||'(no\x20descri'+_0x15d8bb(0x1d5),'severity':_0x16fb89,'suggestion':_0x18b7cb(_0x59b044(0x17e))||_0x15d8bb(0x166)+'tion)','raw':_0x136023};}export async function analyzeTrends(_0x3daa0a){const _0x21035a=_0x1a279d,_0x518e32=_0xe19cfe;if(isDisabled())return null;if(!_0x3daa0a)return null;const _0x12a1c9=readSnapshots(-0x27*0x34+-0x76*-0x37+-0x1150),_0x2b19a6=parseInt(process['env'][_0x21035a(0x1da)+_0x518e32(0x1cf)+_0x518e32(0x14d)]||'',0x24fc+0x26+-0x2*0x128c)||DEFAULT_AI_THRESHOLD_DAYS;if(_0x12a1c9[_0x21035a(0x1db)]<_0x2b19a6)return null;let _0x56f847;try{_0x56f847=_0x3daa0a['getActive']();}catch{return null;}if(!_0x56f847)return null;const _0x4d69fe=_0x12a1c9[_0x518e32(0x19e)](_0x3d5e98=>JSON['stringify'](_0x3d5e98))[_0x21035a(0x124)]('\x0a'),_0x4127de=TREND_PROMPT_TEMPLATE[_0x518e32(0x1aa)]('{N}',String(_0x12a1c9[_0x21035a(0x1db)]))[_0x518e32(0x1aa)](_0x518e32(0x1a9)+'}',_0x4d69fe),_0x3380f8=new AbortController(),_0x37aad4=setTimeout(()=>_0x3380f8[_0x21035a(0x13f)](),0xe9f7+-0xebe2*0x1+0xec4b);let _0x2e380b='';try{for await(const _0x3094f3 of _0x56f847['query']({'prompt':_0x4127de,'systemPrompt':_0x21035a(0x1ae)+_0x21035a(0x168)+_0x21035a(0x157)+'t.\x20Reply\x20O'+_0x21035a(0x16c)+_0x518e32(0x131)+'\x20format.','abortSignal':_0x3380f8[_0x518e32(0x1bc)]})){if(_0x3094f3[_0x518e32(0x1b0)]===_0x518e32(0x12b)){if(_0x3094f3['delta'])_0x2e380b+=_0x3094f3['delta'];else{if(_0x3094f3[_0x21035a(0x12b)])_0x2e380b=_0x3094f3[_0x518e32(0x12b)];}}else{if(_0x3094f3[_0x518e32(0x1b0)]===_0x518e32(0x19d))return clearTimeout(_0x37aad4),null;else{if(_0x3094f3['type']===_0x21035a(0x139)){if(_0x3094f3[_0x518e32(0x12b)])_0x2e380b=_0x3094f3[_0x21035a(0x12b)];break;}}}}}catch{return clearTimeout(_0x37aad4),null;}clearTimeout(_0x37aad4);if(!_0x2e380b[_0x21035a(0x11e)]())return null;return parseTrendResponse(_0x2e380b);}async function dailyTask(_0x370cc6){const _0x113b8d=_0xe19cfe,_0xd07807=_0xe19cfe;try{const _0x491aa0=((()=>{const _0x1dca0c=_0x5b7b,_0x13ae25=_0x5b7b;try{return _0x370cc6?.[_0x1dca0c(0x171)+'ey']()||_0x1dca0c(0x179);}catch{return _0x1dca0c(0x179);}})()),_0x34ed2b=takeSnapshot(_0x491aa0);appendSnapshot(_0x34ed2b),console[_0x113b8d(0x194)](_0xd07807(0x18f)+_0xd07807(0x1c5)+'ken:\x20rss='+_0x34ed2b[_0x113b8d(0x1dd)]+_0xd07807(0x1c1)+_0x34ed2b[_0x113b8d(0x185)]+'\x20crashes='+_0x34ed2b[_0xd07807(0x133)+'h']);const _0x48723b=await analyzeTrends(_0x370cc6);if(!_0x48723b)return;if(!_0x48723b[_0x113b8d(0x1a6)+_0xd07807(0x12d)]){console[_0x113b8d(0x194)](_0xd07807(0x14b)+_0xd07807(0x1b3)+_0x113b8d(0x1c6)+'ed');return;}const _0x12d8de=readSnapshots(0x1c1b+0x14e4+0x81*-0x61),_0xb36846=/crash|restart|loop|uptime/i[_0xd07807(0x19f)](_0x48723b[_0x113b8d(0x181)+'n']);if(_0xb36846&&!hasRealCrashEvidence(_0x12d8de)&&hasRepresentativeUptime(_0x12d8de)){console[_0xd07807(0x194)](_0x113b8d(0x14b)+_0xd07807(0x16e)+_0x113b8d(0x1a0)+_0x48723b[_0xd07807(0x181)+'n']+_0xd07807(0x1d4)+(_0x113b8d(0x169)+'tart\x20patte'+_0x113b8d(0x19b)+_0xd07807(0x117)+_0x113b8d(0x1d2)+'apshot\x20sho'+_0xd07807(0x1c7))+(_0x113b8d(0x189)+'tive\x20peak\x20'+_0xd07807(0x167)+STARTUP_TRANSIENT_S+('s);\x20the\x20pr'+_0x113b8d(0x172)))+(_0xd07807(0x11b)+'ell\x20past\x20t'+'he\x20post-re'+_0x113b8d(0x140)+_0xd07807(0x12f)+_0x113b8d(0x126)+_0xd07807(0x17b)));return;}if(_0xb36846&&!hasRealCrashEvidence(_0x12d8de)){console['log'](_0x113b8d(0x14b)+_0x113b8d(0x16e)+'sed\x20WARN\x20\x22'+_0x48723b[_0xd07807(0x181)+'n']+_0xd07807(0x1d4)+(_0x113b8d(0x193)+_0x113b8d(0x161)+_0xd07807(0x12c)+'\x20but\x20crash'+'es_24h=0\x20a'+_0x113b8d(0x1cc)+_0xd07807(0x187))+('(deliberat'+_0x113b8d(0x174)+'only,\x20not\x20'+'a\x20real\x20cra'+_0x113b8d(0x184)));return;}console[_0xd07807(0x194)](_0xd07807(0x14b)+'I:\x20ANOMALY'+'\x20('+_0x48723b['severity']+')\x20—\x20'+_0x48723b[_0xd07807(0x181)+'n']),emitCritical({'category':_0x113b8d(0x132),'severity':_0x48723b['severity']===_0xd07807(0x176)?_0xd07807(0x176):_0x113b8d(0x1ab),'title':_0xd07807(0x170)+_0x113b8d(0x1c6)+_0x113b8d(0x149)+_0x48723b[_0xd07807(0x181)+'n'],'detail':'30-day\x20tre'+'nd\x20analysi'+_0x113b8d(0x183)+_0xd07807(0x192)+_0xd07807(0x138)+_0x113b8d(0x14c)+(_0xd07807(0x177)+':\x20'+_0x48723b[_0x113b8d(0x175)]+'\x0a\x0a')+(_0x113b8d(0x1d1)+':\x20'+TRENDS_PATH),'suggestedAction':_0x48723b[_0xd07807(0x175)]});}catch(_0x40fbde){console[_0xd07807(0x1ab)]('📊\x20Trends\x20d'+_0x113b8d(0x1ce)+_0x113b8d(0x15e)+(_0x40fbde instanceof Error?_0x40fbde[_0x113b8d(0x180)]:String(_0x40fbde)));}}export function startTrendsCollector(_0x12d4ce){const _0x1a5841=_0xe19cfe,_0x5019cc=_0xe19cfe;if(isDisabled())return;const _0x1e29cf=parseInt(process[_0x1a5841(0x1af)]['ALVIN_TREN'+'DS_INTERVA'+_0x1a5841(0x1d3)]||'',0xe0d+-0x23d*0x2+-0x989)||DEFAULT_INTERVAL_HOURS,_0x20a82f=_0x1e29cf*(0x1*0x1bd7+0xeeb+-0x1*0x2a86)*(-0x252b+0x1*-0x24d7+0x4a3e)*(-0xa12*-0x1+0xbe*0x17+-0x173c);setTimeout(()=>{const _0x69135=_0x5019cc;void dailyTask(_0x12d4ce),trendsTimer=setInterval(()=>void dailyTask(_0x12d4ce),_0x20a82f);if(trendsTimer['unref'])trendsTimer[_0x69135(0x191)]();},-0x3*-0x2315+0x55cd+-0x2b54*-0x1);}export function stopTrendsCollector(){trendsTimer&&(clearInterval(trendsTimer),trendsTimer=null);}
|