@darksol/terminal 0.10.0 → 0.12.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/src/cli.js CHANGED
@@ -2,12 +2,15 @@ import { Command } from 'commander';
2
2
  import { showBanner, showMiniBanner, showSection } from './ui/banner.js';
3
3
  import { theme } from './ui/theme.js';
4
4
  import { kvDisplay, success, error, warn, info } from './ui/components.js';
5
+ import { createDashboard } from './ui/dashboard.js';
5
6
  import { getConfig, setConfig, getAllConfig, getRPC, setRPC, configPath } from './config/store.js';
6
7
  import { createWallet, importWallet, showWallets, getBalance, useWallet, exportWallet, sendFunds, receiveAddress } from './wallet/manager.js';
7
8
  import { showPortfolio } from './wallet/portfolio.js';
8
9
  import { showHistory } from './wallet/history.js';
9
10
  import { showGas } from './services/gas.js';
10
11
  import { watchPrice, checkPrices } from './services/watch.js';
12
+ import { getWhaleActivity, listTracked, mirrorTrade, stopTracking, trackWallet } from './services/whale.js';
13
+ import { startWhaleFeed } from './services/whale-monitor.js';
11
14
  import { mailSetup, mailCreate, mailInboxes, mailSend, mailList, mailRead, mailReply, mailForward, mailThreads, mailDelete, mailUse, mailStats, mailStatus } from './services/mail.js';
12
15
  import { startWebShell } from './web/server.js';
13
16
  import { executeSwap } from './trading/swap.js';
@@ -22,6 +25,17 @@ import { cardsCatalog, cardsOrder, cardsStatus } from './services/cards.js';
22
25
  import { facilitatorHealth, facilitatorVerify, facilitatorSettle } from './services/facilitator.js';
23
26
  import { buildersLeaderboard, buildersLookup, buildersFeed } from './services/builders.js';
24
27
  import { createScript, listScripts, runScript, showScript, editScript, deleteScript, cloneScript, listTemplates } from './scripts/engine.js';
28
+ import {
29
+ launchBrowserCommand,
30
+ navigateBrowserCommand,
31
+ browserScreenshotCommand,
32
+ browserClickCommand,
33
+ browserTypeCommand,
34
+ browserEvalCommand,
35
+ browserCloseCommand,
36
+ showBrowserStatus,
37
+ installPlaywrightBrowsers,
38
+ } from './services/browser.js';
25
39
  import { showTradingTips, showScriptTips, showNetworkReference, showQuickStart, showWalletSummary, showTokenInfo, showTxResult } from './utils/helpers.js';
26
40
  import { addKey, removeKey, listKeys } from './config/keys.js';
27
41
  import { parseIntent, startChat, adviseStrategy, analyzeToken, executeIntent } from './llm/intent.js';
@@ -31,6 +45,9 @@ import { runSetupWizard } from './setup/wizard.js';
31
45
  import { displaySoul, hasSoul, resetSoul, runSoulSetup } from './soul/index.js';
32
46
  import { clearMemories, exportMemories, getRecentMemories, searchMemories } from './memory/index.js';
33
47
  import { getAgentStatus, planAgentGoal, runAgentTask } from './agent/index.js';
48
+ import { getAuditLog, getStatus as getAutoStatus, listStrategies as listAutoStrategies, startAutonomous, stopAutonomous } from './agent/autonomous.js';
49
+ import { daemonStart, daemonStop, daemonStatus, daemonRestart } from './daemon/index.js';
50
+ import { telegramSetup, telegramStartForeground, telegramStopCommand, telegramStatusCommand, telegramSendCommand } from './services/telegram.js';
34
51
  import { createRequire } from 'module';
35
52
  import { resolve } from 'path';
36
53
  import { getConfiguredModel, getProviderDefaultModel } from './llm/models.js';
@@ -316,6 +333,159 @@ export function cli(argv) {
316
333
  .description('Execute pending DCA orders')
317
334
  .action(() => runDCA());
318
335
 
336
+ const auto = program
337
+ .command('auto')
338
+ .description('Autonomous trader mode - goal-based automated execution');
339
+
340
+ auto
341
+ .command('start <goal>')
342
+ .description('Start an autonomous strategy from a natural language goal')
343
+ .requiredOption('--budget <amount>', 'Total USDC budget')
344
+ .requiredOption('--max-per-trade <amount>', 'Per-trade cap')
345
+ .option('--risk <level>', 'Risk level (conservative|moderate|aggressive)', 'moderate')
346
+ .option('--interval <minutes>', 'Evaluation interval in minutes', '5')
347
+ .option('--chain <chain>', 'Target chain (repeatable)', (value, previous = []) => previous.concat(value), [])
348
+ .option('--dry-run', 'Simulate decisions without executing swaps')
349
+ .action(async (goal, opts) => {
350
+ showMiniBanner();
351
+ showSection('AUTONOMOUS START');
352
+ const strategy = await startAutonomous(goal, {
353
+ budget: parseFloat(opts.budget),
354
+ maxPerTrade: parseFloat(opts.maxPerTrade),
355
+ riskLevel: opts.risk,
356
+ interval: parseFloat(opts.interval),
357
+ chains: opts.chain,
358
+ dryRun: opts.dryRun,
359
+ });
360
+
361
+ kvDisplay([
362
+ ['ID', strategy.id],
363
+ ['Goal', strategy.goal],
364
+ ['Budget', `${strategy.budget} USDC`],
365
+ ['Max / Trade', `${strategy.maxPerTrade} USDC`],
366
+ ['Risk', strategy.riskLevel],
367
+ ['Mode', strategy.dryRun ? 'dry-run' : 'live'],
368
+ ['Next Check', strategy.nextCheckAt],
369
+ ]);
370
+ console.log('');
371
+ });
372
+
373
+ auto
374
+ .command('stop <id>')
375
+ .description('Stop a running autonomous strategy')
376
+ .action((id) => {
377
+ showMiniBanner();
378
+ showSection('AUTONOMOUS STOP');
379
+ const strategy = stopAutonomous(id);
380
+ if (!strategy) {
381
+ warn(`Strategy not found: ${id}`);
382
+ console.log('');
383
+ return;
384
+ }
385
+ success(`Stopped ${strategy.id}`);
386
+ console.log('');
387
+ });
388
+
389
+ auto
390
+ .command('status [id]')
391
+ .description('Show one autonomous strategy or all active strategies')
392
+ .action((id) => {
393
+ showMiniBanner();
394
+ showSection('AUTONOMOUS STATUS');
395
+
396
+ if (!id) {
397
+ const items = getAutoStatus();
398
+ if (!items.length) {
399
+ warn('No autonomous strategies found');
400
+ console.log('');
401
+ return;
402
+ }
403
+ items.forEach((item) => {
404
+ kvDisplay([
405
+ ['ID', item.id],
406
+ ['Status', item.status],
407
+ ['Spent', `${item.spent}/${item.budget} USDC`],
408
+ ['Trades', String(item.tradesExecuted)],
409
+ ['PnL', `${item.pnl}`],
410
+ ['Next Check', item.nextCheckAt || '-'],
411
+ ]);
412
+ console.log('');
413
+ });
414
+ return;
415
+ }
416
+
417
+ const strategy = getAutoStatus(id);
418
+ if (!strategy) {
419
+ warn(`Strategy not found: ${id}`);
420
+ console.log('');
421
+ return;
422
+ }
423
+
424
+ kvDisplay([
425
+ ['ID', strategy.id],
426
+ ['Goal', strategy.goal],
427
+ ['Status', strategy.status],
428
+ ['Spent', `${strategy.spent}/${strategy.budget} USDC`],
429
+ ['Trades', String(strategy.tradesExecuted)],
430
+ ['PnL', `${strategy.pnl}`],
431
+ ['Risk', strategy.riskLevel],
432
+ ['Mode', strategy.dryRun ? 'dry-run' : 'live'],
433
+ ['Next Check', strategy.nextCheckAt || '-'],
434
+ ['Last Decision', strategy.lastDecision || '-'],
435
+ ]);
436
+ console.log('');
437
+ });
438
+
439
+ auto
440
+ .command('log <id>')
441
+ .description('Show the recent autonomous audit log')
442
+ .option('--limit <n>', 'Number of audit entries', '20')
443
+ .action((id, opts) => {
444
+ showMiniBanner();
445
+ showSection('AUTONOMOUS AUDIT');
446
+ const entries = getAuditLog(id, parseInt(opts.limit, 10));
447
+ if (!entries.length) {
448
+ warn('No audit entries found');
449
+ console.log('');
450
+ return;
451
+ }
452
+
453
+ entries.forEach((entry) => {
454
+ const headline = `${entry.timestamp} ${entry.type}${entry.action ? ` ${entry.action}` : ''}`;
455
+ console.log(` ${theme.gold(headline)}`);
456
+ if (entry.reason) console.log(` ${theme.dim(entry.reason)}`);
457
+ if (entry.message) console.log(` ${theme.dim(entry.message)}`);
458
+ if (entry.price !== undefined) console.log(` ${theme.dim(`price: ${entry.price}`)}`);
459
+ console.log('');
460
+ });
461
+ });
462
+
463
+ auto
464
+ .command('list')
465
+ .description('List all autonomous strategies')
466
+ .action(() => {
467
+ showMiniBanner();
468
+ showSection('AUTONOMOUS STRATEGIES');
469
+ const items = listAutoStrategies();
470
+ if (!items.length) {
471
+ warn('No autonomous strategies found');
472
+ console.log('');
473
+ return;
474
+ }
475
+
476
+ items.forEach((item) => {
477
+ kvDisplay([
478
+ ['ID', item.id],
479
+ ['Status', item.status],
480
+ ['Spent', `${item.spent}/${item.budget} USDC`],
481
+ ['Trades', String(item.tradesExecuted)],
482
+ ['PnL', `${item.pnl}`],
483
+ ['Next Check', item.nextCheckAt || '-'],
484
+ ]);
485
+ console.log('');
486
+ });
487
+ });
488
+
319
489
  // ═══════════════════════════════════════
320
490
  // MARKET COMMANDS
321
491
  // ═══════════════════════════════════════
@@ -608,6 +778,64 @@ export function cli(argv) {
608
778
  .option('--no-open', 'Don\'t auto-open browser')
609
779
  .action((opts) => startWebShell(opts));
610
780
 
781
+ const browser = program
782
+ .command('browser')
783
+ .description('Playwright-powered browser automation');
784
+
785
+ browser
786
+ .command('launch')
787
+ .description('Launch a browser instance and keep it running')
788
+ .option('--headed', 'Launch with a visible browser window')
789
+ .option('--type <browser>', 'Browser type', 'chromium')
790
+ .option('--profile <name>', 'Browser profile name', 'default')
791
+ .action((opts) => launchBrowserCommand(opts));
792
+
793
+ browser
794
+ .command('navigate <url>')
795
+ .description('Navigate the active page to a URL')
796
+ .action((url) => navigateBrowserCommand(url));
797
+
798
+ browser
799
+ .command('screenshot [filename]')
800
+ .description('Capture a screenshot of the active page')
801
+ .action((filename) => browserScreenshotCommand(filename));
802
+
803
+ browser
804
+ .command('click <selector>')
805
+ .description('Click an element on the active page')
806
+ .action((selector) => browserClickCommand(selector));
807
+
808
+ browser
809
+ .command('type <selector> <text>')
810
+ .description('Type text into an element on the active page')
811
+ .action((selector, text) => browserTypeCommand(selector, text));
812
+
813
+ browser
814
+ .command('eval <js>')
815
+ .description('Evaluate JavaScript in the active page')
816
+ .action((js) => browserEvalCommand(js));
817
+
818
+ browser
819
+ .command('close')
820
+ .description('Close the running browser service')
821
+ .action(() => browserCloseCommand());
822
+
823
+ browser
824
+ .command('status')
825
+ .description('Show current browser state')
826
+ .action(() => showBrowserStatus());
827
+
828
+ browser
829
+ .command('install')
830
+ .description('Install a Playwright browser binary after user confirmation')
831
+ .action(async () => {
832
+ try {
833
+ await installPlaywrightBrowsers();
834
+ } catch (err) {
835
+ error(err.message);
836
+ }
837
+ });
838
+
611
839
  // ═══════════════════════════════════════
612
840
  // PORTFOLIO SHORTCUT
613
841
  // ═══════════════════════════════════════
@@ -1031,6 +1259,114 @@ export function cli(argv) {
1031
1259
  .description('Uninstall a skill')
1032
1260
  .action((name) => uninstallSkill(name));
1033
1261
 
1262
+ // ═══════════════════════════════════════
1263
+ // DAEMON COMMANDS
1264
+ // ═══════════════════════════════════════
1265
+ const daemon = program
1266
+ .command('daemon')
1267
+ .description('Background daemon - manage persistent services');
1268
+
1269
+ daemon
1270
+ .command('start')
1271
+ .description('Start the background daemon')
1272
+ .option('-p, --port <port>', 'Health server port', '18792')
1273
+ .action((opts) => daemonStart(opts));
1274
+
1275
+ daemon
1276
+ .command('stop')
1277
+ .description('Stop the background daemon')
1278
+ .action(() => daemonStop());
1279
+
1280
+ daemon
1281
+ .command('status')
1282
+ .description('Show daemon status and health')
1283
+ .option('-p, --port <port>', 'Health server port', '18792')
1284
+ .action((opts) => daemonStatus(opts));
1285
+
1286
+ daemon
1287
+ .command('restart')
1288
+ .description('Restart the daemon')
1289
+ .option('-p, --port <port>', 'Health server port', '18792')
1290
+ .action((opts) => daemonRestart(opts));
1291
+
1292
+ const whale = program
1293
+ .command('whale')
1294
+ .description('Whale Radar - wallet tracking and mirror trades');
1295
+
1296
+ whale
1297
+ .command('track <address>')
1298
+ .description('Track a wallet for new activity')
1299
+ .option('-c, --chain <chain>', 'Chain to monitor', 'base')
1300
+ .option('-l, --label <label>', 'Friendly wallet label')
1301
+ .option('--notify', 'Enable terminal notifications', true)
1302
+ .action((address, opts) => trackWallet(address, opts));
1303
+
1304
+ whale
1305
+ .command('list')
1306
+ .description('List tracked whale wallets')
1307
+ .action(() => listTracked());
1308
+
1309
+ whale
1310
+ .command('stop <address>')
1311
+ .description('Stop tracking a wallet')
1312
+ .action((address) => stopTracking(address));
1313
+
1314
+ whale
1315
+ .command('mirror <address>')
1316
+ .description('Enable copy-trading for a tracked whale')
1317
+ .option('--max <amount>', 'Max USDC-equivalent per trade')
1318
+ .option('-s, --slippage <pct>', 'Mirror trade slippage %', '2')
1319
+ .option('--dry-run', 'Log mirror trades without executing')
1320
+ .action((address, opts) => mirrorTrade(address, {
1321
+ maxPerTrade: opts.max ? parseFloat(opts.max) : null,
1322
+ slippage: parseFloat(opts.slippage),
1323
+ dryRun: Boolean(opts.dryRun),
1324
+ }));
1325
+
1326
+ whale
1327
+ .command('activity <address>')
1328
+ .description('Show recent activity for a whale wallet')
1329
+ .option('-l, --limit <n>', 'Number of transactions', '10')
1330
+ .option('-c, --chain <chain>', 'Chain to query', 'base')
1331
+ .action((address, opts) => getWhaleActivity(address, parseInt(opts.limit, 10), opts));
1332
+
1333
+ whale
1334
+ .command('feed')
1335
+ .description('Open the live whale event feed')
1336
+ .action(() => startWhaleFeed());
1337
+
1338
+ // ═══════════════════════════════════════
1339
+ // TELEGRAM COMMANDS
1340
+ // ═══════════════════════════════════════
1341
+ const telegram = program
1342
+ .command('telegram')
1343
+ .description('Telegram bot - AI chat via Telegram');
1344
+
1345
+ telegram
1346
+ .command('setup')
1347
+ .description('Interactive Telegram bot setup with BotFather')
1348
+ .action(() => telegramSetup());
1349
+
1350
+ telegram
1351
+ .command('start')
1352
+ .description('Start the Telegram bot (foreground)')
1353
+ .action(() => telegramStartForeground());
1354
+
1355
+ telegram
1356
+ .command('stop')
1357
+ .description('Stop the Telegram bot')
1358
+ .action(() => telegramStopCommand());
1359
+
1360
+ telegram
1361
+ .command('status')
1362
+ .description('Show bot info and connection state')
1363
+ .action(() => telegramStatusCommand());
1364
+
1365
+ telegram
1366
+ .command('send <chatId> <message...>')
1367
+ .description('Send a direct message to a chat')
1368
+ .action((chatId, message) => telegramSendCommand(chatId, message));
1369
+
1034
1370
  // ═══════════════════════════════════════
1035
1371
  // TIPS & REFERENCE COMMANDS
1036
1372
  // ═══════════════════════════════════════
@@ -1256,6 +1592,19 @@ export function cli(argv) {
1256
1592
  }
1257
1593
  });
1258
1594
 
1595
+ program
1596
+ .command('dash')
1597
+ .description('Launch the live terminal dashboard')
1598
+ .option('--refresh <seconds>', 'Refresh interval in seconds', '30')
1599
+ .option('--compact', 'Use the compact 2-panel layout')
1600
+ .action(async (opts) => {
1601
+ const dashboard = createDashboard({
1602
+ refresh: parseInt(opts.refresh, 10),
1603
+ compact: Boolean(opts.compact),
1604
+ });
1605
+ await dashboard.ready;
1606
+ });
1607
+
1259
1608
  // ═══════════════════════════════════════
1260
1609
  // FUZZY / NATURAL LANGUAGE FALLBACK
1261
1610
  // ═══════════════════════════════════════
@@ -1584,6 +1933,7 @@ function showCommandList() {
1584
1933
  ['watch', 'Live price monitoring + alerts'],
1585
1934
  ['gas', 'Gas prices & cost estimates'],
1586
1935
  ['trade', 'Swap tokens, snipe, trading'],
1936
+ ['auto', 'Autonomous trader strategies'],
1587
1937
  ['bridge', 'Cross-chain bridge (LI.FI)'],
1588
1938
  ['dca', 'Dollar-cost averaging orders'],
1589
1939
  ['ai chat', 'Standalone AI chat session'],
@@ -1594,6 +1944,7 @@ function showCommandList() {
1594
1944
  ['memory', 'Persistent cross-session memory'],
1595
1945
  ['script', 'Execution scripts & strategies'],
1596
1946
  ['market', 'Market intel & token data'],
1947
+ ['whale', 'Whale Radar - wallet tracking'],
1597
1948
  ['oracle', 'On-chain random oracle'],
1598
1949
  ['casino', 'The Clawsino - betting'],
1599
1950
  ['poker', 'GTO Poker Arena — heads-up holdem'],
@@ -1602,6 +1953,9 @@ function showCommandList() {
1602
1953
  ['mail', 'AgentMail - email for your agent'],
1603
1954
  ['facilitator', 'x402 payment facilitator'],
1604
1955
  ['skills', 'Agent skill directory'],
1956
+ ['browser', 'Playwright browser automation'],
1957
+ ['daemon', 'Background service daemon'],
1958
+ ['telegram', 'Telegram bot - AI chat'],
1605
1959
  ['serve', 'Launch web terminal in browser'],
1606
1960
  ['setup', 'Re-run setup wizard'],
1607
1961
  ['config', 'Terminal configuration'],
@@ -126,6 +126,14 @@ export const SERVICES = {
126
126
  docsUrl: 'https://docs.dexscreener.com',
127
127
  validate: (key) => key.length > 10,
128
128
  },
129
+ etherscan: {
130
+ name: 'Etherscan',
131
+ category: 'data',
132
+ description: 'Explorer APIs — Etherscan, Basescan, Arbiscan, Polygonscan',
133
+ envVar: 'ETHERSCAN_API_KEY',
134
+ docsUrl: 'https://etherscan.io/apis',
135
+ validate: (key) => key.length > 10,
136
+ },
129
137
  defillama: {
130
138
  name: 'DefiLlama',
131
139
  category: 'data',
@@ -178,6 +186,16 @@ export const SERVICES = {
178
186
  docsUrl: 'https://console.agentmail.to',
179
187
  validate: (key) => key.startsWith('am_'),
180
188
  },
189
+
190
+ // Messaging
191
+ telegram: {
192
+ name: 'Telegram Bot',
193
+ category: 'messaging',
194
+ description: 'Telegram bot token — AI chat via Telegram',
195
+ envVar: 'TELEGRAM_BOT_TOKEN',
196
+ docsUrl: 'https://core.telegram.org/bots#botfather',
197
+ validate: (key) => /^\d+:.+$/.test(key),
198
+ },
181
199
  paraswap: {
182
200
  name: 'ParaSwap',
183
201
  category: 'trading',
@@ -288,6 +306,14 @@ export function getKeyFromEnv(service) {
288
306
  return null;
289
307
  }
290
308
 
309
+ /**
310
+ * Get an API key without prompting.
311
+ * Prefers auto-stored keys, then environment variables.
312
+ */
313
+ export function getApiKey(service) {
314
+ return getKeyAuto(service) || getKeyFromEnv(service);
315
+ }
316
+
291
317
  /**
292
318
  * Remove a key
293
319
  */
@@ -319,8 +345,8 @@ export function listKeys() {
319
345
 
320
346
  showSection('API KEY VAULT');
321
347
 
322
- const categories = ['llm', 'data', 'rpc', 'trading', 'email'];
323
- const catNames = { llm: '🧠 LLM PROVIDERS', data: '📊 DATA PROVIDERS', rpc: '🌐 RPC PROVIDERS', trading: '📈 TRADING', email: '📧 EMAIL' };
348
+ const categories = ['llm', 'data', 'rpc', 'trading', 'email', 'messaging'];
349
+ const catNames = { llm: '🧠 LLM PROVIDERS', data: '📊 DATA PROVIDERS', rpc: '🌐 RPC PROVIDERS', trading: '📈 TRADING', email: '📧 EMAIL', messaging: '💬 MESSAGING' };
324
350
 
325
351
  for (const cat of categories) {
326
352
  console.log('');
@@ -51,6 +51,12 @@ const config = new Conf({
51
51
  maxOrders: 100,
52
52
  },
53
53
  },
54
+ autonomous: {
55
+ type: 'object',
56
+ default: {
57
+ strategies: [],
58
+ },
59
+ },
54
60
  services: {
55
61
  type: 'object',
56
62
  default: {