dankgrinder 8.42.0 → 8.43.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
@@ -721,14 +721,11 @@ class AccountWorker {
721
721
  log(type, msg) {
722
722
  const stripped = msg.replace(/\x1b\[[0-9;]*m/g, '');
723
723
  if (type !== 'debug') this.lastStatus = stripped.substring(0, 28);
724
- // Route through UI
725
- const icons = { info: '.', success: '[OK]', error: '[X]', warn: '[!]', cmd: '>', coin: '$', buy: '#', bal: '*', debug: '.' };
726
- const icon = icons[type] || icons.info;
727
- const text = `${icon} ${this.username} ${msg}`;
724
+ // Route through UI — msg already has context, no need to prepend username
728
725
  if (typeof ui !== 'undefined') {
729
- try { ui.log(this.idx, text); } catch { process.stdout.write(text + '\n'); }
726
+ try { ui.log(this.idx, msg); } catch { process.stdout.write(msg + '\n'); }
730
727
  } else {
731
- process.stdout.write(text + '\n');
728
+ process.stdout.write(msg + '\n');
732
729
  }
733
730
  }
734
731
 
@@ -2512,6 +2509,7 @@ class AccountWorker {
2512
2509
  clearTimeout(timeoutId);
2513
2510
  this.username = this.client.user.tag || this.username;
2514
2511
  this.avatarUrl = this.client.user.displayAvatarURL?.({ format: 'png', dynamic: true, size: 128 }) || null;
2512
+ this.loggedIn = true; // so statusColor/statusText show correct state
2515
2513
 
2516
2514
  // Attach raw gateway logger for CV2 component capture
2517
2515
  rawLogger.attachRawLogger(this.client, { channelId: this.account.channel_id });
package/lib/ui.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI Live Dashboard — fixed box at top, events stream below.
2
+ * CLI Live Dashboard — clean box at top, events stream below.
3
3
  * Box drawn once. Events appended line-by-line. No flicker.
4
4
  */
5
5
 
@@ -8,37 +8,11 @@ let _workers = [];
8
8
  let _isShuttingDown = () => false;
9
9
  let _version = '0.0.0';
10
10
  let _live = false;
11
- let _boxHeight = 0; // rows consumed by the box
12
11
 
13
12
  // ── Spinner frames ────────────────────────────────────────────
14
13
  const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
15
14
  function spinnerFrame() { return SPINNER[Math.floor(Date.now() / 150) % SPINNER.length]; }
16
15
 
17
- // ── Big ASCII art banner ──────────────────────────────────────
18
- const BANNER_LINES = [
19
- ' ██████╗ ██╗ ██╗███╗ ██╗ ██████╗ ███████╗ ██████╗ ███╗ ██╗',
20
- ' ██╔══██╗██║ ██║████╗ ██║██╔════╝ ██╔════╝██╔═══██╗████╗ ██║',
21
- ' ██║ ██║██║ ██║██╔██╗ ██║██║ ███╗█████╗ ██║ ██║██╔██╗ ██║',
22
- ' ██║ ██║██║ ██║██║╚██╗██║██║ ██║██╔══╝ ██║ ██║██║╚██╗██║',
23
- ' ██████╔╝╚██████╔╝██║ ╚████║╚██████╔╝███████╗╚██████╔╝██║ ╚████║',
24
- ' ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═══╝',
25
- ' ██╗██╗ ██╗███╗ ██╗ ██████╗ ██╗ ███████╗██████╗ ',
26
- ' ██║██║ ██║████╗ ██║██╔═══██╗██║ ██╔════╝██╔══██╗',
27
- ' ███████╗███████╗ ██║██║ ██║██╔██╗ ██║██║ ██║██║ █████╗ ██████╔╝',
28
- ' ╚════██║╚════██║ ██║██║ ██║██║╚██╗██║██║ ██║██║ ██╔══╝ ██╔══██╗',
29
- ' ██║ ██║ ██║╚██████╔╝██║ ╚████║╚██████╔╝███████╗███████╗██║ ██║',
30
- ' ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝╚══════╝╚═╝ ╚═╝',
31
- ];
32
-
33
- function gradientLine(text, r1, g1, b1, r2, g2, b2) {
34
- let out = '';
35
- for (let i = 0; i < text.length; i++) {
36
- const t = text.length <= 1 ? 0 : i / (text.length - 1);
37
- out += `\x1b[38;2;${Math.round(r1 + (r2 - r1) * t)};${Math.round(g1 + (g2 - g1) * t)};${Math.round(b1 + (b2 - b1) * t)}m${text[i]}`;
38
- }
39
- return out + '\x1b[0m';
40
- }
41
-
42
16
  // ── Palette ───────────────────────────────────────────────────
43
17
  const PALETTE = [
44
18
  '\x1b[38;2;77;212;238m', '\x1b[38;2;255;194;77m', '\x1b[38;2;130;210;100m',
@@ -76,7 +50,7 @@ function fmtUptime() {
76
50
 
77
51
  // ── Status helpers ─────────────────────────────────────────────
78
52
  function statusColor(w) {
79
- if (!w.running || !w.channel) return c.red;
53
+ if (!w.loggedIn || !w.channel) return c.red;
80
54
  if (w.paused || w.dashboardPaused) return c.yellow;
81
55
  if (w.busy || w._invRunning || w._sellRunning) return c.yellow;
82
56
  if (Date.now() < w.globalCooldownUntil) return c.blue;
@@ -84,7 +58,7 @@ function statusColor(w) {
84
58
  }
85
59
 
86
60
  function statusText(w) {
87
- if (!w.running || !w.channel) return 'ERROR';
61
+ if (!w.loggedIn || !w.channel) return 'CONNECTING';
88
62
  if (w.paused) return 'PAUSED';
89
63
  if (w.dashboardPaused) return 'HELD';
90
64
  if (w._alert?.type === 'death') return 'DEAD';
@@ -99,75 +73,66 @@ function statusText(w) {
99
73
 
100
74
  // ── Layout ────────────────────────────────────────────────────
101
75
  function layout() {
102
- const W = Math.min(process.stdout.columns || 120, 120);
76
+ const W = Math.min(process.stdout.columns || 100, 120);
103
77
  const rows = process.stdout.rows || 40;
104
- const bannerH = BANNER_LINES.length + 1; // +1 blank
105
- const statusH = 1;
106
- const headerH = 2; // headers + hr
107
- const footerH = 2; // totals + hr
108
- const maxAccounts = Math.min(_workers.length, Math.max(3, rows - bannerH - statusH - headerH - footerH - 5));
109
- return { W, bannerH, statusH, headerH, footerH, maxAccounts };
78
+ // Box: header(2) + title(1) + gap(1) + statusBar(1) + divider(1) + headerRow(1) + hr(1) + maxAccounts + totals(2) + divider(1)
79
+ const maxAccounts = Math.min(_workers.length, Math.max(3, rows - 16));
80
+ return { W, maxAccounts };
110
81
  }
111
82
 
112
83
  // ── Draw the fixed box ────────────────────────────────────────
113
84
  function draw() {
114
- const { W, bannerH, statusH, headerH, footerH, maxAccounts } = layout();
115
- const T = '─'.repeat(W - 2);
116
-
117
- // ── Save cursor, clear screen, go to top ──
118
- process.stdout.write('\x1b[s'); // save cursor
119
- process.stdout.write('\x1b[2J\x1b[H'); // clear screen + home
120
- process.stdout.write('\x1b[1G'); // column 1
121
-
122
- // ── Top of box ──
123
- process.stdout.write(`\x1b[38;2;77;212;238m┌─${T}─┐\x1b[0m\n`);
124
-
125
- // ── Banner inside box ──
126
- for (const line of BANNER_LINES) {
127
- process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m ${gradientLine(line, 77, 212, 238, 255, 92, 147)} \x1b[38;2;77;212;238m│\x1b[0m\n`);
128
- }
129
- process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m\n`);
130
-
131
- // ── Status bar inside box ──
132
- const running = _workers.filter(w => w.running && w.channel && !w.paused && !w.dashboardPaused).length;
85
+ const { W, maxAccounts } = layout();
86
+ const inner = W - 2;
87
+
88
+ // ── Save cursor + clear screen ──
89
+ process.stdout.write('\x1b[s'); // save cursor
90
+ process.stdout.write('\x1b[2J\x1b[H'); // clear screen + home
91
+
92
+ // ── Title ──
93
+ process.stdout.write(`\x1b[38;2;77;212;238m┌${'─'.repeat(inner)}┐\x1b[0m\n`);
94
+ const title = ` ${c.bold}${c.cyan}DANK${c.reset}${c.bold}${c.white}GRINDER${c.reset} ${c.dim}v${_version}${c.reset} `;
95
+ const dots = ' '.repeat(Math.max(0, inner - stripAnsi(title) - 10));
96
+ const upStr = `${DIM}${fmtUptime()}${c.reset}`;
97
+ const upPad = ' '.repeat(Math.max(0, inner - stripAnsi(title) - stripAnsi(dots) - stripAnsi(upStr) - 2));
98
+ process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m${title}${dots}${upStr}${upPad}\x1b[38;2;77;212;238m│\x1b[0m\n`);
99
+
100
+ // ── Status bar ──
101
+ const running = _workers.filter(w => w.loggedIn && w.channel && !w.paused && !w.dashboardPaused).length;
133
102
  const paused = _workers.filter(w => w.paused || w.dashboardPaused).length;
134
- const errors = _workers.filter(w => !w.running || !w.channel).length;
135
- const statusLine = [
136
- `${c.bold}v${_version}${c.reset}`,
137
- `${c.green}●${c.reset} online`,
138
- `${fmtUptime()}`,
139
- `${c.green}·${c.reset}${running}`,
140
- `${c.yellow}~${c.reset}${paused}`,
141
- errors > 0 ? `${c.red}E${c.reset}${errors}` : null,
103
+ const errors = _workers.filter(w => !w.loggedIn || !w.channel).length;
104
+ const statusParts = [
105
+ `${c.green}●${c.reset} ${running} online`,
106
+ paused > 0 ? `${c.yellow}~${c.reset} ${paused} paused` : null,
107
+ errors > 0 ? `${c.red}E${c.reset} ${errors} error` : null,
142
108
  `${DIM}Ctrl+C${c.reset}`,
143
- ].filter(Boolean).join(' ');
144
- const statusPad = W - 4 - stripAnsi(statusLine).length;
145
- process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m ${statusLine}${' '.repeat(Math.max(0, statusPad))} \x1b[38;2;77;212;238m│\x1b[0m\n`);
146
- process.stdout.write(`\x1b[38;2;77;212;238m├─${T}─┤\x1b[0m\n`);
109
+ ].filter(Boolean);
110
+ const statusStr = statusParts.join(' ');
111
+ const statusPad = ' '.repeat(Math.max(0, inner - stripAnsi(statusStr)));
112
+ process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m ${statusStr}${statusPad}\x1b[38;2;77;212;238m│\x1b[0m\n`);
113
+ process.stdout.write(`\x1b[38;2;77;212;238m├${'─'.repeat(inner)}┤\x1b[0m\n`);
147
114
 
148
115
  // ── Table header ──
149
- const col = {
150
- st: 9, name: 20, last: 22, cmds: 6, ok: 5, earned: 10,
151
- };
152
- const nameExtra = Math.max(0, W - 4 - col.st - col.name - col.last - col.cmds - col.ok - col.earned - 14);
116
+ const col = { st: 9, name: 18, last: 24, cmds: 6, ok: 5, earned: 10 };
117
+ const nameExtra = Math.max(0, inner - col.st - col.name - col.last - col.cmds - col.ok - col.earned - 8);
153
118
  col.name += nameExtra;
154
119
 
155
120
  process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m `);
156
121
  process.stdout.write(`${c.bold}#${c.reset} `);
157
122
  process.stdout.write(`${c.bold}${padR('STATUS', col.st)}${c.reset} `);
158
123
  process.stdout.write(`${c.bold}${padR('ACCOUNT', col.name)}${c.reset} `);
159
- process.stdout.write(`${c.bold}${padR('LAST CMD', col.last)}${c.reset} `);
124
+ process.stdout.write(`${c.bold}${padR('LAST COMMAND', col.last)}${c.reset} `);
160
125
  process.stdout.write(`${c.bold}${padL('CMDS', col.cmds)}${c.reset} `);
161
126
  process.stdout.write(`${c.bold}${padL('OK%', col.ok)}${c.reset} `);
162
127
  process.stdout.write(`${c.bold}${padL('EARNED', col.earned)}${c.reset} `);
163
128
  process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m\n`);
164
- process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m ${'─'.repeat(W - 4)} \x1b[38;2;77;212;238m│\x1b[0m\n`);
129
+ process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m ${'─'.repeat(inner)} \x1b[38;2;77;212;238m│\x1b[0m\n`);
165
130
 
166
131
  // ── Account rows ──
167
132
  const sorted = [..._workers].sort((a, b) => {
168
- if (!a.channel !== !b.channel) return !a.channel ? 1 : -1;
169
- const aA = a.running && a.channel && !a.paused && !a.dashboardPaused;
170
- const bA = b.running && b.channel && !b.paused && !b.dashboardPaused;
133
+ if (!a.loggedIn !== !b.loggedIn) return !a.loggedIn ? 1 : -1;
134
+ const aA = a.loggedIn && a.channel && !a.paused && !a.dashboardPaused;
135
+ const bA = b.loggedIn && b.channel && !b.paused && !b.dashboardPaused;
171
136
  if (aA !== bA) return bA ? 1 : -1;
172
137
  return (b.stats.commands || 0) - (a.stats.commands || 0);
173
138
  });
@@ -195,7 +160,8 @@ function draw() {
195
160
  }
196
161
 
197
162
  if (sorted.length > maxAccounts) {
198
- process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m ${DIM}+${sorted.length - maxAccounts} more${' '.repeat(Math.max(0, W - 20 - String(sorted.length - maxAccounts).length))}${c.reset} \x1b[38;2;77;212;238m│\x1b[0m\n`);
163
+ const extra = sorted.length - maxAccounts;
164
+ process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m ${DIM}+ ${extra} more accounts${' '.repeat(Math.max(0, inner - 20 - String(extra).length))}${c.reset} \x1b[38;2;77;212;238m│\x1b[0m\n`);
199
165
  }
200
166
 
201
167
  // ── Totals ──
@@ -208,7 +174,7 @@ function draw() {
208
174
  const rate = totalCmds > 0 ? Math.round((totalOk / totalCmds) * 100) : 0;
209
175
  const memMB = Math.round((process.memoryUsage?.rss?.() ?? process.memoryUsage().rss) / 1048576);
210
176
 
211
- process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m ${'─'.repeat(W - 4)} \x1b[38;2;77;212;238m│\x1b[0m\n`);
177
+ process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m ${'─'.repeat(inner)} \x1b[38;2;77;212;238m│\x1b[0m\n`);
212
178
  process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m `);
213
179
  process.stdout.write(`${c.bold}Σ${c.reset} `);
214
180
  process.stdout.write(`${DIM}${padL(_workers.length, 2)} acc${c.reset} `);
@@ -216,18 +182,19 @@ function draw() {
216
182
  process.stdout.write(`${' '.repeat(col.last)} `);
217
183
  process.stdout.write(`${padL(totalCmds, col.cmds)} `);
218
184
  process.stdout.write(`${padL(rate, col.ok)}% `);
219
- process.stdout.write(`${totalCoins > 0 ? c.green + padL('+' + totalCoins.toLocaleString(), col.earned) + c.reset : DIM + padL('—', col.earned) + c.reset} `);
220
- process.stdout.write(`${DIM}${fmtUptime()} | ${memMB}MB${c.reset} `.padEnd(W - 4));
185
+ if (totalCoins > 0) {
186
+ process.stdout.write(`${c.green}${padL('+' + totalCoins.toLocaleString(), col.earned)}${c.reset} `);
187
+ } else {
188
+ process.stdout.write(`${DIM}${padL('—', col.earned)}${c.reset} `);
189
+ }
190
+ process.stdout.write(`${DIM}${fmtUptime()} | ${memMB}MB${c.reset} `.padEnd(inner));
221
191
  process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m\n`);
222
192
 
223
- // ── Bottom of box ──
224
- process.stdout.write(`\x1b[38;2;77;212;238m└─${T}─┘\x1b[0m\n`);
193
+ // ── Bottom ──
194
+ process.stdout.write(`\x1b[38;2;77;212;238m└${'─'.repeat(inner)}┘\x1b[0m\n`);
225
195
 
226
- // Record how many rows the box consumed
227
- _boxHeight = bannerH + statusH + 1 + headerH + shown.length + (sorted.length > maxAccounts ? 1 : 0) + footerH + 1;
228
-
229
- // Restore cursor to just below the box
230
- process.stdout.write(`\x1b[u`); // restore cursor
196
+ // Restore cursor to after the box
197
+ process.stdout.write('\x1b[u');
231
198
  }
232
199
 
233
200
  // ── Strip ANSI for length calc ───────────────────────────────
@@ -237,7 +204,7 @@ function stripAnsi(s) {
237
204
 
238
205
  // ── Event tracking ────────────────────────────────────────────
239
206
  let _eventLines = []; // [accountIdx] = [{text, ts}]
240
- const MAX_EVENTS = 2;
207
+ const MAX_EVENTS = 3;
241
208
 
242
209
  // ── Public API ────────────────────────────────────────────────
243
210
 
@@ -253,10 +220,9 @@ function init({ workers, isShuttingDown }) {
253
220
  function drawBanner(version) { _version = version; }
254
221
  function start() {}
255
222
  function stop() { _live = false; process.stdout.write(c.reset + '\n'); }
256
-
257
- // Enable live mode — from this point, log() appends below the box
258
223
  function setLive(val) { _live = val; }
259
224
 
225
+ // log: append event below the box (no redraw of box)
260
226
  function log(accountIdx, msg) {
261
227
  const now = new Date();
262
228
  const ts = `${padL(now.getHours(), 2, '0')}:${padL(now.getMinutes(), 2, '0')}:${padL(now.getSeconds(), 2, '0')}`;
@@ -270,14 +236,11 @@ function log(accountIdx, msg) {
270
236
 
271
237
  if (!_live) return; // during login: just track, don't output yet
272
238
 
273
- // ── Append event LINE BY LINE below the box ──
274
- const col2 = accountIdx >= 0 ? wc(accountIdx) : '';
275
- const name = accountIdx >= 0 ? trunc(_workers[accountIdx]?.username || '?', 12) : 'GLOBAL';
276
-
277
- process.stdout.write(`\x1b[38;2;77;212;238m│\x1b[0m `);
278
- process.stdout.write(`${col2}${padR(name, 12)}${c.reset} `);
279
- process.stdout.write(`${DIM}[${ts}]${c.reset} ${msg}`);
280
- process.stdout.write(`\n`);
239
+ // ── Append event cleanly below the box ──
240
+ const col2 = accountIdx >= 0 ? wc(accountIdx) : c.cyan;
241
+ const name = accountIdx >= 0 ? trunc(_workers[accountIdx]?.username || '?', 14) : 'GLOBAL';
242
+ const text = DIM + name + c.reset + ' ' + DIM + ts + c.reset + ' ' + msg;
243
+ process.stdout.write(text + '\n');
281
244
  }
282
245
 
283
246
  function logGlobal(msg) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dankgrinder",
3
- "version": "8.42.0",
3
+ "version": "8.43.0",
4
4
  "description": "Dank Memer automation engine — grind coins while you sleep",
5
5
  "bin": {
6
6
  "dankgrinder": "bin/dankgrinder.js"