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
|
@@ -1,311 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Internal Watchdog — Self-monitoring for crash-loop detection.
|
|
3
|
-
*
|
|
4
|
-
* Writes a liveness beacon file every 30 s with the current pid + boot
|
|
5
|
-
* time + crash counter. On startup, reads the beacon to detect whether
|
|
6
|
-
* the previous process exited cleanly or crashed. If too many crashes
|
|
7
|
-
* happen in a short window, refuses to keep restarting and writes an
|
|
8
|
-
* alert file so the user can investigate.
|
|
9
|
-
*
|
|
10
|
-
* Persistence layers this complements:
|
|
11
|
-
* - launchd KeepAlive: true → restarts on any exit (good)
|
|
12
|
-
* - ThrottleInterval: 5 → minimum 5 s between restarts (good)
|
|
13
|
-
* - This watchdog → caps the total restart count so we
|
|
14
|
-
* don't burn CPU on a truly broken state
|
|
15
|
-
*
|
|
16
|
-
* What this CAN catch:
|
|
17
|
-
* - Process crash → exit non-zero → launchd restarts → next boot reads
|
|
18
|
-
* beacon, sees a recent exit, increments crash counter
|
|
19
|
-
* - Tight crash loop → counter accumulates → hits brake at 10
|
|
20
|
-
*
|
|
21
|
-
* What this CANNOT catch (yet):
|
|
22
|
-
* - True event-loop deadlocks (process alive but frozen). That requires
|
|
23
|
-
* an external watchdog process — tracked as a follow-up.
|
|
24
|
-
*/
|
|
25
|
-
import fs from "fs";
|
|
26
|
-
import { resolve } from "path";
|
|
27
|
-
import os from "os";
|
|
28
|
-
import { execSync } from "child_process";
|
|
29
|
-
import { BOT_VERSION } from "../version.js";
|
|
30
|
-
import { emitCritical } from "./critical-notify.js";
|
|
31
|
-
import { writeDiagnosticBundle } from "./auto-diagnostic.js";
|
|
32
|
-
import { decideBrakeAction, shouldResetCrashCounter, normalizeBeacon, DEFAULTS, } from "./watchdog-brake.js";
|
|
33
|
-
const DATA_DIR = process.env.ALVIN_DATA_DIR || resolve(os.homedir(), ".alvin-bot");
|
|
34
|
-
const STATE_DIR = resolve(DATA_DIR, "state");
|
|
35
|
-
const BEACON_FILE = resolve(STATE_DIR, "watchdog.json");
|
|
36
|
-
const ALERT_FILE = resolve(STATE_DIR, "crash-loop.alert");
|
|
37
|
-
const BEACON_INTERVAL_MS = 30_000; // write a beacon every 30 s
|
|
38
|
-
// Thresholds and windows live in watchdog-brake.ts DEFAULTS.
|
|
39
|
-
let beaconTimer = null;
|
|
40
|
-
let resetTimer = null;
|
|
41
|
-
let bootTime = 0;
|
|
42
|
-
/** Captured in startWatchdog(): did the previous process exit via a
|
|
43
|
-
* controlled restart? Read by the cron scheduler for fast-resume. */
|
|
44
|
-
let bootExpectedRestart = false;
|
|
45
|
-
/**
|
|
46
|
-
* True when this boot was preceded by a *controlled* restart
|
|
47
|
-
* (`markExpectedRestart` had set the beacon flag) rather than a crash.
|
|
48
|
-
* Returns false until startWatchdog() has run, and false after a crash —
|
|
49
|
-
* the safe default (no fast-resume) in both cases.
|
|
50
|
-
*/
|
|
51
|
-
export function bootWasExpectedRestart() {
|
|
52
|
-
return bootExpectedRestart;
|
|
53
|
-
}
|
|
54
|
-
function ensureStateDir() {
|
|
55
|
-
try {
|
|
56
|
-
fs.mkdirSync(STATE_DIR, { recursive: true });
|
|
57
|
-
}
|
|
58
|
-
catch (err) {
|
|
59
|
-
console.error("[watchdog] failed to create state dir:", err);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
function readBeacon() {
|
|
63
|
-
try {
|
|
64
|
-
const raw = fs.readFileSync(BEACON_FILE, "utf-8");
|
|
65
|
-
return normalizeBeacon(JSON.parse(raw));
|
|
66
|
-
}
|
|
67
|
-
catch {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
function writeBeacon(data) {
|
|
72
|
-
try {
|
|
73
|
-
fs.writeFileSync(BEACON_FILE, JSON.stringify(data, null, 0), "utf-8");
|
|
74
|
-
}
|
|
75
|
-
catch (err) {
|
|
76
|
-
console.error("[watchdog] failed to write beacon:", err);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Mark the imminent process exit as an INTENTIONAL restart so the next
|
|
81
|
-
* boot's decideBrakeAction does not count it as a crash. Called by the
|
|
82
|
-
* updater right before process.exit(0) for auto-update / `/update`.
|
|
83
|
-
*
|
|
84
|
-
* Read-modify-write: preserves the live crash counters; only flips the
|
|
85
|
-
* expectedRestart flag. Best-effort and synchronous — if the beacon
|
|
86
|
-
* can't be read (first run, disk issue) we simply skip; worst case the
|
|
87
|
-
* restart is counted as one crash, which is the pre-fix behavior.
|
|
88
|
-
*/
|
|
89
|
-
export function markExpectedRestart() {
|
|
90
|
-
const current = readBeacon();
|
|
91
|
-
if (!current)
|
|
92
|
-
return;
|
|
93
|
-
writeBeacon({ ...current, lastBeat: Date.now(), expectedRestart: true });
|
|
94
|
-
}
|
|
95
|
-
function writeAlert(reason, crashCount) {
|
|
96
|
-
try {
|
|
97
|
-
const content = [
|
|
98
|
-
`Alvin Bot crash-loop brake hit at ${new Date().toISOString()}`,
|
|
99
|
-
`Version: ${BOT_VERSION}`,
|
|
100
|
-
`Crashes in the last ${DEFAULTS.SHORT_WINDOW_MS / 60_000} minutes: ${crashCount}`,
|
|
101
|
-
`Short-window threshold: ${DEFAULTS.SHORT_BRAKE_THRESHOLD}`,
|
|
102
|
-
`Daily threshold: ${DEFAULTS.DAILY_BRAKE_THRESHOLD}`,
|
|
103
|
-
``,
|
|
104
|
-
`Reason: ${reason}`,
|
|
105
|
-
``,
|
|
106
|
-
`The bot will refuse to start until this file is removed AND the`,
|
|
107
|
-
`LaunchAgent is reloaded. Investigate the recent error log:`,
|
|
108
|
-
` ${resolve(DATA_DIR, "logs", "alvin-bot.err.log")}`,
|
|
109
|
-
``,
|
|
110
|
-
`Recovery steps once you've fixed the underlying issue:`,
|
|
111
|
-
` rm "${ALERT_FILE}"`,
|
|
112
|
-
` alvin-bot launchd install # or just kickstart the service`,
|
|
113
|
-
``,
|
|
114
|
-
].join("\n");
|
|
115
|
-
fs.writeFileSync(ALERT_FILE, content, "utf-8");
|
|
116
|
-
}
|
|
117
|
-
catch (err) {
|
|
118
|
-
console.error("[watchdog] failed to write alert:", err);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Check whether the watchdog has hit the crash-loop brake. Called once
|
|
123
|
-
* at startup, BEFORE most of the bot initializes. If the brake is set
|
|
124
|
-
* (alert file exists), the bot exits cleanly with code 3 — and because
|
|
125
|
-
* launchd's KeepAlive will keep retrying, we also try to unload our
|
|
126
|
-
* own LaunchAgent so the retries stop.
|
|
127
|
-
*/
|
|
128
|
-
export function checkCrashLoopBrake() {
|
|
129
|
-
if (!fs.existsSync(ALERT_FILE))
|
|
130
|
-
return;
|
|
131
|
-
console.error("");
|
|
132
|
-
console.error("==================================================");
|
|
133
|
-
console.error("⛔ alvin-bot crash-loop brake is engaged");
|
|
134
|
-
console.error("==================================================");
|
|
135
|
-
try {
|
|
136
|
-
const content = fs.readFileSync(ALERT_FILE, "utf-8");
|
|
137
|
-
console.error(content);
|
|
138
|
-
}
|
|
139
|
-
catch { /* ignore */ }
|
|
140
|
-
// Attempt to unload our own LaunchAgent so launchd stops retrying.
|
|
141
|
-
// If we don't do this, launchd just KeepAlive's us forever and we
|
|
142
|
-
// burn CPU writing the same alert.
|
|
143
|
-
if (process.platform === "darwin") {
|
|
144
|
-
try {
|
|
145
|
-
const home = os.homedir();
|
|
146
|
-
const plistPath = resolve(home, "Library", "LaunchAgents", "com.alvinbot.app.plist");
|
|
147
|
-
if (fs.existsSync(plistPath)) {
|
|
148
|
-
execSync(`launchctl unload -w "${plistPath}"`, { stdio: "pipe" });
|
|
149
|
-
console.error("[watchdog] LaunchAgent unloaded — bot will not auto-restart.");
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
catch (err) {
|
|
153
|
-
console.error("[watchdog] failed to unload LaunchAgent:", err);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// Exit with a distinct code so logs make the cause obvious
|
|
157
|
-
process.exit(3);
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Start the watchdog. Called from src/index.ts after all services are
|
|
161
|
-
* initialized. Reads the previous beacon, increments crash counter if
|
|
162
|
-
* the previous run exited recently, schedules the periodic beacon
|
|
163
|
-
* writer, and schedules a recovery-mark reset after RECOVERY_UPTIME_MS
|
|
164
|
-
* of clean uptime.
|
|
165
|
-
*/
|
|
166
|
-
export function startWatchdog() {
|
|
167
|
-
ensureStateDir();
|
|
168
|
-
bootTime = Date.now();
|
|
169
|
-
const previous = readBeacon();
|
|
170
|
-
// Capture whether the *previous* process exited via a controlled
|
|
171
|
-
// restart (markExpectedRestart set the flag) BEFORE writeBeacon below
|
|
172
|
-
// resets it. The cron scheduler uses this to fast-resume a job that a
|
|
173
|
-
// controlled restart interrupted, while never resuming after a crash.
|
|
174
|
-
bootExpectedRestart = previous?.expectedRestart === true;
|
|
175
|
-
const decision = decideBrakeAction(previous, bootTime);
|
|
176
|
-
if (decision.action === "brake") {
|
|
177
|
-
console.error(`[watchdog] crash-loop brake triggered: ${decision.reason}`);
|
|
178
|
-
writeAlert(decision.reason, previous?.crashCount ?? 0);
|
|
179
|
-
// Critical-event notify (Self-Preservation Phase 1, feature 1D).
|
|
180
|
-
// emitCritical is synchronous-fast (file flag + osascript inline)
|
|
181
|
-
// and schedules a detached Telegram DM via curl that survives the
|
|
182
|
-
// process.exit(3) below — exactly the case this mechanism was
|
|
183
|
-
// built for.
|
|
184
|
-
// Auto-diagnostic (feature 2F) — collect forensic bundle BEFORE
|
|
185
|
-
// emitCritical so the Telegram DM can reference the file path.
|
|
186
|
-
let bundlePath = null;
|
|
187
|
-
try {
|
|
188
|
-
bundlePath = writeDiagnosticBundle({
|
|
189
|
-
category: "watchdog-brake",
|
|
190
|
-
severity: "critical",
|
|
191
|
-
title: "Watchdog crash-loop brake engaged",
|
|
192
|
-
detail: `${decision.reason}\n` +
|
|
193
|
-
`Bot version: ${BOT_VERSION}`,
|
|
194
|
-
suggestedAction: `rm "${ALERT_FILE}" && alvin-bot launchd install`,
|
|
195
|
-
});
|
|
196
|
-
if (bundlePath) {
|
|
197
|
-
console.error(`[auto-diagnostic] forensic bundle written: ${bundlePath}`);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
catch (err) {
|
|
201
|
-
console.error("[watchdog] auto-diagnostic failed:", err);
|
|
202
|
-
}
|
|
203
|
-
try {
|
|
204
|
-
emitCritical({
|
|
205
|
-
category: "watchdog-brake",
|
|
206
|
-
severity: "critical",
|
|
207
|
-
title: "Watchdog crash-loop brake engaged",
|
|
208
|
-
detail: `${decision.reason}\n` +
|
|
209
|
-
`Bot version: ${BOT_VERSION}\n` +
|
|
210
|
-
`The bot has stopped itself to prevent further damage.` +
|
|
211
|
-
(bundlePath ? `\n\nDiagnostic bundle: ${bundlePath}` : ""),
|
|
212
|
-
suggestedAction: `rm "${ALERT_FILE}" && alvin-bot launchd install`,
|
|
213
|
-
}, {
|
|
214
|
-
// We're about to process.exit(3). Block on the Telegram POST
|
|
215
|
-
// synchronously — detached spawn races the exit on macOS+launchd
|
|
216
|
-
// and the alert silently never lands. Adds ~1-2 s before exit;
|
|
217
|
-
// worth it to actually inform the user their bot just braked.
|
|
218
|
-
blockTelegram: true,
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
catch (err) {
|
|
222
|
-
console.error("[watchdog] critical-notify failed:", err);
|
|
223
|
-
}
|
|
224
|
-
// checkCrashLoopBrake tries to unload the LaunchAgent so launchd stops
|
|
225
|
-
// retrying. It only runs the exit path if ALERT_FILE exists, which is
|
|
226
|
-
// normally true after writeAlert — but if writeAlert failed silently
|
|
227
|
-
// (disk full, permissions), we MUST still halt this boot. The trailing
|
|
228
|
-
// process.exit(3) below is the mandatory guarantee.
|
|
229
|
-
checkCrashLoopBrake();
|
|
230
|
-
process.exit(3);
|
|
231
|
-
}
|
|
232
|
-
let crashCount = decision.crashCount;
|
|
233
|
-
let crashWindowStart = decision.crashWindowStart;
|
|
234
|
-
let dailyCrashCount = decision.dailyCrashCount;
|
|
235
|
-
let dailyCrashWindowStart = decision.dailyCrashWindowStart;
|
|
236
|
-
if (previous) {
|
|
237
|
-
const timeSinceLastBeat = bootTime - previous.lastBeat;
|
|
238
|
-
if (timeSinceLastBeat < DEFAULTS.STALE_BEACON_MS) {
|
|
239
|
-
console.log(`[watchdog] detected restart after ${Math.round(timeSinceLastBeat / 1000)}s — ` +
|
|
240
|
-
`crash ${crashCount}/${DEFAULTS.SHORT_BRAKE_THRESHOLD} in current ` +
|
|
241
|
-
`${DEFAULTS.SHORT_WINDOW_MS / 60_000}min window, ` +
|
|
242
|
-
`${dailyCrashCount}/${DEFAULTS.DAILY_BRAKE_THRESHOLD} in current 24h window`);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
// Write the first beacon immediately so a fresh restart updates the file
|
|
246
|
-
writeBeacon({
|
|
247
|
-
lastBeat: bootTime,
|
|
248
|
-
pid: process.pid,
|
|
249
|
-
bootTime,
|
|
250
|
-
crashCount,
|
|
251
|
-
crashWindowStart,
|
|
252
|
-
dailyCrashCount,
|
|
253
|
-
dailyCrashWindowStart,
|
|
254
|
-
version: BOT_VERSION,
|
|
255
|
-
});
|
|
256
|
-
// Periodic beacon writer
|
|
257
|
-
beaconTimer = setInterval(() => {
|
|
258
|
-
writeBeacon({
|
|
259
|
-
lastBeat: Date.now(),
|
|
260
|
-
pid: process.pid,
|
|
261
|
-
bootTime,
|
|
262
|
-
crashCount,
|
|
263
|
-
crashWindowStart,
|
|
264
|
-
dailyCrashCount,
|
|
265
|
-
dailyCrashWindowStart,
|
|
266
|
-
version: BOT_VERSION,
|
|
267
|
-
});
|
|
268
|
-
}, BEACON_INTERVAL_MS);
|
|
269
|
-
// Schedule a recovery counter reset after RESET_AFTER_MS (1 h by default)
|
|
270
|
-
// of clean uptime. The old policy was 5 min — too short because chronic
|
|
271
|
-
// crashes often had 5-10 min gaps and never tripped the brake.
|
|
272
|
-
resetTimer = setTimeout(() => {
|
|
273
|
-
const uptime = Date.now() - bootTime;
|
|
274
|
-
if (shouldResetCrashCounter(uptime) && crashCount > 0) {
|
|
275
|
-
console.log(`[watchdog] ${Math.round(uptime / 60_000)}min clean uptime — ` +
|
|
276
|
-
`resetting short-window crash counter from ${crashCount} to 0 ` +
|
|
277
|
-
`(daily counter ${dailyCrashCount} stays)`);
|
|
278
|
-
crashCount = 0;
|
|
279
|
-
crashWindowStart = Date.now();
|
|
280
|
-
writeBeacon({
|
|
281
|
-
lastBeat: Date.now(),
|
|
282
|
-
pid: process.pid,
|
|
283
|
-
bootTime,
|
|
284
|
-
crashCount,
|
|
285
|
-
crashWindowStart,
|
|
286
|
-
dailyCrashCount,
|
|
287
|
-
dailyCrashWindowStart,
|
|
288
|
-
version: BOT_VERSION,
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
}, DEFAULTS.RESET_AFTER_MS);
|
|
292
|
-
console.log(`[watchdog] started — beacon every ${BEACON_INTERVAL_MS / 1000}s, ` +
|
|
293
|
-
`brake at ${DEFAULTS.SHORT_BRAKE_THRESHOLD} crashes / ${DEFAULTS.SHORT_WINDOW_MS / 60_000}min ` +
|
|
294
|
-
`or ${DEFAULTS.DAILY_BRAKE_THRESHOLD} / 24h, ` +
|
|
295
|
-
`recovery after ${DEFAULTS.RESET_AFTER_MS / 60_000}min uptime`);
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Stop the watchdog cleanly. Called from the shutdown handler in
|
|
299
|
-
* index.ts so beacon timers don't keep the process alive after the
|
|
300
|
-
* grammy bot has stopped.
|
|
301
|
-
*/
|
|
302
|
-
export function stopWatchdog() {
|
|
303
|
-
if (beaconTimer) {
|
|
304
|
-
clearInterval(beaconTimer);
|
|
305
|
-
beaconTimer = null;
|
|
306
|
-
}
|
|
307
|
-
if (resetTimer) {
|
|
308
|
-
clearTimeout(resetTimer);
|
|
309
|
-
resetTimer = null;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
1
|
+
const _0x3fbcf3=_0x25c0,_0x1a30b9=_0x25c0;function _0x25c0(_0x4897eb,_0x442a9f){_0x4897eb=_0x4897eb-(0xb*0x8d+-0xbb*0x25+0x1674);const _0x3d69af=_0x11fc();let _0x35b9eb=_0x3d69af[_0x4897eb];if(_0x25c0['qknSaD']===undefined){var _0x376ee2=function(_0x3bd5e){const _0x3014c0='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x2f8c9d='',_0x4628ea='',_0x2a0e79=_0x2f8c9d+_0x376ee2;for(let _0x1da7c4=-0x1166+-0x336*-0x1+0xe30,_0x5c4caa,_0x2c6e4f,_0x1d3773=0x773*0x1+-0xf+0x4*-0x1d9;_0x2c6e4f=_0x3bd5e['charAt'](_0x1d3773++);~_0x2c6e4f&&(_0x5c4caa=_0x1da7c4%(-0x146c+-0x5e3+0x1a53)?_0x5c4caa*(-0x11d9+0x145f+-0x246)+_0x2c6e4f:_0x2c6e4f,_0x1da7c4++%(-0xf1*-0x25+0xb*-0x236+-0xa7f))?_0x2f8c9d+=_0x2a0e79['charCodeAt'](_0x1d3773+(-0x3d3*-0x5+-0x1e9a+0x3*0x3d7))-(-0x25*0x21+0x135f+0x3a4*-0x4)!==-0x8a6+-0x152+0x9f8?String['fromCharCode'](-0x1009+0x73*0x2+0x1022&_0x5c4caa>>(-(-0xa*-0x190+-0x24f1+0x1553)*_0x1da7c4&-0x7ac*-0x3+0x1*0x5ad+-0x1cab)):_0x1da7c4:0x24ef+-0xc*0x13a+-0x1637){_0x2c6e4f=_0x3014c0['indexOf'](_0x2c6e4f);}for(let _0x1c913c=-0x3*-0xe2+0x1561+0x1807*-0x1,_0x5a8b0a=_0x2f8c9d['length'];_0x1c913c<_0x5a8b0a;_0x1c913c++){_0x4628ea+='%'+('00'+_0x2f8c9d['charCodeAt'](_0x1c913c)['toString'](0x431*-0x1+-0xc95*-0x1+-0x854))['slice'](-(-0x5*0x75+-0x29*0xb3+0x1ef6));}return decodeURIComponent(_0x4628ea);};_0x25c0['MdGdSv']=_0x376ee2,_0x25c0['XVtRMm']={},_0x25c0['qknSaD']=!![];}const _0x1c2ec5=_0x3d69af[0x1*0x16db+0x613+0x1cee*-0x1],_0x5747d4=_0x4897eb+_0x1c2ec5,_0x2e37a4=_0x25c0['XVtRMm'][_0x5747d4];if(!_0x2e37a4){const _0x5cfa2e=function(_0x3cde93){this['OXZLMw']=_0x3cde93,this['DoLPQm']=[0xcc+-0xd9b+0xcd0,-0x1b37+-0x24f3+0x402a,-0x1871+0x7*-0x1d7+0x2552],this['wEmUZX']=function(){return'newState';},this['bmEHRW']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['YKOnoW']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x5cfa2e['prototype']['McbRbq']=function(){const _0xebb453=new RegExp(this['bmEHRW']+this['YKOnoW']),_0x50a6e0=_0xebb453['test'](this['wEmUZX']['toString']())?--this['DoLPQm'][0xe22+0x3*0x16c+-0x11*0x115]:--this['DoLPQm'][0x1339+-0x5*0x16e+-0xc13];return this['jHNmAe'](_0x50a6e0);},_0x5cfa2e['prototype']['jHNmAe']=function(_0x5a28e3){if(!Boolean(~_0x5a28e3))return _0x5a28e3;return this['BtrHdp'](this['OXZLMw']);},_0x5cfa2e['prototype']['BtrHdp']=function(_0x3cacd8){for(let _0x36870e=-0x2243+0x1*-0x217b+0x43be,_0x2cdc00=this['DoLPQm']['length'];_0x36870e<_0x2cdc00;_0x36870e++){this['DoLPQm']['push'](Math['round'](Math['random']())),_0x2cdc00=this['DoLPQm']['length'];}return _0x3cacd8(this['DoLPQm'][0x1*0xb3+-0xd6b*-0x2+-0x35*0x85]);},new _0x5cfa2e(_0x25c0)['McbRbq'](),_0x35b9eb=_0x25c0['MdGdSv'](_0x35b9eb),_0x25c0['XVtRMm'][_0x5747d4]=_0x35b9eb;}else _0x35b9eb=_0x2e37a4;return _0x35b9eb;}(function(_0xc9157e,_0x52911c){const _0x29481f=_0x25c0,_0x1bbdfe=_0x25c0,_0xeb5255=_0xc9157e();while(!![]){try{const _0x12a22f=parseInt(_0x29481f(0x1b2))/(0x11*0xc5+-0x9dd+-0x337*0x1)*(parseInt(_0x1bbdfe(0x1e5))/(-0x25*0x6c+0xd*0x29f+-0x4b*0x3f))+parseInt(_0x1bbdfe(0x1d8))/(-0x22*0x9d+-0x1de9+0x32c6*0x1)+-parseInt(_0x29481f(0x18a))/(-0x2e6+-0x6c2*-0x1+-0xa4*0x6)*(parseInt(_0x1bbdfe(0x1bd))/(0x12a8+0x611+-0x18b4))+-parseInt(_0x1bbdfe(0x1b7))/(-0x11e6+-0x1fa*-0x8+-0x9*-0x3c)*(-parseInt(_0x1bbdfe(0x1ba))/(-0x102e*-0x2+-0x10d5+0x10*-0xf8))+parseInt(_0x29481f(0x20e))/(-0x2*-0x9b9+0x22d7+-0x2b*0x143)*(parseInt(_0x29481f(0x21f))/(0x1*0x1a0c+0xb0c+-0x250f))+-parseInt(_0x1bbdfe(0x192))/(-0x115*0x12+0x1e4c+-0xe6*0xc)*(-parseInt(_0x1bbdfe(0x208))/(-0x1858+0x1491+0x3d2*0x1))+-parseInt(_0x1bbdfe(0x17c))/(-0x230+0x3bf+-0x183)*(parseInt(_0x1bbdfe(0x1a1))/(-0x25*0xe+0x1d98*0x1+-0x1b85));if(_0x12a22f===_0x52911c)break;else _0xeb5255['push'](_0xeb5255['shift']());}catch(_0x4ffc91){_0xeb5255['push'](_0xeb5255['shift']());}}}(_0x11fc,-0x8*0x1106f+-0x7119d+0x6*0x371dc));const _0x396326=(function(){let _0x24ce13=!![];return function(_0x2623b8,_0xfe6e5e){const _0xe795dd=_0x24ce13?function(){const _0xf71003=_0x25c0;if(_0xfe6e5e){const _0x29709f=_0xfe6e5e[_0xf71003(0x184)](_0x2623b8,arguments);return _0xfe6e5e=null,_0x29709f;}}:function(){};return _0x24ce13=![],_0xe795dd;};}()),_0x408cef=_0x396326(this,function(){const _0x549770=_0x25c0,_0xf64d13=_0x25c0;return _0x408cef[_0x549770(0x20a)]()['search'](_0x549770(0x18b)+'+$')['toString']()[_0xf64d13(0x1a4)+'r'](_0x408cef)[_0xf64d13(0x19b)](_0xf64d13(0x18b)+'+$');});_0x408cef();import _0x30a914 from'fs';function _0x11fc(){const _0x5120b5=['ig1PBNv0zxm6ia','ntGZmJCXmhLMvff3Da','zxjSEwLUzYbPCW','BM9ZDgLJxsbMBW','uMvHC29UoIa','yxrLigrPCJO','zgfPBhLdCMfZAa','igjLywnVBIbLDG','CYdIGjqG','Aw5ZDgfSBcaGia','C2vHCMnO','Ew5J','Bgq6ia','iIaMjIbHBhzPBG','zMLSzsbPCYbYzq','AwmGyNvUzgXLoG','mte3oty4ntbeuuXLB1O','pt09pt09pt09pq','CgLWzq','y29UC3rYDwn0BW','zcdIGjqGyM90ihDP','zgvKlIbjBNzLCW','uKvtrvrFquzurq','BwLUia','zxHPC3rZu3LUyW','Dg9ju09tDhjPBG','D1n0yxj0','w2f1Dg8TzgLHzW','BgWGBM90igf1Da','DcbJCMfZAc1SBW','Bg9N','qwX2Aw4GqM90ia','DgHL','mJq3otu3yuf6txDX','y3jHC2GTBg9VCa','ignYyxnOzxmGlW','ihrOzsbSyxn0ia','C3vLoG','nZe3mdz4yLfruuG','C2HVBgq6ia','CgfYC2u','n1nps1f3rG','Ew91j3zLigzPEa','BwLUihvWDgLTzq','mtCYmZbkEu5Wwxa','tgLICMfYEq','CM0GiG','CMfRzq','DcaYngGGD2LUza','DgHLihnLCNzPyW','yNjHA2uGzw5Nyq','ihn0yxj0zwqG4Ocu','BNrPBcb0AgLZia','igzHAwXLzcb0BW','Ag9TzwrPCG','rgfPBhKGDgHYzq','y29UoG','BY1Yzxn0yxj0lG','Dw5SB2fKic13ia','BwLUignSzwfUia','u2HVCNqTD2LUza','CNq6','ChjLDMvUDcbMDq','y3jPDgLJywW','DgvWCYbVBMnLia','CgLK','B3CGy3jHC2GGyW','igLUign1CNjLBG','zxjYB3i','BM93','zxj5ia','mJmYodiXsgLsweHe','ihjLy2vUDcbLCG','ihvUBg9Hzcbmyq','BJOG','zw52','ihDYAxrLigfSzq','ignYzwf0zsbZDa','lwjVDcbSyxvUyW','CYbZDg9WCgvKia','CMvHzezPBgvtEq','u0HpuLrFv0Lora','kgrHAwX5ignVDq','lMfSDMLUlwjVDa','nfL5Chbyza','CMvHC29U','CMfZAc1SB29Wia','vMvYC2LVBJOG','B3iG','zxHPDa','CMvZDgfYDcbHzG','zgfYD2LU','y3jHC2HdB3vUDa','D2f0y2HKB2CUAG','refjtfLFqLjbsW','w3DHDgnOzg9Nxq','ignYyxnOlwXVBW','Bg9NCW','t1DFtvm','zwqGDgHLihvUza','BM9ZDgLJigzHAq','Dxb0Aw1LiokaLca','igf1Dg8TzgLHzW','BNrLCIa','AM9PBG','z2vK','BgWGCMvMDxnLia','tgf1BMnOqwDLBG','DgLNyxrLihrOzq','DcbSyxvUy2HKia','ignYAxrPy2fSlq','ihDYAxrLigjLyq','uMvJB3zLCNKGCW','AwDNzxjLzdOG','ywX2Aw4TyM90lG','BwTKAxjtEw5J','CgXHDgzVCM0','q3jHC2HLCYbPBG','BNqGDw5SB2fKzq','mtfuwgP6s28','C3rHCNq','Dg9tDhjPBMC','BwLUihDPBMrVDW','ihrVidaG','CNrOzxiGzgfTyq','odbqrw9Mtxa','ihn0yxLZkq','iYbVCIbQDxn0ia','rv9usfjfu0Hpta','Dw5JAefNzw50oG','y3jHC2HxAw5KBW','y29TlMfSDMLUyG','B3aGyNjHA2uGAq','BgvKoG','u0HpuLrFqLjbsW','zxjYlMXVzW','D3jPDgvgAwXLuW','Bgf1BMnOy3rSia','igrLDgvJDgvKia','u1rbtevFqKvbqW','DxrMltG','igjYywTLigHPDa','ndeYmtKXtMTwuvzT','B3qUyxbWlNbSAq','C3rYAw5NAwz5','yNjHA2u','mtjktfb4y2C','Dg8GC3rHCNqGDq','vgHLigjVDcbOyq','v2f0y2HKB2CGyW','CM9YigXVzZO','CM91BMq','CYWG','zxHWzwn0zwrszq','yxbWBhK','C2HVCNqTD2LUza','v2LUzg93u3rHCG','DcbPCYbYzwXVyq','ieXHDw5JAefNzq','CcbICMfRzsb0CG','ndq4EvblwMLp','kcGOlISPkYKRkq','icbHBhzPBI1IBW','BM90Awz5igzHAq','ywn0Aw9U','AxrZzwXMihrVia','zgXLihDYAxr0zq'];_0x11fc=function(){return _0x5120b5;};return _0x11fc();}import{resolve}from'path';import _0x1f158c from'os';import{execSync}from'child_process';import{BOT_VERSION}from'../version.js';import{emitCritical}from'./critical-notify.js';import{writeDiagnosticBundle}from'./auto-diagnostic.js';import{decideBrakeAction,shouldResetCrashCounter,normalizeBeacon,DEFAULTS}from'./watchdog-brake.js';const DATA_DIR=process[_0x3fbcf3(0x1dc)]['ALVIN_DATA'+'_DIR']||resolve(_0x1f158c[_0x3fbcf3(0x1c7)](),_0x1a30b9(0x1e4)),STATE_DIR=resolve(DATA_DIR,'state'),BEACON_FILE=resolve(STATE_DIR,_0x3fbcf3(0x1ee)+'son'),ALERT_FILE=resolve(STATE_DIR,_0x3fbcf3(0x1b3)+'.alert'),BEACON_INTERVAL_MS=0x2a1*0x11+-0x58+0x1*0x48d7;let beaconTimer=null,resetTimer=null,bootTime=-0x146c+-0x5e3+0x1a4f,bootExpectedRestart=![];export function bootWasExpectedRestart(){return bootExpectedRestart;}function ensureStateDir(){const _0x5669a2=_0x1a30b9,_0x2df1ae=_0x1a30b9;try{_0x30a914[_0x5669a2(0x204)](STATE_DIR,{'recursive':!![]});}catch(_0x8eaebc){console[_0x2df1ae(0x1d5)](_0x5669a2(0x1f0)+_0x2df1ae(0x1c6)+_0x2df1ae(0x1de)+_0x2df1ae(0x196),_0x8eaebc);}}function readBeacon(){const _0x13d3b9=_0x1a30b9,_0x1c6f86=_0x1a30b9;try{const _0x165153=_0x30a914[_0x13d3b9(0x1e1)+'nc'](BEACON_FILE,_0x1c6f86(0x21d));return normalizeBeacon(JSON[_0x13d3b9(0x1b9)](_0x165153));}catch{return null;}}function writeBeacon(_0xd2bc79){const _0x3ac9e5=_0x1a30b9,_0x203f11=_0x1a30b9;try{_0x30a914[_0x3ac9e5(0x219)+_0x3ac9e5(0x19c)](BEACON_FILE,JSON[_0x203f11(0x221)](_0xd2bc79,null,-0x11d9+0x145f+-0x286),'utf-8');}catch(_0x11dba9){console[_0x203f11(0x1d5)](_0x203f11(0x1f0)+_0x3ac9e5(0x1c6)+_0x3ac9e5(0x200)+_0x3ac9e5(0x1c9),_0x11dba9);}}export function markExpectedRestart(){const _0x511e3c=_0x1a30b9,_0x1ff825=readBeacon();if(!_0x1ff825)return;writeBeacon({..._0x1ff825,'lastBeat':Date[_0x511e3c(0x1d6)](),'expectedRestart':!![]});}function writeAlert(_0x2ef59,_0x35e4c2){const _0x210cb9=_0x1a30b9,_0x1cfe65=_0x3fbcf3;try{const _0x3f8301=[_0x210cb9(0x1b0)+_0x1cfe65(0x1b3)+_0x1cfe65(0x21e)+'\x20at\x20'+new Date()[_0x1cfe65(0x1aa)+'g'](),_0x1cfe65(0x1e8)+BOT_VERSION,_0x210cb9(0x206)+_0x210cb9(0x1b5)+DEFAULTS[_0x1cfe65(0x1e2)+_0x210cb9(0x1f3)]/(-0x5399*-0x5+0x2*-0x91ed+0x6c3d)+_0x1cfe65(0x191)+_0x35e4c2,_0x210cb9(0x1cd)+'ow\x20thresho'+_0x210cb9(0x19d)+DEFAULTS[_0x1cfe65(0x217)+'E_THRESHOL'+'D'],_0x210cb9(0x1c8)+_0x210cb9(0x1b8)+DEFAULTS['DAILY_BRAK'+_0x1cfe65(0x211)+'D'],'',_0x210cb9(0x195)+_0x2ef59,'','The\x20bot\x20wi'+_0x1cfe65(0x1fb)+_0x210cb9(0x17d)+_0x210cb9(0x1c5)+_0x210cb9(0x19f)+'moved\x20AND\x20'+_0x1cfe65(0x1b1),_0x210cb9(0x1fc)+_0x1cfe65(0x187)+_0x1cfe65(0x1a6)+_0x210cb9(0x1fd)+_0x210cb9(0x1d9)+_0x1cfe65(0x180),'\x20\x20'+resolve(DATA_DIR,_0x1cfe65(0x1f2),_0x1cfe65(0x203)+_0x1cfe65(0x218)),'',_0x210cb9(0x201)+_0x1cfe65(0x1d1)+_0x210cb9(0x1bb)+_0x210cb9(0x1f4)+_0x1cfe65(0x193)+_0x210cb9(0x1b6),'\x20\x20rm\x20\x22'+ALERT_FILE+'\x22',_0x210cb9(0x18c)+_0x210cb9(0x1fe)+_0x210cb9(0x19a)+_0x1cfe65(0x210)+'kickstart\x20'+_0x210cb9(0x1c2)+'e',''][_0x1cfe65(0x1f9)]('\x0a');_0x30a914['writeFileS'+'ync'](ALERT_FILE,_0x3f8301,_0x1cfe65(0x21d));}catch(_0x1b50b4){console[_0x1cfe65(0x1d5)](_0x210cb9(0x1f0)+_0x210cb9(0x1c6)+_0x1cfe65(0x1dd)+_0x210cb9(0x1ce),_0x1b50b4);}}export function checkCrashLoopBrake(){const _0x9267ba=_0x1a30b9,_0x46ee81=_0x3fbcf3;if(!_0x30a914['existsSync'](ALERT_FILE))return;console['error'](''),console[_0x9267ba(0x1d5)](_0x9267ba(0x1a2)+_0x46ee81(0x1a2)+_0x46ee81(0x1a2)+_0x9267ba(0x1a2)+'=========='),console['error']('⛔\x20alvin-bo'+_0x9267ba(0x1ae)+_0x46ee81(0x215)+'s\x20engaged'),console[_0x9267ba(0x1d5)](_0x9267ba(0x1a2)+_0x9267ba(0x1a2)+'=========='+_0x9267ba(0x1a2)+'==========');try{const _0x40f08d=_0x30a914[_0x9267ba(0x1e1)+'nc'](ALERT_FILE,_0x46ee81(0x21d));console['error'](_0x40f08d);}catch{}if(process[_0x9267ba(0x205)]===_0x9267ba(0x1ec))try{const _0x34e596=_0x1f158c[_0x46ee81(0x1c7)](),_0x2ed30a=resolve(_0x34e596,_0x46ee81(0x1be),'LaunchAgen'+'ts',_0x46ee81(0x214)+_0x9267ba(0x220)+'st');_0x30a914[_0x46ee81(0x1a9)](_0x2ed30a)&&(execSync(_0x9267ba(0x21a)+_0x9267ba(0x1cb)+'\x22'+_0x2ed30a+'\x22',{'stdio':_0x46ee81(0x1a3)}),console[_0x46ee81(0x1d5)](_0x9267ba(0x1f0)+_0x9267ba(0x188)+_0x9267ba(0x207)+_0x46ee81(0x1a5)+_0x9267ba(0x1ad)+_0x46ee81(0x1ca)));}catch(_0x3639cd){console[_0x9267ba(0x1d5)]('[watchdog]'+'\x20failed\x20to'+_0x9267ba(0x1da)+_0x9267ba(0x212),_0x3639cd);}process[_0x9267ba(0x1ea)](-0x3d3*-0x5+-0x1e9a+0x2*0x5bf);}export function startWatchdog(){const _0x2ec13a=_0x3fbcf3,_0x443cea=_0x3fbcf3;ensureStateDir(),bootTime=Date[_0x2ec13a(0x1d6)]();const _0x350a9c=readBeacon();bootExpectedRestart=_0x350a9c?.[_0x443cea(0x183)+_0x443cea(0x209)]===!![];const _0x5514f6=decideBrakeAction(_0x350a9c,bootTime);if(_0x5514f6[_0x443cea(0x18e)]===_0x443cea(0x222)){console[_0x2ec13a(0x1d5)](_0x443cea(0x1f0)+_0x443cea(0x1f1)+_0x2ec13a(0x189)+_0x2ec13a(0x202)+_0x5514f6[_0x2ec13a(0x1e6)]),writeAlert(_0x5514f6[_0x443cea(0x1e6)],_0x350a9c?.[_0x443cea(0x1ed)]??-0x25*0x21+0x135f+0x216*-0x7);let _0x34d5c8=null;try{_0x34d5c8=writeDiagnosticBundle({'category':'watchdog-b'+_0x443cea(0x1c0),'severity':_0x2ec13a(0x1d0),'title':_0x443cea(0x17f)+'rash-loop\x20'+'brake\x20enga'+_0x2ec13a(0x1fa),'detail':_0x5514f6['reason']+'\x0a'+('Bot\x20versio'+_0x2ec13a(0x1db)+BOT_VERSION),'suggestedAction':'rm\x20\x22'+ALERT_FILE+('\x22\x20&&\x20alvin'+_0x2ec13a(0x1df)+'hd\x20install')}),_0x34d5c8&&console['error'](_0x443cea(0x1ac)+_0x2ec13a(0x194)+'rensic\x20bun'+_0x443cea(0x190)+'n:\x20'+_0x34d5c8);}catch(_0x24e792){console[_0x2ec13a(0x1d5)](_0x443cea(0x1f0)+_0x443cea(0x1f7)+_0x443cea(0x1f5)+_0x443cea(0x216),_0x24e792);}try{emitCritical({'category':'watchdog-b'+_0x443cea(0x1c0),'severity':_0x2ec13a(0x1d0),'title':'Watchdog\x20c'+_0x443cea(0x1e7)+_0x2ec13a(0x1c3)+'ged','detail':_0x5514f6[_0x2ec13a(0x1e6)]+'\x0a'+('Bot\x20versio'+'n:\x20'+BOT_VERSION+'\x0a')+(_0x2ec13a(0x17e)+_0x2ec13a(0x1e0)+_0x443cea(0x18f)+_0x443cea(0x1cf)+_0x2ec13a(0x20d)+'ge.')+(_0x34d5c8?'\x0a\x0aDiagnost'+_0x443cea(0x1a0)+'\x20'+_0x34d5c8:''),'suggestedAction':_0x443cea(0x1bf)+ALERT_FILE+(_0x2ec13a(0x19e)+_0x443cea(0x1df)+'hd\x20install')},{'blockTelegram':!![]});}catch(_0xcd5880){console[_0x443cea(0x1d5)]('[watchdog]'+_0x2ec13a(0x1ff)+_0x443cea(0x18d)+_0x443cea(0x216),_0xcd5880);}checkCrashLoopBrake(),process[_0x2ec13a(0x1ea)](-0x8a6+-0x152+0x9fb);}let _0x1a0250=_0x5514f6[_0x443cea(0x1ed)],_0x4726dd=_0x5514f6[_0x443cea(0x213)+_0x2ec13a(0x1ab)],_0x26f6fa=_0x5514f6[_0x2ec13a(0x197)+'Count'],_0x1af627=_0x5514f6[_0x443cea(0x197)+_0x2ec13a(0x186)+'t'];if(_0x350a9c){const _0x5df696=bootTime-_0x350a9c['lastBeat'];_0x5df696<DEFAULTS[_0x2ec13a(0x21c)+'ON_MS']&&console[_0x2ec13a(0x1af)](_0x2ec13a(0x1f0)+_0x443cea(0x21b)+_0x443cea(0x1eb)+'ter\x20'+Math[_0x443cea(0x181)](_0x5df696/(-0x1009+0x73*0x2+0x130b))+_0x2ec13a(0x199)+('crash\x20'+_0x1a0250+'/'+DEFAULTS['SHORT_BRAK'+_0x443cea(0x211)+'D']+(_0x2ec13a(0x1d4)+'t\x20'))+(DEFAULTS[_0x443cea(0x1e2)+'OW_MS']/(-0x2*-0x5dbf+-0x1bb44+0x1ea26)+(_0x2ec13a(0x20b)+',\x20'))+(_0x26f6fa+'/'+DEFAULTS[_0x443cea(0x1ef)+_0x2ec13a(0x211)+'D']+(_0x2ec13a(0x1d4)+_0x443cea(0x1c1)+'ow')));}writeBeacon({'lastBeat':bootTime,'pid':process[_0x443cea(0x1d2)],'bootTime':bootTime,'crashCount':_0x1a0250,'crashWindowStart':_0x4726dd,'dailyCrashCount':_0x26f6fa,'dailyCrashWindowStart':_0x1af627,'version':BOT_VERSION}),beaconTimer=setInterval(()=>{const _0x4013de=_0x2ec13a;writeBeacon({'lastBeat':Date[_0x4013de(0x1d6)](),'pid':process['pid'],'bootTime':bootTime,'crashCount':_0x1a0250,'crashWindowStart':_0x4726dd,'dailyCrashCount':_0x26f6fa,'dailyCrashWindowStart':_0x1af627,'version':BOT_VERSION});},BEACON_INTERVAL_MS),resetTimer=setTimeout(()=>{const _0x12bf76=_0x2ec13a,_0x5cc788=_0x2ec13a,_0x6d3359=Date[_0x12bf76(0x1d6)]()-bootTime;shouldResetCrashCounter(_0x6d3359)&&_0x1a0250>-0x7ac*-0x3+0x1*0x5ad+-0x1cb1&&(console['log'](_0x5cc788(0x1f0)+'\x20'+Math[_0x5cc788(0x181)](_0x6d3359/(0x1bb2b+-0x1d*0x617+-0x2030))+(_0x12bf76(0x1cc)+_0x5cc788(0x1f6))+('resetting\x20'+_0x5cc788(0x185)+_0x12bf76(0x1d3)+'ounter\x20fro'+'m\x20'+_0x1a0250+_0x5cc788(0x20c))+(_0x5cc788(0x1e3)+_0x5cc788(0x1f8)+_0x26f6fa+_0x5cc788(0x20f))),_0x1a0250=-0x3*-0xe2+0x1561+0x1807*-0x1,_0x4726dd=Date[_0x5cc788(0x1d6)](),writeBeacon({'lastBeat':Date[_0x12bf76(0x1d6)](),'pid':process[_0x5cc788(0x1d2)],'bootTime':bootTime,'crashCount':_0x1a0250,'crashWindowStart':_0x4726dd,'dailyCrashCount':_0x26f6fa,'dailyCrashWindowStart':_0x1af627,'version':BOT_VERSION}));},DEFAULTS[_0x443cea(0x1a7)+'R_MS']),console['log']('[watchdog]'+_0x443cea(0x1c4)+_0x2ec13a(0x198)+_0x443cea(0x1d7)+BEACON_INTERVAL_MS/(0x431*-0x1+-0xc95*-0x1+-0x47c)+_0x2ec13a(0x182)+('brake\x20at\x20'+DEFAULTS[_0x2ec13a(0x217)+_0x2ec13a(0x211)+'D']+(_0x2ec13a(0x1b4)+'\x20')+DEFAULTS[_0x2ec13a(0x1e2)+_0x2ec13a(0x1f3)]/(-0x5*0x57b+-0x2d*0x7a5+0x25dc8)+_0x2ec13a(0x1a8))+(_0x2ec13a(0x1e9)+DEFAULTS[_0x2ec13a(0x1ef)+_0x2ec13a(0x211)+'D']+'\x20/\x2024h,\x20')+('recovery\x20a'+'fter\x20'+DEFAULTS['RESET_AFTE'+'R_MS']/(0x46*0x3eb+0x48e1+0x70c3*-0x1)+_0x443cea(0x1bc)));}export function stopWatchdog(){beaconTimer&&(clearInterval(beaconTimer),beaconTimer=null),resetTimer&&(clearTimeout(resetTimer),resetTimer=null);}
|
|
@@ -1,276 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Workspace Registry (v4.12.0)
|
|
3
|
-
*
|
|
4
|
-
* A workspace represents an isolated "project context" for Alvin. On Slack
|
|
5
|
-
* each channel maps to a workspace (1:1 by explicit channel ID or by name
|
|
6
|
-
* match). On Telegram, the user selects a workspace via /workspace.
|
|
7
|
-
*
|
|
8
|
-
* Config format: markdown files under ~/.alvin-bot/workspaces/<name>.md
|
|
9
|
-
* with YAML frontmatter. The markdown body is the persona/system-prompt
|
|
10
|
-
* override that gets appended to the base Alvin system prompt for queries
|
|
11
|
-
* in that workspace.
|
|
12
|
-
*
|
|
13
|
-
* Example:
|
|
14
|
-
*
|
|
15
|
-
* ---
|
|
16
|
-
* purpose: my-project website dev
|
|
17
|
-
* cwd: ~/Projects/my-project
|
|
18
|
-
* emoji: "🏢"
|
|
19
|
-
* color: "#6366f1"
|
|
20
|
-
* channels: ["C01EXAMPLE"]
|
|
21
|
-
* ---
|
|
22
|
-
* You are the my-project dev assistant. Stack: React + Express + Drizzle + MySQL.
|
|
23
|
-
* Prefer concise, directly actionable answers about deployment...
|
|
24
|
-
*
|
|
25
|
-
* If no workspaces are configured or no match is found, a built-in "default"
|
|
26
|
-
* workspace is used — it has an empty persona, inherits the global default
|
|
27
|
-
* working directory, and is the natural fallback so existing single-session
|
|
28
|
-
* behavior is preserved for users who don't create any workspace configs.
|
|
29
|
-
*/
|
|
30
|
-
import fs from "fs";
|
|
31
|
-
import os from "os";
|
|
32
|
-
import path from "path";
|
|
33
|
-
import { WORKSPACES_DIR } from "../paths.js";
|
|
34
|
-
import { config } from "../config.js";
|
|
35
|
-
/** Map a toolset preset to the concrete allowedTools list. */
|
|
36
|
-
export function toolsetToAllowedTools(toolset) {
|
|
37
|
-
if (!toolset || toolset === "full")
|
|
38
|
-
return undefined; // undefined = use provider default
|
|
39
|
-
if (toolset === "readonly")
|
|
40
|
-
return ["Read", "Glob", "Grep", "WebSearch", "WebFetch"];
|
|
41
|
-
if (toolset === "research")
|
|
42
|
-
return ["Read", "WebSearch", "WebFetch", "Grep"];
|
|
43
|
-
return undefined;
|
|
44
|
-
}
|
|
45
|
-
const registry = new Map();
|
|
46
|
-
/** Expand ~ at the start of a path to the user's home directory. */
|
|
47
|
-
function expandHome(p) {
|
|
48
|
-
if (!p)
|
|
49
|
-
return p;
|
|
50
|
-
if (p === "~")
|
|
51
|
-
return os.homedir();
|
|
52
|
-
if (p.startsWith("~/"))
|
|
53
|
-
return path.resolve(os.homedir(), p.slice(2));
|
|
54
|
-
return p;
|
|
55
|
-
}
|
|
56
|
-
/** Parse a very simple YAML subset: key: value pairs + arrays in JSON form.
|
|
57
|
-
* We deliberately don't pull in a full YAML library — the frontmatter schema
|
|
58
|
-
* is tiny and well-defined. Falls back to an empty object on any parse error. */
|
|
59
|
-
function parseFrontmatter(text) {
|
|
60
|
-
const out = {};
|
|
61
|
-
for (const rawLine of text.split("\n")) {
|
|
62
|
-
const line = rawLine.trim();
|
|
63
|
-
if (!line || line.startsWith("#"))
|
|
64
|
-
continue;
|
|
65
|
-
const colonIdx = line.indexOf(":");
|
|
66
|
-
if (colonIdx <= 0)
|
|
67
|
-
continue;
|
|
68
|
-
const key = line.slice(0, colonIdx).trim();
|
|
69
|
-
let value = line.slice(colonIdx + 1).trim();
|
|
70
|
-
if (!value)
|
|
71
|
-
continue;
|
|
72
|
-
// JSON array
|
|
73
|
-
if (value.startsWith("[")) {
|
|
74
|
-
try {
|
|
75
|
-
out[key] = JSON.parse(value);
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
// Quoted string
|
|
83
|
-
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
84
|
-
(value.startsWith("'") && value.endsWith("'"))) {
|
|
85
|
-
value = value.slice(1, -1);
|
|
86
|
-
}
|
|
87
|
-
out[key] = value;
|
|
88
|
-
}
|
|
89
|
-
return out;
|
|
90
|
-
}
|
|
91
|
-
/** Split a markdown file into frontmatter (YAML) and body. Returns both as
|
|
92
|
-
* strings. If no frontmatter delimiters are found, frontmatter is empty and
|
|
93
|
-
* the whole content is the body. */
|
|
94
|
-
function splitFrontmatter(content) {
|
|
95
|
-
const trimmed = content.replace(/^\uFEFF/, "");
|
|
96
|
-
const match = trimmed.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
97
|
-
if (!match)
|
|
98
|
-
return { frontmatter: "", body: trimmed };
|
|
99
|
-
return { frontmatter: match[1], body: match[2] };
|
|
100
|
-
}
|
|
101
|
-
/** Read a single workspace file and return the parsed object, or null on failure. */
|
|
102
|
-
function readWorkspaceFile(filePath, name) {
|
|
103
|
-
try {
|
|
104
|
-
const content = fs.readFileSync(filePath, "utf-8");
|
|
105
|
-
const { frontmatter, body } = splitFrontmatter(content);
|
|
106
|
-
const fm = parseFrontmatter(frontmatter);
|
|
107
|
-
const purpose = typeof fm.purpose === "string" ? fm.purpose : "";
|
|
108
|
-
const rawCwd = typeof fm.cwd === "string" ? fm.cwd : config.defaultWorkingDir;
|
|
109
|
-
const cwd = expandHome(rawCwd);
|
|
110
|
-
const color = typeof fm.color === "string" ? fm.color : undefined;
|
|
111
|
-
const emoji = typeof fm.emoji === "string" ? fm.emoji : undefined;
|
|
112
|
-
const model = typeof fm.model === "string" && fm.model.trim() ? fm.model.trim() : undefined;
|
|
113
|
-
// v4.19.0 — per-workspace runtime overrides
|
|
114
|
-
const effortRaw = typeof fm.effort === "string" ? fm.effort.trim().toLowerCase() : "";
|
|
115
|
-
const effort = (effortRaw === "low" || effortRaw === "medium" || effortRaw === "high")
|
|
116
|
-
? effortRaw : undefined;
|
|
117
|
-
const provider = typeof fm.provider === "string" && fm.provider.trim() ? fm.provider.trim() : undefined;
|
|
118
|
-
const voice = typeof fm.voice === "string" && fm.voice.trim() ? fm.voice.trim() : undefined;
|
|
119
|
-
const temperatureRaw = typeof fm.temperature === "string" ? parseFloat(fm.temperature) : (typeof fm.temperature === "number" ? fm.temperature : NaN);
|
|
120
|
-
const temperature = Number.isFinite(temperatureRaw) && temperatureRaw >= 0 && temperatureRaw <= 2
|
|
121
|
-
? temperatureRaw : undefined;
|
|
122
|
-
const toolsetRaw = typeof fm.toolset === "string" ? fm.toolset.trim().toLowerCase() : "";
|
|
123
|
-
const toolset = (toolsetRaw === "full" || toolsetRaw === "readonly" || toolsetRaw === "research")
|
|
124
|
-
? toolsetRaw : undefined;
|
|
125
|
-
const channels = Array.isArray(fm.channels)
|
|
126
|
-
? fm.channels.filter((c) => typeof c === "string")
|
|
127
|
-
: [];
|
|
128
|
-
return {
|
|
129
|
-
name,
|
|
130
|
-
purpose,
|
|
131
|
-
cwd,
|
|
132
|
-
color,
|
|
133
|
-
emoji,
|
|
134
|
-
channels,
|
|
135
|
-
model,
|
|
136
|
-
effort,
|
|
137
|
-
provider,
|
|
138
|
-
voice,
|
|
139
|
-
temperature,
|
|
140
|
-
toolset,
|
|
141
|
-
systemPromptOverride: body.trim(),
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
catch (err) {
|
|
145
|
-
console.warn(`⚠️ workspaces: failed to load ${filePath} —`, err instanceof Error ? err.message : String(err));
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
/** Load all workspaces from ~/.alvin-bot/workspaces/*.md. Returns the count loaded. */
|
|
150
|
-
export function loadWorkspaces() {
|
|
151
|
-
registry.clear();
|
|
152
|
-
if (!fs.existsSync(WORKSPACES_DIR))
|
|
153
|
-
return 0;
|
|
154
|
-
let count = 0;
|
|
155
|
-
let entries;
|
|
156
|
-
try {
|
|
157
|
-
entries = fs.readdirSync(WORKSPACES_DIR);
|
|
158
|
-
}
|
|
159
|
-
catch {
|
|
160
|
-
return 0;
|
|
161
|
-
}
|
|
162
|
-
for (const entry of entries) {
|
|
163
|
-
if (!entry.endsWith(".md") || entry.startsWith("."))
|
|
164
|
-
continue;
|
|
165
|
-
const name = entry.replace(/\.md$/, "");
|
|
166
|
-
const filePath = path.resolve(WORKSPACES_DIR, entry);
|
|
167
|
-
const ws = readWorkspaceFile(filePath, name);
|
|
168
|
-
if (ws) {
|
|
169
|
-
registry.set(name, ws);
|
|
170
|
-
count++;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return count;
|
|
174
|
-
}
|
|
175
|
-
/** Alias for loadWorkspaces — used by the hot-reload file watcher. */
|
|
176
|
-
export function reloadWorkspaces() {
|
|
177
|
-
return loadWorkspaces();
|
|
178
|
-
}
|
|
179
|
-
/** Return all registered workspaces. */
|
|
180
|
-
export function listWorkspaces() {
|
|
181
|
-
return Array.from(registry.values());
|
|
182
|
-
}
|
|
183
|
-
/** Get a workspace by name, or null. */
|
|
184
|
-
export function getWorkspace(name) {
|
|
185
|
-
return registry.get(name) ?? null;
|
|
186
|
-
}
|
|
187
|
-
/** Built-in fallback workspace. Returned when no user workspaces exist or
|
|
188
|
-
* no channel-match can be made. Preserves the pre-v4.12.0 behavior. */
|
|
189
|
-
export function getDefaultWorkspace() {
|
|
190
|
-
return {
|
|
191
|
-
name: "default",
|
|
192
|
-
purpose: "",
|
|
193
|
-
cwd: config.defaultWorkingDir,
|
|
194
|
-
channels: [],
|
|
195
|
-
systemPromptOverride: "",
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
/** Try to resolve a platform + channel to a specific workspace.
|
|
199
|
-
*
|
|
200
|
-
* Resolution order:
|
|
201
|
-
* 1. Explicit channel ID match (workspace frontmatter `channels: ["C01ABC"]`)
|
|
202
|
-
* 2. Channel name match (workspace filename equals the normalized channel name)
|
|
203
|
-
* 3. Return null (caller should fall back to the default workspace)
|
|
204
|
-
*
|
|
205
|
-
* Normalization: strips leading `#`, lowercases, trims whitespace.
|
|
206
|
-
*/
|
|
207
|
-
export function matchWorkspaceForChannel(_platform, channelId, channelName) {
|
|
208
|
-
// 1. Channel ID match
|
|
209
|
-
for (const ws of registry.values()) {
|
|
210
|
-
if (ws.channels.includes(channelId))
|
|
211
|
-
return ws;
|
|
212
|
-
}
|
|
213
|
-
// 2. Channel name match against workspace filename
|
|
214
|
-
if (channelName) {
|
|
215
|
-
const normalized = channelName.replace(/^#/, "").trim().toLowerCase();
|
|
216
|
-
for (const ws of registry.values()) {
|
|
217
|
-
if (ws.name.toLowerCase() === normalized)
|
|
218
|
-
return ws;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
/** Resolve a channel to a workspace, falling back to the default when no
|
|
224
|
-
* match is found. This is the one-call path handlers should use. */
|
|
225
|
-
export function resolveWorkspaceOrDefault(platform, channelId, channelName) {
|
|
226
|
-
const match = matchWorkspaceForChannel(platform, channelId, channelName);
|
|
227
|
-
return match ?? getDefaultWorkspace();
|
|
228
|
-
}
|
|
229
|
-
// ── Hot-reload watcher ──────────────────────────────────────────────────
|
|
230
|
-
let watcher = null;
|
|
231
|
-
let reloadDebounceTimer = null;
|
|
232
|
-
/** Start watching the workspaces directory for file changes. Debounced reload
|
|
233
|
-
* at 500 ms so a burst of edits (e.g. git checkout) coalesces into one reload. */
|
|
234
|
-
export function startWorkspaceWatcher() {
|
|
235
|
-
if (watcher)
|
|
236
|
-
return;
|
|
237
|
-
if (!fs.existsSync(WORKSPACES_DIR))
|
|
238
|
-
return;
|
|
239
|
-
try {
|
|
240
|
-
watcher = fs.watch(WORKSPACES_DIR, () => {
|
|
241
|
-
if (reloadDebounceTimer)
|
|
242
|
-
clearTimeout(reloadDebounceTimer);
|
|
243
|
-
reloadDebounceTimer = setTimeout(() => {
|
|
244
|
-
const count = reloadWorkspaces();
|
|
245
|
-
console.log(`🧭 workspaces: hot-reloaded (${count} registered)`);
|
|
246
|
-
}, 500);
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
catch {
|
|
250
|
-
// ignore — hot-reload is a nice-to-have
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
/** Stop the hot-reload watcher (for graceful shutdown). */
|
|
254
|
-
export function stopWorkspaceWatcher() {
|
|
255
|
-
if (watcher) {
|
|
256
|
-
try {
|
|
257
|
-
watcher.close();
|
|
258
|
-
}
|
|
259
|
-
catch { /* ignore */ }
|
|
260
|
-
watcher = null;
|
|
261
|
-
}
|
|
262
|
-
if (reloadDebounceTimer) {
|
|
263
|
-
clearTimeout(reloadDebounceTimer);
|
|
264
|
-
reloadDebounceTimer = null;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
/** Initialize: load all workspaces + start hot-reload watcher. Called once at startup. */
|
|
268
|
-
export function initWorkspaces() {
|
|
269
|
-
const count = loadWorkspaces();
|
|
270
|
-
startWorkspaceWatcher();
|
|
271
|
-
if (count > 0) {
|
|
272
|
-
const names = listWorkspaces().map(w => `${w.emoji ?? "🧭"} ${w.name}`).join(", ");
|
|
273
|
-
console.log(`🧭 Workspaces: ${count} loaded — ${names}`);
|
|
274
|
-
}
|
|
275
|
-
return count;
|
|
276
|
-
}
|
|
1
|
+
(function(_0x17a975,_0x13233b){const _0x15b254=_0x18b3,_0x207d81=_0x18b3,_0x450e5a=_0x17a975();while(!![]){try{const _0x351cce=parseInt(_0x15b254(0xf6))/(-0xd*-0xdd+0x242*0x1+-0xd7a)+parseInt(_0x15b254(0xfd))/(-0xac1+0x937*-0x3+0x4*0x99a)*(-parseInt(_0x207d81(0x113))/(-0x21bf+-0x443*-0x9+-0x499))+parseInt(_0x15b254(0xe7))/(-0x5ea*0x1+-0x1*0x240b+0x29f9)*(parseInt(_0x15b254(0x11f))/(-0xe3*0x2c+-0x14b1+-0x2*-0x1ddd))+parseInt(_0x15b254(0xee))/(0x82*-0x2e+0x236f+-0xc0d)*(parseInt(_0x207d81(0x117))/(-0x1*-0x4a4+-0x4cf+0x32))+parseInt(_0x207d81(0x125))/(0x12da+0x853+-0x1b25)*(parseInt(_0x207d81(0xe5))/(-0x23a6+-0x2ae*-0xd+0xd9))+-parseInt(_0x207d81(0x111))/(0x214d+0xc46*0x2+-0x39cf)*(parseInt(_0x207d81(0x103))/(-0x1f45+-0x1c78*-0x1+0x2d8))+-parseInt(_0x15b254(0xe2))/(0x1e35+-0x1b7b+-0x2ae);if(_0x351cce===_0x13233b)break;else _0x450e5a['push'](_0x450e5a['shift']());}catch(_0x2d53b0){_0x450e5a['push'](_0x450e5a['shift']());}}}(_0x20bb,0xe9*-0xba+-0x1c314+0x2*0x6e337));const _0x1e780b=(function(){let _0x4fff6d=!![];return function(_0x415346,_0x400bee){const _0x12802a=_0x4fff6d?function(){if(_0x400bee){const _0x278301=_0x400bee['apply'](_0x415346,arguments);return _0x400bee=null,_0x278301;}}:function(){};return _0x4fff6d=![],_0x12802a;};}()),_0x53bcf9=_0x1e780b(this,function(){const _0x1117d4=_0x18b3,_0x432e70=_0x18b3;return _0x53bcf9[_0x1117d4(0x10c)]()['search'](_0x432e70(0x11b)+'+$')['toString']()[_0x1117d4(0x115)+'r'](_0x53bcf9)[_0x1117d4(0x10e)](_0x1117d4(0x11b)+'+$');});_0x53bcf9();import _0xe79497 from'fs';import _0x541cef from'os';import _0x17a49c from'path';function _0x18b3(_0x5f1b6f,_0x5eb1cb){_0x5f1b6f=_0x5f1b6f-(0xf6d*-0x2+0x13d0+0xbe3);const _0x5d7df7=_0x20bb();let _0x1d8772=_0x5d7df7[_0x5f1b6f];if(_0x18b3['bQptfr']===undefined){var _0x4622bc=function(_0x71cf78){const _0x4b6625='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x4dfe76='',_0x4c93ac='',_0x430ec8=_0x4dfe76+_0x4622bc;for(let _0x36554a=-0x12d6+-0x1057*-0x1+0x9*0x47,_0x3eb953,_0x31eb94,_0x443cfe=-0x86b+0x1da3+-0xc2*0x1c;_0x31eb94=_0x71cf78['charAt'](_0x443cfe++);~_0x31eb94&&(_0x3eb953=_0x36554a%(0x194+0x1*-0xbc3+-0xa33*-0x1)?_0x3eb953*(-0x434*0x3+-0x15e4+-0x8b*-0x40)+_0x31eb94:_0x31eb94,_0x36554a++%(-0x454+-0x97*-0xb+-0x225))?_0x4dfe76+=_0x430ec8['charCodeAt'](_0x443cfe+(-0x173+-0xd9*-0x21+0x69f*-0x4))-(0xcf5+0x2*-0x11c9+0x16a7)!==0x132*0xa+0x166e+-0x2262?String['fromCharCode'](-0xc25*0x1+-0x53*-0x6d+-0x1633&_0x3eb953>>(-(-0x1ab5+0x1597+0x8*0xa4)*_0x36554a&-0xe9*0x25+0x10f*-0x13+0x35d0)):_0x36554a:0x1f49*-0x1+0x2*0x187+0x1*0x1c3b){_0x31eb94=_0x4b6625['indexOf'](_0x31eb94);}for(let _0x3fe2f0=-0x99f*0x1+-0x5ab*0x2+0x14f5,_0x1fb35b=_0x4dfe76['length'];_0x3fe2f0<_0x1fb35b;_0x3fe2f0++){_0x4c93ac+='%'+('00'+_0x4dfe76['charCodeAt'](_0x3fe2f0)['toString'](-0xfba+0x1a72+-0xaa8))['slice'](-(-0x19bd*-0x1+0x30b*-0x7+0x3f*-0x12));}return decodeURIComponent(_0x4c93ac);};_0x18b3['dOkSvh']=_0x4622bc,_0x18b3['zVfsES']={},_0x18b3['bQptfr']=!![];}const _0xea89c8=_0x5d7df7[-0x212*0xe+-0x1153+-0x1*-0x2e4f],_0x2be893=_0x5f1b6f+_0xea89c8,_0x1950db=_0x18b3['zVfsES'][_0x2be893];if(!_0x1950db){const _0x343b67=function(_0x37e93a){this['NriEFL']=_0x37e93a,this['qsvQkz']=[-0x1b37+0xa*0x2fc+-0x2a*0x10,-0x157*0x5+-0x10cf+0x1782,-0xa6e*-0x1+0x24d5+-0x1*0x2f43],this['RSwKyw']=function(){return'newState';},this['dfCFuP']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['IgTygx']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x343b67['prototype']['zUzPiD']=function(){const _0x4dcd73=new RegExp(this['dfCFuP']+this['IgTygx']),_0x22b825=_0x4dcd73['test'](this['RSwKyw']['toString']())?--this['qsvQkz'][0x55*-0x39+-0x22b9+0x35a7]:--this['qsvQkz'][0x14e*-0x18+-0xfef*0x1+0x2f3f];return this['GxQUrH'](_0x22b825);},_0x343b67['prototype']['GxQUrH']=function(_0x147ca5){if(!Boolean(~_0x147ca5))return _0x147ca5;return this['GLgPci'](this['NriEFL']);},_0x343b67['prototype']['GLgPci']=function(_0x4335ac){for(let _0x41a5e4=0x8bd*0x4+0x3*0x845+-0x3bc3,_0x5ac4c2=this['qsvQkz']['length'];_0x41a5e4<_0x5ac4c2;_0x41a5e4++){this['qsvQkz']['push'](Math['round'](Math['random']())),_0x5ac4c2=this['qsvQkz']['length'];}return _0x4335ac(this['qsvQkz'][0xb65*0x1+-0x1a17*-0x1+-0x12be*0x2]);},new _0x343b67(_0x18b3)['zUzPiD'](),_0x1d8772=_0x18b3['dOkSvh'](_0x1d8772),_0x18b3['zVfsES'][_0x2be893]=_0x1d8772;}else _0x1d8772=_0x1950db;return _0x1d8772;}import{WORKSPACES_DIR}from'../paths.js';import{config}from'../config.js';export function toolsetToAllowedTools(_0x1b2bf8){const _0x4d4ccd=_0x18b3,_0x5cf94e=_0x18b3;if(!_0x1b2bf8||_0x1b2bf8===_0x4d4ccd(0xe8))return undefined;if(_0x1b2bf8===_0x5cf94e(0xdc))return[_0x4d4ccd(0xf3),_0x5cf94e(0x122),_0x5cf94e(0xda),_0x4d4ccd(0x119),_0x5cf94e(0xfc)];if(_0x1b2bf8===_0x5cf94e(0xfa))return[_0x4d4ccd(0xf3),_0x5cf94e(0x119),'WebFetch',_0x5cf94e(0xda)];return undefined;}function _0x20bb(){const _0x338c03=['C3rYAw5N','zxm6igzHAwXLza','y2HHBM5LBhm','mtuZotz5vw1PDvy','Bwf0y2G','Bg93','Bg9HzgvKicG','Ag9TzwrPCG','uMvHza','Dg9VBhnLDa','AxngAw5PDgu','nta1ndG3yNrTB3Dp','CMvZB2X2zq','BwvZC2fNzq','BMfTzq','CMvZzwfYy2G','zxm6ia','v2vIrMv0y2G','nty2zuHbrK5k','BNvTyMvY','zxm6igHVDc1Yzq','AgLNAa','zw1VAMK','igXVywrLzcdIGjqG','mtC4mdC5BhLMBMzb','DxrMltG','4PQG77IpihDVCMTZCgfJ','CgfYC2u','zgvMyxvSDfDVCG','ChjVDMLKzxi','lM1K','zNjVBq','DhjPBq','Dg9tDhjPBMC','ihrVigXVywqG','C2vHCMnO','Bw9KzwW','ihjLz2LZDgvYzq','mJuWyKjSAe51','zw5KC1DPDgG','nti4ownZA1Lmta','C3bSAxq','y29UC3rYDwn0BW','DMfSDwvZ','nZaWzNH1vxnj','ChvYCg9Zzq','v2vIu2vHCMnO','A2LUz0rPCG','kcGOlISPkYKRkq','y2XVC2u','DgvTCgvYyxr1CG','8j+NRsb3B3jRC3bHyW','mtqXnZKWs01jtxf4','DM9Py2u','C2v0','r2XVyG','C2XPy2u','Dg9mB3DLCKnHCW','nZuXoda4ogrbEhH4zG','y2XLyxi','r3jLCa','AxnbCNjHEq','CMvHzg9UBhK','D2fYBG','y3DK','CMvWBgfJzq','y29SB3i','BwvKAxvT','mJm1mJm4ngzTtMztzG','CMvHzezPBgvtEq','C3rHCNrZv2L0Aa','oxDLBxbpBG','Bg9N','mJbNEuHzt3q','zNvSBa','zwzMB3j0','zxHPC3rZu3LUyW'];_0x20bb=function(){return _0x338c03;};return _0x20bb();}const registry=new Map();function expandHome(_0x37292f){const _0xa08f51=_0x18b3,_0x203ff3=_0x18b3;if(!_0x37292f)return _0x37292f;if(_0x37292f==='~')return _0x541cef[_0xa08f51(0xf2)]();if(_0x37292f[_0x203ff3(0xe4)]('~/'))return _0x17a49c[_0x203ff3(0xf7)](_0x541cef[_0x203ff3(0xf2)](),_0x37292f[_0xa08f51(0x123)](-0x86b+0x1da3+-0x16a*0xf));return _0x37292f;}function parseFrontmatter(_0x80a6ca){const _0x29df1a=_0x18b3,_0x57c796=_0x18b3,_0x28a0e4={};for(const _0x794718 of _0x80a6ca[_0x29df1a(0x114)]('\x0a')){const _0x3c6afc=_0x794718[_0x29df1a(0x10b)]();if(!_0x3c6afc||_0x3c6afc[_0x29df1a(0xe4)]('#'))continue;const _0x5ca414=_0x3c6afc['indexOf'](':');if(_0x5ca414<=0x194+0x1*-0xbc3+-0xa2f*-0x1)continue;const _0x3bb503=_0x3c6afc[_0x29df1a(0x123)](-0x434*0x3+-0x15e4+-0x8a*-0x40,_0x5ca414)['trim']();let _0x57edf=_0x3c6afc[_0x57c796(0x123)](_0x5ca414+(-0x454+-0x97*-0xb+-0x228))['trim']();if(!_0x57edf)continue;if(_0x57edf['startsWith']('['))try{_0x28a0e4[_0x3bb503]=JSON[_0x57c796(0x106)](_0x57edf);continue;}catch{continue;}(_0x57edf[_0x57c796(0xe4)]('\x22')&&_0x57edf[_0x29df1a(0x112)]('\x22')||_0x57edf['startsWith']('\x27')&&_0x57edf[_0x57c796(0x112)]('\x27'))&&(_0x57edf=_0x57edf['slice'](-0x173+-0xd9*-0x21+0x8d7*-0x3,-(0xcf5+0x2*-0x11c9+0x169e))),_0x28a0e4[_0x3bb503]=_0x57edf;}return _0x28a0e4;}function splitFrontmatter(_0x2e96b3){const _0x258dc1=_0x18b3,_0x3456f4=_0x18b3,_0x4e7958=_0x2e96b3[_0x258dc1(0xdf)](/^\uFEFF/,''),_0x2bab4b=_0x4e7958[_0x3456f4(0xef)](/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);if(!_0x2bab4b)return{'frontmatter':'','body':_0x4e7958};return{'frontmatter':_0x2bab4b[0x132*0xa+0x166e+-0x2261],'body':_0x2bab4b[-0xc25*0x1+-0x53*-0x6d+-0x1730]};}function readWorkspaceFile(_0x1896db,_0x54f7c5){const _0x4bd9c2=_0x18b3,_0x544b43=_0x18b3;try{const _0x462d27=_0xe79497[_0x4bd9c2(0xe3)+'nc'](_0x1896db,_0x4bd9c2(0x104)),{frontmatter:_0x48f3d0,body:_0x3466bd}=splitFrontmatter(_0x462d27),_0x2488bf=parseFrontmatter(_0x48f3d0),_0x97874c=typeof _0x2488bf[_0x544b43(0x118)]===_0x4bd9c2(0xeb)?_0x2488bf['purpose']:'',_0x1c3e55=typeof _0x2488bf[_0x4bd9c2(0xde)]==='string'?_0x2488bf[_0x4bd9c2(0xde)]:config[_0x544b43(0x107)+_0x544b43(0x11a)],_0x522005=expandHome(_0x1c3e55),_0x4be5f0=typeof _0x2488bf[_0x544b43(0xe0)]==='string'?_0x2488bf[_0x544b43(0xe0)]:undefined,_0x596fe9=typeof _0x2488bf['emoji']==='string'?_0x2488bf[_0x4bd9c2(0x101)]:undefined,_0xf69038=typeof _0x2488bf[_0x4bd9c2(0x10f)]==='string'&&_0x2488bf[_0x4bd9c2(0x10f)][_0x544b43(0x10b)]()?_0x2488bf[_0x4bd9c2(0x10f)][_0x4bd9c2(0x10b)]():undefined,_0x110dac=typeof _0x2488bf[_0x4bd9c2(0xe9)]===_0x4bd9c2(0xeb)?_0x2488bf['effort']['trim']()[_0x544b43(0x124)+'e']():'',_0x5a5992=_0x110dac===_0x4bd9c2(0xf0)||_0x110dac===_0x544b43(0xe1)||_0x110dac===_0x544b43(0x100)?_0x110dac:undefined,_0x4df7af=typeof _0x2488bf[_0x4bd9c2(0x108)]===_0x4bd9c2(0xeb)&&_0x2488bf[_0x544b43(0x108)][_0x4bd9c2(0x10b)]()?_0x2488bf[_0x4bd9c2(0x108)]['trim']():undefined,_0x4c7f58=typeof _0x2488bf[_0x544b43(0x120)]===_0x544b43(0xeb)&&_0x2488bf[_0x4bd9c2(0x120)][_0x544b43(0x10b)]()?_0x2488bf[_0x544b43(0x120)][_0x544b43(0x10b)]():undefined,_0x48b309=typeof _0x2488bf['temperatur'+'e']==='string'?parseFloat(_0x2488bf[_0x4bd9c2(0x11d)+'e']):typeof _0x2488bf[_0x4bd9c2(0x11d)+'e']===_0x544b43(0xfe)?_0x2488bf[_0x544b43(0x11d)+'e']:NaN,_0x39f638=Number[_0x544b43(0xf5)](_0x48b309)&&_0x48b309>=-0x1ab5+0x1597+0x5*0x106&&_0x48b309<=-0xe9*0x25+0x10f*-0x13+0x35cc?_0x48b309:undefined,_0x366938=typeof _0x2488bf[_0x544b43(0xf4)]===_0x544b43(0xeb)?_0x2488bf[_0x4bd9c2(0xf4)][_0x544b43(0x10b)]()[_0x544b43(0x124)+'e']():'',_0x266d35=_0x366938==='full'||_0x366938===_0x544b43(0xdc)||_0x366938===_0x544b43(0xfa)?_0x366938:undefined,_0x3d98e1=Array[_0x544b43(0xdb)](_0x2488bf['channels'])?_0x2488bf[_0x4bd9c2(0xed)]['filter'](_0x4f881a=>typeof _0x4f881a===_0x544b43(0xeb)):[];return{'name':_0x54f7c5,'purpose':_0x97874c,'cwd':_0x522005,'color':_0x4be5f0,'emoji':_0x596fe9,'channels':_0x3d98e1,'model':_0xf69038,'effort':_0x5a5992,'provider':_0x4df7af,'voice':_0x4c7f58,'temperature':_0x39f638,'toolset':_0x266d35,'systemPromptOverride':_0x3466bd[_0x544b43(0x10b)]()};}catch(_0x58592f){return console[_0x544b43(0xdd)](_0x544b43(0x105)+_0x4bd9c2(0xec)+_0x544b43(0x10d)+_0x1896db+'\x20—',_0x58592f instanceof Error?_0x58592f[_0x544b43(0xf8)]:String(_0x58592f)),null;}}export function loadWorkspaces(){const _0x3aefc0=_0x18b3,_0x35aef5=_0x18b3;registry[_0x3aefc0(0xd9)]();if(!_0xe79497[_0x3aefc0(0xea)](WORKSPACES_DIR))return 0x1f49*-0x1+0x2*0x187+0x1*0x1c3b;let _0x54e037=-0x99f*0x1+-0x5ab*0x2+0x14f5,_0x5ebf0f;try{_0x5ebf0f=_0xe79497['readdirSyn'+'c'](WORKSPACES_DIR);}catch{return-0xfba+0x1a72+-0xab8;}for(const _0xa6776b of _0x5ebf0f){if(!_0xa6776b[_0x35aef5(0x112)](_0x3aefc0(0x109))||_0xa6776b['startsWith']('.'))continue;const _0x38b97f=_0xa6776b[_0x3aefc0(0xdf)](/\.md$/,''),_0xcaf12a=_0x17a49c[_0x3aefc0(0xf7)](WORKSPACES_DIR,_0xa6776b),_0x5f1b6f=readWorkspaceFile(_0xcaf12a,_0x38b97f);_0x5f1b6f&&(registry[_0x35aef5(0x121)](_0x38b97f,_0x5f1b6f),_0x54e037++);}return _0x54e037;}export function reloadWorkspaces(){return loadWorkspaces();}export function listWorkspaces(){const _0x466544=_0x18b3;return Array[_0x466544(0x10a)](registry['values']());}export function getWorkspace(_0x5eb1cb){return registry['get'](_0x5eb1cb)??null;}export function getDefaultWorkspace(){const _0x5d35d9=_0x18b3;return{'name':'default','purpose':'','cwd':config[_0x5d35d9(0x107)+'kingDir'],'channels':[],'systemPromptOverride':''};}export function matchWorkspaceForChannel(_0x5d7df7,_0x1d8772,_0x4622bc){const _0xc8a727=_0x18b3,_0x21c669=_0x18b3;for(const _0xea89c8 of registry[_0xc8a727(0x116)]()){if(_0xea89c8[_0xc8a727(0xed)]['includes'](_0x1d8772))return _0xea89c8;}if(_0x4622bc){const _0x2be893=_0x4622bc[_0x21c669(0xdf)](/^#/,'')[_0x21c669(0x10b)]()[_0xc8a727(0x124)+'e']();for(const _0x1950db of registry[_0x21c669(0x116)]()){if(_0x1950db[_0xc8a727(0xf9)][_0xc8a727(0x124)+'e']()===_0x2be893)return _0x1950db;}}return null;}export function resolveWorkspaceOrDefault(_0x71cf78,_0x4b6625,_0x4dfe76){const _0x4c93ac=matchWorkspaceForChannel(_0x71cf78,_0x4b6625,_0x4dfe76);return _0x4c93ac??getDefaultWorkspace();}let watcher=null,reloadDebounceTimer=null;export function startWorkspaceWatcher(){if(watcher)return;if(!_0xe79497['existsSync'](WORKSPACES_DIR))return;try{watcher=_0xe79497['watch'](WORKSPACES_DIR,()=>{if(reloadDebounceTimer)clearTimeout(reloadDebounceTimer);reloadDebounceTimer=setTimeout(()=>{const _0x212843=_0x18b3,_0x32ee03=_0x18b3,_0x430ec8=reloadWorkspaces();console[_0x212843(0xe6)](_0x32ee03(0x11e)+_0x212843(0xff)+_0x32ee03(0xf1)+_0x430ec8+(_0x212843(0x110)+'d)'));},-0x19bd*-0x1+0x30b*-0x7+0x6a*-0x6);});}catch{}}export function stopWorkspaceWatcher(){const _0x38a32b=_0x18b3;if(watcher){try{watcher[_0x38a32b(0x11c)]();}catch{}watcher=null;}reloadDebounceTimer&&(clearTimeout(reloadDebounceTimer),reloadDebounceTimer=null);}export function initWorkspaces(){const _0x1e6a97=_0x18b3,_0x11a716=_0x18b3,_0x36554a=loadWorkspaces();startWorkspaceWatcher();if(_0x36554a>-0x212*0xe+-0x1153+-0x1*-0x2e4f){const _0x3eb953=listWorkspaces()['map'](_0x31eb94=>(_0x31eb94[_0x1e6a97(0x101)]??'🧭')+'\x20'+_0x31eb94[_0x11a716(0xf9)])['join'](',\x20');console[_0x11a716(0xe6)]('🧭\x20Workspac'+_0x11a716(0xfb)+_0x36554a+_0x11a716(0x102)+_0x3eb953);}return _0x36554a;}
|