dankgrinder 8.76.0 → 8.78.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.
package/lib/grinder.js CHANGED
@@ -3060,7 +3060,7 @@ async function start(apiKey, apiUrl, opts = {}) {
3060
3060
 
3061
3061
  const memFinal = Math.round((process.memoryUsage?.rss?.() ?? process.memoryUsage().rss) / 1048576);
3062
3062
  const cpm = globalCmdRate.getRate().toFixed(1);
3063
- console.log(`${c.bold}Total:${c.reset} +⏣${finalCoins.toLocaleString()} in ${formatUptime()} | ${finalCmds}cmds | ~${cpm}cmd/m | ${memFinal}MB`);
3063
+ console.log(`${c.bold}Total:${c.reset} +⏣${finalCoins.toLocaleString()} in ${ui.formatUptime()} | ${finalCmds}cmds | ~${cpm}cmd/m | ${memFinal}MB`);
3064
3064
 
3065
3065
  // Stop workers immediately (don't wait) — instant shutdown
3066
3066
  for (const wk of workers) {
@@ -3084,7 +3084,7 @@ async function start(apiKey, apiUrl, opts = {}) {
3084
3084
  console.log(` ${c.dim}${totalRecoveries} recoveries, ${totalDisconnects} disconnects, ${totalRateLimits} rate-limits${c.reset}`);
3085
3085
  }
3086
3086
 
3087
- const webhookMsg = `+⏣ ${finalCoins.toLocaleString()} | ${finalCmds} cmds | ${formatUptime()}` +
3087
+ const webhookMsg = `+⏣ ${finalCoins.toLocaleString()} | ${finalCmds} cmds | ${ui.formatUptime()}` +
3088
3088
  (totalRecoveries > 0 ? ` | ${totalRecoveries} auto-recoveries` : '') +
3089
3089
  (CLUSTER_ENABLED ? ` | node: ${NODE_ID.substring(0, 12)}` : '');
3090
3090
  sendWebhook('Session Ended', webhookMsg, 0x8b5cf6).catch(() => {});
package/lib/ui.js CHANGED
@@ -53,11 +53,7 @@ function init({ workers }) { _workers = workers; _startTime = Date.now(); _event
53
53
 
54
54
  function drawBanner(version) {
55
55
  _version = version || '0.0.0';
56
- console.clear();
57
- const titleStr = figlet.textSync('DANK GRINDER', { font: 'ANSI Shadow' });
58
- console.log(chalk.bold(applyGradient(titleStr)));
59
- console.log(chalk.bold.magenta(`v${_version} — ${getLoader()} Booting... `));
60
- console.log();
56
+ // Do not console.log here, let render() handle the banner to prevent log-update resize duplication
61
57
  }
62
58
 
63
59
  function fmtUptime() {
@@ -92,35 +88,55 @@ function log(accountIdx, msg) { if (!_live && accountIdx === -1) console.log(cha
92
88
  function updateAccountRow() { }
93
89
 
94
90
  // Precision width padding
95
- function padFixed(str, len, isAnsiPrepared = false) {
96
- if (!isAnsiPrepared) {
97
- if (str.length > len) return str.substring(0, len - 1) + '…';
98
- return str.padEnd(len, ' ');
99
- } else {
100
- const rawLen = str.replace(/\x1b\[[0-9;]*m/g, '').length;
101
- if (rawLen < len) return str + ' '.repeat(len - rawLen);
102
- return str; // Assume caller pre-truncated the inner text
103
- }
91
+ function trunc(str, max) {
92
+ return str.length > max ? str.substring(0, max - 1) + '…' : str;
93
+ }
94
+ function pad(str, len) {
95
+ const vLen = str.replace(/\x1b\[[0-9;]*m/g, '').length;
96
+ return str + ' '.repeat(Math.max(0, len - vLen));
97
+ }
98
+ function makeRow(c1, c2, c3, c4, c5, c6, wCols, logW) {
99
+ return `│ ${pad(c1, wCols.num)} │ ${pad(c2, wCols.name)} │ ${pad(c3, wCols.bal)} │ ${pad(c4, wCols.ls)} │ ${pad(c5, wCols.lv)} │ ${pad(c6, logW)} │`;
104
100
  }
105
101
 
106
102
  function render() {
107
103
  if (!_live) return;
108
- const cols = process.stdout.columns || 110;
109
- const rows = process.stdout.rows || 30;
110
-
104
+ const C = process.stdout.columns || 110;
105
+
106
+ let out = '';
107
+ // Banner
111
108
  const titleStr = figlet.textSync('DANK GRINDER', { font: 'ANSI Shadow' });
112
- let out = chalk.bold(applyGradient(titleStr));
109
+ out += chalk.bold(applyGradient(titleStr));
110
+ out += chalk.bold.magenta(`v${_version} — ${getLoader()} Running... `) + '\n\n';
111
+
112
+ const wCols = { num: 4, name: 18, bal: 14, ls: 5, lv: 5 };
113
113
 
114
- const sep = chalk.hex('#4dd4ee').bold('━'.repeat(cols));
115
- out += sep + '\n';
114
+ const overhead = 19 + wCols.num + wCols.name + wCols.bal + wCols.ls + wCols.lv;
115
+ const logW = Math.max(10, C - overhead);
116
+ const actualC = logW + overhead;
117
+
118
+ const summaryW = actualC - 4;
116
119
 
117
- const wCols = { num: 4, name: 18, bal: 14, ls: 6, lv: 6 };
118
- let logW = Math.max(15, cols - (wCols.num + wCols.name + wCols.bal + wCols.ls + wCols.lv + 12));
120
+ out += '╭' + '─'.repeat(wCols.num + 2) + '┬'
121
+ + '─'.repeat(wCols.name + 2) + '┬'
122
+ + '─'.repeat(wCols.bal + 2) + '┬'
123
+ + '─'.repeat(wCols.ls + 2) + '┬'
124
+ + '─'.repeat(wCols.lv + 2) + '┬'
125
+ + '─'.repeat(logW + 2) + '╮\n';
126
+
127
+ out += makeRow(
128
+ chalk.bold('#'), chalk.bold('ACCOUNT'), chalk.bold('BAL'),
129
+ chalk.bold('LS'), chalk.bold('LV'), chalk.bold('LOGS'),
130
+ wCols, logW
131
+ ) + '\n';
119
132
 
120
- out += `${chalk.bold(' #').padEnd(wCols.num)} ${chalk.bold('ACCOUNT').padEnd(wCols.name)} ${chalk.bold('BAL').padEnd(wCols.bal)} ${chalk.bold('LS').padEnd(wCols.ls)} ${chalk.bold('LV').padEnd(wCols.lv)} ${chalk.bold('LOGS')} \n`;
121
- out += sep + '\n';
133
+ out += '' + ''.repeat(wCols.num + 2) + ''
134
+ + '─'.repeat(wCols.name + 2) + ''
135
+ + '─'.repeat(wCols.bal + 2) + '┼'
136
+ + '─'.repeat(wCols.ls + 2) + '┼'
137
+ + '─'.repeat(wCols.lv + 2) + '┼'
138
+ + '─'.repeat(logW + 2) + '┤\n';
122
139
 
123
- const maxShown = Math.max(3, rows - 24);
124
140
  const sorted = [..._workers].sort((a, b) => {
125
141
  if (!a.channel !== !b.channel) return a.channel ? -1 : 1;
126
142
  const aA = a.channel && !a.paused && !a.dashboardPaused;
@@ -130,17 +146,11 @@ function render() {
130
146
  });
131
147
 
132
148
  let totalCoins = 0, totalBal = 0, onlineCount = 0;
133
- for (let i = 0; i < _workers.length; i++) {
134
- const w = _workers[i];
149
+ for (let i = 0; i < sorted.length; i++) {
150
+ const w = sorted[i];
135
151
  totalCoins += w.stats.coins || 0;
136
152
  totalBal += w.stats.balance || 0;
137
153
  if (w.channel && !w.paused && !w.dashboardPaused) onlineCount++;
138
- }
139
-
140
- const shown = sorted.slice(0, maxShown);
141
- for (let i = 0; i < shown.length; i++) {
142
- const w = shown[i];
143
- const rawIdx = String(_workers.indexOf(w) + 1);
144
154
 
145
155
  let logText = w.lastStatus || 'idle';
146
156
  let activity = '';
@@ -156,54 +166,51 @@ function render() {
156
166
  activity = chalk.gray(getLoader());
157
167
  }
158
168
 
159
- // Fixed widths construction
160
- const numPart = padFixed(` ${rawIdx}`, wCols.num);
161
-
162
- // Name Part
169
+ const numStr = trunc(String(i + 1), wCols.num);
163
170
  const dot = getDot(w);
164
- let uName = w.username || '?';
165
- // dot + space + name -> subtract 2 from allowed length
166
- if (uName.length > wCols.name - 2) uName = uName.substring(0, wCols.name - 3) + '…';
167
- const cName = `${dot.color(dot.dot)} ${getAccountColor(uName)(chalk.bold(uName))}`;
168
- const namePart = padFixed(cName, wCols.name, true);
169
171
 
170
- // Bal Part
172
+ const nameRaw = trunc(w.username || '?', wCols.name - 2);
173
+ const nameStr = dot.color(dot.dot) + ' ' + getAccountColor(nameRaw)(chalk.bold(nameRaw));
174
+
171
175
  let bVal = w.stats.balance !== undefined ? (w.stats.balance >= 1000 ? w.stats.balance.toLocaleString() : String(w.stats.balance)) : '—';
172
- bVal = bVal.length > wCols.bal - 2 ? bVal.substring(0, wCols.bal - 3) + '…' : bVal;
173
- const cBal = bVal === '—' ? chalk.dim('—') : chalk.bold.green(`⏣${bVal}`);
174
- const balPart = padFixed(cBal, wCols.bal, true);
176
+ const balRaw = trunc(bVal === '—' ? '—' : '⏣' + bVal, wCols.bal);
177
+ const balStr = balRaw === '—' ? chalk.dim('—') : chalk.bold.green(balRaw);
175
178
 
176
- // LS Part
177
- let lVal = w._lifesavers !== undefined ? String(w._lifesavers) : '—';
178
- const lColor = lVal === '—' ? chalk.dim : (w._lifesavers === 0 ? chalk.bold.red : (w._lifesavers <= 2 ? chalk.bold.yellow : chalk.bold.cyan));
179
- const lsPart = padFixed(lColor(lVal.substring(0, wCols.ls)), wCols.ls, true);
179
+ const lsRaw = trunc(w._lifesavers !== undefined ? String(w._lifesavers) : '—', wCols.ls);
180
+ const lColor = lsRaw === '—' ? chalk.dim : (w._lifesavers === 0 ? chalk.bold.red : (w._lifesavers <= 2 ? chalk.bold.yellow : chalk.bold.cyan));
181
+ const lsStr = lColor(lsRaw);
180
182
 
181
- // LV Part
182
- let lvVal = w._level !== undefined ? String(w._level) : '—';
183
- const lvPart = padFixed(chalk.bold.magenta(lvVal.substring(0, wCols.lv)), wCols.lv, true);
183
+ const lvRaw = trunc(w._level !== undefined ? String(w._level) : '—', wCols.lv);
184
+ const lvStr = chalk.bold.magenta(lvRaw);
184
185
 
185
- // Log Part
186
- let lStr = logText;
187
- if (lStr.length > logW - 3) lStr = lStr.substring(0, logW - 4) + '…';
188
- const cLog = `${activity} ${chalk.dim.bold(lStr)}`;
189
- const logPart = padFixed(cLog, logW, true);
186
+ const logRaw = trunc(logText, logW - 2);
187
+ const logStr = activity + ' ' + chalk.dim.bold(logRaw);
190
188
 
191
- out += `${chalk.dim(numPart)} ${namePart} ${balPart} ${lsPart} ${lvPart} ${logPart}\n`;
189
+ out += makeRow(numStr, nameStr, balStr, lsStr, lvStr, logStr, wCols, logW) + '\n';
192
190
  }
193
191
 
194
- if (_workers.length > maxShown) {
195
- out += chalk.bold.dim(` ... and ${(_workers.length - maxShown).toLocaleString()} more accounts running ${getSpinner()}\n`);
196
- }
192
+ out += '├' + '─'.repeat(wCols.num + 2) + '┴'
193
+ + '─'.repeat(wCols.name + 2) + '┴'
194
+ + '─'.repeat(wCols.bal + 2) + '┴'
195
+ + '─'.repeat(wCols.ls + 2) + '┴'
196
+ + '─'.repeat(wCols.lv + 2) + '┴'
197
+ + '─'.repeat(logW + 2) + '┤\n';
197
198
 
198
- out += sep + '\n';
199
199
  const totC = totalCoins >= 1000000 ? (totalCoins/1000000).toFixed(1)+'M' : (totalCoins >= 1000 ? (totalCoins/1000).toFixed(1)+'k' : totalCoins);
200
- out += ` ${chalk.bold('Σ ACCOUNTS:')} ${chalk.bold.magenta(_workers.length)} │ ${chalk.bold('⚡ ONLINE:')} ${chalk.bold.cyan(onlineCount)} │ ${chalk.bold('💰 TOTAL:')} ${chalk.bold.green('⏣' + totalBal.toLocaleString())} ${chalk.bold('📈 GAINED:')} ${chalk.bold.yellow('+' + totC)} │ ${chalk.bold('⏱ UP:')} ${chalk.bold.dim(fmtUptime())}\n`;
201
- out += sep + '\n';
200
+ const summLine = chalk.bold('Σ ACT: ') + chalk.bold.magenta(_workers.length) + chalk.dim(' │ ') +
201
+ chalk.bold('⚡ ON: ') + chalk.bold.cyan(onlineCount) + chalk.dim('') +
202
+ chalk.bold('💰 TR/BAL: ') + chalk.bold.green('⏣' + totalBal.toLocaleString()) + chalk.dim(' │ ') +
203
+ chalk.bold('📈 GAINED: ') + chalk.bold.yellow('+' + totC) + chalk.dim(' │ ') +
204
+ chalk.bold('⏱ UP: ') + chalk.bold.dim(fmtUptime());
205
+
206
+ out += `│ ${pad(summLine, summaryW)} │\n`;
207
+ out += '├' + '─'.repeat(actualC - 2) + '┤\n';
208
+ out += `│ ${pad(chalk.bold.cyan('📻 LATEST EVENTS'), summaryW)} │\n`;
209
+
210
+ if (_events.length === 0) out += `│ ${pad(chalk.dim(' Quiet here...'), summaryW)} │\n`;
211
+ _events.forEach(ev => { out += `│ ${pad(chalk.dim(`[${ev.ts}] `) + ev.icon + ' ' + ev.msg, summaryW)} │\n`; });
202
212
 
203
- out += chalk.bold.cyan(` 📻 LATEST EVENTS \n`) + chalk.dim.bold('─'.repeat(cols)) + '\n';
204
- if (_events.length === 0) out += chalk.dim(' Quiet here...\n');
205
- _events.forEach(ev => { out += chalk.dim(` [${ev.ts}] `) + `${ev.icon} ${ev.msg}\n`; });
206
- out += chalk.dim.bold('─'.repeat(cols)) + '\n';
213
+ out += '╰' + '─'.repeat(actualC - 2) + '╯\n';
207
214
 
208
215
  logUpdate(out);
209
216
  }
@@ -216,4 +223,4 @@ function startRefresh() { if (!_refreshTimer) _refreshTimer = setInterval(() =>
216
223
  function stopRefresh() { if (_refreshTimer) { clearInterval(_refreshTimer); _refreshTimer = null; } }
217
224
  function stop() { _live = false; stopRefresh(); logUpdate.clear(); }
218
225
 
219
- module.exports = { init, drawBanner, start, draw, log, logGlobal, stop, setLive, setPhase, updateAccountRow, startRefresh, stopRefresh, addEvent };
226
+ module.exports = { init, drawBanner, start, draw, log, logGlobal, stop, setLive, setPhase, updateAccountRow, startRefresh, stopRefresh, addEvent, formatUptime: fmtUptime };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dankgrinder",
3
- "version": "8.76.0",
3
+ "version": "8.78.0",
4
4
  "description": "Dank Memer automation engine — grind coins while you sleep",
5
5
  "bin": {
6
6
  "dankgrinder": "bin/dankgrinder.js"