@darksol/terminal 0.3.0 → 0.3.1
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/package.json +1 -1
- package/src/cli.js +197 -38
- package/src/setup/wizard.js +3 -14
- package/src/ui/banner.js +3 -2
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -591,62 +591,221 @@ export function cli(argv) {
|
|
|
591
591
|
});
|
|
592
592
|
|
|
593
593
|
// ═══════════════════════════════════════
|
|
594
|
-
// DASHBOARD (default)
|
|
594
|
+
// DASHBOARD (default) — CHAT-FIRST
|
|
595
595
|
// ═══════════════════════════════════════
|
|
596
596
|
program
|
|
597
597
|
.command('dashboard', { isDefault: true })
|
|
598
|
-
.description('Show DARKSOL Terminal
|
|
598
|
+
.description('Show DARKSOL Terminal — chat-first interface')
|
|
599
599
|
.action(async () => {
|
|
600
600
|
showBanner();
|
|
601
601
|
|
|
602
|
-
// First-run detection —
|
|
602
|
+
// First-run detection — force setup
|
|
603
603
|
const ranSetup = await checkFirstRun();
|
|
604
604
|
if (ranSetup) return;
|
|
605
605
|
|
|
606
606
|
const cfg = getAllConfig();
|
|
607
607
|
const wallet = cfg.activeWallet;
|
|
608
|
+
const { hasKey } = await import('./config/keys.js');
|
|
609
|
+
const hasLLM = ['openai', 'anthropic', 'openrouter', 'ollama'].some(s => hasKey(s));
|
|
610
|
+
|
|
611
|
+
// ── Status bar (compact) ──
|
|
612
|
+
const statusParts = [
|
|
613
|
+
wallet ? theme.success(`● ${wallet}`) : theme.dim('○ no wallet'),
|
|
614
|
+
theme.dim(`${cfg.chain}`),
|
|
615
|
+
theme.dim(`${cfg.slippage}% slip`),
|
|
616
|
+
hasLLM ? theme.success('● AI ready') : theme.accent('○ no AI'),
|
|
617
|
+
];
|
|
618
|
+
console.log(` ${statusParts.join(theme.dim(' │ '))}`);
|
|
619
|
+
console.log('');
|
|
620
|
+
|
|
621
|
+
// ── CHAT INTERFACE (primary) ──
|
|
622
|
+
if (hasLLM) {
|
|
623
|
+
// AI is connected — drop straight into chat
|
|
624
|
+
console.log(theme.gold(' ╔══════════════════════════════════════════════════════════╗'));
|
|
625
|
+
console.log(theme.gold(' ║') + theme.label(' DARKSOL AI — ready. Ask anything. ') + theme.gold('║'));
|
|
626
|
+
console.log(theme.gold(' ║') + theme.dim(' "swap 0.1 ETH for USDC" • "what\'s AERO at?" • "help" ') + theme.gold('║'));
|
|
627
|
+
console.log(theme.gold(' ║') + theme.dim(' Type "commands" to see all tools. Type "exit" to quit. ') + theme.gold('║'));
|
|
628
|
+
console.log(theme.gold(' ╚══════════════════════════════════════════════════════════╝'));
|
|
629
|
+
console.log('');
|
|
630
|
+
|
|
631
|
+
// Start interactive chat loop
|
|
632
|
+
await startChatLoop(cfg);
|
|
633
|
+
} else {
|
|
634
|
+
// No AI — show connect prompt
|
|
635
|
+
console.log(theme.gold(' ╔══════════════════════════════════════════════════════════╗'));
|
|
636
|
+
console.log(theme.gold(' ║') + theme.accent(' ⚠ No AI provider connected ') + theme.gold('║'));
|
|
637
|
+
console.log(theme.gold(' ║') + theme.dim(' The DARKSOL AI needs an LLM to work. ') + theme.gold('║'));
|
|
638
|
+
console.log(theme.gold(' ║') + theme.dim(' ') + theme.gold('║'));
|
|
639
|
+
console.log(theme.gold(' ║') + theme.dim(' Run: ') + theme.label('darksol setup') + theme.dim(' to connect OpenAI/Anthropic ') + theme.gold('║'));
|
|
640
|
+
console.log(theme.gold(' ║') + theme.dim(' Run: ') + theme.label('darksol keys add openai') + theme.dim(' to add an API key ') + theme.gold('║'));
|
|
641
|
+
console.log(theme.gold(' ║') + theme.dim(' ') + theme.gold('║'));
|
|
642
|
+
console.log(theme.gold(' ║') + theme.dim(' Or use Ollama for free local AI — no key needed. ') + theme.gold('║'));
|
|
643
|
+
console.log(theme.gold(' ╚══════════════════════════════════════════════════════════╝'));
|
|
644
|
+
console.log('');
|
|
645
|
+
showCommandList();
|
|
646
|
+
}
|
|
647
|
+
});
|
|
608
648
|
|
|
609
|
-
|
|
649
|
+
program.parse(argv);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// ═══════════════════════════════════════
|
|
653
|
+
// CHAT-FIRST LOOP (default experience)
|
|
654
|
+
// ═══════════════════════════════════════
|
|
655
|
+
|
|
656
|
+
async function startChatLoop(cfg) {
|
|
657
|
+
const { createLLM } = await import('./llm/engine.js');
|
|
658
|
+
const { quickPrice } = await import('./utils/helpers.js');
|
|
659
|
+
const { executeIntent, parseIntent, INTENT_SYSTEM_PROMPT } = await import('./llm/intent.js');
|
|
660
|
+
|
|
661
|
+
let llm;
|
|
662
|
+
try {
|
|
663
|
+
llm = await createLLM({});
|
|
664
|
+
const chain = cfg.chain || 'base';
|
|
665
|
+
const wallet = cfg.activeWallet || '(not set)';
|
|
666
|
+
const slippage = cfg.slippage || 0.5;
|
|
667
|
+
|
|
668
|
+
const systemPrompt = INTENT_SYSTEM_PROMPT
|
|
669
|
+
.replace('{{chain}}', chain)
|
|
670
|
+
.replace('{{wallet}}', wallet)
|
|
671
|
+
.replace('{{slippage}}', slippage);
|
|
672
|
+
|
|
673
|
+
llm.setSystemPrompt(systemPrompt);
|
|
674
|
+
} catch (err) {
|
|
675
|
+
error(`AI init failed: ${err.message}`);
|
|
676
|
+
info('Run: darksol setup');
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
const inquirerMod = await import('inquirer');
|
|
681
|
+
const inquirerDefault = inquirerMod.default;
|
|
682
|
+
|
|
683
|
+
while (true) {
|
|
684
|
+
const { input } = await inquirerDefault.prompt([{
|
|
685
|
+
type: 'input',
|
|
686
|
+
name: 'input',
|
|
687
|
+
message: theme.gold('🌑'),
|
|
688
|
+
validate: (v) => v.length > 0 || ' ',
|
|
689
|
+
}]);
|
|
690
|
+
|
|
691
|
+
const trimmed = input.trim().toLowerCase();
|
|
692
|
+
|
|
693
|
+
// Meta-commands within chat
|
|
694
|
+
if (['exit', 'quit', 'q'].includes(trimmed)) {
|
|
695
|
+
const usage = llm.getUsage();
|
|
696
|
+
info(`Session: ${usage.calls} calls, ${usage.totalTokens} tokens`);
|
|
697
|
+
break;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (['commands', 'help', 'cmds', '?'].includes(trimmed)) {
|
|
701
|
+
showCommandList();
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
if (trimmed === 'status') {
|
|
610
706
|
kvDisplay([
|
|
611
|
-
['Wallet',
|
|
707
|
+
['Wallet', cfg.activeWallet || theme.dim('(none)')],
|
|
612
708
|
['Chain', cfg.chain],
|
|
709
|
+
['Provider', `${llm.provider}/${llm.model}`],
|
|
613
710
|
['Slippage', `${cfg.slippage}%`],
|
|
614
711
|
]);
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
615
714
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
['setup', 'First-run setup wizard'],
|
|
639
|
-
];
|
|
715
|
+
// Check if it looks like a trade intent
|
|
716
|
+
const tradeWords = ['buy', 'sell', 'swap', 'snipe', 'transfer', 'send', 'trade'];
|
|
717
|
+
const isTradeIntent = tradeWords.some(w => trimmed.startsWith(w));
|
|
718
|
+
|
|
719
|
+
if (isTradeIntent) {
|
|
720
|
+
// Parse as trade intent with confirmation
|
|
721
|
+
const intent = await parseIntent(input, {});
|
|
722
|
+
if (intent.action !== 'error' && intent.action !== 'unknown') {
|
|
723
|
+
showSection('PARSED INTENT');
|
|
724
|
+
kvDisplay(Object.entries(intent)
|
|
725
|
+
.filter(([k]) => !['raw', 'model', 'reasoning'].includes(k))
|
|
726
|
+
.map(([k, v]) => [k, Array.isArray(v) ? v.join(', ') : String(v)])
|
|
727
|
+
);
|
|
728
|
+
if (intent.warnings?.length) intent.warnings.forEach(w => warn(w));
|
|
729
|
+
if (intent.command) info(`Command: ${theme.gold(intent.command)}`);
|
|
730
|
+
console.log('');
|
|
731
|
+
} else {
|
|
732
|
+
// Fall through to regular chat
|
|
733
|
+
await chatResponse(llm, input);
|
|
734
|
+
}
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
640
737
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
738
|
+
// Regular chat
|
|
739
|
+
await chatResponse(llm, input);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
644
742
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
743
|
+
async function chatResponse(llm, input) {
|
|
744
|
+
const { quickPrice } = await import('./utils/helpers.js');
|
|
745
|
+
const { spinner: spin } = await import('./ui/components.js');
|
|
746
|
+
const s = spin('Thinking...').start();
|
|
747
|
+
|
|
748
|
+
try {
|
|
749
|
+
// Enrich with live price data
|
|
750
|
+
let enriched = input;
|
|
751
|
+
const tokenPattern = /\b([A-Z]{2,10})\b/g;
|
|
752
|
+
const tokens = [...new Set(input.toUpperCase().match(tokenPattern) || [])];
|
|
753
|
+
const skipTokens = ['ETH', 'THE', 'FOR', 'AND', 'BUY', 'SELL', 'DCA', 'SWAP', 'WHAT', 'PRICE', 'HOW', 'MUCH', 'NOT', 'CAN', 'YOU', 'HELP'];
|
|
754
|
+
|
|
755
|
+
const priceData = [];
|
|
756
|
+
for (const t of tokens.filter(t => !skipTokens.includes(t)).slice(0, 3)) {
|
|
757
|
+
const p = await quickPrice(t);
|
|
758
|
+
if (p) priceData.push(`${p.symbol}: $${p.price} (liq: $${p.liquidity})`);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
if (priceData.length > 0) {
|
|
762
|
+
enriched += `\n\n[Live data: ${priceData.join(', ')}]`;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const result = await llm.chat(enriched);
|
|
766
|
+
s.succeed('');
|
|
767
|
+
|
|
768
|
+
// Display response
|
|
769
|
+
console.log('');
|
|
770
|
+
const lines = result.content.split('\n');
|
|
771
|
+
for (const line of lines) {
|
|
772
|
+
console.log(theme.dim(' ') + line);
|
|
773
|
+
}
|
|
774
|
+
console.log('');
|
|
775
|
+
} catch (err) {
|
|
776
|
+
s.fail('Error');
|
|
777
|
+
error(err.message);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
650
780
|
|
|
651
|
-
|
|
781
|
+
function showCommandList() {
|
|
782
|
+
console.log('');
|
|
783
|
+
showSection('COMMANDS');
|
|
784
|
+
const commands = [
|
|
785
|
+
['wallet', 'Create, import, manage wallets'],
|
|
786
|
+
['trade', 'Swap tokens, snipe, trading'],
|
|
787
|
+
['dca', 'Dollar-cost averaging orders'],
|
|
788
|
+
['ai chat', 'Standalone AI chat session'],
|
|
789
|
+
['ai execute', 'Parse + execute a trade via AI'],
|
|
790
|
+
['agent start', 'Start secure agent signer'],
|
|
791
|
+
['keys', 'API key vault'],
|
|
792
|
+
['script', 'Execution scripts & strategies'],
|
|
793
|
+
['market', 'Market intel & token data'],
|
|
794
|
+
['oracle', 'On-chain random oracle'],
|
|
795
|
+
['casino', 'The Clawsino — betting'],
|
|
796
|
+
['cards', 'Prepaid Visa/MC cards'],
|
|
797
|
+
['builders', 'ERC-8021 builder index'],
|
|
798
|
+
['facilitator', 'x402 payment facilitator'],
|
|
799
|
+
['skills', 'Agent skill directory'],
|
|
800
|
+
['setup', 'Re-run setup wizard'],
|
|
801
|
+
['config', 'Terminal configuration'],
|
|
802
|
+
];
|
|
803
|
+
|
|
804
|
+
commands.forEach(([cmd, desc]) => {
|
|
805
|
+
console.log(` ${theme.gold(cmd.padEnd(16))} ${theme.dim(desc)}`);
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
console.log('');
|
|
809
|
+
console.log(theme.dim(' Run any command: darksol <command> --help'));
|
|
810
|
+
console.log('');
|
|
652
811
|
}
|
package/src/setup/wizard.js
CHANGED
|
@@ -494,23 +494,12 @@ function showPostSetup() {
|
|
|
494
494
|
}
|
|
495
495
|
|
|
496
496
|
/**
|
|
497
|
-
* Quick check on startup — if first run,
|
|
497
|
+
* Quick check on startup — if first run, FORCE setup (no prompt)
|
|
498
498
|
*/
|
|
499
499
|
export async function checkFirstRun() {
|
|
500
500
|
if (isFirstRun()) {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
const { runSetup } = await inquirer.prompt([{
|
|
504
|
-
type: 'confirm',
|
|
505
|
-
name: 'runSetup',
|
|
506
|
-
message: theme.gold('Run setup wizard?'),
|
|
507
|
-
default: true,
|
|
508
|
-
}]);
|
|
509
|
-
if (runSetup) {
|
|
510
|
-
await runSetupWizard();
|
|
511
|
-
return true;
|
|
512
|
-
}
|
|
513
|
-
info('Skip for now. Run later: darksol setup');
|
|
501
|
+
await runSetupWizard();
|
|
502
|
+
return true;
|
|
514
503
|
}
|
|
515
504
|
return false;
|
|
516
505
|
}
|
package/src/ui/banner.js
CHANGED
|
@@ -26,7 +26,7 @@ export function showBanner(opts = {}) {
|
|
|
26
26
|
);
|
|
27
27
|
console.log(
|
|
28
28
|
theme.dim(' ║ ') +
|
|
29
|
-
theme.subtle(' v0.3.
|
|
29
|
+
theme.subtle(' v0.3.1') +
|
|
30
30
|
theme.dim(' ') +
|
|
31
31
|
theme.gold('🌑') +
|
|
32
32
|
theme.dim(' ║')
|
|
@@ -44,7 +44,7 @@ export function showBanner(opts = {}) {
|
|
|
44
44
|
|
|
45
45
|
export function showMiniBanner() {
|
|
46
46
|
console.log('');
|
|
47
|
-
console.log(theme.gold.bold(' 🌑 DARKSOL TERMINAL') + theme.dim(' v0.3.
|
|
47
|
+
console.log(theme.gold.bold(' 🌑 DARKSOL TERMINAL') + theme.dim(' v0.3.1'));
|
|
48
48
|
console.log(theme.dim(' ─────────────────────────────'));
|
|
49
49
|
console.log('');
|
|
50
50
|
}
|
|
@@ -63,3 +63,4 @@ export function showDivider() {
|
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
|
|
66
|
+
|