dankgrinder 5.0.2 → 5.0.3

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.
Files changed (2) hide show
  1. package/lib/grinder.js +29 -37
  2. package/package.json +1 -1
package/lib/grinder.js CHANGED
@@ -565,32 +565,20 @@ async function reportEarnings(accountId, accountName, earned, spent, command) {
565
565
  earningsBatch.push({ account_id: accountId, account_name: accountName, earned, spent, command });
566
566
  }
567
567
 
568
- const feedBatch = new AsyncBatchQueue(async (batch) => {
568
+ // Command feed sends directly (no batching) for real-time dashboard SSE updates.
569
+ // The dashboard live queue depends on instant delivery via eventBus.emit("sse").
570
+ async function reportCommandFeed(accountId, accountName, data) {
569
571
  if (!API_URL) return;
572
+ const normalized = { ...data };
573
+ if (typeof normalized.command === 'string') normalized.command = stripAnsi(normalized.command).replace(/\s+/g, ' ').trim();
574
+ if (typeof normalized.result === 'string') normalized.result = stripAnsi(normalized.result).replace(/\s+/g, ' ').trim();
570
575
  try {
571
- await fetch(`${API_URL}/api/grinder/command-feed-batch`, {
576
+ await fetch(`${API_URL}/api/grinder/command-feed`, {
572
577
  method: 'POST',
573
578
  headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
574
- body: JSON.stringify({ items: batch }),
579
+ body: JSON.stringify({ account_id: accountId, account_name: accountName, ...normalized }),
575
580
  });
576
- } catch {
577
- for (const item of batch) {
578
- try {
579
- await fetch(`${API_URL}/api/grinder/command-feed`, {
580
- method: 'POST',
581
- headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
582
- body: JSON.stringify(item),
583
- });
584
- } catch {}
585
- }
586
- }
587
- }, { maxSize: 100, flushMs: 2000 });
588
-
589
- async function reportCommandFeed(accountId, accountName, data) {
590
- const normalized = { ...data };
591
- if (typeof normalized.command === 'string') normalized.command = stripAnsi(normalized.command).replace(/\s+/g, ' ').trim();
592
- if (typeof normalized.result === 'string') normalized.result = stripAnsi(normalized.result).replace(/\s+/g, ' ').trim();
593
- feedBatch.push({ account_id: accountId, account_name: accountName, ...normalized });
581
+ } catch { /* silent — dashboard just won't see this update */ }
594
582
  }
595
583
 
596
584
  function randomDelay(min, max) {
@@ -1886,7 +1874,7 @@ class AccountWorker {
1886
1874
  this.tickTimeout = setTimeout(() => this.tick(), 5000);
1887
1875
  return;
1888
1876
  }
1889
- if (this.busy) {
1877
+ if (this.busy || this._invRunning) {
1890
1878
  this.tickTimeout = setTimeout(() => this.tick(), 2000);
1891
1879
  return;
1892
1880
  }
@@ -2189,9 +2177,9 @@ class AccountWorker {
2189
2177
  // Handle pending actions from dashboard
2190
2178
  if (Array.isArray(data.pendingActions)) {
2191
2179
  for (const action of data.pendingActions) {
2192
- if (action.action === 'check_inventory' && !this.busy) {
2180
+ if (action.action === 'check_inventory' && !this.busy && !this._invRunning) {
2193
2181
  this.log('info', 'Dashboard requested inventory check');
2194
- this.checkInventory().catch(() => {});
2182
+ await this.checkInventory().catch(() => {});
2195
2183
  try {
2196
2184
  await fetch(`${API_URL}/api/grinder/actions`, {
2197
2185
  method: 'DELETE',
@@ -2280,6 +2268,8 @@ class AccountWorker {
2280
2268
 
2281
2269
  // Let Discord gateway settle before sending first command
2282
2270
  await new Promise(r => setTimeout(r, 2500));
2271
+ // Run initial inventory check (awaited) before grind loop starts
2272
+ await this.checkInventory().catch(() => {});
2283
2273
  this.grindLoop();
2284
2274
  resolve();
2285
2275
  });
@@ -2341,7 +2331,6 @@ async function start(apiKey, apiUrl) {
2341
2331
  API_URL = apiUrl || process.env.DANKGRINDER_URL || 'http://localhost:3000';
2342
2332
  REDIS_URL = process.env.REDIS_URL || '';
2343
2333
  WEBHOOK_URL = process.env.WEBHOOK_URL || '';
2344
- initRedis();
2345
2334
 
2346
2335
  process.stdout.write('\x1b[2J\x1b[H');
2347
2336
  const tw = Math.min(process.stdout.columns || 80, 78);
@@ -2361,16 +2350,6 @@ async function start(apiKey, apiUrl) {
2361
2350
  );
2362
2351
  console.log(bar);
2363
2352
 
2364
- const checks = [];
2365
- checks.push(`${rgb(52, 211, 153)}✓${c.reset} ${c.white}API${c.reset}`);
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}`);
2369
- if (CLUSTER_ENABLED) {
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}`);
2371
- }
2372
- console.log(` ${checks.join(' ')}`);
2373
-
2374
2353
  log('info', `${c.dim}Fetching accounts...${c.reset}`);
2375
2354
 
2376
2355
  let data = await fetchConfig(4, 2000);
@@ -2381,6 +2360,13 @@ async function start(apiKey, apiUrl) {
2381
2360
  data = await fetchConfig(4, 2000);
2382
2361
  }
2383
2362
 
2363
+ // Pull Redis/Webhook URLs from API config if not in env
2364
+ if (!REDIS_URL && data.redis_url) REDIS_URL = data.redis_url;
2365
+ if (!REDIS_URL && data.redisUrl) REDIS_URL = data.redisUrl;
2366
+ if (!WEBHOOK_URL && data.webhook_url) WEBHOOK_URL = data.webhook_url;
2367
+ if (!WEBHOOK_URL && data.webhookUrl) WEBHOOK_URL = data.webhookUrl;
2368
+ initRedis();
2369
+
2384
2370
  let { accounts } = data;
2385
2371
  if (!accounts || accounts.length === 0) {
2386
2372
  log('error', 'No active accounts. Add them in the dashboard.');
@@ -2397,9 +2383,15 @@ async function start(apiKey, apiUrl) {
2397
2383
  }
2398
2384
  }
2399
2385
 
2386
+ const checks = [];
2387
+ checks.push(`${rgb(52, 211, 153)}✓${c.reset} ${c.white}API${c.reset}`);
2388
+ if (REDIS_URL) checks.push(redis ? `${rgb(52, 211, 153)}✓${c.reset} ${c.white}Redis${c.reset}` : `${rgb(251, 191, 36)}○${c.reset} ${c.dim}Redis (connecting...)${c.reset}`);
2389
+ if (hasZlib) checks.push(`${rgb(52, 211, 153)}✓${c.reset} ${c.white}zlib${c.reset}`);
2390
+ if (WEBHOOK_URL) checks.push(`${rgb(52, 211, 153)}✓${c.reset} ${c.white}Webhook${c.reset}`);
2391
+ if (CLUSTER_ENABLED) {
2392
+ checks.push(`${rgb(52, 211, 153)}✓${c.reset} ${rgb(34, 211, 238)}Cluster${c.reset} ${c.dim}(${NODE_ID.substring(0, 12)})${c.reset}`);
2393
+ }
2400
2394
  checks.push(`${rgb(52, 211, 153)}✓${c.reset} ${c.white}${accounts.length} Account${accounts.length > 1 ? 's' : ''}${c.reset}`);
2401
- process.stdout.write(c.cursorUp(1));
2402
- process.stdout.write(c.clearLine + '\r');
2403
2395
  console.log(` ${checks.join(' ')}`);
2404
2396
  console.log('');
2405
2397
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dankgrinder",
3
- "version": "5.0.2",
3
+ "version": "5.0.3",
4
4
  "description": "Dank Memer automation engine — grind coins while you sleep",
5
5
  "bin": {
6
6
  "dankgrinder": "bin/dankgrinder.js"