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.
Files changed (137) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +1 -1
  3. package/dist/claude.js +1 -102
  4. package/dist/config.js +1 -96
  5. package/dist/engine.js +1 -90
  6. package/dist/find-claude-binary.js +1 -98
  7. package/dist/handlers/async-agent-chunk-handler.js +1 -50
  8. package/dist/handlers/background-bypass.js +1 -75
  9. package/dist/handlers/commands.js +1 -2336
  10. package/dist/handlers/cron-progress.js +1 -52
  11. package/dist/handlers/document.js +1 -194
  12. package/dist/handlers/message.js +1 -959
  13. package/dist/handlers/photo.js +1 -154
  14. package/dist/handlers/platform-message.js +1 -360
  15. package/dist/handlers/stuck-timer.js +1 -54
  16. package/dist/handlers/video.js +1 -237
  17. package/dist/handlers/voice.js +1 -148
  18. package/dist/i18n.js +1 -805
  19. package/dist/index.js +1 -697
  20. package/dist/init-data-dir.js +1 -98
  21. package/dist/middleware/auth.js +1 -233
  22. package/dist/migrate.js +1 -162
  23. package/dist/paths.js +1 -146
  24. package/dist/platforms/discord.js +1 -175
  25. package/dist/platforms/index.js +1 -130
  26. package/dist/platforms/signal.js +1 -205
  27. package/dist/platforms/slack-slash-parser.js +1 -32
  28. package/dist/platforms/slack.js +1 -501
  29. package/dist/platforms/telegram.js +1 -111
  30. package/dist/platforms/types.js +1 -8
  31. package/dist/platforms/whatsapp-auth-helpers.js +1 -53
  32. package/dist/platforms/whatsapp.js +1 -707
  33. package/dist/providers/claude-sdk-provider.js +1 -565
  34. package/dist/providers/codex-cli-provider.js +1 -134
  35. package/dist/providers/index.js +1 -7
  36. package/dist/providers/ollama-provider.js +1 -32
  37. package/dist/providers/openai-compatible.js +1 -406
  38. package/dist/providers/registry.js +1 -352
  39. package/dist/providers/runtime-header.js +1 -45
  40. package/dist/providers/tool-executor.js +1 -475
  41. package/dist/providers/types.js +1 -227
  42. package/dist/services/access.js +1 -144
  43. package/dist/services/allowed-users-gate.js +1 -56
  44. package/dist/services/alvin-dispatch.js +1 -130
  45. package/dist/services/alvin-mcp-tools.js +1 -104
  46. package/dist/services/asset-index.js +1 -224
  47. package/dist/services/async-agent-parser.js +1 -418
  48. package/dist/services/async-agent-watcher.js +1 -443
  49. package/dist/services/auto-diagnostic.js +1 -228
  50. package/dist/services/broadcast.js +1 -52
  51. package/dist/services/browser-manager.js +1 -562
  52. package/dist/services/browser-webfetch.js +1 -127
  53. package/dist/services/browser.js +1 -121
  54. package/dist/services/cdp-bootstrap.js +1 -357
  55. package/dist/services/compaction.js +1 -144
  56. package/dist/services/critical-notify.js +1 -203
  57. package/dist/services/cron-resolver.js +1 -58
  58. package/dist/services/cron-scheduling.js +1 -310
  59. package/dist/services/cron.js +1 -861
  60. package/dist/services/custom-tools.js +1 -317
  61. package/dist/services/delivery-queue.js +1 -173
  62. package/dist/services/delivery-registry.js +1 -21
  63. package/dist/services/disk-cleanup.js +1 -203
  64. package/dist/services/elevenlabs.js +1 -58
  65. package/dist/services/embeddings/auto-detect.js +1 -74
  66. package/dist/services/embeddings/fts5.js +1 -108
  67. package/dist/services/embeddings/gemini.js +1 -65
  68. package/dist/services/embeddings/index.js +1 -496
  69. package/dist/services/embeddings/ollama.js +1 -78
  70. package/dist/services/embeddings/openai.js +1 -49
  71. package/dist/services/embeddings/provider.js +1 -22
  72. package/dist/services/embeddings/vector-base.js +1 -113
  73. package/dist/services/embeddings-migration.js +1 -193
  74. package/dist/services/embeddings.js +1 -9
  75. package/dist/services/env-file.js +1 -50
  76. package/dist/services/exec-guard.js +1 -71
  77. package/dist/services/fallback-order.js +1 -154
  78. package/dist/services/file-permissions.js +1 -93
  79. package/dist/services/heartbeat-file.js +1 -65
  80. package/dist/services/heartbeat.js +1 -313
  81. package/dist/services/hooks.js +1 -44
  82. package/dist/services/imagegen.js +1 -72
  83. package/dist/services/language-detect.js +1 -154
  84. package/dist/services/markdown.js +1 -63
  85. package/dist/services/mcp.js +1 -263
  86. package/dist/services/memory-extractor.js +1 -178
  87. package/dist/services/memory-inject-mode.js +1 -43
  88. package/dist/services/memory-layers.js +1 -156
  89. package/dist/services/memory.js +1 -146
  90. package/dist/services/ollama-manager.js +1 -339
  91. package/dist/services/permissions-wizard.js +1 -291
  92. package/dist/services/personality.js +1 -376
  93. package/dist/services/plugins.js +1 -171
  94. package/dist/services/preflight.js +1 -292
  95. package/dist/services/process-manager.js +1 -291
  96. package/dist/services/release-highlights.js +1 -79
  97. package/dist/services/reminders.js +1 -97
  98. package/dist/services/restart.js +1 -48
  99. package/dist/services/security-audit.js +1 -74
  100. package/dist/services/self-diagnosis.js +1 -272
  101. package/dist/services/self-search.js +1 -129
  102. package/dist/services/session-persistence.js +1 -237
  103. package/dist/services/session.js +1 -282
  104. package/dist/services/skills.js +1 -290
  105. package/dist/services/ssrf-guard.js +1 -162
  106. package/dist/services/standing-orders.js +1 -29
  107. package/dist/services/steer-channel.js +1 -46
  108. package/dist/services/stop-controller.js +1 -52
  109. package/dist/services/subagent-dedup.js +1 -0
  110. package/dist/services/subagent-delivery.js +1 -452
  111. package/dist/services/subagent-stats.js +1 -123
  112. package/dist/services/subagents.js +1 -814
  113. package/dist/services/sudo.js +1 -329
  114. package/dist/services/telegram.js +1 -158
  115. package/dist/services/timing-safe-bearer.js +1 -51
  116. package/dist/services/tool-discovery.js +1 -214
  117. package/dist/services/trends.js +1 -580
  118. package/dist/services/updater.js +1 -291
  119. package/dist/services/usage-tracker.js +1 -144
  120. package/dist/services/users.js +1 -271
  121. package/dist/services/voice.js +1 -104
  122. package/dist/services/watchdog-brake.js +1 -154
  123. package/dist/services/watchdog.js +1 -311
  124. package/dist/services/workspaces.js +1 -276
  125. package/dist/tui/index.js +1 -667
  126. package/dist/util/console-formatter.js +1 -109
  127. package/dist/util/debounce.js +1 -24
  128. package/dist/util/telegram-error-filter.js +1 -62
  129. package/dist/version.js +1 -24
  130. package/dist/web/bind-strategy.js +1 -42
  131. package/dist/web/canvas.js +1 -30
  132. package/dist/web/doctor-api.js +1 -604
  133. package/dist/web/openai-compat.js +1 -252
  134. package/dist/web/server.js +1 -1831
  135. package/dist/web/setup-api.js +1 -1101
  136. package/package.json +5 -2
  137. package/dist/.metadata_never_index +0 -0
@@ -1,861 +1 @@
1
- /**
2
- * Cron Service — Persistent scheduled tasks.
3
- *
4
- * Supports:
5
- * - Interval-based jobs (every 5m, 1h, etc.)
6
- * - Cron expressions (0 9 * * 1 = every Monday 9am)
7
- * - One-shot scheduled tasks (run once at a specific time)
8
- * - Job types: reminder, shell, ai-query, http
9
- * - Management via /cron command + Web UI
10
- * - Persisted to docs/cron-jobs.json (survives restarts)
11
- */
12
- import fs from "fs";
13
- import { execSync } from "child_process";
14
- import { resolve, dirname } from "path";
15
- import { CRON_FILE, BOT_ROOT } from "../paths.js";
16
- import { prepareForExecution, handleStartupCatchup, calculateNextRunFrom, } from "./cron-scheduling.js";
17
- import { resolveJobByNameOrId } from "./cron-resolver.js";
18
- import { bootWasExpectedRestart } from "./watchdog.js";
19
- // ── Storage ─────────────────────────────────────────────
20
- /** Allowed job types — must stay in sync with the JobType union above. */
21
- const ALLOWED_JOB_TYPES = new Set(["reminder", "shell", "ai-query", "http", "message"]);
22
- /**
23
- * M4: Per-entry structural validation for a raw parsed cron-jobs.json entry.
24
- *
25
- * Rules:
26
- * - Must be a non-null object
27
- * - `id`, `name`, `schedule`, `createdBy` must be non-empty strings
28
- * - `type` must be one of the allowed JobType values
29
- * - `payload` must be an object (not null)
30
- * - `target` must be an object with `platform` (string) and `chatId` (string)
31
- * - `enabled` must be a boolean
32
- * - `createdAt`, `runCount` must be numbers
33
- * - `oneShot` must be a boolean
34
- * - Nullable fields (lastRunAt, lastResult, lastError, nextRunAt) can be
35
- * null or their expected types — lenient check, just must not be undefined
36
- *
37
- * Returns a validated CronJob (cast) on success, null on failure.
38
- * Logs a calm warning for every skipped entry.
39
- */
40
- function validateCronJobEntry(raw, index) {
41
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
42
- console.warn(`[cron] skipping entry #${index}: not an object`);
43
- return null;
44
- }
45
- const e = raw;
46
- if (typeof e.id !== "string" || !e.id) {
47
- console.warn(`[cron] skipping entry #${index}: missing or invalid 'id'`);
48
- return null;
49
- }
50
- if (typeof e.name !== "string" || !e.name) {
51
- console.warn(`[cron] skipping entry #${index} (id=${e.id}): missing or invalid 'name'`);
52
- return null;
53
- }
54
- if (typeof e.type !== "string" || !ALLOWED_JOB_TYPES.has(e.type)) {
55
- console.warn(`[cron] skipping entry #${index} (id=${e.id}): unknown or missing job type '${e.type}'`);
56
- return null;
57
- }
58
- if (typeof e.schedule !== "string" || !e.schedule) {
59
- console.warn(`[cron] skipping entry #${index} (id=${e.id}): missing or invalid 'schedule'`);
60
- return null;
61
- }
62
- if (!e.payload || typeof e.payload !== "object" || Array.isArray(e.payload)) {
63
- console.warn(`[cron] skipping entry #${index} (id=${e.id}): 'payload' must be an object`);
64
- return null;
65
- }
66
- if (!e.target || typeof e.target !== "object" || Array.isArray(e.target)) {
67
- console.warn(`[cron] skipping entry #${index} (id=${e.id}): 'target' must be an object`);
68
- return null;
69
- }
70
- const t = e.target;
71
- if (typeof t.platform !== "string" || typeof t.chatId !== "string") {
72
- console.warn(`[cron] skipping entry #${index} (id=${e.id}): 'target.platform' and 'target.chatId' must be strings`);
73
- return null;
74
- }
75
- if (typeof e.enabled !== "boolean") {
76
- console.warn(`[cron] skipping entry #${index} (id=${e.id}): 'enabled' must be a boolean`);
77
- return null;
78
- }
79
- if (typeof e.createdAt !== "number") {
80
- console.warn(`[cron] skipping entry #${index} (id=${e.id}): 'createdAt' must be a number`);
81
- return null;
82
- }
83
- if (typeof e.runCount !== "number") {
84
- console.warn(`[cron] skipping entry #${index} (id=${e.id}): 'runCount' must be a number`);
85
- return null;
86
- }
87
- if (typeof e.oneShot !== "boolean") {
88
- console.warn(`[cron] skipping entry #${index} (id=${e.id}): 'oneShot' must be a boolean`);
89
- return null;
90
- }
91
- // Lenient nullable fields
92
- if (e.createdBy !== undefined && typeof e.createdBy !== "string") {
93
- console.warn(`[cron] skipping entry #${index} (id=${e.id}): 'createdBy' must be a string`);
94
- return null;
95
- }
96
- return raw;
97
- }
98
- function loadJobs() {
99
- let raw;
100
- try {
101
- raw = fs.readFileSync(CRON_FILE, "utf-8");
102
- }
103
- catch {
104
- return [];
105
- }
106
- let parsed;
107
- try {
108
- parsed = JSON.parse(raw);
109
- }
110
- catch (err) {
111
- console.warn("[cron] cron-jobs.json is not valid JSON — starting with empty job list:", err instanceof Error ? err.message : String(err));
112
- return [];
113
- }
114
- if (!Array.isArray(parsed)) {
115
- console.warn("[cron] cron-jobs.json root is not an array — starting with empty job list");
116
- return [];
117
- }
118
- // M4: Per-entry validation — one bad entry must NOT crash the whole list
119
- const jobs = [];
120
- for (let i = 0; i < parsed.length; i++) {
121
- const validated = validateCronJobEntry(parsed[i], i);
122
- if (validated !== null) {
123
- jobs.push(validated);
124
- }
125
- }
126
- return jobs;
127
- }
128
- function saveJobs(jobs) {
129
- const dir = dirname(CRON_FILE);
130
- if (!fs.existsSync(dir))
131
- fs.mkdirSync(dir, { recursive: true });
132
- fs.writeFileSync(CRON_FILE, JSON.stringify(jobs, null, 2));
133
- }
134
- // ── Cron Parsing ────────────────────────────────────────
135
- /**
136
- * Parse an interval string (5m, 1h, 30s, 2d) to milliseconds.
137
- */
138
- function parseInterval(input) {
139
- const match = input.match(/^(\d+(?:\.\d+)?)\s*(s|sec|m|min|h|hr|d|day)s?$/i);
140
- if (!match)
141
- return null;
142
- const value = parseFloat(match[1]);
143
- const unit = match[2].toLowerCase();
144
- const mult = { s: 1000, sec: 1000, m: 60_000, min: 60_000, h: 3_600_000, hr: 3_600_000, d: 86_400_000, day: 86_400_000 };
145
- return value * (mult[unit] || 60_000);
146
- }
147
- /**
148
- * Parse a cron expression and find the next run time.
149
- * Supports: minute hour day month weekday
150
- * Simple implementation — covers common cases.
151
- */
152
- function nextCronRun(expression, after = new Date()) {
153
- const parts = expression.trim().split(/\s+/);
154
- if (parts.length !== 5)
155
- return null;
156
- const [minExpr, hourExpr, dayExpr, monthExpr, weekdayExpr] = parts;
157
- /**
158
- * Parse a single cron field token (no commas — commas handled by parseField).
159
- * Supports: `*`, `a`, `a-b`, `a-b/s`, `*\/s`, `a/s`.
160
- * Returns null for invalid/garbage tokens.
161
- */
162
- function parseFieldToken(token, min, max) {
163
- const fullRange = () => Array.from({ length: max - min + 1 }, (_, i) => i + min);
164
- if (token.includes("/")) {
165
- const slashIdx = token.indexOf("/");
166
- const basePart = token.slice(0, slashIdx);
167
- const stepPart = token.slice(slashIdx + 1);
168
- const step = parseInt(stepPart, 10);
169
- if (!Number.isFinite(step) || step <= 0)
170
- return null;
171
- let base;
172
- if (basePart === "*") {
173
- base = fullRange();
174
- }
175
- else if (basePart.includes("-")) {
176
- const dashParts = basePart.split("-");
177
- if (dashParts.length !== 2)
178
- return null;
179
- const a = parseInt(dashParts[0], 10);
180
- const b = parseInt(dashParts[1], 10);
181
- if (!Number.isFinite(a) || !Number.isFinite(b) || a > b || a < min || b > max)
182
- return null;
183
- base = Array.from({ length: b - a + 1 }, (_, i) => i + a);
184
- }
185
- else {
186
- const a = parseInt(basePart, 10);
187
- if (!Number.isFinite(a) || a < min || a > max)
188
- return null;
189
- base = [a];
190
- }
191
- const baseStart = base[0];
192
- return base.filter((v) => (v - baseStart) % step === 0);
193
- }
194
- if (token === "*")
195
- return fullRange();
196
- if (token.includes("-")) {
197
- const dashParts = token.split("-");
198
- if (dashParts.length !== 2)
199
- return null;
200
- const a = parseInt(dashParts[0], 10);
201
- const b = parseInt(dashParts[1], 10);
202
- if (!Number.isFinite(a) || !Number.isFinite(b) || a > b || a < min || b > max)
203
- return null;
204
- return Array.from({ length: b - a + 1 }, (_, i) => i + a);
205
- }
206
- const v = parseInt(token, 10);
207
- if (!Number.isFinite(v) || v < min || v > max)
208
- return null;
209
- return [v];
210
- }
211
- /**
212
- * Parse a cron field expression (may contain commas) into a sorted array of valid integers.
213
- * Returns null if any token is invalid/garbage (the expression is rejected).
214
- */
215
- function parseField(expr, min, max) {
216
- const tokens = expr.split(",").filter((t) => t.length > 0);
217
- if (tokens.length === 0)
218
- return null;
219
- const result = new Set();
220
- for (const token of tokens) {
221
- const vals = parseFieldToken(token, min, max);
222
- if (vals === null)
223
- return null;
224
- for (const v of vals)
225
- result.add(v);
226
- }
227
- const arr = [...result].sort((a, b) => a - b);
228
- return arr.length > 0 ? arr : null;
229
- }
230
- const minutes = parseField(minExpr, 0, 59);
231
- const hours = parseField(hourExpr, 0, 23);
232
- const days = parseField(dayExpr, 1, 31);
233
- const months = parseField(monthExpr, 1, 12);
234
- const weekdays = parseField(weekdayExpr, 0, 6); // 0=Sun
235
- // Any field returning null means the expression is invalid — reject it
236
- if (!minutes || !hours || !days || !months || !weekdays)
237
- return null;
238
- // Search forward up to 366 days
239
- const candidate = new Date(after);
240
- candidate.setSeconds(0, 0);
241
- candidate.setMinutes(candidate.getMinutes() + 1);
242
- for (let i = 0; i < 366 * 24 * 60; i++) {
243
- const m = candidate.getMinutes();
244
- const h = candidate.getHours();
245
- const d = candidate.getDate();
246
- const mo = candidate.getMonth() + 1;
247
- const wd = candidate.getDay();
248
- if (minutes.includes(m) && hours.includes(h) && days.includes(d) && months.includes(mo) && weekdays.includes(wd)) {
249
- return candidate;
250
- }
251
- candidate.setMinutes(candidate.getMinutes() + 1);
252
- }
253
- return null;
254
- }
255
- /**
256
- * Calculate next run time for a job.
257
- */
258
- function calculateNextRun(job) {
259
- if (!job.enabled)
260
- return null;
261
- // Interval-based
262
- const intervalMs = parseInterval(job.schedule);
263
- if (intervalMs) {
264
- const base = job.lastRunAt || job.createdAt;
265
- return base + intervalMs;
266
- }
267
- // Cron expression
268
- const next = nextCronRun(job.schedule);
269
- return next ? next.getTime() : null;
270
- }
271
- let notifyCallback = null;
272
- export function setNotifyCallback(fn) {
273
- notifyCallback = fn;
274
- }
275
- /** @internal exported for unit-test use only */
276
- export async function runJob(job) {
277
- return executeJob(job);
278
- }
279
- async function executeJob(job) {
280
- try {
281
- switch (job.type) {
282
- case "reminder":
283
- case "message": {
284
- const text = job.payload.text || "(no message)";
285
- if (notifyCallback) {
286
- await notifyCallback(job.target, `⏰ ${job.name}\n\n${text}`);
287
- }
288
- return { output: `Sent: ${text.slice(0, 100)}` };
289
- }
290
- case "shell": {
291
- const cmd = job.payload.command || "echo 'no command'";
292
- // v4.12.2 — Cron shell jobs now go through exec-guard. Before
293
- // v4.12.2 cron bypassed the allowlist, which was inconsistent
294
- // with the rest of the bot's shell execution policy. With
295
- // EXEC_SECURITY=allowlist (default) this rejects jobs with
296
- // shell metacharacters or non-allowlisted binaries. Operators
297
- // who legitimately need complex shell pipelines in cron set
298
- // EXEC_SECURITY=full explicitly.
299
- const { checkExecAllowed } = await import("./exec-guard.js");
300
- const guard = checkExecAllowed(cmd);
301
- if (!guard.allowed) {
302
- const msg = `Cron shell job blocked by exec-guard: ${guard.reason}`;
303
- console.warn(`[cron] ${job.name}: ${msg}`);
304
- if (notifyCallback) {
305
- await notifyCallback(job.target, `🛑 ${job.name}\n${msg}\n\nSet EXEC_SECURITY=full if this is intentional.`);
306
- }
307
- return { output: msg };
308
- }
309
- // Per-job timeout, default = no timeout (execSync treats timeout=0
310
- // or "undefined" as infinite). Users opt in via /cron add … --timeout N.
311
- const shellOpts = {
312
- stdio: "pipe",
313
- env: { ...process.env, PATH: process.env.PATH + ":/opt/homebrew/bin:/usr/local/bin" },
314
- };
315
- if (typeof job.timeoutMs === "number" && job.timeoutMs > 0) {
316
- shellOpts.timeout = job.timeoutMs;
317
- }
318
- const output = execSync(cmd, shellOpts).toString().trim();
319
- // Notify with output
320
- if (notifyCallback && output) {
321
- await notifyCallback(job.target, `🔧 ${job.name}\n\`\`\`\n${output.slice(0, 3000)}\n\`\`\``);
322
- }
323
- return { output: output.slice(0, 5000) };
324
- }
325
- case "http": {
326
- const url = job.payload.url || "";
327
- const method = job.payload.method || "GET";
328
- const headers = job.payload.headers || {};
329
- // M1: SSRF guard — reject private/internal destinations before fetching.
330
- // Runs even when EXEC_SECURITY=deny (it's a separate, independent control).
331
- // We validate EVERY redirect hop manually (redirect:"manual") so a
332
- // public host cannot 302 us into an internal address (post-redirect SSRF).
333
- const { assertSsrfSafe, SsrfBlockedError: SsrfBlockedErrorCron } = await import("./ssrf-guard.js");
334
- await assertSsrfSafe(url);
335
- const baseOpts = { method, headers };
336
- if (job.payload.body && method !== "GET") {
337
- baseOpts.body = job.payload.body;
338
- }
339
- const MAX_CRON_REDIRECTS = 10;
340
- let currentUrl = url;
341
- let res;
342
- for (let hop = 0;; hop++) {
343
- res = await fetch(currentUrl, { ...baseOpts, redirect: "manual" });
344
- // Not a redirect — we have the final response
345
- if (res.status < 300 || res.status >= 400)
346
- break;
347
- const loc = res.headers.get("location");
348
- if (!loc)
349
- break; // no Location header — treat as final response
350
- if (hop >= MAX_CRON_REDIRECTS) {
351
- throw new SsrfBlockedErrorCron(url, `too many redirects (> ${MAX_CRON_REDIRECTS})`);
352
- }
353
- const next = new URL(loc, currentUrl).href;
354
- // Re-validate each redirect target before following — closes the
355
- // post-redirect SSRF bypass.
356
- await assertSsrfSafe(next);
357
- currentUrl = next;
358
- }
359
- const text = await res.text();
360
- const output = `HTTP ${res.status}: ${text.slice(0, 2000)}`;
361
- if (notifyCallback) {
362
- await notifyCallback(job.target, `🌐 ${job.name}\n${output.slice(0, 500)}`);
363
- }
364
- return { output };
365
- }
366
- case "ai-query": {
367
- // AI queries run as isolated sub-agents rather than directly against
368
- // the registry. This gives cron jobs timeout/cancel/state-tracking
369
- // "for free" via the existing subagents infrastructure, and — most
370
- // importantly — keeps them completely independent of any user's
371
- // active main session. A cron job can run in the background while
372
- // the user chats with Alvin in the foreground; neither interferes
373
- // with the other.
374
- const prompt = job.payload.prompt || "";
375
- // Dynamic import to avoid circular dep chain (cron → engine → registry
376
- // and subagents → engine). Type-only import at file top is erased,
377
- // so no runtime cycle is created.
378
- const { spawnSubAgent } = await import("./subagents.js");
379
- try {
380
- // Turn the fire-and-forget spawnSubAgent into an awaitable via
381
- // the onComplete callback. Rejection of the spawn promise itself
382
- // means the max-parallel limit was hit.
383
- // Parse the target chat id for I3 delivery routing. Only telegram
384
- // targets get a numeric parentChatId — other platforms/web get
385
- // undefined and fall through the delivery router's warning path.
386
- const parentChatId = job.target.platform === "telegram" && job.target.chatId
387
- ? Number(job.target.chatId)
388
- : undefined;
389
- const result = await new Promise((resolve, reject) => {
390
- // Only pass `timeout` through when the job has a per-job value.
391
- // Otherwise the sub-agent inherits the current /subagents default.
392
- const spawnConfig = {
393
- name: job.name,
394
- prompt,
395
- workingDir: BOT_ROOT,
396
- source: "cron",
397
- parentChatId,
398
- onComplete: (r) => resolve(r),
399
- };
400
- if (typeof job.timeoutMs === "number") {
401
- spawnConfig.timeout = job.timeoutMs;
402
- }
403
- spawnSubAgent(spawnConfig).catch(reject);
404
- });
405
- // Non-success: don't notify here. The I3 delivery router has
406
- // already posted the appropriate banner (cancelled / timeout /
407
- // error) to parentChatId, so a legacy notifyCallback would
408
- // produce a duplicate message.
409
- if (result.status !== "completed") {
410
- return {
411
- output: "",
412
- error: `Sub-agent ${result.status}: ${result.error || result.status}`,
413
- };
414
- }
415
- const fullResponse = result.output;
416
- // NOTE: No notifyCallback for ai-query jobs. The I3 delivery
417
- // router (src/services/subagent-delivery.ts) fires from
418
- // spawnSubAgent().finally() and sends a proper banner+final to
419
- // parentChatId. Legacy notifyCallback stays in use for the
420
- // other job types (reminder, shell, http, message) which do
421
- // not route through spawnSubAgent.
422
- return { output: fullResponse.slice(0, 500) };
423
- }
424
- catch (err) {
425
- // Re-throw without notifying — the outer catch will record
426
- // lastError on the job, and the I3 delivery router has already
427
- // posted a banner if the failure came from inside spawnSubAgent.
428
- throw err;
429
- }
430
- }
431
- default:
432
- return { output: "", error: `Unknown job type: ${job.type}` };
433
- }
434
- }
435
- catch (err) {
436
- const error = err instanceof Error ? err.message : String(err);
437
- // Skip notification for ai-query jobs — the I3 delivery router has
438
- // already posted the banner. Other job types still get the legacy
439
- // notify path because they don't route through spawnSubAgent.
440
- if (notifyCallback && job.type !== "ai-query") {
441
- await notifyCallback(job.target, `❌ Cron Error (${job.name}): ${error}`);
442
- }
443
- return { output: "", error };
444
- }
445
- }
446
- // ── Scheduler Loop ──────────────────────────────────────
447
- let schedulerTimer = null;
448
- const runningJobs = new Set(); // Guard against overlapping executions
449
- // ── Cross-process job lock ──────────────────────────────
450
- //
451
- // `runningJobs` only guards overlap WITHIN this process. If two bot
452
- // instances are briefly alive at once (a launchd/pm2 restart that left
453
- // the old process running, or startup-catchup racing the normal tick),
454
- // each has its own in-memory Set and the same job can fire twice —
455
- // observed in the wild: a weekly job mailed its report, then mailed an
456
- // empty duplicate 30 s later. This atomic `mkdir` lock makes the claim
457
- // cross-process: the second instance sees the lock and skips the slot
458
- // instead of double-firing. Stale locks (owning PID gone, or — when the
459
- // meta is unreadable — older than the catch-up grace) are reclaimed so a
460
- // crash can never wedge a job forever. No deps, cross-platform.
461
- const CRON_LOCK_DIR = resolve(dirname(CRON_FILE), ".cron-locks");
462
- const CRON_LOCK_MAX_AGE_MS = 6 * 60 * 60 * 1000; // backstop for corrupt meta
463
- function cronLockPath(jobId) {
464
- return resolve(CRON_LOCK_DIR, `${jobId.replace(/[^A-Za-z0-9_-]/g, "_")}.lock`);
465
- }
466
- function acquireJobLock(jobId) {
467
- const lock = cronLockPath(jobId);
468
- const writeMeta = () => {
469
- try {
470
- fs.writeFileSync(resolve(lock, "meta"), JSON.stringify({ pid: process.pid, at: Date.now() }));
471
- }
472
- catch { /* meta is best-effort */ }
473
- };
474
- try {
475
- fs.mkdirSync(CRON_LOCK_DIR, { recursive: true });
476
- }
477
- catch { /* ignore */ }
478
- try {
479
- fs.mkdirSync(lock); // atomic: throws EEXIST if another instance holds it
480
- writeMeta();
481
- return true;
482
- }
483
- catch {
484
- let stale = false;
485
- try {
486
- const meta = JSON.parse(fs.readFileSync(resolve(lock, "meta"), "utf-8"));
487
- if (typeof meta.pid === "number") {
488
- try {
489
- process.kill(meta.pid, 0); // same-host liveness probe (no signal sent)
490
- }
491
- catch (e) {
492
- if (e.code === "ESRCH")
493
- stale = true; // owner gone
494
- }
495
- }
496
- else {
497
- stale = true; // no usable pid recorded
498
- }
499
- }
500
- catch {
501
- // meta missing/corrupt → fall back to lock-dir age
502
- try {
503
- stale = Date.now() - fs.statSync(lock).mtimeMs > CRON_LOCK_MAX_AGE_MS;
504
- }
505
- catch {
506
- stale = false; // can't stat → treat as held (skip rather than double-fire)
507
- }
508
- }
509
- if (!stale)
510
- return false;
511
- try {
512
- fs.rmSync(lock, { recursive: true, force: true });
513
- fs.mkdirSync(lock);
514
- writeMeta();
515
- return true;
516
- }
517
- catch {
518
- return false;
519
- }
520
- }
521
- }
522
- function releaseJobLock(jobId) {
523
- try {
524
- fs.rmSync(cronLockPath(jobId), { recursive: true, force: true });
525
- }
526
- catch { /* ignore */ }
527
- }
528
- export function startScheduler() {
529
- if (schedulerTimer)
530
- return;
531
- // Startup catch-up — nachholen runs whose last attempt crashed within
532
- // the grace window. Must run BEFORE the first scheduler tick so the
533
- // catch-up nextRunAt rewind is visible on the very next pass.
534
- try {
535
- const bootJobs = loadJobs();
536
- const caught = handleStartupCatchup(bootJobs, Date.now(), undefined, {
537
- expectedRestart: bootWasExpectedRestart(),
538
- });
539
- // Only persist if something actually changed to avoid needless writes
540
- const mutated = caught.some((j, i) => j.nextRunAt !== bootJobs[i].nextRunAt);
541
- if (mutated) {
542
- saveJobs(caught);
543
- const names = caught
544
- .filter((j, i) => j.nextRunAt !== bootJobs[i].nextRunAt)
545
- .map((j) => j.name);
546
- console.log(`⏰ Cron startup catch-up: rewound ${names.length} job(s): ${names.join(", ")}`);
547
- }
548
- }
549
- catch (err) {
550
- console.error("⏰ Cron startup catch-up failed:", err);
551
- }
552
- // Check every 30 seconds for due jobs
553
- schedulerTimer = setInterval(async () => {
554
- const jobs = loadJobs();
555
- const now = Date.now();
556
- let changed = false;
557
- for (const job of jobs) {
558
- if (!job.enabled)
559
- continue;
560
- // Skip if this job is already running in THIS bot instance
561
- if (runningJobs.has(job.id))
562
- continue;
563
- // Calculate next run if not set
564
- if (!job.nextRunAt) {
565
- job.nextRunAt = calculateNextRun(job);
566
- changed = true;
567
- }
568
- if (job.nextRunAt && now >= job.nextRunAt) {
569
- console.log(`Cron: Running job "${job.name}" (${job.id})`);
570
- // Pre-execution state update: advance nextRunAt to the NEXT regular
571
- // trigger (NOT null) and stamp lastAttemptAt. If the bot crashes
572
- // mid-execution, handleStartupCatchup will notice the attempt
573
- // without completion and nachholen within the grace window.
574
- runningJobs.add(job.id);
575
- // Cross-process claim: if another bot instance already owns this
576
- // slot, skip instead of double-firing (the duplicate-report bug).
577
- if (!acquireJobLock(job.id)) {
578
- runningJobs.delete(job.id);
579
- console.log(`Cron: job "${job.name}" (${job.id}) already claimed by another instance — skipping to avoid double-fire`);
580
- continue;
581
- }
582
- const prepared = prepareForExecution(job, now);
583
- Object.assign(job, prepared);
584
- saveJobs(jobs);
585
- try {
586
- const result = await executeJob(job);
587
- // Re-load jobs in case they were modified during execution
588
- const freshJobs = loadJobs();
589
- const freshJob = freshJobs.find(j => j.id === job.id);
590
- if (freshJob) {
591
- freshJob.lastRunAt = Date.now();
592
- freshJob.lastResult = result.output.slice(0, 4000);
593
- freshJob.lastError = result.error || null;
594
- freshJob.runCount++;
595
- if (freshJob.oneShot) {
596
- freshJob.enabled = false;
597
- freshJob.nextRunAt = null;
598
- }
599
- else {
600
- // nextRunAt already set pre-execution, but recalculate in case
601
- // the schedule or enabled state changed during execution.
602
- freshJob.nextRunAt = calculateNextRunFrom(freshJob, Date.now());
603
- }
604
- saveJobs(freshJobs);
605
- }
606
- }
607
- finally {
608
- runningJobs.delete(job.id);
609
- releaseJobLock(job.id);
610
- }
611
- continue; // Skip the outer changed/save since we save inside
612
- }
613
- }
614
- if (changed)
615
- saveJobs(jobs);
616
- }, 30_000);
617
- console.log("⏰ Cron scheduler started (30s interval)");
618
- }
619
- export function stopScheduler() {
620
- if (schedulerTimer) {
621
- clearInterval(schedulerTimer);
622
- schedulerTimer = null;
623
- }
624
- }
625
- // ── Public CRUD API ─────────────────────────────────────
626
- function generateId() {
627
- return Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
628
- }
629
- export function createJob(input) {
630
- const job = {
631
- id: generateId(),
632
- name: input.name,
633
- type: input.type,
634
- schedule: input.schedule,
635
- oneShot: input.oneShot ?? false,
636
- payload: input.payload,
637
- target: input.target,
638
- enabled: input.enabled ?? true,
639
- createdAt: Date.now(),
640
- lastRunAt: null,
641
- lastResult: null,
642
- lastError: null,
643
- nextRunAt: null,
644
- runCount: 0,
645
- createdBy: input.createdBy || "unknown",
646
- ...(typeof input.timeoutMs === "number" ? { timeoutMs: input.timeoutMs } : {}),
647
- };
648
- // Calculate first run
649
- job.nextRunAt = calculateNextRun(job);
650
- const jobs = loadJobs();
651
- jobs.push(job);
652
- saveJobs(jobs);
653
- return job;
654
- }
655
- export function listJobs() {
656
- return loadJobs();
657
- }
658
- export function getJob(id) {
659
- return loadJobs().find(j => j.id === id);
660
- }
661
- export function updateJob(id, updates) {
662
- const jobs = loadJobs();
663
- const idx = jobs.findIndex(j => j.id === id);
664
- if (idx < 0)
665
- return null;
666
- Object.assign(jobs[idx], updates);
667
- if (updates.schedule || updates.enabled !== undefined) {
668
- jobs[idx].nextRunAt = calculateNextRun(jobs[idx]);
669
- }
670
- saveJobs(jobs);
671
- return jobs[idx];
672
- }
673
- export function deleteJob(id) {
674
- const jobs = loadJobs();
675
- const filtered = jobs.filter(j => j.id !== id);
676
- if (filtered.length === jobs.length)
677
- return false;
678
- saveJobs(filtered);
679
- return true;
680
- }
681
- export function toggleJob(id) {
682
- const jobs = loadJobs();
683
- const job = jobs.find(j => j.id === id);
684
- if (!job)
685
- return null;
686
- job.enabled = !job.enabled;
687
- job.nextRunAt = calculateNextRun(job);
688
- saveJobs(jobs);
689
- return job;
690
- }
691
- /**
692
- * Manual /cron run — resolves `nameOrId` against the job list, then
693
- * executes the job while honouring the in-memory `runningJobs` guard
694
- * so a simultaneous scheduler-trigger can't overlap.
695
- */
696
- export async function runJobNow(nameOrId) {
697
- const job = resolveJobByNameOrId(loadJobs(), nameOrId);
698
- if (!job)
699
- return { status: "not-found" };
700
- if (runningJobs.has(job.id)) {
701
- return { status: "already-running", job };
702
- }
703
- runningJobs.add(job.id);
704
- // Cross-process: another bot instance may already be running this job.
705
- if (!acquireJobLock(job.id)) {
706
- runningJobs.delete(job.id);
707
- return { status: "already-running", job };
708
- }
709
- try {
710
- // executeJob catches its own errors and returns { output, error }.
711
- // The inner try/catch here is a defensive belt against future
712
- // refactors that might remove executeJob's outer catch — it
713
- // guarantees runJobNow's typed contract, so commands.ts never
714
- // sees an uncaught throw escape into grammy's middleware.
715
- let result;
716
- try {
717
- result = await executeJob(job);
718
- }
719
- catch (err) {
720
- result = {
721
- output: "",
722
- error: err instanceof Error ? err.message : String(err),
723
- };
724
- }
725
- // Persist the manual run the same way the scheduler does so the
726
- // timeline stays honest: lastAttemptAt + lastRunAt + runCount bump.
727
- try {
728
- const freshJobs = loadJobs();
729
- const freshJob = freshJobs.find((j) => j.id === job.id);
730
- if (freshJob) {
731
- const now = Date.now();
732
- freshJob.lastAttemptAt = now;
733
- freshJob.lastRunAt = now;
734
- freshJob.lastResult = result.output.slice(0, 4000);
735
- freshJob.lastError = result.error || null;
736
- freshJob.runCount++;
737
- saveJobs(freshJobs);
738
- }
739
- }
740
- catch (err) {
741
- console.error("[cron] failed to persist manual run state:", err);
742
- }
743
- return { status: "ran", job, output: result.output, error: result.error };
744
- }
745
- finally {
746
- runningJobs.delete(job.id);
747
- releaseJobLock(job.id);
748
- }
749
- }
750
- /**
751
- * Convert a cron expression or interval string to a human-readable German description.
752
- */
753
- export function humanReadableSchedule(schedule) {
754
- // Interval strings (5m, 1h, 30s, 2d)
755
- const intervalMatch = schedule.match(/^(\d+(?:\.\d+)?)\s*(s|sec|m|min|h|hr|d|day)s?$/i);
756
- if (intervalMatch) {
757
- const value = parseFloat(intervalMatch[1]);
758
- const unit = intervalMatch[2].toLowerCase();
759
- const labels = {
760
- s: ["second", "seconds"], sec: ["second", "seconds"],
761
- m: ["minute", "minutes"], min: ["minute", "minutes"],
762
- h: ["hour", "hours"], hr: ["hour", "hours"],
763
- d: ["day", "days"], day: ["day", "days"],
764
- };
765
- const [sing, plur] = labels[unit] || ["?", "?"];
766
- return `Every ${value} ${value === 1 ? sing : plur}`;
767
- }
768
- // Cron expression: MIN HOUR DAY MONTH WEEKDAY
769
- const parts = schedule.trim().split(/\s+/);
770
- if (parts.length !== 5)
771
- return schedule;
772
- const [minExpr, hourExpr, dayExpr, monthExpr, weekdayExpr] = parts;
773
- const weekdayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
774
- const monthNames = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
775
- // Helper: format time from hour + minute expressions
776
- function formatTime(h, m) {
777
- if (h === "*" && m === "*")
778
- return "";
779
- const hh = h === "*" ? "*" : h.padStart(2, "0");
780
- const mm = m === "*" ? "00" : m.padStart(2, "0");
781
- return `${hh}:${mm}`;
782
- }
783
- // Helper: expand comma/range fields to readable list
784
- function expandField(expr, names) {
785
- if (expr === "*")
786
- return "";
787
- const vals = expr.split(",").map(v => {
788
- if (v.includes("-")) {
789
- const [a, b] = v.split("-");
790
- if (names)
791
- return `${names[+a]}–${names[+b]}`;
792
- return `${a}–${b}`;
793
- }
794
- return names ? (names[+v] || v) : v;
795
- });
796
- return vals.join(", ");
797
- }
798
- const time = formatTime(hourExpr, minExpr);
799
- const hasStep = [minExpr, hourExpr].some(e => e.includes("/"));
800
- // Every X minutes/hours
801
- if (minExpr.includes("/") && hourExpr === "*" && dayExpr === "*" && monthExpr === "*" && weekdayExpr === "*") {
802
- const step = minExpr.split("/")[1];
803
- return `Every ${step} min`;
804
- }
805
- if (hourExpr.includes("/") && dayExpr === "*" && monthExpr === "*" && weekdayExpr === "*") {
806
- const step = hourExpr.split("/")[1];
807
- return `Every ${step}h`;
808
- }
809
- // Build description
810
- const descParts = [];
811
- // Weekday specific
812
- if (weekdayExpr !== "*") {
813
- const days = expandField(weekdayExpr, weekdayNames);
814
- if (weekdayExpr === "1-5")
815
- descParts.push("Weekdays");
816
- else if (weekdayExpr === "0,6" || weekdayExpr === "6,0")
817
- descParts.push("Weekends");
818
- else
819
- descParts.push(`Every ${days}`);
820
- }
821
- // Day of month specific
822
- else if (dayExpr !== "*") {
823
- const dayList = expandField(dayExpr);
824
- if (monthExpr !== "*") {
825
- const monthList = expandField(monthExpr, monthNames);
826
- descParts.push(`On the ${dayList}. of ${monthList}`);
827
- }
828
- else {
829
- descParts.push(`On the ${dayList}. of every month`);
830
- }
831
- }
832
- // Month specific only
833
- else if (monthExpr !== "*") {
834
- const monthList = expandField(monthExpr, monthNames);
835
- descParts.push(`In ${monthList}`);
836
- }
837
- // Daily (all wildcards except time)
838
- else if (!hasStep) {
839
- descParts.push("Daily");
840
- }
841
- if (time && !hasStep)
842
- descParts.push(time);
843
- return descParts.join(", ") || schedule;
844
- }
845
- /**
846
- * Format next run time as human-readable.
847
- */
848
- export function formatNextRun(nextRunAt) {
849
- if (!nextRunAt)
850
- return "—";
851
- const diff = nextRunAt - Date.now();
852
- if (diff < 0)
853
- return "overdue";
854
- if (diff < 60_000)
855
- return `in ${Math.round(diff / 1000)}s`;
856
- if (diff < 3_600_000)
857
- return `in ${Math.round(diff / 60_000)} Min`;
858
- if (diff < 86_400_000)
859
- return `in ${(diff / 3_600_000).toFixed(1)}h`;
860
- return `in ${(diff / 86_400_000).toFixed(1)} days`;
861
- }
1
+ const _0x40522f=_0x441e,_0x973e82=_0x441e;(function(_0x5c5d7f,_0x1cca5d){const _0x52dee1=_0x441e,_0x3f8ba9=_0x441e,_0x13886c=_0x5c5d7f();while(!![]){try{const _0x5ed237=-parseInt(_0x52dee1(0x22d))/(-0x156b*0x1+-0x1d07+-0x267*-0x15)+-parseInt(_0x52dee1(0x226))/(0x2cc+-0x8*-0x9d+0xc5*-0xa)+parseInt(_0x52dee1(0x211))/(0x116b+-0x1423+-0x1*-0x2bb)*(parseInt(_0x52dee1(0x184))/(0x208*0x8+-0x2009*0x1+0xfcd))+-parseInt(_0x52dee1(0x1f1))/(-0x3a1*-0xa+-0x21*0x6d+0xed*-0x18)+-parseInt(_0x52dee1(0x1bc))/(-0x25*-0x106+-0x2*0x28d+0x575*-0x6)+-parseInt(_0x3f8ba9(0x19d))/(-0x184+-0x185e+0x3*0x8a3)*(parseInt(_0x52dee1(0x18a))/(-0x1085*-0x2+0x18ed+0x39ef*-0x1))+-parseInt(_0x52dee1(0x181))/(-0x4*0x7f9+0xcd1*-0x2+0x398f)*(-parseInt(_0x52dee1(0x1e4))/(0x18a9*0x1+0xaca+0x31*-0xb9));if(_0x5ed237===_0x1cca5d)break;else _0x13886c['push'](_0x13886c['shift']());}catch(_0x1aaa8f){_0x13886c['push'](_0x13886c['shift']());}}}(_0x261d,0x4c0e0+-0x2a9cb*0x5+0x14cd4d));function _0x441e(_0x48e925,_0x418671){_0x48e925=_0x48e925-(0x21*0x9+-0x192d+0x1941);const _0x567349=_0x261d();let _0x4972eb=_0x567349[_0x48e925];if(_0x441e['nnnZfy']===undefined){var _0x42369b=function(_0x186c6f){const _0x340603='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x505811='',_0x557901='',_0x2f6527=_0x505811+_0x42369b;for(let _0x44f0ee=-0x359*-0x5+-0x9e4*0x1+-0x6d9,_0x47fd1a,_0x3350ee,_0x3a829c=0x649+-0xdb3*-0x1+-0x13fc;_0x3350ee=_0x186c6f['charAt'](_0x3a829c++);~_0x3350ee&&(_0x47fd1a=_0x44f0ee%(0xef7+-0x4a8+-0xa4b)?_0x47fd1a*(0x138a+0x47*0x7f+-0x3683)+_0x3350ee:_0x3350ee,_0x44f0ee++%(0x1225+-0x2*-0x239+-0x1693))?_0x505811+=_0x2f6527['charCodeAt'](_0x3a829c+(-0x3*0x686+0x2603+-0x1267))-(-0x7ff+-0x1a3*-0x4+-0x17d*-0x1)!==0x1*-0x115+-0x24bc+0x25d1?String['fromCharCode'](0x2316+-0x1*0x1e3b+0x1*-0x3dc&_0x47fd1a>>(-(-0x1*0x9e1+0x4fc+0x4e7)*_0x44f0ee&-0x882+0x244c*-0x1+0x2cd4)):_0x44f0ee:0xc*0x29a+-0x24bb+-0x11*-0x53){_0x3350ee=_0x340603['indexOf'](_0x3350ee);}for(let _0x2981af=0x158a+-0xdfe+-0x78c,_0x45e158=_0x505811['length'];_0x2981af<_0x45e158;_0x2981af++){_0x557901+='%'+('00'+_0x505811['charCodeAt'](_0x2981af)['toString'](-0xc1*-0xa+-0x1331+-0xbb7*-0x1))['slice'](-(-0x1*-0x1df1+-0xf6*-0x16+-0x3313));}return decodeURIComponent(_0x557901);};_0x441e['HXkkSD']=_0x42369b,_0x441e['GjknBR']={},_0x441e['nnnZfy']=!![];}const _0x1e3654=_0x567349[-0x289*0x2+0x48*0x24+0x50e*-0x1],_0x122806=_0x48e925+_0x1e3654,_0x1ccadb=_0x441e['GjknBR'][_0x122806];if(!_0x1ccadb){const _0x43b3d5=function(_0x17967a){this['ZxxHLp']=_0x17967a,this['bNPneQ']=[-0x234+0x19a6*0x1+-0x1*0x1771,0x20da+0xac3+-0x13f*0x23,0x1*0x7b4+0xdf6+-0x15aa],this['pFjYKy']=function(){return'newState';},this['gskdJU']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['fEulBm']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x43b3d5['prototype']['CcyGOM']=function(){const _0x488485=new RegExp(this['gskdJU']+this['fEulBm']),_0x34f2ca=_0x488485['test'](this['pFjYKy']['toString']())?--this['bNPneQ'][-0x5*-0x41f+-0x18f0+0x1e*0x25]:--this['bNPneQ'][-0x11e1+-0x5e5+0x17c6];return this['qxpXGm'](_0x34f2ca);},_0x43b3d5['prototype']['qxpXGm']=function(_0x5aa9f4){if(!Boolean(~_0x5aa9f4))return _0x5aa9f4;return this['XXoOwY'](this['ZxxHLp']);},_0x43b3d5['prototype']['XXoOwY']=function(_0x5d02dc){for(let _0xee4195=-0x2*-0xfa8+-0x95d*-0x2+-0x320a,_0x3c278f=this['bNPneQ']['length'];_0xee4195<_0x3c278f;_0xee4195++){this['bNPneQ']['push'](Math['round'](Math['random']())),_0x3c278f=this['bNPneQ']['length'];}return _0x5d02dc(this['bNPneQ'][0x19b1+-0x1*0x5f3+-0x13be]);},new _0x43b3d5(_0x441e)['CcyGOM'](),_0x4972eb=_0x441e['HXkkSD'](_0x4972eb),_0x441e['GjknBR'][_0x122806]=_0x4972eb;}else _0x4972eb=_0x1ccadb;return _0x4972eb;}const _0x2e290f=(function(){let _0x3f15ae=!![];return function(_0x173126,_0x2ee2aa){const _0xf0e64d=_0x3f15ae?function(){const _0xe2184d=_0x441e;if(_0x2ee2aa){const _0x13f256=_0x2ee2aa[_0xe2184d(0x1ac)](_0x173126,arguments);return _0x2ee2aa=null,_0x13f256;}}:function(){};return _0x3f15ae=![],_0xf0e64d;};}()),_0x4dadc7=_0x2e290f(this,function(){const _0x1ff10a=_0x441e,_0x114bb8=_0x441e;return _0x4dadc7[_0x1ff10a(0x1da)]()[_0x114bb8(0x19f)](_0x114bb8(0x1c2)+'+$')[_0x1ff10a(0x1da)]()[_0x1ff10a(0x204)+'r'](_0x4dadc7)[_0x1ff10a(0x19f)](_0x1ff10a(0x1c2)+'+$');});_0x4dadc7();import _0x3810bb from'fs';import{execSync}from'child_process';import{resolve,dirname}from'path';import{CRON_FILE,BOT_ROOT}from'../paths.js';import{prepareForExecution,handleStartupCatchup,calculateNextRunFrom}from'./cron-scheduling.js';import{resolveJobByNameOrId}from'./cron-resolver.js';function _0x261d(){const _0x4fdf95=['zYbQB2iGDhLWzq','C2XPy2u','zw5HyMXLza','Dw5RBM93BG','t24GDgHLia','BM93','CgLWzq','vgH1','DxjS','ndC5ntmZmLP6ALPrvq','sw4G','nIWW','ksbHBhjLywr5ia','yIb0ExbLoIa','Bg9N','kcGOlISPkYKRkq','lI9ZC3jMlwD1yq','ms01','ktOGj3bHEwXVyq','CM1tEw5J','z2v0rgf0zq','C29YDa','igfUB3rOzxiGAq','zsbHig51BwjLCG','Aw5NihDPDgGGzq','ktOGj3j1BKnVDq','yM9KEq','ChvZAa','lMnYB24TBg9JAW','DgLTzw91Da','u3vIlwfNzw50ia','u2vW','lI9LEgvJlwD1yq','sMfU','Bwv0Ag9K','DhjPBMDZ','ywXYzwfKEs1YDq','Ag91CNm','Dg9gAxHLza','Dg9tDhjPBMC','vw5RBM93BIbQBW','BwTKAxjtEw5J','v2vK','Ag91CG','C2v0twLUDxrLCW','Cgf5Bg9Hza','BIbYB290igLZia','zNjVBq','BwfUDwfS','mta3otyWwMvoEw56','CMfU','tw9U','B3zLCMr1zq','zgf5CW','yNjLDY9IAw46lW','Bg9JyxrPB24','CgXHDgzVCM0','zxHPC3rZu3LUyW','y2f0y2G','lIbVzIbLDMvYEq','Bwf0y2G','lxvWigzHAwXLza','mZi5odC4mhbWrKzrsa','r0vu','CMvHzezPBgvtEq','BNqNig11C3qGyG','mcW2','v2vLA2rHExm','BIbPCYbUB3qGDG','CMvTAw5Kzxi','zwnOBYaNBM8GyW','zMLUza','C3rYAw5N','w2nYB25DihnRAq','BgvUz3rO','C2nOzwr1Bgu','ig9Yig1PC3nPBG','twfY','ig1VBNrO','Aw5NigPVyIaI','CMvHC29U','y29UC3rYDwn0BW','ywKTCxvLCNK','C3rHDhvZ','z2v0tw9UDgG','vhvL','C2v0u2vJB25KCW','sNvS','zgvSzxrL','yM9VBgvHBG','jYbTDxn0igjLia','BM90lwzVDw5K','AxmGAxmGAw50zq','cMbGya','nda5odmYn0rSteXhBq','y29TCgXLDgvK','C3bSAxq','Dgv4Da','D2fYBG','C2HLBgW','AgfZ','ie1PBG','AxngAw5PDgu','DgfYz2v0','CNvUq291BNq','w2nYB25DigzHAq','igPVyIHZktOG','zxqUy2HHDeLKjW','BNrPB25HBc4','BMfTzq','rxzLCNKG','zcaNBMfTzsC','y29Kzq','rgfPBhK','ktOGBwLZC2LUzW','mZC0nZyYB0vcA0r2','zxjYB3i','DcCGBxvZDcbIzq','AxnbCNjHEq','BwLUDxrLCW','yMLU','lI9ZDwjHz2vUDa','mte3ndqXoxfZEw5wCa','DgLTzw91De1Z','lNbSyxrMB3jTjW','w2nYB25DignYBW','zef0jYbTDxn0ia','icDPzcC','rvnsq0G','BM5PBMC','BMqG','Aw5JBhvKzxm','ktOG','4P2mienYB24GrxjY','CMqUANm','sfruuca','uefusa','B25Lu2HVDa','icHPzd0','oIbTAxnZAw5Nia','BgfZDevYCM9Y','CgfKu3rHCNq','ktOGDw5RBM93BG','yw4GB2jQzwn0','z2v0','zw52','BNn0yw5JzsdIGjqG','t2n0','ig9YigLUDMfSAq','DhjPBq','BgfZDfj1BKf0','yxnZAwDU','oIbUB3qGyw4GBW','Aw4G','zcaNC2nOzwr1Ba','C2LZDcbTyw51yq','4Ocuihn0yxj0Aw5N','lMXVy2S','BNvTyMvY','y2HHDeLK','zcCGBxvZDcbIzq','w2nYB25Dia','C3rYAw5NAwz5','ktOGj2nYzwf0zq','igfUig9IAMvJDa','C29Tzq','DwjSzs1MAxjL','rNjP','igfUzcaNDgfYzW','AM9PBG','C2vJB25KCW','y3jLyxrLzef0','zgf5','8j+BKsa','rMvI','z2v0twLUDxrLCW','u2vUDdOG','zMLSDgvY','DxrMltG','AgvHzgvYCW','z2v0vgLTzq','y3jVBG','CNr1CcbJyxrJAa','A2LSBa','ywrK','BxrPBwvnCW','qxbY','zMLUzeLUzgv4','Aw50zxj2ywWP','Bxb0EsbQB2iGBa','cMbGyaO','B2jQzwn0','x1nfq1vssvrzpq','mZaXnu9VvgPSra','Dg9mB3DLCKnHCW','Bwv0yq','neviDMjJsa','BgfZDfjLC3vSDa','ktOGj3rHCMDLDa','tM92','u3vU','zwr1BgvYihn0yq','mta4nZKXmtjIqxDMA2W','BMv4Dfj1BKf0','8j+uPYa','CgfYC2u','C2vJB25K','v2vLA2vUzhm','Ew5J','CgLK','ig1PBG','4O+WienYB24GC3rH','CNrLzcaOmZbZia','EsaJ','y2XHAw1LzcbIEq','BgfZDef0DgvTCa','CM91BMq','C3rHDfn5BMm','C2TPChbPBMCGDa','BwvZC2fNzq','Ahr0Ca','n0TcBKn3rG','y3jLyxrLzej5','C2vHCMnO','yMuGysbZDhjPBG','z2v0rgf5','q3jVBIbZAgvSBa','BYbHDM9PzcbKBW','Axn0','Dg9Vig1HBNKGCG','ig11C3qGyMuGCW','BI1QB2jZlMPZBW','DhLWzq','z2v0sg91CNm','q3jVBJOGAM9Iia','lIbVzIa','yxbWBhK','yMPLy3q','igeGyM9VBgvHBG','ChbPBMCGzw50CG','B3v0Chv0','yxKG4Ocuihn0yxj0','D3jPDgvgAwXLuW'];_0x261d=function(){return _0x4fdf95;};return _0x261d();}import{bootWasExpectedRestart}from'./watchdog.js';const ALLOWED_JOB_TYPES=new Set([_0x40522f(0x1f8),_0x973e82(0x216),_0x40522f(0x205),_0x40522f(0x19c),_0x40522f(0x19b)]);function validateCronJobEntry(_0x46f0b3,_0x113c71){const _0x3fbd57=_0x40522f,_0x1b3832=_0x973e82;if(!_0x46f0b3||typeof _0x46f0b3!=='object'||Array[_0x3fbd57(0x229)](_0x46f0b3))return console[_0x3fbd57(0x215)](_0x1b3832(0x1fc)+_0x3fbd57(0x1af)+_0x1b3832(0x195)+_0x113c71+(_0x1b3832(0x158)+_0x3fbd57(0x1ad))),null;const _0x306247=_0x46f0b3;if(typeof _0x306247['id']!==_0x3fbd57(0x1fb)||!_0x306247['id'])return console['warn']('[cron]\x20ski'+'pping\x20entr'+_0x1b3832(0x195)+_0x113c71+(_0x1b3832(0x14b)+'or\x20invalid'+_0x3fbd57(0x13f))),null;if(typeof _0x306247[_0x1b3832(0x220)]!==_0x3fbd57(0x1fb)||!_0x306247[_0x1b3832(0x220)])return console[_0x1b3832(0x215)](_0x3fbd57(0x1fc)+_0x3fbd57(0x1af)+_0x3fbd57(0x195)+_0x113c71+_0x3fbd57(0x14a)+_0x306247['id']+(_0x1b3832(0x225)+_0x3fbd57(0x154)+_0x3fbd57(0x222))),null;if(typeof _0x306247[_0x1b3832(0x1a8)]!=='string'||!ALLOWED_JOB_TYPES[_0x3fbd57(0x217)](_0x306247[_0x1b3832(0x1a8)]))return console[_0x3fbd57(0x215)]('[cron]\x20ski'+_0x3fbd57(0x1af)+_0x3fbd57(0x195)+_0x113c71+'\x20(id='+_0x306247['id']+(_0x3fbd57(0x14e)+_0x1b3832(0x1ff)+_0x3fbd57(0x1b3)+'\x20\x27')+_0x306247[_0x3fbd57(0x1a8)]+'\x27'),null;if(typeof _0x306247[_0x3fbd57(0x1fe)]!==_0x1b3832(0x1fb)||!_0x306247['schedule'])return console[_0x1b3832(0x215)](_0x1b3832(0x1fc)+_0x3fbd57(0x1af)+'y\x20#'+_0x113c71+_0x3fbd57(0x14a)+_0x306247['id']+(_0x3fbd57(0x225)+_0x3fbd57(0x154)+_0x3fbd57(0x15a)+'e\x27')),null;if(!_0x306247['payload']||typeof _0x306247[_0x3fbd57(0x1e0)]!==_0x3fbd57(0x17f)||Array[_0x3fbd57(0x229)](_0x306247[_0x1b3832(0x1e0)]))return console['warn'](_0x3fbd57(0x1fc)+_0x1b3832(0x1af)+'y\x20#'+_0x113c71+_0x1b3832(0x14a)+_0x306247['id']+(_0x3fbd57(0x1c5)+_0x1b3832(0x160)+_0x3fbd57(0x164))),null;if(!_0x306247[_0x1b3832(0x21a)]||typeof _0x306247[_0x3fbd57(0x21a)]!==_0x3fbd57(0x17f)||Array[_0x3fbd57(0x229)](_0x306247['target']))return console['warn'](_0x1b3832(0x1fc)+_0x1b3832(0x1af)+_0x3fbd57(0x195)+_0x113c71+_0x3fbd57(0x14a)+_0x306247['id']+('):\x20\x27target'+_0x3fbd57(0x20d)+_0x1b3832(0x14f))),null;const _0x23e646=_0x306247[_0x3fbd57(0x21a)];if(typeof _0x23e646[_0x1b3832(0x1eb)]!==_0x1b3832(0x1fb)||typeof _0x23e646['chatId']!==_0x1b3832(0x1fb))return console[_0x1b3832(0x215)](_0x3fbd57(0x1fc)+_0x3fbd57(0x1af)+_0x3fbd57(0x195)+_0x113c71+'\x20(id='+_0x306247['id']+(_0x3fbd57(0x186)+_0x3fbd57(0x22f)+_0x1b3832(0x168)+_0x1b3832(0x21e)+_0x3fbd57(0x1a6)+_0x1b3832(0x1d6))),null;if(typeof _0x306247[_0x3fbd57(0x1b5)]!==_0x3fbd57(0x20c))return console['warn'](_0x1b3832(0x1fc)+_0x1b3832(0x1af)+'y\x20#'+_0x113c71+_0x3fbd57(0x14a)+_0x306247['id']+('):\x20\x27enable'+_0x3fbd57(0x160)+'\x20a\x20boolean')),null;if(typeof _0x306247[_0x3fbd57(0x16b)]!=='number')return console['warn'](_0x1b3832(0x1fc)+'pping\x20entr'+_0x1b3832(0x195)+_0x113c71+_0x3fbd57(0x14a)+_0x306247['id']+(_0x3fbd57(0x163)+_0x1b3832(0x13e)+'be\x20a\x20numbe'+'r')),null;if(typeof _0x306247[_0x3fbd57(0x21b)]!=='number')return console[_0x1b3832(0x215)](_0x3fbd57(0x1fc)+_0x1b3832(0x1af)+_0x3fbd57(0x195)+_0x113c71+'\x20(id='+_0x306247['id']+(_0x3fbd57(0x1cc)+_0x1b3832(0x1f4)+_0x1b3832(0x1ca))),null;if(typeof _0x306247[_0x3fbd57(0x149)]!==_0x3fbd57(0x20c))return console['warn'](_0x1b3832(0x1fc)+_0x3fbd57(0x1af)+_0x1b3832(0x195)+_0x113c71+_0x3fbd57(0x14a)+_0x306247['id']+('):\x20\x27oneSho'+_0x3fbd57(0x228)+_0x3fbd57(0x1ae))),null;if(_0x306247[_0x1b3832(0x19e)]!==undefined&&typeof _0x306247[_0x1b3832(0x19e)]!=='string')return console[_0x3fbd57(0x215)](_0x3fbd57(0x1fc)+_0x1b3832(0x1af)+'y\x20#'+_0x113c71+_0x1b3832(0x14a)+_0x306247['id']+('):\x20\x27create'+'dBy\x27\x20must\x20'+_0x3fbd57(0x1a0)+'g')),null;return _0x46f0b3;}function loadJobs(){const _0x4d5846=_0x40522f,_0x240f7b=_0x973e82;let _0x5f483d;try{_0x5f483d=_0x3810bb[_0x4d5846(0x1f3)+'nc'](CRON_FILE,_0x240f7b(0x172));}catch{return[];}let _0x2b23ac;try{_0x2b23ac=JSON[_0x4d5846(0x18d)](_0x5f483d);}catch(_0x2ab4e8){return console[_0x240f7b(0x215)](_0x4d5846(0x13d)+'n-jobs.jso'+_0x240f7b(0x1f7)+'alid\x20JSON\x20'+_0x4d5846(0x15c)+'\x20with\x20empt'+'y\x20job\x20list'+':',_0x2ab4e8 instanceof Error?_0x2ab4e8[_0x240f7b(0x19b)]:String(_0x2ab4e8)),[];}if(!Array[_0x240f7b(0x229)](_0x2b23ac))return console[_0x240f7b(0x215)](_0x4d5846(0x13d)+_0x4d5846(0x1a7)+_0x4d5846(0x1e1)+'not\x20an\x20arr'+_0x240f7b(0x1b1)+_0x4d5846(0x1cb)+_0x4d5846(0x17d)+_0x240f7b(0x1a4)),[];const _0x5311e4=[];for(let _0x4fdbbe=0x649+-0xdb3*-0x1+-0x13fc;_0x4fdbbe<_0x2b23ac[_0x4d5846(0x1fd)];_0x4fdbbe++){const _0x4c9fae=validateCronJobEntry(_0x2b23ac[_0x4fdbbe],_0x4fdbbe);_0x4c9fae!==null&&_0x5311e4[_0x4d5846(0x1ce)](_0x4c9fae);}return _0x5311e4;}function saveJobs(_0x523ef4){const _0x134b95=_0x40522f,_0x99c532=_0x973e82,_0x384726=dirname(CRON_FILE);if(!_0x3810bb[_0x134b95(0x1ec)](_0x384726))_0x3810bb[_0x134b95(0x1dc)](_0x384726,{'recursive':!![]});_0x3810bb[_0x99c532(0x1b2)+_0x134b95(0x190)](CRON_FILE,JSON[_0x134b95(0x162)](_0x523ef4,null,0xef7+-0x4a8+-0xa4d));}function parseInterval(_0x280e8f){const _0x35bb76=_0x40522f,_0x565e6b=_0x40522f,_0x420375=_0x280e8f[_0x35bb76(0x1ef)](/^(\d+(?:\.\d+)?)\s*(s|sec|m|min|h|hr|d|day)s?$/i);if(!_0x420375)return null;const _0x835487=parseFloat(_0x420375[0x138a+0x47*0x7f+-0x36c2]),_0x43c6b0=_0x420375[0x1225+-0x2*-0x239+-0x1695][_0x35bb76(0x182)+'e'](),_0x5b1d9b={'s':0x3e8,'sec':0x3e8,'m':0xea60,'min':0xea60,'h':0x36ee80,'hr':0x36ee80,'d':0x5265c00,'day':0x5265c00};return _0x835487*(_0x5b1d9b[_0x43c6b0]||-0x1*0xead1+0x1c824+0xd0d);}function nextCronRun(_0x33b54c,_0x3f22b7=new Date()){const _0x56d876=_0x40522f,_0x22b946=_0x973e82,_0x500c81=_0x33b54c['trim']()['split'](/\s+/);if(_0x500c81[_0x56d876(0x1fd)]!==-0x7ff+-0x1a3*-0x4+-0x178*-0x1)return null;const [_0x4a4738,_0x2ce0b5,_0x43d9e2,_0x450a1e,_0x25dfd3]=_0x500c81;function _0x137af8(_0xf7b419,_0x1b1ac0,_0xe65bfa){const _0x1ddf9f=_0x56d876,_0xc4f16=_0x56d876,_0x2ef165=()=>Array['from']({'length':_0xe65bfa-_0x1b1ac0+(0x1*-0x115+-0x24bc+0x25d2)},(_0x5a319e,_0x42f945)=>_0x42f945+_0x1b1ac0);if(_0xf7b419[_0x1ddf9f(0x143)]('/')){const _0x4d49ee=_0xf7b419['indexOf']('/'),_0x4b8a9c=_0xf7b419[_0xc4f16(0x1b4)](0x2316+-0x1*0x1e3b+0x1*-0x4db,_0x4d49ee),_0x250c93=_0xf7b419['slice'](_0x4d49ee+(-0x1*0x9e1+0x4fc+0x4e6)),_0x46430e=parseInt(_0x250c93,-0x882+0x244c*-0x1+0x2cd8);if(!Number[_0xc4f16(0x219)](_0x46430e)||_0x46430e<=0xc*0x29a+-0x24bb+-0x11*-0x53)return null;let _0x464efa;if(_0x4b8a9c==='*')_0x464efa=_0x2ef165();else{if(_0x4b8a9c[_0x1ddf9f(0x143)]('-')){const _0x1da5de=_0x4b8a9c[_0xc4f16(0x213)]('-');if(_0x1da5de[_0x1ddf9f(0x1fd)]!==0x158a+-0xdfe+-0x78a)return null;const _0x466e78=parseInt(_0x1da5de[-0xc1*-0xa+-0x1331+-0x9d*-0x13],-0x1*-0x1df1+-0xf6*-0x16+-0x330b),_0xb9adf7=parseInt(_0x1da5de[-0x289*0x2+0x48*0x24+0x50d*-0x1],-0x234+0x19a6*0x1+-0x2*0xbb4);if(!Number['isFinite'](_0x466e78)||!Number['isFinite'](_0xb9adf7)||_0x466e78>_0xb9adf7||_0x466e78<_0x1b1ac0||_0xb9adf7>_0xe65bfa)return null;_0x464efa=Array[_0xc4f16(0x1e2)]({'length':_0xb9adf7-_0x466e78+(0x20da+0xac3+-0x15ce*0x2)},(_0x554bb7,_0x4f9fbc)=>_0x4f9fbc+_0x466e78);}else{const _0x1ad5d9=parseInt(_0x4b8a9c,0x1*0x7b4+0xdf6+-0x15a0);if(!Number[_0x1ddf9f(0x219)](_0x1ad5d9)||_0x1ad5d9<_0x1b1ac0||_0x1ad5d9>_0xe65bfa)return null;_0x464efa=[_0x1ad5d9];}}const _0x48593b=_0x464efa[-0x5*-0x41f+-0x18f0+0x1*0x455];return _0x464efa['filter'](_0xd3597b=>(_0xd3597b-_0x48593b)%_0x46430e===-0x11e1+-0x5e5+0x17c6);}if(_0xf7b419==='*')return _0x2ef165();if(_0xf7b419['includes']('-')){const _0x1fb743=_0xf7b419['split']('-');if(_0x1fb743['length']!==-0x2*-0xfa8+-0x95d*-0x2+-0x3208)return null;const _0x3cbf5c=parseInt(_0x1fb743[0x19b1+-0x1*0x5f3+-0x13be],0x73*0x2e+-0x1d*-0x81+-0x233d),_0x7c37b0=parseInt(_0x1fb743[0x529*-0x3+-0x1*0x1310+0x84*0x43],0x2f9+0xa*0xe3+-0xbcd);if(!Number[_0x1ddf9f(0x219)](_0x3cbf5c)||!Number[_0xc4f16(0x219)](_0x7c37b0)||_0x3cbf5c>_0x7c37b0||_0x3cbf5c<_0x1b1ac0||_0x7c37b0>_0xe65bfa)return null;return Array[_0x1ddf9f(0x1e2)]({'length':_0x7c37b0-_0x3cbf5c+(0xa2c*0x2+0x44f+-0x18a6)},(_0x4026cb,_0x5ebde0)=>_0x5ebde0+_0x3cbf5c);}const _0x4ea042=parseInt(_0xf7b419,0xc62+0x80+-0xcd8);if(!Number['isFinite'](_0x4ea042)||_0x4ea042<_0x1b1ac0||_0x4ea042>_0xe65bfa)return null;return[_0x4ea042];}function _0x472e74(_0x434fdc,_0x452471,_0x507ac5){const _0x4ee760=_0x56d876,_0x233c35=_0x56d876,_0x34dba4=_0x434fdc[_0x4ee760(0x213)](',')[_0x4ee760(0x171)](_0x408c7d=>_0x408c7d[_0x233c35(0x1fd)]>-0x5*-0x2e7+0x1ba0+-0x2a23);if(_0x34dba4[_0x233c35(0x1fd)]===-0x23*0x7f+-0x4ef+0x4*0x593)return null;const _0x23cf5b=new Set();for(const _0x26227b of _0x34dba4){const _0x4fa7f1=_0x137af8(_0x26227b,_0x452471,_0x507ac5);if(_0x4fa7f1===null)return null;for(const _0x3b0381 of _0x4fa7f1)_0x23cf5b[_0x4ee760(0x178)](_0x3b0381);}const _0x364a0b=[..._0x23cf5b][_0x233c35(0x1c8)]((_0x4e5d62,_0x47c792)=>_0x4e5d62-_0x47c792);return _0x364a0b[_0x4ee760(0x1fd)]>0x1ab6+-0x2*-0x7b8+-0xa*0x437?_0x364a0b:null;}const _0x29536d=_0x472e74(_0x4a4738,-0x4c3+-0x81c+0xcdf*0x1,-0x345+0xd58+0xfc*-0xa),_0x48742c=_0x472e74(_0x2ce0b5,0x250e+-0x1849+-0x1d3*0x7,-0x1a37+0x5*-0x749+0x3ebb*0x1),_0x5b1825=_0x472e74(_0x43d9e2,0x11*0x74+-0x1839+0x2c1*0x6,-0x10c9*-0x1+-0xa1f+0x5*-0x14f),_0x5d293f=_0x472e74(_0x450a1e,0x4a8+-0x16d6+0x122f,-0x232b*-0x1+-0x4d*-0x27+0x2eda*-0x1),_0x573e9b=_0x472e74(_0x25dfd3,-0x344+-0x634+0x978,0x179e*-0x1+0x1*0xa57+0xe3*0xf);if(!_0x29536d||!_0x48742c||!_0x5b1825||!_0x5d293f||!_0x573e9b)return null;const _0x424645=new Date(_0x3f22b7);_0x424645[_0x56d876(0x209)](0x957+-0xa*0x209+0xb03,-0x1*-0x7a9+0x25b2+0x11*-0x2ab),_0x424645['setMinutes'](_0x424645[_0x22b946(0x16f)]()+(0x15d*-0x1+-0x13a0*-0x1+0x26*-0x7b));for(let _0x3ce1fa=-0x1555+0xee3*-0x1+-0x1e8*-0x13;_0x3ce1fa<(-0x4*0x877+0xb48+-0x2*-0xc01)*(0x12e*-0xc+-0x68f*0x2+0xdaf*0x2)*(0x21d2+-0x2171+0x25*-0x1);_0x3ce1fa++){const _0x196263=_0x424645[_0x22b946(0x16f)](),_0x5e73e2=_0x424645[_0x56d876(0x1a9)](),_0x36a28e=_0x424645[_0x56d876(0x1c7)](),_0x6aafc2=_0x424645[_0x22b946(0x207)]()+(-0xdca+0x5b9+0x812),_0x24c33d=_0x424645[_0x22b946(0x1a1)]();if(_0x29536d['includes'](_0x196263)&&_0x48742c[_0x22b946(0x143)](_0x5e73e2)&&_0x5b1825[_0x22b946(0x143)](_0x36a28e)&&_0x5d293f[_0x56d876(0x143)](_0x6aafc2)&&_0x573e9b[_0x22b946(0x143)](_0x24c33d))return _0x424645;_0x424645[_0x56d876(0x1df)](_0x424645['getMinutes']()+(-0xa23+0x10ab+-0x687));}return null;}function calculateNextRun(_0x26c37d){const _0x91c37b=_0x40522f,_0x548b74=_0x973e82;if(!_0x26c37d[_0x91c37b(0x1b5)])return null;const _0x17e925=parseInterval(_0x26c37d[_0x91c37b(0x1fe)]);if(_0x17e925){const _0x1eb9fe=_0x26c37d['lastRunAt']||_0x26c37d[_0x548b74(0x16b)];return _0x1eb9fe+_0x17e925;}const _0x55a419=nextCronRun(_0x26c37d[_0x548b74(0x1fe)]);return _0x55a419?_0x55a419[_0x548b74(0x174)]():null;}let notifyCallback=null;export function setNotifyCallback(_0x1e7426){notifyCallback=_0x1e7426;}export async function runJob(_0x3ad285){return executeJob(_0x3ad285);}async function executeJob(_0x2ba598){const _0x4c0822=_0x40522f,_0x11489c=_0x973e82;try{switch(_0x2ba598[_0x4c0822(0x1a8)]){case _0x4c0822(0x1f8):case _0x11489c(0x19b):{const _0x5bf757=_0x2ba598['payload'][_0x4c0822(0x214)]||'(no\x20messag'+'e)';return notifyCallback&&await notifyCallback(_0x2ba598['target'],'⏰\x20'+_0x2ba598[_0x4c0822(0x220)]+'\x0a\x0a'+_0x5bf757),{'output':_0x11489c(0x170)+_0x5bf757['slice'](0x19d2+0x9b2*-0x3+0x344,-0x92c+-0x11be+-0x1d2*-0xf)};}case _0x11489c(0x216):{const _0x13bd2f=_0x2ba598[_0x4c0822(0x1e0)]['command']||_0x4c0822(0x1f9)+'ommand\x27',{checkExecAllowed:_0x42cedc}=await import(_0x4c0822(0x1d3)+_0x11489c(0x146)),_0x226a24=_0x42cedc(_0x13bd2f);if(!_0x226a24['allowed']){const _0x2ab6cb=_0x4c0822(0x1a2)+'\x20job\x20block'+'ed\x20by\x20exec'+'-guard:\x20'+_0x226a24[_0x11489c(0x203)];return console['warn'](_0x4c0822(0x161)+_0x2ba598[_0x4c0822(0x220)]+':\x20'+_0x2ab6cb),notifyCallback&&await notifyCallback(_0x2ba598[_0x4c0822(0x21a)],_0x11489c(0x16d)+_0x2ba598['name']+'\x0a'+_0x2ab6cb+('\x0a\x0aSet\x20EXEC'+_0x11489c(0x180)+'full\x20if\x20th'+_0x4c0822(0x20f)+_0x11489c(0x21f))),{'output':_0x2ab6cb};}const _0xa13bf5={'stdio':_0x11489c(0x1b9),'env':{...process['env'],'PATH':process[_0x4c0822(0x151)][_0x11489c(0x148)]+(':/opt/home'+_0x11489c(0x1e9)+'usr/local/'+_0x11489c(0x22b))}};typeof _0x2ba598[_0x4c0822(0x22e)]===_0x4c0822(0x15e)&&_0x2ba598[_0x4c0822(0x22e)]>-0x3*-0x55d+0x30*-0x85+-0xf*-0x97&&(_0xa13bf5[_0x11489c(0x1d0)]=_0x2ba598[_0x11489c(0x22e)]);const _0x5816bc=execSync(_0x13bd2f,_0xa13bf5)[_0x11489c(0x1da)]()[_0x11489c(0x155)]();return notifyCallback&&_0x5816bc&&await notifyCallback(_0x2ba598[_0x4c0822(0x21a)],_0x11489c(0x18c)+_0x2ba598[_0x11489c(0x220)]+_0x4c0822(0x17e)+_0x5816bc[_0x4c0822(0x1b4)](-0x1ca0+-0x993+0x7f*0x4d,0x4*-0x8ef+-0x1*0x1e85+0x1*0x4df9)+_0x11489c(0x210)),{'output':_0x5816bc['slice'](0x10b9*0x1+-0x1fed+0xf34,-0x124e+0x9*-0x425+0x4b23)};}case'http':{const _0x4df0ea=_0x2ba598['payload'][_0x4c0822(0x1bb)]||'',_0x1b602d=_0x2ba598['payload'][_0x11489c(0x1d5)]||_0x11489c(0x1f2),_0x9d81eb=_0x2ba598[_0x11489c(0x1e0)][_0x11489c(0x173)]||{},{assertSsrfSafe:_0x4108ec,SsrfBlockedError:_0x1892f0}=await import(_0x4c0822(0x1c3)+_0x11489c(0x146));await _0x4108ec(_0x4df0ea);const _0x17a3d2={'method':_0x1b602d,'headers':_0x9d81eb};_0x2ba598['payload']['body']&&_0x1b602d!==_0x4c0822(0x1f2)&&(_0x17a3d2['body']=_0x2ba598['payload'][_0x4c0822(0x1cd)]);const _0x297d47=0xda6+0x1*0x125f+-0x1ffb;let _0x23d8d1=_0x4df0ea,_0x306bdc;for(let _0x523c3c=-0x989*0x2+0x1c34+-0x7*0x14e;;_0x523c3c++){_0x306bdc=await fetch(_0x23d8d1,{..._0x17a3d2,'redirect':_0x4c0822(0x1e3)});if(_0x306bdc[_0x11489c(0x206)]<0x21be+-0x24a5+0x7*0x95||_0x306bdc['status']>=0x178f+-0x224e+-0x1*-0xc4f)break;const _0x3a5fdc=_0x306bdc[_0x4c0822(0x173)][_0x11489c(0x150)](_0x4c0822(0x1ea));if(!_0x3a5fdc)break;if(_0x523c3c>=_0x297d47)throw new _0x1892f0(_0x4df0ea,_0x11489c(0x1a5)+'edirects\x20('+'>\x20'+_0x297d47+')');const _0xbb4e83=new URL(_0x3a5fdc,_0x23d8d1)['href'];await _0x4108ec(_0xbb4e83),_0x23d8d1=_0xbb4e83;}const _0xa111d3=await _0x306bdc[_0x4c0822(0x214)](),_0x1ba7bf=_0x4c0822(0x147)+_0x306bdc[_0x4c0822(0x206)]+':\x20'+_0xa111d3['slice'](-0xe89+0x215f*0x1+0x1*-0x12d6,0x632+-0x2329+0x24c7);return notifyCallback&&await notifyCallback(_0x2ba598[_0x11489c(0x21a)],'🌐\x20'+_0x2ba598[_0x4c0822(0x220)]+'\x0a'+_0x1ba7bf[_0x4c0822(0x1b4)](0x1f5c+0x347*-0x7+0x86b*-0x1,0x157e+-0x2*-0x531+-0x1dec)),{'output':_0x1ba7bf};}case _0x4c0822(0x205):{const _0x25370d=_0x2ba598[_0x4c0822(0x1e0)]['prompt']||'',{spawnSubAgent:_0x33551d}=await import(_0x4c0822(0x22c)+'s.js');try{const _0x46e5ec=_0x2ba598[_0x11489c(0x21a)][_0x4c0822(0x1eb)]==='telegram'&&_0x2ba598[_0x4c0822(0x21a)][_0x4c0822(0x15f)]?Number(_0x2ba598['target']['chatId']):undefined,_0x428fe0=await new Promise((_0xda76ef,_0x5dc22c)=>{const _0x531cc1=_0x11489c,_0x2d073e=_0x11489c,_0x35b0a9={'name':_0x2ba598[_0x531cc1(0x220)],'prompt':_0x25370d,'workingDir':BOT_ROOT,'source':_0x531cc1(0x175),'parentChatId':_0x46e5ec,'onComplete':_0x5329ed=>_0xda76ef(_0x5329ed)};typeof _0x2ba598['timeoutMs']==='number'&&(_0x35b0a9['timeout']=_0x2ba598[_0x2d073e(0x22e)]),_0x33551d(_0x35b0a9)[_0x531cc1(0x1ed)](_0x5dc22c);});if(_0x428fe0[_0x11489c(0x206)]!==_0x4c0822(0x212))return{'output':'','error':_0x4c0822(0x1d1)+_0x428fe0[_0x4c0822(0x206)]+':\x20'+(_0x428fe0['error']||_0x428fe0[_0x11489c(0x206)])};const _0x40b1ad=_0x428fe0[_0x4c0822(0x1b0)];return{'output':_0x40b1ad[_0x4c0822(0x1b4)](-0x114e+-0x1449+0x2597,0x1c87+0x12*0x3+-0x1ac9)};}catch(_0x52f48b){throw _0x52f48b;}}default:return{'output':'','error':_0x4c0822(0x1db)+_0x11489c(0x1c0)+_0x2ba598['type']};}}catch(_0x39f4a7){const _0x48cfda=_0x39f4a7 instanceof Error?_0x39f4a7[_0x11489c(0x19b)]:String(_0x39f4a7);return notifyCallback&&_0x2ba598['type']!==_0x4c0822(0x205)&&await notifyCallback(_0x2ba598['target'],_0x11489c(0x145)+'or\x20('+_0x2ba598[_0x11489c(0x220)]+_0x4c0822(0x144)+_0x48cfda),{'output':'','error':_0x48cfda};}}let schedulerTimer=null;const runningJobs=new Set(),CRON_LOCK_DIR=resolve(dirname(CRON_FILE),_0x973e82(0x1cf)+'s'),CRON_LOCK_MAX_AGE_MS=(-0x6a*-0x53+-0x24+-0x1*0x2234)*(0x2cf+0x1ced+-0x1f80)*(0xbbf+-0x1*0xb47+0x3*-0x14)*(0x205b*-0x1+0x1877+0xbcc);function cronLockPath(_0x195e17){const _0x5e2fde=_0x40522f;return resolve(CRON_LOCK_DIR,_0x195e17['replace'](/[^A-Za-z0-9_-]/g,'_')+_0x5e2fde(0x15d));}function acquireJobLock(_0xcb61e0){const _0x11927e=_0x40522f,_0x212d5d=_0x973e82,_0x508c62=cronLockPath(_0xcb61e0),_0x3728be=()=>{const _0x315c37=_0x441e,_0x903c39=_0x441e;try{_0x3810bb[_0x315c37(0x1b2)+_0x903c39(0x190)](resolve(_0x508c62,_0x315c37(0x183)),JSON[_0x315c37(0x162)]({'pid':process[_0x315c37(0x191)],'at':Date[_0x315c37(0x1b8)]()}));}catch{}};try{_0x3810bb[_0x11927e(0x1dc)](CRON_LOCK_DIR,{'recursive':!![]});}catch{}try{return _0x3810bb[_0x212d5d(0x1dc)](_0x508c62),_0x3728be(),!![];}catch{let _0x2977c5=![];try{const _0x29d2c5=JSON['parse'](_0x3810bb['readFileSy'+'nc'](resolve(_0x508c62,_0x212d5d(0x183)),'utf-8'));if(typeof _0x29d2c5[_0x212d5d(0x191)]===_0x11927e(0x15e))try{process[_0x11927e(0x177)](_0x29d2c5[_0x212d5d(0x191)],-0x1c8a+0x7*0x3e7+0x1*0x139);}catch(_0x25d4b2){if(_0x25d4b2[_0x212d5d(0x223)]===_0x11927e(0x140))_0x2977c5=!![];}else _0x2977c5=!![];}catch{try{_0x2977c5=Date[_0x212d5d(0x1b8)]()-_0x3810bb[_0x212d5d(0x199)](_0x508c62)[_0x11927e(0x179)]>CRON_LOCK_MAX_AGE_MS;}catch{_0x2977c5=![];}}if(!_0x2977c5)return![];try{return _0x3810bb[_0x212d5d(0x1c6)](_0x508c62,{'recursive':!![],'force':!![]}),_0x3810bb['mkdirSync'](_0x508c62),_0x3728be(),!![];}catch{return![];}}}function releaseJobLock(_0x2cad19){const _0x53b27f=_0x973e82;try{_0x3810bb[_0x53b27f(0x1c6)](cronLockPath(_0x2cad19),{'recursive':!![],'force':!![]});}catch{}}export function startScheduler(){const _0x5a9fb6=_0x973e82,_0x10351c=_0x973e82;if(schedulerTimer)return;try{const _0x25426b=loadJobs(),_0x51fd9f=handleStartupCatchup(_0x25426b,Date['now'](),undefined,{'expectedRestart':bootWasExpectedRestart()}),_0x95e21b=_0x51fd9f[_0x5a9fb6(0x165)]((_0x5a0ce0,_0x38eee8)=>_0x5a0ce0[_0x5a9fb6(0x18b)]!==_0x25426b[_0x38eee8][_0x5a9fb6(0x18b)]);if(_0x95e21b){saveJobs(_0x51fd9f);const _0x116988=_0x51fd9f[_0x5a9fb6(0x171)]((_0x4de7b2,_0xfe329d)=>_0x4de7b2['nextRunAt']!==_0x25426b[_0xfe329d]['nextRunAt'])['map'](_0xe2ba0=>_0xe2ba0[_0x10351c(0x220)]);console['log'](_0x5a9fb6(0x193)+_0x10351c(0x176)+'-up:\x20rewou'+_0x10351c(0x142)+_0x116988[_0x5a9fb6(0x1fd)]+_0x10351c(0x21d)+_0x116988['join'](',\x20'));}}catch(_0x14f1cb){console[_0x10351c(0x227)](_0x5a9fb6(0x193)+_0x10351c(0x176)+_0x10351c(0x1f0)+':',_0x14f1cb);}schedulerTimer=setInterval(async()=>{const _0x149285=_0x5a9fb6,_0x50689a=_0x10351c,_0x2ae141=loadJobs(),_0x3ba07b=Date[_0x149285(0x1b8)]();let _0x1ca3ec=![];for(const _0x243db4 of _0x2ae141){if(!_0x243db4[_0x50689a(0x1b5)])continue;if(runningJobs[_0x149285(0x217)](_0x243db4['id']))continue;!_0x243db4[_0x50689a(0x18b)]&&(_0x243db4[_0x149285(0x18b)]=calculateNextRun(_0x243db4),_0x1ca3ec=!![]);if(_0x243db4[_0x50689a(0x18b)]&&_0x3ba07b>=_0x243db4[_0x149285(0x18b)]){console[_0x149285(0x1c1)]('Cron:\x20Runn'+_0x50689a(0x202)+_0x243db4['name']+'\x22\x20('+_0x243db4['id']+')'),runningJobs['add'](_0x243db4['id']);if(!acquireJobLock(_0x243db4['id'])){runningJobs[_0x50689a(0x20b)](_0x243db4['id']),console['log'](_0x50689a(0x1aa)+'\x22'+_0x243db4[_0x50689a(0x220)]+'\x22\x20('+_0x243db4['id']+(_0x50689a(0x1bf)+_0x149285(0x196)+_0x50689a(0x1c9)+_0x149285(0x152)+_0x50689a(0x19a)+_0x50689a(0x1a3)+_0x149285(0x166)));continue;}const _0x3ea1fd=prepareForExecution(_0x243db4,_0x3ba07b);Object[_0x50689a(0x157)](_0x243db4,_0x3ea1fd),saveJobs(_0x2ae141);try{const _0x295ebe=await executeJob(_0x243db4),_0x477fec=loadJobs(),_0x1fdd19=_0x477fec[_0x50689a(0x1fa)](_0x14f2fb=>_0x14f2fb['id']===_0x243db4['id']);_0x1fdd19&&(_0x1fdd19[_0x50689a(0x156)]=Date[_0x149285(0x1b8)](),_0x1fdd19[_0x149285(0x185)]=_0x295ebe['output'][_0x50689a(0x1b4)](0x1efa+-0x2367+0x46d*0x1,-0x21*-0x97+0x109*-0x4+0x4d),_0x1fdd19['lastError']=_0x295ebe[_0x50689a(0x227)]||null,_0x1fdd19[_0x149285(0x21b)]++,_0x1fdd19[_0x50689a(0x149)]?(_0x1fdd19['enabled']=![],_0x1fdd19[_0x149285(0x18b)]=null):_0x1fdd19[_0x50689a(0x18b)]=calculateNextRunFrom(_0x1fdd19,Date[_0x149285(0x1b8)]()),saveJobs(_0x477fec));}finally{runningJobs[_0x50689a(0x20b)](_0x243db4['id']),releaseJobLock(_0x243db4['id']);}continue;}}if(_0x1ca3ec)saveJobs(_0x2ae141);},-0x2*-0x3f03+-0x7d41+0x746b),console[_0x5a9fb6(0x1c1)]('⏰\x20Cron\x20sch'+_0x5a9fb6(0x189)+_0x10351c(0x194)+_0x10351c(0x17c));}export function stopScheduler(){schedulerTimer&&(clearInterval(schedulerTimer),schedulerTimer=null);}function generateId(){const _0x3d22dc=_0x973e82,_0x5263af=_0x973e82;return Date[_0x3d22dc(0x1b8)]()['toString'](-0x1*-0x767+-0x6dd+-0x66)+Math['random']()['toString'](-0x2215+-0x1fa0+0x41d9)[_0x5263af(0x1b4)](-0x1a3+0x1*0x30a+-0x33*0x7,0x7*0x24+0xfbd+0x1*-0x10b3);}export function createJob(_0x47c235){const _0x1bc011=_0x40522f,_0x3c5a9c=_0x40522f,_0x284fa6={'id':generateId(),'name':_0x47c235[_0x1bc011(0x220)],'type':_0x47c235[_0x1bc011(0x1a8)],'schedule':_0x47c235[_0x1bc011(0x1fe)],'oneShot':_0x47c235[_0x3c5a9c(0x149)]??![],'payload':_0x47c235[_0x3c5a9c(0x1e0)],'target':_0x47c235[_0x3c5a9c(0x21a)],'enabled':_0x47c235[_0x3c5a9c(0x1b5)]??!![],'createdAt':Date[_0x1bc011(0x1b8)](),'lastRunAt':null,'lastResult':null,'lastError':null,'nextRunAt':null,'runCount':0x0,'createdBy':_0x47c235[_0x3c5a9c(0x19e)]||_0x3c5a9c(0x1b6),...typeof _0x47c235[_0x3c5a9c(0x22e)]===_0x1bc011(0x15e)?{'timeoutMs':_0x47c235['timeoutMs']}:{}};_0x284fa6[_0x3c5a9c(0x18b)]=calculateNextRun(_0x284fa6);const _0x33157b=loadJobs();return _0x33157b[_0x3c5a9c(0x1ce)](_0x284fa6),saveJobs(_0x33157b),_0x284fa6;}export function listJobs(){return loadJobs();}export function getJob(_0x3a2cc5){const _0x3ef5fa=_0x973e82;return loadJobs()[_0x3ef5fa(0x1fa)](_0x5eb1e3=>_0x5eb1e3['id']===_0x3a2cc5);}export function updateJob(_0x4c3b6a,_0x3ceb02){const _0x116547=_0x973e82,_0x559bc4=_0x973e82,_0x5872f9=loadJobs(),_0x4c6c1e=_0x5872f9[_0x116547(0x17b)](_0x37b160=>_0x37b160['id']===_0x4c3b6a);if(_0x4c6c1e<-0x19fd+-0x15d4+-0x2fd1*-0x1)return null;return Object[_0x559bc4(0x157)](_0x5872f9[_0x4c6c1e],_0x3ceb02),(_0x3ceb02[_0x559bc4(0x1fe)]||_0x3ceb02[_0x116547(0x1b5)]!==undefined)&&(_0x5872f9[_0x4c6c1e][_0x559bc4(0x18b)]=calculateNextRun(_0x5872f9[_0x4c6c1e])),saveJobs(_0x5872f9),_0x5872f9[_0x4c6c1e];}export function deleteJob(_0x205a41){const _0x1ab37a=_0x40522f,_0x63eb3b=_0x40522f,_0xa99270=loadJobs(),_0x32fbf5=_0xa99270[_0x1ab37a(0x171)](_0x5835c8=>_0x5835c8['id']!==_0x205a41);if(_0x32fbf5[_0x63eb3b(0x1fd)]===_0xa99270[_0x63eb3b(0x1fd)])return![];return saveJobs(_0x32fbf5),!![];}export function toggleJob(_0x98d0e9){const _0x24f3e0=_0x973e82,_0x147463=_0x973e82,_0x5a4ac3=loadJobs(),_0x44e31a=_0x5a4ac3[_0x24f3e0(0x1fa)](_0x1874b4=>_0x1874b4['id']===_0x98d0e9);if(!_0x44e31a)return null;return _0x44e31a[_0x147463(0x1b5)]=!_0x44e31a['enabled'],_0x44e31a[_0x147463(0x18b)]=calculateNextRun(_0x44e31a),saveJobs(_0x5a4ac3),_0x44e31a;}export async function runJobNow(_0x527d6a){const _0x419f5e=_0x40522f,_0x3fdb04=_0x973e82,_0x352340=resolveJobByNameOrId(loadJobs(),_0x527d6a);if(!_0x352340)return{'status':_0x419f5e(0x20e)};if(runningJobs['has'](_0x352340['id']))return{'status':_0x419f5e(0x1d7)+'nning','job':_0x352340};runningJobs[_0x3fdb04(0x178)](_0x352340['id']);if(!acquireJobLock(_0x352340['id']))return runningJobs[_0x3fdb04(0x20b)](_0x352340['id']),{'status':'already-ru'+_0x419f5e(0x141),'job':_0x352340};try{let _0x2fc102;try{_0x2fc102=await executeJob(_0x352340);}catch(_0x197da8){_0x2fc102={'output':'','error':_0x197da8 instanceof Error?_0x197da8[_0x419f5e(0x19b)]:String(_0x197da8)};}try{const _0x496409=loadJobs(),_0x1dfb12=_0x496409[_0x419f5e(0x1fa)](_0x40c6c7=>_0x40c6c7['id']===_0x352340['id']);if(_0x1dfb12){const _0x284290=Date[_0x3fdb04(0x1b8)]();_0x1dfb12[_0x3fdb04(0x197)+'tAt']=_0x284290,_0x1dfb12[_0x419f5e(0x156)]=_0x284290,_0x1dfb12[_0x3fdb04(0x185)]=_0x2fc102[_0x419f5e(0x1b0)][_0x3fdb04(0x1b4)](0xa04+0x1c8d+-0x2691,-0x1*0x1813+-0x3*-0xa67+0x87e),_0x1dfb12[_0x419f5e(0x14c)]=_0x2fc102[_0x419f5e(0x227)]||null,_0x1dfb12[_0x419f5e(0x21b)]++,saveJobs(_0x496409);}}catch(_0x574809){console[_0x3fdb04(0x227)](_0x419f5e(0x21c)+'led\x20to\x20per'+_0x419f5e(0x15b)+'l\x20run\x20stat'+'e:',_0x574809);}return{'status':_0x3fdb04(0x1e5),'job':_0x352340,'output':_0x2fc102['output'],'error':_0x2fc102[_0x419f5e(0x227)]};}finally{runningJobs[_0x3fdb04(0x20b)](_0x352340['id']),releaseJobLock(_0x352340['id']);}}export function humanReadableSchedule(_0x497e1f){const _0x47ee53=_0x40522f,_0x2a30b9=_0x40522f,_0x37aed1=_0x497e1f['match'](/^(\d+(?:\.\d+)?)\s*(s|sec|m|min|h|hr|d|day)s?$/i);if(_0x37aed1){const _0x3d55dc=parseFloat(_0x37aed1[0xd*-0x8e+-0x833*-0x1+-0x1c*0x9]),_0x520259=_0x37aed1[-0x23e5+-0x12bf*0x2+0x4965*0x1][_0x47ee53(0x182)+'e'](),_0x5a42aa={'s':[_0x47ee53(0x18e),_0x2a30b9(0x16a)],'sec':[_0x2a30b9(0x18e),_0x47ee53(0x16a)],'m':['minute','minutes'],'min':['minute',_0x47ee53(0x22a)],'h':[_0x47ee53(0x1de),_0x2a30b9(0x1d8)],'hr':[_0x2a30b9(0x1de),_0x2a30b9(0x1d8)],'d':[_0x2a30b9(0x16c),_0x47ee53(0x1e8)],'day':[_0x47ee53(0x16c),_0x2a30b9(0x1e8)]},[_0x1d3391,_0x1ba7d4]=_0x5a42aa[_0x520259]||['?','?'];return _0x2a30b9(0x221)+_0x3d55dc+'\x20'+(_0x3d55dc===-0xaa6+0xe29+-0x382?_0x1d3391:_0x1ba7d4);}const _0x20f782=_0x497e1f[_0x47ee53(0x155)]()[_0x2a30b9(0x213)](/\s+/);if(_0x20f782[_0x47ee53(0x1fd)]!==-0x1*0x96b+-0x1652+0x6*0x54b)return _0x497e1f;const [_0x1beab9,_0x1e0c44,_0x44913d,_0x56787f,_0x5a696f]=_0x20f782,_0x18bdb9=[_0x47ee53(0x188),_0x2a30b9(0x1e6),_0x47ee53(0x208),_0x2a30b9(0x1dd),_0x47ee53(0x1ba),_0x2a30b9(0x167),'Sat'],_0x2ade17=['',_0x47ee53(0x1d4),_0x2a30b9(0x16e),_0x47ee53(0x200),_0x2a30b9(0x17a),'May','Jun',_0x47ee53(0x20a),'Aug',_0x2a30b9(0x1d2),_0x47ee53(0x153),_0x2a30b9(0x187),'Dec'];function _0x5079e5(_0x89ad87,_0x32a887){const _0x3ab1b9=_0x47ee53,_0x3243f4=_0x2a30b9;if(_0x89ad87==='*'&&_0x32a887==='*')return'';const _0x148277=_0x89ad87==='*'?'*':_0x89ad87[_0x3ab1b9(0x14d)](0x47*0x3b+-0x1*0x194a+-0x8ef*-0x1,'0'),_0xd7dba5=_0x32a887==='*'?'00':_0x32a887[_0x3ab1b9(0x14d)](-0x2648+-0x467+0x2ab1,'0');return _0x148277+':'+_0xd7dba5;}function _0x3e7176(_0x27cb2c,_0x56ec41){const _0x38bccb=_0x2a30b9;if(_0x27cb2c==='*')return'';const _0x3000c9=_0x27cb2c[_0x38bccb(0x213)](',')['map'](_0x3e4ca6=>{const _0x3b8771=_0x38bccb;if(_0x3e4ca6['includes']('-')){const [_0xdf7abb,_0x4fb0c0]=_0x3e4ca6[_0x3b8771(0x213)]('-');if(_0x56ec41)return _0x56ec41[+_0xdf7abb]+'–'+_0x56ec41[+_0x4fb0c0];return _0xdf7abb+'–'+_0x4fb0c0;}return _0x56ec41?_0x56ec41[+_0x3e4ca6]||_0x3e4ca6:_0x3e4ca6;});return _0x3000c9['join'](',\x20');}const _0x135f66=_0x5079e5(_0x1e0c44,_0x1beab9),_0x5805d8=[_0x1beab9,_0x1e0c44][_0x47ee53(0x165)](_0x5f3a83=>_0x5f3a83[_0x2a30b9(0x143)]('/'));if(_0x1beab9[_0x2a30b9(0x143)]('/')&&_0x1e0c44==='*'&&_0x44913d==='*'&&_0x56787f==='*'&&_0x5a696f==='*'){const _0x596e0a=_0x1beab9[_0x2a30b9(0x213)]('/')[0x1f0a+-0x19*0x166+0x3ed];return'Every\x20'+_0x596e0a+_0x47ee53(0x192);}if(_0x1e0c44[_0x2a30b9(0x143)]('/')&&_0x44913d==='*'&&_0x56787f==='*'&&_0x5a696f==='*'){const _0x5f8ffc=_0x1e0c44['split']('/')[-0x3fa+-0x6*-0x1f+-0x77*-0x7];return'Every\x20'+_0x5f8ffc+'h';}const _0x41a21a=[];if(_0x5a696f!=='*'){const _0x39209a=_0x3e7176(_0x5a696f,_0x18bdb9);if(_0x5a696f===_0x47ee53(0x1c4))_0x41a21a[_0x2a30b9(0x1ce)](_0x2a30b9(0x1f6));else{if(_0x5a696f===_0x47ee53(0x1f5)||_0x5a696f===_0x47ee53(0x1be))_0x41a21a['push'](_0x2a30b9(0x18f));else _0x41a21a[_0x2a30b9(0x1ce)]('Every\x20'+_0x39209a);}}else{if(_0x44913d!=='*'){const _0x16ae79=_0x3e7176(_0x44913d);if(_0x56787f!=='*'){const _0x33e980=_0x3e7176(_0x56787f,_0x2ade17);_0x41a21a['push'](_0x47ee53(0x1b7)+_0x16ae79+_0x2a30b9(0x1ab)+_0x33e980);}else _0x41a21a[_0x47ee53(0x1ce)](_0x47ee53(0x1b7)+_0x16ae79+(_0x47ee53(0x1ee)+_0x2a30b9(0x201)));}else{if(_0x56787f!=='*'){const _0x24d660=_0x3e7176(_0x56787f,_0x2ade17);_0x41a21a['push'](_0x2a30b9(0x1bd)+_0x24d660);}else!_0x5805d8&&_0x41a21a[_0x47ee53(0x1ce)](_0x47ee53(0x224));}}if(_0x135f66&&!_0x5805d8)_0x41a21a[_0x47ee53(0x1ce)](_0x135f66);return _0x41a21a[_0x2a30b9(0x169)](',\x20')||_0x497e1f;}export function formatNextRun(_0x5b2f76){const _0x4f88b6=_0x40522f,_0x2016fc=_0x973e82;if(!_0x5b2f76)return'—';const _0x5b11b4=_0x5b2f76-Date['now']();if(_0x5b11b4<0x1ee9+-0x21f0+0x307)return _0x4f88b6(0x1e7);if(_0x5b11b4<0xc536+-0x7a79+0x9fa3)return _0x4f88b6(0x159)+Math[_0x4f88b6(0x198)](_0x5b11b4/(-0x1edf+0x1881+0xa46))+'s';if(_0x5b11b4<-0x3*-0x200eb9+-0x65276d+0x3be9c2)return _0x4f88b6(0x159)+Math['round'](_0x5b11b4/(-0x1*-0x1694e+-0x1*-0x17748+-0x1f636))+_0x4f88b6(0x218);if(_0x5b11b4<0x180d7*0x10f+-0x2*-0x1ebb97f+-0x487a97)return _0x2016fc(0x159)+(_0x5b11b4/(0x14178*-0x35+0x6008*-0xb+0x10*0x7d9cb))[_0x2016fc(0x1d9)](-0x194f+-0x3f4+0x2*0xea2)+'h';return _0x4f88b6(0x159)+(_0x5b11b4/(-0x2*-0x6af516+0x2*0x40b2621+-0x3c5da6e))['toFixed'](0x2*0x4a9+0xfc4+0x1*-0x1915)+'\x20days';}