dankgrinder 6.42.0 → 6.45.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.
@@ -198,7 +198,7 @@ async function runInventory({ channel, waitForDankMemer, client, accountId, redi
198
198
  LOG.cmd(`${c.white}${c.bold}pls inv${c.reset}`);
199
199
 
200
200
  await channel.send('pls inv');
201
- let response = await waitForDankMemer(10000);
201
+ let response = await waitForDankMemer(15000);
202
202
 
203
203
  if (!response) {
204
204
  LOG.warn('[inv] No response');
package/lib/grinder.js CHANGED
@@ -2026,16 +2026,6 @@ class AccountWorker {
2026
2026
  return;
2027
2027
  }
2028
2028
 
2029
- // Died flag from crime/search handler (death detected in the command response)
2030
- if (cmdResult.died) {
2031
- this.log('error', `${cmdName} → DIED! Checking lifesaver count...`);
2032
- // The DM will come separately with the actual death details
2033
- // For now, be cautious — set a short cooldown and let DM listener handle the rest
2034
- await this.setCooldown('crime', 300); // 5 min cooldown to check DMs
2035
- await this.setCooldown('search', 300);
2036
- return;
2037
- }
2038
-
2039
2029
  // Premium-only command detection — disable permanently
2040
2030
  if (resultLower.includes('only available on premium') || resultLower.includes('premium') ||
2041
2031
  resultLower.includes('buy the ability to use this command') ||
@@ -2625,6 +2615,18 @@ class AccountWorker {
2625
2615
  return;
2626
2616
  }
2627
2617
 
2618
+ // Startup delay: don't send commands for the first 30s after grindLoop() starts.
2619
+ // This prevents flooding Dank Memer during the Phase 2 inventory check which
2620
+ // sends pls inv for all accounts simultaneously after login.
2621
+ if (this._startupDelayUntil && now < this._startupDelayUntil) {
2622
+ const waitMs = this._startupDelayUntil - now;
2623
+ this.setStatus('warming up...');
2624
+ item.nextRunAt = now + waitMs + 1000;
2625
+ if (this.commandQueue) this.commandQueue.push(item);
2626
+ this.tickTimeout = setTimeout(() => this.tick(), waitMs + 1000);
2627
+ return;
2628
+ }
2629
+
2628
2630
  this.busy = true;
2629
2631
 
2630
2632
  // ── Run command (with interactive retry) ───────────────────
@@ -2765,6 +2767,11 @@ class AccountWorker {
2765
2767
  this.failStreak = 0;
2766
2768
  this.cycleCount = 0;
2767
2769
  this.lastCommandRun = 0;
2770
+ // Delay first command by 30s to avoid competing with Phase 2 inventory check
2771
+ // which sends pls inv for all accounts simultaneously after login.
2772
+ // Without this, the grind loop floods Dank Memer with commands during the
2773
+ // login surge, triggering rate-limits that cause Phase 2 inventory to fail.
2774
+ this._startupDelayUntil = Date.now() + 30000;
2768
2775
  await this._loadLearnedCooldowns();
2769
2776
  this.commandQueue = await this.buildCommandQueue();
2770
2777
  this.lastHealthCheck = Date.now();
@@ -3165,19 +3172,38 @@ async function start(apiKey, apiUrl) {
3165
3172
  // Init rawLogger Redis (uses same URL — logs all raw gateway data)
3166
3173
  if (REDIS_URL) {
3167
3174
  rawLogger.init(REDIS_URL).catch(() => {});
3168
- // Listen for DM death events across all accounts
3175
+ // Live DM listener: detect deaths and level-ups in real-time across all accounts
3169
3176
  rawLogger.onDmEvent((event, raw) => {
3170
- if (event.type === 'death' && event.lifesaversLeft === 0) {
3171
- const channelId = raw.channel_id;
3172
- // Find which worker uses this DM channel and disable their crime/search
3173
- for (const w of workers) {
3174
- if (w.client?.user?.dmChannel?.id === channelId || w.channel?.id) {
3175
- w.log?.('error', `DEATH in DMs! 0 lifesavers — disabling crime/search`);
3176
- w.setCooldown?.('crime', 86400);
3177
- w.setCooldown?.('search', 86400);
3177
+ const dmChannelId = raw.channel_id;
3178
+
3179
+ // Find which worker owns this DM channel
3180
+ const worker = workers.find(w => w._dmChannelId === dmChannelId);
3181
+ if (!worker) return;
3182
+
3183
+ if (event.type === 'death') {
3184
+ const lsLeft = event.lifesaversLeft;
3185
+
3186
+ if (lsLeft === 0) {
3187
+ // 0 lifesavers — disable crime/search immediately
3188
+ worker.log?.('error', `DEATH in DMs! 0 lifesavers — disabling crime/search`);
3189
+ worker.setCooldown?.('crime', 86400);
3190
+ worker.setCooldown?.('search', 86400);
3191
+ worker._lifesavers = 0;
3192
+ sendWebhook?.('DEATH ALERT (DM)', `**${worker.username}** died! **0 lifesavers!**\nCrime/search auto-disabled.`, 0xef4444);
3193
+ } else if (lsLeft > 0) {
3194
+ // Lifesaver(s) used — update count in real-time
3195
+ worker._lifesavers = lsLeft;
3196
+ worker.log?.('warn', `Lifesaver used! ${lsLeft} remaining.`);
3197
+ if (lsLeft <= 2) {
3198
+ sendWebhook?.('LOW LIFESAVERS', `**${worker.username}** died! Only **${lsLeft}** lifesaver(s) left!`, 0xfbbf24);
3178
3199
  }
3179
3200
  }
3180
- sendWebhook?.('DEATH ALERT (DM)', `Account died! **0 lifesavers!**\nCrime/search auto-disabled.`, 0xef4444);
3201
+ } else if (event.type === 'levelup') {
3202
+ // Level up — update in-memory level
3203
+ if (event.to > 0) {
3204
+ worker._level = event.to;
3205
+ worker.log?.('info', `Level up! Now level ${event.to}.`);
3206
+ }
3181
3207
  }
3182
3208
  });
3183
3209
  checks.push(`${rgb(52, 211, 153)}✓${c.reset} ${c.white}RawLog${c.reset}`);
@@ -3385,7 +3411,7 @@ async function start(apiKey, apiUrl) {
3385
3411
  const num = `${c.dim}${(i + 1).toString().padStart(iColNum - 1)}${c.reset}`;
3386
3412
  const name = (w.username || w.account.label || '?').substring(0, iColName).padEnd(iColName);
3387
3413
  let invRes;
3388
- try { invRes = await w.checkInventory({ force: true, requireComplete: true, maxAttempts: 3, silent: true }); }
3414
+ try { invRes = await w.checkInventory({ force: true, requireComplete: true, maxAttempts: 5, silent: true }); }
3389
3415
  catch { invRes = { ok: false }; }
3390
3416
  invPending--;
3391
3417
  const items = invRes?.ok ? (invRes.result?.items?.length || 0) : 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dankgrinder",
3
- "version": "6.42.0",
3
+ "version": "6.45.0",
4
4
  "description": "Dank Memer automation engine — grind coins while you sleep",
5
5
  "bin": {
6
6
  "dankgrinder": "bin/dankgrinder.js"