@darksol/terminal 0.9.2 → 0.11.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
@@ -17,10 +17,22 @@ import { executeLifiSwap, executeLifiBridge, checkBridgeStatus, showSupportedCha
17
17
  import { topMovers, tokenDetail, compareTokens } from './services/market.js';
18
18
  import { oracleFlip, oracleDice, oracleNumber, oracleShuffle, oracleHealth } from './services/oracle.js';
19
19
  import { casinoBet, casinoTables, casinoStats, casinoReceipt, casinoHealth, casinoVerify } from './services/casino.js';
20
+ import { pokerNewGame, pokerAction, pokerStatus, pokerHistory } from './services/poker.js';
20
21
  import { cardsCatalog, cardsOrder, cardsStatus } from './services/cards.js';
21
22
  import { facilitatorHealth, facilitatorVerify, facilitatorSettle } from './services/facilitator.js';
22
23
  import { buildersLeaderboard, buildersLookup, buildersFeed } from './services/builders.js';
23
24
  import { createScript, listScripts, runScript, showScript, editScript, deleteScript, cloneScript, listTemplates } from './scripts/engine.js';
25
+ import {
26
+ launchBrowserCommand,
27
+ navigateBrowserCommand,
28
+ browserScreenshotCommand,
29
+ browserClickCommand,
30
+ browserTypeCommand,
31
+ browserEvalCommand,
32
+ browserCloseCommand,
33
+ showBrowserStatus,
34
+ installPlaywrightBrowsers,
35
+ } from './services/browser.js';
24
36
  import { showTradingTips, showScriptTips, showNetworkReference, showQuickStart, showWalletSummary, showTokenInfo, showTxResult } from './utils/helpers.js';
25
37
  import { addKey, removeKey, listKeys } from './config/keys.js';
26
38
  import { parseIntent, startChat, adviseStrategy, analyzeToken, executeIntent } from './llm/intent.js';
@@ -30,6 +42,8 @@ import { runSetupWizard } from './setup/wizard.js';
30
42
  import { displaySoul, hasSoul, resetSoul, runSoulSetup } from './soul/index.js';
31
43
  import { clearMemories, exportMemories, getRecentMemories, searchMemories } from './memory/index.js';
32
44
  import { getAgentStatus, planAgentGoal, runAgentTask } from './agent/index.js';
45
+ import { daemonStart, daemonStop, daemonStatus, daemonRestart } from './daemon/index.js';
46
+ import { telegramSetup, telegramStartForeground, telegramStopCommand, telegramStatusCommand, telegramSendCommand } from './services/telegram.js';
33
47
  import { createRequire } from 'module';
34
48
  import { resolve } from 'path';
35
49
  import { getConfiguredModel, getProviderDefaultModel } from './llm/models.js';
@@ -41,7 +55,7 @@ export function cli(argv) {
41
55
 
42
56
  program
43
57
  .name('darksol')
44
- .description(theme.gold('DARKSOL Terminal') + theme.dim(' Ghost in the machine with teeth 🌑'))
58
+ .description(theme.gold('DARKSOL Terminal') + theme.dim(' - Ghost in the machine with teeth 🌑'))
45
59
  .version(PKG_VERSION)
46
60
  ;
47
61
 
@@ -50,7 +64,7 @@ export function cli(argv) {
50
64
  // ═══════════════════════════════════════
51
65
  const wallet = program
52
66
  .command('wallet')
53
- .description('Wallet management create, import, list, balance');
67
+ .description('Wallet management - create, import, list, balance');
54
68
 
55
69
  wallet
56
70
  .command('create [name]')
@@ -115,7 +129,7 @@ export function cli(argv) {
115
129
  // ═══════════════════════════════════════
116
130
  const trade = program
117
131
  .command('trade')
118
- .description('Trading swap, snipe, DCA');
132
+ .description('Trading - swap, snipe, DCA');
119
133
 
120
134
  trade
121
135
  .command('swap')
@@ -163,14 +177,14 @@ export function cli(argv) {
163
177
  // If LI.FI failed (not cancelled), fall back to direct
164
178
  if (result?.error !== 'cancelled') {
165
179
  const { warn: showWarn, info: showInfo } = await import('./ui/components.js');
166
- showWarn('LI.FI route failed falling back to direct Uniswap V3...');
180
+ showWarn('LI.FI route failed - falling back to direct Uniswap V3...');
167
181
  console.log('');
168
182
  } else {
169
183
  return; // User cancelled, don't fallback
170
184
  }
171
185
  } catch {
172
186
  const { warn: showWarn } = await import('./ui/components.js');
173
- showWarn('LI.FI unavailable falling back to direct Uniswap V3...');
187
+ showWarn('LI.FI unavailable - falling back to direct Uniswap V3...');
174
188
  console.log('');
175
189
  }
176
190
  }
@@ -181,7 +195,7 @@ export function cli(argv) {
181
195
 
182
196
  trade
183
197
  .command('snipe <token>')
184
- .description('Snipe a token fast buy with ETH')
198
+ .description('Snipe a token - fast buy with ETH')
185
199
  .requiredOption('-a, --amount <eth>', 'ETH amount to spend')
186
200
  .option('-s, --slippage <percent>', 'Max slippage %', '1')
187
201
  .option('-g, --gas <multiplier>', 'Gas priority multiplier', '1.5')
@@ -215,7 +229,7 @@ export function cli(argv) {
215
229
  optimism: ['ETH/USDC', 'ETH/OP'],
216
230
  polygon: ['POL/USDC', 'POL/WETH', 'USDC/USDT'],
217
231
  };
218
- showSection(`COMMON PAIRS ${chain.toUpperCase()}`);
232
+ showSection(`COMMON PAIRS - ${chain.toUpperCase()}`);
219
233
  const pairs = byChain[chain] || byChain.base;
220
234
  pairs.forEach((p) => console.log(` ${theme.gold(p)}`));
221
235
  console.log('');
@@ -228,7 +242,7 @@ export function cli(argv) {
228
242
  // ═══════════════════════════════════════
229
243
  const bridge = program
230
244
  .command('bridge')
231
- .description('Cross-chain bridge move tokens between chains via LI.FI');
245
+ .description('Cross-chain bridge - move tokens between chains via LI.FI');
232
246
 
233
247
  bridge
234
248
  .command('send')
@@ -320,7 +334,7 @@ export function cli(argv) {
320
334
  // ═══════════════════════════════════════
321
335
  const market = program
322
336
  .command('market')
323
- .description('Market intel prices, movers, analysis');
337
+ .description('Market intel - prices, movers, analysis');
324
338
 
325
339
  market
326
340
  .command('top')
@@ -331,7 +345,7 @@ export function cli(argv) {
331
345
 
332
346
  market
333
347
  .command('token <query>')
334
- .description('Token detail price, volume, liquidity')
348
+ .description('Token detail - price, volume, liquidity')
335
349
  .action((query) => tokenDetail(query));
336
350
 
337
351
  market
@@ -376,7 +390,7 @@ export function cli(argv) {
376
390
  // ═══════════════════════════════════════
377
391
  const casino = program
378
392
  .command('casino')
379
- .description('The Clawsino on-chain betting');
393
+ .description('The Clawsino - on-chain betting');
380
394
 
381
395
  casino
382
396
  .command('status')
@@ -416,12 +430,29 @@ export function cli(argv) {
416
430
  .description('Verify bet on-chain')
417
431
  .action((id) => casinoVerify(id));
418
432
 
433
+ const poker = program
434
+ .command('poker [subcommand]')
435
+ .description('GTO Poker Arena — heads-up holdem against the house');
436
+
437
+ poker
438
+ .option('--free', 'Free play mode (default)')
439
+ .option('--real', 'Real mode ($1 buy-in, $2 payout on win)')
440
+ .action(async (subcommand, opts) => {
441
+ if (subcommand === 'status') {
442
+ return showPokerCliStatus();
443
+ }
444
+ if (subcommand === 'history') {
445
+ return showPokerCliHistory();
446
+ }
447
+ return playPokerCli(opts);
448
+ });
449
+
419
450
  // ═══════════════════════════════════════
420
451
  // CARDS COMMANDS
421
452
  // ═══════════════════════════════════════
422
453
  const cards = program
423
454
  .command('cards')
424
- .description('Prepaid cards crypto to Visa/MC');
455
+ .description('Prepaid cards - crypto to Visa/MC');
425
456
 
426
457
  cards
427
458
  .command('catalog')
@@ -498,7 +529,7 @@ export function cli(argv) {
498
529
  // ═══════════════════════════════════════
499
530
  const mail = program
500
531
  .command('mail')
501
- .description('📧 AgentMail email for your agent');
532
+ .description('📧 AgentMail - email for your agent');
502
533
 
503
534
  mail
504
535
  .command('setup')
@@ -590,6 +621,64 @@ export function cli(argv) {
590
621
  .option('--no-open', 'Don\'t auto-open browser')
591
622
  .action((opts) => startWebShell(opts));
592
623
 
624
+ const browser = program
625
+ .command('browser')
626
+ .description('Playwright-powered browser automation');
627
+
628
+ browser
629
+ .command('launch')
630
+ .description('Launch a browser instance and keep it running')
631
+ .option('--headed', 'Launch with a visible browser window')
632
+ .option('--type <browser>', 'Browser type', 'chromium')
633
+ .option('--profile <name>', 'Browser profile name', 'default')
634
+ .action((opts) => launchBrowserCommand(opts));
635
+
636
+ browser
637
+ .command('navigate <url>')
638
+ .description('Navigate the active page to a URL')
639
+ .action((url) => navigateBrowserCommand(url));
640
+
641
+ browser
642
+ .command('screenshot [filename]')
643
+ .description('Capture a screenshot of the active page')
644
+ .action((filename) => browserScreenshotCommand(filename));
645
+
646
+ browser
647
+ .command('click <selector>')
648
+ .description('Click an element on the active page')
649
+ .action((selector) => browserClickCommand(selector));
650
+
651
+ browser
652
+ .command('type <selector> <text>')
653
+ .description('Type text into an element on the active page')
654
+ .action((selector, text) => browserTypeCommand(selector, text));
655
+
656
+ browser
657
+ .command('eval <js>')
658
+ .description('Evaluate JavaScript in the active page')
659
+ .action((js) => browserEvalCommand(js));
660
+
661
+ browser
662
+ .command('close')
663
+ .description('Close the running browser service')
664
+ .action(() => browserCloseCommand());
665
+
666
+ browser
667
+ .command('status')
668
+ .description('Show current browser state')
669
+ .action(() => showBrowserStatus());
670
+
671
+ browser
672
+ .command('install')
673
+ .description('Install a Playwright browser binary after user confirmation')
674
+ .action(async () => {
675
+ try {
676
+ await installPlaywrightBrowsers();
677
+ } catch (err) {
678
+ error(err.message);
679
+ }
680
+ });
681
+
593
682
  // ═══════════════════════════════════════
594
683
  // PORTFOLIO SHORTCUT
595
684
  // ═══════════════════════════════════════
@@ -752,7 +841,7 @@ export function cli(argv) {
752
841
  // ═══════════════════════════════════════
753
842
  program
754
843
  .command('setup')
755
- .description('First-run setup wizard configure AI provider, chain, wallet')
844
+ .description('First-run setup wizard - configure AI provider, chain, wallet')
756
845
  .option('-f, --force', 'Re-run even if already configured')
757
846
  .action((opts) => runSetupWizard({ force: opts.force }));
758
847
 
@@ -860,7 +949,7 @@ export function cli(argv) {
860
949
  // ═══════════════════════════════════════
861
950
  const keys = program
862
951
  .command('keys')
863
- .description('API key vault store keys for LLMs, data providers, RPCs');
952
+ .description('API key vault - store keys for LLMs, data providers, RPCs');
864
953
 
865
954
  keys
866
955
  .command('list')
@@ -883,7 +972,7 @@ export function cli(argv) {
883
972
  // ═══════════════════════════════════════
884
973
  const agent = program
885
974
  .command('agent')
886
- .description('Secure agent signer PK-isolated wallet for AI agents');
975
+ .description('Secure agent signer - PK-isolated wallet for AI agents');
887
976
 
888
977
  agent
889
978
  .command('task <goal...>')
@@ -991,7 +1080,7 @@ export function cli(argv) {
991
1080
  // ═══════════════════════════════════════
992
1081
  const skills = program
993
1082
  .command('skills')
994
- .description('DARKSOL skills directory install agent skills');
1083
+ .description('DARKSOL skills directory - install agent skills');
995
1084
 
996
1085
  skills
997
1086
  .command('list')
@@ -1013,6 +1102,68 @@ export function cli(argv) {
1013
1102
  .description('Uninstall a skill')
1014
1103
  .action((name) => uninstallSkill(name));
1015
1104
 
1105
+ // ═══════════════════════════════════════
1106
+ // DAEMON COMMANDS
1107
+ // ═══════════════════════════════════════
1108
+ const daemon = program
1109
+ .command('daemon')
1110
+ .description('Background daemon - manage persistent services');
1111
+
1112
+ daemon
1113
+ .command('start')
1114
+ .description('Start the background daemon')
1115
+ .option('-p, --port <port>', 'Health server port', '18792')
1116
+ .action((opts) => daemonStart(opts));
1117
+
1118
+ daemon
1119
+ .command('stop')
1120
+ .description('Stop the background daemon')
1121
+ .action(() => daemonStop());
1122
+
1123
+ daemon
1124
+ .command('status')
1125
+ .description('Show daemon status and health')
1126
+ .option('-p, --port <port>', 'Health server port', '18792')
1127
+ .action((opts) => daemonStatus(opts));
1128
+
1129
+ daemon
1130
+ .command('restart')
1131
+ .description('Restart the daemon')
1132
+ .option('-p, --port <port>', 'Health server port', '18792')
1133
+ .action((opts) => daemonRestart(opts));
1134
+
1135
+ // ═══════════════════════════════════════
1136
+ // TELEGRAM COMMANDS
1137
+ // ═══════════════════════════════════════
1138
+ const telegram = program
1139
+ .command('telegram')
1140
+ .description('Telegram bot - AI chat via Telegram');
1141
+
1142
+ telegram
1143
+ .command('setup')
1144
+ .description('Interactive Telegram bot setup with BotFather')
1145
+ .action(() => telegramSetup());
1146
+
1147
+ telegram
1148
+ .command('start')
1149
+ .description('Start the Telegram bot (foreground)')
1150
+ .action(() => telegramStartForeground());
1151
+
1152
+ telegram
1153
+ .command('stop')
1154
+ .description('Stop the Telegram bot')
1155
+ .action(() => telegramStopCommand());
1156
+
1157
+ telegram
1158
+ .command('status')
1159
+ .description('Show bot info and connection state')
1160
+ .action(() => telegramStatusCommand());
1161
+
1162
+ telegram
1163
+ .command('send <chatId> <message...>')
1164
+ .description('Send a direct message to a chat')
1165
+ .action((chatId, message) => telegramSendCommand(chatId, message));
1166
+
1016
1167
  // ═══════════════════════════════════════
1017
1168
  // TIPS & REFERENCE COMMANDS
1018
1169
  // ═══════════════════════════════════════
@@ -1056,7 +1207,7 @@ export function cli(argv) {
1056
1207
  .action(async (address, opts) => {
1057
1208
  showMiniBanner();
1058
1209
  if (address.length === 42 && address.startsWith('0x')) {
1059
- // Could be token or wallet try token first
1210
+ // Could be token or wallet - try token first
1060
1211
  try {
1061
1212
  await showTokenInfo(address, opts.chain);
1062
1213
  } catch {
@@ -1073,7 +1224,7 @@ export function cli(argv) {
1073
1224
  // ═══════════════════════════════════════
1074
1225
  const script = program
1075
1226
  .command('script')
1076
- .description('Execution scripts automated trading strategies');
1227
+ .description('Execution scripts - automated trading strategies');
1077
1228
 
1078
1229
  script
1079
1230
  .command('create')
@@ -1200,7 +1351,7 @@ export function cli(argv) {
1200
1351
  });
1201
1352
 
1202
1353
  // ═══════════════════════════════════════
1203
- // DASHBOARD (default) commands + optional AI
1354
+ // DASHBOARD (default) - commands + optional AI
1204
1355
  // ═══════════════════════════════════════
1205
1356
  program
1206
1357
  .command('dashboard', { isDefault: true })
@@ -1228,7 +1379,7 @@ export function cli(argv) {
1228
1379
 
1229
1380
  // ── AI nudge or chat prompt ──
1230
1381
  if (hasLLM) {
1231
- console.log(theme.gold(' 💬 AI is ready run ') + theme.label('darksol ai chat') + theme.gold(' or just ') + theme.label('darksol chat'));
1382
+ console.log(theme.gold(' 💬 AI is ready - run ') + theme.label('darksol ai chat') + theme.gold(' or just ') + theme.label('darksol chat'));
1232
1383
  console.log(theme.dim(' "swap 0.1 ETH for USDC" • "what\'s AERO at?" • any question'));
1233
1384
  console.log('');
1234
1385
  } else {
@@ -1252,7 +1403,7 @@ export function cli(argv) {
1252
1403
  const { info, error: showError } = await import('./ui/components.js');
1253
1404
 
1254
1405
  console.log('');
1255
- info(`"${input}" isn't a command asking AI...`);
1406
+ info(`"${input}" isn't a command - asking AI...`);
1256
1407
  console.log('');
1257
1408
 
1258
1409
  try {
@@ -1406,6 +1557,154 @@ async function chatResponse(llm, input) {
1406
1557
  }
1407
1558
  }
1408
1559
 
1560
+ function pokerModeFromOpts(opts = {}) {
1561
+ return opts.real ? 'real' : 'free';
1562
+ }
1563
+
1564
+ function renderPokerCards(cards, hidden = false) {
1565
+ const suitMap = { s: '♠', h: '♥', d: '♦', c: '♣' };
1566
+ const colorize = (card, text) => {
1567
+ const suit = card[1];
1568
+ return suit === 'h' || suit === 'd' ? theme.error(text) : theme.bright(text);
1569
+ };
1570
+
1571
+ const source = hidden ? ['??', '??'] : cards;
1572
+ const rows = ['', '', '', '', ''];
1573
+
1574
+ for (const card of source) {
1575
+ if (card === '??') {
1576
+ rows[0] += `${theme.dim('┌─────┐')} `;
1577
+ rows[1] += `${theme.dim('│░░░░░│')} `;
1578
+ rows[2] += `${theme.dim('│░░▓░░│')} `;
1579
+ rows[3] += `${theme.dim('│░░░░░│')} `;
1580
+ rows[4] += `${theme.dim('└─────┘')} `;
1581
+ continue;
1582
+ }
1583
+
1584
+ const rank = card[0] === 'T' ? '10' : card[0];
1585
+ const suit = suitMap[card[1]];
1586
+ rows[0] += `${theme.dim('┌─────┐')} `;
1587
+ rows[1] += `${theme.dim('│')}${colorize(card, rank.padEnd(2, ' '))}${theme.dim(' │')} `;
1588
+ rows[2] += `${theme.dim('│ ')}${colorize(card, suit)}${theme.dim(' │')} `;
1589
+ rows[3] += `${theme.dim('│ ')}${colorize(card, rank.padStart(2, ' '))}${theme.dim('│')} `;
1590
+ rows[4] += `${theme.dim('└─────┘')} `;
1591
+ }
1592
+
1593
+ rows.forEach((row) => console.log(` ${row}`));
1594
+ }
1595
+
1596
+ function showPokerState(status) {
1597
+ showSection(`POKER ARENA - ${status.mode === 'real' ? 'REAL MODE' : 'FREE MODE'}`);
1598
+ kvDisplay([
1599
+ ['Street', status.street.toUpperCase()],
1600
+ ['Dealer', status.dealer],
1601
+ ['Pot', `${status.pot} chips`],
1602
+ ['Current Bet', `${status.currentBet} chips`],
1603
+ ['Your Stack', `${status.player.stack} chips`],
1604
+ ['House Stack', `${status.house.stack} chips`],
1605
+ ['To Act', status.currentActor || '-'],
1606
+ ]);
1607
+
1608
+ console.log('');
1609
+ console.log(` ${theme.label('House')}`);
1610
+ renderPokerCards(status.house.hole, status.house.holeHidden);
1611
+ console.log('');
1612
+ console.log(` ${theme.label('Board')}`);
1613
+ if (status.community.length) renderPokerCards(status.community);
1614
+ else console.log(` ${theme.dim(' No community cards yet')}`);
1615
+ console.log('');
1616
+ console.log(` ${theme.label('You')}`);
1617
+ renderPokerCards(status.player.hole);
1618
+ console.log('');
1619
+
1620
+ if (status.street === 'finished') {
1621
+ const result = status.winner === 'player'
1622
+ ? theme.success('WIN')
1623
+ : status.winner === 'house'
1624
+ ? theme.error('LOSS')
1625
+ : theme.warning('PUSH');
1626
+ kvDisplay([
1627
+ ['Result', result],
1628
+ ['Summary', status.summary || '-'],
1629
+ ['Your Hand', status.player.hand?.name || '-'],
1630
+ ['House Hand', status.house.hand?.name || '-'],
1631
+ ['Payout', status.mode === 'real' && status.winner === 'player' ? `$${status.payoutUsdc} USDC` : status.mode === 'real' ? '$0 USDC' : 'free mode'],
1632
+ ]);
1633
+ console.log('');
1634
+ } else if (status.availableActions?.length) {
1635
+ info(`Actions: ${status.availableActions.join(', ')}`);
1636
+ }
1637
+ }
1638
+
1639
+ async function playPokerCli(opts = {}) {
1640
+ const inquirer = (await import('inquirer')).default;
1641
+ const mode = pokerModeFromOpts(opts);
1642
+ const spin = spinner(`Opening ${mode === 'real' ? 'real-mode' : 'free-mode'} poker table...`).start();
1643
+
1644
+ try {
1645
+ let status = await pokerNewGame({ mode });
1646
+ spin.succeed('Table ready');
1647
+
1648
+ while (status && status.street !== 'finished') {
1649
+ console.log('');
1650
+ showPokerState(status);
1651
+
1652
+ if (status.currentActor !== 'player') {
1653
+ status = pokerStatus(status.id);
1654
+ continue;
1655
+ }
1656
+
1657
+ const { action } = await inquirer.prompt([{
1658
+ type: 'list',
1659
+ name: 'action',
1660
+ message: theme.gold('Pick your action:'),
1661
+ choices: status.availableActions.map((item) => ({
1662
+ name: item === 'all-in' ? 'all-in' : item,
1663
+ value: item,
1664
+ })),
1665
+ }]);
1666
+
1667
+ status = await pokerAction(status.id, action);
1668
+ }
1669
+
1670
+ console.log('');
1671
+ showPokerState(status);
1672
+ } catch (err) {
1673
+ spin.fail('Poker table unavailable');
1674
+ error(err.message);
1675
+ }
1676
+ }
1677
+
1678
+ function showPokerCliStatus() {
1679
+ showMiniBanner();
1680
+ const status = pokerStatus();
1681
+ if (!status) {
1682
+ info('No active poker game');
1683
+ return;
1684
+ }
1685
+ showPokerState(status);
1686
+ }
1687
+
1688
+ function showPokerCliHistory() {
1689
+ showMiniBanner();
1690
+ const items = pokerHistory();
1691
+ if (!items.length) {
1692
+ info('No poker hands played yet');
1693
+ return;
1694
+ }
1695
+
1696
+ showSection('POKER HISTORY');
1697
+ items.slice(0, 10).forEach((item) => {
1698
+ const verdict = item.winner === 'player'
1699
+ ? theme.success('W')
1700
+ : item.winner === 'house'
1701
+ ? theme.error('L')
1702
+ : theme.warning('P');
1703
+ console.log(` ${verdict} ${theme.gold(item.mode.toUpperCase().padEnd(5))} ${theme.bright(item.summary)}`);
1704
+ });
1705
+ console.log('');
1706
+ }
1707
+
1409
1708
  function showCommandList() {
1410
1709
  console.log('');
1411
1710
  showSection('COMMANDS');
@@ -1429,12 +1728,16 @@ function showCommandList() {
1429
1728
  ['script', 'Execution scripts & strategies'],
1430
1729
  ['market', 'Market intel & token data'],
1431
1730
  ['oracle', 'On-chain random oracle'],
1432
- ['casino', 'The Clawsino betting'],
1731
+ ['casino', 'The Clawsino - betting'],
1732
+ ['poker', 'GTO Poker Arena — heads-up holdem'],
1433
1733
  ['cards', 'Prepaid Visa/MC cards'],
1434
1734
  ['builders', 'ERC-8021 builder index'],
1435
- ['mail', 'AgentMail email for your agent'],
1735
+ ['mail', 'AgentMail - email for your agent'],
1436
1736
  ['facilitator', 'x402 payment facilitator'],
1437
1737
  ['skills', 'Agent skill directory'],
1738
+ ['browser', 'Playwright browser automation'],
1739
+ ['daemon', 'Background service daemon'],
1740
+ ['telegram', 'Telegram bot - AI chat'],
1438
1741
  ['serve', 'Launch web terminal in browser'],
1439
1742
  ['setup', 'Re-run setup wizard'],
1440
1743
  ['config', 'Terminal configuration'],
@@ -178,6 +178,16 @@ export const SERVICES = {
178
178
  docsUrl: 'https://console.agentmail.to',
179
179
  validate: (key) => key.startsWith('am_'),
180
180
  },
181
+
182
+ // Messaging
183
+ telegram: {
184
+ name: 'Telegram Bot',
185
+ category: 'messaging',
186
+ description: 'Telegram bot token — AI chat via Telegram',
187
+ envVar: 'TELEGRAM_BOT_TOKEN',
188
+ docsUrl: 'https://core.telegram.org/bots#botfather',
189
+ validate: (key) => /^\d+:.+$/.test(key),
190
+ },
181
191
  paraswap: {
182
192
  name: 'ParaSwap',
183
193
  category: 'trading',
@@ -319,8 +329,8 @@ export function listKeys() {
319
329
 
320
330
  showSection('API KEY VAULT');
321
331
 
322
- const categories = ['llm', 'data', 'rpc', 'trading', 'email'];
323
- const catNames = { llm: '🧠 LLM PROVIDERS', data: '📊 DATA PROVIDERS', rpc: '🌐 RPC PROVIDERS', trading: '📈 TRADING', email: '📧 EMAIL' };
332
+ const categories = ['llm', 'data', 'rpc', 'trading', 'email', 'messaging'];
333
+ const catNames = { llm: '🧠 LLM PROVIDERS', data: '📊 DATA PROVIDERS', rpc: '🌐 RPC PROVIDERS', trading: '📈 TRADING', email: '📧 EMAIL', messaging: '💬 MESSAGING' };
324
334
 
325
335
  for (const cat of categories) {
326
336
  console.log('');