nyxora 26.6.20 → 26.6.22-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.
Files changed (116) hide show
  1. package/README.md +18 -1
  2. package/bin/nyxora.mjs +46 -2
  3. package/dist/packages/core/src/agent/cronManager.js +107 -0
  4. package/dist/packages/core/src/agent/reasoning.js +95 -22
  5. package/dist/packages/core/src/agent/transactionManager.js +2 -2
  6. package/dist/packages/core/src/agent/updateIdentity.js +71 -0
  7. package/dist/packages/core/src/config/parser.js +121 -7
  8. package/dist/packages/core/src/config/paths.js +5 -20
  9. package/dist/packages/core/src/gateway/chat.js +120 -0
  10. package/dist/packages/core/src/gateway/cli.js +82 -19
  11. package/dist/packages/core/src/gateway/server.js +142 -63
  12. package/dist/packages/core/src/gateway/setup.js +39 -22
  13. package/dist/packages/core/src/gateway/telegram.js +43 -0
  14. package/dist/packages/core/src/gateway/tracker.js +58 -0
  15. package/dist/packages/core/src/memory/logger.js +1 -1
  16. package/dist/packages/core/src/system/skills/cancelTask.js +40 -0
  17. package/dist/packages/core/src/system/skills/editFile.js +5 -0
  18. package/dist/packages/core/src/system/skills/scheduleTask.js +39 -0
  19. package/dist/packages/core/src/system/skills/writeFile.js +5 -0
  20. package/dist/packages/core/src/utils/formatter.test.js +40 -0
  21. package/dist/packages/core/src/utils/skillManager.js +91 -0
  22. package/dist/packages/core/src/utils/userWhitelistManager.js +41 -36
  23. package/dist/packages/core/src/web3/aggregator/aggregatorMainnet.js +2 -2
  24. package/dist/packages/core/src/web3/aggregator/defiRouter.js +3 -0
  25. package/dist/packages/core/src/web3/skills/bridgeToken.js +4 -0
  26. package/dist/packages/core/src/web3/skills/checkRegistryStatus.js +13 -0
  27. package/dist/packages/core/src/web3/skills/customTx.js +2 -0
  28. package/dist/packages/core/src/web3/skills/defiLending.js +2 -0
  29. package/dist/packages/core/src/web3/skills/getPrice.js +1 -1
  30. package/dist/packages/core/src/web3/skills/manageCustomTokens.js +18 -32
  31. package/dist/packages/core/src/web3/skills/marketAnalysis.js +3 -1
  32. package/dist/packages/core/src/web3/skills/mintNft.js +2 -0
  33. package/dist/packages/core/src/web3/skills/provideLiquidity.js +2 -0
  34. package/dist/packages/core/src/web3/skills/revokeApprovals.js +2 -0
  35. package/dist/packages/core/src/web3/skills/swapToken.js +4 -2
  36. package/dist/packages/core/src/web3/skills/transfer.js +2 -0
  37. package/dist/packages/core/src/web3/skills/yieldVault.js +2 -0
  38. package/dist/packages/core/src/web3/utils/tokens.js +9 -1
  39. package/dist/packages/policy/src/server.js +1 -1
  40. package/package.json +5 -1
  41. package/packages/core/package.json +5 -1
  42. package/packages/core/src/agent/cronManager.ts +87 -0
  43. package/packages/core/src/agent/reasoning.ts +102 -21
  44. package/packages/core/src/agent/transactionManager.ts +2 -1
  45. package/packages/core/src/agent/updateIdentity.ts +68 -0
  46. package/packages/core/src/config/parser.ts +119 -9
  47. package/packages/core/src/config/paths.ts +5 -23
  48. package/packages/core/src/gateway/chat.ts +124 -0
  49. package/packages/core/src/gateway/cli.ts +73 -10
  50. package/packages/core/src/gateway/server.ts +158 -66
  51. package/packages/core/src/gateway/setup.ts +39 -27
  52. package/packages/core/src/gateway/telegram.ts +49 -0
  53. package/packages/core/src/gateway/tracker.ts +55 -0
  54. package/packages/core/src/memory/logger.ts +1 -1
  55. package/packages/core/src/system/skills/cancelTask.ts +38 -0
  56. package/packages/core/src/system/skills/editFile.ts +7 -0
  57. package/packages/core/src/system/skills/scheduleTask.ts +38 -0
  58. package/packages/core/src/system/skills/writeFile.ts +7 -0
  59. package/packages/core/src/utils/formatter.test.ts +41 -0
  60. package/packages/core/src/utils/skillManager.ts +98 -0
  61. package/packages/core/src/utils/userWhitelistManager.ts +48 -39
  62. package/packages/core/src/web3/aggregator/aggregatorMainnet.ts +2 -2
  63. package/packages/core/src/web3/aggregator/defiRouter.ts +4 -0
  64. package/packages/core/src/web3/skills/bridgeToken.ts +3 -0
  65. package/packages/core/src/web3/skills/checkRegistryStatus.ts +13 -0
  66. package/packages/core/src/web3/skills/customTx.ts +1 -0
  67. package/packages/core/src/web3/skills/defiLending.ts +1 -0
  68. package/packages/core/src/web3/skills/getPrice.ts +1 -1
  69. package/packages/core/src/web3/skills/manageCustomTokens.ts +18 -29
  70. package/packages/core/src/web3/skills/marketAnalysis.ts +2 -1
  71. package/packages/core/src/web3/skills/mintNft.ts +1 -0
  72. package/packages/core/src/web3/skills/provideLiquidity.ts +1 -0
  73. package/packages/core/src/web3/skills/revokeApprovals.ts +1 -0
  74. package/packages/core/src/web3/skills/swapToken.ts +3 -2
  75. package/packages/core/src/web3/skills/transfer.ts +1 -0
  76. package/packages/core/src/web3/skills/yieldVault.ts +1 -0
  77. package/packages/core/src/web3/utils/tokens.ts +9 -1
  78. package/packages/dashboard/dist/assets/index-CjZWf1Ei.css +1 -0
  79. package/packages/dashboard/dist/assets/index-CmWZofn_.js +16 -0
  80. package/packages/dashboard/dist/index.html +2 -2
  81. package/packages/dashboard/dist/routers/0x.png +0 -0
  82. package/packages/dashboard/dist/routers/1inch.png +0 -0
  83. package/packages/dashboard/dist/routers/cmc.png +0 -0
  84. package/packages/dashboard/dist/routers/kyberswap.png +0 -0
  85. package/packages/dashboard/dist/routers/lifi.png +0 -0
  86. package/packages/dashboard/dist/routers/openocean.png +0 -0
  87. package/packages/dashboard/dist/routers/relay.png +0 -0
  88. package/packages/dashboard/dist/routers/zerion.png +0 -0
  89. package/packages/dashboard/package.json +1 -1
  90. package/packages/mcp-server/package.json +1 -1
  91. package/packages/policy/package.json +1 -1
  92. package/packages/policy/src/server.ts +1 -1
  93. package/packages/signer/package.json +1 -1
  94. package/dist/packages/core/src/agent/limitOrderManager.js +0 -124
  95. package/dist/packages/core/src/system/pluginManager.js +0 -91
  96. package/dist/packages/core/src/system/skills/installSkill.js +0 -52
  97. package/dist/packages/core/src/test-all-routers.js +0 -81
  98. package/dist/packages/core/src/test-router.js +0 -38
  99. package/dist/packages/core/src/web3/skills/autonomousDefi.js +0 -191
  100. package/dist/packages/core/src/web3/skills/createWallet.js +0 -34
  101. package/dist/packages/core/src/web3/skills/limitOrder.js +0 -106
  102. package/dist/packages/core/src/web3/utils/protocolRegistry.js +0 -46
  103. package/dist/tsconfig.tsbuildinfo +0 -1
  104. package/packages/core/src/__tests__/reasoning.test.ts +0 -81
  105. package/packages/core/src/__tests__/tokens.test.ts +0 -55
  106. package/packages/core/src/__tests__/web3.test.ts +0 -50
  107. package/packages/core/src/agent/reasoning.d.ts.map +0 -1
  108. package/packages/core/src/config/parser.d.ts.map +0 -1
  109. package/packages/core/src/gateway/cli.d.ts.map +0 -1
  110. package/packages/core/src/memory/logger.d.ts.map +0 -1
  111. package/packages/core/src/test-all-routers.ts +0 -59
  112. package/packages/core/src/test-router.ts +0 -49
  113. package/packages/core/src/web3/config.d.ts.map +0 -1
  114. package/packages/core/src/web3/skills/getBalance.d.ts.map +0 -1
  115. package/packages/dashboard/dist/assets/index-CQNHWZtN.css +0 -1
  116. package/packages/dashboard/dist/assets/index-O2m42q4p.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 (Multi-Sig Safe):** `0x490717E50D6434C348AA0D2bD5fe682392823708`
192
+ - **EVM :** `0x490717E50D6434C348AA0D2bD5fe682392823708`
176
193
 
177
194
  ---
178
195
  **License:** MIT License
package/bin/nyxora.mjs CHANGED
@@ -86,18 +86,30 @@ async function start() {
86
86
  }
87
87
  }
88
88
 
89
- async function stop() {
89
+ async function stop(preserveTracker = false) {
90
90
  const pid = await getDaemonPid();
91
91
  if (pid) {
92
92
  console.log(`Stopping Nyxora daemon (PID: ${pid})...`);
93
93
  try {
94
94
  process.kill(-pid, 'SIGTERM');
95
+
96
+ // Wait for process to exit to avoid race condition with flushState
97
+ let attempts = 0;
98
+ while (isDaemonRunning(pid.toString()) && attempts < 20) {
99
+ await new Promise(r => setTimeout(r, 100));
100
+ attempts++;
101
+ }
102
+
95
103
  console.log('Nyxora stopped gracefully.');
96
104
  } catch (e) {
97
105
  console.error('Failed to kill process:', e.message);
98
106
  }
99
107
  try {
100
108
  fs.unlinkSync(pidFile);
109
+ if (!preserveTracker) {
110
+ const trackerFile = path.join(appDir, 'run', 'tracker.json');
111
+ if (fs.existsSync(trackerFile)) fs.unlinkSync(trackerFile);
112
+ }
101
113
  } catch(e) {}
102
114
  } else {
103
115
  console.log('Nyxora is not running.');
@@ -105,7 +117,7 @@ async function stop() {
105
117
  }
106
118
 
107
119
  async function restart() {
108
- await stop();
120
+ await stop(true);
109
121
  setTimeout(start, 1000);
110
122
  }
111
123
 
@@ -267,6 +279,34 @@ async function wallet(cliArgs) {
267
279
  await new Promise(resolve => child.on('close', resolve));
268
280
  }
269
281
 
282
+ async function uninstall(cliArgs) {
283
+ const compiledCli = path.join(projectRoot, 'dist', 'packages/core/src/gateway/cli.js');
284
+ const useCompiled = fs.existsSync(compiledCli);
285
+ const cmd = useCompiled ? 'node' : 'npx';
286
+ const args = useCompiled ? [compiledCli, 'uninstall', ...cliArgs] : ['ts-node', '-T', 'packages/core/src/gateway/cli.ts', 'uninstall', ...cliArgs];
287
+ const child = spawn(cmd, args, {
288
+ cwd: projectRoot,
289
+ stdio: 'inherit',
290
+ env: { ...process.env, TS_NODE_CACHE: 'false' }
291
+ });
292
+
293
+ await new Promise(resolve => child.on('close', resolve));
294
+ }
295
+
296
+ async function chat(cliArgs) {
297
+ const compiledCli = path.join(projectRoot, 'dist', 'packages/core/src/gateway/cli.js');
298
+ const useCompiled = fs.existsSync(compiledCli);
299
+ const cmd = useCompiled ? 'node' : 'npx';
300
+ const args = useCompiled ? [compiledCli, 'chat', ...cliArgs] : ['ts-node', '-T', 'packages/core/src/gateway/cli.ts', 'chat', ...cliArgs];
301
+ const child = spawn(cmd, args, {
302
+ cwd: projectRoot,
303
+ stdio: 'inherit',
304
+ env: { ...process.env, TS_NODE_CACHE: 'false' }
305
+ });
306
+
307
+ await new Promise(resolve => child.on('close', resolve));
308
+ }
309
+
270
310
  async function runDoctor() {
271
311
  const compiledCli = path.join(projectRoot, 'dist', 'packages/core/src/gateway/doctor.js');
272
312
  const useCompiled = fs.existsSync(compiledCli);
@@ -317,6 +357,8 @@ async function main() {
317
357
  case 'clear': await clearMemory(process.argv.slice(3)); break;
318
358
  case 'set-key': await setKey(process.argv.slice(3)); break;
319
359
  case 'wallet': await wallet(process.argv.slice(3)); break;
360
+ case 'chat': await chat(process.argv.slice(3)); break;
361
+ case 'uninstall': await uninstall(process.argv.slice(3)); break;
320
362
  case 'start': await start(); break;
321
363
  case 'stop': await stop(); break;
322
364
  case 'restart': await restart(); break;
@@ -341,6 +383,7 @@ Commands:
341
383
  start Start the Nyxora background daemon
342
384
  stop Stop the running daemon
343
385
  restart Restart the daemon
386
+ chat Chat interactively with the AI in terminal
344
387
  setup Run the interactive Setup Wizard
345
388
  dashboard Open the dashboard in your browser
346
389
  unlock Unlock an inactive dashboard session
@@ -350,6 +393,7 @@ Commands:
350
393
  autostart Enable/disable autostart on boot (usage: nyxora autostart enable)
351
394
  set-key Securely save API Key (usage: nyxora set-key <provider> <key>)
352
395
  wallet Manage your Web3 Wallet (usage: nyxora wallet update)
396
+ uninstall Wipe AI memory, securely delete keys, and remove configuration
353
397
 
354
398
  Options:
355
399
  -v, --version Show current version
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.cronManager = void 0;
40
+ const cron = __importStar(require("node-cron"));
41
+ const parser_1 = require("../config/parser");
42
+ const telegram_1 = require("../gateway/telegram");
43
+ const crypto_1 = require("crypto");
44
+ const picocolors_1 = __importDefault(require("picocolors"));
45
+ class CronManager {
46
+ jobs = new Map();
47
+ addJob(expression, prompt) {
48
+ const id = (0, crypto_1.randomUUID)();
49
+ // Validate expression
50
+ if (!cron.validate(expression)) {
51
+ throw new Error(`Invalid cron expression: ${expression}`);
52
+ }
53
+ const task = cron.schedule(expression, async () => {
54
+ console.log(picocolors_1.default.cyan(`[Cron] Executing job ${id}: "${prompt}"`));
55
+ try {
56
+ // Dynamically import processUserInput to avoid circular dependencies
57
+ const { processUserInput } = await Promise.resolve().then(() => __importStar(require('./reasoning')));
58
+ // Execute the prompt as a background system task
59
+ const response = await processUserInput(prompt, 'system', undefined, `cron-${id}`);
60
+ // Push notification to Telegram if configured
61
+ const config = (0, parser_1.loadConfig)();
62
+ if (config.integrations?.telegram?.enabled && config.integrations?.telegram?.authorized_chat_id) {
63
+ const message = `🤖 *AI Scheduled Report*\n\n${response}`;
64
+ await (0, telegram_1.sendPushNotification)(config.integrations.telegram.authorized_chat_id, message);
65
+ }
66
+ }
67
+ catch (err) {
68
+ console.error(picocolors_1.default.red(`[Cron] Failed to execute job ${id}:`), err);
69
+ const config = (0, parser_1.loadConfig)();
70
+ if (config.integrations?.telegram?.enabled && config.integrations?.telegram?.authorized_chat_id) {
71
+ await (0, telegram_1.sendPushNotification)(config.integrations.telegram.authorized_chat_id, `⚠️ *Cron Job Error*\n\nPrompt: ${prompt}\nError: ${err.message}`);
72
+ }
73
+ }
74
+ });
75
+ this.jobs.set(id, {
76
+ id,
77
+ expression,
78
+ prompt,
79
+ task,
80
+ createdAt: Date.now()
81
+ });
82
+ console.log(picocolors_1.default.green(`[Cron] Scheduled new job ${id} with expression '${expression}'`));
83
+ return id;
84
+ }
85
+ removeJob(id) {
86
+ const job = this.jobs.get(id);
87
+ if (job) {
88
+ job.task.stop();
89
+ this.jobs.delete(id);
90
+ console.log(picocolors_1.default.yellow(`[Cron] Removed job ${id}`));
91
+ return true;
92
+ }
93
+ return false;
94
+ }
95
+ getJobs() {
96
+ return Array.from(this.jobs.values()).map(job => ({
97
+ id: job.id,
98
+ expression: job.expression,
99
+ prompt: job.prompt,
100
+ createdAt: job.createdAt
101
+ }));
102
+ }
103
+ getActiveJobsCount() {
104
+ return this.jobs.size;
105
+ }
106
+ }
107
+ exports.cronManager = new CronManager();
@@ -34,6 +34,7 @@ const provideLiquidity_1 = require("../web3/skills/provideLiquidity");
34
34
  const getTxHistory_1 = require("../web3/skills/getTxHistory");
35
35
  const createLimitOrder_1 = require("../web3/skills/createLimitOrder");
36
36
  const updateProfile_1 = require("./updateProfile");
37
+ const updateIdentity_1 = require("./updateIdentity");
37
38
  const updateSecurityPolicy_1 = require("../system/skills/updateSecurityPolicy");
38
39
  const analyzeDocument_1 = require("../system/skills/analyzeDocument");
39
40
  const readFile_1 = require("../system/skills/readFile");
@@ -48,6 +49,8 @@ const xManager_1 = require("../system/skills/xManager");
48
49
  const notionWorkspace_1 = require("../system/skills/notionWorkspace");
49
50
  const audioTranscribe_1 = require("../system/skills/audioTranscribe");
50
51
  const summarizeText_1 = require("../system/skills/summarizeText");
52
+ const scheduleTask_1 = require("../system/skills/scheduleTask");
53
+ const cancelTask_1 = require("../system/skills/cancelTask");
51
54
  const googleWorkspace_1 = require("../system/skills/googleWorkspace");
52
55
  const paths_1 = require("../config/paths");
53
56
  const picocolors_1 = __importDefault(require("picocolors"));
@@ -143,35 +146,62 @@ CRITICAL RULE 11: ADAPTIVE RESPONSE RULE. You must process Web3 data (portfolio,
143
146
  CRITICAL RULE 13: WALLET CONTEXT CACHING. Portfolio data in chat history is potentially stale. Do not use cached data for transactional planning; refresh the balance via tools first.
144
147
  CRITICAL RULE 14: TRANSACTION EXECUTION. For ALL state-changing transactions (swap, bridge, transfer, stake), do NOT ask for verbal confirmation. Execute the tool IMMEDIATELY. The tool itself will trigger a secure popup in the user's dashboard UI for final approval.
145
148
  CRITICAL RULE 17: MINIMIZE UNNECESSARY TOOL CALLS. Do not call tools if the answer exists in recent verified context and freshness is not strictly required. Use history to save latency.
149
+ CRITICAL RULE 19: GET_PRICE USAGE. Use get_price ONLY when the user explicitly asks for a simple price check (e.g. 'harga', 'price'). Do NOT use this for 'analysis', 'market analysis', or 'analisis pasar'.
146
150
 
147
151
  [ANTI-HALLUCINATION PROTOCOL]
148
152
  CRITICAL RULE 6: NETWORK SAFETY VALIDATION. If a request implies cross-chain or mainnet/testnet mixing, or the token symbol is ambiguous (USDC vs USDC.e), YOU MUST NOT GUESS. Ask for confirmation.
149
153
  CRITICAL RULE 7: TOOL CONFIDENCE & HALUCINATION PREVENTION. NEVER fabricate blockchain data. If a tool fails or data is missing, state it explicitly. Do not estimate balances, prices, APY, or gas.
154
+ CRITICAL RULE 18: AMOUNT PRECISION. When displaying crypto amounts, use exactly 6 decimal places for precision, or round to 2 decimals only if the value is significantly large (>$10,000). Never abbreviate unless the number is >$1,000,000.
150
155
  CRITICAL RULE 9: DEFI CONFIGURATION FALLBACK. If a tool fails due to Rate Limits, Unauthorized, or Missing API Keys, instruct the user to visit the "DeFi Configuration 🔑" menu in the dashboard.
151
156
  CRITICAL RULE 12: SMART SLIPPAGE AWARENESS. For low-liquidity assets, warn the user that default slippage might not be enough. NEVER invent specific slippage percentage numbers.
152
157
  CRITICAL RULE 16: CAPABILITY HONESTY. NEVER claim a capability not available through installed tools. If asked for an unsupported action, state honestly that the skill is missing.
153
- CRITICAL RULE 19: MARKET CONFIDENCE SCORE. When analyzing market data, token security, or preparing trades, you MUST explicitly declare a 'Confidence Score (0-100%)' INSIDE your <think> block. If your score is below 40%, you must firmly WARN the user and advise against the trade in your final response.`;
154
- // Read IDENTITY.md for core AI persona
158
+ CRITICAL RULE 19: MARKET CONFIDENCE SCORE. When analyzing market data, token security, or preparing trades, you MUST explicitly declare a 'Confidence Score (0-100%)' INSIDE your <think> block. If your score is below 40%, you must firmly WARN the user and advise against the trade in your final response.
159
+ CRITICAL RULE 20: CRON JOBS VS LIMIT ORDERS. STRICT RULE: Do NOT use schedule_task for price-based trading triggers or buying/selling at a specific price level. Use create_limit_order. STRICT RULE: Do NOT use create_limit_order for time-based recurring tasks (e.g. 'every 5 minutes', 'every Monday'). Use schedule_task.
160
+ CRITICAL RULE 21: CONFIGURATION SECURITY. You are STRICTLY FORBIDDEN from modifying config.yaml, rpc_key.yaml, or policy.yaml using OS skills or terminal commands (like sed, echo, nano). If you need to change your name, use the update_identity tool.`;
161
+ const identityMdPath = (0, paths_1.getPath)('IDENTITY.md');
162
+ const userMdPath = (0, paths_1.getPath)('user.md');
163
+ let isFirstTime = false;
155
164
  try {
156
- const identityMdPath = (0, paths_1.getPath)('IDENTITY.md');
157
- if (fs_1.default.existsSync(identityMdPath)) {
158
- const identityInstructions = fs_1.default.readFileSync(identityMdPath, 'utf8');
159
- basePrompt += `\n\n--- CORE IDENTITY & PERSONA ---\n${identityInstructions}`;
160
- }
165
+ const identityContent = fs_1.default.existsSync(identityMdPath) ? fs_1.default.readFileSync(identityMdPath, 'utf8').trim() : '';
166
+ const userContent = fs_1.default.existsSync(userMdPath) ? fs_1.default.readFileSync(userMdPath, 'utf8').trim() : '';
167
+ // Check if files are empty or contain the default installation text
168
+ const isIdentityDefault = !identityContent || identityContent.includes('You are a Web3 AI assistant named Nyxora.');
169
+ const isUserDefault = !userContent || userContent.includes('Write custom instructions, special rules, user profiles');
170
+ isFirstTime = isIdentityDefault && isUserDefault;
161
171
  }
162
- catch (error) {
163
- console.error('Failed to read IDENTITY.md:', error);
172
+ catch (e) {
173
+ isFirstTime = true;
164
174
  }
165
- // Read user.md for custom instructions
166
- try {
167
- const userMdPath = (0, paths_1.getPath)('user.md');
168
- if (fs_1.default.existsSync(userMdPath)) {
169
- const customInstructions = fs_1.default.readFileSync(userMdPath, 'utf8');
170
- basePrompt += `\n\n--- CUSTOM USER INSTRUCTIONS ---\n${customInstructions}`;
171
- }
175
+ if (isFirstTime) {
176
+ basePrompt += `\n\n[ONBOARDING MODE]
177
+ This is your VERY FIRST interaction with the user. You MUST warmly welcome them to Nyxora and ask for 4 things to initialize your setup:
178
+ 1. Their Name
179
+ 2. What they want to name YOU (the AI Agent)
180
+ 3. Their Hobbies or Job (so you can tailor your conversation context)
181
+ 4. Your Persona/Character (e.g., professional, sarcastic, JARVIS, anime waifu)
182
+ Do NOT perform any web3 tasks or generic answers until they provide all 4 details. Once they answer, use 'update_profile' to save their name and hobbies/job to user.md, and use 'update_identity' (making sure to provide the 'agentName' parameter!) to save your new name and persona to IDENTITY.md.`;
172
183
  }
173
- catch (error) {
174
- console.error('Failed to read user.md:', error);
184
+ else {
185
+ // Read IDENTITY.md for core AI persona
186
+ try {
187
+ if (fs_1.default.existsSync(identityMdPath)) {
188
+ const identityInstructions = fs_1.default.readFileSync(identityMdPath, 'utf8');
189
+ basePrompt += `\n\n--- CORE IDENTITY & PERSONA ---\n${identityInstructions}`;
190
+ }
191
+ }
192
+ catch (error) {
193
+ console.error('Failed to read IDENTITY.md:', error);
194
+ }
195
+ // Read user.md for custom instructions
196
+ try {
197
+ if (fs_1.default.existsSync(userMdPath)) {
198
+ const customInstructions = fs_1.default.readFileSync(userMdPath, 'utf8');
199
+ basePrompt += `\n\n--- CUSTOM USER INSTRUCTIONS ---\n${customInstructions}`;
200
+ }
201
+ }
202
+ catch (error) {
203
+ console.error('Failed to read user.md:', error);
204
+ }
175
205
  }
176
206
  // Read policy.yaml for NLP security constraints
177
207
  try {
@@ -226,7 +256,7 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
226
256
  exports.logger.addEntry({ role, content: input }, sessionId);
227
257
  const history = exports.logger.getHistory(sessionId);
228
258
  // Format messages for OpenAI
229
- const messages = [
259
+ let messages = [
230
260
  { role: 'system', content: getSystemPrompt() },
231
261
  ...history
232
262
  .filter(m => !(m.role === 'tool' && !m.tool_call_id))
@@ -244,6 +274,10 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
244
274
  return msg;
245
275
  })
246
276
  ];
277
+ // Remove orphaned tool responses (truncated by the 40-message limit) at the start of the history window
278
+ while (messages.length > 1 && messages[1].role === 'tool') {
279
+ messages.splice(1, 1);
280
+ }
247
281
  try {
248
282
  const lowerInput = input.toLowerCase();
249
283
  const hasWeb3Keyword = /swap|transfer|price|token|crypto|bridge|wallet|balance|portfolio|buy|sell|send|receive|address|market|limit|mint|nft/i.test(lowerInput);
@@ -252,7 +286,7 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
252
286
  if ((0, skillManager_1.isSkillActive)('web3')) {
253
287
  tools.push(getBalance_1.getBalanceToolDefinition, transfer_1.transferToolDefinition, getPrice_1.getPriceToolDefinition, swapToken_1.swapTokenToolDefinition, bridgeToken_1.bridgeTokenToolDefinition, mintNft_1.mintNftToolDefinition, customTx_1.customTxToolDefinition, checkSecurity_1.checkSecurityToolDefinition, marketAnalysis_1.marketAnalysisToolDefinition, createMarketWatchAgent_1.createMarketWatchAgentToolDefinition, checkPortfolio_1.checkPortfolioToolDefinition, checkAddress_1.checkAddressToolDefinition, getMyAddress_1.getMyAddressToolDefinition, manageCustomTokens_1.manageCustomTokensDefinition, revokeApprovals_1.revokeApprovalToolDefinition, defiLending_1.aaveSupplyToolDefinition, yieldVault_1.vaultDepositToolDefinition, provideLiquidity_1.provideLiquidityToolDefinition, getTxHistory_1.getTxHistoryToolDefinition, createLimitOrder_1.createLimitOrderToolDefinition);
254
288
  }
255
- const SYSTEM_TOOLS = [updateProfile_1.updateProfileToolDefinition, updateSecurityPolicy_1.updateSecurityPolicyToolDefinition, analyzeDocument_1.analyzeDocumentToolDefinition, readFile_1.readLocalFileToolDefinition, writeFile_1.writeLocalFileToolDefinition, generateExcel_1.generateExcelToolDefinition, executeShell_1.runTerminalCommandToolDefinition, browseWeb_1.browseWebsiteToolDefinition, searchWeb_1.searchWebToolDefinition, editFile_1.editLocalFileToolDefinition, gitManager_1.gitManagerToolDefinition, xManager_1.xManagerToolDefinition, notionWorkspace_1.notionWorkspaceToolDefinition, audioTranscribe_1.audioTranscribeToolDefinition, summarizeText_1.summarizeTextToolDefinition];
289
+ const SYSTEM_TOOLS = [updateProfile_1.updateProfileToolDefinition, updateIdentity_1.updateIdentityToolDefinition, updateSecurityPolicy_1.updateSecurityPolicyToolDefinition, analyzeDocument_1.analyzeDocumentToolDefinition, readFile_1.readLocalFileToolDefinition, writeFile_1.writeLocalFileToolDefinition, generateExcel_1.generateExcelToolDefinition, executeShell_1.runTerminalCommandToolDefinition, browseWeb_1.browseWebsiteToolDefinition, searchWeb_1.searchWebToolDefinition, editFile_1.editLocalFileToolDefinition, gitManager_1.gitManagerToolDefinition, xManager_1.xManagerToolDefinition, notionWorkspace_1.notionWorkspaceToolDefinition, audioTranscribe_1.audioTranscribeToolDefinition, summarizeText_1.summarizeTextToolDefinition, scheduleTask_1.scheduleTaskDefinition, cancelTask_1.cancelTaskDefinition];
256
290
  const GOOGLE_TOOLS = [googleWorkspace_1.readGmailInboxToolDefinition, googleWorkspace_1.listCalendarEventsToolDefinition, googleWorkspace_1.appendRowToSheetsToolDefinition, googleWorkspace_1.readGoogleDocsToolDefinition, googleWorkspace_1.readGoogleFormResponsesToolDefinition];
257
291
  let activeTools = [];
258
292
  if (hasGoogleKeyword && !hasWeb3Keyword) {
@@ -315,6 +349,16 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
315
349
  }, sessionId);
316
350
  continue;
317
351
  }
352
+ if (!(0, skillManager_1.isSkillActive)(toolName)) {
353
+ console.warn(picocolors_1.default.red(`[Security] Blocked illegal execution of disabled skill: ${toolName}`));
354
+ result = `[System Error] Access denied: Skill '${toolName}' is currently disabled by the user.`;
355
+ exports.logger.addEntry({
356
+ role: "tool",
357
+ tool_call_id: toolCall.id,
358
+ content: result
359
+ }, sessionId);
360
+ continue;
361
+ }
318
362
  try {
319
363
  switch (toolName) {
320
364
  case 'get_balance': {
@@ -402,6 +446,10 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
402
446
  result = (0, updateProfile_1.updateProfile)(args.content, args.mode);
403
447
  break;
404
448
  }
449
+ case 'update_identity': {
450
+ result = (0, updateIdentity_1.updateIdentity)(args.content, args.mode);
451
+ break;
452
+ }
405
453
  case 'update_security_policy': {
406
454
  result = await (0, updateSecurityPolicy_1.updateSecurityPolicy)(args.policy, args.action || 'add');
407
455
  break;
@@ -458,6 +506,14 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
458
506
  result = await (0, searchWeb_1.searchWeb)(args.query, args.depth);
459
507
  break;
460
508
  }
509
+ case 'schedule_task': {
510
+ result = await (0, scheduleTask_1.executeScheduleTask)(args);
511
+ break;
512
+ }
513
+ case 'cancel_task': {
514
+ result = await (0, cancelTask_1.executeCancelTask)(args);
515
+ break;
516
+ }
461
517
  case 'read_gmail_inbox': {
462
518
  result = await (0, googleWorkspace_1.readGmailInbox)(args.maxResults);
463
519
  break;
@@ -541,11 +597,28 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
541
597
  tracker_1.Tracker.addTokens(secondResponse.usage.total_tokens, config.llm.provider);
542
598
  }
543
599
  tracker_1.Tracker.addEvent('llm.final_response', { provider: config.llm.provider });
544
- const finalContent = secondResponse.choices[0].message.content || "";
600
+ let finalContent = secondResponse.choices[0].message.content || "";
601
+ // Clean up orphaned <think> blocks that forgot to output </think>
602
+ finalContent = finalContent.replace(/<thought>[\s\S]*?<\/thought>\n?/gi, '');
603
+ finalContent = finalContent.replace(/<think>[\s\S]*?<\/think>\n?/gi, '');
604
+ if (finalContent.includes('<think>')) {
605
+ finalContent = finalContent.replace(/<think>[\s\S]*?\n\n/i, '');
606
+ finalContent = finalContent.replace(/<think>[\s\S]*$/i, '');
607
+ }
608
+ finalContent = finalContent.trim();
545
609
  exports.logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
546
610
  return finalContent;
547
611
  }
548
- return responseMessage.content || "No response generated.";
612
+ let finalContent = responseMessage.content || "No response generated.";
613
+ // Clean up orphaned <think> blocks that forgot to output </think>
614
+ finalContent = finalContent.replace(/<thought>[\s\S]*?<\/thought>\n?/gi, '');
615
+ finalContent = finalContent.replace(/<think>[\s\S]*?<\/think>\n?/gi, '');
616
+ if (finalContent.includes('<think>')) {
617
+ finalContent = finalContent.replace(/<think>[\s\S]*?\n\n/i, '');
618
+ finalContent = finalContent.replace(/<think>[\s\S]*$/i, '');
619
+ }
620
+ finalContent = finalContent.trim();
621
+ return finalContent;
549
622
  }
550
623
  catch (error) {
551
624
  console.error("LLM Error:", error);
@@ -6,13 +6,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.txManager = void 0;
7
7
  const crypto_1 = __importDefault(require("crypto"));
8
8
  const fs_1 = __importDefault(require("fs"));
9
- const path_1 = __importDefault(require("path"));
9
+ const paths_1 = require("../config/paths");
10
10
  class TransactionManager {
11
11
  transactions = new Map();
12
12
  withdrawals = new Map();
13
13
  dbPath;
14
14
  constructor() {
15
- this.dbPath = path_1.default.join(process.cwd(), '.nyxora_withdrawals.json');
15
+ this.dbPath = (0, paths_1.getPath)('.nyxora_withdrawals.json');
16
16
  this.loadWithdrawals();
17
17
  }
18
18
  loadWithdrawals() {
@@ -0,0 +1,71 @@
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.updateIdentityToolDefinition = void 0;
7
+ exports.updateIdentity = updateIdentity;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const paths_1 = require("../config/paths");
10
+ const parser_1 = require("../config/parser");
11
+ function updateIdentity(content, mode, agentName) {
12
+ try {
13
+ const identityMdPath = (0, paths_1.getPath)('IDENTITY.md');
14
+ if (mode === 'replace') {
15
+ fs_1.default.writeFileSync(identityMdPath, content, 'utf8');
16
+ let msg = "Identity replaced successfully. New IDENTITY.md has been saved.";
17
+ if (agentName) {
18
+ const config = (0, parser_1.loadConfig)();
19
+ config.agent.name = agentName;
20
+ (0, parser_1.saveConfig)(config);
21
+ msg += ` Agent Name updated to '${agentName}' in config.`;
22
+ }
23
+ return msg;
24
+ }
25
+ else {
26
+ let existingContent = "";
27
+ if (fs_1.default.existsSync(identityMdPath)) {
28
+ existingContent = fs_1.default.readFileSync(identityMdPath, 'utf8');
29
+ }
30
+ const newContent = existingContent + "\n" + content;
31
+ fs_1.default.writeFileSync(identityMdPath, newContent, 'utf8');
32
+ let msg = "Identity appended successfully. New instructions added to IDENTITY.md.";
33
+ if (agentName) {
34
+ const config = (0, parser_1.loadConfig)();
35
+ config.agent.name = agentName;
36
+ (0, parser_1.saveConfig)(config);
37
+ msg += ` Agent Name updated to '${agentName}' in config.`;
38
+ }
39
+ return msg;
40
+ }
41
+ }
42
+ catch (error) {
43
+ return `Failed to update identity: ${error.message}`;
44
+ }
45
+ }
46
+ exports.updateIdentityToolDefinition = {
47
+ type: "function",
48
+ function: {
49
+ name: "update_identity",
50
+ description: "Updates or rewrites the IDENTITY.md file. Use this when the user sets or changes your AI name, persona, or core character instructions.",
51
+ parameters: {
52
+ type: "object",
53
+ properties: {
54
+ content: {
55
+ type: "string",
56
+ description: "The content to write or append to IDENTITY.md",
57
+ },
58
+ mode: {
59
+ type: "string",
60
+ enum: ["append", "replace"],
61
+ description: "Whether to append the content to the existing file or replace the entire file.",
62
+ },
63
+ agentName: {
64
+ type: "string",
65
+ description: "The short display name of the AI agent (e.g. Hinata, Nyxora). MUST be provided if the user assigns you a new name.",
66
+ }
67
+ },
68
+ required: ["content", "mode"],
69
+ },
70
+ },
71
+ };