alvin-bot 5.7.0 → 5.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +25 -31
- package/dist/claude.js +1 -102
- package/dist/config.js +1 -96
- package/dist/engine.js +1 -90
- package/dist/find-claude-binary.js +1 -98
- package/dist/handlers/async-agent-chunk-handler.js +1 -50
- package/dist/handlers/background-bypass.js +1 -75
- package/dist/handlers/commands.js +1 -2336
- package/dist/handlers/cron-progress.js +1 -52
- package/dist/handlers/document.js +1 -194
- package/dist/handlers/message.js +1 -959
- package/dist/handlers/photo.js +1 -154
- package/dist/handlers/platform-message.js +1 -360
- package/dist/handlers/stuck-timer.js +1 -54
- package/dist/handlers/video.js +1 -237
- package/dist/handlers/voice.js +1 -148
- package/dist/i18n.js +1 -805
- package/dist/index.js +1 -697
- package/dist/init-data-dir.js +1 -98
- package/dist/middleware/auth.js +1 -233
- package/dist/migrate.js +1 -162
- package/dist/paths.js +1 -146
- package/dist/platforms/discord.js +1 -175
- package/dist/platforms/index.js +1 -130
- package/dist/platforms/signal.js +1 -205
- package/dist/platforms/slack-slash-parser.js +1 -32
- package/dist/platforms/slack.js +1 -501
- package/dist/platforms/telegram.js +1 -111
- package/dist/platforms/types.js +1 -8
- package/dist/platforms/whatsapp-auth-helpers.js +1 -53
- package/dist/platforms/whatsapp.js +1 -707
- package/dist/providers/claude-sdk-provider.js +1 -565
- package/dist/providers/codex-cli-provider.js +1 -134
- package/dist/providers/index.js +1 -7
- package/dist/providers/ollama-provider.js +1 -32
- package/dist/providers/openai-compatible.js +1 -406
- package/dist/providers/registry.js +1 -352
- package/dist/providers/runtime-header.js +1 -45
- package/dist/providers/tool-executor.js +1 -475
- package/dist/providers/types.js +1 -227
- package/dist/services/access.js +1 -144
- package/dist/services/allowed-users-gate.js +1 -56
- package/dist/services/alvin-dispatch.js +1 -174
- package/dist/services/alvin-mcp-tools.js +1 -104
- package/dist/services/asset-index.js +1 -224
- package/dist/services/async-agent-parser.js +1 -418
- package/dist/services/async-agent-watcher.js +1 -583
- package/dist/services/auto-diagnostic.js +1 -228
- package/dist/services/broadcast.js +1 -52
- package/dist/services/browser-manager.js +1 -562
- package/dist/services/browser-webfetch.js +1 -127
- package/dist/services/browser.js +1 -121
- package/dist/services/cdp-bootstrap.js +1 -357
- package/dist/services/compaction.js +1 -144
- package/dist/services/critical-notify.js +1 -203
- package/dist/services/cron-resolver.js +1 -58
- package/dist/services/cron-scheduling.js +1 -310
- package/dist/services/cron.js +1 -861
- package/dist/services/custom-tools.js +1 -317
- package/dist/services/delivery-queue.js +1 -173
- package/dist/services/delivery-registry.js +1 -21
- package/dist/services/disk-cleanup.js +1 -203
- package/dist/services/elevenlabs.js +1 -58
- package/dist/services/embeddings/auto-detect.js +1 -74
- package/dist/services/embeddings/fts5.js +1 -108
- package/dist/services/embeddings/gemini.js +1 -65
- package/dist/services/embeddings/index.js +1 -496
- package/dist/services/embeddings/ollama.js +1 -78
- package/dist/services/embeddings/openai.js +1 -49
- package/dist/services/embeddings/provider.js +1 -22
- package/dist/services/embeddings/vector-base.js +1 -113
- package/dist/services/embeddings-migration.js +1 -193
- package/dist/services/embeddings.js +1 -9
- package/dist/services/env-file.js +1 -50
- package/dist/services/exec-guard.js +1 -71
- package/dist/services/fallback-order.js +1 -154
- package/dist/services/file-permissions.js +1 -93
- package/dist/services/heartbeat-file.js +1 -65
- package/dist/services/heartbeat.js +1 -313
- package/dist/services/hooks.js +1 -44
- package/dist/services/imagegen.js +1 -72
- package/dist/services/language-detect.js +1 -154
- package/dist/services/markdown.js +1 -63
- package/dist/services/mcp.js +1 -263
- package/dist/services/memory-extractor.js +1 -178
- package/dist/services/memory-inject-mode.js +1 -43
- package/dist/services/memory-layers.js +1 -156
- package/dist/services/memory.js +1 -146
- package/dist/services/ollama-manager.js +1 -339
- package/dist/services/permissions-wizard.js +1 -291
- package/dist/services/personality.js +1 -376
- package/dist/services/plugins.js +1 -171
- package/dist/services/preflight.js +1 -292
- package/dist/services/process-manager.js +1 -291
- package/dist/services/release-highlights.js +1 -79
- package/dist/services/reminders.js +1 -97
- package/dist/services/restart.js +1 -48
- package/dist/services/security-audit.js +1 -74
- package/dist/services/self-diagnosis.js +1 -272
- package/dist/services/self-search.js +1 -129
- package/dist/services/session-persistence.js +1 -237
- package/dist/services/session.js +1 -282
- package/dist/services/skills.js +1 -290
- package/dist/services/ssrf-guard.js +1 -162
- package/dist/services/standing-orders.js +1 -29
- package/dist/services/steer-channel.js +1 -46
- package/dist/services/stop-controller.js +1 -52
- package/dist/services/subagent-dedup.js +1 -86
- package/dist/services/subagent-delivery.js +1 -452
- package/dist/services/subagent-stats.js +1 -123
- package/dist/services/subagents.js +1 -814
- package/dist/services/sudo.js +1 -329
- package/dist/services/telegram.js +1 -158
- package/dist/services/timing-safe-bearer.js +1 -51
- package/dist/services/tool-discovery.js +1 -214
- package/dist/services/trends.js +1 -580
- package/dist/services/updater.js +1 -291
- package/dist/services/usage-tracker.js +1 -144
- package/dist/services/users.js +1 -271
- package/dist/services/voice.js +1 -104
- package/dist/services/watchdog-brake.js +1 -154
- package/dist/services/watchdog.js +1 -311
- package/dist/services/workspaces.js +1 -276
- package/dist/tui/index.js +1 -667
- package/dist/util/console-formatter.js +1 -109
- package/dist/util/debounce.js +1 -24
- package/dist/util/telegram-error-filter.js +1 -62
- package/dist/version.js +1 -24
- package/dist/web/bind-strategy.js +1 -42
- package/dist/web/canvas.js +1 -30
- package/dist/web/doctor-api.js +1 -604
- package/dist/web/openai-compat.js +1 -252
- package/dist/web/server.js +1 -1902
- package/dist/web/setup-api.js +1 -1101
- package/package.json +5 -2
- package/dist/.metadata_never_index +0 -0
|
@@ -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 _0x5ca307=_0x101f,_0x5a7793=_0x101f;(function(_0x4434dd,_0x159866){const _0x477692=_0x101f,_0x554e5c=_0x101f,_0x287fd9=_0x4434dd();while(!![]){try{const _0x50c5c9=-parseInt(_0x477692(0x226))/(-0x1ca*-0x13+0xfa1+-0x92*0x57)+parseInt(_0x554e5c(0x20f))/(0x1e06+0x780*-0x5+-0x1df*-0x4)*(parseInt(_0x477692(0x1c4))/(0x1580+-0x16dc+0x15f))+parseInt(_0x477692(0x218))/(-0x1ae6+0x101*0x11+-0x1*-0x9d9)*(-parseInt(_0x477692(0x216))/(0x1*-0x2131+0xc1e+0x1518))+-parseInt(_0x477692(0x207))/(0x19bb+0x1c1b*0x1+-0x35d0)*(parseInt(_0x554e5c(0x202))/(-0x1*0x79f+0x1*0x1af0+-0x134a))+parseInt(_0x554e5c(0x256))/(-0x1f6d+-0x14*-0x63+0x1*0x17b9)*(-parseInt(_0x554e5c(0x1f7))/(0x1*0xb23+-0x27*-0xc5+-0x291d))+parseInt(_0x477692(0x1ea))/(-0x8c9+0x11e1+-0x90e)+-parseInt(_0x477692(0x1f6))/(0x2155*0x1+0x1e9e+-0xcc8*0x5)*(-parseInt(_0x477692(0x1ef))/(0x1d7e+-0xc89+-0x10e9));if(_0x50c5c9===_0x159866)break;else _0x287fd9['push'](_0x287fd9['shift']());}catch(_0x4402c0){_0x287fd9['push'](_0x287fd9['shift']());}}}(_0x52aa,0x34*0x3565+0x7a187+-0x1*0x92741));const _0x6c5637=(function(){let _0x39698c=!![];return function(_0x457a2b,_0x1f2dd1){const _0x43687a=_0x39698c?function(){const _0x4e1e9f=_0x101f;if(_0x1f2dd1){const _0x3dcc92=_0x1f2dd1[_0x4e1e9f(0x1d0)](_0x457a2b,arguments);return _0x1f2dd1=null,_0x3dcc92;}}:function(){};return _0x39698c=![],_0x43687a;};}()),_0x2bfb00=_0x6c5637(this,function(){const _0x473c38=_0x101f,_0x135a42=_0x101f;return _0x2bfb00[_0x473c38(0x22b)]()[_0x473c38(0x217)]('(((.+)+)+)'+'+$')[_0x473c38(0x22b)]()['constructo'+'r'](_0x2bfb00)[_0x473c38(0x217)](_0x135a42(0x1e4)+'+$');});_0x2bfb00();import _0x36fcbb from'fs';import{resolve}from'path';import _0x375889 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[_0x5ca307(0x242)][_0x5a7793(0x1cb)+_0x5a7793(0x1e2)]||resolve(_0x375889[_0x5a7793(0x263)](),_0x5ca307(0x1fb)),STATE_DIR=resolve(DATA_DIR,'state'),BEACON_FILE=resolve(STATE_DIR,_0x5a7793(0x239)+'son'),ALERT_FILE=resolve(STATE_DIR,_0x5ca307(0x1c2)+_0x5a7793(0x213)),BEACON_INTERVAL_MS=-0x21d*0x20+0xc5*-0x11b+0x19297*0x1;let beaconTimer=null,resetTimer=null,bootTime=-0xaa8+0xb27+-0x7f,bootExpectedRestart=![];export function bootWasExpectedRestart(){return bootExpectedRestart;}function ensureStateDir(){const _0x213fb2=_0x5ca307,_0x3f6afa=_0x5a7793;try{_0x36fcbb['mkdirSync'](STATE_DIR,{'recursive':!![]});}catch(_0x91f0a7){console['error']('[watchdog]'+_0x213fb2(0x24a)+_0x3f6afa(0x251)+_0x213fb2(0x205),_0x91f0a7);}}function readBeacon(){const _0x456e04=_0x5ca307,_0x3dc4b7=_0x5a7793;try{const _0x2bf0f9=_0x36fcbb[_0x456e04(0x255)+'nc'](BEACON_FILE,_0x3dc4b7(0x1e9));return normalizeBeacon(JSON[_0x456e04(0x1f8)](_0x2bf0f9));}catch{return null;}}function writeBeacon(_0x33b837){const _0xf5ec37=_0x5a7793,_0x106490=_0x5ca307;try{_0x36fcbb[_0xf5ec37(0x21d)+_0x106490(0x1cd)](BEACON_FILE,JSON[_0xf5ec37(0x20c)](_0x33b837,null,0xc26+0xb8c+0x2a2*-0x9),_0xf5ec37(0x1e9));}catch(_0x3246ac){console[_0x106490(0x227)](_0x106490(0x231)+_0xf5ec37(0x24a)+_0xf5ec37(0x1e0)+_0xf5ec37(0x244),_0x3246ac);}}function _0x101f(_0x43dae7,_0x5e1cc6){_0x43dae7=_0x43dae7-(-0x1*-0x433+0x17f3+-0xda*0x1f);const _0x2b106d=_0x52aa();let _0x4704a4=_0x2b106d[_0x43dae7];if(_0x101f['uagtSB']===undefined){var _0x4f2d34=function(_0x3e43b6){const _0xf7cb58='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x22b790='',_0x4f42d9='',_0x10900a=_0x22b790+_0x4f2d34;for(let _0x290bb9=0x23d*-0x2+0x2b*0x6b+-0xd7f,_0x527d8e,_0xa2d65d,_0x26f089=-0x244c+0x25*0xc2+0x421*0x2;_0xa2d65d=_0x3e43b6['charAt'](_0x26f089++);~_0xa2d65d&&(_0x527d8e=_0x290bb9%(-0xaa8+0xb27+-0x7b)?_0x527d8e*(0xc26+0xb8c+0xbb9*-0x2)+_0xa2d65d:_0xa2d65d,_0x290bb9++%(0x1*-0x167c+-0x1af*-0x2+-0x3e*-0x4f))?_0x22b790+=_0x10900a['charCodeAt'](_0x26f089+(-0x4f*0x6f+0x1aa0+0xd*0x97))-(0x57*0x59+0x157d+-0x33b2)!==0xab9*0x1+-0x1*-0x2709+-0x31c2?String['fromCharCode'](0xc65+-0x555+-0x611&_0x527d8e>>(-(-0x1345*0x2+0xd55+0x1937)*_0x290bb9&-0x836+0x27*0xe5+-0x1aa7)):_0x290bb9:-0x1*-0x19db+0x13*-0x1ac+-0x5e9*-0x1){_0xa2d65d=_0xf7cb58['indexOf'](_0xa2d65d);}for(let _0x3e0cfe=-0x1732*0x1+-0x1dcb*0x1+0x34fd,_0x599579=_0x22b790['length'];_0x3e0cfe<_0x599579;_0x3e0cfe++){_0x4f42d9+='%'+('00'+_0x22b790['charCodeAt'](_0x3e0cfe)['toString'](-0x1ef4+0x19cd+0x537))['slice'](-(0x1c6d+0x19a4*-0x1+-0x2c7));}return decodeURIComponent(_0x4f42d9);};_0x101f['SiEjuV']=_0x4f2d34,_0x101f['LudbEy']={},_0x101f['uagtSB']=!![];}const _0x3571fd=_0x2b106d[0x7f4*-0x3+-0x11be+0x299a],_0x3d34a1=_0x43dae7+_0x3571fd,_0x4740bb=_0x101f['LudbEy'][_0x3d34a1];if(!_0x4740bb){const _0x4d8ffd=function(_0x5c0b15){this['kPIBoF']=_0x5c0b15,this['irXQJp']=[-0xc16*0x3+0x646+0x3*0x9ff,0x1*-0x1f99+-0x312+-0x6ef*-0x5,0x1ccd+-0x255+-0x1a78],this['nFlpYf']=function(){return'newState';},this['SPyOAP']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['IVSZYz']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x4d8ffd['prototype']['CQbFXD']=function(){const _0x172911=new RegExp(this['SPyOAP']+this['IVSZYz']),_0x5f315c=_0x172911['test'](this['nFlpYf']['toString']())?--this['irXQJp'][0x12c4+0x15a0+-0x1*0x2863]:--this['irXQJp'][-0x1*-0x98c+-0x12e7+0x95b];return this['hlwZUr'](_0x5f315c);},_0x4d8ffd['prototype']['hlwZUr']=function(_0x17ce3c){if(!Boolean(~_0x17ce3c))return _0x17ce3c;return this['TSsuzb'](this['kPIBoF']);},_0x4d8ffd['prototype']['TSsuzb']=function(_0x2dbe01){for(let _0x26a779=-0x4*-0x153+-0x2ea+-0x262,_0x1bf0bc=this['irXQJp']['length'];_0x26a779<_0x1bf0bc;_0x26a779++){this['irXQJp']['push'](Math['round'](Math['random']())),_0x1bf0bc=this['irXQJp']['length'];}return _0x2dbe01(this['irXQJp'][0x3*0x982+0x1*-0xda9+-0xedd*0x1]);},new _0x4d8ffd(_0x101f)['CQbFXD'](),_0x4704a4=_0x101f['SiEjuV'](_0x4704a4),_0x101f['LudbEy'][_0x3d34a1]=_0x4704a4;}else _0x4704a4=_0x4740bb;return _0x4704a4;}function _0x52aa(){const _0x2c97a0=['lMfSDMLUlwjVDa','pt09pt09pt09pq','iIaMjIbHBhzPBG','q291BNq','zgXLihDYAxr0zq','refjtfLFqLjbsW','AxrZzwXMihrVia','n0LUD1zoBa','Bgf1BMnOy3rSia','igf0ia','yxrLigrPCJO','igjLywnVBIbLDG','ntmWnZaWnK9uy0rtEG','BgfZDejLyxq','DgvYia','B3aGyNjHA2uGAq','BgWGBM90igf1Da','C3rYAw5NAwz5','BNrLCIa','ChjLDMvUDcbMDq','mJe0uMP3u2z2','y3jHC2HxAw5KBW','q3jHC2HLCYbPBG','w2f1Dg8TzgLHzW','lMfSzxj0','Dw5SB2fKic13ia','vgHLigjVDcbOyq','mtu5nZy3nxvxrfHHwq','C2vHCMnO','ng15DNblBq','CMvZzxr0Aw5Nia','y3jPDgLJywW','B3qUyxbWlNbSAq','CM9YigXVzZO','D3jPDgvgAwXLuW','BJOG','BgWGCMvMDxnLia','ihrOzsbSyxn0ia','CMvUC2LJigj1BG','CM0GiG','t05Ftvm','ihjLy2vUDcbLCG','y3jHC2HdB3vUDa','oteXmZLese1iAxm','zxjYB3i','Bgq6ia','Dg9ju09tDhjPBG','BM9ZDgLJxsbMBW','Dg9tDhjPBMC','BwLUihDPBMrVDW','DcbJCMfZAc1SBW','zNrLCIa','yNjHA2u','icbHBhzPBI1IBW','w3DHDgnOzg9Nxq','qwX2Aw4GqM90ia','lwjVDcbSyxvUyW','B3iG','zxHPC3rZu3LUyW','uL9nuW','B3CGDgHYzxnOBW','uKvtrvrFquzurq','D2f0y2HKB2CUAG','DcbPCYbYzwXVyq','ihDYAxrLigfSzq','CMfZAc1SB29Wia','BgvKoG','ignYyxnOlwXVBW','zxHWzwn0zwrszq','CYdIGjqG','u0HpuLrFqLjbsW','zw52','CgLK','y29UoG','uMvHC29UoIa','y29TlMfSDMLUyG','B3CGy3jHC2GGyW','BM93','vMvYC2LVBJOG','igzHAwXLzcb0BW','AM9PBG','DgvWCYbVBMnLia','C3rHCNq','Ew91j3zLigzPEa','zxj5ia','ihrVidaG','ignYzwf0zsbZDa','ieXHDw5JAefNzq','BM90Awz5igzHAq','DcaYngGGD2LUza','CMvHzezPBgvtEq','nJa5odqZmNDbyxnHqq','igjYywTLigHPDa','CMfRzq','cGPeAwfNBM9ZDa','CcbICMfRzsb0CG','t1DFtvm','ihvUBg9Hzcbmyq','DcbSyxvUy2HKia','Dg8GC3rHCNqGDq','ihn0yxLZkq','tgf1BMnOqwDLBG','BY1Yzxn0yxj0lG','iYbVCIbQDxn0ia','Ag9TzwrPCG','CYWG','BNrPBcb0AgLZia','rv9usfjfu0Hpta','zgfPBhLdCMfZAa','y3jHC2GTBg9VCa','igrLDgvJDgvKia','otK2sgrrww1A','ihn0yxj0zwqG4Ocu','CMvHC29U','zgfYD2LU','D2f0y2HKB2CTyG','qM90ihzLCNnPBW','DgHL','quXwsu5Frefuqq','CNrOzxiGzgfTyq','Ew5J','ywn0Aw9U','Dxb0Aw1LiokaLca','yxbWBhK','kgrHAwX5ignVDq','rgfPBhKGDgHYzq','BM9ZDgLJigzHAq','u0HpuLrFv0Lora','CMvJB3zLCNKGyq','CgLWzq','Bw92zwqGqu5eia','z2uU','CM91BMq','CMvZDgfYDcbHzG','y3jHC2GG','v2f0y2HKB2CGyW','DgLNyxrLihrOzq','DgHLihnLCNzPyW','AgqGAw5ZDgfSBa','ihDYAxrLigjLyq','B3vUDgvYigzYBW','x0rjuG','C2HVCNqTD2LUza','kcGOlISPkYKRkq','zxjYlMXVzW','ywX2Aw4TyM90lG','uMvJB3zLCNKGCW','yNjHA2uGyxqG','DxrMltG','odKYmZiYmgDuqNnmvq','BwLUignSzwfUia','tgLICMfYEq','4PUuigfSDMLUlwjV','Dw5JAefNzw50oG','mtjlBfPKEwW','CYbZDg9WCgvKia','yNjHA2uGzw5Nyq','u2HVCNqTD2LUza','AwmGyNvUzgXLoG','z2vK','CYbLBMDHz2vK','mtKXndCXnJfsyxfREMS','oufeBeTKta','CgfYC2u','Bg9N','Bg9NCW'];_0x52aa=function(){return _0x2c97a0;};return _0x52aa();}export function markExpectedRestart(){const _0x4518f0=_0x5ca307,_0x2697a9=readBeacon();if(!_0x2697a9)return;writeBeacon({..._0x2697a9,'lastBeat':Date[_0x4518f0(0x248)](),'expectedRestart':!![]});}function writeAlert(_0x4fc6e0,_0xa406be){const _0x468acb=_0x5ca307,_0x1686a5=_0x5a7793;try{const _0x52d699=[_0x468acb(0x232)+_0x468acb(0x1c2)+_0x468acb(0x257)+_0x468acb(0x204)+new Date()[_0x468acb(0x229)+'g'](),_0x1686a5(0x249)+BOT_VERSION,_0x1686a5(0x211)+_0x1686a5(0x220)+DEFAULTS[_0x468acb(0x1d4)+_0x1686a5(0x25b)]/(0x1*-0x10dd2+-0x2e3*-0xe+-0x123*-0x198)+'\x20minutes:\x20'+_0xa406be,_0x468acb(0x1f2)+_0x468acb(0x237)+_0x1686a5(0x228)+DEFAULTS[_0x1686a5(0x241)+_0x1686a5(0x1c0)+'D'],_0x468acb(0x1d2)+'shold:\x20'+DEFAULTS['DAILY_BRAK'+_0x468acb(0x1c0)+'D'],'',_0x468acb(0x245)+_0x4fc6e0,'','The\x20bot\x20wi'+_0x468acb(0x21f)+_0x468acb(0x25e)+_0x468acb(0x265)+'file\x20is\x20re'+_0x468acb(0x1d7)+_0x468acb(0x1ca),_0x468acb(0x260)+_0x1686a5(0x23a)+'ded.\x20Inves'+_0x1686a5(0x1dd)+_0x468acb(0x224)+_0x468acb(0x21c),'\x20\x20'+resolve(DATA_DIR,_0x468acb(0x1fa),_0x468acb(0x1e6)+_0x468acb(0x1e5)),'',_0x468acb(0x1e7)+_0x1686a5(0x24c)+_0x1686a5(0x24e)+'ed\x20the\x20und'+'erlying\x20is'+'sue:','\x20\x20rm\x20\x22'+ALERT_FILE+'\x22',_0x468acb(0x230)+_0x1686a5(0x25d)+'install\x20\x20\x20'+_0x468acb(0x262)+'kickstart\x20'+_0x468acb(0x1de)+'e',''][_0x1686a5(0x24b)]('\x0a');_0x36fcbb[_0x468acb(0x21d)+_0x468acb(0x1cd)](ALERT_FILE,_0x52d699,_0x1686a5(0x1e9));}catch(_0x2cd805){console[_0x1686a5(0x227)](_0x1686a5(0x231)+_0x468acb(0x24a)+_0x468acb(0x23b)+'rt:',_0x2cd805);}}export function checkCrashLoopBrake(){const _0x5d13a5=_0x5ca307,_0x2434d5=_0x5ca307;if(!_0x36fcbb[_0x5d13a5(0x235)](ALERT_FILE))return;console[_0x5d13a5(0x227)](''),console[_0x2434d5(0x227)](_0x2434d5(0x1fc)+'=========='+_0x5d13a5(0x1fc)+_0x2434d5(0x1fc)+'=========='),console[_0x2434d5(0x227)](_0x5d13a5(0x1ed)+_0x5d13a5(0x22d)+_0x2434d5(0x20a)+_0x2434d5(0x1f5)),console[_0x5d13a5(0x227)](_0x5d13a5(0x1fc)+_0x2434d5(0x1fc)+_0x2434d5(0x1fc)+_0x2434d5(0x1fc)+_0x5d13a5(0x1fc));try{const _0x14cbfd=_0x36fcbb[_0x5d13a5(0x255)+'nc'](ALERT_FILE,_0x5d13a5(0x1e9));console[_0x2434d5(0x227)](_0x14cbfd);}catch{}if(process['platform']===_0x5d13a5(0x1c7))try{const _0x379c16=_0x375889[_0x2434d5(0x263)](),_0x24dee6=resolve(_0x379c16,_0x2434d5(0x1ec),'LaunchAgen'+'ts',_0x5d13a5(0x246)+_0x2434d5(0x21b)+'st');_0x36fcbb[_0x5d13a5(0x235)](_0x24dee6)&&(execSync(_0x2434d5(0x203)+_0x2434d5(0x214)+'\x22'+_0x24dee6+'\x22',{'stdio':_0x5d13a5(0x1d6)}),console[_0x2434d5(0x227)](_0x5d13a5(0x231)+_0x2434d5(0x252)+'nt\x20unloade'+'d\x20—\x20bot\x20wi'+_0x5d13a5(0x20b)+_0x2434d5(0x261)));}catch(_0x46973f){console[_0x2434d5(0x227)](_0x2434d5(0x231)+_0x2434d5(0x24a)+_0x2434d5(0x25c)+_0x5d13a5(0x1ee),_0x46973f);}process['exit'](-0x4f*0x6f+0x1aa0+0x4*0x1e9);}export function startWatchdog(){const _0x25d66f=_0x5a7793,_0x18f606=_0x5a7793;ensureStateDir(),bootTime=Date['now']();const _0x4a153a=readBeacon();bootExpectedRestart=_0x4a153a?.[_0x25d66f(0x23f)+_0x18f606(0x24d)]===!![];const _0x911d5a=decideBrakeAction(_0x4a153a,bootTime);if(_0x911d5a[_0x25d66f(0x1ce)]===_0x18f606(0x22f)){console[_0x18f606(0x227)](_0x25d66f(0x231)+_0x25d66f(0x23e)+_0x18f606(0x25a)+'iggered:\x20'+_0x911d5a[_0x18f606(0x1c6)]),writeAlert(_0x911d5a[_0x18f606(0x1c6)],_0x4a153a?.['crashCount']??0x57*0x59+0x157d+-0x33bc);let _0x189e5c=null;try{_0x189e5c=writeDiagnosticBundle({'category':_0x18f606(0x1c8)+_0x18f606(0x258),'severity':_0x25d66f(0x21a),'title':'Watchdog\x20c'+_0x25d66f(0x23c)+_0x18f606(0x1f1)+_0x18f606(0x1f4),'detail':_0x911d5a[_0x18f606(0x1c6)]+'\x0a'+(_0x25d66f(0x1c9)+_0x25d66f(0x21e)+BOT_VERSION),'suggestedAction':'rm\x20\x22'+ALERT_FILE+(_0x25d66f(0x1fd)+_0x25d66f(0x233)+_0x18f606(0x1df))}),_0x189e5c&&console[_0x25d66f(0x227)](_0x25d66f(0x212)+_0x18f606(0x22a)+_0x25d66f(0x221)+_0x25d66f(0x1ff)+_0x18f606(0x21e)+_0x189e5c);}catch(_0x3f2209){console['error'](_0x25d66f(0x231)+'\x20auto-diag'+_0x25d66f(0x1d3)+'led:',_0x3f2209);}try{emitCritical({'category':_0x18f606(0x1c8)+'rake','severity':_0x25d66f(0x21a),'title':_0x25d66f(0x1dc)+_0x25d66f(0x23c)+_0x18f606(0x1f1)+'ged','detail':_0x911d5a[_0x18f606(0x1c6)]+'\x0a'+('Bot\x20versio'+_0x25d66f(0x21e)+BOT_VERSION+'\x0a')+(_0x18f606(0x215)+_0x18f606(0x1f0)+_0x25d66f(0x201)+_0x18f606(0x20e)+_0x25d66f(0x1cc)+_0x18f606(0x1d8))+(_0x189e5c?_0x18f606(0x259)+_0x18f606(0x1f3)+'\x20'+_0x189e5c:''),'suggestedAction':_0x25d66f(0x222)+ALERT_FILE+(_0x18f606(0x1fd)+_0x18f606(0x233)+_0x25d66f(0x1df))},{'blockTelegram':!![]});}catch(_0x2edc3f){console[_0x25d66f(0x227)]('[watchdog]'+'\x20critical-'+_0x25d66f(0x253)+_0x25d66f(0x23d),_0x2edc3f);}checkCrashLoopBrake(),process['exit'](0xab9*0x1+-0x1*-0x2709+-0x31bf);}let _0xf7c1a7=_0x911d5a[_0x25d66f(0x225)],_0x361ab0=_0x911d5a[_0x18f606(0x210)+'wStart'],_0x2cf673=_0x911d5a[_0x18f606(0x1c1)+_0x25d66f(0x1fe)],_0x3b57cb=_0x911d5a[_0x18f606(0x1c1)+'WindowStar'+'t'];if(_0x4a153a){const _0x2dbce8=bootTime-_0x4a153a[_0x18f606(0x208)];_0x2dbce8<DEFAULTS['STALE_BEAC'+_0x25d66f(0x223)]&&console[_0x18f606(0x1f9)](_0x18f606(0x231)+_0x18f606(0x1c3)+_0x25d66f(0x1da)+_0x25d66f(0x209)+Math['round'](_0x2dbce8/(0xc65+-0x555+-0x328))+_0x25d66f(0x240)+(_0x18f606(0x1db)+_0xf7c1a7+'/'+DEFAULTS['SHORT_BRAK'+_0x25d66f(0x1c0)+'D']+('\x20in\x20curren'+'t\x20'))+(DEFAULTS[_0x25d66f(0x1d4)+_0x18f606(0x25b)]/(-0x1b34*0x11+0x9ffb+0x218d9)+(_0x25d66f(0x22c)+',\x20'))+(_0x2cf673+'/'+DEFAULTS[_0x25d66f(0x200)+_0x25d66f(0x1c0)+'D']+('\x20in\x20curren'+_0x18f606(0x254)+'ow')));}writeBeacon({'lastBeat':bootTime,'pid':process[_0x18f606(0x243)],'bootTime':bootTime,'crashCount':_0xf7c1a7,'crashWindowStart':_0x361ab0,'dailyCrashCount':_0x2cf673,'dailyCrashWindowStart':_0x3b57cb,'version':BOT_VERSION}),beaconTimer=setInterval(()=>{const _0x50527a=_0x25d66f,_0x3c3aee=_0x25d66f;writeBeacon({'lastBeat':Date[_0x50527a(0x248)](),'pid':process[_0x50527a(0x243)],'bootTime':bootTime,'crashCount':_0xf7c1a7,'crashWindowStart':_0x361ab0,'dailyCrashCount':_0x2cf673,'dailyCrashWindowStart':_0x3b57cb,'version':BOT_VERSION});},BEACON_INTERVAL_MS),resetTimer=setTimeout(()=>{const _0x137cff=_0x18f606,_0x3d7d32=_0x18f606,_0x642b1a=Date[_0x137cff(0x248)]()-bootTime;shouldResetCrashCounter(_0x642b1a)&&_0xf7c1a7>-0x836+0x27*0xe5+-0x1aad&&(console[_0x3d7d32(0x1f9)](_0x3d7d32(0x231)+'\x20'+Math[_0x3d7d32(0x1d9)](_0x642b1a/(-0x1*-0x13645+0x1*-0x17d2b+-0x3d0e*-0x5))+(_0x137cff(0x1eb)+_0x137cff(0x1cf))+(_0x3d7d32(0x219)+_0x3d7d32(0x1e3)+_0x137cff(0x247)+_0x3d7d32(0x1e1)+'m\x20'+_0xf7c1a7+_0x3d7d32(0x250))+(_0x3d7d32(0x1d1)+_0x3d7d32(0x20d)+_0x2cf673+_0x3d7d32(0x25f))),_0xf7c1a7=-0x1732*0x1+-0x1dcb*0x1+0x34fd,_0x361ab0=Date[_0x3d7d32(0x248)](),writeBeacon({'lastBeat':Date[_0x137cff(0x248)](),'pid':process[_0x3d7d32(0x243)],'bootTime':bootTime,'crashCount':_0xf7c1a7,'crashWindowStart':_0x361ab0,'dailyCrashCount':_0x2cf673,'dailyCrashWindowStart':_0x3b57cb,'version':BOT_VERSION}));},DEFAULTS[_0x18f606(0x238)+_0x18f606(0x236)]),console[_0x25d66f(0x1f9)](_0x18f606(0x231)+_0x25d66f(0x1c5)+_0x25d66f(0x206)+_0x25d66f(0x24f)+BEACON_INTERVAL_MS/(-0x1ef4+0x19cd+0x90f)+_0x25d66f(0x264)+(_0x25d66f(0x1e8)+DEFAULTS['SHORT_BRAK'+_0x25d66f(0x1c0)+'D']+('\x20crashes\x20/'+'\x20')+DEFAULTS[_0x25d66f(0x1d4)+'OW_MS']/(0x15517+0x6690*-0x3+0xc8f9)+'min\x20')+(_0x25d66f(0x234)+DEFAULTS[_0x25d66f(0x200)+'E_THRESHOL'+'D']+'\x20/\x2024h,\x20')+(_0x25d66f(0x1d5)+_0x18f606(0x22e)+DEFAULTS['RESET_AFTE'+_0x25d66f(0x236)]/(0x17dc*-0xc+-0xd4e4+0x2dd94)+'min\x20uptime'));}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(_0x506a33,_0x9ff9bf){const _0x3d713b=_0xf23d,_0x578ada=_0xf23d,_0xbc20b=_0x506a33();while(!![]){try{const _0x241785=parseInt(_0x3d713b(0x13d))/(0x55a+-0x1*-0xe91+-0x9f5*0x2)*(parseInt(_0x578ada(0x140))/(0x155c+-0xff7+-0x563))+parseInt(_0x3d713b(0x102))/(0xe*-0x287+-0x1*0x1be+-0x1*-0x2523)*(parseInt(_0x578ada(0x104))/(0x127+0x2*0x12c3+-0x26a9))+-parseInt(_0x578ada(0x134))/(0x2056+0x2b6+-0x2307)+parseInt(_0x578ada(0x126))/(-0x240+0x2038+-0x1df2)+-parseInt(_0x3d713b(0x100))/(0x1*-0x355+-0x1139*-0x1+-0xddd)*(-parseInt(_0x578ada(0x117))/(0x1423+-0x21c1*-0x1+-0x35dc))+parseInt(_0x3d713b(0x132))/(0xc5b+-0xae4+-0x16e)+-parseInt(_0x578ada(0x11e))/(0x4*0x822+0x161b+0x1233*-0x3);if(_0x241785===_0x9ff9bf)break;else _0xbc20b['push'](_0xbc20b['shift']());}catch(_0x2c7f1c){_0xbc20b['push'](_0xbc20b['shift']());}}}(_0x4290,0x2a1c9*0x2+-0x25519*0x5+0xcb485));const _0x5256ce=(function(){let _0x1af145=!![];return function(_0x16f6e9,_0x55a076){const _0x186d86=_0x1af145?function(){const _0xa0dac7=_0xf23d;if(_0x55a076){const _0xdb7fef=_0x55a076[_0xa0dac7(0x10c)](_0x16f6e9,arguments);return _0x55a076=null,_0xdb7fef;}}:function(){};return _0x1af145=![],_0x186d86;};}()),_0x283eed=_0x5256ce(this,function(){const _0x340f15=_0xf23d,_0x15e404=_0xf23d;return _0x283eed[_0x340f15(0x135)]()[_0x15e404(0xfc)](_0x15e404(0x107)+'+$')[_0x340f15(0x135)]()['constructo'+'r'](_0x283eed)[_0x15e404(0xfc)](_0x340f15(0x107)+'+$');});function _0xf23d(_0x17b4a8,_0xdcdafa){_0x17b4a8=_0x17b4a8-(-0x1*-0x757+-0x1089*0x1+0xa2c);const _0x27ee25=_0x4290();let _0x1c3369=_0x27ee25[_0x17b4a8];if(_0xf23d['RRwCgZ']===undefined){var _0x2dc058=function(_0x32cd6c){const _0x19cbc9='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x5cc8de='',_0x20ce8b='',_0x315baa=_0x5cc8de+_0x2dc058;for(let _0x17fe2d=0x2*-0xc4+-0x1*-0x16f6+-0x156e,_0x1a29d2,_0x2b4505,_0xb239a6=0x1*-0x1357+-0x14c7+0x281e;_0x2b4505=_0x32cd6c['charAt'](_0xb239a6++);~_0x2b4505&&(_0x1a29d2=_0x17fe2d%(0x1fa6+-0x236f+-0x8b*-0x7)?_0x1a29d2*(0x144e+0x28*-0x1b+0x7eb*-0x2)+_0x2b4505:_0x2b4505,_0x17fe2d++%(0x1898+0x25d+-0x39*0x79))?_0x5cc8de+=_0x315baa['charCodeAt'](_0xb239a6+(0x1d25+0x1fd4+0x13*-0x335))-(0x17c2+-0x858*0x4+0x9a8)!==-0xde2+-0x25*-0x98+-0x5*0x19e?String['fromCharCode'](0x1924+0x80*-0x20+0x825*-0x1&_0x1a29d2>>(-(-0x12de+-0x1771+0x3*0xe1b)*_0x17fe2d&0x6*-0x3df+-0x329*0x7+0x2d5f)):_0x17fe2d:0x8c2+0x12f1*0x1+-0x7*0x3f5){_0x2b4505=_0x19cbc9['indexOf'](_0x2b4505);}for(let _0x85fb29=-0x592+0x77b*-0x3+0x1c03,_0x2e711b=_0x5cc8de['length'];_0x85fb29<_0x2e711b;_0x85fb29++){_0x20ce8b+='%'+('00'+_0x5cc8de['charCodeAt'](_0x85fb29)['toString'](-0xb36*-0x3+0x5*-0xee+-0x73b*0x4))['slice'](-(0x566+0x454+0x1*-0x9b8));}return decodeURIComponent(_0x20ce8b);};_0xf23d['dvMqIN']=_0x2dc058,_0xf23d['vVhtdK']={},_0xf23d['RRwCgZ']=!![];}const _0xe6b417=_0x27ee25[-0x5*-0x5c6+-0x159d+-0x26b*0x3],_0x2312c4=_0x17b4a8+_0xe6b417,_0x256b0a=_0xf23d['vVhtdK'][_0x2312c4];if(!_0x256b0a){const _0x52823d=function(_0x1376d7){this['xQBdaZ']=_0x1376d7,this['ajOtDx']=[-0x10d8+0x892+0x847,0x1f15+0x29*-0x77+-0x39*0x36,-0x5bf+0x351+0x26e],this['Ofhcaq']=function(){return'newState';},this['wyAGOK']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['RgPOFX']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x52823d['prototype']['vzpOuN']=function(){const _0x4d644f=new RegExp(this['wyAGOK']+this['RgPOFX']),_0x213570=_0x4d644f['test'](this['Ofhcaq']['toString']())?--this['ajOtDx'][-0x1ea9+0x4b*0x71+-0x271]:--this['ajOtDx'][-0x1552+-0x1*0xcc7+0x2219];return this['kWKXQL'](_0x213570);},_0x52823d['prototype']['kWKXQL']=function(_0x5aed1c){if(!Boolean(~_0x5aed1c))return _0x5aed1c;return this['yeAvvq'](this['xQBdaZ']);},_0x52823d['prototype']['yeAvvq']=function(_0x478b76){for(let _0x199dc3=0x1*-0x136d+0x174*0x3+-0x227*-0x7,_0x3c0a10=this['ajOtDx']['length'];_0x199dc3<_0x3c0a10;_0x199dc3++){this['ajOtDx']['push'](Math['round'](Math['random']())),_0x3c0a10=this['ajOtDx']['length'];}return _0x478b76(this['ajOtDx'][0x1bb3+0x132d+-0x2ee0]);},new _0x52823d(_0xf23d)['vzpOuN'](),_0x1c3369=_0xf23d['dvMqIN'](_0x1c3369),_0xf23d['vVhtdK'][_0x2312c4]=_0x1c3369;}else _0x1c3369=_0x256b0a;return _0x1c3369;}_0x283eed();import _0x1b21b5 from'fs';import _0x3a25b0 from'os';import _0x950d15 from'path';import{WORKSPACES_DIR}from'../paths.js';import{config}from'../config.js';export function toolsetToAllowedTools(_0x55e2f9){const _0x51b462=_0xf23d,_0x2d4960=_0xf23d;if(!_0x55e2f9||_0x55e2f9===_0x51b462(0x138))return undefined;if(_0x55e2f9===_0x51b462(0x127))return[_0x2d4960(0x130),_0x51b462(0xff),_0x51b462(0x11a),'WebSearch','WebFetch'];if(_0x55e2f9===_0x2d4960(0x10e))return['Read',_0x2d4960(0x105),_0x2d4960(0x120),_0x2d4960(0x11a)];return undefined;}const registry=new Map();function expandHome(_0x41f1b4){const _0x5855fa=_0xf23d,_0x458b35=_0xf23d;if(!_0x41f1b4)return _0x41f1b4;if(_0x41f1b4==='~')return _0x3a25b0[_0x5855fa(0x103)]();if(_0x41f1b4['startsWith']('~/'))return _0x950d15[_0x458b35(0x121)](_0x3a25b0['homedir'](),_0x41f1b4['slice'](-0x75f+0x1*-0x1357+0x1ab8));return _0x41f1b4;}function parseFrontmatter(_0x2fe611){const _0x1dfa26=_0xf23d,_0x5c09a0=_0xf23d,_0x15c5e6={};for(const _0x28ad78 of _0x2fe611[_0x1dfa26(0xfa)]('\x0a')){const _0x33bcd0=_0x28ad78[_0x5c09a0(0x129)]();if(!_0x33bcd0||_0x33bcd0['startsWith']('#'))continue;const _0xad8921=_0x33bcd0[_0x1dfa26(0x106)](':');if(_0xad8921<=-0x159c+0x1fa6+-0xa0a)continue;const _0x187ec7=_0x33bcd0[_0x1dfa26(0x112)](-0x3*-0x560+-0x13ea+0x61*0xa,_0xad8921)[_0x5c09a0(0x129)]();let _0x197d34=_0x33bcd0['slice'](_0xad8921+(0x1*0x5f4+0x18fe+-0x1ef1))[_0x1dfa26(0x129)]();if(!_0x197d34)continue;if(_0x197d34[_0x5c09a0(0x110)]('['))try{_0x15c5e6[_0x187ec7]=JSON[_0x1dfa26(0x10a)](_0x197d34);continue;}catch{continue;}(_0x197d34[_0x5c09a0(0x110)]('\x22')&&_0x197d34[_0x1dfa26(0x118)]('\x22')||_0x197d34[_0x1dfa26(0x110)]('\x27')&&_0x197d34['endsWith']('\x27'))&&(_0x197d34=_0x197d34['slice'](0x95b*0x2+-0x10c8+-0x1ed,-(-0x6d0*-0x3+0xa20+-0x1e8f*0x1))),_0x15c5e6[_0x187ec7]=_0x197d34;}return _0x15c5e6;}function splitFrontmatter(_0xa445a8){const _0x2ab657=_0xf23d,_0x581858=_0xa445a8[_0x2ab657(0x12e)](/^\uFEFF/,''),_0x1c1dad=_0x581858['match'](/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);if(!_0x1c1dad)return{'frontmatter':'','body':_0x581858};return{'frontmatter':_0x1c1dad[-0x1397*0x1+-0x2*0x6f1+-0x2*-0x10bd],'body':_0x1c1dad[0x1924+0x80*-0x20+0x922*-0x1]};}function readWorkspaceFile(_0x47c4f2,_0x44f166){const _0x36d5eb=_0xf23d,_0x5bb8f1=_0xf23d;try{const _0x2c9e5d=_0x1b21b5[_0x36d5eb(0x128)+'nc'](_0x47c4f2,_0x5bb8f1(0x101)),{frontmatter:_0x15ab3f,body:_0x2017fa}=splitFrontmatter(_0x2c9e5d),_0x258e55=parseFrontmatter(_0x15ab3f),_0x3c44db=typeof _0x258e55['purpose']===_0x5bb8f1(0x139)?_0x258e55[_0x36d5eb(0x119)]:'',_0x22637b=typeof _0x258e55[_0x5bb8f1(0x111)]===_0x36d5eb(0x139)?_0x258e55['cwd']:config[_0x36d5eb(0x141)+_0x36d5eb(0x12a)],_0x169e0e=expandHome(_0x22637b),_0x17fafe=typeof _0x258e55[_0x5bb8f1(0xfb)]===_0x5bb8f1(0x139)?_0x258e55[_0x5bb8f1(0xfb)]:undefined,_0x35020d=typeof _0x258e55[_0x5bb8f1(0x10f)]===_0x5bb8f1(0x139)?_0x258e55['emoji']:undefined,_0x359459=typeof _0x258e55[_0x36d5eb(0x12c)]==='string'&&_0x258e55[_0x5bb8f1(0x12c)]['trim']()?_0x258e55[_0x5bb8f1(0x12c)][_0x5bb8f1(0x129)]():undefined,_0x331b28=typeof _0x258e55[_0x5bb8f1(0x12f)]==='string'?_0x258e55[_0x5bb8f1(0x12f)][_0x36d5eb(0x129)]()['toLowerCas'+'e']():'',_0x473557=_0x331b28===_0x36d5eb(0x114)||_0x331b28===_0x36d5eb(0x13a)||_0x331b28===_0x5bb8f1(0x136)?_0x331b28:undefined,_0x58fc2a=typeof _0x258e55['provider']===_0x5bb8f1(0x139)&&_0x258e55[_0x36d5eb(0x131)][_0x36d5eb(0x129)]()?_0x258e55[_0x5bb8f1(0x131)][_0x5bb8f1(0x129)]():undefined,_0x40baca=typeof _0x258e55[_0x5bb8f1(0x13e)]===_0x5bb8f1(0x139)&&_0x258e55[_0x36d5eb(0x13e)][_0x5bb8f1(0x129)]()?_0x258e55[_0x5bb8f1(0x13e)]['trim']():undefined,_0xb99000=typeof _0x258e55[_0x36d5eb(0x13c)+'e']===_0x5bb8f1(0x139)?parseFloat(_0x258e55[_0x36d5eb(0x13c)+'e']):typeof _0x258e55[_0x36d5eb(0x13c)+'e']==='number'?_0x258e55[_0x36d5eb(0x13c)+'e']:NaN,_0x517e92=Number[_0x5bb8f1(0x10d)](_0xb99000)&&_0xb99000>=-0x12de+-0x1771+0x1*0x2a4f&&_0xb99000<=0x6*-0x3df+-0x329*0x7+0x2d5b?_0xb99000:undefined,_0x4717f8=typeof _0x258e55[_0x5bb8f1(0x12d)]===_0x5bb8f1(0x139)?_0x258e55[_0x5bb8f1(0x12d)][_0x5bb8f1(0x129)]()[_0x5bb8f1(0x11c)+'e']():'',_0x89603=_0x4717f8===_0x5bb8f1(0x138)||_0x4717f8==='readonly'||_0x4717f8==='research'?_0x4717f8:undefined,_0x1e48c2=Array['isArray'](_0x258e55[_0x5bb8f1(0x11b)])?_0x258e55['channels'][_0x5bb8f1(0x113)](_0x110e36=>typeof _0x110e36==='string'):[];return{'name':_0x44f166,'purpose':_0x3c44db,'cwd':_0x169e0e,'color':_0x17fafe,'emoji':_0x35020d,'channels':_0x1e48c2,'model':_0x359459,'effort':_0x473557,'provider':_0x58fc2a,'voice':_0x40baca,'temperature':_0x517e92,'toolset':_0x89603,'systemPromptOverride':_0x2017fa['trim']()};}catch(_0x17b4a8){return console['warn']('⚠️\x20workspac'+'es:\x20failed'+_0x5bb8f1(0x11f)+_0x47c4f2+'\x20—',_0x17b4a8 instanceof Error?_0x17b4a8[_0x5bb8f1(0x116)]:String(_0x17b4a8)),null;}}export function loadWorkspaces(){const _0x369995=_0xf23d,_0x2d581f=_0xf23d;registry[_0x369995(0x108)]();if(!_0x1b21b5[_0x369995(0x137)](WORKSPACES_DIR))return 0x8c2+0x12f1*0x1+-0x7*0x3f5;let _0xdcdafa=-0x592+0x77b*-0x3+0x1c03,_0x27ee25;try{_0x27ee25=_0x1b21b5['readdirSyn'+'c'](WORKSPACES_DIR);}catch{return-0xb36*-0x3+0x5*-0xee+-0x212*0xe;}for(const _0x1c3369 of _0x27ee25){if(!_0x1c3369[_0x369995(0x118)](_0x2d581f(0x133))||_0x1c3369[_0x369995(0x110)]('.'))continue;const _0x2dc058=_0x1c3369[_0x2d581f(0x12e)](/\.md$/,''),_0xe6b417=_0x950d15[_0x369995(0x121)](WORKSPACES_DIR,_0x1c3369),_0x2312c4=readWorkspaceFile(_0xe6b417,_0x2dc058);_0x2312c4&&(registry[_0x2d581f(0x124)](_0x2dc058,_0x2312c4),_0xdcdafa++);}return _0xdcdafa;}export function reloadWorkspaces(){return loadWorkspaces();}export function listWorkspaces(){const _0x330f72=_0xf23d,_0x774ba9=_0xf23d;return Array[_0x330f72(0x125)](registry[_0x330f72(0x109)]());}export function getWorkspace(_0x256b0a){const _0x17088c=_0xf23d;return registry[_0x17088c(0x123)](_0x256b0a)??null;}export function getDefaultWorkspace(){const _0x3413c5=_0xf23d,_0x12c6b2=_0xf23d;return{'name':_0x3413c5(0x10b),'purpose':'','cwd':config[_0x3413c5(0x141)+_0x3413c5(0x12a)],'channels':[],'systemPromptOverride':''};}export function matchWorkspaceForChannel(_0x32cd6c,_0x19cbc9,_0x5cc8de){const _0x1018bb=_0xf23d,_0xc4af5c=_0xf23d;for(const _0x20ce8b of registry[_0x1018bb(0x109)]()){if(_0x20ce8b[_0xc4af5c(0x11b)]['includes'](_0x19cbc9))return _0x20ce8b;}if(_0x5cc8de){const _0x315baa=_0x5cc8de['replace'](/^#/,'')[_0x1018bb(0x129)]()[_0x1018bb(0x11c)+'e']();for(const _0x17fe2d of registry[_0x1018bb(0x109)]()){if(_0x17fe2d[_0x1018bb(0x13f)][_0xc4af5c(0x11c)+'e']()===_0x315baa)return _0x17fe2d;}}return null;}export function resolveWorkspaceOrDefault(_0x1a29d2,_0x2b4505,_0xb239a6){const _0x85fb29=matchWorkspaceForChannel(_0x1a29d2,_0x2b4505,_0xb239a6);return _0x85fb29??getDefaultWorkspace();}let watcher=null,reloadDebounceTimer=null;export function startWorkspaceWatcher(){if(watcher)return;if(!_0x1b21b5['existsSync'](WORKSPACES_DIR))return;try{watcher=_0x1b21b5['watch'](WORKSPACES_DIR,()=>{if(reloadDebounceTimer)clearTimeout(reloadDebounceTimer);reloadDebounceTimer=setTimeout(()=>{const _0x190a4b=_0xf23d,_0x5a353c=_0xf23d,_0x2e711b=reloadWorkspaces();console[_0x190a4b(0xfd)]('🧭\x20workspac'+_0x5a353c(0x11d)+_0x5a353c(0x12b)+_0x2e711b+(_0x190a4b(0x13b)+'d)'));},0x566+0x454+0x1*-0x7c6);});}catch{}}export function stopWorkspaceWatcher(){if(watcher){try{watcher['close']();}catch{}watcher=null;}reloadDebounceTimer&&(clearTimeout(reloadDebounceTimer),reloadDebounceTimer=null);}export function initWorkspaces(){const _0x280083=_0xf23d,_0x434a5b=_0xf23d,_0x52823d=loadWorkspaces();startWorkspaceWatcher();if(_0x52823d>-0x5*-0x5c6+-0x159d+-0x26b*0x3){const _0x1376d7=listWorkspaces()[_0x280083(0x115)](_0x4d644f=>(_0x4d644f[_0x434a5b(0x10f)]??'🧭')+'\x20'+_0x4d644f[_0x280083(0x13f)])['join'](',\x20');console[_0x434a5b(0xfd)](_0x280083(0x122)+'es:\x20'+_0x52823d+_0x280083(0xfe)+_0x1376d7);}return _0x52823d;}function _0x4290(){const _0x2018a9=['mJrsuMXKAw8','zw5KC1DPDgG','ChvYCg9Zzq','r3jLCa','y2HHBM5LBhm','Dg9mB3DLCKnHCW','zxm6igHVDc1Yzq','mta4ntaZmZbHtgLesg8','ihrVigXVywqG','v2vIrMv0y2G','CMvZB2X2zq','8j+NRsbxB3jRC3bHyW','z2v0','C2v0','zNjVBq','mti4ndG2nfLHueDqzG','CMvHzg9UBhK','CMvHzezPBgvtEq','DhjPBq','A2LUz0rPCG','Bg9HzgvKicG','Bw9KzwW','Dg9VBhnLDa','CMvWBgfJzq','zwzMB3j0','uMvHza','ChjVDMLKzxi','mJaYnZiZmMnhuKzLrG','lM1K','mtKXmZq4nwDkr3ntuW','Dg9tDhjPBMC','AgLNAa','zxHPC3rZu3LUyW','zNvSBa','C3rYAw5N','BwvKAxvT','ihjLz2LZDgvYzq','DgvTCgvYyxr1CG','mJy4n09OteHSra','DM9Py2u','BMfTzq','ntu4vM1rvMnO','zgvMyxvSDfDVCG','C3bSAxq','y29SB3i','C2vHCMnO','Bg9N','igXVywrLzcdIGjqG','r2XVyG','nJq5ntm3tgD6tgni','DxrMltG','nZK4EgPdufHj','Ag9TzwrPCG','nJiYmgjVwuTYua','v2vIu2vHCMnO','Aw5KzxHpzG','kcGOlISPkYKRkq','y2XLyxi','DMfSDwvZ','CgfYC2u','zgvMyxvSDa','yxbWBhK','AxngAw5PDgu','CMvZzwfYy2G','zw1VAMK','C3rHCNrZv2L0Aa','y3DK','C2XPy2u','zMLSDgvY','Bg93','BwfW','BwvZC2fNzq'];_0x4290=function(){return _0x2018a9;};return _0x4290();}
|