dankgrinder 8.110.0 → 8.112.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.
@@ -37,6 +37,7 @@ const {
37
37
  LOG, c, sleep, humanDelay, getFullText, parseCoins,
38
38
  getAllButtons, getAllSelectMenus, findButton,
39
39
  safeClickButton, isHoldTight, logMsg, checkLevelLock,
40
+ sendCommand,
40
41
  } = require('./utils');
41
42
 
42
43
  const RE_DISCORD_TIMESTAMP = /<t:(\d+)(?::[tTdDfFR])?>/g;
@@ -276,13 +277,15 @@ async function playAdventureRounds(channel, msg, adventureAnswers) {
276
277
  * @param {function} opts.waitForDankMemer - Waits for Dank Memer response
277
278
  * @param {object} [opts.client] - Discord client (for modal handling in shop)
278
279
  * @param {object} [opts.adventureAnswers] - Per-type answer map from AccountWorker.ADVENTURE_ANSWERS
280
+ * @param {boolean} [opts.useSlash] - Use Discord slash command API instead of text
281
+ * @param {string} [opts.prefix] - Text prefix ('pls' or '/')
279
282
  * @returns {Promise<{result: string, coins: number, nextCooldownSec: number|null}>}
280
283
  */
281
- async function runAdventure({ channel, waitForDankMemer, client, adventureAnswers }) {
284
+ async function runAdventure({ channel, waitForDankMemer, client, adventureAnswers, useSlash, prefix = 'pls' }) {
282
285
  LOG.cmd(`${c.white}${c.bold}pls adventure${c.reset}`);
283
286
 
284
287
  // Step 1: Send the command
285
- await channel.send('pls adventure');
288
+ await sendCommand(channel, 'adventure', { useSlash, prefix });
286
289
  let response = await waitForDankMemer(12000);
287
290
 
288
291
  if (!response) {
@@ -3,7 +3,8 @@
3
3
  * Simple command: send "pls beg", parse coins from response.
4
4
  */
5
5
 
6
- const { LOG, c, getFullText, parseCoins, logMsg, isHoldTight, getHoldTightReason, sleep, checkLevelLock } = require('./utils');
6
+ const { LOG, c, getFullText, parseCoins, logMsg, isHoldTight, getHoldTightReason, sleep, checkLevelLock,
7
+ sendCommand, } = require('./utils');
7
8
 
8
9
  const RE_NEWLINE = /\n/g;
9
10
 
@@ -16,7 +17,7 @@ const RE_NEWLINE = /\n/g;
16
17
  async function runBeg({ channel, waitForDankMemer }) {
17
18
  LOG.cmd(`${c.white}${c.bold}pls beg${c.reset}`);
18
19
 
19
- await channel.send('pls beg');
20
+ await sendCommand(channel, 'beg', { useSlash, prefix });
20
21
  const response = await waitForDankMemer(10000);
21
22
 
22
23
  if (!response) {
@@ -7,6 +7,7 @@
7
7
  const {
8
8
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton,
9
9
  logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay, ensureCV2, checkLevelLock,
10
+ sendCommand,
10
11
  } = require('./utils');
11
12
 
12
13
  const RE_BACKTICK_SCORE = /`\s*(\d+)\s*`/;
@@ -133,11 +134,11 @@ async function clickFast(msg, btn, retries = 2) {
133
134
  return null;
134
135
  }
135
136
 
136
- async function runBlackjack({ channel, waitForDankMemer, betAmount = 5000 }) {
137
- const cmd = `pls bj ${betAmount}`;
137
+ async function runBlackjack({ channel, waitForDankMemer, betAmount = 5000, useSlash, prefix = 'pls' }) {
138
+ const cmdName = 'bj';
139
+ const cmd = `${prefix} ${cmdName} ${betAmount}`;
138
140
  LOG.cmd(`${c.white}${c.bold}${cmd}${c.reset}`);
139
-
140
- await channel.send(cmd);
141
+ await sendCommand(channel, cmdName, { useSlash, prefix, args: [betAmount] });
141
142
  let current = await waitForDankMemer(12000);
142
143
 
143
144
  if (!current) {
@@ -12,6 +12,7 @@ const {
12
12
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton,
13
13
  logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay,
14
14
  isCV2, ensureCV2, checkLevelLock,
15
+ sendCommand,
15
16
  } = require('./utils');
16
17
  const { Trie, VoseAlias, LRUCache } = require('../structures');
17
18
 
@@ -86,7 +87,7 @@ function pickSafeButton(buttons, customSafe) {
86
87
  async function runCrime({ channel, waitForDankMemer, safeAnswers }) {
87
88
  LOG.cmd(`${c.white}${c.bold}pls crime${c.reset}`);
88
89
 
89
- await channel.send('pls crime');
90
+ await sendCommand(channel, 'crime', { useSlash, prefix });
90
91
  const response = await waitForDankMemer(10000);
91
92
 
92
93
  if (!response) {
@@ -5,6 +5,7 @@
5
5
 
6
6
  const {
7
7
  LOG, c, getFullText, parseCoins, logMsg, isHoldTight, getHoldTightReason, sleep,
8
+ sendCommand,
8
9
  } = require('./utils');
9
10
 
10
11
  /**
@@ -16,7 +17,7 @@ const {
16
17
  async function runDeposit({ channel, waitForDankMemer }) {
17
18
  LOG.cmd(`${c.white}${c.bold}pls dep max${c.reset}`);
18
19
 
19
- await channel.send('pls dep max');
20
+ await sendCommand(channel, 'dep max', { useSlash, prefix });
20
21
  const response = await waitForDankMemer(10000);
21
22
 
22
23
  if (!response) {
@@ -7,6 +7,7 @@ const {
7
7
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton, humanDelay,
8
8
  logMsg, isHoldTight, getHoldTightReason, sleep, needsItem,
9
9
  isCV2, ensureCV2, stripAnsi, checkLevelLock,
10
+ sendCommand,
10
11
  } = require('./utils');
11
12
  const { buyItem } = require('./shop');
12
13
 
@@ -96,7 +97,7 @@ async function resolveDigFlow({ channel, waitForDankMemer, response }) {
96
97
  async function runDig({ channel, waitForDankMemer, client }) {
97
98
  LOG.cmd(`${c.white}${c.bold}pls dig${c.reset}`);
98
99
 
99
- await channel.send('pls dig');
100
+ await sendCommand(channel, 'dig', { useSlash, prefix });
100
101
  const response = await waitForDankMemer(10000);
101
102
 
102
103
  if (!response) {
@@ -142,7 +143,7 @@ async function runDig({ channel, waitForDankMemer, client }) {
142
143
  while (await waitForDankMemer(1500)) { /* drain */ }
143
144
  await sleep(1000);
144
145
 
145
- await channel.send('pls dig');
146
+ await sendCommand(channel, 'dig', { useSlash, prefix });
146
147
  const r2 = await waitForDankMemer(10000);
147
148
  if (r2) {
148
149
  if (isCV2(r2)) await ensureCV2(r2);
@@ -1,6 +1,7 @@
1
1
  const {
2
2
  LOG, c, getFullText, parseCoins, getAllButtons,
3
3
  safeClickButton, logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay,
4
+ sendCommand,
4
5
  } = require('./utils');
5
6
 
6
7
  const RE_BLOCK_SPLIT = /\n\n+/;
@@ -16,7 +17,7 @@ const RE_WHITESPACE_UNDERSCORE = /\s+/g;
16
17
  async function runDrops({ channel, waitForDankMemer, redis, accountId }) {
17
18
  LOG.cmd(`${c.white}${c.bold}pls drops${c.reset}`);
18
19
 
19
- await channel.send('pls drops');
20
+ await sendCommand(channel, 'drops', { useSlash, prefix });
20
21
  const response = await waitForDankMemer(10000);
21
22
 
22
23
  if (!response) return { result: 'no response', coins: 0 };
@@ -2,6 +2,7 @@ const {
2
2
  LOG, c, getFullText, parseCoins, getAllButtons, getAllSelectMenus,
3
3
  safeClickButton, logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay,
4
4
  isCV2, ensureCV2, stripAnsi, needsItem, clickCV2SelectMenu, checkLevelLock,
5
+ sendCommand,
5
6
  } = require('./utils');
6
7
  const { buyItem, buyItemsBatch } = require('./shop');
7
8
  const rawLogger = require('../../lib/rawLogger');
@@ -1295,7 +1296,7 @@ async function advancePastConfirmation(response, waitForDankMemer) {
1295
1296
  async function runFarm({ channel, waitForDankMemer, client, redis, accountId, forceRun }) {
1296
1297
  LOG.cmd(`${c.white}${c.bold}pls farm view${c.reset}`);
1297
1298
 
1298
- await channel.send('pls farm view');
1299
+ await sendCommand(channel, 'farm view', { useSlash, prefix });
1299
1300
  let response = await waitForDankMemer(12000);
1300
1301
 
1301
1302
  if (!response) {
@@ -1322,7 +1323,7 @@ async function runFarm({ channel, waitForDankMemer, client, redis, accountId, fo
1322
1323
  // Subcommand required — retry once.
1323
1324
  if (lower.includes('must specify a subcommand')) {
1324
1325
  LOG.warn('[farm] Subcommand required; retrying "pls farm view"');
1325
- await channel.send('pls farm view');
1326
+ await sendCommand(channel, 'farm view', { useSlash, prefix });
1326
1327
  const retry = await waitForDankMemer(12000);
1327
1328
  if (!retry) return { result: 'no response after farm view retry', coins: 0, nextCooldownSec: 120 };
1328
1329
  response = retry;
@@ -1383,7 +1384,7 @@ async function runFarm({ channel, waitForDankMemer, client, redis, accountId, fo
1383
1384
  LOG.success(`[farm] Auto-bought ${bought.itemName}. Retrying farm flow...`);
1384
1385
  await sleep(1200);
1385
1386
  // Retry once with the same flow.
1386
- await channel.send('pls farm view');
1387
+ await sendCommand(channel, 'farm view', { useSlash, prefix });
1387
1388
  response = await waitForDankMemer(12000);
1388
1389
  if (!response) return { result: 'no response after retry', coins: 0, nextCooldownSec: 90 };
1389
1390
  if (isCV2(response)) await ensureCV2(response);
@@ -1474,7 +1475,7 @@ async function runFarm({ channel, waitForDankMemer, client, redis, accountId, fo
1474
1475
  LOG.success(`[farm] Bought ${missing}. Retrying cycle...`);
1475
1476
  await sleep(1200);
1476
1477
  // Restart the whole cycle after buying
1477
- await channel.send('pls farm view');
1478
+ await sendCommand(channel, 'farm view', { useSlash, prefix });
1478
1479
  const re = await waitForDankMemer(12000);
1479
1480
  if (!re) return { result: 'no response after restock retry', coins: 0, nextCooldownSec: 90 };
1480
1481
  if (isCV2(re)) await ensureCV2(re);
@@ -17,12 +17,10 @@
17
17
  const {
18
18
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton,
19
19
  logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay,
20
- isCV2, ensureCV2, checkLevelLock,
20
+ isCV2, ensureCV2, checkLevelLock, sendCommand,
21
21
  } = require('./utils');
22
22
  const { downloadImage, extractImageUrl, findSafeCells } = require('./fishVision');
23
23
 
24
- const { DANK_MEMER_ID } = require('./utils');
25
-
26
24
  const RE_FISH_COOLDOWN_TS = /<t:(\d+):R>/;
27
25
  const RE_FISH_HEADER = /###\s*(.+?)(?:\s*-#|$)/;
28
26
  const RE_CAUGHT_PHRASE = /caught\s+(?:a\s+)?(.+?)(?:\s*[!.]|$)/i;
@@ -41,7 +39,7 @@ async function refetchMsg(channel, msgId) {
41
39
  */
42
40
  async function sellAllFish({ channel, waitForDankMemer, sellFor = 'tokens' }) {
43
41
  LOG.info('[fish] Selling all fish from buckets...');
44
- await channel.send('pls fish buckets');
42
+ await sendCommand(channel, 'fish buckets', { useSlash, prefix });
45
43
  let msg = await waitForDankMemer(8000);
46
44
  if (!msg) { LOG.warn('[fish] No response to pls fish buckets'); return false; }
47
45
  let fresh = await refetchMsg(channel, msg.id);
@@ -308,7 +306,7 @@ async function playFishRound({ gameMsg, channel, msgId, waitForDankMemer }) {
308
306
  async function runFish({ channel, waitForDankMemer }) {
309
307
  LOG.cmd(`${c.white}${c.bold}pls fish catch${c.reset}`);
310
308
 
311
- await channel.send('pls fish catch');
309
+ await sendCommand(channel, 'fish catch', { useSlash, prefix });
312
310
  let response = await waitForDankMemer(10000);
313
311
  if (!response) return { result: 'no response', coins: 0 };
314
312
 
@@ -393,7 +391,7 @@ async function runFish({ channel, waitForDankMemer }) {
393
391
  async function runFishLoop({ channel, waitForDankMemer, maxRounds = 50, onRound, signal }) {
394
392
  LOG.cmd(`${c.white}${c.bold}pls fish catch${c.reset} (loop mode, max ${maxRounds} rounds)`);
395
393
 
396
- await channel.send('pls fish catch');
394
+ await sendCommand(channel, 'fish catch', { useSlash, prefix });
397
395
  let response = await waitForDankMemer(10000);
398
396
  if (!response) return { totalRounds: 0, totalCaught: 0, totalMines: 0, results: [] };
399
397
 
@@ -437,7 +435,7 @@ async function runFishLoop({ channel, waitForDankMemer, maxRounds = 50, onRound,
437
435
  await sellAllFish({ channel, waitForDankMemer });
438
436
 
439
437
  // Re-send command to get fresh dashboard after sell
440
- await channel.send('pls fish catch');
438
+ await sendCommand(channel, 'fish catch', { useSlash, prefix });
441
439
  let newDash = await waitForDankMemer(8000);
442
440
  if (newDash) {
443
441
  let freshDash = await refetchMsg(channel, newDash.id);
@@ -569,7 +567,7 @@ async function runFishLoop({ channel, waitForDankMemer, maxRounds = 50, onRound,
569
567
  // Approach 2: If Fish Again not found, re-send "pls fish catch" fresh
570
568
  if (!fishAgainClicked) {
571
569
  LOG.debug('[fish] Fish Again not found, re-sending pls fish catch');
572
- await channel.send('pls fish catch');
570
+ await sendCommand(channel, 'fish catch', { useSlash, prefix });
573
571
  let newResp = await waitForDankMemer(8000);
574
572
  if (!newResp) { LOG.warn('[fish] No response to re-send'); break; }
575
573
  let freshResp = await refetchMsg(channel, newResp.id);
@@ -12,6 +12,7 @@
12
12
  const {
13
13
  LOG, c, getFullText, parseCoins, parseNetCoins, getAllButtons, safeClickButton,
14
14
  logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay, ensureCV2, checkLevelLock,
15
+ sendCommand,
15
16
  } = require('./utils');
16
17
  const { EMA, AhoCorasick, SlidingWindowCounter } = require('../structures');
17
18
 
@@ -143,10 +144,11 @@ async function clickFast(msg, btn, retries = 2) {
143
144
  /**
144
145
  * Cointoss — CV2 format. Pick Heads/Tails randomly.
145
146
  */
146
- async function runCointoss({ channel, waitForDankMemer, betAmount = 10000 }) {
147
- const cmd = `pls cointoss ${betAmount}`;
147
+ async function runCointoss({ channel, waitForDankMemer, betAmount = 10000, useSlash, prefix = 'pls' }) {
148
+ const cmdName = 'cointoss';
149
+ const cmd = `${prefix} ${cmdName} ${betAmount}`;
148
150
  LOG.cmd(`${c.white}${c.bold}${cmd}${c.reset}`);
149
- await channel.send(cmd);
151
+ await sendCommand(channel, cmdName, { useSlash, prefix, args: [betAmount] });
150
152
  let response = await waitForDankMemer(12000);
151
153
 
152
154
  await ensureCV2(response);
@@ -184,12 +186,13 @@ async function runCointoss({ channel, waitForDankMemer, betAmount = 10000 }) {
184
186
  * Roulette — pick color, click button, wait for result.
185
187
  * Strategy: ~47.5% red, ~47.5% black, ~5% green.
186
188
  */
187
- async function runRoulette({ channel, waitForDankMemer, betAmount = 10000 }) {
189
+ async function runRoulette({ channel, waitForDankMemer, betAmount = 10000, useSlash, prefix = 'pls' }) {
188
190
  const roll = Math.random();
189
191
  const color = roll < 0.475 ? 'red' : roll < 0.95 ? 'black' : 'green';
190
- const cmd = `pls roulette ${betAmount} ${color}`;
192
+ const cmdName = 'roulette';
193
+ const cmd = `${prefix} ${cmdName} ${betAmount} ${color}`;
191
194
  LOG.cmd(`${c.white}${c.bold}${cmd}${c.reset}`);
192
- await channel.send(cmd);
195
+ await sendCommand(channel, cmdName, { useSlash, prefix, args: [betAmount, color] });
193
196
  let response = await waitForDankMemer(12000);
194
197
 
195
198
  const chk = await commonChecks(response, 'roulette');
@@ -227,10 +230,11 @@ async function runRoulette({ channel, waitForDankMemer, betAmount = 10000 }) {
227
230
  /**
228
231
  * Slots — auto-spin, wait for animation to finish, parse result.
229
232
  */
230
- async function runSlots({ channel, waitForDankMemer, betAmount = 10000 }) {
231
- const cmd = `pls slots ${betAmount}`;
233
+ async function runSlots({ channel, waitForDankMemer, betAmount = 10000, useSlash, prefix = 'pls' }) {
234
+ const cmdName = 'slots';
235
+ const cmd = `${prefix} ${cmdName} ${betAmount}`;
232
236
  LOG.cmd(`${c.white}${c.bold}${cmd}${c.reset}`);
233
- await channel.send(cmd);
237
+ await sendCommand(channel, cmdName, { useSlash, prefix, args: [betAmount] });
234
238
  let response = await waitForDankMemer(12000);
235
239
 
236
240
  const chk = await commonChecks(response, 'slots');
@@ -258,10 +262,11 @@ async function runSlots({ channel, waitForDankMemer, betAmount = 10000 }) {
258
262
  /**
259
263
  * Snakeeyes — auto-roll, wait for animation to finish, parse result.
260
264
  */
261
- async function runSnakeeyes({ channel, waitForDankMemer, betAmount = 10000 }) {
262
- const cmd = `pls snakeeyes ${betAmount}`;
265
+ async function runSnakeeyes({ channel, waitForDankMemer, betAmount = 10000, useSlash, prefix = 'pls' }) {
266
+ const cmdName = 'snakeeyes';
267
+ const cmd = `${prefix} ${cmdName} ${betAmount}`;
263
268
  LOG.cmd(`${c.white}${c.bold}${cmd}${c.reset}`);
264
- await channel.send(cmd);
269
+ await sendCommand(channel, cmdName, { useSlash, prefix, args: [betAmount] });
265
270
  let response = await waitForDankMemer(12000);
266
271
 
267
272
  const chk = await commonChecks(response, 'snakeeyes');
@@ -11,7 +11,7 @@
11
11
  const {
12
12
  LOG, c, getFullText, parseCoins, getAllButtons, getAllSelectMenus,
13
13
  safeClickButton, logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay, needsItem,
14
- isCV2, ensureCV2, stripAnsi,
14
+ isCV2, ensureCV2, stripAnsi, sendCommand,
15
15
  } = require('./utils');
16
16
  const { buyItem } = require('./shop');
17
17
  const { AhoCorasick, LRUCache } = require('../structures');
@@ -50,10 +50,15 @@ async function waitForEditedMessage(channel, messageId, baselineText, timeoutMs
50
50
  * @param {object} [opts.client]
51
51
  * @returns {Promise<{result: string, coins: number}>}
52
52
  */
53
- async function runGeneric({ channel, waitForDankMemer, cmdString, cmdName, client }) {
53
+ async function runGeneric({ channel, waitForDankMemer, cmdString, cmdName, client, useSlash, prefix = 'pls' }) {
54
54
  LOG.cmd(`${c.white}${c.bold}${cmdString}${c.reset}`);
55
-
56
- await channel.send(cmdString);
55
+ // cmdString = "pls farm view" or "/farm view"
56
+ // Build slash command: strip prefix → "farm view" → sendSlash('farm view')
57
+ const slashName = cmdString
58
+ .replace(/^pls\s+/, '')
59
+ .replace(/^\/\s*/, '')
60
+ .trim();
61
+ await sendCommand(channel, slashName, { useSlash, prefix });
57
62
  let response = await waitForDankMemer(10000);
58
63
 
59
64
  if (!response) {
@@ -82,7 +87,7 @@ async function runGeneric({ channel, waitForDankMemer, cmdString, cmdName, clien
82
87
  if (bought) {
83
88
  LOG.success(`[${cmdName}] Bought ${missing}, retrying command...`);
84
89
  await sleep(1500);
85
- await channel.send(cmdString);
90
+ await sendCommand(channel, cmdName, { useSlash, prefix });
86
91
  const r2 = await waitForDankMemer(10000);
87
92
  if (r2) {
88
93
  logMsg(r2, `${cmdName}-retry`);
@@ -209,7 +214,7 @@ async function runGeneric({ channel, waitForDankMemer, cmdString, cmdName, clien
209
214
  async function runAlert({ channel, waitForDankMemer }) {
210
215
  LOG.cmd(`${c.white}${c.bold}pls alert${c.reset}`);
211
216
 
212
- await channel.send('pls alert');
217
+ await sendCommand(channel, 'alert', { useSlash, prefix });
213
218
  const response = await waitForDankMemer(10000);
214
219
 
215
220
  if (!response) return { result: 'no response', coins: 0 };
@@ -7,6 +7,7 @@
7
7
  const {
8
8
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton,
9
9
  logMsg, isHoldTight, getHoldTightReason, sleep, checkLevelLock,
10
+ sendCommand,
10
11
  } = require('./utils');
11
12
 
12
13
  const RE_HINT_BOLD = /hint.*?\*\*(\d+)\*\*/i;
@@ -129,7 +130,7 @@ async function playHighLow(response, depth = 0) {
129
130
  async function runHighLow({ channel, waitForDankMemer }) {
130
131
  LOG.cmd(`${c.white}${c.bold}pls hl${c.reset}`);
131
132
 
132
- await channel.send('pls hl');
133
+ await sendCommand(channel, 'hl', { useSlash, prefix });
133
134
  const response = await waitForDankMemer(12000);
134
135
 
135
136
  if (!response) {
@@ -8,6 +8,7 @@ const {
8
8
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton,
9
9
  logMsg, isHoldTight, getHoldTightReason, sleep, needsItem,
10
10
  isCV2, ensureCV2, stripAnsi, checkLevelLock,
11
+ sendCommand,
11
12
  } = require('./utils');
12
13
  const { buyItem } = require('./shop');
13
14
 
@@ -80,7 +81,7 @@ function pickDodgeLane(dragonPos, buttons) {
80
81
  async function runHunt({ channel, waitForDankMemer, client }) {
81
82
  LOG.cmd(`${c.white}${c.bold}pls hunt${c.reset}`);
82
83
 
83
- await channel.send('pls hunt');
84
+ await sendCommand(channel, 'hunt', { useSlash, prefix });
84
85
  const response = await waitForDankMemer(12000);
85
86
 
86
87
  if (!response) {
@@ -118,7 +119,7 @@ async function runHunt({ channel, waitForDankMemer, client }) {
118
119
  LOG.success('[hunt] Rifle bought! Retrying...');
119
120
  while (await waitForDankMemer(1500)) {}
120
121
  await sleep(1000);
121
- await channel.send('pls hunt');
122
+ await sendCommand(channel, 'hunt', { useSlash, prefix });
122
123
  const r2 = await waitForDankMemer(12000);
123
124
  if (r2) {
124
125
  if (isCV2(r2)) await ensureCV2(r2);
@@ -15,6 +15,7 @@ const {
15
15
  LOG, c, sleep, humanDelay, getFullText, getAllButtons,
16
16
  safeClickButton, logMsg, isHoldTight, getHoldTightReason,
17
17
  isCV2, ensureCV2,
18
+ sendCommand,
18
19
  } = require('./utils');
19
20
  const { Trie, LRUCache } = require('../structures');
20
21
 
@@ -197,7 +198,7 @@ async function enrichItems(items) {
197
198
  async function runInventory({ channel, waitForDankMemer, client, accountId, redis, onPageProgress }) {
198
199
  LOG.cmd(`${c.white}${c.bold}pls inv${c.reset}`);
199
200
 
200
- await channel.send('pls inv');
201
+ await sendCommand(channel, 'inv', { useSlash, prefix });
201
202
  let response = await waitForDankMemer(10000);
202
203
 
203
204
  if (!response) {
@@ -16,6 +16,7 @@ const {
16
16
  LOG, c, getFullText, parseCoins, getAllButtons, getAllSelectMenus,
17
17
  findButton, safeClickButton, logMsg, isHoldTight, getHoldTightReason,
18
18
  sleep, humanDelay, checkLevelLock,
19
+ sendCommand,
19
20
  } = require('./utils');
20
21
 
21
22
  const RE_COOLDOWN_MIN = /(\d+)\s*minute/i;
@@ -37,7 +38,7 @@ async function refetchMsg(channel, msgId) {
37
38
  async function runPostMemes({ channel, waitForDankMemer }) {
38
39
  LOG.cmd(`${c.white}${c.bold}pls pm${c.reset}`);
39
40
 
40
- await channel.send('pls pm');
41
+ await sendCommand(channel, 'pm', { useSlash, prefix });
41
42
  let response = await waitForDankMemer(10000);
42
43
 
43
44
  if (!response) {
@@ -7,6 +7,7 @@
7
7
 
8
8
  const {
9
9
  LOG, c, getFullText, logMsg, isHoldTight, sleep, stripAnsi,
10
+ sendCommand,
10
11
  } = require('./utils');
11
12
 
12
13
  const CACHE_TTL = 10 * 60 * 1000; // 10 minutes
@@ -175,7 +176,7 @@ async function getPlayerLevel({ channel, waitForDankMemer, accountId = 'default'
175
176
  }
176
177
  } catch {}
177
178
  }
178
- await channel.send('pls profile');
179
+ await sendCommand(channel, 'profile', { useSlash, prefix });
179
180
  const response = await waitForDankMemer(8000);
180
181
  if (!response) { LOG.warn('[profile] No response'); return null; }
181
182
  if (isHoldTight(response)) { await sleep(5000); return null; }
@@ -202,7 +203,7 @@ async function getPlayerLevel({ channel, waitForDankMemer, accountId = 'default'
202
203
  */
203
204
  async function runProfile({ channel, waitForDankMemer, accountId = 'default', redis }) {
204
205
  LOG.cmd(`${c.white}${c.bold}pls profile${c.reset}`);
205
- await channel.send('pls profile');
206
+ await sendCommand(channel, 'profile', { useSlash, prefix });
206
207
  const response = await waitForDankMemer(8000);
207
208
  if (!response) {
208
209
  LOG.warn('[profile] No response');
@@ -7,6 +7,7 @@
7
7
  const {
8
8
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton,
9
9
  logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay, checkLevelLock,
10
+ sendCommand,
10
11
  } = require('./utils');
11
12
  const { meetsLevelRequirement } = require('./profile');
12
13
 
@@ -27,7 +28,7 @@ async function runScratch({ channel, waitForDankMemer, accountId, redis }) {
27
28
  }
28
29
  LOG.cmd(`${c.white}${c.bold}pls scratch${c.reset}`);
29
30
 
30
- await channel.send('pls scratch');
31
+ await sendCommand(channel, 'scratch', { useSlash, prefix });
31
32
  const response = await waitForDankMemer(10000);
32
33
 
33
34
  if (!response) {
@@ -12,6 +12,7 @@ const {
12
12
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton,
13
13
  logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay,
14
14
  isCV2, ensureCV2, checkLevelLock,
15
+ sendCommand,
15
16
  } = require('./utils');
16
17
  const { VoseAlias, Trie, EMA, LRUCache } = require('../structures');
17
18
 
@@ -84,7 +85,7 @@ function pickSafeButton(buttons, customSafe) {
84
85
  async function runSearch({ channel, waitForDankMemer, safeAnswers }) {
85
86
  LOG.cmd(`${c.white}${c.bold}pls search${c.reset}`);
86
87
 
87
- await channel.send('pls search');
88
+ await sendCommand(channel, 'search', { useSlash, prefix });
88
89
  const response = await waitForDankMemer(10000);
89
90
 
90
91
  if (!response) {
@@ -17,6 +17,7 @@ const {
17
17
  LOG, c, sleep, humanDelay, getFullText,
18
18
  getAllButtons, findSelectMenuOption, getAllSelectMenus, safeClickButton,
19
19
  logMsg, isHoldTight, isCV2, ensureCV2, stripAnsi,
20
+ sendCommand,
20
21
  } = require('./utils');
21
22
  const { LRUCache, Trie } = require('../structures');
22
23
 
@@ -135,7 +136,7 @@ function normalizeShopRequest(itemName, quantity = 1) {
135
136
  }
136
137
 
137
138
  async function openShopView({ channel, waitForDankMemer }) {
138
- await channel.send('pls shop view');
139
+ await sendCommand(channel, 'shop view', { useSlash, prefix });
139
140
  let response = await waitForDankMemer(10000);
140
141
 
141
142
  if (!response) return { ok: false, reason: 'no-response', response: null };
@@ -2,6 +2,7 @@ const {
2
2
  LOG, c, getFullText, parseCoins, getAllButtons, getAllSelectMenus,
3
3
  safeClickButton, logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay, needsItem,
4
4
  isCV2, ensureCV2, stripAnsi, clickCV2Button, checkLevelLock,
5
+ sendCommand,
5
6
  } = require('./utils');
6
7
  const { buyItem } = require('./shop');
7
8
 
@@ -196,7 +197,7 @@ async function selectRandomStreamOption(msg) {
196
197
  async function runStream({ channel, waitForDankMemer, client }) {
197
198
  LOG.cmd(`${c.white}${c.bold}pls stream${c.reset}`);
198
199
 
199
- await channel.send('pls stream');
200
+ await sendCommand(channel, 'stream', { useSlash, prefix });
200
201
  let response = await waitForDankMemer(12000);
201
202
 
202
203
  if (!response) {
@@ -238,7 +239,7 @@ async function runStream({ channel, waitForDankMemer, client }) {
238
239
  }
239
240
 
240
241
  await sleep(800);
241
- await channel.send('pls stream');
242
+ await sendCommand(channel, 'stream', { useSlash, prefix });
242
243
  response = await waitForDankMemer(12000);
243
244
  if (!response) return { result: 'no response after buy', coins: 0, nextCooldownSec: 180 };
244
245
  await hydrate(response);
@@ -10,6 +10,7 @@
10
10
  const {
11
11
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton,
12
12
  logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay, checkLevelLock,
13
+ sendCommand,
13
14
  } = require('./utils');
14
15
 
15
16
  const RE_TRIVIA_MD_BOLD = /\*\*/g;
@@ -79,7 +80,7 @@ async function learnFromResult(question, correctAnswer, redis) {
79
80
  async function runTrivia({ channel, waitForDankMemer, redis }) {
80
81
  LOG.cmd(`${c.white}${c.bold}pls trivia${c.reset}`);
81
82
 
82
- await channel.send('pls trivia');
83
+ await sendCommand(channel, 'trivia', { useSlash, prefix });
83
84
  const response = await waitForDankMemer(10000);
84
85
 
85
86
  if (!response) {
@@ -54,6 +54,34 @@ const c = {
54
54
  magenta: '\x1b[35m', white: '\x1b[37m', blue: '\x1b[34m',
55
55
  };
56
56
 
57
+ // ── Slash Command Helper (dmg pattern) ──────────────────────
58
+ // Wraps channel.send for slash commands — uses Discord interaction API
59
+ // when use_slash=true, falls back to text prefix (pls or /) otherwise.
60
+ // Usage: await sendCommand(channel, 'adventure', { useSlash: true, prefix: '/' })
61
+ async function sendCommand(channel, commandName, opts = {}) {
62
+ const {
63
+ useSlash = false,
64
+ prefix = 'pls',
65
+ args = [],
66
+ } = opts;
67
+
68
+ if (useSlash && channel?.sendSlash) {
69
+ try {
70
+ // sendSlash takes botId, commandName, ...args
71
+ await channel.sendSlash(DANK_MEMER_ID, commandName, ...args);
72
+ return;
73
+ } catch (e) {
74
+ LOG.warn(`[sendSlash] ${commandName} failed: ${e.message} — falling back to text`);
75
+ }
76
+ }
77
+
78
+ // Fallback: text command
79
+ const textCmd = args.length > 0
80
+ ? `${prefix} ${commandName} ${args.join(' ')}`
81
+ : `${prefix} ${commandName}`;
82
+ await channel.send(textCmd);
83
+ }
84
+
57
85
  // ── Logging ──────────────────────────────────────────────────
58
86
  // When dashboard is active, suppress direct console output from command handlers.
59
87
  // grinder.js sets this to true once the live dashboard starts rendering.
@@ -765,6 +793,7 @@ module.exports = {
765
793
  getFullText,
766
794
  stripAnsi,
767
795
  parseCoins,
796
+ sendCommand,
768
797
  parseNetCoins,
769
798
  parseBalance,
770
799
  getAllButtons,
@@ -19,6 +19,7 @@ const {
19
19
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton,
20
20
  logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay,
21
21
  isCV2, ensureCV2, stripAnsi, checkLevelLock,
22
+ sendCommand,
22
23
  } = require('./utils');
23
24
 
24
25
  const RE_MEMORY_BACKTICK_CHUNK = /`([^`]+)`/g;
@@ -142,7 +143,7 @@ function parseWorkCooldown(text) {
142
143
  */
143
144
  async function resignFromJob({ channel, waitForDankMemer }) {
144
145
  LOG.info('[work] Resigning from current job...');
145
- await channel.send('pls work resign');
146
+ await sendCommand(channel, 'work resign', { useSlash, prefix });
146
147
  const response = await waitForDankMemer(8000);
147
148
  if (!response) { LOG.warn('[work] No response to resign'); return false; }
148
149
  logMsg(response, 'work-resign');
@@ -175,7 +176,7 @@ async function resignFromJob({ channel, waitForDankMemer }) {
175
176
  */
176
177
  async function autoApplyForJob({ channel, waitForDankMemer }) {
177
178
  LOG.info('[work] No job! Applying for Babysitter...');
178
- await channel.send('pls work apply babysitter');
179
+ await sendCommand(channel, 'work apply babysitter', { useSlash, prefix });
179
180
  const response = await waitForDankMemer(10000);
180
181
  if (!response) {
181
182
  LOG.warn('[work] No response to apply');
@@ -406,7 +407,7 @@ async function handleGenericMinigame({ channel, current, waitForDankMemer }) {
406
407
  async function runWorkShift({ channel, waitForDankMemer }) {
407
408
  LOG.cmd(`${c.white}${c.bold}pls work shift${c.reset}`);
408
409
 
409
- await channel.send('pls work shift');
410
+ await sendCommand(channel, 'work shift', { useSlash, prefix });
410
411
  let current = await waitForDankMemer(10000);
411
412
 
412
413
  if (!current) {
@@ -453,7 +454,7 @@ async function runWorkShift({ channel, waitForDankMemer }) {
453
454
  while (await waitForDankMemer(1500)) {}
454
455
  await sleep(500);
455
456
 
456
- await channel.send('pls work shift');
457
+ await sendCommand(channel, 'work shift', { useSlash, prefix });
457
458
  current = await waitForDankMemer(10000);
458
459
  if (!current) return { result: 'no response after apply', coins: 0, nextCooldownSec: 180 };
459
460
  if (isCV2(current)) await ensureCV2(current);
package/lib/grinder.js CHANGED
@@ -1400,6 +1400,8 @@ class AccountWorker {
1400
1400
  safeAnswers: cmdName === 'search' ? safeParseJSON(this.account.search_answers, []) :
1401
1401
  cmdName === 'crime' ? safeParseJSON(this.account.crime_answers, []) : [],
1402
1402
  adventureAnswers: AccountWorker.ADVENTURE_ANSWERS,
1403
+ useSlash: !!this.account.use_slash,
1404
+ prefix: this.account.use_slash ? '/' : 'pls',
1403
1405
  betAmount: this._questBetOverride || (['blackjack'].includes(cmdName) ? bjBet : gambBet),
1404
1406
  accountId: this.account.id,
1405
1407
  redis,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dankgrinder",
3
- "version": "8.110.0",
3
+ "version": "8.112.0",
4
4
  "description": "Dank Memer automation engine — grind coins while you sleep",
5
5
  "bin": {
6
6
  "dankgrinder": "bin/dankgrinder.js"