dankgrinder 8.85.0 → 8.87.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 (2) hide show
  1. package/lib/ui.js +39 -23
  2. package/package.json +1 -1
package/lib/ui.js CHANGED
@@ -7,6 +7,7 @@ let _version = '0.0.0';
7
7
  let _live = false;
8
8
  let _startTime = Date.now();
9
9
  let _events = [];
10
+ let _coinHistory = new Array(10).fill(0);
10
11
  const MAX_EVENTS = 5;
11
12
  let _refreshTimer = null;
12
13
 
@@ -49,6 +50,18 @@ const STATUS_DOT = {
49
50
  connect: { dot: '◯', color: chalk.hex('#ffb450') }
50
51
  };
51
52
 
53
+
54
+ function getSparkline() {
55
+ const min = Math.min(..._coinHistory);
56
+ const max = Math.max(..._coinHistory);
57
+ if (min === max) return chalk.dim('⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤');
58
+ const sparks = [' ', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
59
+ return _coinHistory.map(v => {
60
+ const idx = Math.floor(((v - min) / (max - min)) * 7);
61
+ return chalk.green(sparks[idx]);
62
+ }).join('');
63
+ }
64
+
52
65
  function init({ workers }) { _workers = workers; _startTime = Date.now(); _events = []; _live = false; }
53
66
 
54
67
  function drawBanner(version) {
@@ -119,24 +132,20 @@ function render() {
119
132
  if (!_live) return;
120
133
  const C = process.stdout.columns || 110;
121
134
 
122
- // Clear screen to prevent duplication on resize
123
- let out = '\x1b[2J\x1b[H';
135
+ let out = '';
124
136
 
125
137
  // Banner
126
138
  const titleStr = figlet.textSync('DANK GRINDER', { font: 'ANSI Shadow' });
127
139
  out += chalk.bold(applyGradient(titleStr));
128
- out += chalk.bold.magenta(` v${_version} — ${getLoader()} Running... \n`);
140
+ out += chalk.bold.magenta(` v${_version} — ${getLoader()} Running... \n\n`);
129
141
 
130
- const wCols = { num: 4, name: 18, bal: 14, ls: 5, lv: 5 };
142
+ const wCols = { num: 4, name: 18, bal: 14, ls: 6, lv: 5 };
131
143
  const overhead = 19 + wCols.num + wCols.name + wCols.bal + wCols.ls + wCols.lv;
132
144
  const logW = Math.max(10, C - overhead);
133
145
  const actualC = logW + overhead;
134
146
 
135
147
  const sorted = [..._workers].sort((a, b) => {
136
148
  if (!a.channel !== !b.channel) return a.channel ? -1 : 1;
137
- const aA = a.channel && !a.paused && !a.dashboardPaused;
138
- const bB = b.channel && !b.paused && !b.dashboardPaused;
139
- if (aA !== bB) return aA ? -1 : 1;
140
149
  return (b.stats.commands || 0) - (a.stats.commands || 0);
141
150
  });
142
151
 
@@ -148,15 +157,23 @@ function render() {
148
157
  if (w.channel && !w.paused && !w.dashboardPaused) onlineCount++;
149
158
  }
150
159
 
151
- // High-Visibility Summary directly below the Title
160
+ // BIG STATS DASHBOARD
152
161
  const totC = totalCoins > 0 ? '+' + formatBal(totalCoins) : '+0';
153
- const summStr = chalk.bold(' 🌟 ACT: ') + chalk.bold.magenta(_workers.length) + chalk.dim(' │ ') +
154
- chalk.bold('⚡ ON: ') + chalk.bold.cyan(onlineCount) + chalk.dim(' │ ') +
155
- chalk.bold('💰 BAL: ') + chalk.bold.green('⏣' + formatBal(totalBal)) + chalk.dim(' │ ') +
156
- chalk.bold('📈 GAINED: ') + chalk.bold.yellow(totC) + chalk.dim(' │ ') +
157
- chalk.bold('⏱ UP: ') + chalk.bold.dim(fmtUptime());
158
162
 
159
- out += '\n' + summStr + '\n\n';
163
+ out += chalk.cyan('' + '─'.repeat(actualC - 2) + '╮\n');
164
+ out += chalk.cyan('│') + ' ' + chalk.bold('ACCOUNTS: ') + String(_workers.length).padEnd(5) +
165
+ chalk.bold('ONLINE: ') + String(onlineCount).padEnd(5) +
166
+ chalk.bold('UPTIME: ') + fmtUptime().padEnd(10) + ' '.repeat(Math.max(0, actualC - 48)) + chalk.cyan('│\n');
167
+
168
+ const balStr = '⏣ ' + formatBal(totalBal);
169
+ const balPadding = Math.max(0, 16 - balStr.length);
170
+ const profStr = totC;
171
+ const graph = getSparkline();
172
+
173
+ out += chalk.cyan('│') + ' ' + chalk.bold.green('BALANCE: ') + chalk.bold.greenBright(balStr) + ' '.repeat(balPadding) +
174
+ chalk.bold.yellow('PROFIT: ') + chalk.bold.yellowBright(profStr).padEnd(12) +
175
+ chalk.dim('TREND: [') + graph + chalk.dim(']') + ' '.repeat(Math.max(0, actualC - 70)) + chalk.cyan('│\n');
176
+ out += chalk.cyan('╰' + '─'.repeat(actualC - 2) + '╯\n');
160
177
 
161
178
  // Accounts Table
162
179
  out += '╭' + '─'.repeat(wCols.num + 2) + '┬'
@@ -199,25 +216,23 @@ function render() {
199
216
  const numStr = trunc(String(i + 1), wCols.num);
200
217
  const dot = getDot(w);
201
218
 
202
- // Support previous UI events format dynamically extracting name
203
219
  const nameRaw = trunc(w.username || 'Worker ' + (i+1), wCols.name - 2);
204
220
  const nameStr = dot.color(dot.dot) + ' ' + getAccountColor(nameRaw)(chalk.bold(nameRaw));
205
221
 
206
- // Balance Formatter
207
222
  const bVal = w.stats.balance !== undefined ? formatBal(w.stats.balance) : '—';
208
223
  const balRaw = trunc(bVal === '—' ? '—' : '⏣' + bVal, wCols.bal);
209
224
  const balStr = balRaw === '—' ? chalk.dim('—') : chalk.bold.green(balRaw);
210
225
 
211
- // Heart Lifesavers
226
+ // Exact unicode block character, NOT an emoji
212
227
  let lsRaw = '—';
213
228
  let lsStr = chalk.dim('—');
214
229
  if (w._lifesavers !== undefined) {
215
230
  let lsCount = w._lifesavers;
216
- let lsEmoji = '❤️'; // Red for 0-2
231
+ let lsEmoji = ''; // Solid code block character!
217
232
  let lsColor = chalk.bold.red;
218
233
 
219
- if (lsCount >= 5) { lsEmoji = '💚'; lsColor = chalk.bold.green; }
220
- else if (lsCount >= 3) { lsEmoji = '💛'; lsColor = chalk.bold.yellow; }
234
+ if (lsCount >= 5) { lsColor = chalk.bold.green; }
235
+ else if (lsCount >= 3) { lsColor = chalk.bold.yellow; }
221
236
 
222
237
  lsRaw = trunc(`${lsEmoji} ${lsCount}`, wCols.ls);
223
238
  lsStr = lsColor(lsRaw);
@@ -243,19 +258,20 @@ function render() {
243
258
  + '─'.repeat(wCols.lv + 2) + '┴'
244
259
  + '─'.repeat(logW + 2) + '╯\n\n';
245
260
 
246
- // Latest events beneath the table cleanly
247
261
  out += chalk.bold.cyan(' 📻 LATEST EVENTS') + '\n';
248
262
  if (_events.length === 0) out += chalk.dim(' Quiet here...\n');
249
263
  _events.forEach(ev => { out += ` ${chalk.dim(`[${ev.ts}]`)} ${ev.icon} ${ev.msg}\n`; });
250
264
 
251
- require("log-update")(out);
265
+ // Fixing the blank space spam by ensuring exactly no trailing newlines and NO raw buffer resets
266
+ logUpdate(out.trimEnd());
252
267
  }
253
268
 
254
269
  function start() {}
255
270
  function draw() { render(); }
256
271
  function setLive(val) { _live = val; if (val) render(); }
257
272
  function setPhase(phase) {}
258
- function startRefresh() { if (!_refreshTimer) _refreshTimer = setInterval(() => { if (_live) render(); }, 80); }
273
+ function startRefresh() { setInterval(() => { if(_live){ const tot = _workers.reduce((a,w)=>a+(w.stats.coins||0),0); _coinHistory.shift(); _coinHistory.push(tot); } }, 5000);
274
+ if (!_refreshTimer) _refreshTimer = setInterval(() => { if (_live) render(); }, 80); }
259
275
  function stopRefresh() { if (_refreshTimer) { clearInterval(_refreshTimer); _refreshTimer = null; } }
260
276
  function stop() { _live = false; stopRefresh(); logUpdate.clear(); }
261
277
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dankgrinder",
3
- "version": "8.85.0",
3
+ "version": "8.87.0",
4
4
  "description": "Dank Memer automation engine — grind coins while you sleep",
5
5
  "bin": {
6
6
  "dankgrinder": "bin/dankgrinder.js"