@vizzor/cli 0.15.1 → 0.15.2

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/dist/index.js CHANGED
@@ -47499,6 +47499,124 @@ var init_horizon_packs = __esm({
47499
47499
  }
47500
47500
  });
47501
47501
 
47502
+ // src/notifications/scheduler-state.ts
47503
+ var scheduler_state_exports = {};
47504
+ __export(scheduler_state_exports, {
47505
+ applySchedulerStateOverlay: () => applySchedulerStateOverlay,
47506
+ isSchedulerRunningPersisted: () => isSchedulerRunningPersisted,
47507
+ persistDefaultSymbols: () => persistDefaultSymbols,
47508
+ persistSchedulerRunning: () => persistSchedulerRunning,
47509
+ persistSlotEnabled: () => persistSlotEnabled,
47510
+ persistSlotFiringTimesUtc: () => persistSlotFiringTimesUtc,
47511
+ persistSlotHorizons: () => persistSlotHorizons,
47512
+ persistSlotInterval: () => persistSlotInterval,
47513
+ persistSlotSymbols: () => persistSlotSymbols
47514
+ });
47515
+ function ensureTable6() {
47516
+ getDb().exec(`
47517
+ CREATE TABLE IF NOT EXISTS scheduler_state (
47518
+ key TEXT PRIMARY KEY,
47519
+ value TEXT NOT NULL,
47520
+ updated_at INTEGER NOT NULL
47521
+ )
47522
+ `);
47523
+ }
47524
+ function setKey(key, value) {
47525
+ ensureTable6();
47526
+ getDb().prepare(
47527
+ `INSERT INTO scheduler_state (key, value, updated_at) VALUES (?, ?, ?)
47528
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`
47529
+ ).run(key, JSON.stringify(value), Date.now());
47530
+ }
47531
+ function getKey(key) {
47532
+ ensureTable6();
47533
+ const row2 = getDb().prepare(`SELECT value FROM scheduler_state WHERE key = ?`).get(key);
47534
+ if (!row2) return null;
47535
+ try {
47536
+ return JSON.parse(row2.value);
47537
+ } catch {
47538
+ return null;
47539
+ }
47540
+ }
47541
+ function persistDefaultSymbols(symbols) {
47542
+ setKey("defaultSymbols", symbols);
47543
+ }
47544
+ function persistSchedulerRunning(running6) {
47545
+ setKey("running", running6);
47546
+ }
47547
+ function isSchedulerRunningPersisted() {
47548
+ return getKey("running");
47549
+ }
47550
+ function persistSlotEnabled(slotName, enabled) {
47551
+ const current = getKey("slotsEnabled") ?? {};
47552
+ current[slotName] = enabled;
47553
+ setKey("slotsEnabled", current);
47554
+ }
47555
+ function persistSlotSymbols(slotName, symbols) {
47556
+ const current = getKey("slotSymbols") ?? {};
47557
+ current[slotName] = symbols;
47558
+ setKey("slotSymbols", current);
47559
+ }
47560
+ function persistSlotHorizons(slotName, horizons) {
47561
+ const current = getKey("slotHorizons") ?? {};
47562
+ current[slotName] = horizons;
47563
+ setKey("slotHorizons", current);
47564
+ }
47565
+ function persistSlotInterval(slotName, intervalMinutes) {
47566
+ const current = getKey("slotIntervals") ?? {};
47567
+ current[slotName] = intervalMinutes;
47568
+ setKey("slotIntervals", current);
47569
+ }
47570
+ function persistSlotFiringTimesUtc(slotName, firingTimesUtc) {
47571
+ const current = getKey("slotFiringTimesUtc") ?? {};
47572
+ current[slotName] = firingTimesUtc === void 0 ? null : firingTimesUtc;
47573
+ setKey("slotFiringTimesUtc", current);
47574
+ }
47575
+ function applySchedulerStateOverlay(cfg) {
47576
+ try {
47577
+ const defaultSymbols = getKey("defaultSymbols");
47578
+ if (Array.isArray(defaultSymbols)) {
47579
+ cfg.defaultSymbols = defaultSymbols;
47580
+ }
47581
+ const slotsEnabled = getKey("slotsEnabled") ?? {};
47582
+ const slotSymbols = getKey("slotSymbols") ?? {};
47583
+ const slotHorizons = getKey("slotHorizons") ?? {};
47584
+ const slotIntervals = getKey("slotIntervals") ?? {};
47585
+ const slotFiringTimesUtc = getKey("slotFiringTimesUtc") ?? {};
47586
+ cfg.slots = cfg.slots.map((slot) => {
47587
+ const next = { ...slot };
47588
+ if (slotsEnabled[slot.name] !== void 0) next.enabled = slotsEnabled[slot.name];
47589
+ if (slotSymbols[slot.name] !== void 0) next.symbols = slotSymbols[slot.name];
47590
+ if (slotHorizons[slot.name] !== void 0) next.horizons = slotHorizons[slot.name];
47591
+ if (slotIntervals[slot.name] !== void 0) next.intervalMinutes = slotIntervals[slot.name];
47592
+ if (slotFiringTimesUtc[slot.name] !== void 0) {
47593
+ const v = slotFiringTimesUtc[slot.name];
47594
+ if (v === null) {
47595
+ delete next.firingTimesUtc;
47596
+ } else {
47597
+ next.firingTimesUtc = v;
47598
+ }
47599
+ }
47600
+ return next;
47601
+ });
47602
+ return cfg;
47603
+ } catch (err) {
47604
+ log111.debug(
47605
+ `applySchedulerStateOverlay failed: ${err instanceof Error ? err.message : String(err)}`
47606
+ );
47607
+ return cfg;
47608
+ }
47609
+ }
47610
+ var log111;
47611
+ var init_scheduler_state = __esm({
47612
+ "src/notifications/scheduler-state.ts"() {
47613
+ "use strict";
47614
+ init_cache();
47615
+ init_logger();
47616
+ log111 = createLogger("notifications:scheduler-state");
47617
+ }
47618
+ });
47619
+
47502
47620
  // src/notifications/bridges/prediction-scheduler.ts
47503
47621
  var prediction_scheduler_exports = {};
47504
47622
  __export(prediction_scheduler_exports, {
@@ -47690,7 +47808,7 @@ async function runPredictionSlot(slot, defaultSymbols, resolveFirst, maxConcurre
47690
47808
  if (slot.activeHoursStart !== void 0 && slot.activeHoursEnd !== void 0) {
47691
47809
  const hour = getHourInTimezone(slot.activeHoursTimezone);
47692
47810
  if (hour < slot.activeHoursStart || hour >= slot.activeHoursEnd) {
47693
- log111.debug(
47811
+ log112.debug(
47694
47812
  `Slot "${slot.name}" outside active hours (${slot.activeHoursStart}-${slot.activeHoursEnd}${slot.activeHoursTimezone ? `, tz=${slot.activeHoursTimezone}` : ""}), skipping`
47695
47813
  );
47696
47814
  return;
@@ -47698,18 +47816,20 @@ async function runPredictionSlot(slot, defaultSymbols, resolveFirst, maxConcurre
47698
47816
  }
47699
47817
  const symbols = slot.symbols.length > 0 ? slot.symbols : defaultSymbols;
47700
47818
  if (symbols.length === 0) {
47701
- log111.debug(`Slot "${slot.name}" has no symbols configured, skipping`);
47819
+ log112.warn(
47820
+ `[${slot.name}] No symbols configured for this slot and no defaults available \u2014 cycle skipped. Set defaults via /scheduler defaults BTC,ETH,SOL or override per-slot.`
47821
+ );
47702
47822
  return;
47703
47823
  }
47704
47824
  const horizonsStr = slot.horizons.join(",");
47705
- log111.info(`[${slot.name}] Running predictions for ${symbols.join(",")} @ ${horizonsStr}`);
47825
+ log112.info(`[${slot.name}] Running predictions for ${symbols.join(",")} @ ${horizonsStr}`);
47706
47826
  if (resolveFirst) {
47707
47827
  try {
47708
47828
  const { handleTool: handleTool2 } = await Promise.resolve().then(() => (init_tool_handler(), tool_handler_exports));
47709
47829
  await handleTool2("resolve_predictions", {});
47710
- log111.debug(`[${slot.name}] Resolved pending predictions`);
47830
+ log112.debug(`[${slot.name}] Resolved pending predictions`);
47711
47831
  } catch (err) {
47712
- log111.debug(
47832
+ log112.debug(
47713
47833
  `[${slot.name}] Resolve failed: ${err instanceof Error ? err.message : String(err)}`
47714
47834
  );
47715
47835
  }
@@ -47767,7 +47887,7 @@ ${SUMMARY_DIVIDER}
47767
47887
  });
47768
47888
  }
47769
47889
  } catch (err) {
47770
- log111.debug(
47890
+ log112.debug(
47771
47891
  `Admin fan-out skipped for scheduler summary: ${err instanceof Error ? err.message : String(err)}`
47772
47892
  );
47773
47893
  }
@@ -47789,12 +47909,12 @@ ${SUMMARY_DIVIDER}
47789
47909
  }
47790
47910
  }
47791
47911
  } catch (err) {
47792
- log111.debug(
47912
+ log112.debug(
47793
47913
  `Channel fan-out skipped for scheduler summary: ${err instanceof Error ? err.message : String(err)}`
47794
47914
  );
47795
47915
  }
47796
47916
  }
47797
- log111.info(`[${slot.name}] Completed ${allResults.length}/${symbols.length} predictions`);
47917
+ log112.info(`[${slot.name}] Completed ${allResults.length}/${symbols.length} predictions`);
47798
47918
  }
47799
47919
  async function runSinglePrediction(symbol, horizons, slot) {
47800
47920
  try {
@@ -47810,7 +47930,7 @@ async function runSinglePrediction(symbol, horizons, slot) {
47810
47930
  tracker.tagPredictionsBySlot(symbol.toUpperCase(), h.trim(), slot.name, preEmitSec);
47811
47931
  }
47812
47932
  } catch (tagErr) {
47813
- log111.debug(
47933
+ log112.debug(
47814
47934
  `Slot-tag failed for ${slot.name}: ${tagErr instanceof Error ? tagErr.message : String(tagErr)}`
47815
47935
  );
47816
47936
  }
@@ -47843,11 +47963,19 @@ async function runSinglePrediction(symbol, horizons, slot) {
47843
47963
  if (slot.autoAlerts) {
47844
47964
  const isShort = (d) => d === "down";
47845
47965
  const isLong2 = (d) => d === "up";
47966
+ let armed = 0;
47967
+ let skippedSideways = 0;
47968
+ let skippedAlreadyPast = 0;
47969
+ let skippedInvalid = 0;
47970
+ let skippedFailed = 0;
47846
47971
  for (const pred of predictions) {
47847
47972
  if (!pred.forecast) continue;
47848
47973
  const fc = pred.forecast;
47849
47974
  const dir = pred.direction;
47850
- if (!isShort(dir) && !isLong2(dir)) continue;
47975
+ if (!isShort(dir) && !isLong2(dir)) {
47976
+ skippedSideways++;
47977
+ continue;
47978
+ }
47851
47979
  const tpAbove = isLong2(dir);
47852
47980
  const slAbove = isShort(dir);
47853
47981
  const spot = pred.forecast.entry ?? 0;
@@ -47857,11 +47985,20 @@ async function runSinglePrediction(symbol, horizons, slot) {
47857
47985
  { price: fc.sl, label: `${pred.horizon} SL`, above: slAbove }
47858
47986
  ];
47859
47987
  for (const alert of candidates) {
47860
- if (!alert.price || !isFinite(alert.price) || alert.price <= 0) continue;
47988
+ if (!alert.price || !isFinite(alert.price) || alert.price <= 0) {
47989
+ skippedInvalid++;
47990
+ continue;
47991
+ }
47861
47992
  if (spot > 0) {
47862
47993
  const pad2 = spot * 2e-4;
47863
- if (alert.above && alert.price <= spot + pad2) continue;
47864
- if (!alert.above && alert.price >= spot - pad2) continue;
47994
+ if (alert.above && alert.price <= spot + pad2) {
47995
+ skippedAlreadyPast++;
47996
+ continue;
47997
+ }
47998
+ if (!alert.above && alert.price >= spot - pad2) {
47999
+ skippedAlreadyPast++;
48000
+ continue;
48001
+ }
47865
48002
  }
47866
48003
  try {
47867
48004
  await handleTool2("set_price_alert", {
@@ -47869,10 +48006,17 @@ async function runSinglePrediction(symbol, horizons, slot) {
47869
48006
  [alert.above ? "above" : "below"]: alert.price,
47870
48007
  label: alert.label
47871
48008
  });
48009
+ armed++;
47872
48010
  } catch {
48011
+ skippedFailed++;
47873
48012
  }
47874
48013
  }
47875
48014
  }
48015
+ if (armed > 0 || skippedAlreadyPast > 0 || skippedFailed > 0 || skippedSideways > 0) {
48016
+ log112.info(
48017
+ `[${slot.name}] ${symbol} auto-alerts: armed=${armed}, skipped(sideways)=${skippedSideways}, skipped(already-past-spot)=${skippedAlreadyPast}, skipped(invalid)=${skippedInvalid}, skipped(failed)=${skippedFailed}`
48018
+ );
48019
+ }
47876
48020
  }
47877
48021
  return {
47878
48022
  symbol,
@@ -47882,7 +48026,7 @@ async function runSinglePrediction(symbol, horizons, slot) {
47882
48026
  predictions
47883
48027
  };
47884
48028
  } catch (err) {
47885
- log111.warn(
48029
+ log112.warn(
47886
48030
  `[${slot.name}] Prediction failed for ${symbol}: ${err instanceof Error ? err.message : String(err)}`
47887
48031
  );
47888
48032
  return null;
@@ -47890,24 +48034,24 @@ async function runSinglePrediction(symbol, horizons, slot) {
47890
48034
  }
47891
48035
  function startPredictionScheduler(config3) {
47892
48036
  if (!config3.enabled) {
47893
- log111.debug("Prediction scheduler disabled");
48037
+ log112.debug("Prediction scheduler disabled");
47894
48038
  return () => {
47895
48039
  };
47896
48040
  }
47897
48041
  if (process.env["BACKGROUND_TASKS"] === "false") {
47898
- log111.info("prediction-scheduler: BACKGROUND_TASKS=false \u2014 staying idle");
48042
+ log112.info("prediction-scheduler: BACKGROUND_TASKS=false \u2014 staying idle");
47899
48043
  return () => {
47900
48044
  };
47901
48045
  }
47902
48046
  if (running2) {
47903
- log111.warn("Prediction scheduler already running");
48047
+ log112.warn("Prediction scheduler already running");
47904
48048
  return () => stopPredictionScheduler();
47905
48049
  }
47906
48050
  running2 = true;
47907
48051
  onShutdown("prediction-scheduler", () => stopPredictionScheduler(), "timers");
47908
48052
  const activeSlots = config3.slots.filter((s) => s.enabled);
47909
48053
  if (activeSlots.length === 0) {
47910
- log111.debug("No active schedule slots configured");
48054
+ log112.debug("No active schedule slots configured");
47911
48055
  return () => {
47912
48056
  };
47913
48057
  }
@@ -47917,7 +48061,7 @@ function startPredictionScheduler(config3) {
47917
48061
  const firingSlots = activeSlots.filter(
47918
48062
  (s) => Array.isArray(s.firingTimesUtc) && s.firingTimesUtc.length > 0
47919
48063
  );
47920
- log111.info(
48064
+ log112.info(
47921
48065
  `Starting prediction scheduler with ${activeSlots.length} slot(s): ` + [
47922
48066
  ...intervalSlots.map((s) => `${s.name}(${s.intervalMinutes ?? "?"}m)`),
47923
48067
  ...firingSlots.map((s) => `${s.name}(utc=${(s.firingTimesUtc ?? []).join(",")})`)
@@ -47926,14 +48070,16 @@ function startPredictionScheduler(config3) {
47926
48070
  for (const slot of intervalSlots) {
47927
48071
  const minutes = slot.intervalMinutes;
47928
48072
  if (!minutes || minutes <= 0) {
47929
- log111.warn(`Slot "${slot.name}" has no intervalMinutes or firingTimesUtc \u2014 skipping`);
48073
+ log112.warn(`Slot "${slot.name}" has no intervalMinutes or firingTimesUtc \u2014 skipping`);
47930
48074
  continue;
47931
48075
  }
47932
48076
  const intervalMs = minutes * 6e4;
47933
48077
  const initialDelay = setTimeout(() => {
47934
48078
  if (!running2) return;
48079
+ applySchedulerStateOverlay(config3);
48080
+ const liveSlot = config3.slots.find((s) => s.name === slot.name) ?? slot;
47935
48081
  void runPredictionSlot(
47936
- slot,
48082
+ liveSlot,
47937
48083
  config3.defaultSymbols,
47938
48084
  config3.resolveBeforePredict,
47939
48085
  config3.maxConcurrent
@@ -47941,8 +48087,10 @@ function startPredictionScheduler(config3) {
47941
48087
  }, 15e3);
47942
48088
  const interval = setInterval(() => {
47943
48089
  if (!running2) return;
48090
+ applySchedulerStateOverlay(config3);
48091
+ const liveSlot = config3.slots.find((s) => s.name === slot.name) ?? slot;
47944
48092
  void runPredictionSlot(
47945
- slot,
48093
+ liveSlot,
47946
48094
  config3.defaultSymbols,
47947
48095
  config3.resolveBeforePredict,
47948
48096
  config3.maxConcurrent
@@ -47956,17 +48104,19 @@ function startPredictionScheduler(config3) {
47956
48104
  const heartbeat = setInterval(() => {
47957
48105
  if (!running2) return;
47958
48106
  if (!tryAcquireBackgroundLeader()) return;
48107
+ applySchedulerStateOverlay(config3);
47959
48108
  const now = /* @__PURE__ */ new Date();
47960
48109
  const hhmm = getCurrentUtcHhmm(now);
47961
48110
  const minuteEpoch = Math.floor(now.getTime() / 6e4);
47962
48111
  for (const slot of firingSlots) {
47963
- if (!slot.firingTimesUtc?.includes(hhmm)) continue;
47964
- const key = `${slot.name}:${minuteEpoch}`;
48112
+ const liveSlot = config3.slots.find((s) => s.name === slot.name) ?? slot;
48113
+ if (!liveSlot.firingTimesUtc?.includes(hhmm)) continue;
48114
+ const key = `${liveSlot.name}:${minuteEpoch}`;
47965
48115
  if (firedThisMinute.has(key)) continue;
47966
48116
  firedThisMinute.set(key, minuteEpoch);
47967
- log111.info(`[${slot.name}] Firing at ${hhmm} UTC (premarket window)`);
48117
+ log112.info(`[${liveSlot.name}] Firing at ${hhmm} UTC (premarket window)`);
47968
48118
  void runPredictionSlot(
47969
- slot,
48119
+ liveSlot,
47970
48120
  config3.defaultSymbols,
47971
48121
  config3.resolveBeforePredict,
47972
48122
  config3.maxConcurrent
@@ -47990,7 +48140,7 @@ function stopPredictionScheduler() {
47990
48140
  clearTimeout(timer5);
47991
48141
  }
47992
48142
  timers.length = 0;
47993
- log111.info("Prediction scheduler stopped");
48143
+ log112.info("Prediction scheduler stopped");
47994
48144
  }
47995
48145
  async function triggerPredictionCycle(config3, slotName) {
47996
48146
  const slots = slotName ? config3.slots.filter((s) => s.name === slotName && s.enabled) : config3.slots.filter((s) => s.enabled);
@@ -48003,7 +48153,7 @@ async function triggerPredictionCycle(config3, slotName) {
48003
48153
  );
48004
48154
  }
48005
48155
  }
48006
- var log111, DEFAULT_PREDICTION_SCHEDULER, timers, running2;
48156
+ var log112, DEFAULT_PREDICTION_SCHEDULER, timers, running2;
48007
48157
  var init_prediction_scheduler = __esm({
48008
48158
  "src/notifications/bridges/prediction-scheduler.ts"() {
48009
48159
  "use strict";
@@ -48012,7 +48162,8 @@ var init_prediction_scheduler = __esm({
48012
48162
  init_leader_lock();
48013
48163
  init_engine_config();
48014
48164
  init_graceful_shutdown();
48015
- log111 = createLogger("prediction-scheduler");
48165
+ init_scheduler_state();
48166
+ log112 = createLogger("prediction-scheduler");
48016
48167
  DEFAULT_PREDICTION_SCHEDULER = {
48017
48168
  enabled: false,
48018
48169
  defaultSymbols: [],
@@ -48076,21 +48227,21 @@ var engine_exports2 = {};
48076
48227
  __export(engine_exports2, {
48077
48228
  BacktestEngine: () => BacktestEngine
48078
48229
  });
48079
- var log112, BacktestEngine;
48230
+ var log113, BacktestEngine;
48080
48231
  var init_engine3 = __esm({
48081
48232
  "src/core/backtest/engine.ts"() {
48082
48233
  "use strict";
48083
48234
  init_binance();
48084
48235
  init_manager();
48085
48236
  init_logger();
48086
- log112 = createLogger("backtest");
48237
+ log113 = createLogger("backtest");
48087
48238
  BacktestEngine = class {
48088
48239
  config;
48089
48240
  constructor(config3) {
48090
48241
  this.config = config3;
48091
48242
  }
48092
48243
  async run() {
48093
- log112.info(
48244
+ log113.info(
48094
48245
  `Backtest: ${this.config.strategy} on ${this.config.pair} (${this.config.from} \u2192 ${this.config.to})`
48095
48246
  );
48096
48247
  const strategy = getStrategy(this.config.strategy);
@@ -48471,7 +48622,7 @@ async function fetchDexScreener(path2) {
48471
48622
  function resolveChain(chain) {
48472
48623
  return CHAIN_MAP3[chain.toLowerCase()] ?? chain.toLowerCase();
48473
48624
  }
48474
- function ensureTable6() {
48625
+ function ensureTable7() {
48475
48626
  if (tableInitialized6) return;
48476
48627
  const db2 = getDb();
48477
48628
  db2.exec(`
@@ -48495,13 +48646,13 @@ function ensureTable6() {
48495
48646
  `);
48496
48647
  tableInitialized6 = true;
48497
48648
  }
48498
- var log113, DEXSCREENER_BASE, CHAIN_MAP3, tableInitialized6, DexPairTracker;
48649
+ var log114, DEXSCREENER_BASE, CHAIN_MAP3, tableInitialized6, DexPairTracker;
48499
48650
  var init_dex_pair_tracker = __esm({
48500
48651
  "src/data/sources/dex-pair-tracker.ts"() {
48501
48652
  "use strict";
48502
48653
  init_logger();
48503
48654
  init_cache();
48504
- log113 = createLogger("dex-pair-tracker");
48655
+ log114 = createLogger("dex-pair-tracker");
48505
48656
  DEXSCREENER_BASE = "https://api.dexscreener.com";
48506
48657
  CHAIN_MAP3 = {
48507
48658
  ethereum: "ethereum",
@@ -48516,7 +48667,7 @@ var init_dex_pair_tracker = __esm({
48516
48667
  tableInitialized6 = false;
48517
48668
  DexPairTracker = class {
48518
48669
  constructor() {
48519
- ensureTable6();
48670
+ ensureTable7();
48520
48671
  }
48521
48672
  /**
48522
48673
  * Detect new pairs on a specific chain within the given time window.
@@ -48541,10 +48692,10 @@ var init_dex_pair_tracker = __esm({
48541
48692
  for (const pair of newPairs) {
48542
48693
  this.cachePair(pair);
48543
48694
  }
48544
- log113.info(`Detected ${newPairs.length} new pairs on ${resolvedChain} in last ${sinceMins}min`);
48695
+ log114.info(`Detected ${newPairs.length} new pairs on ${resolvedChain} in last ${sinceMins}min`);
48545
48696
  return newPairs;
48546
48697
  } catch (err) {
48547
- log113.error(
48698
+ log114.error(
48548
48699
  `Failed to detect new pairs on ${resolvedChain}: ${err instanceof Error ? err.message : String(err)}`
48549
48700
  );
48550
48701
  return [];
@@ -48578,7 +48729,7 @@ var init_dex_pair_tracker = __esm({
48578
48729
  timestamp: Date.now()
48579
48730
  };
48580
48731
  } catch (err) {
48581
- log113.error(
48732
+ log114.error(
48582
48733
  `Failed to track pair ${pairAddress}: ${err instanceof Error ? err.message : String(err)}`
48583
48734
  );
48584
48735
  return {
@@ -48651,7 +48802,7 @@ var init_dex_pair_tracker = __esm({
48651
48802
  pair.createdAt
48652
48803
  );
48653
48804
  } catch (err) {
48654
- log113.debug(
48805
+ log114.debug(
48655
48806
  `Failed to cache pair ${pair.pairAddress}: ${err instanceof Error ? err.message : String(err)}`
48656
48807
  );
48657
48808
  }
@@ -48881,7 +49032,7 @@ async function computeCorrelationMatrix(symbols, interval = "4h", limit = 100) {
48881
49032
  const closes2 = result.value.map((k) => k.close);
48882
49033
  returnsBySymbol[symbols[i]] = logReturns4(closes2);
48883
49034
  } else {
48884
- log114.debug(`Kline fetch failed for ${symbols[i]}`);
49035
+ log115.debug(`Kline fetch failed for ${symbols[i]}`);
48885
49036
  }
48886
49037
  }
48887
49038
  const validSymbols = Object.keys(returnsBySymbol);
@@ -48909,13 +49060,13 @@ async function computeCorrelationMatrix(symbols, interval = "4h", limit = 100) {
48909
49060
  strongNegative: sorted.filter((p) => p.correlation < cfg.strongNegativeThreshold).slice(0, 5)
48910
49061
  };
48911
49062
  }
48912
- var log114;
49063
+ var log115;
48913
49064
  var init_correlation = __esm({
48914
49065
  "src/data/sources/correlation.ts"() {
48915
49066
  "use strict";
48916
49067
  init_engine_config();
48917
49068
  init_logger();
48918
- log114 = createLogger("correlation");
49069
+ log115 = createLogger("correlation");
48919
49070
  }
48920
49071
  });
48921
49072
 
@@ -49008,7 +49159,7 @@ function persistSkippedTrackingNotification(symbol, trackingSummary) {
49008
49159
  createdAt: Date.now()
49009
49160
  });
49010
49161
  } catch (err) {
49011
- log115.debug(
49162
+ log116.debug(
49012
49163
  `persistSkippedTrackingNotification failed for ${symbol}: ${err instanceof Error ? err.message : String(err)}`
49013
49164
  );
49014
49165
  }
@@ -49091,7 +49242,7 @@ async function handleToolUnsafe(name, input, userId) {
49091
49242
  _meta: buildMeta(metaSources)
49092
49243
  };
49093
49244
  } catch (err) {
49094
- log115.debug(
49245
+ log116.debug(
49095
49246
  `get_market_data Binance fetch failed for ${symbol}, falling back to CoinGecko: ${err instanceof Error ? err.message : String(err)}`
49096
49247
  );
49097
49248
  const data = await fetchMarketData(symbol);
@@ -49609,7 +49760,7 @@ async function handleToolUnsafe(name, input, userId) {
49609
49760
  };
49610
49761
  }
49611
49762
  } catch (err) {
49612
- log115.debug(
49763
+ log116.debug(
49613
49764
  `get_prediction ChronoVisor engine failed for ${symbol}, using legacy predictor: ${err instanceof Error ? err.message : String(err)}`
49614
49765
  );
49615
49766
  }
@@ -49626,7 +49777,7 @@ async function handleToolUnsafe(name, input, userId) {
49626
49777
  const ticker = await fetchAggregatedPrice(symbol);
49627
49778
  initialPrice = ticker.price;
49628
49779
  } catch (err) {
49629
- log115.debug(
49780
+ log116.debug(
49630
49781
  `get_prediction legacy price fetch failed for ${symbol}: ${err instanceof Error ? err.message : String(err)}`
49631
49782
  );
49632
49783
  }
@@ -49656,7 +49807,7 @@ async function handleToolUnsafe(name, input, userId) {
49656
49807
  });
49657
49808
  }
49658
49809
  } catch (err) {
49659
- log115.debug(
49810
+ log116.debug(
49660
49811
  `get_prediction legacy accuracy tracking failed for ${symbol}: ${err instanceof Error ? err.message : String(err)}`
49661
49812
  );
49662
49813
  }
@@ -49683,7 +49834,7 @@ async function handleToolUnsafe(name, input, userId) {
49683
49834
  mlClient2 = initMLClient(cfg.ml.engineUrl);
49684
49835
  }
49685
49836
  } catch (err) {
49686
- log115.debug(
49837
+ log116.debug(
49687
49838
  `get_ml_prediction config load failed: ${err instanceof Error ? err.message : String(err)}`
49688
49839
  );
49689
49840
  }
@@ -49758,7 +49909,7 @@ async function handleToolUnsafe(name, input, userId) {
49758
49909
  try {
49759
49910
  goplus = await checkTokenSecurity(address, chain);
49760
49911
  } catch (err) {
49761
- log115.debug(
49912
+ log116.debug(
49762
49913
  `get_rug_ml_analysis GoPlus security check failed: ${err instanceof Error ? err.message : String(err)}`
49763
49914
  );
49764
49915
  }
@@ -49770,7 +49921,7 @@ async function handleToolUnsafe(name, input, userId) {
49770
49921
  mlClient2 = initMLClient(cfg.ml.engineUrl);
49771
49922
  }
49772
49923
  } catch (err) {
49773
- log115.debug(
49924
+ log116.debug(
49774
49925
  `get_rug_ml_analysis ML config load failed: ${err instanceof Error ? err.message : String(err)}`
49775
49926
  );
49776
49927
  }
@@ -49844,7 +49995,7 @@ async function handleToolUnsafe(name, input, userId) {
49844
49995
  mlClient2 = initMLClient(cfg.ml.engineUrl);
49845
49996
  }
49846
49997
  } catch (err) {
49847
- log115.debug(
49998
+ log116.debug(
49848
49999
  `analyze_news_sentiment ML config load failed: ${err instanceof Error ? err.message : String(err)}`
49849
50000
  );
49850
50001
  }
@@ -50017,7 +50168,7 @@ async function handleToolUnsafe(name, input, userId) {
50017
50168
  mlClient2 = initMLClient(cfg.ml.engineUrl);
50018
50169
  }
50019
50170
  } catch (err) {
50020
- log115.debug(
50171
+ log116.debug(
50021
50172
  `get_portfolio_forecast ML config load failed: ${err instanceof Error ? err.message : String(err)}`
50022
50173
  );
50023
50174
  }
@@ -50165,7 +50316,7 @@ async function handleToolUnsafe(name, input, userId) {
50165
50316
  try {
50166
50317
  balance = await getWalletBalance(agent.walletAddress);
50167
50318
  } catch (err) {
50168
- log115.debug(
50319
+ log116.debug(
50169
50320
  `get_agent_wallet balance fetch failed for ${agent.name}: ${err instanceof Error ? err.message : String(err)}`
50170
50321
  );
50171
50322
  balance = "0";
@@ -50317,7 +50468,7 @@ async function handleToolUnsafe(name, input, userId) {
50317
50468
  mlClient2 = initMLClient(cfg.ml.engineUrl);
50318
50469
  }
50319
50470
  } catch (err) {
50320
- log115.debug(
50471
+ log116.debug(
50321
50472
  `get_ml_model_health ML config load failed: ${err instanceof Error ? err.message : String(err)}`
50322
50473
  );
50323
50474
  }
@@ -50351,7 +50502,7 @@ async function handleToolUnsafe(name, input, userId) {
50351
50502
  mlClient2 = initMLClient(cfg.ml.engineUrl);
50352
50503
  }
50353
50504
  } catch (err) {
50354
- log115.debug(
50505
+ log116.debug(
50355
50506
  `classify_user_intent ML config load failed: ${err instanceof Error ? err.message : String(err)}`
50356
50507
  );
50357
50508
  }
@@ -50894,7 +51045,7 @@ async function handleToolUnsafe(name, input, userId) {
50894
51045
  const ticker = await fetchAggregatedPrice2(symbol);
50895
51046
  priceAtCreation = ticker.price;
50896
51047
  } catch (err) {
50897
- log115.debug(
51048
+ log116.debug(
50898
51049
  `set_price_alert price fetch failed for ${symbol}: ${err instanceof Error ? err.message : String(err)}`
50899
51050
  );
50900
51051
  }
@@ -50954,7 +51105,7 @@ async function handleToolUnsafe(name, input, userId) {
50954
51105
  const engine = getChronoVisor2();
50955
51106
  engineResult = await engine.predict(symbol, ["4h"], { userId });
50956
51107
  } catch (err) {
50957
- log115.debug(
51108
+ log116.debug(
50958
51109
  `set_price_alert ChronoVisor engine unavailable for ${symbol}: ${err instanceof Error ? err.message : String(err)}`
50959
51110
  );
50960
51111
  }
@@ -51064,7 +51215,7 @@ async function handleToolUnsafe(name, input, userId) {
51064
51215
  });
51065
51216
  }
51066
51217
  } catch (err) {
51067
- log115.debug(
51218
+ log116.debug(
51068
51219
  `set_price_alert prediction mirroring failed for ${symbol}: ${err instanceof Error ? err.message : String(err)}`
51069
51220
  );
51070
51221
  }
@@ -51639,7 +51790,7 @@ async function handleToolUnsafe(name, input, userId) {
51639
51790
  const signalKeys = Object.keys(breakdown);
51640
51791
  sigCount = signalKeys.filter((k) => breakdown[k].score !== 0).length;
51641
51792
  } catch (err) {
51642
- log115.debug(
51793
+ log116.debug(
51643
51794
  `get_position_sizing ChronoVisor meta-score fetch failed for ${symbol}: ${err instanceof Error ? err.message : String(err)}`
51644
51795
  );
51645
51796
  }
@@ -51965,7 +52116,7 @@ async function handleToolUnsafe(name, input, userId) {
51965
52116
  return { error: `Unknown tool: ${name}` };
51966
52117
  }
51967
52118
  }
51968
- var log115;
52119
+ var log116;
51969
52120
  var init_tool_handler = __esm({
51970
52121
  "src/ai/tool-handler.ts"() {
51971
52122
  "use strict";
@@ -51998,7 +52149,7 @@ var init_tool_handler = __esm({
51998
52149
  init_store();
51999
52150
  init_sanitize();
52000
52151
  init_logger();
52001
- log115 = createLogger("tool-handler");
52152
+ log116 = createLogger("tool-handler");
52002
52153
  }
52003
52154
  });
52004
52155
 
@@ -54707,7 +54858,7 @@ function instrumentAck(ctx) {
54707
54858
  try {
54708
54859
  return await original(...args2);
54709
54860
  } catch (err) {
54710
- log116.debug(`answerCallbackQuery failed: ${err instanceof Error ? err.message : String(err)}`);
54861
+ log117.debug(`answerCallbackQuery failed: ${err instanceof Error ? err.message : String(err)}`);
54711
54862
  return true;
54712
54863
  }
54713
54864
  });
@@ -54734,7 +54885,7 @@ function mountCallbackRouter(bot) {
54734
54885
  const key = `${userId}:${data}`;
54735
54886
  const existing = dedup.get(key);
54736
54887
  if (existing && (existing.inFlight || existing.until > now)) {
54737
- log116.debug(`Dedup'd callback "${data}" for user ${userId}`);
54888
+ log117.debug(`Dedup'd callback "${data}" for user ${userId}`);
54738
54889
  await ctx.answerCallbackQuery();
54739
54890
  return;
54740
54891
  }
@@ -54759,7 +54910,7 @@ function mountCallbackRouter(bot) {
54759
54910
  }
54760
54911
  } catch (err) {
54761
54912
  const msg = err instanceof Error ? err.message : String(err);
54762
- log116.warn(`Callback "${prefix}" failed: ${msg}`);
54913
+ log117.warn(`Callback "${prefix}" failed: ${msg}`);
54763
54914
  if (userId) {
54764
54915
  recordDebugLine(userId, `callback:${prefix} ERROR ${msg}`);
54765
54916
  }
@@ -54774,13 +54925,13 @@ function mountCallbackRouter(bot) {
54774
54925
  }
54775
54926
  });
54776
54927
  }
54777
- var log116, handlers, DEDUP_WINDOW_MS, EARLY_ACK_MS, dedup, mounted;
54928
+ var log117, handlers, DEDUP_WINDOW_MS, EARLY_ACK_MS, dedup, mounted;
54778
54929
  var init_callbacks = __esm({
54779
54930
  "src/telegram/callbacks.ts"() {
54780
54931
  "use strict";
54781
54932
  init_logger();
54782
54933
  init_debug_log();
54783
- log116 = createLogger("telegram:callbacks");
54934
+ log117 = createLogger("telegram:callbacks");
54784
54935
  handlers = /* @__PURE__ */ new Map();
54785
54936
  DEDUP_WINDOW_MS = 1500;
54786
54937
  EARLY_ACK_MS = 600;
@@ -55032,11 +55183,13 @@ async function deliverPredictions(ctx, symbolArg, filter, editPrevious) {
55032
55183
  await ctx.reply("Login required \u2014 send /start first.");
55033
55184
  return;
55034
55185
  }
55186
+ const isAdmin3 = ctx.state?.user?.role === "admin";
55035
55187
  const { getUserWatchlist: getUserWatchlist2 } = await Promise.resolve().then(() => (init_users(), users_exports));
55036
- const subscribedSymbols = getUserWatchlist2(userId).map((w) => w.symbol);
55188
+ const subscribedSymbols = isAdmin3 ? [] : getUserWatchlist2(userId).map((w) => w.symbol);
55037
55189
  const tracker = new AccuracyTracker();
55038
- const pending = tracker.getPendingPredictions(userId, subscribedSymbols);
55039
- const recentResolved = tracker.getAllRecentPredictions(100, userId, subscribedSymbols).filter((p) => p.wasCorrect !== null);
55190
+ const queryUserId = isAdmin3 ? void 0 : userId;
55191
+ const pending = tracker.getPendingPredictions(queryUserId, subscribedSymbols);
55192
+ const recentResolved = tracker.getAllRecentPredictions(100, queryUserId, subscribedSymbols).filter((p) => p.wasCorrect !== null);
55040
55193
  let rows;
55041
55194
  if (filter === "pending") rows = pending;
55042
55195
  else if (filter === "resolved") rows = recentResolved;
@@ -55240,22 +55393,24 @@ async function renderPrecisions(ctx, symbol, horizon, editPrevious) {
55240
55393
  await ctx.reply("Login required \u2014 send /start first.");
55241
55394
  return;
55242
55395
  }
55396
+ const isAdmin3 = ctx.state?.user?.role === "admin";
55243
55397
  const { getUserWatchlist: getUserWatchlist2 } = await Promise.resolve().then(() => (init_users(), users_exports));
55244
- const subscribedSymbols = getUserWatchlist2(userId).map((w) => w.symbol);
55398
+ const subscribedSymbols = isAdmin3 ? [] : getUserWatchlist2(userId).map((w) => w.symbol);
55399
+ const queryUserId = isAdmin3 ? void 0 : userId;
55245
55400
  const tracker = new AccuracyTracker();
55246
55401
  const trackedMetrics = tracker.getAccuracyMetrics(
55247
55402
  symbol,
55248
55403
  horizon,
55249
55404
  void 0,
55250
55405
  void 0,
55251
- userId,
55406
+ queryUserId,
55252
55407
  subscribedSymbols
55253
55408
  );
55254
55409
  const displayMetrics = tracker.getDisplayAccuracyMetrics(
55255
55410
  symbol,
55256
55411
  horizon,
55257
55412
  void 0,
55258
- userId,
55413
+ queryUserId,
55259
55414
  subscribedSymbols
55260
55415
  );
55261
55416
  const status = getPredictionControlStatus();
@@ -55328,7 +55483,7 @@ async function renderPrecisions(ctx, symbol, horizon, editPrevious) {
55328
55483
  )
55329
55484
  );
55330
55485
  }
55331
- const slotAccuracy = tracker.getAccuracyBySlot(userId, subscribedSymbols);
55486
+ const slotAccuracy = tracker.getAccuracyBySlot(queryUserId, subscribedSymbols);
55332
55487
  const slotRows = [];
55333
55488
  if (slotAccuracy.length > 0) {
55334
55489
  slotRows.push(section("\u{1F4C5}", "Per Scheduler"));
@@ -55447,7 +55602,7 @@ function trainLogisticRegression(rows, opts = {}) {
55447
55602
  const l2 = opts.l2 ?? 0.01;
55448
55603
  const holdoutFrac = opts.holdoutFrac ?? 0.2;
55449
55604
  if (rows.length < 30) {
55450
- log117.info(`trainLogisticRegression: only ${rows.length} rows, need \u226530 \u2014 skipping fit`);
55605
+ log118.info(`trainLogisticRegression: only ${rows.length} rows, need \u226530 \u2014 skipping fit`);
55451
55606
  return null;
55452
55607
  }
55453
55608
  const allFeatures = rows.map(extractFeatures2);
@@ -55505,7 +55660,7 @@ function trainLogisticRegression(rows, opts = {}) {
55505
55660
  if ((p >= 0.5 ? 1 : 0) === valY[i]) correct++;
55506
55661
  }
55507
55662
  const holdoutAccuracy = valX.length > 0 ? correct / valX.length : null;
55508
- log117.info(
55663
+ log118.info(
55509
55664
  `Trained logistic regression: n=${rows.length} (${trainX.length} train, ${valX.length} val) holdoutAcc=${holdoutAccuracy !== null ? (holdoutAccuracy * 100).toFixed(1) + "%" : "n/a"} bias=${bias.toFixed(3)}`
55510
55665
  );
55511
55666
  return {
@@ -55539,9 +55694,9 @@ async function persistModel(state) {
55539
55694
  try {
55540
55695
  await fs.mkdir(path.dirname(target), { recursive: true });
55541
55696
  await fs.writeFile(target, JSON.stringify(state, null, 2));
55542
- log117.info(`Persisted trained model to ${target}`);
55697
+ log118.info(`Persisted trained model to ${target}`);
55543
55698
  } catch (err) {
55544
- log117.warn(`Failed to persist model: ${err instanceof Error ? err.message : String(err)}`);
55699
+ log118.warn(`Failed to persist model: ${err instanceof Error ? err.message : String(err)}`);
55545
55700
  }
55546
55701
  }
55547
55702
  async function loadPersistedModel() {
@@ -55550,7 +55705,7 @@ async function loadPersistedModel() {
55550
55705
  const raw = await fs.readFile(target, "utf-8");
55551
55706
  const parsed = JSON.parse(raw);
55552
55707
  if (parsed.version !== 1) {
55553
- log117.info(`Persisted model version ${parsed.version} != 1, ignoring`);
55708
+ log118.info(`Persisted model version ${parsed.version} != 1, ignoring`);
55554
55709
  return null;
55555
55710
  }
55556
55711
  return parsed;
@@ -55564,12 +55719,12 @@ function getCachedModel() {
55564
55719
  function setCachedModel(state) {
55565
55720
  cachedModel = state;
55566
55721
  }
55567
- var log117, SIGNAL_NAMES, cachedModel;
55722
+ var log118, SIGNAL_NAMES, cachedModel;
55568
55723
  var init_trainer = __esm({
55569
55724
  "src/ml/native/trainer.ts"() {
55570
55725
  "use strict";
55571
55726
  init_logger();
55572
- log117 = createLogger("ml:native:trainer");
55727
+ log118 = createLogger("ml:native:trainer");
55573
55728
  SIGNAL_NAMES = [
55574
55729
  "onChain",
55575
55730
  "mlEnsemble",
@@ -56266,124 +56421,6 @@ var init_chronovisor = __esm({
56266
56421
  }
56267
56422
  });
56268
56423
 
56269
- // src/notifications/scheduler-state.ts
56270
- var scheduler_state_exports = {};
56271
- __export(scheduler_state_exports, {
56272
- applySchedulerStateOverlay: () => applySchedulerStateOverlay,
56273
- isSchedulerRunningPersisted: () => isSchedulerRunningPersisted,
56274
- persistDefaultSymbols: () => persistDefaultSymbols,
56275
- persistSchedulerRunning: () => persistSchedulerRunning,
56276
- persistSlotEnabled: () => persistSlotEnabled,
56277
- persistSlotFiringTimesUtc: () => persistSlotFiringTimesUtc,
56278
- persistSlotHorizons: () => persistSlotHorizons,
56279
- persistSlotInterval: () => persistSlotInterval,
56280
- persistSlotSymbols: () => persistSlotSymbols
56281
- });
56282
- function ensureTable7() {
56283
- getDb().exec(`
56284
- CREATE TABLE IF NOT EXISTS scheduler_state (
56285
- key TEXT PRIMARY KEY,
56286
- value TEXT NOT NULL,
56287
- updated_at INTEGER NOT NULL
56288
- )
56289
- `);
56290
- }
56291
- function setKey(key, value) {
56292
- ensureTable7();
56293
- getDb().prepare(
56294
- `INSERT INTO scheduler_state (key, value, updated_at) VALUES (?, ?, ?)
56295
- ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`
56296
- ).run(key, JSON.stringify(value), Date.now());
56297
- }
56298
- function getKey(key) {
56299
- ensureTable7();
56300
- const row2 = getDb().prepare(`SELECT value FROM scheduler_state WHERE key = ?`).get(key);
56301
- if (!row2) return null;
56302
- try {
56303
- return JSON.parse(row2.value);
56304
- } catch {
56305
- return null;
56306
- }
56307
- }
56308
- function persistDefaultSymbols(symbols) {
56309
- setKey("defaultSymbols", symbols);
56310
- }
56311
- function persistSchedulerRunning(running6) {
56312
- setKey("running", running6);
56313
- }
56314
- function isSchedulerRunningPersisted() {
56315
- return getKey("running");
56316
- }
56317
- function persistSlotEnabled(slotName, enabled) {
56318
- const current = getKey("slotsEnabled") ?? {};
56319
- current[slotName] = enabled;
56320
- setKey("slotsEnabled", current);
56321
- }
56322
- function persistSlotSymbols(slotName, symbols) {
56323
- const current = getKey("slotSymbols") ?? {};
56324
- current[slotName] = symbols;
56325
- setKey("slotSymbols", current);
56326
- }
56327
- function persistSlotHorizons(slotName, horizons) {
56328
- const current = getKey("slotHorizons") ?? {};
56329
- current[slotName] = horizons;
56330
- setKey("slotHorizons", current);
56331
- }
56332
- function persistSlotInterval(slotName, intervalMinutes) {
56333
- const current = getKey("slotIntervals") ?? {};
56334
- current[slotName] = intervalMinutes;
56335
- setKey("slotIntervals", current);
56336
- }
56337
- function persistSlotFiringTimesUtc(slotName, firingTimesUtc) {
56338
- const current = getKey("slotFiringTimesUtc") ?? {};
56339
- current[slotName] = firingTimesUtc === void 0 ? null : firingTimesUtc;
56340
- setKey("slotFiringTimesUtc", current);
56341
- }
56342
- function applySchedulerStateOverlay(cfg) {
56343
- try {
56344
- const defaultSymbols = getKey("defaultSymbols");
56345
- if (Array.isArray(defaultSymbols)) {
56346
- cfg.defaultSymbols = defaultSymbols;
56347
- }
56348
- const slotsEnabled = getKey("slotsEnabled") ?? {};
56349
- const slotSymbols = getKey("slotSymbols") ?? {};
56350
- const slotHorizons = getKey("slotHorizons") ?? {};
56351
- const slotIntervals = getKey("slotIntervals") ?? {};
56352
- const slotFiringTimesUtc = getKey("slotFiringTimesUtc") ?? {};
56353
- cfg.slots = cfg.slots.map((slot) => {
56354
- const next = { ...slot };
56355
- if (slotsEnabled[slot.name] !== void 0) next.enabled = slotsEnabled[slot.name];
56356
- if (slotSymbols[slot.name] !== void 0) next.symbols = slotSymbols[slot.name];
56357
- if (slotHorizons[slot.name] !== void 0) next.horizons = slotHorizons[slot.name];
56358
- if (slotIntervals[slot.name] !== void 0) next.intervalMinutes = slotIntervals[slot.name];
56359
- if (slotFiringTimesUtc[slot.name] !== void 0) {
56360
- const v = slotFiringTimesUtc[slot.name];
56361
- if (v === null) {
56362
- delete next.firingTimesUtc;
56363
- } else {
56364
- next.firingTimesUtc = v;
56365
- }
56366
- }
56367
- return next;
56368
- });
56369
- return cfg;
56370
- } catch (err) {
56371
- log118.debug(
56372
- `applySchedulerStateOverlay failed: ${err instanceof Error ? err.message : String(err)}`
56373
- );
56374
- return cfg;
56375
- }
56376
- }
56377
- var log118;
56378
- var init_scheduler_state = __esm({
56379
- "src/notifications/scheduler-state.ts"() {
56380
- "use strict";
56381
- init_cache();
56382
- init_logger();
56383
- log118 = createLogger("notifications:scheduler-state");
56384
- }
56385
- });
56386
-
56387
56424
  // src/telegram/commands/scheduler.ts
56388
56425
  var scheduler_exports = {};
56389
56426
  __export(scheduler_exports, {
@@ -56462,6 +56499,9 @@ async function handleScheduler(ctx) {
56462
56499
  await doToggleSlot(ctx, schedCfg, args2[1], sub === "enable");
56463
56500
  return;
56464
56501
  case "symbols":
56502
+ case "defaults":
56503
+ case "default-symbols":
56504
+ case "defaultsymbols":
56465
56505
  await doSetSymbols(ctx, schedCfg, args2.slice(1).join(" "));
56466
56506
  return;
56467
56507
  case "interval":
@@ -56501,7 +56541,9 @@ async function handleScheduler(ctx) {
56501
56541
  }
56502
56542
  async function renderStatus3(ctx, schedCfg) {
56503
56543
  if (!schedCfg) return;
56504
- const running6 = isPredictionSchedulerRunning();
56544
+ const persisted = isSchedulerRunningPersisted();
56545
+ const running6 = persisted ?? isPredictionSchedulerRunning();
56546
+ applySchedulerStateOverlay(schedCfg);
56505
56547
  const slots = schedCfg.slots ?? [];
56506
56548
  const defaultCount = schedCfg.defaultSymbols.length;
56507
56549
  const slotLines = slots.map((s) => {
@@ -56564,7 +56606,7 @@ function helpText() {
56564
56606
  "*Edit \\(admin\\)*",
56565
56607
  "`/scheduler enable <slot>`",
56566
56608
  "`/scheduler disable <slot>`",
56567
- "`/scheduler symbols BTC,ETH,SOL`",
56609
+ "`/scheduler symbols BTC,ETH,SOL` \u2014 replace default symbols \\(alias: `defaults`\\)",
56568
56610
  "`/scheduler interval <slot> <minutes>`",
56569
56611
  "`/scheduler firing <slot> 08:30,09:00` \u2014 fixed UTC firing times",
56570
56612
  "`/scheduler firing <slot> clear` \u2014 back to interval cadence",
@@ -57807,15 +57849,17 @@ async function renderWr(ctx, symbol) {
57807
57849
  await ctx.reply("Login required \u2014 send /start first.");
57808
57850
  return;
57809
57851
  }
57852
+ const isAdmin3 = ctx.state?.user?.role === "admin";
57810
57853
  const { getUserWatchlist: getUserWatchlist2 } = await Promise.resolve().then(() => (init_users(), users_exports));
57811
- const subscribedSymbols = getUserWatchlist2(userId).map((w) => w.symbol);
57854
+ const subscribedSymbols = isAdmin3 ? [] : getUserWatchlist2(userId).map((w) => w.symbol);
57855
+ const queryUserId = isAdmin3 ? void 0 : userId;
57812
57856
  const tracker = new AccuracyTracker();
57813
57857
  const tracked = tracker.getAccuracyMetrics(
57814
57858
  symbol,
57815
57859
  void 0,
57816
57860
  void 0,
57817
57861
  { excludeWarmup: true },
57818
- userId,
57862
+ queryUserId,
57819
57863
  subscribedSymbols
57820
57864
  );
57821
57865
  const trackedIncl = tracker.getAccuracyMetrics(
@@ -57823,14 +57867,14 @@ async function renderWr(ctx, symbol) {
57823
57867
  void 0,
57824
57868
  void 0,
57825
57869
  void 0,
57826
- userId,
57870
+ queryUserId,
57827
57871
  subscribedSymbols
57828
57872
  );
57829
57873
  const display = tracker.getDisplayAccuracyMetrics(
57830
57874
  symbol,
57831
57875
  void 0,
57832
57876
  void 0,
57833
- userId,
57877
+ queryUserId,
57834
57878
  subscribedSymbols
57835
57879
  );
57836
57880
  const warmup = tracker.getWarmupStats(symbol);