dankgrinder 6.45.0 → 6.46.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 +74 -161
- package/package.json +1 -1
package/lib/grinder.js
CHANGED
|
@@ -3217,39 +3217,21 @@ async function start(apiKey, apiUrl) {
|
|
|
3217
3217
|
console.log(` ${checks.join(' ')}`);
|
|
3218
3218
|
console.log('');
|
|
3219
3219
|
|
|
3220
|
-
// ── Phase 1: Login with per-
|
|
3220
|
+
// ── Phase 1: Login — inline table with per-row updates ─────────
|
|
3221
3221
|
const startupTw = process.stdout.columns || 90;
|
|
3222
|
-
const colNum = 4;
|
|
3223
|
-
const colSts = 3;
|
|
3222
|
+
const colNum = 4;
|
|
3223
|
+
const colSts = 3;
|
|
3224
3224
|
const colName = Math.min(24, Math.max(12, Math.floor(startupTw * 0.25)));
|
|
3225
3225
|
const colGuild = Math.min(18, Math.max(8, Math.floor(startupTw * 0.2)));
|
|
3226
3226
|
const colCmds = 8;
|
|
3227
3227
|
const loginVis = colNum + colSts + colName + colGuild + colCmds + 10;
|
|
3228
3228
|
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
let loginLines = [];
|
|
3237
|
-
loginLines.push(` ${'─'.repeat(loginVis)}`);
|
|
3238
|
-
for (let i = 0; i < loginStates.length; i++) {
|
|
3239
|
-
const s = loginStates[i];
|
|
3240
|
-
const num = `${c.dim}${(i + 1).toString().padStart(colNum - 1)}${c.reset}`;
|
|
3241
|
-
const name = s.name.substring(0, colName).padEnd(colName);
|
|
3242
|
-
const guild = c.dim + '···'.padEnd(colGuild) + c.reset;
|
|
3243
|
-
const cmds = c.dim + '···'.padEnd(colCmds) + c.reset;
|
|
3244
|
-
loginLines.push(` ${num} ${c.dim}··${c.reset} ${name} ${guild} ${cmds}`);
|
|
3245
|
-
}
|
|
3246
|
-
loginLines.push(` ${'─'.repeat(loginVis)}`);
|
|
3247
|
-
for (const l of loginLines) console.log(l);
|
|
3248
|
-
|
|
3249
|
-
// Dynamically capture the starting row of the login table via DSR
|
|
3250
|
-
let loginBaseRow = 1;
|
|
3251
|
-
const captureLoginRow = () => new Promise(resolve => {
|
|
3252
|
-
process.stdout.write(MARKER);
|
|
3229
|
+
// Use DSR to find starting row, then use explicit row numbers for all table writes.
|
|
3230
|
+
// This avoids relying on cursor tracking via \n which varies by terminal.
|
|
3231
|
+
let tableTopRow = 1;
|
|
3232
|
+
let pendingSet = new Set(Array.from({ length: accounts.length }, (_, i) => i));
|
|
3233
|
+
const captureTopRow = () => new Promise(resolve => {
|
|
3234
|
+
process.stdout.write('\x1b[6n');
|
|
3253
3235
|
const chunks = [];
|
|
3254
3236
|
const handler = (chunk) => {
|
|
3255
3237
|
chunks.push(chunk);
|
|
@@ -3257,51 +3239,52 @@ async function start(apiKey, apiUrl) {
|
|
|
3257
3239
|
const m = raw.match(/\x1b\[(\d+);\d+R/);
|
|
3258
3240
|
if (m) {
|
|
3259
3241
|
process.stdin.removeListener('data', handler);
|
|
3260
|
-
|
|
3242
|
+
tableTopRow = parseInt(m[1], 10);
|
|
3261
3243
|
resolve();
|
|
3262
3244
|
}
|
|
3263
3245
|
};
|
|
3264
3246
|
process.stdin.on('data', handler);
|
|
3265
3247
|
setTimeout(resolve, 50);
|
|
3266
3248
|
});
|
|
3267
|
-
await
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
const
|
|
3249
|
+
await captureTopRow();
|
|
3250
|
+
|
|
3251
|
+
// Absolute row numbers for all table elements (calculated from captured top row)
|
|
3252
|
+
const borderTopRow = tableTopRow; // border
|
|
3253
|
+
const dataStartRow = tableTopRow + 1; // first account row
|
|
3254
|
+
const borderBotRow = tableTopRow + accounts.length + 1; // bottom border
|
|
3255
|
+
const bottomRow = borderBotRow + 1; // cursor final position after table
|
|
3256
|
+
|
|
3257
|
+
// Print initial table using explicit row positioning
|
|
3258
|
+
process.stdout.write(`\x1b[${borderTopRow};1H ${'─'.repeat(loginVis)}`);
|
|
3259
|
+
for (let i = 0; i < accounts.length; i++) {
|
|
3260
|
+
const row = dataStartRow + i;
|
|
3261
|
+
const name = (accounts[i].label || accounts[i].id || '?').substring(0, colName).padEnd(colName);
|
|
3262
|
+
const num = `${c.dim}${(i + 1).toString().padStart(colNum - 1)}${c.reset}`;
|
|
3263
|
+
process.stdout.write(`\x1b[${row};1H ${num} ${c.dim}··${c.reset} ${name} ${c.dim}${'···'.padEnd(colGuild)}${c.reset} ${c.dim}${'···'.padEnd(colCmds)}${c.reset}\x1b[K`);
|
|
3264
|
+
}
|
|
3265
|
+
process.stdout.write(`\x1b[${borderBotRow};1H ${'─'.repeat(loginVis)}\x1b[K`);
|
|
3271
3266
|
|
|
3267
|
+
// Spinner: updates rows inline using absolute row numbers
|
|
3272
3268
|
const drawLoginSpinners = () => {
|
|
3273
|
-
for (
|
|
3274
|
-
if (!loginPending[i]) continue;
|
|
3269
|
+
for (const i of pendingSet) {
|
|
3275
3270
|
const spin = BRAILLE_SPIN[Math.floor(Date.now() / 80) % BRAILLE_SPIN.length];
|
|
3271
|
+
const name = (accounts[i].label || accounts[i].id || '?').substring(0, colName).padEnd(colName);
|
|
3276
3272
|
const num = `${c.dim}${(i + 1).toString().padStart(colNum - 1)}${c.reset}`;
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
const cmds = c.dim + '···'.padEnd(colCmds) + c.reset;
|
|
3280
|
-
const row = loginBaseRow + 1 + i; // +1 skips the top border line
|
|
3281
|
-
moveToRow(row);
|
|
3282
|
-
process.stdout.write(` ${num} ${rgb(139, 92, 246)}${spin}${c.reset} ${name} ${guild} ${cmds}\x1b[K`);
|
|
3283
|
-
}
|
|
3284
|
-
// Move cursor back to bottom to avoid overwriting the bottom border
|
|
3285
|
-
const lastRow = loginBaseRow + 1 + accounts.length + 1;
|
|
3286
|
-
moveToRow(lastRow);
|
|
3273
|
+
process.stdout.write(`\x1b[${dataStartRow + i};1H ${num} ${rgb(139, 92, 246)}${spin}${c.reset} ${name} ${c.dim}${'logging in...'.substring(0, colGuild)}${c.reset} ${c.dim}${'···'.padEnd(colCmds)}${c.reset}\x1b[K`);
|
|
3274
|
+
}
|
|
3287
3275
|
};
|
|
3288
|
-
const
|
|
3289
|
-
|
|
3290
|
-
const finalizeLoginLine = (idx, worker) => {
|
|
3291
|
-
if (!loginPending[idx]) return;
|
|
3292
|
-
loginPending[idx] = false;
|
|
3293
|
-
const s = loginStates[idx];
|
|
3294
|
-
s.done = true;
|
|
3295
|
-
s.worker = worker;
|
|
3276
|
+
const loginSpinner = setInterval(drawLoginSpinners, 80);
|
|
3296
3277
|
|
|
3278
|
+
const finalizeLoginRow = (idx, worker) => {
|
|
3279
|
+
if (!pendingSet.has(idx)) return;
|
|
3280
|
+
pendingSet.delete(idx);
|
|
3297
3281
|
const num = `${c.dim}${(idx + 1).toString().padStart(colNum - 1)}${c.reset}`;
|
|
3298
|
-
const name = (worker.username ||
|
|
3282
|
+
const name = (worker.username || accounts[idx].label || accounts[idx].id || '?').substring(0, colName).padEnd(colName);
|
|
3299
3283
|
let sts, guild, cmds;
|
|
3300
3284
|
if (worker._tokenInvalid) {
|
|
3301
3285
|
sts = `${rgb(239, 68, 68)}✗${c.reset}`;
|
|
3302
3286
|
guild = 'INVALID'.padEnd(colGuild);
|
|
3303
3287
|
cmds = '···'.padEnd(colCmds);
|
|
3304
|
-
s.failed = true;
|
|
3305
3288
|
} else if (worker.channel) {
|
|
3306
3289
|
sts = `${rgb(52, 211, 153)}✓${c.reset}`;
|
|
3307
3290
|
const gn = (worker.channel.guild?.name || worker.channel.guild?.id || 'DM').substring(0, colGuild);
|
|
@@ -3312,9 +3295,7 @@ async function start(apiKey, apiUrl) {
|
|
|
3312
3295
|
guild = 'timeout'.padEnd(colGuild);
|
|
3313
3296
|
cmds = '···'.padEnd(colCmds);
|
|
3314
3297
|
}
|
|
3315
|
-
|
|
3316
|
-
moveToRow(row);
|
|
3317
|
-
process.stdout.write(` ${num} ${sts} ${name} ${c.dim}${guild}${c.reset} ${c.dim}${cmds}${c.reset}\x1b[K`);
|
|
3298
|
+
process.stdout.write(`\x1b[${dataStartRow + idx};1H ${num} ${sts} ${name} ${c.dim}${guild}${c.reset} ${c.dim}${cmds}${c.reset}\x1b[K`);
|
|
3318
3299
|
};
|
|
3319
3300
|
|
|
3320
3301
|
const parsedGapMin = Number.parseInt(String(process.env.LOGIN_GAP_MIN_MS || '50'), 10);
|
|
@@ -3332,58 +3313,34 @@ async function start(apiKey, apiUrl) {
|
|
|
3332
3313
|
const worker = new AccountWorker(acc, i + idx);
|
|
3333
3314
|
workers.push(worker);
|
|
3334
3315
|
workerMap.set(acc.id, worker);
|
|
3335
|
-
loginStates[i + idx].worker = worker;
|
|
3336
3316
|
await worker.start();
|
|
3337
|
-
|
|
3317
|
+
finalizeLoginRow(i + idx, worker);
|
|
3338
3318
|
}));
|
|
3339
3319
|
if (i + BATCH_SIZE < accounts.length) await new Promise(r => setTimeout(r, randomLoginGap()));
|
|
3340
3320
|
hintGC();
|
|
3341
3321
|
}
|
|
3342
3322
|
|
|
3343
|
-
clearInterval(
|
|
3344
|
-
const loginDone = workers.filter(w => !w._tokenInvalid && w.channel).length;
|
|
3323
|
+
clearInterval(loginSpinner);
|
|
3345
3324
|
const invalidWorkers = workers.filter(w => w._tokenInvalid);
|
|
3346
3325
|
const timedOutWorkers = workers.filter(w => !w.channel && !w._tokenInvalid);
|
|
3347
|
-
|
|
3348
|
-
|
|
3326
|
+
const activeWorkers = workers.filter(w => !w._tokenInvalid);
|
|
3327
|
+
const loginDone = activeWorkers.filter(w => w.channel).length;
|
|
3328
|
+
// Clear bottom border row, move to new line, print login complete
|
|
3329
|
+
process.stdout.write(`\x1b[${borderBotRow};1H\x1b[2K\n ${rgb(52, 211, 153)}✓${c.reset} ${c.bold}Login complete${c.reset} ${rgb(52, 211, 153)}${loginDone}${c.reset}${c.dim}/${c.reset}${c.white}${accounts.length}${c.reset} ${c.dim}accounts connected${c.reset}\n`);
|
|
3349
3330
|
if (invalidWorkers.length > 0) {
|
|
3350
|
-
log(
|
|
3351
|
-
for (const w of invalidWorkers) log('error', ` ✗ ${w.account.label || w.account.id} — token is invalid or expired`);
|
|
3352
|
-
console.log('');
|
|
3331
|
+
console.log(` ${rgb(239, 68, 68)}✗${c.reset} ${c.bold}${c.red}${invalidWorkers.length} INVALID token(s):${c.reset} ${invalidWorkers.map(w => w.account.label || w.account.id).join(', ')}`);
|
|
3353
3332
|
}
|
|
3354
3333
|
if (timedOutWorkers.length > 0) log('warn', `${timedOutWorkers.length} account(s) timed out during login (will retry in background)`);
|
|
3334
|
+
console.log('');
|
|
3355
3335
|
|
|
3356
|
-
|
|
3336
|
+
// ── Phase 2: Inventory check — clean sequential table ─────────
|
|
3357
3337
|
|
|
3358
|
-
// ── Phase 2: Inventory check — spinner for pending count, results inline ─────────
|
|
3359
3338
|
const iColNum = 4;
|
|
3360
3339
|
const iColName = Math.min(22, Math.max(12, Math.floor(startupTw * 0.22)));
|
|
3361
3340
|
const iColItems = 8;
|
|
3362
3341
|
const iColVal = 16;
|
|
3363
3342
|
const invVis = 7 + iColNum + iColName + iColItems + iColVal + 12;
|
|
3364
3343
|
|
|
3365
|
-
// Print a unique marker, query its position, then overwrite it with the table
|
|
3366
|
-
process.stdout.write(MARKER);
|
|
3367
|
-
let invBaseRow = 1;
|
|
3368
|
-
const captureRow = () => new Promise(resolve => {
|
|
3369
|
-
const chunks = [];
|
|
3370
|
-
const handler = (chunk) => {
|
|
3371
|
-
chunks.push(chunk);
|
|
3372
|
-
const raw = chunks.join('');
|
|
3373
|
-
const m = raw.match(/\x1b\[(\d+);\d+R/);
|
|
3374
|
-
if (m) {
|
|
3375
|
-
process.stdin.removeListener('data', handler);
|
|
3376
|
-
invBaseRow = parseInt(m[1], 10) + 1; // +1: first account row is after marker
|
|
3377
|
-
resolve();
|
|
3378
|
-
}
|
|
3379
|
-
};
|
|
3380
|
-
process.stdin.on('data', handler);
|
|
3381
|
-
setTimeout(resolve, 50);
|
|
3382
|
-
});
|
|
3383
|
-
await captureRow();
|
|
3384
|
-
|
|
3385
|
-
// Now print the inventory table starting at invBaseRow
|
|
3386
|
-
const invMoveToRow = (row) => process.stdout.write(`\x1b[${row};1H`);
|
|
3387
3344
|
console.log(` ${'─'.repeat(invVis)}`);
|
|
3388
3345
|
for (let i = 0; i < activeWorkers.length; i++) {
|
|
3389
3346
|
const w = activeWorkers[i];
|
|
@@ -3393,40 +3350,31 @@ async function start(apiKey, apiUrl) {
|
|
|
3393
3350
|
}
|
|
3394
3351
|
console.log(` ${'─'.repeat(invVis)}`);
|
|
3395
3352
|
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
const bar = rgb(34, 211, 238) + '█'.repeat(filled) + rgb(50, 50, 70) + '░'.repeat(barW - filled) + c.reset;
|
|
3404
|
-
const pctStr = `${Math.round(pct * 100)}%`;
|
|
3405
|
-
invMoveToRow(invBaseRow);
|
|
3406
|
-
process.stdout.write(` ${rgb(34, 211, 238)}${spin}${c.reset} ${c.dim}Inventory...${c.reset} ${bar} ${c.bold}${rgb(52, 211, 153)}${activeWorkers.length - invPending}${c.reset}${c.dim}/${c.reset}${c.white}${activeWorkers.length}${c.reset} ${c.dim}${pctStr}${c.reset} \x1b[K`);
|
|
3407
|
-
};
|
|
3408
|
-
const invSpinnerInterval = setInterval(drawInvProgress, 80);
|
|
3353
|
+
const invResults = await Promise.all(activeWorkers.map(async (w, i) => {
|
|
3354
|
+
try {
|
|
3355
|
+
return await w.checkInventory({ force: true, requireComplete: true, maxAttempts: 5, silent: true });
|
|
3356
|
+
} catch {
|
|
3357
|
+
return { ok: false };
|
|
3358
|
+
}
|
|
3359
|
+
}));
|
|
3409
3360
|
|
|
3410
|
-
|
|
3361
|
+
let invDone = 0, invFailed = 0;
|
|
3362
|
+
// Re-print table with results
|
|
3363
|
+
console.log(` ${'─'.repeat(invVis)}`);
|
|
3364
|
+
for (let i = 0; i < activeWorkers.length; i++) {
|
|
3365
|
+
const invRes = invResults[i] || { ok: false };
|
|
3366
|
+
const w = activeWorkers[i];
|
|
3411
3367
|
const num = `${c.dim}${(i + 1).toString().padStart(iColNum - 1)}${c.reset}`;
|
|
3412
3368
|
const name = (w.username || w.account.label || '?').substring(0, iColName).padEnd(iColName);
|
|
3413
|
-
let invRes;
|
|
3414
|
-
try { invRes = await w.checkInventory({ force: true, requireComplete: true, maxAttempts: 5, silent: true }); }
|
|
3415
|
-
catch { invRes = { ok: false }; }
|
|
3416
|
-
invPending--;
|
|
3417
3369
|
const items = invRes?.ok ? (invRes.result?.items?.length || 0) : 0;
|
|
3418
3370
|
const val = invRes?.ok ? (invRes.result?.totalValue || 0) : 0;
|
|
3419
3371
|
const sts = invRes?.ok ? `${rgb(52, 211, 153)}✓${c.reset}` : `${rgb(239, 68, 68)}✗${c.reset}`;
|
|
3420
3372
|
const itemStr = `${items}`.padEnd(iColItems);
|
|
3421
3373
|
const valStr = invRes?.ok ? `${c.green}⏣${val.toLocaleString()}${c.reset}` : `${c.dim}···${c.reset}`;
|
|
3422
|
-
|
|
3423
|
-
invMoveToRow(row);
|
|
3424
|
-
process.stdout.write(` ${num} ${sts} ${name} ${itemStr} ${valStr.padEnd(iColVal + 5)}\x1b[K`);
|
|
3374
|
+
console.log(` ${num} ${sts} ${name} ${itemStr} ${valStr.padEnd(iColVal + 5)}`);
|
|
3425
3375
|
if (invRes?.ok) invDone++; else invFailed++;
|
|
3426
|
-
}
|
|
3427
|
-
|
|
3428
|
-
clearInterval(invSpinnerInterval);
|
|
3429
|
-
process.stdout.write(`\r\x1b[2K`);
|
|
3376
|
+
}
|
|
3377
|
+
console.log(` ${'─'.repeat(invVis)}`);
|
|
3430
3378
|
|
|
3431
3379
|
if (invFailed > 0) {
|
|
3432
3380
|
console.log(` ${rgb(239, 68, 68)}✗${c.reset} ${c.bold}Inventory incomplete${c.reset} ${rgb(52, 211, 153)}${invDone}${c.reset}${c.dim}/${c.reset}${c.white}${activeWorkers.length}${c.reset} ${c.dim}done, ${rgb(239, 68, 68)}${invFailed} failed${c.reset}`);
|
|
@@ -3436,7 +3384,7 @@ async function start(apiKey, apiUrl) {
|
|
|
3436
3384
|
console.log(` ${rgb(52, 211, 153)}✓${c.reset} ${c.bold}Inventory complete${c.reset} ${rgb(52, 211, 153)}${invDone}/${activeWorkers.length}${c.reset} ${c.dim}all clear${c.reset}`);
|
|
3437
3385
|
console.log('');
|
|
3438
3386
|
|
|
3439
|
-
// ── Phase 2.5: Balance check —
|
|
3387
|
+
// ── Phase 2.5: Balance check — clean sequential table ─────────
|
|
3440
3388
|
const bColNum = 4;
|
|
3441
3389
|
const bColName = Math.min(22, Math.max(12, Math.floor(startupTw * 0.22)));
|
|
3442
3390
|
const bColWallet = 12;
|
|
@@ -3445,27 +3393,6 @@ async function start(apiKey, apiUrl) {
|
|
|
3445
3393
|
const bColLs = 4;
|
|
3446
3394
|
const balVis = 7 + bColNum + bColName + bColWallet + bColBank + bColTotal + bColLs + 14;
|
|
3447
3395
|
|
|
3448
|
-
// Capture starting row for balance phase
|
|
3449
|
-
process.stdout.write(MARKER);
|
|
3450
|
-
let balBaseRow = 1;
|
|
3451
|
-
const balCaptureRow = () => new Promise(resolve => {
|
|
3452
|
-
const chunks = [];
|
|
3453
|
-
const handler = (chunk) => {
|
|
3454
|
-
chunks.push(chunk);
|
|
3455
|
-
const raw = chunks.join('');
|
|
3456
|
-
const m = raw.match(/\x1b\[(\d+);\d+R/);
|
|
3457
|
-
if (m) {
|
|
3458
|
-
process.stdin.removeListener('data', handler);
|
|
3459
|
-
balBaseRow = parseInt(m[1], 10) + 1;
|
|
3460
|
-
resolve();
|
|
3461
|
-
}
|
|
3462
|
-
};
|
|
3463
|
-
process.stdin.on('data', handler);
|
|
3464
|
-
setTimeout(resolve, 50);
|
|
3465
|
-
});
|
|
3466
|
-
await balCaptureRow();
|
|
3467
|
-
|
|
3468
|
-
const balMoveToRow = (row) => process.stdout.write(`\x1b[${row};1H`);
|
|
3469
3396
|
console.log(` ${'─'.repeat(balVis)}`);
|
|
3470
3397
|
for (let i = 0; i < activeWorkers.length; i++) {
|
|
3471
3398
|
const w = activeWorkers[i];
|
|
@@ -3475,22 +3402,14 @@ async function start(apiKey, apiUrl) {
|
|
|
3475
3402
|
}
|
|
3476
3403
|
console.log(` ${'─'.repeat(balVis)}`);
|
|
3477
3404
|
|
|
3478
|
-
|
|
3479
|
-
const drawBalProgress = () => {
|
|
3480
|
-
if (balPending === 0) return;
|
|
3481
|
-
const spin = BRAILLE_SPIN[Math.floor(Date.now() / 80) % BRAILLE_SPIN.length];
|
|
3482
|
-
const pct = activeWorkers.length > 0 ? ((activeWorkers.length - balPending) / activeWorkers.length) : 0;
|
|
3483
|
-
const barW = Math.min(20, startupTw - 40);
|
|
3484
|
-
const filled = Math.round(pct * barW);
|
|
3485
|
-
const bar = rgb(251, 191, 36) + '█'.repeat(filled) + rgb(50, 50, 70) + '░'.repeat(barW - filled) + c.reset;
|
|
3486
|
-
balMoveToRow(balBaseRow);
|
|
3487
|
-
process.stdout.write(` ${rgb(251, 191, 36)}${spin}${c.reset} ${c.dim}Balance...${c.reset} ${bar} ${c.bold}${rgb(52, 211, 153)}${activeWorkers.length - balPending}${c.reset}${c.dim}/${c.reset}${c.white}${activeWorkers.length}${c.reset} \x1b[K`);
|
|
3488
|
-
};
|
|
3489
|
-
const balSpinnerInterval = setInterval(drawBalProgress, 80);
|
|
3490
|
-
|
|
3491
|
-
await Promise.all(activeWorkers.map(async (w, i) => {
|
|
3405
|
+
await Promise.all(activeWorkers.map(async (w) => {
|
|
3492
3406
|
try { await w.checkBalance(true); } catch {}
|
|
3493
|
-
|
|
3407
|
+
}));
|
|
3408
|
+
|
|
3409
|
+
// Re-print table with results
|
|
3410
|
+
console.log(` ${'─'.repeat(balVis)}`);
|
|
3411
|
+
for (let i = 0; i < activeWorkers.length; i++) {
|
|
3412
|
+
const w = activeWorkers[i];
|
|
3494
3413
|
const num = `${c.dim}${(i + 1).toString().padStart(bColNum - 1)}${c.reset}`;
|
|
3495
3414
|
const name = (w.username || w.account.label || '?').substring(0, bColName).padEnd(bColName);
|
|
3496
3415
|
const wallet = w.stats?.balance || 0;
|
|
@@ -3500,14 +3419,9 @@ async function start(apiKey, apiUrl) {
|
|
|
3500
3419
|
const walletStr = `${c.green}⏣${wallet.toLocaleString()}${c.reset}`;
|
|
3501
3420
|
const bankStr = `${c.cyan}⏣${bank.toLocaleString()}${c.reset}`;
|
|
3502
3421
|
const totalStr = `${c.bold}⏣${(wallet + bank).toLocaleString()}${c.reset}`;
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
balDone++;
|
|
3507
|
-
}));
|
|
3508
|
-
|
|
3509
|
-
clearInterval(balSpinnerInterval);
|
|
3510
|
-
process.stdout.write(`\r\x1b[2K`);
|
|
3422
|
+
console.log(` ${num} ${rgb(52, 211, 153)}✓${c.reset} ${name} ${walletStr.padEnd(bColWallet + 4)} ${bankStr.padEnd(bColBank + 4)} ${totalStr.padEnd(bColTotal + 3)} ${lsColor}♥${ls}${c.reset}`);
|
|
3423
|
+
}
|
|
3424
|
+
console.log(` ${'─'.repeat(balVis)}`);
|
|
3511
3425
|
|
|
3512
3426
|
let totalWallet = 0, totalBank = 0, noLifesaverAccounts = [];
|
|
3513
3427
|
for (const w of activeWorkers) {
|
|
@@ -3521,7 +3435,6 @@ async function start(apiKey, apiUrl) {
|
|
|
3521
3435
|
}
|
|
3522
3436
|
console.log('');
|
|
3523
3437
|
|
|
3524
|
-
|
|
3525
3438
|
// Phase 2.75: Check DM history for deaths/level-ups (sequential, fast)
|
|
3526
3439
|
console.log(` ${rgb(139, 92, 246)}${BRAILLE_SPIN[0]}${c.reset} ${c.dim}Checking DM history...${c.reset}`);
|
|
3527
3440
|
let dmDeaths = 0, dmLevelUps = 0, dmNoLs = [];
|