nyxora 1.0.9 → 1.1.2
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/IDENTITY.md +5 -6
- package/README.md +1 -1
- package/dashboard/dist/assets/{index-DR9Ii-ZU.js → index-CKUbyknW.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dist/agent/reasoning.js +3 -3
- package/dist/gateway/cli.js +9 -20
- package/dist/gateway/server.js +12 -5
- package/dist/gateway/setup.js +31 -31
- package/dist/gateway/telegram.js +24 -19
- package/dist/utils/formatter.js +30 -0
- package/package.json +2 -3
- package/user.md +6 -7
- package/config.yaml +0 -15
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>Nyxora Dashboard</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-CKUbyknW.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-33NxKAJt.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/dist/agent/reasoning.js
CHANGED
|
@@ -103,10 +103,10 @@ If the user doesn't specify a chain, default to: ${config.agent.default_chain}.`
|
|
|
103
103
|
}
|
|
104
104
|
return basePrompt;
|
|
105
105
|
}
|
|
106
|
-
async function processUserInput(input) {
|
|
106
|
+
async function processUserInput(input, role = 'user') {
|
|
107
107
|
const config = (0, parser_1.loadConfig)();
|
|
108
|
-
// Add
|
|
109
|
-
exports.logger.addEntry({ role
|
|
108
|
+
// Add input to memory
|
|
109
|
+
exports.logger.addEntry({ role, content: input });
|
|
110
110
|
const history = exports.logger.getHistory();
|
|
111
111
|
// Format messages for OpenAI
|
|
112
112
|
const messages = [
|
package/dist/gateway/cli.js
CHANGED
|
@@ -30,23 +30,12 @@ async function main() {
|
|
|
30
30
|
// 2. Setup boilerplate files if in global mode and they don't exist
|
|
31
31
|
let isFirstBoot = false;
|
|
32
32
|
if (isGlobalMode) {
|
|
33
|
-
const globalEnvPath = path_1.default.join(appDir, '.env');
|
|
34
33
|
const globalConfigPath = path_1.default.join(appDir, 'config.yaml');
|
|
35
34
|
const globalUserMdPath = path_1.default.join(appDir, 'user.md');
|
|
36
35
|
const globalIdentityMdPath = path_1.default.join(appDir, 'IDENTITY.md');
|
|
37
|
-
// Copy .env.example to ~/.nyxora/.env if it doesn't exist
|
|
38
|
-
if (!fs_1.default.existsSync(globalEnvPath)) {
|
|
39
|
-
isFirstBoot = true;
|
|
40
|
-
const exampleEnvPath = path_1.default.resolve(__dirname, '../../../.env.example');
|
|
41
|
-
if (fs_1.default.existsSync(exampleEnvPath)) {
|
|
42
|
-
fs_1.default.copyFileSync(exampleEnvPath, globalEnvPath);
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
fs_1.default.writeFileSync(globalEnvPath, '# Nyxora Environment Variables\nPRIVATE_KEY=\n');
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
36
|
// Copy default config.yaml
|
|
49
37
|
if (!fs_1.default.existsSync(globalConfigPath)) {
|
|
38
|
+
isFirstBoot = true;
|
|
50
39
|
const exampleConfigPath = path_1.default.resolve(__dirname, '../../../config.yaml');
|
|
51
40
|
if (fs_1.default.existsSync(exampleConfigPath)) {
|
|
52
41
|
fs_1.default.copyFileSync(exampleConfigPath, globalConfigPath);
|
|
@@ -56,39 +45,39 @@ async function main() {
|
|
|
56
45
|
}
|
|
57
46
|
}
|
|
58
47
|
if (!fs_1.default.existsSync(globalUserMdPath)) {
|
|
59
|
-
fs_1.default.writeFileSync(globalUserMdPath, '
|
|
48
|
+
fs_1.default.writeFileSync(globalUserMdPath, 'Write custom instructions, special rules, user profiles, or the persona you want for Nyxora AI in this file.\n');
|
|
60
49
|
}
|
|
61
50
|
if (!fs_1.default.existsSync(globalIdentityMdPath)) {
|
|
62
|
-
fs_1.default.writeFileSync(globalIdentityMdPath, '
|
|
51
|
+
fs_1.default.writeFileSync(globalIdentityMdPath, 'You are a Web3 AI assistant named Nyxora.\n');
|
|
63
52
|
}
|
|
64
53
|
}
|
|
65
54
|
if (isFirstBoot) {
|
|
66
|
-
console.log('[Setup]
|
|
55
|
+
console.log('[Setup] New installation detected. Starting Setup Wizard...');
|
|
67
56
|
await (0, setup_1.runSetupWizard)();
|
|
68
57
|
}
|
|
69
58
|
// 3. Load Private Key into Memory
|
|
70
59
|
const keystorePath = path_1.default.join(appDir, 'keystore.json');
|
|
71
60
|
if (fs_1.default.existsSync(keystorePath)) {
|
|
72
61
|
const masterPassword = await (0, prompts_1.password)({
|
|
73
|
-
message: '🔒
|
|
62
|
+
message: '🔒 Vault locked! Enter Master Password to access Nyxora:',
|
|
74
63
|
});
|
|
75
64
|
if ((0, prompts_1.isCancel)(masterPassword) || !masterPassword) {
|
|
76
|
-
console.log(picocolors_1.default.red('
|
|
65
|
+
console.log(picocolors_1.default.red('Access denied. Exiting Nyxora.'));
|
|
77
66
|
return process.exit(0);
|
|
78
67
|
}
|
|
79
68
|
try {
|
|
80
69
|
const keystore = JSON.parse(fs_1.default.readFileSync(keystorePath, 'utf8'));
|
|
81
70
|
const privateKey = (0, crypto_1.decryptKey)(keystore, masterPassword);
|
|
82
71
|
(0, state_1.setPrivateKey)(privateKey);
|
|
83
|
-
console.log(picocolors_1.default.green('✅
|
|
72
|
+
console.log(picocolors_1.default.green('✅ Private Key successfully decrypted into memory.'));
|
|
84
73
|
}
|
|
85
74
|
catch (error) {
|
|
86
|
-
console.log(picocolors_1.default.red('❌ Master Password
|
|
75
|
+
console.log(picocolors_1.default.red('❌ Invalid Master Password or corrupted keystore. Exiting Nyxora.'));
|
|
87
76
|
return process.exit(1);
|
|
88
77
|
}
|
|
89
78
|
}
|
|
90
79
|
else {
|
|
91
|
-
console.log(picocolors_1.default.yellow('⚠️ Keystore
|
|
80
|
+
console.log(picocolors_1.default.yellow('⚠️ Keystore not found. Web3 features will be disabled unless you run `nyxora setup`.'));
|
|
92
81
|
}
|
|
93
82
|
// 4. Start the Express API Server (which also serves the static dashboard and Telegram bot)
|
|
94
83
|
(0, server_1.startServer)();
|
package/dist/gateway/server.js
CHANGED
|
@@ -19,6 +19,7 @@ const transfer_2 = require("../web3/skills/transfer");
|
|
|
19
19
|
const getPrice_1 = require("../web3/skills/getPrice");
|
|
20
20
|
const swapToken_2 = require("../web3/skills/swapToken");
|
|
21
21
|
const telegram_1 = require("./telegram");
|
|
22
|
+
const formatter_1 = require("../utils/formatter");
|
|
22
23
|
// Intercept console.log and console.error
|
|
23
24
|
const originalLog = console.log;
|
|
24
25
|
const originalError = console.error;
|
|
@@ -115,13 +116,19 @@ app.post('/api/transactions/:id/approve', async (req, res) => {
|
|
|
115
116
|
result = await (0, swapToken_1.executeSwap)(tx.chainName, tx.details.fromToken, tx.details.toToken, tx.details.amount);
|
|
116
117
|
}
|
|
117
118
|
transactionManager_1.txManager.updateStatus(id, 'executed', result);
|
|
118
|
-
//
|
|
119
|
-
(0,
|
|
119
|
+
// Add programmatic beautiful message directly to chat
|
|
120
|
+
const prettyMsg = (0, formatter_1.formatTransactionSuccess)(tx, result);
|
|
121
|
+
reasoning_1.logger.addEntry({ role: 'assistant', content: `✅ Transaction processed:\n\n${prettyMsg}` });
|
|
122
|
+
// Background update to LLM
|
|
123
|
+
(0, reasoning_1.processUserInput)(`Transaction ${id} was APPROVED and EXECUTED by the user via Dashboard. Result: ${result}`, 'system').catch(() => { });
|
|
120
124
|
res.json({ success: true, result });
|
|
121
125
|
}
|
|
122
126
|
catch (err) {
|
|
123
127
|
transactionManager_1.txManager.updateStatus(id, 'failed', err.message);
|
|
124
|
-
|
|
128
|
+
// Add programmatic beautiful error message directly to chat
|
|
129
|
+
const prettyError = (0, formatter_1.formatTransactionError)(tx, err.message);
|
|
130
|
+
reasoning_1.logger.addEntry({ role: 'assistant', content: prettyError });
|
|
131
|
+
(0, reasoning_1.processUserInput)(`Transaction ${id} was APPROVED but FAILED to execute. Error: ${err.message}`, 'system').catch(() => { });
|
|
125
132
|
res.status(500).json({ error: err.message });
|
|
126
133
|
}
|
|
127
134
|
});
|
|
@@ -129,9 +136,9 @@ app.post('/api/transactions/:id/reject', (req, res) => {
|
|
|
129
136
|
const id = req.params.id;
|
|
130
137
|
const tx = transactionManager_1.txManager.getTransaction(id);
|
|
131
138
|
if (!tx || tx.status !== 'pending')
|
|
132
|
-
return res.status(404).json({ error: 'Transaction not found' });
|
|
139
|
+
return res.status(404).json({ error: 'Transaction not found or not pending' });
|
|
133
140
|
transactionManager_1.txManager.updateStatus(id, 'rejected');
|
|
134
|
-
(0, reasoning_1.processUserInput)(`
|
|
141
|
+
(0, reasoning_1.processUserInput)(`Transaction ${id} was REJECTED by the user via Dashboard. Acknowledge this briefly.`, 'system').catch(() => { });
|
|
135
142
|
res.json({ success: true });
|
|
136
143
|
});
|
|
137
144
|
app.post('/api/chat', async (req, res) => {
|
package/dist/gateway/setup.js
CHANGED
|
@@ -22,62 +22,62 @@ async function runSetupWizard() {
|
|
|
22
22
|
╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝
|
|
23
23
|
`;
|
|
24
24
|
console.log(picocolors_1.default.cyan(logo));
|
|
25
|
-
(0, prompts_1.intro)(picocolors_1.default.inverse('
|
|
25
|
+
(0, prompts_1.intro)(picocolors_1.default.inverse(' Nyxora CLI Setup '));
|
|
26
26
|
const appDir = (0, paths_1.getAppDir)();
|
|
27
27
|
const config = (0, parser_1.loadConfig)();
|
|
28
|
-
const disclaimer = `Nyxora
|
|
28
|
+
const disclaimer = `Nyxora is a Web3 Assistant that operates with full access under your control.
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
- Private Key
|
|
32
|
-
-
|
|
33
|
-
-
|
|
30
|
+
Critical Precautions:
|
|
31
|
+
- Your Private Key is the lifeblood of your assets. NEVER copy or share the keystore.json file.
|
|
32
|
+
- Any instructions you provide via Telegram or Dashboard can trigger on-chain transactions.
|
|
33
|
+
- It is recommended to use a smart AI model for maximum accuracy.
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
(0, prompts_1.note)(disclaimer, '
|
|
35
|
+
By using Nyxora, you retain full control over your own keys.`;
|
|
36
|
+
(0, prompts_1.note)(disclaimer, 'Security Warning');
|
|
37
37
|
const understand = await (0, prompts_1.confirm)({
|
|
38
|
-
message: '
|
|
38
|
+
message: 'I understand that Private Key security is my responsibility. Continue?',
|
|
39
39
|
initialValue: true,
|
|
40
40
|
});
|
|
41
41
|
if ((0, prompts_1.isCancel)(understand) || !understand) {
|
|
42
|
-
(0, prompts_1.cancel)('
|
|
42
|
+
(0, prompts_1.cancel)('Setup cancelled.');
|
|
43
43
|
return process.exit(0);
|
|
44
44
|
}
|
|
45
45
|
const existingConfigNote = `Workspace: ${appDir}
|
|
46
|
-
Model
|
|
46
|
+
Current Model: ${config.llm.model}
|
|
47
47
|
Provider: ${config.llm.provider}`;
|
|
48
|
-
(0, prompts_1.note)(existingConfigNote, '
|
|
48
|
+
(0, prompts_1.note)(existingConfigNote, 'Configuration Detected');
|
|
49
49
|
const action = await (0, prompts_1.select)({
|
|
50
|
-
message: '
|
|
50
|
+
message: 'What would you like to do?',
|
|
51
51
|
options: [
|
|
52
|
-
{ value: 'keep', label: '
|
|
53
|
-
{ value: 'update', label: '
|
|
52
|
+
{ value: 'keep', label: 'Keep current values' },
|
|
53
|
+
{ value: 'update', label: 'Review and update settings' },
|
|
54
54
|
],
|
|
55
55
|
});
|
|
56
56
|
if ((0, prompts_1.isCancel)(action)) {
|
|
57
|
-
(0, prompts_1.cancel)('
|
|
57
|
+
(0, prompts_1.cancel)('Setup cancelled.');
|
|
58
58
|
return process.exit(0);
|
|
59
59
|
}
|
|
60
60
|
if (action === 'keep') {
|
|
61
|
-
(0, prompts_1.outro)(picocolors_1.default.green('
|
|
61
|
+
(0, prompts_1.outro)(picocolors_1.default.green('Done! Configuration unchanged. Starting Nyxora...'));
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
64
|
// --- WIZARD FORM ---
|
|
65
65
|
// 1. LLM Provider
|
|
66
66
|
const provider = await (0, prompts_1.select)({
|
|
67
|
-
message: '
|
|
67
|
+
message: 'Select AI Engine (Provider):',
|
|
68
68
|
initialValue: config.llm.provider,
|
|
69
69
|
options: [
|
|
70
|
-
{ value: 'openai', label: 'OpenAI (
|
|
70
|
+
{ value: 'openai', label: 'OpenAI (Recommended)' },
|
|
71
71
|
{ value: 'gemini', label: 'Google Gemini' },
|
|
72
|
-
{ value: 'openrouter', label: 'OpenRouter (
|
|
73
|
-
{ value: 'ollama', label: 'Ollama (
|
|
72
|
+
{ value: 'openrouter', label: 'OpenRouter (Many Models)' },
|
|
73
|
+
{ value: 'ollama', label: 'Ollama (Local)' },
|
|
74
74
|
],
|
|
75
75
|
});
|
|
76
76
|
if ((0, prompts_1.isCancel)(provider))
|
|
77
77
|
return process.exit(0);
|
|
78
78
|
// 2. Model Name
|
|
79
79
|
const model = await (0, prompts_1.text)({
|
|
80
|
-
message: '
|
|
80
|
+
message: 'Enter AI model name (e.g. gpt-4o, gemini-2.5-flash):',
|
|
81
81
|
initialValue: config.llm.model,
|
|
82
82
|
});
|
|
83
83
|
if ((0, prompts_1.isCancel)(model))
|
|
@@ -86,14 +86,14 @@ Provider: ${config.llm.provider}`;
|
|
|
86
86
|
let apiKey = '';
|
|
87
87
|
if (provider !== 'ollama') {
|
|
88
88
|
apiKey = (await (0, prompts_1.password)({
|
|
89
|
-
message: `
|
|
89
|
+
message: `Enter API Key for ${provider} (Leave empty if already set):`,
|
|
90
90
|
}));
|
|
91
91
|
if ((0, prompts_1.isCancel)(apiKey))
|
|
92
92
|
return process.exit(0);
|
|
93
93
|
}
|
|
94
94
|
// 4. Default Chain
|
|
95
95
|
const defaultChain = await (0, prompts_1.select)({
|
|
96
|
-
message: '
|
|
96
|
+
message: 'Select Default Chain:',
|
|
97
97
|
initialValue: config.agent.default_chain,
|
|
98
98
|
options: [
|
|
99
99
|
{ value: 'sepolia', label: 'Sepolia (Testnet)' },
|
|
@@ -108,7 +108,7 @@ Provider: ${config.llm.provider}`;
|
|
|
108
108
|
return process.exit(0);
|
|
109
109
|
// 5. Telegram Bot
|
|
110
110
|
const setupTelegram = await (0, prompts_1.confirm)({
|
|
111
|
-
message: '
|
|
111
|
+
message: 'Do you want to setup the Telegram Bot?',
|
|
112
112
|
initialValue: config.integrations?.telegram?.enabled || false,
|
|
113
113
|
});
|
|
114
114
|
if ((0, prompts_1.isCancel)(setupTelegram))
|
|
@@ -116,21 +116,21 @@ Provider: ${config.llm.provider}`;
|
|
|
116
116
|
let telegramToken = '';
|
|
117
117
|
if (setupTelegram) {
|
|
118
118
|
telegramToken = (await (0, prompts_1.password)({
|
|
119
|
-
message: '
|
|
119
|
+
message: 'Enter Telegram Bot Token from @BotFather (Leave empty if already set):',
|
|
120
120
|
}));
|
|
121
121
|
if ((0, prompts_1.isCancel)(telegramToken))
|
|
122
122
|
return process.exit(0);
|
|
123
123
|
}
|
|
124
124
|
// 6. Wallet Private Key (keystore.json)
|
|
125
125
|
const privateKey = await (0, prompts_1.password)({
|
|
126
|
-
message: '
|
|
126
|
+
message: 'Enter Wallet Private Key (0x...)\n (Will be AES-256-GCM encrypted. Leave empty to keep current):',
|
|
127
127
|
});
|
|
128
128
|
if ((0, prompts_1.isCancel)(privateKey))
|
|
129
129
|
return process.exit(0);
|
|
130
130
|
let masterPassword = '';
|
|
131
131
|
if (privateKey) {
|
|
132
132
|
masterPassword = (await (0, prompts_1.password)({
|
|
133
|
-
message: '
|
|
133
|
+
message: 'Enter MASTER PASSWORD to encrypt your key vault:',
|
|
134
134
|
}));
|
|
135
135
|
if ((0, prompts_1.isCancel)(masterPassword) || !masterPassword)
|
|
136
136
|
return process.exit(0);
|
|
@@ -169,12 +169,12 @@ Provider: ${config.llm.provider}`;
|
|
|
169
169
|
const envPath = path_1.default.join(appDir, '.env');
|
|
170
170
|
if (fs_1.default.existsSync(envPath)) {
|
|
171
171
|
fs_1.default.unlinkSync(envPath);
|
|
172
|
-
console.log(picocolors_1.default.yellow('
|
|
172
|
+
console.log(picocolors_1.default.yellow('Legacy .env file has been deleted for security.'));
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
catch (error) {
|
|
176
|
-
console.error('
|
|
176
|
+
console.error('Failed to save keystore.json:', error);
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
|
-
(0, prompts_1.outro)(picocolors_1.default.green('✨ Setup
|
|
179
|
+
(0, prompts_1.outro)(picocolors_1.default.green('✨ Setup Successful! All configurations have been securely saved.'));
|
|
180
180
|
}
|
package/dist/gateway/telegram.js
CHANGED
|
@@ -10,6 +10,7 @@ const parser_1 = require("../config/parser");
|
|
|
10
10
|
const transactionManager_1 = require("../agent/transactionManager");
|
|
11
11
|
const transfer_1 = require("../web3/skills/transfer");
|
|
12
12
|
const swapToken_1 = require("../web3/skills/swapToken");
|
|
13
|
+
const formatter_1 = require("../utils/formatter");
|
|
13
14
|
function startTelegramBot() {
|
|
14
15
|
const config = (0, parser_1.loadConfig)();
|
|
15
16
|
const token = config.integrations?.telegram?.bot_token;
|
|
@@ -32,17 +33,17 @@ function startTelegramBot() {
|
|
|
32
33
|
// Feed the message to the AI agent
|
|
33
34
|
const response = await (0, reasoning_1.processUserInput)(text);
|
|
34
35
|
// Send the AI's response back to Telegram
|
|
35
|
-
//
|
|
36
|
-
const
|
|
37
|
-
if (
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
if (
|
|
36
|
+
// Check for newly created pending transactions
|
|
37
|
+
const pendingTxs = transactionManager_1.txManager.getPending();
|
|
38
|
+
if (pendingTxs.length > 0) {
|
|
39
|
+
const latestTx = pendingTxs[pendingTxs.length - 1];
|
|
40
|
+
// If the transaction was created within the last 2 minutes, show the inline keyboard
|
|
41
|
+
if (Date.now() - latestTx.createdAt < 120000) {
|
|
41
42
|
bot.sendMessage(chatId, response, {
|
|
42
43
|
reply_markup: {
|
|
43
44
|
inline_keyboard: [[
|
|
44
|
-
{ text: '✅ Approve', callback_data: `approve_${
|
|
45
|
-
{ text: '❌ Reject', callback_data: `reject_${
|
|
45
|
+
{ text: '✅ Approve', callback_data: `approve_${latestTx.id}` },
|
|
46
|
+
{ text: '❌ Reject', callback_data: `reject_${latestTx.id}` }
|
|
46
47
|
]]
|
|
47
48
|
}
|
|
48
49
|
});
|
|
@@ -53,7 +54,7 @@ function startTelegramBot() {
|
|
|
53
54
|
}
|
|
54
55
|
catch (error) {
|
|
55
56
|
console.error('[Telegram] Error processing message:', error);
|
|
56
|
-
bot.sendMessage(chatId, '❌
|
|
57
|
+
bot.sendMessage(chatId, '❌ Sorry, I encountered an error while processing your message.');
|
|
57
58
|
}
|
|
58
59
|
});
|
|
59
60
|
bot.on('callback_query', async (query) => {
|
|
@@ -63,12 +64,12 @@ function startTelegramBot() {
|
|
|
63
64
|
const [action, txId] = query.data.split('_');
|
|
64
65
|
const tx = transactionManager_1.txManager.getTransaction(txId);
|
|
65
66
|
if (!tx || tx.status !== 'pending') {
|
|
66
|
-
bot.answerCallbackQuery(query.id, { text: '
|
|
67
|
+
bot.answerCallbackQuery(query.id, { text: 'Transaction not found or already processed.', show_alert: true });
|
|
67
68
|
return;
|
|
68
69
|
}
|
|
69
70
|
if (action === 'approve') {
|
|
70
|
-
bot.answerCallbackQuery(query.id, { text: '
|
|
71
|
-
bot.sendMessage(chatId, `⏳
|
|
71
|
+
bot.answerCallbackQuery(query.id, { text: 'Processing transaction...' });
|
|
72
|
+
bot.sendMessage(chatId, `⏳ Processing transaction ${txId}...`);
|
|
72
73
|
try {
|
|
73
74
|
let result = '';
|
|
74
75
|
if (tx.type === 'transfer') {
|
|
@@ -78,20 +79,24 @@ function startTelegramBot() {
|
|
|
78
79
|
result = await (0, swapToken_1.executeSwap)(tx.chainName, tx.details.fromToken, tx.details.toToken, tx.details.amount);
|
|
79
80
|
}
|
|
80
81
|
transactionManager_1.txManager.updateStatus(txId, 'executed', result);
|
|
81
|
-
(0,
|
|
82
|
-
bot.sendMessage(chatId, `✅
|
|
82
|
+
const prettyMsg = (0, formatter_1.formatTransactionSuccess)(tx, result);
|
|
83
|
+
bot.sendMessage(chatId, `✅ Transaction processed:\n\n${prettyMsg}`);
|
|
84
|
+
// Background update to LLM
|
|
85
|
+
(0, reasoning_1.processUserInput)(`Transaction ${txId} was APPROVED via Telegram. Result: ${result}`, 'system').catch(() => { });
|
|
83
86
|
}
|
|
84
87
|
catch (err) {
|
|
85
88
|
transactionManager_1.txManager.updateStatus(txId, 'failed', err.message);
|
|
86
|
-
(0,
|
|
87
|
-
bot.sendMessage(chatId,
|
|
89
|
+
const prettyError = (0, formatter_1.formatTransactionError)(tx, err.message);
|
|
90
|
+
bot.sendMessage(chatId, prettyError);
|
|
91
|
+
// Background update to LLM
|
|
92
|
+
(0, reasoning_1.processUserInput)(`Transaction ${txId} FAILED via Telegram. Error: ${err.message}`, 'system').catch(() => { });
|
|
88
93
|
}
|
|
89
94
|
}
|
|
90
95
|
else if (action === 'reject') {
|
|
91
96
|
transactionManager_1.txManager.updateStatus(txId, 'rejected');
|
|
92
|
-
(0, reasoning_1.processUserInput)(`
|
|
93
|
-
bot.answerCallbackQuery(query.id, { text: '
|
|
94
|
-
bot.sendMessage(chatId, `❌
|
|
97
|
+
(0, reasoning_1.processUserInput)(`Transaction ${txId} was REJECTED via Telegram. Acknowledge this briefly.`, 'system').catch(() => { });
|
|
98
|
+
bot.answerCallbackQuery(query.id, { text: 'Transaction cancelled.' });
|
|
99
|
+
bot.sendMessage(chatId, `❌ Transaction cancelled.`);
|
|
95
100
|
}
|
|
96
101
|
// Remove inline keyboard
|
|
97
102
|
bot.editMessageReplyMarkup({ inline_keyboard: [] }, { chat_id: chatId, message_id: query.message?.message_id });
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatTransactionSuccess = formatTransactionSuccess;
|
|
4
|
+
exports.formatTransactionError = formatTransactionError;
|
|
5
|
+
function formatTransactionSuccess(tx, rawResult) {
|
|
6
|
+
let txHash = 'N/A';
|
|
7
|
+
try {
|
|
8
|
+
const parsed = JSON.parse(rawResult);
|
|
9
|
+
if (parsed.txHash)
|
|
10
|
+
txHash = parsed.txHash;
|
|
11
|
+
}
|
|
12
|
+
catch (e) {
|
|
13
|
+
const hashMatch = rawResult.match(/Hash: (0x[a-fA-F0-9]+)/);
|
|
14
|
+
if (hashMatch) {
|
|
15
|
+
txHash = hashMatch[1];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const chainFormatted = tx.chainName.charAt(0).toUpperCase() + tx.chainName.slice(1);
|
|
19
|
+
if (tx.type === 'swap') {
|
|
20
|
+
return `Alright, I have completed the swap from ${tx.details.amount} ${tx.details.fromToken.toUpperCase()} to ${tx.details.toToken.toUpperCase()}.\n\nChain: ${chainFormatted}\nTx Hash:\n${txHash}`;
|
|
21
|
+
}
|
|
22
|
+
else if (tx.type === 'transfer') {
|
|
23
|
+
return `Alright, I have completed the transfer of ${tx.details.amountEth} tokens to ${tx.details.toAddress}.\n\nChain: ${chainFormatted}\nTx Hash:\n${txHash}`;
|
|
24
|
+
}
|
|
25
|
+
return `Transaction successful!\n\nChain: ${chainFormatted}\nTx Hash:\n${txHash}`;
|
|
26
|
+
}
|
|
27
|
+
function formatTransactionError(tx, errorMsg) {
|
|
28
|
+
const chainFormatted = tx.chainName.charAt(0).toUpperCase() + tx.chainName.slice(1);
|
|
29
|
+
return `❌ Failed to process transaction on ${chainFormatted}.\n\nError: ${errorMsg}`;
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nyxora",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/gateway/cli.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
8
8
|
"dashboard/dist",
|
|
9
|
-
"config.yaml",
|
|
10
9
|
"user.md",
|
|
11
10
|
"IDENTITY.md",
|
|
12
11
|
"SECURITY.md",
|
|
@@ -20,7 +19,7 @@
|
|
|
20
19
|
"start": "node dist/gateway/cli.js",
|
|
21
20
|
"dashboard": "npm run build && node dist/gateway/cli.js",
|
|
22
21
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
23
|
-
"deploy": "npm run build && git add . && git commit -m \"chore: auto-deploy new feature\" && git push && npm publish"
|
|
22
|
+
"deploy": "npm run build && git add . && git commit -m \"chore: auto-deploy new feature\" && git push && git push --tags && npm publish"
|
|
24
23
|
},
|
|
25
24
|
"keywords": [],
|
|
26
25
|
"author": "",
|
package/user.md
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
Write custom instructions, special rules, user profiles, or the persona you want for Nyxora AI in this file.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Every time the agent reads your messages, it will read this file first as its primary guideline.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* "Panggil saya dengan sebutan Yudha"
|
|
8
|
-
* "Gunakan gaya bahasa santai dan gaul"
|
|
9
|
-
* "Fokuskan analisis pada sudut pandang teknikal trading"
|
|
5
|
+
Examples:
|
|
10
6
|
|
|
7
|
+
* "Call me Yudha"
|
|
8
|
+
* "Use casual and slang language"
|
|
9
|
+
* "Focus analysis from a technical trading perspective"
|
package/config.yaml
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
agent:
|
|
2
|
-
name: Nyxora-EVM-Agent
|
|
3
|
-
default_chain: sepolia
|
|
4
|
-
llm:
|
|
5
|
-
provider: gemini
|
|
6
|
-
model: gemini-2.5-flash
|
|
7
|
-
temperature: 0.2
|
|
8
|
-
credentials:
|
|
9
|
-
gemini_key: AIzaSyDBlde1SSp_kbTweW1QXHknwzRTYHp98IQ
|
|
10
|
-
memory:
|
|
11
|
-
type: file
|
|
12
|
-
path: ./memory.json
|
|
13
|
-
integrations:
|
|
14
|
-
telegram:
|
|
15
|
-
enabled: false
|