dankgrinder 5.9.0 → 5.11.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.
@@ -42,7 +42,7 @@ async function runDig({ channel, waitForDankMemer, client }) {
42
42
  const missing = needsItem(cleanText);
43
43
 
44
44
  const shovelMissing = missing === 'shovel'
45
- || /(?:don't have|do not have|need|needs|requires?|missing|must have|you need|lack)\s+(?:a\s+)?shovel/.test(textLower)
45
+ || /(?:don['’]?t have|do not have|need|needs|requires?|missing|must have|you need|lack)\s+(?:a\s+)?shovel/.test(textLower)
46
46
  || (textLower.includes('following items') && textLower.includes('shovel'));
47
47
 
48
48
  // Check if we need a shovel
@@ -42,7 +42,7 @@ async function runHunt({ channel, waitForDankMemer, client }) {
42
42
  const missing = needsItem(cleanText);
43
43
 
44
44
  const rifleMissing = missing === 'hunting rifle'
45
- || /(?:don't have|do not have|need|needs|requires?|missing|must have|you need|lack)\s+(?:a\s+)?(?:hunting\s+)?rifle/.test(textLower)
45
+ || /(?:don['’]?t have|do not have|need|needs|requires?|missing|must have|you need|lack)\s+(?:a\s+)?(?:hunting\s+)?rifle/.test(textLower)
46
46
  || ((textLower.includes('following items') || textLower.includes('missing items')) && textLower.includes('rifle'));
47
47
 
48
48
  // Check if we need a rifle
@@ -16,7 +16,7 @@
16
16
  const {
17
17
  LOG, c, sleep, humanDelay, getFullText,
18
18
  getAllButtons, findSelectMenuOption,
19
- logMsg, isHoldTight,
19
+ logMsg, isHoldTight, isCV2, ensureCV2,
20
20
  } = require('./utils');
21
21
  const { LRUCache, Trie } = require('../structures');
22
22
 
@@ -100,6 +100,8 @@ async function buyItem({ channel, waitForDankMemer, itemName, quantity = 1, clie
100
100
  return false;
101
101
  }
102
102
 
103
+ if (isCV2(response)) await ensureCV2(response);
104
+
103
105
  logMsg(response, 'shop');
104
106
 
105
107
  // Step 2: Switch shop tab if needed (e.g. Fishing Shop for fishing pole)
@@ -129,6 +131,7 @@ async function buyItem({ channel, waitForDankMemer, itemName, quantity = 1, clie
129
131
  );
130
132
  if (result) {
131
133
  response = result;
134
+ if (isCV2(response)) await ensureCV2(response);
132
135
  LOG.success(`Switched to ${targetTab}`);
133
136
  }
134
137
  await sleep(300);
@@ -141,9 +144,14 @@ async function buyItem({ channel, waitForDankMemer, itemName, quantity = 1, clie
141
144
 
142
145
  // Step 3: Find the Buy button for our item
143
146
  const allBtns = getAllButtons(response);
147
+ const normalizedSearch = String(searchTerm || '').toLowerCase().replace(/\s+/g, '');
148
+ const normalizedKey = String(key || '').toLowerCase().replace(/\s+/g, '');
144
149
  const buyBtn = allBtns.find(b => {
145
- if (!b.label) return false;
146
- return b.label.toLowerCase().includes(searchTerm);
150
+ const label = String(b.label || '').toLowerCase();
151
+ const id = String(b.customId || b.custom_id || '').toLowerCase().replace(/\s+/g, '');
152
+ return label.includes(searchTerm)
153
+ || (normalizedSearch && id.includes(normalizedSearch))
154
+ || (normalizedKey && id.includes(normalizedKey));
147
155
  });
148
156
 
149
157
  if (!buyBtn) {
@@ -529,10 +529,16 @@ itemDetector.addPattern('missing items', '__multi__');
529
529
  itemDetector.build();
530
530
 
531
531
  function needsItem(text) {
532
- const match = itemDetector.hasAny(text);
532
+ const normalized = String(text || '')
533
+ .toLowerCase()
534
+ .normalize('NFKC')
535
+ .replace(/[’‘`´]/g, "'")
536
+ .replace(/\bdon'?t\b/g, "don't");
537
+
538
+ const match = itemDetector.hasAny(normalized);
533
539
  if (!match) return null;
534
540
  if (match === '__multi__') {
535
- const lower = text.toLowerCase();
541
+ const lower = normalized;
536
542
  if (lower.includes('shovel')) return 'shovel';
537
543
  if (lower.includes('fishing pole') || lower.includes('fishing')) return 'fishing pole';
538
544
  if (lower.includes('hunting rifle') || lower.includes('rifle')) return 'hunting rifle';
@@ -18,6 +18,7 @@
18
18
  const {
19
19
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton,
20
20
  logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay,
21
+ isCV2, ensureCV2, stripAnsi,
21
22
  } = require('./utils');
22
23
 
23
24
  const RE_MEMORY_BACKTICK_CHUNK = /`([^`]+)`/g;
@@ -26,6 +27,24 @@ const RE_WORK_COOLDOWN_TS = /<t:(\d+):R>/;
26
27
  const RE_WORK_COOLDOWN_MINUTES = /(\d+)\s*minute/i;
27
28
  const RE_WORK_COOLDOWN_HOURS = /(\d+)\s*hour/i;
28
29
 
30
+ function normalizeLower(text) {
31
+ return String(text || '')
32
+ .normalize('NFKC')
33
+ .replace(/[’‘`´]/g, "'")
34
+ .replace(/\bdon'?t\b/gi, "don't")
35
+ .toLowerCase();
36
+ }
37
+
38
+ function isNoJobText(text) {
39
+ const t = normalizeLower(stripAnsi(text)).replace(/\s+/g, ' ').trim();
40
+ return t.includes("don't currently have a job")
41
+ || t.includes("don't have a job")
42
+ || t.includes('no job to work at')
43
+ || t.includes('you need a job')
44
+ || t.includes('/work list')
45
+ || (t.includes('work list') && t.includes('available jobs'));
46
+ }
47
+
29
48
  // Job progression list (order matters — first is easiest to get)
30
49
  const JOBS = Object.freeze([
31
50
  'babysitter', 'dog walker', 'fast food worker', 'youtuber',
@@ -114,14 +133,15 @@ async function resignFromJob({ channel, waitForDankMemer }) {
114
133
  async function autoApplyForJob({ channel, waitForDankMemer }) {
115
134
  LOG.info('[work] No job! Applying for Babysitter...');
116
135
  await channel.send('pls work apply babysitter');
117
- const response = await waitForDankMemer(8000);
136
+ const response = await waitForDankMemer(10000);
118
137
  if (!response) {
119
138
  LOG.warn('[work] No response to apply');
120
139
  return { applied: false };
121
140
  }
141
+ if (isCV2(response)) await ensureCV2(response);
122
142
  logMsg(response, 'work-apply');
123
143
  const text = getFullText(response);
124
- const tl = text.toLowerCase();
144
+ const tl = normalizeLower(stripAnsi(text)).replace(/\s+/g, ' ').trim();
125
145
  if (tl.includes('congratulations') || tl.includes('now working')) {
126
146
  LOG.success('[work] Applied for Babysitter!');
127
147
  return { applied: true };
@@ -301,6 +321,8 @@ async function runWorkShift({ channel, waitForDankMemer }) {
301
321
  return { result: `hold tight (${reason || 'unknown'})`, coins: 0, holdTightReason: reason };
302
322
  }
303
323
 
324
+ if (isCV2(current)) await ensureCV2(current);
325
+
304
326
  logMsg(current, 'work');
305
327
  let text = getFullText(current);
306
328
 
@@ -314,11 +336,10 @@ async function runWorkShift({ channel, waitForDankMemer }) {
314
336
  return { result: `work cooldown (${Math.ceil(cooldownSec / 60)}m)`, coins: 0, nextCooldownSec: cooldownSec };
315
337
  }
316
338
 
317
- const textLower = text.toLowerCase();
339
+ const textLower = normalizeLower(stripAnsi(text)).replace(/\s+/g, ' ').trim();
318
340
 
319
341
  // ── No job? Auto-apply ─────────────────────────────────────
320
- if (textLower.includes("don't currently have a job") || textLower.includes('don\'t have a job') ||
321
- textLower.includes('you need a job') || textLower.includes('work list')) {
342
+ if (isNoJobText(textLower)) {
322
343
  const applyResult = await autoApplyForJob({ channel, waitForDankMemer });
323
344
  if (!applyResult.applied) {
324
345
  return { result: 'no job (apply failed)', coins: 0, nextCooldownSec: applyResult.cooldownSec || 600 };
@@ -331,6 +352,7 @@ async function runWorkShift({ channel, waitForDankMemer }) {
331
352
  await channel.send('pls work shift');
332
353
  current = await waitForDankMemer(10000);
333
354
  if (!current) return { result: 'no response after apply', coins: 0 };
355
+ if (isCV2(current)) await ensureCV2(current);
334
356
  logMsg(current, 'work-after-apply');
335
357
  text = getFullText(current);
336
358
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dankgrinder",
3
- "version": "5.9.0",
3
+ "version": "5.11.0",
4
4
  "description": "Dank Memer automation engine — grind coins while you sleep",
5
5
  "bin": {
6
6
  "dankgrinder": "bin/dankgrinder.js"