dankgrinder 5.0.1 → 5.0.2
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/commands/utils.js +24 -2
- package/lib/grinder.js +26 -26
- package/package.json +1 -1
package/lib/commands/utils.js
CHANGED
|
@@ -282,7 +282,9 @@ function findSelectMenuOption(msg, label) {
|
|
|
282
282
|
return null;
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
// Safe button click — tries library methods first, falls back to raw HTTP for CV2
|
|
285
|
+
// Safe button click — tries library methods first, falls back to raw HTTP for CV2.
|
|
286
|
+
// When CV2 fallback is used, waits for the message to update so callers always
|
|
287
|
+
// get the updated message back (instead of null, which broke multi-round games).
|
|
286
288
|
async function safeClickButton(msg, button) {
|
|
287
289
|
if (typeof button.click === 'function') {
|
|
288
290
|
return button.click();
|
|
@@ -295,9 +297,29 @@ async function safeClickButton(msg, button) {
|
|
|
295
297
|
// Fall through to CV2 raw interaction fallback.
|
|
296
298
|
}
|
|
297
299
|
}
|
|
298
|
-
// CV2 fallback: send interaction via raw HTTP
|
|
300
|
+
// CV2 fallback: send interaction via raw HTTP, then wait for the message
|
|
301
|
+
// to update so we can return the updated message to the caller.
|
|
299
302
|
if (id) {
|
|
300
303
|
await clickCV2Button(msg, id);
|
|
304
|
+
// Wait for Dank Memer to process the interaction and update the message
|
|
305
|
+
const updatedMsg = await new Promise((resolve) => {
|
|
306
|
+
const timeout = setTimeout(() => {
|
|
307
|
+
msg.client?.removeListener?.('messageUpdate', handler);
|
|
308
|
+
resolve(null);
|
|
309
|
+
}, 8000);
|
|
310
|
+
const handler = (_, newMsg) => {
|
|
311
|
+
if (newMsg.id === msg.id) {
|
|
312
|
+
clearTimeout(timeout);
|
|
313
|
+
msg.client?.removeListener?.('messageUpdate', handler);
|
|
314
|
+
resolve(newMsg);
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
msg.client?.on?.('messageUpdate', handler);
|
|
318
|
+
});
|
|
319
|
+
if (updatedMsg) {
|
|
320
|
+
await ensureCV2(updatedMsg);
|
|
321
|
+
return updatedMsg;
|
|
322
|
+
}
|
|
301
323
|
return null;
|
|
302
324
|
}
|
|
303
325
|
throw new Error('No click method available on button');
|
package/lib/grinder.js
CHANGED
|
@@ -453,19 +453,16 @@ function renderDashboard() {
|
|
|
453
453
|
|
|
454
454
|
lines.push(bar);
|
|
455
455
|
|
|
456
|
+
// Use absolute cursor positioning (row 1, col 1) to avoid ghost bar drift
|
|
457
|
+
process.stdout.write('\x1b[H');
|
|
456
458
|
const prevLines = dashboardLines;
|
|
457
|
-
if (prevLines > 0) {
|
|
458
|
-
process.stdout.write(c.cursorUp(prevLines));
|
|
459
|
-
}
|
|
460
459
|
for (const line of lines) {
|
|
461
460
|
process.stdout.write(c.clearLine + '\r' + line + '\n');
|
|
462
461
|
}
|
|
463
|
-
// Clear trailing
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
process.stdout.write(c.cursorUp(prevLines - lines.length));
|
|
462
|
+
// Clear any trailing lines from previous (larger) render
|
|
463
|
+
const maxClear = Math.max(prevLines - lines.length, 0) + 3;
|
|
464
|
+
for (let i = 0; i < maxClear; i++) {
|
|
465
|
+
process.stdout.write(c.clearLine + '\r\n');
|
|
469
466
|
}
|
|
470
467
|
dashboardLines = lines.length;
|
|
471
468
|
dashboardRendering = false;
|
|
@@ -1535,11 +1532,13 @@ class AccountWorker {
|
|
|
1535
1532
|
|
|
1536
1533
|
if (cmdResult.holdTightReason) {
|
|
1537
1534
|
const reason = cmdResult.holdTightReason;
|
|
1538
|
-
|
|
1535
|
+
const holdSec = 35;
|
|
1536
|
+
this.log('warn', `Hold Tight: /${reason} — ${holdSec}s global cooldown`);
|
|
1539
1537
|
const reasonMap = { postmemes: 'pm', highlow: 'hl', blackjack: 'bj', 'work shift': 'work shift' };
|
|
1540
1538
|
const mappedCmd = reasonMap[reason] || reason;
|
|
1541
|
-
await this.setCooldown(mappedCmd,
|
|
1542
|
-
await this.setCooldown(cmdName,
|
|
1539
|
+
await this.setCooldown(mappedCmd, holdSec);
|
|
1540
|
+
await this.setCooldown(cmdName, holdSec);
|
|
1541
|
+
this.globalCooldownUntil = Math.max(this.globalCooldownUntil, Date.now() + holdSec * 1000);
|
|
1543
1542
|
}
|
|
1544
1543
|
|
|
1545
1544
|
this.stats.successes++;
|
|
@@ -2025,6 +2024,14 @@ class AccountWorker {
|
|
|
2025
2024
|
await this.runCommand(item.cmd, prefix);
|
|
2026
2025
|
const earned = this.stats.coins - beforeCoins;
|
|
2027
2026
|
|
|
2027
|
+
// Grace period for interactive (button-click) commands — Dank Memer
|
|
2028
|
+
// needs time to process the interaction before accepting the next command.
|
|
2029
|
+
// Without this, the next command gets "Hold Tight" errors.
|
|
2030
|
+
const INTERACTIVE_CMDS = new Set(['hl', 'blackjack', 'trivia', 'scratch', 'adventure', 'stream', 'fish']);
|
|
2031
|
+
if (INTERACTIVE_CMDS.has(item.cmd)) {
|
|
2032
|
+
await new Promise(r => setTimeout(r, 2500 + Math.random() * 1500));
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2028
2035
|
// EMA: track smoothed earnings per command for adaptive scheduling
|
|
2029
2036
|
if (earned > 0) {
|
|
2030
2037
|
this._earningsEMA.update(earned);
|
|
@@ -2075,14 +2082,8 @@ class AccountWorker {
|
|
|
2075
2082
|
if (this.cycleCount > 0 && this.cycleCount % 10 === 0) this.printStats();
|
|
2076
2083
|
// Rebuild BloomFilter every 50 cycles to clear expired entries
|
|
2077
2084
|
if (this.cycleCount > 0 && this.cycleCount % 50 === 0) this._rebuildBloom();
|
|
2078
|
-
if (this.cycleCount > 0 && this.cycleCount % 5 === 0) {
|
|
2079
|
-
this.busy = true;
|
|
2080
|
-
await this.checkBalance();
|
|
2081
|
-
this.busy = false;
|
|
2082
|
-
}
|
|
2083
|
-
|
|
2084
2085
|
if (this.running && !shutdownCalled) {
|
|
2085
|
-
const nextDelay = this.failStreak > 0 ?
|
|
2086
|
+
const nextDelay = this.failStreak > 0 ? 3000 : 1500;
|
|
2086
2087
|
this.tickTimeout = setTimeout(() => this.tick(), nextDelay);
|
|
2087
2088
|
}
|
|
2088
2089
|
}
|
|
@@ -2090,7 +2091,6 @@ class AccountWorker {
|
|
|
2090
2091
|
async grindLoop() {
|
|
2091
2092
|
if (this.running) return;
|
|
2092
2093
|
this.running = true;
|
|
2093
|
-
this.busy = false;
|
|
2094
2094
|
this.paused = false;
|
|
2095
2095
|
this.dashboardPaused = false;
|
|
2096
2096
|
this.failStreak = 0;
|
|
@@ -2280,8 +2280,6 @@ class AccountWorker {
|
|
|
2280
2280
|
|
|
2281
2281
|
// Let Discord gateway settle before sending first command
|
|
2282
2282
|
await new Promise(r => setTimeout(r, 2500));
|
|
2283
|
-
await this.checkBalance();
|
|
2284
|
-
this.checkInventory().catch(() => {});
|
|
2285
2283
|
this.grindLoop();
|
|
2286
2284
|
resolve();
|
|
2287
2285
|
});
|
|
@@ -2365,9 +2363,9 @@ async function start(apiKey, apiUrl) {
|
|
|
2365
2363
|
|
|
2366
2364
|
const checks = [];
|
|
2367
2365
|
checks.push(`${rgb(52, 211, 153)}✓${c.reset} ${c.white}API${c.reset}`);
|
|
2368
|
-
checks.push(
|
|
2369
|
-
checks.push(
|
|
2370
|
-
checks.push(
|
|
2366
|
+
if (REDIS_URL) checks.push(`${rgb(52, 211, 153)}✓${c.reset} ${c.white}Redis${c.reset}`);
|
|
2367
|
+
if (hasZlib) checks.push(`${rgb(52, 211, 153)}✓${c.reset} ${c.white}zlib${c.reset}`);
|
|
2368
|
+
if (WEBHOOK_URL) checks.push(`${rgb(52, 211, 153)}✓${c.reset} ${c.white}Webhook${c.reset}`);
|
|
2371
2369
|
if (CLUSTER_ENABLED) {
|
|
2372
2370
|
checks.push(`${rgb(52, 211, 153)}✓${c.reset} ${rgb(34, 211, 238)}Cluster${c.reset} ${c.dim}(${NODE_ID.substring(0, 12)})${c.reset}`);
|
|
2373
2371
|
}
|
|
@@ -2421,11 +2419,13 @@ async function start(apiKey, apiUrl) {
|
|
|
2421
2419
|
}
|
|
2422
2420
|
}
|
|
2423
2421
|
|
|
2424
|
-
console.log('');
|
|
2425
2422
|
startTime = Date.now();
|
|
2426
2423
|
dashboardStarted = true;
|
|
2427
2424
|
setDashboardActive(true);
|
|
2425
|
+
// Clear entire screen so startup logs don't create ghost bars
|
|
2426
|
+
process.stdout.write('\x1b[2J\x1b[H');
|
|
2428
2427
|
process.stdout.write(c.hide);
|
|
2428
|
+
dashboardLines = 0;
|
|
2429
2429
|
|
|
2430
2430
|
setInterval(() => scheduleRender(), 1000);
|
|
2431
2431
|
scheduleRender();
|