@darksol/terminal 0.5.5 → 0.5.6
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/llm/intent.js +62 -12
- package/src/services/cards.js +90 -29
- package/src/web/commands.js +4 -1
package/package.json
CHANGED
package/src/llm/intent.js
CHANGED
|
@@ -9,17 +9,36 @@ import { showSection } from '../ui/banner.js';
|
|
|
9
9
|
// INTENT SYSTEM PROMPT
|
|
10
10
|
// ──────────────────────────────────────────────────
|
|
11
11
|
|
|
12
|
-
const INTENT_SYSTEM_PROMPT = `You are DARKSOL Terminal's trading AI assistant. You help users execute trades, send/receive tokens, analyze markets, manage DCA strategies, and navigate the DARKSOL ecosystem.
|
|
12
|
+
const INTENT_SYSTEM_PROMPT = `You are DARKSOL Terminal's trading AI assistant. You help users execute trades, send/receive tokens, analyze markets, manage DCA strategies, order prepaid cards, and navigate the DARKSOL ecosystem.
|
|
13
|
+
|
|
14
|
+
You are embedded in a CLI/web terminal. Your responses become actions — when you output structured JSON, the terminal executes real on-chain transactions, card orders, and wallet operations. Be precise. Be careful. Real money is at stake.
|
|
13
15
|
|
|
14
16
|
CAPABILITIES:
|
|
15
|
-
- Parse natural language into structured trade/transfer commands
|
|
17
|
+
- Parse natural language into structured trade/transfer/card-order commands
|
|
18
|
+
- Execute swaps via Uniswap V3 (Base SwapRouter02, V1 on ETH/Arb/OP/Polygon)
|
|
19
|
+
- Send ETH and ERC-20 tokens to any address
|
|
20
|
+
- Snipe tokens via Uniswap V2 (Base, Ethereum)
|
|
21
|
+
- Order prepaid Visa/Mastercard cards with crypto (via Trocador)
|
|
16
22
|
- Analyze token prices, liquidity, and market conditions
|
|
17
23
|
- Suggest DCA strategies based on user goals
|
|
18
24
|
- Explain transaction results and gas costs
|
|
19
25
|
- Warn about risks (low liquidity, high slippage, unverified contracts)
|
|
20
26
|
|
|
21
27
|
SUPPORTED CHAINS: Base (default), Ethereum, Polygon, Arbitrum, Optimism
|
|
22
|
-
KNOWN TOKENS
|
|
28
|
+
KNOWN TOKENS PER CHAIN:
|
|
29
|
+
- Base: ETH, WETH, USDC, USDbC, DAI, AERO, VIRTUAL
|
|
30
|
+
- Ethereum: ETH, WETH, USDC, USDT, DAI
|
|
31
|
+
- Arbitrum: ETH, WETH, USDC, USDT, ARB
|
|
32
|
+
- Optimism: ETH, WETH, USDC, OP
|
|
33
|
+
- Polygon: MATIC/POL (native), WETH, WMATIC, USDC, USDT
|
|
34
|
+
|
|
35
|
+
WEB3 KNOWLEDGE:
|
|
36
|
+
- Uniswap V3 uses fee tiers: 500 (0.05%), 3000 (0.3%), 10000 (1%). Default: 3000.
|
|
37
|
+
- Slippage protection: Quoter V2 gets expected output, then applies tolerance (default 0.5%).
|
|
38
|
+
- Token approvals: ERC-20 tokens need approval before swapping (approve → swap is 2 TXs).
|
|
39
|
+
- Gas: Base is very cheap (~$0.01-0.05/TX), Ethereum is expensive ($2-20+/TX).
|
|
40
|
+
- Never send ETH/tokens to a contract address unless you know what you're doing.
|
|
41
|
+
- Always verify contract addresses — don't guess or hallucinate them.
|
|
23
42
|
|
|
24
43
|
USER CONTEXT:
|
|
25
44
|
- Active chain: {{chain}}
|
|
@@ -50,15 +69,25 @@ ACTIONS (use the most specific one):
|
|
|
50
69
|
|
|
51
70
|
CARDS ORDERING:
|
|
52
71
|
When the user wants to order a prepaid card, you MUST collect:
|
|
53
|
-
1. amount
|
|
54
|
-
2. email
|
|
55
|
-
3. provider
|
|
56
|
-
4. ticker
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
1. amount — ONLY these denominations: $10, $25, $50, $100, $250, $500, $1000
|
|
73
|
+
2. email — delivery address for the card activation link
|
|
74
|
+
3. provider — default "swype" (Global Mastercard). Also: "mpc" (US Mastercard), "reward" (US Visa)
|
|
75
|
+
4. ticker — payment crypto, default "usdc"
|
|
76
|
+
|
|
77
|
+
VERIFIED PAYMENT METHODS (ONLY these work — reject anything else):
|
|
78
|
+
- usdc on base (DEFAULT — cheapest, fastest)
|
|
79
|
+
- usdc on ERC20 (Ethereum — higher gas)
|
|
80
|
+
- usdt on trc20 (Tron — cheap)
|
|
81
|
+
- btc on Mainnet (Bitcoin)
|
|
82
|
+
- eth on ERC20 (Ethereum)
|
|
83
|
+
- sol on Mainnet (Solana)
|
|
84
|
+
- xmr on Mainnet (Monero)
|
|
85
|
+
|
|
86
|
+
⚠ DO NOT accept: eth/base, sol/sol, usdc/polygon, usdt/eth, or any combo not listed above.
|
|
87
|
+
If the user asks for an unsupported combo (like "pay with ETH on Base"), tell them it's not available and suggest alternatives.
|
|
88
|
+
|
|
89
|
+
If the user says "order me a $50 card" but doesn't provide an email, set "needsInfo": ["email"] and ask: "What email should I send the card activation link to?"
|
|
90
|
+
If they mention AgentMail or "my email", suggest using their configured agent email.
|
|
62
91
|
|
|
63
92
|
When parsing, respond with ONLY valid JSON:
|
|
64
93
|
{
|
|
@@ -87,6 +116,27 @@ CONVERSATIONAL RULES:
|
|
|
87
116
|
- Be conversational — "What email should I send the card to?" not "Error: email required"
|
|
88
117
|
- If they mention AgentMail or "my email", suggest using their configured agent email
|
|
89
118
|
- For cards without a specified provider, default to "swype" (global Mastercard)
|
|
119
|
+
- For swaps without a specified chain, use the user's active chain ({{chain}})
|
|
120
|
+
- Never hallucinate contract addresses — if you don't know it, say so
|
|
121
|
+
- When a user asks "how do I..." give them the exact darksol CLI command
|
|
122
|
+
|
|
123
|
+
AGENT/TOOL-USE BEHAVIOR:
|
|
124
|
+
When an AI agent (like OpenClaw) is using this terminal programmatically:
|
|
125
|
+
- Always return structured JSON for actionable intents
|
|
126
|
+
- Include the exact "command" field so the agent can run it
|
|
127
|
+
- Include "warnings" for anything risky (high value, unverified token, etc.)
|
|
128
|
+
- If confidence < 0.6, ask for clarification rather than guessing
|
|
129
|
+
- For card orders: validate amount is in [10,25,50,100,250,500,1000] and ticker is verified
|
|
130
|
+
- For swaps: validate both tokens are known symbols or valid 0x addresses
|
|
131
|
+
- For sends: validate "to" looks like a valid address (0x + 40 hex chars)
|
|
132
|
+
|
|
133
|
+
ERROR GUIDANCE:
|
|
134
|
+
When something fails, help the user fix it:
|
|
135
|
+
- "CALL_EXCEPTION" → likely an RPC issue, suggest switching RPCs
|
|
136
|
+
- "insufficient funds" → tell them their balance, suggest a lower amount
|
|
137
|
+
- "coin not found" → the crypto/network combo isn't supported, list what works
|
|
138
|
+
- "nonce" → pending transaction, wait and retry
|
|
139
|
+
- Don't just say "error" — explain what went wrong and what to do next
|
|
90
140
|
|
|
91
141
|
COMMAND MAPPING:
|
|
92
142
|
- swap → darksol trade swap -i <tokenIn> -o <tokenOut> -a <amount>
|
package/src/services/cards.js
CHANGED
|
@@ -6,40 +6,80 @@ import { showSection } from '../ui/banner.js';
|
|
|
6
6
|
|
|
7
7
|
const BASE = () => getServiceURL('cards') || 'https://acp.darksol.net';
|
|
8
8
|
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
'
|
|
15
|
-
|
|
16
|
-
'
|
|
17
|
-
'
|
|
18
|
-
'
|
|
19
|
-
'
|
|
9
|
+
// ══════════════════════════════════════════════════
|
|
10
|
+
// VERIFIED CRYPTO COMBOS (tested against Trocador API 2026-03-09)
|
|
11
|
+
// Only these combos are allowed — everything else is rejected before hitting the API
|
|
12
|
+
// ══════════════════════════════════════════════════
|
|
13
|
+
const VERIFIED_COMBOS = [
|
|
14
|
+
{ ticker: 'usdc', network: 'base', display: 'USDC on Base', default: true },
|
|
15
|
+
{ ticker: 'usdc', network: 'ERC20', display: 'USDC on Ethereum' },
|
|
16
|
+
{ ticker: 'usdt', network: 'trc20', display: 'USDT on Tron (TRC-20)' },
|
|
17
|
+
{ ticker: 'btc', network: 'Mainnet', display: 'Bitcoin (BTC)' },
|
|
18
|
+
{ ticker: 'eth', network: 'ERC20', display: 'Ethereum (ETH)' },
|
|
19
|
+
{ ticker: 'sol', network: 'Mainnet', display: 'Solana (SOL)' },
|
|
20
|
+
{ ticker: 'xmr', network: 'Mainnet', display: 'Monero (XMR)' },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
// Aliases: what users might type → what Trocador expects
|
|
24
|
+
const TICKER_ALIASES = {
|
|
25
|
+
'ethereum': 'eth', 'ether': 'eth',
|
|
26
|
+
'bitcoin': 'btc',
|
|
27
|
+
'solana': 'sol',
|
|
28
|
+
'monero': 'xmr',
|
|
29
|
+
'tether': 'usdt',
|
|
30
|
+
'usd coin': 'usdc', 'usd-c': 'usdc',
|
|
20
31
|
};
|
|
21
32
|
|
|
22
|
-
|
|
23
|
-
const NETWORK_MAP = {
|
|
33
|
+
const NETWORK_ALIASES = {
|
|
24
34
|
'base': 'base',
|
|
25
|
-
'ethereum': 'ERC20', 'eth': 'ERC20', 'erc20': 'ERC20',
|
|
26
|
-
'tron': 'trc20', 'trc20': 'trc20',
|
|
27
|
-
'mainnet': 'Mainnet', '
|
|
35
|
+
'ethereum': 'ERC20', 'eth': 'ERC20', 'erc20': 'ERC20', 'erc-20': 'ERC20',
|
|
36
|
+
'tron': 'trc20', 'trc20': 'trc20', 'trc-20': 'trc20',
|
|
37
|
+
'mainnet': 'Mainnet', 'main': 'Mainnet',
|
|
28
38
|
};
|
|
29
39
|
|
|
40
|
+
const VALID_AMOUNTS = [10, 25, 50, 100, 250, 500, 1000];
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Resolve user input to a verified ticker/network combo.
|
|
44
|
+
* Returns { ticker, network, display } or null if invalid.
|
|
45
|
+
*/
|
|
30
46
|
function resolveTickerNetwork(ticker, network) {
|
|
31
|
-
const t = (ticker || '').toLowerCase();
|
|
32
|
-
const n = (network || '').toLowerCase();
|
|
47
|
+
const t = TICKER_ALIASES[(ticker || '').toLowerCase()] || (ticker || '').toLowerCase();
|
|
33
48
|
|
|
34
|
-
// If
|
|
35
|
-
if (
|
|
36
|
-
const
|
|
37
|
-
|
|
49
|
+
// If network specified, try to match exactly
|
|
50
|
+
if (network) {
|
|
51
|
+
const n = NETWORK_ALIASES[(network || '').toLowerCase()] || network;
|
|
52
|
+
const match = VERIFIED_COMBOS.find(c => c.ticker === t && c.network === n);
|
|
53
|
+
if (match) return match;
|
|
54
|
+
// Try just the ticker with its default network
|
|
38
55
|
}
|
|
39
56
|
|
|
40
|
-
//
|
|
41
|
-
const
|
|
42
|
-
|
|
57
|
+
// Just ticker — find the verified default for it
|
|
58
|
+
const match = VERIFIED_COMBOS.find(c => c.ticker === t);
|
|
59
|
+
if (match) return match;
|
|
60
|
+
|
|
61
|
+
return null; // Not a verified combo
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get all verified combos (for menus / agent listings)
|
|
66
|
+
*/
|
|
67
|
+
export function getVerifiedCombos() {
|
|
68
|
+
return VERIFIED_COMBOS;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get the default combo
|
|
73
|
+
*/
|
|
74
|
+
export function getDefaultCombo() {
|
|
75
|
+
return VERIFIED_COMBOS.find(c => c.default) || VERIFIED_COMBOS[0];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get valid amounts
|
|
80
|
+
*/
|
|
81
|
+
export function getValidAmounts() {
|
|
82
|
+
return VALID_AMOUNTS;
|
|
43
83
|
}
|
|
44
84
|
|
|
45
85
|
export async function cardsCatalog() {
|
|
@@ -87,19 +127,40 @@ export async function cardsOrder(provider, amount, opts = {}) {
|
|
|
87
127
|
return;
|
|
88
128
|
}
|
|
89
129
|
|
|
130
|
+
// Validate amount
|
|
131
|
+
const numAmount = Number(amount);
|
|
132
|
+
if (!VALID_AMOUNTS.includes(numAmount)) {
|
|
133
|
+
error(`Invalid card amount: $${amount}. Valid amounts: ${VALID_AMOUNTS.map(a => '$' + a).join(', ')}`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Validate provider
|
|
138
|
+
const validProviders = ['swype', 'mpc', 'reward'];
|
|
139
|
+
if (!validProviders.includes((provider || '').toLowerCase())) {
|
|
140
|
+
error(`Invalid provider: ${provider}. Options: swype (Global MC), mpc (US MC), reward (US Visa)`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
90
144
|
const spin = spinner('Processing card order...').start();
|
|
91
145
|
try {
|
|
92
146
|
const body = {
|
|
93
|
-
provider,
|
|
94
|
-
amount:
|
|
147
|
+
provider: provider.toLowerCase(),
|
|
148
|
+
amount: numAmount,
|
|
95
149
|
email: opts.email,
|
|
96
150
|
};
|
|
97
|
-
|
|
151
|
+
|
|
152
|
+
// Resolve and validate crypto
|
|
98
153
|
if (opts.ticker) {
|
|
99
154
|
const resolved = resolveTickerNetwork(opts.ticker, opts.network);
|
|
155
|
+
if (!resolved) {
|
|
156
|
+
spin.fail('Invalid payment method');
|
|
157
|
+
error(`"${opts.ticker}${opts.network ? '/' + opts.network : ''}" is not a supported payment option.`);
|
|
158
|
+
info('Supported: ' + VERIFIED_COMBOS.map(c => c.display).join(', '));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
100
161
|
body.tickerFrom = resolved.ticker;
|
|
101
162
|
body.networkFrom = resolved.network;
|
|
102
|
-
info(`Payment: ${resolved.
|
|
163
|
+
info(`Payment: ${resolved.display}`);
|
|
103
164
|
}
|
|
104
165
|
|
|
105
166
|
const data = await fetchJSON(`${BASE()}/api/cards/order`, {
|
package/src/web/commands.js
CHANGED
|
@@ -215,9 +215,12 @@ export async function handleMenuSelect(id, value, item, ws) {
|
|
|
215
215
|
|
|
216
216
|
case 'cards_crypto':
|
|
217
217
|
if (value === 'back') return {};
|
|
218
|
-
// Execute the order
|
|
218
|
+
// Execute the order with verified combo
|
|
219
219
|
return await executeCardOrder(item?.meta || {}, ws);
|
|
220
220
|
|
|
221
|
+
case 'cards_status_check':
|
|
222
|
+
return await showCardStatus(value, ws);
|
|
223
|
+
|
|
221
224
|
case 'agent_action':
|
|
222
225
|
if (value === 'start') {
|
|
223
226
|
const { listWallets } = await import('../wallet/keystore.js');
|