dankgrinder 6.21.0 → 6.25.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.
- package/lib/grinder.js +54 -40
- package/package.json +1 -1
package/lib/grinder.js
CHANGED
|
@@ -458,7 +458,7 @@ function renderDashboard() {
|
|
|
458
458
|
lines.push(bRow(` ${c.bold}${titleGrad}${c.reset} ${D}v${PKG_VERSION}${c.reset} ${G}${spin}${c.reset}`));
|
|
459
459
|
}
|
|
460
460
|
|
|
461
|
-
lines.push(bRow(` ${D}v${PKG_VERSION}${c.reset} ${G}${spin}${c.reset}`));
|
|
461
|
+
lines.push(bRow(` ${D}v${PKG_VERSION}${c.reset} ${G}${spin}${c.reset} ${Y}◷${c.reset} ${D}UP${c.reset} ${c.bold}${Y}${formatUptime()}${c.reset}`));
|
|
462
462
|
|
|
463
463
|
// Subtitle info
|
|
464
464
|
const activeCount = workers.filter(w => w.running && !w.paused && !w.dashboardPaused).length;
|
|
@@ -487,52 +487,62 @@ function renderDashboard() {
|
|
|
487
487
|
lines.push(bEmpty);
|
|
488
488
|
|
|
489
489
|
// ═══════════════════════════════════════════════════════════════
|
|
490
|
-
// STATS PANEL
|
|
490
|
+
// STATS PANEL — left: metrics (fixed labels) | right: big trend
|
|
491
491
|
// ═══════════════════════════════════════════════════════════════
|
|
492
492
|
lines.push(bSep);
|
|
493
493
|
lines.push(bEmpty);
|
|
494
494
|
|
|
495
|
-
// Earnings sparkline data
|
|
496
495
|
const now = Date.now();
|
|
497
496
|
if (now - lastEarningsSample > 8000) { earningsHistory.push(totalCoins); lastEarningsSample = now; }
|
|
498
497
|
const elapsedHrs = (Date.now() - startTime) / 3_600_000;
|
|
499
498
|
const perHr = elapsedHrs > 0.01 ? Math.round(totalCoins / elapsedHrs) : 0;
|
|
500
|
-
const peakFlag = isNewHigh ? ` ${R}${c.bold}* NEW HIGH *${c.reset}` : '';
|
|
501
499
|
|
|
502
|
-
//
|
|
500
|
+
// ── Compute all metric values ──────────────────────────────────
|
|
503
501
|
const cpmVal = globalCmdRate.getRate().toFixed(1);
|
|
504
502
|
const srColor = successRate >= 95 ? G : successRate >= 80 ? Y : R;
|
|
505
|
-
const
|
|
506
|
-
const srBar = progressBar(successRate, 100, srBarW, successRate >= 95 ? [52, 211, 153] : successRate >= 80 ? [251, 191, 36] : [239, 68, 68]);
|
|
503
|
+
const srBar = progressBar(successRate, 100, 10, successRate >= 95 ? [52, 211, 153] : successRate >= 80 ? [251, 191, 36] : [239, 68, 68]);
|
|
507
504
|
const memMB = Math.round((process.memoryUsage?.rss?.() ?? process.memoryUsage().rss) / 1048576);
|
|
508
505
|
const memCol = memMB > 900 ? [239, 68, 68] : memMB > 600 ? [251, 191, 36] : [52, 211, 153];
|
|
509
|
-
const
|
|
510
|
-
const
|
|
506
|
+
const memBar = progressBar(memMB, 1024, 10, memCol, [40, 40, 55]);
|
|
507
|
+
const perHrColor = perHr >= 0 ? G : R;
|
|
508
|
+
const perHrSign = perHr >= 0 ? '+' : '';
|
|
509
|
+
const newHighFlag = isNewHigh ? ` ${R}${c.bold}★ NEW HIGH ★${c.reset}` : '';
|
|
511
510
|
|
|
512
|
-
//
|
|
513
|
-
const sparkW = Math.floor(iw * 0.
|
|
511
|
+
// ── Big trend sparkline (right column) ──────────────────────
|
|
512
|
+
const sparkW = Math.max(36, Math.floor(iw * 0.55));
|
|
514
513
|
const spark = drawSparkline(earningsHistory.toArray(), sparkW);
|
|
515
514
|
|
|
516
|
-
// Build
|
|
517
|
-
const
|
|
515
|
+
// ── Build each row: left metrics (fixed) | right trend ───────
|
|
516
|
+
const leftW = 36; // chars for left column content
|
|
518
517
|
|
|
519
|
-
//
|
|
520
|
-
const
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
518
|
+
// Helper: build a stat row with fixed-width label
|
|
519
|
+
const statRow = (icon, label, val) => {
|
|
520
|
+
const raw = `${icon} ${label} ${val}`;
|
|
521
|
+
const padded = raw + ' '.repeat(Math.max(0, leftW - raw.replace(RE, '').length));
|
|
522
|
+
return padded;
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
// Row 1: Balance
|
|
526
|
+
const balVal = `${Au}⏣${c.reset}${c.bold} ${formatCoins(totalBalance)}${c.reset}`;
|
|
527
|
+
const balRaw = `${Au}⟐${c.reset} ${D}BALANCE${c.reset} ${balVal}`;
|
|
528
|
+
lines.push(bRow(` ${balRaw.padEnd(leftW + 4)}${A}~${c.reset} ${D}TREND${c.reset} ${spark}`));
|
|
529
|
+
|
|
530
|
+
// Row 2: Earned
|
|
531
|
+
const earnVal = `${perHrColor}${c.bold}${perHrSign}⏣ ${formatCoins(perHr)}/h${c.reset}`;
|
|
532
|
+
const earnRaw = `${G}▲${c.reset} ${D}EARNED${c.reset} ${c.bold}${G}${perHrSign}⏣ ${formatCoins(totalCoins)}${c.reset}${newHighFlag}`;
|
|
533
|
+
lines.push(bRow(` ${earnRaw.padEnd(leftW + 4)}${D}──┬──${c.reset} ${c.dim}earned over session${c.reset}`));
|
|
524
534
|
|
|
525
|
-
// Row
|
|
526
|
-
const
|
|
527
|
-
lines.push(bRow(` ${
|
|
535
|
+
// Row 3: Peak
|
|
536
|
+
const peakRaw = `${O}★${c.reset} ${D}PEAK${c.reset} ${c.bold}${O}⏣ ${formatCoins(sessionPeakCoins)}${c.reset}`;
|
|
537
|
+
lines.push(bRow(` ${peakRaw.padEnd(leftW + 4)}${D} │${c.reset} ${c.dim}⏣ ${formatCoins(Math.abs(perHr))}/h${c.reset}`));
|
|
528
538
|
|
|
529
|
-
// Row
|
|
530
|
-
const
|
|
531
|
-
lines.push(bRow(` ${
|
|
539
|
+
// Row 4: Commands
|
|
540
|
+
const cmdsRaw = `${B}◆${c.reset} ${D}CMDS${c.reset} ${c.bold}${B}${totalCommands}${c.reset} ${srColor}${successRate}%${c.reset} ${srBar} ${Cy}${cpmVal}${c.reset}${D}/min${c.reset}`;
|
|
541
|
+
lines.push(bRow(` ${cmdsRaw.padEnd(leftW + 4)}${D} │${c.reset}`));
|
|
532
542
|
|
|
533
|
-
// Row
|
|
534
|
-
const
|
|
535
|
-
lines.push(bRow(` ${
|
|
543
|
+
// Row 5: Memory
|
|
544
|
+
const memRaw = `${D}≡${c.reset} ${D}MEM${c.reset} ${rgb(memCol[0], memCol[1], memCol[2])}${c.bold}${memMB}MB${c.reset} ${memBar}`;
|
|
545
|
+
lines.push(bRow(` ${memRaw.padEnd(leftW + 4)}${D} │${c.reset}`));
|
|
536
546
|
|
|
537
547
|
lines.push(bEmpty);
|
|
538
548
|
|
|
@@ -642,9 +652,9 @@ function renderDashboard() {
|
|
|
642
652
|
else if (ls != null) lsStr = `${G}♥${ls}${c.reset}`;
|
|
643
653
|
else lsStr = `${D}♥?${c.reset}`;
|
|
644
654
|
|
|
645
|
-
// ── Level indicator ──
|
|
655
|
+
// ── Level indicator (fixed width so value changes don't jitter) ──
|
|
646
656
|
const lvl = wk._level || 0;
|
|
647
|
-
const lvlStr = lvl > 0 ? `${Cy}L${lvl}${c.reset}` : `${D}L
|
|
657
|
+
const lvlStr = lvl > 0 ? `${Cy}L${String(lvl).padStart(3)}${c.reset}` : `${D}L???${c.reset}`;
|
|
648
658
|
|
|
649
659
|
// ── Earned (fixed visible width) ──
|
|
650
660
|
const earnNum = wk.stats.coins || 0;
|
|
@@ -1413,6 +1423,7 @@ class AccountWorker {
|
|
|
1413
1423
|
startupProgress = null,
|
|
1414
1424
|
requireComplete = false,
|
|
1415
1425
|
maxAttempts = 1,
|
|
1426
|
+
silent = false,
|
|
1416
1427
|
} = options;
|
|
1417
1428
|
if (this._invRunning) return { ok: false, skipped: 'busy' };
|
|
1418
1429
|
if (!force && this._lastInvCheck && Date.now() - this._lastInvCheck < 300_000) return { ok: false, skipped: 'recent' };
|
|
@@ -1426,7 +1437,7 @@ class AccountWorker {
|
|
|
1426
1437
|
const baseLabel = startupProgress ? `[inv] ${startupProgress.current}/${startupProgress.total}` : '[inv]';
|
|
1427
1438
|
const attemptLabel = tries > 1 ? ` [try ${attempt}/${tries}]` : '';
|
|
1428
1439
|
const progressLine = `${baseLabel}${c.bold} ${this.username}${c.reset}${attemptLabel}`;
|
|
1429
|
-
process.stdout.write(`\x1b[2K\r${progressLine}`);
|
|
1440
|
+
if (!silent) process.stdout.write(`\x1b[2K\r${progressLine}`);
|
|
1430
1441
|
|
|
1431
1442
|
try {
|
|
1432
1443
|
const result = await commands.runInventory({
|
|
@@ -1436,9 +1447,10 @@ class AccountWorker {
|
|
|
1436
1447
|
accountId: this.account.id,
|
|
1437
1448
|
redis,
|
|
1438
1449
|
onPageProgress: ({ page, total }) => {
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1450
|
+
if (!silent) {
|
|
1451
|
+
const erase = '\x1b[2K\r';
|
|
1452
|
+
process.stdout.write(`${erase}${baseLabel} ${c.bold}${this.username}${c.reset} · page ${page}/${total}${attemptLabel}`);
|
|
1453
|
+
}
|
|
1442
1454
|
},
|
|
1443
1455
|
});
|
|
1444
1456
|
|
|
@@ -1447,8 +1459,10 @@ class AccountWorker {
|
|
|
1447
1459
|
}
|
|
1448
1460
|
|
|
1449
1461
|
// Final result on same line
|
|
1450
|
-
|
|
1451
|
-
|
|
1462
|
+
if (!silent) {
|
|
1463
|
+
const resultLine = `${baseLabel} ${c.bold}${this.username}${c.reset}: ${c.green}${result.items?.length || 0} items${c.reset}, ⏣ ${c.green}${(result.totalValue || 0).toLocaleString()}${c.reset} net${attemptLabel}`;
|
|
1464
|
+
process.stdout.write(`\x1b[2K\r${resultLine}\n`);
|
|
1465
|
+
}
|
|
1452
1466
|
|
|
1453
1467
|
// Extract lifesaver count from inventory and cache in Redis
|
|
1454
1468
|
if (result.items && redis) {
|
|
@@ -1492,7 +1506,7 @@ class AccountWorker {
|
|
|
1492
1506
|
if (attempt < tries) {
|
|
1493
1507
|
const baseLabel = startupProgress ? `[inv] ${startupProgress.current}/${startupProgress.total}` : '[inv]';
|
|
1494
1508
|
const retryLine = `${baseLabel} ${c.bold}${this.username}${c.reset}: ${c.yellow}attempt ${attempt}/${tries} failed${c.reset} — retrying...`;
|
|
1495
|
-
process.stdout.write(`\x1b[2K\r${retryLine}\n`);
|
|
1509
|
+
if (!silent) process.stdout.write(`\x1b[2K\r${retryLine}\n`);
|
|
1496
1510
|
await new Promise((r) => setTimeout(r, 1500 + Math.floor(Math.random() * 1500)));
|
|
1497
1511
|
continue;
|
|
1498
1512
|
}
|
|
@@ -1503,7 +1517,7 @@ class AccountWorker {
|
|
|
1503
1517
|
} catch (e) {
|
|
1504
1518
|
const baseLabel = startupProgress ? `[inv] ${startupProgress.current}/${startupProgress.total}` : '[inv]';
|
|
1505
1519
|
const failLine = `${baseLabel} ${c.bold}${this.username}${c.reset}: ${c.red}failed${c.reset} — ${e.message}`;
|
|
1506
|
-
process.stdout.write(`\x1b[2K\r${failLine}\n`);
|
|
1520
|
+
if (!silent) process.stdout.write(`\x1b[2K\r${failLine}\n`);
|
|
1507
1521
|
return { ok: false, error: e.message };
|
|
1508
1522
|
} finally {
|
|
1509
1523
|
this._invRunning = false;
|
|
@@ -3209,9 +3223,9 @@ async function start(apiKey, apiUrl) {
|
|
|
3209
3223
|
|
|
3210
3224
|
const num = `${c.dim}${(idx + 1).toString().padStart(iColNum - 1)}${c.reset} `;
|
|
3211
3225
|
const name = s.name.substring(0, iColName).padEnd(iColName);
|
|
3212
|
-
const items = `${invRes?.items?.length || 0}`.padEnd(iColItems);
|
|
3226
|
+
const items = `${invRes?.result?.items?.length || 0}`.padEnd(iColItems);
|
|
3213
3227
|
const val = invRes?.ok
|
|
3214
|
-
? `${c.green}⏣${(invRes.totalValue || 0).toLocaleString()}${c.reset}`.padEnd(iColVal + 3)
|
|
3228
|
+
? `${c.green}⏣${(invRes.result?.totalValue || 0).toLocaleString()}${c.reset}`.padEnd(iColVal + 3)
|
|
3215
3229
|
: `${c.dim}··${c.reset}`.padEnd(iColVal);
|
|
3216
3230
|
const sts = invRes?.ok ? `${rgb(52, 211, 153)}✓${c.reset}` : `${rgb(239, 68, 68)}✗${c.reset}`;
|
|
3217
3231
|
|
|
@@ -3221,7 +3235,7 @@ async function start(apiKey, apiUrl) {
|
|
|
3221
3235
|
|
|
3222
3236
|
await Promise.all(activeWorkers.map(async (w, i) => {
|
|
3223
3237
|
try {
|
|
3224
|
-
const invRes = await w.checkInventory({ force: true, requireComplete: true, maxAttempts: 3 });
|
|
3238
|
+
const invRes = await w.checkInventory({ force: true, requireComplete: true, maxAttempts: 3, silent: true });
|
|
3225
3239
|
finalizeInvLine(i, invRes);
|
|
3226
3240
|
} catch {
|
|
3227
3241
|
finalizeInvLine(i, { ok: false });
|