dankgrinder 7.58.0 → 7.62.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.
@@ -4,12 +4,14 @@
4
4
  * Handles sell listings with optional partial sales and privacy settings.
5
5
  *
6
6
  * Dank Memer market post format:
7
- * pls market post for_coins <listing_type> <qty> <item> <price> <days> <allow_partial> <is_private> <partial_min>
7
+ * pls market post for_coins <listing_type> <qty> <item> <price>
8
+ * <allow_partial> <is_private> <partial_min> <days>
8
9
  *
9
10
  * listing_type: "sell" | "auction"
10
11
  * allow_partial: "true" | "false"
11
12
  * is_private: "true" | "false"
12
- * partial_min: only meaningful when allow_partial is true
13
+ * partial_min: integer 1
14
+ * days: 1-7
13
15
  */
14
16
 
15
17
  const {
@@ -48,17 +50,19 @@ async function runMarketPost({
48
50
  return { result: 'no item specified', coins: 0 };
49
51
  }
50
52
 
53
+ // Dank Memer expects: <qty> <item> <price> <allow_partial> <is_private> <days> <partial_min>
54
+ // Note: allow_partial and is_private come BEFORE days (verified via test-market.js)
51
55
  const cmdParts = [
52
56
  'pls', 'market', 'post',
53
- 'for_coins', // price type: "for_coins" fixed price
54
- 'sell', // listing type: "sell" | "auction"
55
- String(quantity), // quantity
56
- itemName, // item name
57
- String(pricePerItem * quantity), // TOTAL price (price per item × quantity)
58
- String(days), // days (1-7)
59
- allowPartial ? 'true' : 'false', // allow partial
60
- isPrivate ? 'true' : 'false', // is private
61
- String(allowPartial ? partialMin : 0), // partial minimum (only meaningful when allowPartial is true)
57
+ 'for_coins', // price type: fixed price
58
+ 'sell', // listing type
59
+ String(quantity), // quantity
60
+ itemName, // item name
61
+ String(pricePerItem * quantity), // TOTAL price
62
+ allowPartial ? 'true' : 'false', // allow partial
63
+ isPrivate ? 'true' : 'false', // is private
64
+ String(Math.max(1, partialMin || 1)), // partial minimum (always ≥1)
65
+ String(days), // days (1-7)
62
66
  ];
63
67
 
64
68
  const cmdString = cmdParts.join(' ');
@@ -84,7 +88,7 @@ async function runMarketPost({
84
88
 
85
89
  // Check for common errors
86
90
  const lowerText = text.toLowerCase();
87
- if (lowerText.includes('you don\'t have') || lowerText.includes('not enough') || lowerText.includes('invalid item') || lowerText.includes('partial minimum can\'t') || lowerText.includes('set allow_partial')) {
91
+ if (lowerText.includes('you don\'t have') || lowerText.includes('not enough') || lowerText.includes('invalid item') || lowerText.includes('partial minimum can\'t') || lowerText.includes('set allow_partial') || lowerText.includes('allow_partial is incorrect') || lowerText.includes('allow_partial')) {
88
92
  return { result: text.substring(0, 80) || 'error listing item', coins: 0 };
89
93
  }
90
94
 
package/lib/grinder.js CHANGED
@@ -586,7 +586,7 @@ function renderDashboard() {
586
586
 
587
587
  for (const wk of visibleWorkers) {
588
588
  const origNum = (wk.idx + 1).toString().padStart(colNum);
589
- const rawStat = (wk.lastStatus || 'idle').replace(RE, '');
589
+ const rawStat = (wk.lastStatus || 'ready').replace(RE, '');
590
590
  const activityText = rawStat.substring(0, colActivity);
591
591
 
592
592
  // ── Status icon ──
@@ -1133,6 +1133,7 @@ class AccountWorker {
1133
1133
  this.lastRunTime = {};
1134
1134
  this.cycleCount = 0;
1135
1135
  this.lastCommandRun = 0;
1136
+ this.lastStatus = 'ready';
1136
1137
  this.paused = false;
1137
1138
  this.dashboardPaused = false;
1138
1139
  this._sellRunning = false;
@@ -1815,7 +1816,8 @@ class AccountWorker {
1815
1816
  if (currentLevel > 0) {
1816
1817
  await redis.set(`dkg:level:${this.account.id}`, String(currentLevel), 'EX', 2592000);
1817
1818
  this._level = currentLevel;
1818
- this.log('info', `DM level: ${c.bold}${currentLevel}${c.reset}`);
1819
+ // Only log to terminal during startup — after dashboardStarted, go to live feed
1820
+ if (dashboardStarted) this.log('info', `DM level: ${c.bold}${currentLevel}${c.reset}`);
1819
1821
  }
1820
1822
  if (lastLifesaverCount >= 0) {
1821
1823
  await redis.set(`dkg:lifesavers:${this.account.id}`, String(lastLifesaverCount), 'EX', 86400);
@@ -1823,7 +1825,7 @@ class AccountWorker {
1823
1825
  if (lastLifesaverCount === 0) {
1824
1826
  await redis.set(`raw:alert:no-lifesaver:${dm.id}`, '1', 'EX', 86400);
1825
1827
  await redis.set(`raw:alert:no-lifesaver:${this.channel?.id}`, '1', 'EX', 86400);
1826
- this.log('error', `${c.red}0 LIFESAVERS! Crime/Search will be disabled.${c.reset}`);
1828
+ if (dashboardStarted) this.log('error', `${c.red}0 LIFESAVERS! Crime/Search will be disabled.${c.reset}`);
1827
1829
  }
1828
1830
  }
1829
1831
  }
@@ -1836,7 +1838,7 @@ class AccountWorker {
1836
1838
  }
1837
1839
  }
1838
1840
  }
1839
- this.log('debug', `DM check failed after ${maxRetries} attempts: ${lastError.message}`);
1841
+ if (dashboardStarted) this.log('debug', `DM check failed after ${maxRetries} attempts: ${lastError.message}`);
1840
1842
  return { deaths: 0, levelUps: 0, currentLevel: 0, lifesavers: -1 };
1841
1843
  }
1842
1844
 
@@ -3646,12 +3648,12 @@ async function start(apiKey, apiUrl, opts = {}) {
3646
3648
  parts.push(`${D}${pulse}♥?${c.reset}`);
3647
3649
  }
3648
3650
  if (parts.length > 0) {
3649
- console.log(` ${c.dim}├${c.reset} ${c.bold}${w.username}${c.reset} ${parts.join(' ')}`);
3651
+ recentLogs.push({ ts: Date.now(), username: w.username, color: w.color, command: 'dm check', response: parts.join(' '), status: 'ok' });
3650
3652
  }
3651
3653
  } catch {}
3652
3654
  }
3653
3655
  if (dmNoLs.length > 0) {
3654
- console.log(` ${rgb(239, 68, 68)}⚠${c.reset} ${c.bold}${c.red}DM confirms 0 lifesavers:${c.reset} ${dmNoLs.join(', ')}`);
3656
+ recentLogs.push({ ts: Date.now(), username: 'system', color: rgb(239, 68, 68), command: 'dm check', response: `⚠ No lifesavers: ${dmNoLs.join(', ')}`, status: 'warn' });
3655
3657
  // Set Redis keys to block crime/search
3656
3658
  for (const w of activeWorkers) {
3657
3659
  if (dmNoLs.includes(w.username) && redis) {
@@ -3663,7 +3665,7 @@ async function start(apiKey, apiUrl, opts = {}) {
3663
3665
  }
3664
3666
  }
3665
3667
  if (dmUnknown.length > 0) {
3666
- console.log(` ${rgb(251, 191, 36)}⚠${c.reset} ${c.dim}Lifesavers unknown — live DM monitor active:${c.reset} ${dmUnknown.join(', ')}`);
3668
+ recentLogs.push({ ts: Date.now(), username: 'system', color: rgb(251, 191, 36), command: 'dm check', response: `⚠ Lifesavers unknown — live monitor: ${dmUnknown.join(', ')}`, status: 'warn' });
3667
3669
  // Crime/search on these accounts will be skipped via safety hold until the live
3668
3670
  // DM gateway listener detects a death (→ sets count) or confirms clean.
3669
3671
  }
@@ -3671,7 +3673,7 @@ async function start(apiKey, apiUrl, opts = {}) {
3671
3673
  if (dmDeaths > 0) dmSummaryParts.push(`${dmDeaths} deaths`);
3672
3674
  if (dmLevelUps > 0) dmSummaryParts.push(`${dmLevelUps} level-ups`);
3673
3675
  if (dmUnknown.length > 0) dmSummaryParts.push(`${dmUnknown.length} pending`);
3674
- console.log(` ${rgb(52, 211, 153)}✓${c.reset} ${c.bold}DM check${c.reset} ${dmSummaryParts.length > 0 ? c.dim + dmSummaryParts.join(', ') + c.reset : c.dim + 'clean — no deaths or level-ups' + c.reset}`);
3676
+ recentLogs.push({ ts: Date.now(), username: 'system', color: rgb(52, 211, 153), command: 'dm check', response: dmSummaryParts.length > 0 ? dmSummaryParts.join(', ') : 'clean — no deaths or level-ups', status: 'ok' });
3675
3677
  console.log('');
3676
3678
 
3677
3679
  console.log(` ${rgb(139, 92, 246)}${c.bold}>>>${c.reset} ${gradientText('Starting grind loops...', [139, 92, 246], [52, 211, 153])}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dankgrinder",
3
- "version": "7.58.0",
3
+ "version": "7.62.0",
4
4
  "description": "Dank Memer automation engine — grind coins while you sleep",
5
5
  "bin": {
6
6
  "dankgrinder": "bin/dankgrinder.js"