@darksol/terminal 0.13.0 → 0.14.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/README.md +7 -1
- package/package.json +1 -1
- package/src/cli.js +54 -0
- package/src/llm/intent.js +13 -0
- package/src/services/approvals.js +452 -0
- package/src/trading/arb-ai.js +827 -0
- package/src/trading/arb.js +57 -9
- package/src/web/commands.js +46 -2
package/src/trading/arb.js
CHANGED
|
@@ -22,6 +22,7 @@ import { spinner, kvDisplay, success, error, warn, info, table } from '../ui/com
|
|
|
22
22
|
import { showSection } from '../ui/banner.js';
|
|
23
23
|
import { resolveToken, getTokenInfo } from './swap.js';
|
|
24
24
|
import { getDexesForChain, DEX_ADAPTERS } from './arb-dexes.js';
|
|
25
|
+
import { aiFilterOpportunity, aiScoreOpportunities } from './arb-ai.js';
|
|
25
26
|
|
|
26
27
|
// ═══════════════════════════════════════════════════════════════
|
|
27
28
|
// CONSTANTS & PATHS
|
|
@@ -346,21 +347,63 @@ export async function arbScan(opts = {}) {
|
|
|
346
347
|
console.log('');
|
|
347
348
|
|
|
348
349
|
const profitable = allOpps.filter(o => o.netProfitUsd >= minProfit);
|
|
349
|
-
|
|
350
|
+
|
|
351
|
+
// Apply AI pattern filter (fast, no API call)
|
|
352
|
+
const aiFiltered = profitable.map(o => {
|
|
353
|
+
const aiResult = aiFilterOpportunity(o);
|
|
354
|
+
return { ...o, aiScore: aiResult.score, aiPass: aiResult.pass, aiReason: aiResult.reason };
|
|
355
|
+
});
|
|
356
|
+
const aiPassed = aiFiltered.filter(o => o.aiPass);
|
|
357
|
+
const aiSkipped = aiFiltered.length - aiPassed.length;
|
|
358
|
+
|
|
359
|
+
displayOpportunities(aiPassed);
|
|
360
|
+
|
|
361
|
+
if (aiSkipped > 0) {
|
|
362
|
+
info(`AI filter skipped ${aiSkipped} low-confidence opportunity(s) — run 'darksol arb learn' to improve accuracy`);
|
|
363
|
+
console.log('');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// AI deep scoring for top opportunities (uses LLM)
|
|
367
|
+
if (aiPassed.length > 0 && !opts.skipAi) {
|
|
368
|
+
const scoreSpin = spinner('AI scoring opportunities...').start();
|
|
369
|
+
try {
|
|
370
|
+
const scoring = await aiScoreOpportunities(aiPassed);
|
|
371
|
+
if (scoring?.scored?.length > 0) {
|
|
372
|
+
scoreSpin.succeed('AI risk scoring complete');
|
|
373
|
+
console.log('');
|
|
374
|
+
console.log(theme.gold(' 🧠 AI Risk Assessment:'));
|
|
375
|
+
for (const s of scoring.scored) {
|
|
376
|
+
const riskColor = s.riskScore <= 3 ? theme.success : s.riskScore <= 6 ? theme.warning : theme.error;
|
|
377
|
+
const recColor = s.recommendation === 'execute' ? theme.success : s.recommendation === 'watch' ? theme.warning : theme.error;
|
|
378
|
+
console.log(` ${theme.bright(s.pair)} — risk: ${riskColor(String(s.riskScore) + '/10')} | MEV: ${theme.dim(s.mevLikelihood)} | ${recColor(s.recommendation.toUpperCase())}`);
|
|
379
|
+
console.log(` ${theme.dim(s.reason)}`);
|
|
380
|
+
}
|
|
381
|
+
if (scoring.summary) {
|
|
382
|
+
console.log('');
|
|
383
|
+
console.log(` ${theme.dim('Summary: ' + scoring.summary)}`);
|
|
384
|
+
}
|
|
385
|
+
console.log('');
|
|
386
|
+
} else {
|
|
387
|
+
scoreSpin.succeed('AI scoring returned no results');
|
|
388
|
+
}
|
|
389
|
+
} catch {
|
|
390
|
+
scoreSpin.warn('AI scoring unavailable — showing raw results');
|
|
391
|
+
}
|
|
392
|
+
}
|
|
350
393
|
|
|
351
394
|
// Log everything (including unprofitable) to history
|
|
352
395
|
for (const o of allOpps) {
|
|
353
396
|
recordArb({ type: 'scan', ...o });
|
|
354
397
|
}
|
|
355
398
|
|
|
356
|
-
if (
|
|
399
|
+
if (aiPassed.length > 0) {
|
|
357
400
|
console.log('');
|
|
358
401
|
console.log(theme.warning(' ⚠ MEV Warning: ') + theme.dim('simple two-tx arb is likely to be front-run.'));
|
|
359
402
|
console.log(theme.dim(' Use WSS endpoints + Flashbots bundles for reliable execution.'));
|
|
360
403
|
console.log('');
|
|
361
404
|
}
|
|
362
405
|
|
|
363
|
-
return
|
|
406
|
+
return aiPassed;
|
|
364
407
|
} catch (err) {
|
|
365
408
|
spin.fail('Scan failed');
|
|
366
409
|
error(err.message);
|
|
@@ -427,15 +470,20 @@ export async function arbMonitor(opts = {}) {
|
|
|
427
470
|
}
|
|
428
471
|
|
|
429
472
|
const profitable = allOpps.filter(o => o.netProfitUsd >= minProfit);
|
|
430
|
-
oppsFound += profitable.length;
|
|
431
473
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
474
|
+
// AI pattern filter (fast, no API call)
|
|
475
|
+
const aiPassed = profitable.filter(o => aiFilterOpportunity(o).pass);
|
|
476
|
+
oppsFound += aiPassed.length;
|
|
477
|
+
|
|
478
|
+
if (aiPassed.length > 0) {
|
|
479
|
+
const skipped = profitable.length - aiPassed.length;
|
|
480
|
+
const skipNote = skipped > 0 ? ` (${skipped} AI-filtered)` : '';
|
|
481
|
+
blockSpin.succeed(`[Block ${blockNumber}] ${aiPassed.length} opportunity(s) found${skipNote}`);
|
|
482
|
+
displayOpportunities(aiPassed.slice(0, 5));
|
|
435
483
|
|
|
436
484
|
// Auto-execute if requested and cooldown satisfied
|
|
437
485
|
if (execute && !dryRun && Date.now() - lastExecute > (arbCfg.cooldownMs || 5000)) {
|
|
438
|
-
const best =
|
|
486
|
+
const best = aiPassed.sort((a, b) => b.netProfitUsd - a.netProfitUsd)[0];
|
|
439
487
|
if (best.netProfitUsd >= minProfit) {
|
|
440
488
|
await arbExecute({ opportunity: best, dryRun: false, skipConfirm: true });
|
|
441
489
|
lastExecute = Date.now();
|
|
@@ -443,7 +491,7 @@ export async function arbMonitor(opts = {}) {
|
|
|
443
491
|
}
|
|
444
492
|
}
|
|
445
493
|
} else {
|
|
446
|
-
blockSpin.text = `[Block ${blockNumber}] No profitable arb found (${allOpps.length}
|
|
494
|
+
blockSpin.text = `[Block ${blockNumber}] No profitable arb found (${allOpps.length} scanned, ${profitable.length} pre-filter)`;
|
|
447
495
|
blockSpin.succeed();
|
|
448
496
|
}
|
|
449
497
|
|
package/src/web/commands.js
CHANGED
|
@@ -1390,14 +1390,58 @@ async function cmdArb(args, ws) {
|
|
|
1390
1390
|
return {};
|
|
1391
1391
|
}
|
|
1392
1392
|
|
|
1393
|
+
if (sub === 'ai') {
|
|
1394
|
+
try {
|
|
1395
|
+
const { aiStrategyBriefing } = await import('../trading/arb-ai.js');
|
|
1396
|
+
await aiStrategyBriefing({ chain: args[1] || getConfig('chain') || 'base' });
|
|
1397
|
+
} catch (e) {
|
|
1398
|
+
ws.sendLine(` ${ANSI.red}AI briefing failed: ${e.message}${ANSI.reset}`);
|
|
1399
|
+
}
|
|
1400
|
+
return {};
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
if (sub === 'discover') {
|
|
1404
|
+
try {
|
|
1405
|
+
const { aiDiscoverPairs } = await import('../trading/arb-ai.js');
|
|
1406
|
+
await aiDiscoverPairs({ chain: args[1] || getConfig('chain') || 'base' });
|
|
1407
|
+
} catch (e) {
|
|
1408
|
+
ws.sendLine(` ${ANSI.red}Discovery failed: ${e.message}${ANSI.reset}`);
|
|
1409
|
+
}
|
|
1410
|
+
return {};
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
if (sub === 'tune') {
|
|
1414
|
+
try {
|
|
1415
|
+
const { aiTuneThresholds } = await import('../trading/arb-ai.js');
|
|
1416
|
+
await aiTuneThresholds({ chain: args[1] || getConfig('chain') || 'base' });
|
|
1417
|
+
} catch (e) {
|
|
1418
|
+
ws.sendLine(` ${ANSI.red}Tuning failed: ${e.message}${ANSI.reset}`);
|
|
1419
|
+
}
|
|
1420
|
+
return {};
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
if (sub === 'learn') {
|
|
1424
|
+
try {
|
|
1425
|
+
const { aiLearn } = await import('../trading/arb-ai.js');
|
|
1426
|
+
await aiLearn({ chain: args[1] || getConfig('chain') || 'base' });
|
|
1427
|
+
} catch (e) {
|
|
1428
|
+
ws.sendLine(` ${ANSI.red}Learning failed: ${e.message}${ANSI.reset}`);
|
|
1429
|
+
}
|
|
1430
|
+
return {};
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1393
1433
|
// Default: show arb menu
|
|
1394
1434
|
ws.sendLine(`${ANSI.gold} ◆ ARBITRAGE${ANSI.reset}`);
|
|
1395
1435
|
ws.sendLine(`${ANSI.dim} ${'─'.repeat(50)}${ANSI.reset}`);
|
|
1396
|
-
ws.sendLine(` ${ANSI.white}
|
|
1436
|
+
ws.sendLine(` ${ANSI.white}AI-powered cross-DEX arbitrage${ANSI.reset}`);
|
|
1397
1437
|
ws.sendLine('');
|
|
1398
1438
|
|
|
1399
1439
|
ws.sendMenu('arb_action', '◆ Arb Actions', [
|
|
1400
|
-
{ value: 'arb scan', label: '🔍 Scan', desc: '
|
|
1440
|
+
{ value: 'arb scan', label: '🔍 Scan', desc: 'AI-scored DEX price comparison' },
|
|
1441
|
+
{ value: 'arb ai', label: '🧠 AI Briefing', desc: 'Strategy assessment + recommendations' },
|
|
1442
|
+
{ value: 'arb discover', label: '📈 Discover', desc: 'AI pair discovery — find new opportunities' },
|
|
1443
|
+
{ value: 'arb tune', label: '🔧 Tune', desc: 'AI threshold optimization' },
|
|
1444
|
+
{ value: 'arb learn', label: '📚 Learn', desc: 'Run learning cycle on history' },
|
|
1401
1445
|
{ value: 'arb stats', label: '📊 Stats', desc: 'View arb history & PnL' },
|
|
1402
1446
|
{ value: 'arb info', label: '📖 Guide', desc: 'How arb works, setup tips, risks' },
|
|
1403
1447
|
{ value: 'back', label: '← Back', desc: '' },
|