nyxora 26.6.19 → 26.6.21
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/README.md +18 -1
- package/bin/nyxora.mjs +32 -0
- package/dist/packages/core/src/agent/reasoning.js +11 -1
- package/dist/packages/core/src/config/parser.js +121 -7
- package/dist/packages/core/src/gateway/chat.js +82 -0
- package/dist/packages/core/src/gateway/cli.js +63 -0
- package/dist/packages/core/src/gateway/server.js +117 -56
- package/dist/packages/core/src/gateway/setup.js +39 -22
- package/dist/packages/core/src/utils/formatter.test.js +40 -0
- package/dist/packages/core/src/utils/skillManager.js +91 -0
- package/dist/packages/core/src/utils/userWhitelistManager.js +41 -36
- package/dist/packages/core/src/web3/aggregator/aggregatorMainnet.js +2 -2
- package/dist/packages/core/src/web3/aggregator/defiRouter.js +3 -0
- package/dist/packages/core/src/web3/skills/bridgeToken.js +4 -0
- package/dist/packages/core/src/web3/skills/checkRegistryStatus.js +13 -0
- package/dist/packages/core/src/web3/skills/customTx.js +2 -0
- package/dist/packages/core/src/web3/skills/defiLending.js +2 -0
- package/dist/packages/core/src/web3/skills/getPrice.js +11 -6
- package/dist/packages/core/src/web3/skills/manageCustomTokens.js +18 -32
- package/dist/packages/core/src/web3/skills/marketAnalysis.js +3 -1
- package/dist/packages/core/src/web3/skills/mintNft.js +2 -0
- package/dist/packages/core/src/web3/skills/provideLiquidity.js +2 -0
- package/dist/packages/core/src/web3/skills/revokeApprovals.js +2 -0
- package/dist/packages/core/src/web3/skills/swapToken.js +4 -2
- package/dist/packages/core/src/web3/skills/transfer.js +2 -0
- package/dist/packages/core/src/web3/skills/yieldVault.js +2 -0
- package/dist/packages/core/src/web3/utils/tokens.js +9 -1
- package/package.json +2 -1
- package/packages/core/package.json +1 -1
- package/packages/core/src/agent/reasoning.ts +12 -1
- package/packages/core/src/config/parser.ts +119 -9
- package/packages/core/src/gateway/chat.ts +85 -0
- package/packages/core/src/gateway/cli.ts +63 -0
- package/packages/core/src/gateway/server.ts +132 -60
- package/packages/core/src/gateway/setup.ts +39 -27
- package/packages/core/src/utils/formatter.test.ts +41 -0
- package/packages/core/src/utils/skillManager.ts +98 -0
- package/packages/core/src/utils/userWhitelistManager.ts +48 -39
- package/packages/core/src/web3/aggregator/aggregatorMainnet.ts +2 -2
- package/packages/core/src/web3/aggregator/defiRouter.ts +4 -0
- package/packages/core/src/web3/skills/bridgeToken.ts +3 -0
- package/packages/core/src/web3/skills/checkRegistryStatus.ts +13 -0
- package/packages/core/src/web3/skills/customTx.ts +1 -0
- package/packages/core/src/web3/skills/defiLending.ts +1 -0
- package/packages/core/src/web3/skills/getPrice.ts +11 -6
- package/packages/core/src/web3/skills/manageCustomTokens.ts +18 -29
- package/packages/core/src/web3/skills/marketAnalysis.ts +2 -1
- package/packages/core/src/web3/skills/mintNft.ts +1 -0
- package/packages/core/src/web3/skills/provideLiquidity.ts +1 -0
- package/packages/core/src/web3/skills/revokeApprovals.ts +1 -0
- package/packages/core/src/web3/skills/swapToken.ts +3 -2
- package/packages/core/src/web3/skills/transfer.ts +1 -0
- package/packages/core/src/web3/skills/yieldVault.ts +1 -0
- package/packages/core/src/web3/utils/tokens.ts +9 -1
- package/packages/dashboard/dist/assets/{index-DnQrbB4c.css → index-CQNHWZtN.css} +1 -1
- package/packages/dashboard/dist/assets/index-Di9x08yk.js +16 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/package.json +1 -1
- package/packages/mcp-server/package.json +1 -1
- package/packages/policy/package.json +1 -1
- package/packages/signer/package.json +1 -1
- package/dist/packages/core/src/agent/limitOrderManager.js +0 -124
- package/dist/packages/core/src/system/pluginManager.js +0 -91
- package/dist/packages/core/src/system/skills/installSkill.js +0 -52
- package/dist/packages/core/src/test-all-routers.js +0 -81
- package/dist/packages/core/src/test-router.js +0 -38
- package/dist/packages/core/src/web3/skills/autonomousDefi.js +0 -191
- package/dist/packages/core/src/web3/skills/createWallet.js +0 -34
- package/dist/packages/core/src/web3/skills/limitOrder.js +0 -106
- package/dist/packages/core/src/web3/utils/protocolRegistry.js +0 -46
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/packages/core/src/__tests__/reasoning.test.ts +0 -81
- package/packages/core/src/__tests__/tokens.test.ts +0 -55
- package/packages/core/src/__tests__/web3.test.ts +0 -50
- package/packages/core/src/agent/reasoning.d.ts.map +0 -1
- package/packages/core/src/config/parser.d.ts.map +0 -1
- package/packages/core/src/gateway/cli.d.ts.map +0 -1
- package/packages/core/src/memory/logger.d.ts.map +0 -1
- package/packages/core/src/test-all-routers.ts +0 -59
- package/packages/core/src/test-router.ts +0 -49
- package/packages/core/src/web3/config.d.ts.map +0 -1
- package/packages/core/src/web3/skills/getBalance.d.ts.map +0 -1
- package/packages/dashboard/dist/assets/index-BAXifdMN.js +0 -16
package/README.md
CHANGED
|
@@ -24,6 +24,9 @@ It operates under a **Zero-Trust, Defense-in-Depth Cryptographically Bound Human
|
|
|
24
24
|
* **3-Tier IPC Architecture**: Nyxora is split into isolated processes: **Core** (LLM Runtime), **Policy Engine** (Guardrails on port 3001), and **Signer Vault** (Isolated Key Manager on Unix Sockets).
|
|
25
25
|
* **DeFi Configuration BYOK & UI Masking**: All aggregator and provider API keys are strictly isolated via a Bring Your Own Keys (BYOK) architecture into a heavily guarded `~/.nyxora/defi_keys.yaml` file. The local web Dashboard masks these injected secrets using `***********` and `IS_SET` censorship, completely neutralizing malicious browser extensions from exfiltrating your keys.
|
|
26
26
|
* **Approval Replay Protection (Nonce Guard)**: Transactions requested by the AI are drafted as hashes and signed with a randomized 16-byte Nonce. The `/api/transactions/:id/approve` endpoint strictly enforces Nonce matching to completely eliminate double-spending and Replay Attacks.
|
|
27
|
+
* **Native Asset Parameter Tampering Protection**: The internal cryptographic HMAC signature rigorously binds `toAddress`, `txData`, and `valueWei`, rendering the system mathematically immune to Native Token (ETH/BNB) destination or amount hijacking via Indirect Prompt Injections.
|
|
28
|
+
* **Human-in-the-Loop Memory Approval**: AI-extracted permanent behavioral rules are strictly quarantined in a `pending` state until explicitly authorized by the user via the Dashboard, neutralizing Persistent Memory Poisoning vectors.
|
|
29
|
+
* **Stateless Policy Engine & DoS Resilience**: The Policy Engine operates as a 100% stateless cryptographic HMAC gatekeeper, hardened with resilient `try...catch` IPC interceptors to withstand Signer-level Denial of Service (Crash) attacks.
|
|
27
30
|
* **Immutable Policy Guardrails**: Transaction limits (e.g. `max_usd_per_tx`) are strictly enforced by the Policy Engine. The LLM has zero write-access to bypass these rules.
|
|
28
31
|
|
|
29
32
|
* **Graceful SQLite WAL Shutdown**: Integrated `SIGTERM`/`SIGINT` interceptors ensure that when the daemon stops, active requests are safely terminated and SQLite Write-Ahead Logs (WAL) are securely flushed, preventing database corruption.
|
|
@@ -133,6 +136,12 @@ nyxora dashboard
|
|
|
133
136
|
```bash
|
|
134
137
|
nyxora clear --force
|
|
135
138
|
```
|
|
139
|
+
|
|
140
|
+
### Utility: Clean Uninstallation
|
|
141
|
+
To completely remove Nyxora, wipe the AI's local memory, and securely delete your Private Key from the OS Keyring before uninstalling the NPM package:
|
|
142
|
+
```bash
|
|
143
|
+
nyxora uninstall
|
|
144
|
+
```
|
|
136
145
|
> **⚠️ IMPORTANT:** Whenever you re-run `nyxora setup` or manually edit the config files, you **must restart the daemon** by running `nyxora restart` for the changes to take effect.
|
|
137
146
|
|
|
138
147
|
### Local Development (From Source)
|
|
@@ -159,6 +168,14 @@ npm start
|
|
|
159
168
|
|
|
160
169
|
---
|
|
161
170
|
|
|
171
|
+
## ⚖️ Terms of Service
|
|
172
|
+
|
|
173
|
+
By downloading, installing, or using the Nyxora AI Agent, you agree to our assumption of risk and liability limitations. Please ensure you review our legal policies before deploying the agent.
|
|
174
|
+
|
|
175
|
+
> **🔗 [Read the Full Terms of Service Here](https://nyxoraai.github.io/Nyxora/terms)**
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
162
179
|
## 📖 Official Documentation
|
|
163
180
|
|
|
164
181
|
For complete technical deep-dives into our Cryptographic Architecture, please visit our official VitePress Documentation Site!
|
|
@@ -172,7 +189,7 @@ For complete technical deep-dives into our Cryptographic Architecture, please vi
|
|
|
172
189
|
**❤️ Support the Project**
|
|
173
190
|
|
|
174
191
|
Building and maintaining a highly secure, zero-trust architecture takes significant time and resources. If you love what we are building, you can help us keep Nyxora open, secure, and constantly evolving by sending a coffee our way:
|
|
175
|
-
- **EVM
|
|
192
|
+
- **EVM :** `0x490717E50D6434C348AA0D2bD5fe682392823708`
|
|
176
193
|
|
|
177
194
|
---
|
|
178
195
|
**License:** MIT License
|
package/bin/nyxora.mjs
CHANGED
|
@@ -267,6 +267,34 @@ async function wallet(cliArgs) {
|
|
|
267
267
|
await new Promise(resolve => child.on('close', resolve));
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
async function uninstall(cliArgs) {
|
|
271
|
+
const compiledCli = path.join(projectRoot, 'dist', 'packages/core/src/gateway/cli.js');
|
|
272
|
+
const useCompiled = fs.existsSync(compiledCli);
|
|
273
|
+
const cmd = useCompiled ? 'node' : 'npx';
|
|
274
|
+
const args = useCompiled ? [compiledCli, 'uninstall', ...cliArgs] : ['ts-node', '-T', 'packages/core/src/gateway/cli.ts', 'uninstall', ...cliArgs];
|
|
275
|
+
const child = spawn(cmd, args, {
|
|
276
|
+
cwd: projectRoot,
|
|
277
|
+
stdio: 'inherit',
|
|
278
|
+
env: { ...process.env, TS_NODE_CACHE: 'false' }
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
await new Promise(resolve => child.on('close', resolve));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async function chat(cliArgs) {
|
|
285
|
+
const compiledCli = path.join(projectRoot, 'dist', 'packages/core/src/gateway/cli.js');
|
|
286
|
+
const useCompiled = fs.existsSync(compiledCli);
|
|
287
|
+
const cmd = useCompiled ? 'node' : 'npx';
|
|
288
|
+
const args = useCompiled ? [compiledCli, 'chat', ...cliArgs] : ['ts-node', '-T', 'packages/core/src/gateway/cli.ts', 'chat', ...cliArgs];
|
|
289
|
+
const child = spawn(cmd, args, {
|
|
290
|
+
cwd: projectRoot,
|
|
291
|
+
stdio: 'inherit',
|
|
292
|
+
env: { ...process.env, TS_NODE_CACHE: 'false' }
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
await new Promise(resolve => child.on('close', resolve));
|
|
296
|
+
}
|
|
297
|
+
|
|
270
298
|
async function runDoctor() {
|
|
271
299
|
const compiledCli = path.join(projectRoot, 'dist', 'packages/core/src/gateway/doctor.js');
|
|
272
300
|
const useCompiled = fs.existsSync(compiledCli);
|
|
@@ -317,6 +345,8 @@ async function main() {
|
|
|
317
345
|
case 'clear': await clearMemory(process.argv.slice(3)); break;
|
|
318
346
|
case 'set-key': await setKey(process.argv.slice(3)); break;
|
|
319
347
|
case 'wallet': await wallet(process.argv.slice(3)); break;
|
|
348
|
+
case 'chat': await chat(process.argv.slice(3)); break;
|
|
349
|
+
case 'uninstall': await uninstall(process.argv.slice(3)); break;
|
|
320
350
|
case 'start': await start(); break;
|
|
321
351
|
case 'stop': await stop(); break;
|
|
322
352
|
case 'restart': await restart(); break;
|
|
@@ -341,6 +371,7 @@ Commands:
|
|
|
341
371
|
start Start the Nyxora background daemon
|
|
342
372
|
stop Stop the running daemon
|
|
343
373
|
restart Restart the daemon
|
|
374
|
+
chat Chat interactively with the AI in terminal
|
|
344
375
|
setup Run the interactive Setup Wizard
|
|
345
376
|
dashboard Open the dashboard in your browser
|
|
346
377
|
unlock Unlock an inactive dashboard session
|
|
@@ -350,6 +381,7 @@ Commands:
|
|
|
350
381
|
autostart Enable/disable autostart on boot (usage: nyxora autostart enable)
|
|
351
382
|
set-key Securely save API Key (usage: nyxora set-key <provider> <key>)
|
|
352
383
|
wallet Manage your Web3 Wallet (usage: nyxora wallet update)
|
|
384
|
+
uninstall Wipe AI memory, securely delete keys, and remove configuration
|
|
353
385
|
|
|
354
386
|
Options:
|
|
355
387
|
-v, --version Show current version
|
|
@@ -315,6 +315,16 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
315
315
|
}, sessionId);
|
|
316
316
|
continue;
|
|
317
317
|
}
|
|
318
|
+
if (!(0, skillManager_1.isSkillActive)(toolName)) {
|
|
319
|
+
console.warn(picocolors_1.default.red(`[Security] Blocked illegal execution of disabled skill: ${toolName}`));
|
|
320
|
+
result = `[System Error] Access denied: Skill '${toolName}' is currently disabled by the user.`;
|
|
321
|
+
exports.logger.addEntry({
|
|
322
|
+
role: "tool",
|
|
323
|
+
tool_call_id: toolCall.id,
|
|
324
|
+
content: result
|
|
325
|
+
}, sessionId);
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
318
328
|
try {
|
|
319
329
|
switch (toolName) {
|
|
320
330
|
case 'get_balance': {
|
|
@@ -327,7 +337,7 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
327
337
|
break;
|
|
328
338
|
}
|
|
329
339
|
case 'get_price': {
|
|
330
|
-
result = await (0, getPrice_1.getPrice)(args.coinId);
|
|
340
|
+
result = await (0, getPrice_1.getPrice)(args.coinId, args.currency);
|
|
331
341
|
break;
|
|
332
342
|
}
|
|
333
343
|
case 'swap_token': {
|
|
@@ -3,15 +3,92 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.encryptDataSync = encryptDataSync;
|
|
7
|
+
exports.decryptDataSync = decryptDataSync;
|
|
6
8
|
exports.loadRpcConfig = loadRpcConfig;
|
|
7
9
|
exports.saveRpcConfig = saveRpcConfig;
|
|
8
10
|
exports.loadApiKeys = loadApiKeys;
|
|
9
11
|
exports.saveApiKeys = saveApiKeys;
|
|
10
12
|
exports.loadConfig = loadConfig;
|
|
11
13
|
exports.saveConfig = saveConfig;
|
|
14
|
+
exports.loadPolicyConfig = loadPolicyConfig;
|
|
12
15
|
const fs_1 = __importDefault(require("fs"));
|
|
13
16
|
const yaml_1 = __importDefault(require("yaml"));
|
|
17
|
+
const path_1 = __importDefault(require("path"));
|
|
18
|
+
const os_1 = __importDefault(require("os"));
|
|
19
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
14
20
|
const paths_1 = require("./paths");
|
|
21
|
+
let cachedEncryptionKey = null;
|
|
22
|
+
function getEncryptionKeySync() {
|
|
23
|
+
if (cachedEncryptionKey)
|
|
24
|
+
return cachedEncryptionKey;
|
|
25
|
+
let masterKeyRaw = process.env.NYXORA_MASTER_KEY;
|
|
26
|
+
if (!masterKeyRaw) {
|
|
27
|
+
try {
|
|
28
|
+
const { execSync } = require('child_process');
|
|
29
|
+
const output = execSync(`node -e "require('@napi-rs/keyring').Entry.prototype.getPassword.call(new (require('@napi-rs/keyring').Entry)('nyxora', 'config_master')).then(console.log).catch(()=>console.log(''))"`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
|
|
30
|
+
const pk = output?.trim();
|
|
31
|
+
if (pk)
|
|
32
|
+
masterKeyRaw = pk;
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
// Ignore
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!masterKeyRaw) {
|
|
39
|
+
try {
|
|
40
|
+
const masterKeyPath = path_1.default.join(os_1.default.homedir(), '.nyxora', 'auth', 'master.key');
|
|
41
|
+
if (fs_1.default.existsSync(masterKeyPath)) {
|
|
42
|
+
masterKeyRaw = fs_1.default.readFileSync(masterKeyPath, 'utf8').trim();
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
masterKeyRaw = crypto_1.default.randomBytes(32).toString('hex');
|
|
46
|
+
try {
|
|
47
|
+
fs_1.default.writeFileSync(masterKeyPath, masterKeyRaw, { mode: 0o600 });
|
|
48
|
+
}
|
|
49
|
+
catch (e) { }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
masterKeyRaw = 'default_fallback_nyxora_key';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
cachedEncryptionKey = crypto_1.default.createHash('sha256').update(masterKeyRaw).digest();
|
|
57
|
+
return cachedEncryptionKey;
|
|
58
|
+
}
|
|
59
|
+
function encryptDataSync(text) {
|
|
60
|
+
if (!text || text.startsWith('ENC:'))
|
|
61
|
+
return text;
|
|
62
|
+
const iv = crypto_1.default.randomBytes(12);
|
|
63
|
+
const cipher = crypto_1.default.createCipheriv('aes-256-gcm', getEncryptionKeySync(), iv);
|
|
64
|
+
let encrypted = cipher.update(text, 'utf8', 'hex');
|
|
65
|
+
encrypted += cipher.final('hex');
|
|
66
|
+
const authTag = cipher.getAuthTag().toString('hex');
|
|
67
|
+
return `ENC:${iv.toString('hex')}:${authTag}:${encrypted}`;
|
|
68
|
+
}
|
|
69
|
+
function decryptDataSync(encryptedText) {
|
|
70
|
+
if (!encryptedText)
|
|
71
|
+
return encryptedText;
|
|
72
|
+
if (!encryptedText.startsWith('ENC:')) {
|
|
73
|
+
return encryptedText;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
const parts = encryptedText.split(':');
|
|
77
|
+
if (parts.length < 4)
|
|
78
|
+
return encryptedText;
|
|
79
|
+
const iv = Buffer.from(parts[1], 'hex');
|
|
80
|
+
const authTag = Buffer.from(parts[2], 'hex');
|
|
81
|
+
const encrypted = parts.slice(3).join(':');
|
|
82
|
+
const decipher = crypto_1.default.createDecipheriv('aes-256-gcm', getEncryptionKeySync(), iv);
|
|
83
|
+
decipher.setAuthTag(authTag);
|
|
84
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
85
|
+
decrypted += decipher.final('utf8');
|
|
86
|
+
return decrypted;
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
return encryptedText; // return raw if decryption fails
|
|
90
|
+
}
|
|
91
|
+
}
|
|
15
92
|
function loadRpcConfig() {
|
|
16
93
|
const rpcPath = (0, paths_1.getPath)('rpc_key.yaml');
|
|
17
94
|
if (fs_1.default.existsSync(rpcPath)) {
|
|
@@ -51,8 +128,28 @@ function loadConfig() {
|
|
|
51
128
|
try {
|
|
52
129
|
const file = fs_1.default.readFileSync(configPath, 'utf8');
|
|
53
130
|
const parsed = yaml_1.default.parse(file);
|
|
54
|
-
// Auto-migration logic: move llm.credentials to root credentials
|
|
55
131
|
let needsSave = false;
|
|
132
|
+
// Decrypt credentials
|
|
133
|
+
if (parsed.credentials) {
|
|
134
|
+
for (const key in parsed.credentials) {
|
|
135
|
+
if (parsed.credentials[key]) {
|
|
136
|
+
if (parsed.credentials[key].startsWith('ENC:'))
|
|
137
|
+
needsSave = true;
|
|
138
|
+
parsed.credentials[key] = decryptDataSync(parsed.credentials[key]);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (parsed.integrations?.telegram?.bot_token) {
|
|
143
|
+
if (parsed.integrations.telegram.bot_token.startsWith('ENC:'))
|
|
144
|
+
needsSave = true;
|
|
145
|
+
parsed.integrations.telegram.bot_token = decryptDataSync(parsed.integrations.telegram.bot_token);
|
|
146
|
+
}
|
|
147
|
+
if (parsed.web3?.explorer_api_key) {
|
|
148
|
+
if (parsed.web3.explorer_api_key.startsWith('ENC:'))
|
|
149
|
+
needsSave = true;
|
|
150
|
+
parsed.web3.explorer_api_key = decryptDataSync(parsed.web3.explorer_api_key);
|
|
151
|
+
}
|
|
152
|
+
// Auto-migration logic: move llm.credentials to root credentials
|
|
56
153
|
if (parsed.llm && parsed.llm.credentials) {
|
|
57
154
|
if (!parsed.credentials) {
|
|
58
155
|
parsed.credentials = {};
|
|
@@ -74,7 +171,7 @@ function loadConfig() {
|
|
|
74
171
|
// Auto-migration logic: move permissions to policy.yaml
|
|
75
172
|
const policyPath = (0, paths_1.getPath)('policy.yaml');
|
|
76
173
|
if (!fs_1.default.existsSync(policyPath)) {
|
|
77
|
-
const defaultPolicy = `
|
|
174
|
+
const defaultPolicy = `auto_approve_limit_usd: 0\ncustom_llm_rules: []\n`;
|
|
78
175
|
fs_1.default.writeFileSync(policyPath, defaultPolicy, 'utf8');
|
|
79
176
|
console.log('[Config] Created default policy.yaml.');
|
|
80
177
|
}
|
|
@@ -84,15 +181,14 @@ function loadConfig() {
|
|
|
84
181
|
}
|
|
85
182
|
if (needsSave) {
|
|
86
183
|
try {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
console.log('[Config] Auto-migrated llm.credentials to root credentials.');
|
|
184
|
+
saveConfig(parsed);
|
|
185
|
+
console.log('[Config] Auto-migrated config file safely.');
|
|
90
186
|
}
|
|
91
187
|
catch (e) {
|
|
92
188
|
console.error('[Config] Failed to auto-migrate config file', e);
|
|
93
189
|
}
|
|
94
190
|
}
|
|
95
|
-
|
|
191
|
+
const validatedConfig = {
|
|
96
192
|
agent: parsed.agent || { name: 'Nyxora-Default', description: 'Your Personal Web3 Assistant.', default_chain: 'base', default_router: 'auto', default_slippage: 'auto' },
|
|
97
193
|
llm: parsed.llm || {
|
|
98
194
|
provider: 'openai',
|
|
@@ -109,13 +205,18 @@ function loadConfig() {
|
|
|
109
205
|
web3: { ...parsed.web3, rpc_urls: rpcUrls },
|
|
110
206
|
integrations: parsed.integrations || {
|
|
111
207
|
telegram: { enabled: false }
|
|
112
|
-
}
|
|
208
|
+
},
|
|
209
|
+
skills: parsed.skills
|
|
113
210
|
};
|
|
211
|
+
return validatedConfig;
|
|
114
212
|
}
|
|
115
213
|
catch (error) {
|
|
116
214
|
if (error.code === 'ENOENT') {
|
|
117
215
|
console.log('[Config] No config.yaml found. Using default configuration.');
|
|
118
216
|
}
|
|
217
|
+
else if (error.name === 'YAMLError' || error.message?.includes('YAML')) {
|
|
218
|
+
console.warn('[Parser] YAML Parse Error:', error.message);
|
|
219
|
+
}
|
|
119
220
|
else {
|
|
120
221
|
console.error('[Config] Failed to load config.yaml. Using default configuration.', error);
|
|
121
222
|
}
|
|
@@ -153,6 +254,7 @@ function saveConfig(newConfig) {
|
|
|
153
254
|
if (configToSave.web3 && configToSave.web3.rpc_urls) {
|
|
154
255
|
delete configToSave.web3.rpc_urls;
|
|
155
256
|
}
|
|
257
|
+
// Keys are no longer encrypted before saving. They are stored in plain text.
|
|
156
258
|
const yamlStr = yaml_1.default.stringify(configToSave);
|
|
157
259
|
fs_1.default.writeFileSync(configPath, yamlStr, 'utf8');
|
|
158
260
|
}
|
|
@@ -160,3 +262,15 @@ function saveConfig(newConfig) {
|
|
|
160
262
|
console.error('Failed to save config.yaml', error);
|
|
161
263
|
}
|
|
162
264
|
}
|
|
265
|
+
function loadPolicyConfig() {
|
|
266
|
+
const policyPath = (0, paths_1.getPath)('policy.yaml');
|
|
267
|
+
if (fs_1.default.existsSync(policyPath)) {
|
|
268
|
+
try {
|
|
269
|
+
return yaml_1.default.parse(fs_1.default.readFileSync(policyPath, 'utf8')) || {};
|
|
270
|
+
}
|
|
271
|
+
catch (e) {
|
|
272
|
+
console.error('[Config] Failed to parse policy.yaml', e);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return {};
|
|
276
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.chatInteractive = chatInteractive;
|
|
7
|
+
const prompts_1 = require("@clack/prompts");
|
|
8
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const paths_1 = require("../config/paths");
|
|
11
|
+
async function chatInteractive() {
|
|
12
|
+
const tokenFile = (0, paths_1.getPath)('auth.token');
|
|
13
|
+
if (!fs_1.default.existsSync(tokenFile)) {
|
|
14
|
+
console.log(picocolors_1.default.red('❌ Nyxora daemon is not running. Please start it with `nyxora start`.'));
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
let token = fs_1.default.readFileSync(tokenFile, 'utf8').trim();
|
|
18
|
+
if (token.startsWith('{')) {
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(token);
|
|
21
|
+
token = parsed.token;
|
|
22
|
+
}
|
|
23
|
+
catch (e) { }
|
|
24
|
+
}
|
|
25
|
+
const logo = `
|
|
26
|
+
███╗ ██╗██╗ ██╗██╗ ██╗ ██████╗ ██████╗ █████╗
|
|
27
|
+
████╗ ██║╚██╗ ██╔╝╚██╗██╔╝██╔═══██╗██╔══██╗██╔══██╗
|
|
28
|
+
██╔██╗ ██║ ╚████╔╝ ╚███╔╝ ██║ ██║██████╔╝███████║
|
|
29
|
+
██║╚██╗██║ ╚██╔╝ ██╔██╗ ██║ ██║██╔══██╗██╔══██║
|
|
30
|
+
██║ ╚████║ ██║ ██╔╝ ██╗╚██████╔╝██║ ██║██║ ██║
|
|
31
|
+
╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝
|
|
32
|
+
`;
|
|
33
|
+
console.log(picocolors_1.default.cyan(logo));
|
|
34
|
+
(0, prompts_1.intro)(picocolors_1.default.inverse(' Nyxora Interactive Shell '));
|
|
35
|
+
console.log(picocolors_1.default.gray('Type your message and press Enter. Type "exit" or press Ctrl+C to quit.\n'));
|
|
36
|
+
while (true) {
|
|
37
|
+
const input = await (0, prompts_1.text)({
|
|
38
|
+
message: picocolors_1.default.cyan('You:'),
|
|
39
|
+
placeholder: 'Send a message...',
|
|
40
|
+
});
|
|
41
|
+
if ((0, prompts_1.isCancel)(input) || input.toString().trim().toLowerCase() === 'exit' || input.toString().trim().toLowerCase() === 'quit') {
|
|
42
|
+
(0, prompts_1.cancel)('Chat session ended.');
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
const messageStr = input.toString().trim();
|
|
46
|
+
if (!messageStr)
|
|
47
|
+
continue;
|
|
48
|
+
const s = (0, prompts_1.spinner)();
|
|
49
|
+
s.start('Thinking...');
|
|
50
|
+
try {
|
|
51
|
+
const response = await fetch('http://localhost:3000/api/chat', {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: {
|
|
54
|
+
'Content-Type': 'application/json',
|
|
55
|
+
'x-nyxora-token': token,
|
|
56
|
+
},
|
|
57
|
+
body: JSON.stringify({ message: messageStr, session_id: 'cli-chat' })
|
|
58
|
+
});
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
s.stop(picocolors_1.default.red('API Error.'));
|
|
61
|
+
if (response.status === 401) {
|
|
62
|
+
console.log(picocolors_1.default.red('Unauthorized: Token is invalid. Please restart the daemon.'));
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
console.log(picocolors_1.default.red(`Gateway returned status ${response.status}`));
|
|
67
|
+
}
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const data = await response.json();
|
|
71
|
+
s.stop(picocolors_1.default.green('Nyxora:'));
|
|
72
|
+
let finalReply = data.response || '';
|
|
73
|
+
// Strip <think> tags for clean UI
|
|
74
|
+
finalReply = finalReply.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
|
|
75
|
+
console.log(finalReply + '\n');
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
s.stop(picocolors_1.default.red('Connection failed.'));
|
|
79
|
+
console.log(picocolors_1.default.red(`Is the daemon running? (http://localhost:3000)`));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -156,6 +156,69 @@ async function main() {
|
|
|
156
156
|
process.exit(1);
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
|
+
// Check for chat command
|
|
160
|
+
if (process.argv.includes('chat')) {
|
|
161
|
+
const { chatInteractive } = await Promise.resolve().then(() => __importStar(require('./chat')));
|
|
162
|
+
await chatInteractive();
|
|
163
|
+
process.exit(0);
|
|
164
|
+
}
|
|
165
|
+
// Check for uninstall command
|
|
166
|
+
if (process.argv.includes('uninstall')) {
|
|
167
|
+
console.log(picocolors_1.default.cyan('\n🗑️ Nyxora Uninstallation Wizard'));
|
|
168
|
+
let shouldProceed = process.argv.includes('--force') || process.argv.includes('-y');
|
|
169
|
+
if (!shouldProceed) {
|
|
170
|
+
const proceed = await (0, prompts_1.confirm)({
|
|
171
|
+
message: picocolors_1.default.bgRed(picocolors_1.default.white(' ⚠️ WARNING ')) + picocolors_1.default.yellow(' This will PERMANENTLY WIPE the AI\'s local memory, securely delete your Private Key and Master Key from the OS Keyring, and remove all configuration.\n\nAre you absolutely sure you want to proceed?'),
|
|
172
|
+
});
|
|
173
|
+
if ((0, prompts_1.isCancel)(proceed) || !proceed)
|
|
174
|
+
process.exit(0);
|
|
175
|
+
}
|
|
176
|
+
console.log(picocolors_1.default.gray('\nStarting cleanup process...'));
|
|
177
|
+
// 1. Wipe AI Memory
|
|
178
|
+
try {
|
|
179
|
+
const { Logger } = require('../memory/logger');
|
|
180
|
+
const logger = new Logger();
|
|
181
|
+
logger.clear();
|
|
182
|
+
console.log(picocolors_1.default.green('✅ AI memory wiped successfully.'));
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
console.log(picocolors_1.default.gray('⚠️ Could not clear AI memory (may not exist).'));
|
|
186
|
+
}
|
|
187
|
+
// 2. Delete OS Keyring entries
|
|
188
|
+
try {
|
|
189
|
+
const { Entry } = await Promise.resolve().then(() => __importStar(require('@napi-rs/keyring')));
|
|
190
|
+
const walletEntry = new Entry('nyxora', 'wallet');
|
|
191
|
+
try {
|
|
192
|
+
await walletEntry.deletePassword();
|
|
193
|
+
}
|
|
194
|
+
catch (e) { }
|
|
195
|
+
console.log(picocolors_1.default.green('✅ Wallet key removed from OS Keyring.'));
|
|
196
|
+
const masterEntry = new Entry('nyxora', 'config_master');
|
|
197
|
+
try {
|
|
198
|
+
await masterEntry.deletePassword();
|
|
199
|
+
}
|
|
200
|
+
catch (e) { }
|
|
201
|
+
console.log(picocolors_1.default.green('✅ Master key removed from OS Keyring.'));
|
|
202
|
+
}
|
|
203
|
+
catch (e) {
|
|
204
|
+
console.log(picocolors_1.default.gray('⚠️ Could not access OS Keyring.'));
|
|
205
|
+
}
|
|
206
|
+
// 3. Delete ~/.nyxora directory
|
|
207
|
+
try {
|
|
208
|
+
const targetDir = path_1.default.join(os_1.default.homedir(), '.nyxora');
|
|
209
|
+
if (fs_1.default.existsSync(targetDir)) {
|
|
210
|
+
fs_1.default.rmSync(targetDir, { recursive: true, force: true });
|
|
211
|
+
console.log(picocolors_1.default.green('✅ Configuration directory (~/.nyxora) deleted.'));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
console.log(picocolors_1.default.red(`❌ Failed to delete ~/.nyxora: ${e.message}`));
|
|
216
|
+
}
|
|
217
|
+
console.log(picocolors_1.default.cyan('\n✨ Nyxora data has been completely removed.'));
|
|
218
|
+
console.log(picocolors_1.default.white('To complete the uninstallation, run:'));
|
|
219
|
+
console.log(picocolors_1.default.green(' npm uninstall -g nyxora\n'));
|
|
220
|
+
process.exit(0);
|
|
221
|
+
}
|
|
159
222
|
// 2. Setup boilerplate files if in global mode and they don't exist
|
|
160
223
|
let isFirstBoot = false;
|
|
161
224
|
if (isGlobalMode) {
|