dankgrinder 8.83.0 → 8.84.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 +70 -42
  2. package/package.json +1 -1
package/lib/ui.js CHANGED
@@ -31,7 +31,7 @@ function applyGradient(str) {
31
31
  const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
32
32
  function getSpinner() { return SPINNER_FRAMES[Math.floor(Date.now() / 80) % SPINNER_FRAMES.length]; }
33
33
 
34
- const LOAD_FRAMES = ['[= ]', '[== ]', '[=== ]', '[ ===]', '[ ==]', '[ =]', '[ ==]', '[ ===]', '[=== ]', '[== ]'];
34
+ const LOAD_FRAMES = ['','','','','','','',''];
35
35
  function getLoader() { return LOAD_FRAMES[Math.floor(Date.now() / 150) % LOAD_FRAMES.length]; }
36
36
 
37
37
  const ACC_COLORS = ['#ff0054', '#ffbd00', '#390099', '#9e0059', '#ff5400', '#00f5d4', '#00bbf9', '#fee440', '#f15bb5', '#9b5de5'];
@@ -107,24 +107,58 @@ function makeRow(c1, c2, c3, c4, c5, c6, wCols, logW) {
107
107
  return `│ ${pad(c1, wCols.num)} │ ${pad(c2, wCols.name)} │ ${pad(c3, wCols.bal)} │ ${pad(c4, wCols.ls)} │ ${pad(c5, wCols.lv)} │ ${pad(c6, logW)} │`;
108
108
  }
109
109
 
110
+ function formatBal(n) {
111
+ if (n === undefined || isNaN(n)) return '—';
112
+ if (n >= 1e9) return (n / 1e9).toFixed(2) + 'B';
113
+ if (n >= 1e6) return (n / 1e6).toFixed(2) + 'M';
114
+ if (n >= 1e3) return (n / 1e3).toFixed(1) + 'k';
115
+ return String(n);
116
+ }
117
+
110
118
  function render() {
111
119
  if (!_live) return;
112
120
  const C = process.stdout.columns || 110;
113
-
114
- let out = '';
121
+
122
+ // Clear screen to prevent duplication on resize
123
+ let out = '\x1b[2J\x1b[H';
124
+
115
125
  // Banner
116
126
  const titleStr = figlet.textSync('DANK GRINDER', { font: 'ANSI Shadow' });
117
127
  out += chalk.bold(applyGradient(titleStr));
118
- out += chalk.bold.magenta(`v${_version} — ${getLoader()} Running... `) + '\n\n';
128
+ out += chalk.bold.magenta(` v${_version} — ${getLoader()} Running... \n`);
119
129
 
120
130
  const wCols = { num: 4, name: 18, bal: 14, ls: 5, lv: 5 };
121
-
122
131
  const overhead = 19 + wCols.num + wCols.name + wCols.bal + wCols.ls + wCols.lv;
123
132
  const logW = Math.max(10, C - overhead);
124
133
  const actualC = logW + overhead;
125
134
 
126
- const summaryW = actualC - 4;
135
+ const sorted = [..._workers].sort((a, b) => {
136
+ 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
+ return (b.stats.commands || 0) - (a.stats.commands || 0);
141
+ });
142
+
143
+ let totalCoins = 0, totalBal = 0, onlineCount = 0;
144
+ for (let i = 0; i < sorted.length; i++) {
145
+ const w = sorted[i];
146
+ totalCoins += w.stats.coins || 0;
147
+ totalBal += w.stats.balance || 0;
148
+ if (w.channel && !w.paused && !w.dashboardPaused) onlineCount++;
149
+ }
150
+
151
+ // High-Visibility Summary directly below the Title
152
+ 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
+
159
+ out += '\n' + summStr + '\n\n';
127
160
 
161
+ // Accounts Table
128
162
  out += '╭' + '─'.repeat(wCols.num + 2) + '┬'
129
163
  + '─'.repeat(wCols.name + 2) + '┬'
130
164
  + '─'.repeat(wCols.bal + 2) + '┬'
@@ -145,26 +179,14 @@ function render() {
145
179
  + '─'.repeat(wCols.lv + 2) + '┼'
146
180
  + '─'.repeat(logW + 2) + '┤\n';
147
181
 
148
- const sorted = [..._workers].sort((a, b) => {
149
- if (!a.channel !== !b.channel) return a.channel ? -1 : 1;
150
- const aA = a.channel && !a.paused && !a.dashboardPaused;
151
- const bB = b.channel && !b.paused && !b.dashboardPaused;
152
- if (aA !== bB) return aA ? -1 : 1;
153
- return (b.stats.commands || 0) - (a.stats.commands || 0);
154
- });
155
-
156
- let totalCoins = 0, totalBal = 0, onlineCount = 0;
157
182
  for (let i = 0; i < sorted.length; i++) {
158
183
  const w = sorted[i];
159
- totalCoins += w.stats.coins || 0;
160
- totalBal += w.stats.balance || 0;
161
- if (w.channel && !w.paused && !w.dashboardPaused) onlineCount++;
162
184
 
163
185
  let logText = w.lastStatus || 'idle';
164
186
  let activity = '';
165
187
  if (w.globalCooldownUntil && Date.now() < w.globalCooldownUntil) {
166
188
  const s = Math.ceil((w.globalCooldownUntil - Date.now()) / 1000);
167
- logText = s > 60 ? `cooldown ${Math.ceil(s/60)}m` : `cd ${s}s`;
189
+ logText = s > 60 ? `cd ${Math.ceil(s/60)}m` : `cd ${s}s`;
168
190
  activity = chalk.yellow(getSpinner());
169
191
  } else if (w.paused || w.dashboardPaused) {
170
192
  logText = 'paused';
@@ -177,16 +199,29 @@ function render() {
177
199
  const numStr = trunc(String(i + 1), wCols.num);
178
200
  const dot = getDot(w);
179
201
 
180
- const nameRaw = trunc(w.username || '?', wCols.name - 2);
202
+ // Support previous UI events format dynamically extracting name
203
+ const nameRaw = trunc(w.username || 'Worker ' + (i+1), wCols.name - 2);
181
204
  const nameStr = dot.color(dot.dot) + ' ' + getAccountColor(nameRaw)(chalk.bold(nameRaw));
182
205
 
183
- let bVal = w.stats.balance !== undefined ? (w.stats.balance >= 1000 ? w.stats.balance.toLocaleString() : String(w.stats.balance)) : '—';
206
+ // Balance Formatter
207
+ const bVal = w.stats.balance !== undefined ? formatBal(w.stats.balance) : '—';
184
208
  const balRaw = trunc(bVal === '—' ? '—' : '⏣' + bVal, wCols.bal);
185
209
  const balStr = balRaw === '—' ? chalk.dim('—') : chalk.bold.green(balRaw);
186
210
 
187
- const lsRaw = trunc(w._lifesavers !== undefined ? String(w._lifesavers) : '—', wCols.ls);
188
- const lColor = lsRaw === '—' ? chalk.dim : (w._lifesavers === 0 ? chalk.bold.red : (w._lifesavers <= 2 ? chalk.bold.yellow : chalk.bold.cyan));
189
- const lsStr = lColor(lsRaw);
211
+ // Heart Lifesavers
212
+ let lsRaw = '—';
213
+ let lsStr = chalk.dim('—');
214
+ if (w._lifesavers !== undefined) {
215
+ let lsCount = w._lifesavers;
216
+ let lsEmoji = '❤️'; // Red for 0-2
217
+ let lsColor = chalk.bold.red;
218
+
219
+ if (lsCount >= 5) { lsEmoji = '💚'; lsColor = chalk.bold.green; }
220
+ else if (lsCount >= 3) { lsEmoji = '💛'; lsColor = chalk.bold.yellow; }
221
+
222
+ lsRaw = trunc(`${lsEmoji} ${lsCount}`, wCols.ls);
223
+ lsStr = lsColor(lsRaw);
224
+ }
190
225
 
191
226
  const lvRaw = trunc(w._level !== undefined ? String(w._level) : '—', wCols.lv);
192
227
  const lvStr = chalk.bold.magenta(lvRaw);
@@ -197,30 +232,23 @@ function render() {
197
232
  out += makeRow(numStr, nameStr, balStr, lsStr, lvStr, logStr, wCols, logW) + '\n';
198
233
  }
199
234
 
200
- out += '├' + '─'.repeat(wCols.num + 2) + '┴'
235
+ if (sorted.length === 0) {
236
+ out += makeRow('—', 'No Accounts', '—', '—', '—', 'Waiting...', wCols, logW) + '\n';
237
+ }
238
+
239
+ out += '╰' + '─'.repeat(wCols.num + 2) + '┴'
201
240
  + '─'.repeat(wCols.name + 2) + '┴'
202
241
  + '─'.repeat(wCols.bal + 2) + '┴'
203
242
  + '─'.repeat(wCols.ls + 2) + '┴'
204
243
  + '─'.repeat(wCols.lv + 2) + '┴'
205
- + '─'.repeat(logW + 2) + '┤\n';
244
+ + '─'.repeat(logW + 2) + '╯\n\n';
206
245
 
207
- const totC = totalCoins >= 1000000 ? (totalCoins/1000000).toFixed(1)+'M' : (totalCoins >= 1000 ? (totalCoins/1000).toFixed(1)+'k' : totalCoins);
208
- const summLine = chalk.bold('Σ ACT: ') + chalk.bold.magenta(_workers.length) + chalk.dim('') +
209
- chalk.bold('⚡ ON: ') + chalk.bold.cyan(onlineCount) + chalk.dim(' ') +
210
- chalk.bold('💰 TR/BAL: ') + chalk.bold.green('⏣' + totalBal.toLocaleString()) + chalk.dim(' │ ') +
211
- chalk.bold('📈 GAINED: ') + chalk.bold.yellow('+' + totC) + chalk.dim(' │ ') +
212
- chalk.bold('⏱ UP: ') + chalk.bold.dim(fmtUptime());
213
-
214
- out += `│ ${pad(summLine, summaryW)} │\n`;
215
- out += '├' + '─'.repeat(actualC - 2) + '┤\n';
216
- out += `│ ${pad(chalk.bold.cyan('📻 LATEST EVENTS'), summaryW)} │\n`;
217
-
218
- if (_events.length === 0) out += `│ ${pad(chalk.dim(' Quiet here...'), summaryW)} │\n`;
219
- _events.forEach(ev => { out += `│ ${pad(chalk.dim(`[${ev.ts}] `) + ev.icon + ' ' + ev.msg, summaryW)} │\n`; });
220
-
221
- out += '╰' + '─'.repeat(actualC - 2) + '╯\n';
246
+ // Latest events beneath the table cleanly
247
+ out += chalk.bold.cyan(' 📻 LATEST EVENTS') + '\n';
248
+ if (_events.length === 0) out += chalk.dim(' Quiet here...\n');
249
+ _events.forEach(ev => { out += ` ${chalk.dim(`[${ev.ts}]`)} ${ev.icon} ${ev.msg}\n`; });
222
250
 
223
- logUpdate(out);
251
+ process.stdout.write(out);
224
252
  }
225
253
 
226
254
  function start() {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dankgrinder",
3
- "version": "8.83.0",
3
+ "version": "8.84.0",
4
4
  "description": "Dank Memer automation engine — grind coins while you sleep",
5
5
  "bin": {
6
6
  "dankgrinder": "bin/dankgrinder.js"