dankgrinder 8.33.0 → 8.36.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 +26 -23
- package/lib/ui.js +40 -9
- package/package.json +1 -1
package/lib/grinder.js
CHANGED
|
@@ -2783,7 +2783,8 @@ async function start(apiKey, apiUrl, opts = {}) {
|
|
|
2783
2783
|
const LOGIN_GAP_MAX_MS = Number.isFinite(parsedGapMax) && parsedGapMax >= LOGIN_GAP_MIN_MS ? parsedGapMax : Math.max(parsedGapMin, 150);
|
|
2784
2784
|
const randomLoginGap = () => LOGIN_GAP_MAX_MS <= LOGIN_GAP_MIN_MS ? LOGIN_GAP_MIN_MS : LOGIN_GAP_MIN_MS + Math.floor(Math.random() * (LOGIN_GAP_MAX_MS - LOGIN_GAP_MIN_MS + 1));
|
|
2785
2785
|
|
|
2786
|
-
|
|
2786
|
+
ui.start(); // show dashboard before login
|
|
2787
|
+
ui.printLogin(`${c.dim}Logging in ${accounts.length} accounts...${c.reset}`);
|
|
2787
2788
|
const BATCH_SIZE = 10;
|
|
2788
2789
|
for (let i = 0; i < accounts.length; i += BATCH_SIZE) {
|
|
2789
2790
|
if (shutdownCalled) break;
|
|
@@ -2792,25 +2793,27 @@ async function start(apiKey, apiUrl, opts = {}) {
|
|
|
2792
2793
|
await Promise.all(batch.map(async (acc, idx) => {
|
|
2793
2794
|
try {
|
|
2794
2795
|
if (idx > 0) await new Promise(r => setTimeout(r, 100 + Math.floor(Math.random() * 500)));
|
|
2795
|
-
console.log(` [${i + idx + 1}] starting: ${acc.label || acc.id}`);
|
|
2796
2796
|
const worker = new AccountWorker(acc, i + idx);
|
|
2797
2797
|
workers.push(worker);
|
|
2798
2798
|
workerMap.set(acc.id, worker);
|
|
2799
2799
|
await worker.start();
|
|
2800
|
-
console.log(` [${i + idx + 1}] done: ${acc.label || acc.id}`);
|
|
2801
2800
|
if (worker._tokenInvalid) {
|
|
2802
|
-
|
|
2801
|
+
worker.lastStatus = 'invalid token';
|
|
2802
|
+
ui.printLogin(` ${c.red}✗${c.reset} [${i + idx + 1}] ${acc.label || acc.id}: invalid token`);
|
|
2803
2803
|
} else if (worker.channel) {
|
|
2804
|
-
|
|
2804
|
+
worker.lastStatus = 'ready';
|
|
2805
|
+
ui.printLogin(` ${c.green}✓${c.reset} [${i + idx + 1}] ${worker.username}`);
|
|
2806
|
+
ui.render();
|
|
2805
2807
|
} else {
|
|
2806
|
-
|
|
2808
|
+
worker.lastStatus = 'timeout';
|
|
2809
|
+
ui.printLogin(` ${c.yellow}✗${c.reset} [${i + idx + 1}] ${acc.label || acc.id}: timeout`);
|
|
2807
2810
|
}
|
|
2808
2811
|
} catch (e) {
|
|
2809
|
-
|
|
2812
|
+
ui.printLogin(` ${c.red}✗${c.reset} [${i + idx + 1}] ERROR: ${e.message}`);
|
|
2810
2813
|
}
|
|
2811
2814
|
}));
|
|
2812
2815
|
} catch (e) {
|
|
2813
|
-
|
|
2816
|
+
ui.printLogin(`${c.red}BATCH ERROR: ${e.message}${c.reset}`);
|
|
2814
2817
|
}
|
|
2815
2818
|
if (i + BATCH_SIZE < accounts.length) await new Promise(r => setTimeout(r, randomLoginGap()));
|
|
2816
2819
|
hintGC();
|
|
@@ -2819,31 +2822,32 @@ async function start(apiKey, apiUrl, opts = {}) {
|
|
|
2819
2822
|
const loginDone = workers.filter(w => !w._tokenInvalid && w.channel).length;
|
|
2820
2823
|
const invalidWorkers = workers.filter(w => w._tokenInvalid);
|
|
2821
2824
|
const timedOutWorkers = workers.filter(w => !w.channel && !w._tokenInvalid);
|
|
2822
|
-
|
|
2825
|
+
ui.printLogin(`${c.green}Login complete: ${loginDone}/${accounts.length} connected${c.reset}`);
|
|
2823
2826
|
if (invalidWorkers.length > 0) {
|
|
2824
|
-
for (const w of invalidWorkers)
|
|
2827
|
+
for (const w of invalidWorkers) ui.printLogin(` ${c.red}FAIL${c.reset} invalid token: ${w.account.label || w.account.id}`);
|
|
2825
2828
|
}
|
|
2826
2829
|
if (timedOutWorkers.length > 0) {
|
|
2827
|
-
|
|
2830
|
+
ui.printLogin(` ${c.yellow}WARN${c.reset} ${timedOutWorkers.length} timed out (will retry in background)`);
|
|
2828
2831
|
}
|
|
2832
|
+
ui.clearLoginLines();
|
|
2829
2833
|
|
|
2830
2834
|
const activeWorkers = workers.filter(w => !w._tokenInvalid);
|
|
2831
2835
|
|
|
2832
2836
|
// ── Phase 2: Inventory check ────────────────────────────────────
|
|
2833
|
-
|
|
2837
|
+
ui.printLogin(`${c.dim}Checking inventory...${c.reset}`);
|
|
2834
2838
|
let invFailed = 0;
|
|
2835
2839
|
await Promise.all(activeWorkers.map(async (w) => {
|
|
2836
2840
|
try { await w.checkInventory({ force: true, requireComplete: true, maxAttempts: 3, silent: true }); }
|
|
2837
2841
|
catch { invFailed++; }
|
|
2838
2842
|
}));
|
|
2839
2843
|
if (invFailed > 0) {
|
|
2840
|
-
|
|
2841
|
-
|
|
2844
|
+
ui.printLogin(`${c.red}Inventory failed for ${invFailed} accounts${c.reset}`);
|
|
2845
|
+
} else {
|
|
2846
|
+
ui.printLogin(`${c.green}Inventory OK${c.reset}`);
|
|
2842
2847
|
}
|
|
2843
|
-
console.log('Inventory check complete');
|
|
2844
2848
|
|
|
2845
2849
|
// ── Phase 2.5: Balance check ───────────────────────────────────
|
|
2846
|
-
|
|
2850
|
+
ui.printLogin(`${c.dim}Checking balances...${c.reset}`);
|
|
2847
2851
|
for (const w of activeWorkers) {
|
|
2848
2852
|
try { await w.checkBalance(true); } catch {}
|
|
2849
2853
|
}
|
|
@@ -2852,10 +2856,10 @@ async function start(apiKey, apiUrl, opts = {}) {
|
|
|
2852
2856
|
totalCoins += w.stats?.balance || 0;
|
|
2853
2857
|
totalCoins += w.stats?.bankBalance || 0;
|
|
2854
2858
|
}
|
|
2855
|
-
|
|
2859
|
+
ui.printLogin(`Balances: total ${c.green}+⏣${totalCoins.toLocaleString()}${c.reset} across ${activeWorkers.length} accounts`);
|
|
2856
2860
|
|
|
2857
2861
|
// ── Phase 2.75: DM history check ────────────────────────────────
|
|
2858
|
-
|
|
2862
|
+
ui.printLogin(`${c.dim}Checking DM history...${c.reset}`);
|
|
2859
2863
|
let dmDeaths = 0, dmLevelUps = 0, dmNoLs = [];
|
|
2860
2864
|
for (const w of activeWorkers) {
|
|
2861
2865
|
try {
|
|
@@ -2873,19 +2877,18 @@ async function start(apiKey, apiUrl, opts = {}) {
|
|
|
2873
2877
|
}
|
|
2874
2878
|
} catch {}
|
|
2875
2879
|
}
|
|
2876
|
-
if (dmNoLs.length > 0)
|
|
2880
|
+
if (dmNoLs.length > 0) ui.printLogin(` ${c.yellow}WARN${c.reset} No lifesavers: ${dmNoLs.join(', ')}`);
|
|
2877
2881
|
const parts = [];
|
|
2878
2882
|
if (dmDeaths > 0) parts.push(`${dmDeaths} deaths`);
|
|
2879
2883
|
if (dmLevelUps > 0) parts.push(`${dmLevelUps} level-ups`);
|
|
2880
|
-
|
|
2884
|
+
ui.printLogin(`DM check: ${parts.length > 0 ? parts.join(', ') : c.green + 'clean' + c.reset}`);
|
|
2885
|
+
ui.clearLoginLines();
|
|
2881
2886
|
|
|
2882
2887
|
// ── Phase 3: Start grind loops ───────────────────────────────────
|
|
2883
|
-
console.log(`Starting ${activeWorkers.length} grind loops...`);
|
|
2884
2888
|
for (const w of activeWorkers) {
|
|
2885
2889
|
if (!shutdownCalled) w.grindLoop();
|
|
2886
2890
|
}
|
|
2887
|
-
ui.
|
|
2888
|
-
console.log(`${c.dim}All grind loops started. | Ctrl+C to stop${c.reset}`);
|
|
2891
|
+
ui.render();
|
|
2889
2892
|
|
|
2890
2893
|
// Cluster heartbeat — lets other nodes see this node is alive
|
|
2891
2894
|
if (CLUSTER_ENABLED) {
|
package/lib/ui.js
CHANGED
|
@@ -46,6 +46,7 @@ function gradientLine(text, from, to) {
|
|
|
46
46
|
|
|
47
47
|
let _lineCount = 0;
|
|
48
48
|
let _interval = null;
|
|
49
|
+
let _loginLines = 0; // number of login progress lines to clear
|
|
49
50
|
|
|
50
51
|
function _statusIcon(w) {
|
|
51
52
|
if (!w.running || !w.channel) return `${c.red}✗${c.reset}`;
|
|
@@ -55,7 +56,7 @@ function _statusIcon(w) {
|
|
|
55
56
|
return `${c.green}●${c.reset}`;
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
function _render() {
|
|
59
|
+
function _render(extraLines = []) {
|
|
59
60
|
const workers = _workers;
|
|
60
61
|
const W = Math.min(process.stdout.columns || 120, 120);
|
|
61
62
|
const lines = [];
|
|
@@ -84,6 +85,8 @@ function _render() {
|
|
|
84
85
|
);
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
for (const el of extraLines) lines.push(el);
|
|
89
|
+
|
|
87
90
|
lines.push(`${c.bold}${'─'.repeat(W)}${c.reset}`);
|
|
88
91
|
|
|
89
92
|
// Totals
|
|
@@ -100,19 +103,28 @@ function _render() {
|
|
|
100
103
|
);
|
|
101
104
|
lines.push('');
|
|
102
105
|
|
|
103
|
-
// Redraw in place
|
|
104
|
-
|
|
106
|
+
// Redraw in place — also clear any login progress lines above
|
|
107
|
+
const clearLines = _lineCount + _loginLines;
|
|
108
|
+
if (clearLines > 0) {
|
|
109
|
+
process.stdout.write(`\x1b[${clearLines}A`);
|
|
110
|
+
for (let i = 0; i < clearLines; i++) {
|
|
111
|
+
process.stdout.write(`\x1b[2K\r${i < clearLines - 1 ? '\x1b[1A' : ''}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
105
114
|
process.stdout.write(lines.join('\n') + '\n');
|
|
106
115
|
_lineCount = lines.length - 1;
|
|
116
|
+
_loginLines = 0;
|
|
107
117
|
}
|
|
108
118
|
|
|
109
119
|
function _clear() {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
const clearLines = _lineCount + _loginLines;
|
|
121
|
+
if (clearLines > 0) {
|
|
122
|
+
process.stdout.write(`\x1b[${clearLines}A`);
|
|
123
|
+
for (let i = 0; i < clearLines; i++) {
|
|
124
|
+
process.stdout.write(`\x1b[2K\r${i < clearLines - 1 ? '\x1b[1A' : ''}`);
|
|
114
125
|
}
|
|
115
126
|
_lineCount = 0;
|
|
127
|
+
_loginLines = 0;
|
|
116
128
|
}
|
|
117
129
|
}
|
|
118
130
|
|
|
@@ -133,9 +145,11 @@ function drawBanner(version) {
|
|
|
133
145
|
console.log('');
|
|
134
146
|
}
|
|
135
147
|
|
|
148
|
+
// Show dashboard and start the 10s refresh interval
|
|
136
149
|
function start() {
|
|
137
|
-
if (_workers.length > 30) return;
|
|
150
|
+
if (_workers.length > 30) return;
|
|
138
151
|
_lineCount = 0;
|
|
152
|
+
_loginLines = 0;
|
|
139
153
|
_render();
|
|
140
154
|
_interval = setInterval(() => {
|
|
141
155
|
if (_isShuttingDown()) {
|
|
@@ -147,9 +161,26 @@ function start() {
|
|
|
147
161
|
}, 10_000);
|
|
148
162
|
}
|
|
149
163
|
|
|
164
|
+
// Immediately re-render the dashboard (use after worker status changes)
|
|
165
|
+
function render() {
|
|
166
|
+
if (_isShuttingDown()) return;
|
|
167
|
+
_render();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Print a login progress line and count it so it gets cleared on next render
|
|
171
|
+
function printLogin(msg) {
|
|
172
|
+
console.log(msg);
|
|
173
|
+
_loginLines++;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Clear login lines and re-render final state
|
|
177
|
+
function clearLoginLines() {
|
|
178
|
+
_render();
|
|
179
|
+
}
|
|
180
|
+
|
|
150
181
|
function stop() {
|
|
151
182
|
if (_interval) { clearInterval(_interval); _interval = null; }
|
|
152
183
|
_clear();
|
|
153
184
|
}
|
|
154
185
|
|
|
155
|
-
module.exports = { init, drawBanner, start, stop };
|
|
186
|
+
module.exports = { init, drawBanner, start, render, printLogin, clearLoginLines, stop };
|