nyxora 26.6.8-2 → 26.6.10-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/CHANGELOG.md +31 -1
- package/README.md +16 -4
- package/SECURITY.md +13 -3
- package/bin/nyxora.mjs +40 -2
- package/dist/packages/core/src/agent/reasoning.js +57 -14
- package/dist/packages/core/src/agent/transactionManager.js +2 -0
- package/dist/packages/core/src/gateway/server.js +119 -6
- package/dist/packages/core/src/gateway/setup.js +3 -0
- package/dist/packages/core/src/memory/episodic.js +78 -0
- package/dist/packages/core/src/memory/logger.js +15 -3
- package/dist/packages/core/src/memory/promotionEngine.js +67 -0
- package/dist/packages/core/src/memory/reflection.js +97 -0
- package/dist/packages/core/src/memory/validator.js +66 -0
- package/dist/packages/core/src/system/pluginManager.js +2 -1
- package/dist/packages/core/src/system/skills/generateExcel.js +88 -0
- package/dist/packages/core/src/system/skills/installSkill.js +2 -1
- package/dist/packages/core/src/utils/state.js +22 -4
- package/dist/packages/core/src/web3/config.js +11 -1
- package/dist/packages/core/src/web3/skills/bridgeToken.js +30 -2
- package/dist/packages/core/src/web3/skills/checkRegistryStatus.js +79 -0
- package/dist/packages/core/src/web3/skills/checkSecurity.js +2 -0
- package/dist/packages/core/src/web3/skills/customTx.js +1 -1
- package/dist/packages/core/src/web3/skills/defiLending.js +121 -0
- package/dist/packages/core/src/web3/skills/getTxHistory.js +112 -0
- package/dist/packages/core/src/web3/skills/mintNft.js +1 -1
- package/dist/packages/core/src/web3/skills/provideLiquidity.js +160 -0
- package/dist/packages/core/src/web3/skills/revokeApprovals.js +154 -0
- package/dist/packages/core/src/web3/skills/swapToken.js +2 -2
- package/dist/packages/core/src/web3/skills/transfer.js +21 -1
- package/dist/packages/core/src/web3/skills/yieldVault.js +119 -0
- package/dist/packages/core/src/web3/utils/tokens.js +6 -0
- package/dist/packages/policy/src/server.js +14 -4
- package/package.json +2 -1
- package/packages/core/package.json +3 -1
- package/packages/core/src/agent/reasoning.ts +103 -15
- package/packages/core/src/agent/transactionManager.ts +4 -1
- package/packages/core/src/config/parser.ts +1 -0
- package/packages/core/src/gateway/server.ts +134 -8
- package/packages/core/src/gateway/setup.ts +3 -0
- package/packages/core/src/memory/episodic.ts +92 -0
- package/packages/core/src/memory/logger.ts +15 -2
- package/packages/core/src/memory/promotionEngine.ts +69 -0
- package/packages/core/src/memory/reflection.ts +99 -0
- package/packages/core/src/memory/validator.ts +70 -0
- package/packages/core/src/system/pluginManager.ts +2 -1
- package/packages/core/src/system/skills/generateExcel.ts +54 -0
- package/packages/core/src/system/skills/installSkill.ts +2 -2
- package/packages/core/src/utils/state.ts +22 -7
- package/packages/core/src/web3/config.ts +10 -2
- package/packages/core/src/web3/skills/bridgeToken.ts +29 -3
- package/packages/core/src/web3/skills/checkRegistryStatus.ts +85 -0
- package/packages/core/src/web3/skills/checkSecurity.ts +2 -0
- package/packages/core/src/web3/skills/customTx.ts +1 -1
- package/packages/core/src/web3/skills/defiLending.ts +128 -0
- package/packages/core/src/web3/skills/getTxHistory.ts +121 -0
- package/packages/core/src/web3/skills/mintNft.ts +1 -1
- package/packages/core/src/web3/skills/provideLiquidity.ts +183 -0
- package/packages/core/src/web3/skills/revokeApprovals.ts +124 -0
- package/packages/core/src/web3/skills/swapToken.ts +2 -2
- package/packages/core/src/web3/skills/transfer.ts +22 -2
- package/packages/core/src/web3/skills/yieldVault.ts +124 -0
- package/packages/core/src/web3/utils/tokens.ts +6 -0
- package/packages/dashboard/dist/assets/index-W77_dgcr.js +361 -0
- package/packages/dashboard/dist/index.html +1 -1
- package/packages/dashboard/package.json +1 -1
- package/packages/mcp-server/package.json +1 -1
- package/packages/policy/package.json +1 -1
- package/packages/policy/src/server.ts +14 -3
- package/packages/registry-contract/artifacts/@openzeppelin/contracts/access/Ownable.sol/Ownable.dbg.json +4 -0
- package/packages/registry-contract/artifacts/@openzeppelin/contracts/access/Ownable.sol/Ownable.json +85 -0
- package/packages/registry-contract/artifacts/@openzeppelin/contracts/utils/Context.sol/Context.dbg.json +4 -0
- package/packages/registry-contract/artifacts/@openzeppelin/contracts/utils/Context.sol/Context.json +10 -0
- package/packages/registry-contract/artifacts/@openzeppelin/contracts/utils/Pausable.sol/Pausable.dbg.json +4 -0
- package/packages/registry-contract/artifacts/@openzeppelin/contracts/utils/Pausable.sol/Pausable.json +60 -0
- package/packages/registry-contract/artifacts/build-info/1a74d547ba64d2f3b7adbff726f3d048.json +1 -0
- package/packages/registry-contract/artifacts/contracts/NyxoraAgentRegistry.sol/NyxoraAgentRegistry.dbg.json +4 -0
- package/packages/registry-contract/artifacts/contracts/NyxoraAgentRegistry.sol/NyxoraAgentRegistry.json +316 -0
- package/packages/registry-contract/cache/solidity-files-cache.json +156 -0
- package/packages/registry-contract/contracts/NyxoraAgentRegistry.sol +93 -0
- package/packages/registry-contract/hardhat.config.ts +32 -0
- package/packages/registry-contract/ignition/deployments/chain-421614/artifacts/RegistryModule#NyxoraAgentRegistry.dbg.json +4 -0
- package/packages/registry-contract/ignition/deployments/chain-421614/artifacts/RegistryModule#NyxoraAgentRegistry.json +316 -0
- package/packages/registry-contract/ignition/deployments/chain-421614/build-info/1a74d547ba64d2f3b7adbff726f3d048.json +12064 -0
- package/packages/registry-contract/ignition/deployments/chain-421614/deployed_addresses.json +3 -0
- package/packages/registry-contract/ignition/deployments/chain-421614/journal.jsonl +8 -0
- package/packages/registry-contract/ignition/modules/Registry.ts +9 -0
- package/packages/registry-contract/package.json +23 -0
- package/packages/registry-contract/typechain-types/@openzeppelin/contracts/access/Ownable.ts +153 -0
- package/packages/registry-contract/typechain-types/@openzeppelin/contracts/access/index.ts +4 -0
- package/packages/registry-contract/typechain-types/@openzeppelin/contracts/index.ts +7 -0
- package/packages/registry-contract/typechain-types/@openzeppelin/contracts/utils/Pausable.ts +150 -0
- package/packages/registry-contract/typechain-types/@openzeppelin/contracts/utils/index.ts +4 -0
- package/packages/registry-contract/typechain-types/@openzeppelin/index.ts +5 -0
- package/packages/registry-contract/typechain-types/common.ts +131 -0
- package/packages/registry-contract/typechain-types/contracts/NyxoraAgentRegistry.ts +416 -0
- package/packages/registry-contract/typechain-types/contracts/index.ts +4 -0
- package/packages/registry-contract/typechain-types/factories/@openzeppelin/contracts/access/Ownable__factory.ts +96 -0
- package/packages/registry-contract/typechain-types/factories/@openzeppelin/contracts/access/index.ts +4 -0
- package/packages/registry-contract/typechain-types/factories/@openzeppelin/contracts/index.ts +5 -0
- package/packages/registry-contract/typechain-types/factories/@openzeppelin/contracts/utils/Pausable__factory.ts +71 -0
- package/packages/registry-contract/typechain-types/factories/@openzeppelin/contracts/utils/index.ts +4 -0
- package/packages/registry-contract/typechain-types/factories/@openzeppelin/index.ts +4 -0
- package/packages/registry-contract/typechain-types/factories/contracts/NyxoraAgentRegistry__factory.ts +378 -0
- package/packages/registry-contract/typechain-types/factories/contracts/index.ts +4 -0
- package/packages/registry-contract/typechain-types/factories/index.ts +5 -0
- package/packages/registry-contract/typechain-types/hardhat.d.ts +99 -0
- package/packages/registry-contract/typechain-types/index.ts +14 -0
- package/packages/signer/package.json +1 -1
- package/packages/dashboard/dist/assets/index-D50q-_33.js +0 -311
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,37 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepashangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [26.6.
|
|
8
|
+
## [26.6.10] - 2026-06-09
|
|
9
|
+
### The DeFi Optimization Update
|
|
10
|
+
- **DeFi Lending Engine**: Integrated native Aave V3 support across all EVM chains. The AI can now autonomously fetch dynamic `Pool` addresses via `PoolAddressesProvider` and securely draft `supply` payloads to earn yield on idle assets.
|
|
11
|
+
- **DeFi Security Guard (Revoke)**: Shipped a critical security skill allowing users to purge "Infinite Approvals". The AI can now construct 0-value `approve()` payloads to instantly revoke access from malicious or vulnerable smart contracts across any chain.
|
|
12
|
+
- **DEX LP Manager**: Integrated Uniswap V3 (and PancakeSwap V3 for BSC) liquidity provision. Enforces strict safety barriers by mandating human-in-the-loop input for `tickLower` and `tickUpper` price ranges, completely neutralizing AI hallucination risks in complex liquidity deployments.
|
|
13
|
+
- **Auto-Compounder Vaults**: Integrated Beefy Finance (Primary) and Yearn Finance (Secondary). The AI can seamlessly route idle LP tokens into auto-compounding smart contracts to automatically maximize yield.
|
|
14
|
+
- **Transaction Chaining (Smart Approve)**: Upgraded the `viem` contract simulator to intelligently read user allowances prior to execution. If a user attempts to supply Aave or deposit to Beefy without prior authorization, the AI will autonomously intercept the request and draft a precise `approve` payload first, drastically improving UX.
|
|
15
|
+
### Enterprise Reporting & History
|
|
16
|
+
- **Automated Excel Reporting**: The AI can now autonomously generate formatted `.xlsx` reports from raw JSON data (e.g., PnL, token balances) via the new `generate_excel_file` OS Skill.
|
|
17
|
+
- **Deep Transaction History**: Integrated `get_tx_history` Web3 skill to fetch complete 30-day (or N-day) history for Native and ERC-20 transfers using the new Unified Etherscan API V2. A single API key now powers cross-chain fetching across 60+ Mainnets and Testnets, featuring a graceful fallback mechanism to public endpoints.
|
|
18
|
+
|
|
19
|
+
### The Masterpiece Memory Architecture
|
|
20
|
+
- **Air-Gapped Security Vault**: Implemented a strict 4-Layer Memory Architecture. The LLM Reflection Engine is now completely air-gapped from the OS Keyring and Wallet System, establishing absolute immunity against memory-based Private Key leakage.
|
|
21
|
+
- **Hard-Coded Anti-Injection Validator**: Deployed a rule-based RegExp Validator (`validator.ts`) acting as the ultimate gatekeeper before SQLite insertion. It autonomously detects and annihilates Private Keys, 12/24 BIP-39 Seed Phrases, API Tokens, and System Prompt Override attempts without relying on LLM behavior.
|
|
22
|
+
- **Smart Suggestion Engine**: The Agent Reasoning Pipeline now natively hooks into the Layer-2 Episodic Database. By injecting the top 10 most confident habits directly into the System Prompt, Nyxora can now autonomously autocomplete repetitive transaction parameters (e.g., preferred network, preferred token) slashing human-in-the-loop latency by up to 90%.
|
|
23
|
+
- **Persistent Background Reflection**: Eliminated static interval timers. The Reflection Engine is now seamlessly triggered via 3 infallible hooks: a 3-minute Idle Timer, an N-Message threshold (every 5 messages), and a `SIGTERM` Graceful Shutdown hook, ensuring resilient memory retention across daemon lifecycles.
|
|
24
|
+
- **Real-Time Memory Log Dashboard**: Exposed a robust `/api/memory` CRUD endpoint and integrated a sleek "Memory Log" panel directly into the Web Dashboard Overview tab. Users can now audit, review confidence scores, and forcefully delete false observations in real-time with zero state desynchronization.
|
|
25
|
+
|
|
26
|
+
## [26.6.9] - 2026-06-08
|
|
27
|
+
### Security & UX Hardening
|
|
28
|
+
- **Zero-Trust Auto-Lock (Passwordless)**: Implemented a robust idle timeout mechanism in the React Dashboard with an elegant glassmorphism blur overlay. The dashboard securely locks after periods of inactivity, requiring the user to authorize unlock directly via the CLI (`nyxora unlock`) to prevent unauthorized local access.
|
|
29
|
+
- **Approval Replay Protection (Nonce Guard)**: Hardened the `transactionManager` to cryptographically sign all pending transaction payloads with a randomized 16-byte Nonce. The `/api/transactions/:id/approve` endpoint now strictly enforces Nonce matching and immediately marks it as `used_` upon first validation, completely eliminating double-spending and Replay Attack vectors.
|
|
30
|
+
- **Graceful Shutdown (SQLite WAL Guard)**: Integrated deep `SIGTERM` and `SIGINT` signal listeners within the Gateway server. When the daemon is halted, the system now safely terminates active incoming requests and explicitly invokes `logger.close()` to securely flush SQLite Write-Ahead Logs (WAL) before exiting, completely eliminating the risk of database corruption.
|
|
31
|
+
- **Resilient UI (Reconnect Overlay)**: Engineered a global network interceptor inside the Dashboard's React `apiFetch` utility. If the daemon goes offline unexpectedly or is restarting, the UI instantly pauses and deploys a transparent, pulsing "Nyxora Daemon Offline" screen. Once the daemon is revived, the overlay automatically lifts, preserving the user's workflow seamlessly.
|
|
32
|
+
|
|
33
|
+
### Architecture & Production Readiness
|
|
34
|
+
- **Dynamic Port Anti-Collision**: Replaced the hardcoded `3001` Policy Server port with a dynamic `process.env.POLICY_PORT` fallback. All Web3 Agents (Bridge, Swap, Transfer, etc.) are now dynamically linked to this environment variable, completely eliminating `ECONNREFUSED` crashes when port 3001 is occupied by other local developer applications.
|
|
35
|
+
- **Production-Ready Path Resolution**: Eliminated hardcoded `process.cwd()` dependencies across the Gateway, Dashboard, and Plugin Manager. The CLI now utilizes robust absolute `__dirname` and `getAppDir()` traversal, guaranteeing the Dashboard UI and External Skills load flawlessly regardless of where the global CLI command is executed from.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## [26.6.8] - 2026-06-08
|
|
9
39
|
### Enterprise Features & Web3 Enhancements
|
|
10
40
|
- **Zero-Downtime Directory Migration**: Restructured the root `~/.nyxora` local data directory into a strict `config/`, `data/`, `auth/`, and `run/` subdirectory architecture. Implemented a Lazy Auto-Migration Engine (`getPath()`) that seamlessly relocates legacy files to their new secure zones instantly upon access, ensuring zero-downtime and zero-data-loss upgrades for existing users.
|
|
11
41
|
### Security & UX Updates
|
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
**Your Personal Web3 Assistant.**
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
[](https://arbitrum.io/)
|
|
5
6
|
[](#)
|
|
6
7
|
[](https://opensource.org/licenses/MIT)
|
|
7
8
|
[](#️-advanced-security-threat-model)
|
|
@@ -19,28 +20,39 @@ It operates under an institutional-grade **Cryptographically Bound Human-in-the-
|
|
|
19
20
|
## 🔥 Key Features
|
|
20
21
|
|
|
21
22
|
### Advanced Security Architecture
|
|
23
|
+
* **🛡️ On-Chain AI Kill-Switch**: Nyxora is governed by an Arbitrum Smart Contract (`NyxoraAgentRegistry`). Users have absolute cryptographic power to instantly paralyze the AI's on-chain execution if compromised, solving the Web3 AI safety dilemma. [Read more about our Arbitrum Architecture ->](https://nyxoraai.github.io/Nyxora/security/smart-contract)
|
|
22
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).
|
|
23
|
-
* **
|
|
25
|
+
* **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.
|
|
24
26
|
* **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.
|
|
25
27
|
* **Plugin Sandbox VM**: Execute community-built external skills securely inside an airtight Node.js `vm` chamber with zero access to your file system or terminal processes.
|
|
26
|
-
* **
|
|
28
|
+
* **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.
|
|
27
29
|
|
|
28
30
|
### 🌐 Web3 Skills (On-Chain)
|
|
29
31
|
* **Security Scanner**: Nyxora can scan smart contracts via GoPlus Labs to detect Honeypots, Hidden Taxes, and malicious proxy upgrades before you buy.
|
|
32
|
+
* **Advanced DeFi Optimization**: Autonomously supply assets to Aave V3, deposit into Beefy/Yearn Auto-Compounder Vaults, manage Uniswap V3 Liquidity (LP), and instantly revoke infinite approvals to secure your wallet. Features intelligent Transaction Chaining to auto-approve allowances prior to execution.
|
|
30
33
|
* **Anti-MEV Slippage Protection**: Hardened routing engine with dynamic Slippage Tolerance (default 0.5%) for Relay and Li.Fi. You can manually adjust slippage via the UI or dynamically override it using natural language (e.g., "Swap 1 ETH to PEPE with 10% slippage").
|
|
31
34
|
* **Automated Take Profit (TP) & Cut Loss (CL)**: The trader's holy grail. Set natural language rules (e.g., "Sell my PEPE if price drops below $0.001"). Nyxora runs a background cron monitor and executes the swap while you sleep.
|
|
32
35
|
* **Cross-Chain Hybrid Market Scanner**: Real-time asset tracking combining CoinGecko global data with DexScreener on-chain metrics across Ethereum, Base, Solana, BSC, and more.
|
|
33
36
|
* **"Lean Degen" Auto-Whitelist**: Automatically intercepts Contract Addresses (CAs) whenever you check balances or swap tokens, saving them to your localized `user_whitelist.json` for future tracking.
|
|
34
37
|
* **Dynamic Portfolio Engine**: Merges standard tokens, your custom Degen CAs, and CoinGecko's daily trending list into a single hyper-fast Multicall scan to deliver a clean, spam-free PnL portfolio report in under 1 second.
|
|
38
|
+
* **Deep Transaction History**: Accurately fetch your 30-day (or custom timeframe) Native and ERC-20 transaction history across all supported EVM chains. Powered by the Unified Etherscan API V2, enabling seamless cross-chain fetching (Mainnets & Testnets) using a single API key.
|
|
35
39
|
|
|
36
40
|
### 💻 OS & Web2 Skills (Off-Chain)
|
|
37
41
|
* **Google Workspace Automation 🚀**: Transform Nyxora into your ultimate personal assistant. The agent can read your latest Gmail inbox, check your Google Calendar, extract text from Google Docs, and even append expense/trading logs directly to your Google Sheets.
|
|
38
42
|
* **System Automation & Full OS Access**: Instruct the agent to read/write local files, run terminal commands, and browse the web natively.
|
|
43
|
+
* **Automated Excel Reporting**: Instruct the agent to compile its Web3 portfolio or transaction history findings and autonomously generate beautiful `.xlsx` spreadsheet reports saved directly to your local machine.
|
|
39
44
|
* **Unstoppable Synergy**: Combine both engines with a single prompt. Example: *"Read the latest presale token email from my Gmail, automatically set a Take Profit limit order on Uniswap, and log the execution result to my Google Sheets."*
|
|
40
45
|
|
|
46
|
+
### 🧠 The Masterpiece Memory Architecture
|
|
47
|
+
* **4-Layer Air-Gapped Vault**: Nyxora features a god-tier memory system that completely isolates conversational habits from the OS Keyring. The AI can dynamically learn your behaviors without ever having physical read-paths to your private keys.
|
|
48
|
+
* **Hard-Coded Anti-Injection Shield**: We enforce a Zero-Trust memory paradigm. Before any user habit is saved to the local SQLite database, it must pass a strict RegExp-based validation layer that autonomously annihilates Private Keys, BIP-39 Seed Phrases, and Prompt Injection attempts.
|
|
49
|
+
* **Smart Suggestion Engine**: Nyxora actively queries its Layer-2 Episodic Database to seamlessly autocomplete your repetitive Web3 routines. If you always swap on Arbitrum using USDC, the AI will proactively suggest it, slashing human-in-the-loop latency by up to 90%.
|
|
50
|
+
* **Persistent Background Reflection**: Empowered by background idle timers and message-count thresholds, Nyxora quietly transcribes your habits into a permanent profile while you step away from the keyboard, ensuring it never forgets your identity even after daemon reboots.
|
|
51
|
+
|
|
41
52
|
### AI & UI Customization
|
|
53
|
+
* **Zero-Trust Auto-Lock (Passwordless)**: A sleek glassmorphism blur overlay automatically locks the dashboard during inactivity. Unlocking requires physical local execution via the CLI (`nyxora unlock`), preventing unauthorized local access.
|
|
54
|
+
* **Resilient UI (Reconnect Overlay)**: Built-in global network interceptors ensure that if the daemon restarts or crashes, the UI immediately pauses with a transparent "Offline" overlay and seamlessly resumes your workflow once revived.
|
|
42
55
|
* **Zero-Click Multi-Session**: Instantly create isolated chat sessions with smart auto-naming triggered by your first prompt, exactly like ChatGPT.
|
|
43
|
-
* **Dynamic Trending Tokens**: Live top 5 crypto assets feed directly injected into the dashboard, completely clickable for instant AI market analysis.
|
|
44
56
|
* **Premium Utility-Centric UI**: A sleek, dark-themed dashboard built for high readability and professional Web3 execution, featuring Pseudo-Generative UI widgets (`<BalanceWidget>`, `<MarketWidget>`, `<SwapWidget>`).
|
|
45
57
|
* **Massive 2026 Model Roster**: Out-of-the-box support for cutting-edge models via Google Gemini, OpenAI, Groq, Mistral, xAI, DeepSeek, OpenRouter, and local Ollama, equipped with a searchable CLI prompt to instantly find your favorite model.
|
|
46
58
|
* **Strict NLP Exactness (Rule 8)**: The AI is rigorously instructed never to hallucinate or guess missing transaction parameters (like destination chains or swap amounts). It halts and requests human clarification, guaranteeing 100% precision.
|
|
@@ -70,7 +82,7 @@ To dive deeper into the technical details of our Zero-Knowledge security archite
|
|
|
70
82
|
|
|
71
83
|
---
|
|
72
84
|
|
|
73
|
-
## 🚀 Quick Start & Installation
|
|
85
|
+
## 1. 🚀 Quick Start & Installation
|
|
74
86
|
|
|
75
87
|
### Global Installation via NPM (Recommended)
|
|
76
88
|
The easiest and fastest way to use Nyxora is to install it globally via NPM. This ensures you get the latest version and can run Nyxora from anywhere on your machine.
|
package/SECURITY.md
CHANGED
|
@@ -66,12 +66,22 @@ approval_hash = sha256(policy_diff + timestamp + user_id)
|
|
|
66
66
|
```
|
|
67
67
|
This ensures that what the human saw on the UI matches exactly what is being executed, preventing the LLM from secretly modifying the payload in transit.
|
|
68
68
|
|
|
69
|
-
### Anti-Replay Challenge Nonce
|
|
70
|
-
Every approval UI prompt utilizes a **Single-Use Challenge Nonce** with
|
|
69
|
+
### Anti-Replay Challenge Nonce (Nonce Guard)
|
|
70
|
+
Every approval UI prompt utilizes a **Single-Use Challenge Nonce** (a randomized 16-byte cryptographic string). The `transactionManager` signs all pending payloads with this Nonce. The `/api/transactions/:id/approve` endpoint strictly enforces matching and immediately marks the Nonce as `used_` upon first validation. This completely eliminates *XSS Token Leaks*, *Double-Spending*, and *Replay Attacks*, ensuring that an old approval token cannot be stolen and reused for a malicious transaction later.
|
|
71
71
|
|
|
72
72
|
---
|
|
73
73
|
|
|
74
|
-
## 4.
|
|
74
|
+
## 4. Physical Access & Data Integrity
|
|
75
|
+
|
|
76
|
+
### Zero-Trust Auto-Lock (Physical Protection)
|
|
77
|
+
To protect against unauthorized physical access (e.g., leaving a laptop unattended), the Dashboard implements a **Zero-Trust Auto-Lock** mechanism. After a period of inactivity, the UI aggressively blurs and locks all state. Unlocking the interface requires the user to execute `nyxora unlock` directly from the host operating system's CLI. This guarantees that anyone physically sitting at the unlocked dashboard cannot execute transactions without also possessing SSH or direct terminal access to the host machine.
|
|
78
|
+
|
|
79
|
+
### SQLite WAL Graceful Shutdown (Data Integrity)
|
|
80
|
+
To prevent database corruption during abrupt terminations, the Gateway daemon employs deep `SIGTERM` and `SIGINT` interceptors. When a halt is requested, the system safely terminates active incoming API requests and explicitly flushes the SQLite Write-Ahead Logs (WAL) before fully exiting, ensuring enterprise-grade state stability.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 5. Plugin Sandboxing (Node.js VM Isolation)
|
|
75
85
|
|
|
76
86
|
Community plugins and custom skills are NEVER executed directly at the OS level. Instead, Nyxora creates an airtight **Virtual Machine (VM) Sandbox** in memory.
|
|
77
87
|
|
package/bin/nyxora.mjs
CHANGED
|
@@ -117,7 +117,13 @@ async function dashboard() {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
if (fs.existsSync(tokenFile)) {
|
|
120
|
-
|
|
120
|
+
let token = fs.readFileSync(tokenFile, 'utf8').trim();
|
|
121
|
+
if (token.startsWith('{')) {
|
|
122
|
+
try {
|
|
123
|
+
const parsed = JSON.parse(token);
|
|
124
|
+
token = parsed.token;
|
|
125
|
+
} catch (e) {}
|
|
126
|
+
}
|
|
121
127
|
const url = `http://localhost:3000?token=${token}`;
|
|
122
128
|
console.log(`Opening Dashboard at ${url}`);
|
|
123
129
|
try {
|
|
@@ -275,8 +281,38 @@ async function runDoctor() {
|
|
|
275
281
|
await new Promise(resolve => child.on('close', resolve));
|
|
276
282
|
}
|
|
277
283
|
|
|
284
|
+
async function unlock() {
|
|
285
|
+
if (fs.existsSync(tokenFile)) {
|
|
286
|
+
let token = fs.readFileSync(tokenFile, 'utf8').trim();
|
|
287
|
+
if (token.startsWith('{')) {
|
|
288
|
+
try {
|
|
289
|
+
const parsed = JSON.parse(token);
|
|
290
|
+
token = parsed.token;
|
|
291
|
+
} catch (e) {}
|
|
292
|
+
}
|
|
293
|
+
try {
|
|
294
|
+
const fetch = (await import('node-fetch')).default;
|
|
295
|
+
const res = await fetch('http://localhost:3000/api/status/unlock', {
|
|
296
|
+
method: 'POST',
|
|
297
|
+
headers: {
|
|
298
|
+
'x-nyxora-token': token
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
if (res.ok) {
|
|
302
|
+
console.log('✅ Dashboard unlocked successfully.');
|
|
303
|
+
} else {
|
|
304
|
+
console.log('❌ Failed to unlock dashboard. Is the daemon running?');
|
|
305
|
+
}
|
|
306
|
+
} catch (e) {
|
|
307
|
+
console.log('❌ Failed to communicate with the daemon. Is it running?');
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
console.log('❌ Authentication token not found.');
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
278
314
|
async function main() {
|
|
279
|
-
switch
|
|
315
|
+
switch(command) {
|
|
280
316
|
case 'doctor': await runDoctor(); break;
|
|
281
317
|
case 'setup': await setup(); break;
|
|
282
318
|
case 'clear': await clearMemory(process.argv.slice(3)); break;
|
|
@@ -286,6 +322,7 @@ async function main() {
|
|
|
286
322
|
case 'stop': await stop(); break;
|
|
287
323
|
case 'restart': await restart(); break;
|
|
288
324
|
case 'dashboard': await dashboard(); break;
|
|
325
|
+
case 'unlock': await unlock(); break;
|
|
289
326
|
case 'clean-logs': await cleanLogs(); break;
|
|
290
327
|
case 'autostart': await autostart(process.argv[3]); break;
|
|
291
328
|
case '-v':
|
|
@@ -307,6 +344,7 @@ Commands:
|
|
|
307
344
|
restart Restart the daemon
|
|
308
345
|
setup Run the interactive Setup Wizard
|
|
309
346
|
dashboard Open the dashboard in your browser
|
|
347
|
+
unlock Unlock an inactive dashboard session
|
|
310
348
|
doctor Run system diagnostics and check requirements
|
|
311
349
|
clear Atomically clear the AI's short/long-term memory SQLite database
|
|
312
350
|
clean-logs Clear the daemon logs
|
|
@@ -4,12 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.logger = void 0;
|
|
7
|
+
exports.getOpenAI = getOpenAI;
|
|
7
8
|
exports.processUserInput = processUserInput;
|
|
8
9
|
const fs_1 = __importDefault(require("fs"));
|
|
9
10
|
const openai_1 = require("openai");
|
|
10
11
|
const parser_1 = require("../config/parser");
|
|
11
12
|
const logger_1 = require("../memory/logger");
|
|
12
13
|
const tracker_1 = require("../gateway/tracker");
|
|
14
|
+
const episodic_1 = require("../memory/episodic");
|
|
13
15
|
const getBalance_1 = require("../web3/skills/getBalance");
|
|
14
16
|
const transfer_1 = require("../web3/skills/transfer");
|
|
15
17
|
const getPrice_1 = require("../web3/skills/getPrice");
|
|
@@ -25,12 +27,18 @@ const checkPortfolio_1 = require("../web3/skills/checkPortfolio");
|
|
|
25
27
|
const checkAddress_1 = require("../web3/skills/checkAddress");
|
|
26
28
|
const getMyAddress_1 = require("../web3/skills/getMyAddress");
|
|
27
29
|
const manageCustomTokens_1 = require("../web3/skills/manageCustomTokens");
|
|
30
|
+
const revokeApprovals_1 = require("../web3/skills/revokeApprovals");
|
|
31
|
+
const defiLending_1 = require("../web3/skills/defiLending");
|
|
32
|
+
const yieldVault_1 = require("../web3/skills/yieldVault");
|
|
33
|
+
const provideLiquidity_1 = require("../web3/skills/provideLiquidity");
|
|
34
|
+
const getTxHistory_1 = require("../web3/skills/getTxHistory");
|
|
28
35
|
const limitOrderManager_1 = require("./limitOrderManager");
|
|
29
36
|
const updateProfile_1 = require("./updateProfile");
|
|
30
37
|
const updateSecurityPolicy_1 = require("../system/skills/updateSecurityPolicy");
|
|
31
38
|
const analyzeDocument_1 = require("../system/skills/analyzeDocument");
|
|
32
39
|
const readFile_1 = require("../system/skills/readFile");
|
|
33
40
|
const writeFile_1 = require("../system/skills/writeFile");
|
|
41
|
+
const generateExcel_1 = require("../system/skills/generateExcel");
|
|
34
42
|
const executeShell_1 = require("../system/skills/executeShell");
|
|
35
43
|
const browseWeb_1 = require("../system/skills/browseWeb");
|
|
36
44
|
const searchWeb_1 = require("../system/skills/searchWeb");
|
|
@@ -114,7 +122,7 @@ function getSystemPrompt() {
|
|
|
114
122
|
You are equipped with a native wallet.
|
|
115
123
|
The current real-world date and time is: ${currentDateTime}. Use this for any time-related questions.
|
|
116
124
|
|
|
117
|
-
CRITICAL RULE 1:
|
|
125
|
+
CRITICAL RULE 1: NEVER expose internal JSON tool calls to the user. Always parse them and explain the outcome naturally.
|
|
118
126
|
CRITICAL RULE 2: STRICT LANGUAGE MATCHING. You MUST strictly reply in the exact same language as the user's LATEST prompt. If the user's latest prompt is in English, you MUST reply entirely in English, completely ignoring the language of previous messages. If their latest prompt is in Indonesian, reply in Indonesian.
|
|
119
127
|
CRITICAL RULE 3: FORMATTING & CONCISENESS.
|
|
120
128
|
- Your responses MUST be concise and to the point. Do not add unnecessary fluff or overly long explanations unless explicitly asked.
|
|
@@ -158,6 +166,19 @@ CRITICAL RULE 8: EXACTNESS AND SAFETY IN TRANSACTIONS. Never guess or hallucinat
|
|
|
158
166
|
catch (error) {
|
|
159
167
|
console.error('Failed to read security_policy.md:', error);
|
|
160
168
|
}
|
|
169
|
+
// Inject Episodic Memories (Smart Suggestions Context)
|
|
170
|
+
try {
|
|
171
|
+
const recentMemories = episodic_1.episodicDB.getMemories().slice(0, 10);
|
|
172
|
+
if (recentMemories.length > 0) {
|
|
173
|
+
basePrompt += `\n\n--- EPISODIC MEMORIES (SMART SUGGESTIONS) ---\nUse these recent observations to proactively suggest or autocomplete parameters (like networks or tokens) without asking the user if they align with the current request:\n`;
|
|
174
|
+
recentMemories.forEach(mem => {
|
|
175
|
+
basePrompt += `- [${mem.category.toUpperCase()}] ${mem.fact} (Confidence: ${(mem.confidence * 100).toFixed(0)}%)\n`;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
// Ignore db errors if not initialized
|
|
181
|
+
}
|
|
161
182
|
return basePrompt;
|
|
162
183
|
}
|
|
163
184
|
async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
@@ -188,25 +209,26 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
188
209
|
if (config.llm.provider !== 'openai' && config.llm.provider !== 'ollama' && config.llm.provider !== 'gemini' && config.llm.provider !== 'openrouter') {
|
|
189
210
|
return `Provider ${config.llm.provider} is configured, but currently only OpenAI, OpenRouter, Ollama, and Gemini adapters are implemented.`;
|
|
190
211
|
}
|
|
191
|
-
// --- v1.7.4 Semantic Keyword Router ---
|
|
192
212
|
const lowerInput = input.toLowerCase();
|
|
193
213
|
const hasWeb3Keyword = /swap|transfer|price|token|crypto|bridge|wallet|balance|portfolio|buy|sell|send|receive|address|market|limit|mint|nft/i.test(lowerInput);
|
|
194
214
|
const hasGoogleKeyword = /email|gmail|calendar|sheet|doc|form|event/i.test(lowerInput);
|
|
195
|
-
|
|
196
|
-
|
|
215
|
+
let tools = [];
|
|
216
|
+
if ((0, skillManager_1.isSkillActive)('web3')) {
|
|
217
|
+
tools.push(getBalance_1.getBalanceToolDefinition, transfer_1.transferToolDefinition, getPrice_1.getPriceToolDefinition, swapToken_1.swapTokenToolDefinition, bridgeToken_1.bridgeTokenToolDefinition, mintNft_1.mintNftToolDefinition, customTx_1.customTxToolDefinition, createWallet_1.createWalletToolDefinition, checkSecurity_1.checkSecurityToolDefinition, marketAnalysis_1.marketAnalysisToolDefinition, checkPortfolio_1.checkPortfolioToolDefinition, checkAddress_1.checkAddressToolDefinition, getMyAddress_1.getMyAddressToolDefinition, manageCustomTokens_1.manageCustomTokensDefinition, limitOrderManager_1.createLimitOrderToolDefinition, limitOrderManager_1.listLimitOrdersToolDefinition, limitOrderManager_1.cancelLimitOrderToolDefinition, revokeApprovals_1.revokeApprovalToolDefinition, defiLending_1.aaveSupplyToolDefinition, yieldVault_1.vaultDepositToolDefinition, provideLiquidity_1.provideLiquidityToolDefinition, getTxHistory_1.getTxHistoryToolDefinition);
|
|
218
|
+
}
|
|
219
|
+
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, installSkill_1.installExternalSkillToolDefinition];
|
|
197
220
|
const GOOGLE_TOOLS = [googleWorkspace_1.readGmailInboxToolDefinition, googleWorkspace_1.listCalendarEventsToolDefinition, googleWorkspace_1.appendRowToSheetsToolDefinition, googleWorkspace_1.readGoogleDocsToolDefinition, googleWorkspace_1.readGoogleFormResponsesToolDefinition];
|
|
198
221
|
let activeTools = [];
|
|
199
222
|
if (hasGoogleKeyword && !hasWeb3Keyword) {
|
|
200
223
|
activeTools = [...GOOGLE_TOOLS, ...SYSTEM_TOOLS, ...pluginManager_1.pluginManager.getToolDefinitions()];
|
|
201
224
|
}
|
|
202
225
|
else if (hasWeb3Keyword && !hasGoogleKeyword) {
|
|
203
|
-
activeTools = [...
|
|
226
|
+
activeTools = [...tools, ...SYSTEM_TOOLS, ...pluginManager_1.pluginManager.getToolDefinitions()];
|
|
204
227
|
}
|
|
205
228
|
else {
|
|
206
|
-
activeTools = [...
|
|
229
|
+
activeTools = [...tools, ...SYSTEM_TOOLS, ...GOOGLE_TOOLS, ...pluginManager_1.pluginManager.getToolDefinitions()];
|
|
207
230
|
}
|
|
208
231
|
activeTools = activeTools.filter(t => (0, skillManager_1.isSkillActive)(t.function.name));
|
|
209
|
-
// ----------------------------------------
|
|
210
232
|
const response = await executeWithRetry(async (client) => {
|
|
211
233
|
return await client.chat.completions.create({
|
|
212
234
|
model: config.llm.model,
|
|
@@ -217,19 +239,16 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
217
239
|
});
|
|
218
240
|
});
|
|
219
241
|
const responseMessage = response.choices[0].message;
|
|
220
|
-
// Log tracking
|
|
221
242
|
tracker_1.Tracker.addMessage();
|
|
222
243
|
if (response.usage?.total_tokens) {
|
|
223
244
|
tracker_1.Tracker.addTokens(response.usage.total_tokens, config.llm.provider);
|
|
224
245
|
}
|
|
225
246
|
tracker_1.Tracker.addEvent('llm.response', { provider: config.llm.provider, tool_calls: responseMessage.tool_calls?.length || 0 });
|
|
226
|
-
// Log assistant response
|
|
227
247
|
exports.logger.addEntry({
|
|
228
248
|
role: 'assistant',
|
|
229
249
|
content: responseMessage.content || "",
|
|
230
250
|
tool_calls: responseMessage.tool_calls,
|
|
231
251
|
}, sessionId);
|
|
232
|
-
// Check if the model wants to call a tool
|
|
233
252
|
if (responseMessage.tool_calls && responseMessage.tool_calls.length > 0) {
|
|
234
253
|
for (const _toolCall of responseMessage.tool_calls) {
|
|
235
254
|
const toolCall = _toolCall;
|
|
@@ -239,10 +258,8 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
239
258
|
console.log(picocolors_1.default.yellow(`[⚡ Tool Execution] AI is calling ${toolName}...`));
|
|
240
259
|
if (onProgress)
|
|
241
260
|
onProgress(`_⚡ Running tool: ${toolName}..._`);
|
|
242
|
-
// Phase 1: LLM Output Validation (Anti-Halusinasi)
|
|
243
261
|
try {
|
|
244
262
|
args = JSON.parse(toolCall.function.arguments);
|
|
245
|
-
// TODO: Zod schema validation could be injected here per-tool
|
|
246
263
|
}
|
|
247
264
|
catch (parseError) {
|
|
248
265
|
console.error(picocolors_1.default.red(`[LLM Validation Error] Invalid JSON arguments for ${toolName}: ${parseError.message}`));
|
|
@@ -252,7 +269,6 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
252
269
|
tool_call_id: toolCall.id,
|
|
253
270
|
content: result
|
|
254
271
|
}, sessionId);
|
|
255
|
-
// Let the second LLM call handle the explanation of the failure
|
|
256
272
|
continue;
|
|
257
273
|
}
|
|
258
274
|
try {
|
|
@@ -279,7 +295,6 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
279
295
|
result = `[Security Blocked] Runtime Permission Denied: Web3 swaps are disabled. Update config.yaml to allow.`;
|
|
280
296
|
break;
|
|
281
297
|
}
|
|
282
|
-
// Note: max_usd_per_tx validation would ideally be calculated here before prepareSwapToken
|
|
283
298
|
result = await (0, swapToken_1.prepareSwapToken)(args.chainName, args.fromToken, args.toToken, args.amountStr || args.amount, args.mode, args.providerName);
|
|
284
299
|
break;
|
|
285
300
|
}
|
|
@@ -331,6 +346,26 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
331
346
|
result = await (0, manageCustomTokens_1.executeManageCustomTokens)(args);
|
|
332
347
|
break;
|
|
333
348
|
}
|
|
349
|
+
case 'revoke_approval': {
|
|
350
|
+
result = await (0, revokeApprovals_1.prepareRevokeApproval)(args.chainName, args.tokenAddressOrSymbol, args.spenderAddress);
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
case 'supply_aave': {
|
|
354
|
+
result = await (0, defiLending_1.prepareAaveSupply)(args.chainName, args.tokenAddressOrSymbol, args.amountStr);
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
case 'deposit_yield_vault': {
|
|
358
|
+
result = await (0, yieldVault_1.prepareVaultDeposit)(args.chainName, args.protocol || 'beefy', args.vaultAddress, args.tokenAddressOrSymbol, args.amountStr);
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
case 'provide_liquidity_v3': {
|
|
362
|
+
result = await (0, provideLiquidity_1.prepareProvideLiquidity)(args.chainName, args.token0AddressOrSymbol, args.token1AddressOrSymbol, args.amount0Str, args.amount1Str, args.feeTier, args.tickLower, args.tickUpper);
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
case 'get_tx_history': {
|
|
366
|
+
result = await (0, getTxHistory_1.getTxHistory)(args.chainName, args.address, args.days);
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
334
369
|
case 'create_limit_order': {
|
|
335
370
|
if (config.permissions?.web3?.allow_swap === false) {
|
|
336
371
|
result = `[Security Blocked] Runtime Permission Denied: Limit orders require swap permissions. Update config.yaml to allow.`;
|
|
@@ -371,6 +406,14 @@ async function processUserInput(input, role = 'user', onProgress, sessionId) {
|
|
|
371
406
|
result = (0, writeFile_1.writeLocalFile)(args.filePath, args.content);
|
|
372
407
|
break;
|
|
373
408
|
}
|
|
409
|
+
case 'generate_excel_file': {
|
|
410
|
+
if (config.permissions?.system?.allow_file_write === false) {
|
|
411
|
+
result = `[Security Blocked] Runtime Permission Denied: File writing is disabled. Update config.yaml to allow.`;
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
result = await (0, generateExcel_1.generateExcelFile)(args.data, args.filePath);
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
374
417
|
case 'run_terminal_command': {
|
|
375
418
|
if (config.permissions?.system?.allow_shell_execution === false) {
|
|
376
419
|
result = `[Security Blocked] Runtime Permission Denied: Shell execution is disabled. Update config.yaml to allow.`;
|
|
@@ -9,6 +9,7 @@ class TransactionManager {
|
|
|
9
9
|
transactions = new Map();
|
|
10
10
|
createPendingTransaction(type, chainName, details) {
|
|
11
11
|
const id = crypto_1.default.randomUUID();
|
|
12
|
+
const nonce = crypto_1.default.randomBytes(16).toString('hex');
|
|
12
13
|
const tx = {
|
|
13
14
|
id,
|
|
14
15
|
type,
|
|
@@ -16,6 +17,7 @@ class TransactionManager {
|
|
|
16
17
|
details,
|
|
17
18
|
status: 'pending',
|
|
18
19
|
createdAt: Date.now(),
|
|
20
|
+
nonce,
|
|
19
21
|
};
|
|
20
22
|
this.transactions.set(id, tx);
|
|
21
23
|
return tx;
|
|
@@ -44,6 +44,12 @@ const skillManager_1 = require("../utils/skillManager");
|
|
|
44
44
|
const bridgeToken_1 = require("../web3/skills/bridgeToken");
|
|
45
45
|
const mintNft_1 = require("../web3/skills/mintNft");
|
|
46
46
|
const customTx_1 = require("../web3/skills/customTx");
|
|
47
|
+
const defiLending_1 = require("../web3/skills/defiLending");
|
|
48
|
+
const revokeApprovals_1 = require("../web3/skills/revokeApprovals");
|
|
49
|
+
const yieldVault_1 = require("../web3/skills/yieldVault");
|
|
50
|
+
const provideLiquidity_1 = require("../web3/skills/provideLiquidity");
|
|
51
|
+
const getTxHistory_1 = require("../web3/skills/getTxHistory");
|
|
52
|
+
const checkRegistryStatus_1 = require("../web3/skills/checkRegistryStatus");
|
|
47
53
|
// System Skills
|
|
48
54
|
const browseWeb_1 = require("../system/skills/browseWeb");
|
|
49
55
|
const executeShell_1 = require("../system/skills/executeShell");
|
|
@@ -51,12 +57,15 @@ const installSkill_1 = require("../system/skills/installSkill");
|
|
|
51
57
|
const readFile_1 = require("../system/skills/readFile");
|
|
52
58
|
const updateSecurityPolicy_1 = require("../system/skills/updateSecurityPolicy");
|
|
53
59
|
const writeFile_1 = require("../system/skills/writeFile");
|
|
60
|
+
const generateExcel_1 = require("../system/skills/generateExcel");
|
|
54
61
|
const analyzeDocument_1 = require("../system/skills/analyzeDocument");
|
|
55
62
|
const searchWeb_1 = require("../system/skills/searchWeb");
|
|
56
63
|
const googleWorkspace_1 = require("../system/skills/googleWorkspace");
|
|
57
64
|
const telegram_1 = require("./telegram");
|
|
58
65
|
const googleAuthModule_1 = require("./googleAuthModule");
|
|
59
66
|
const legalGenerator_1 = require("./legalGenerator");
|
|
67
|
+
const episodic_1 = require("../memory/episodic");
|
|
68
|
+
const reflection_1 = require("../memory/reflection");
|
|
60
69
|
// Initialize Google Auth
|
|
61
70
|
(0, googleAuthModule_1.initGoogleAuth)();
|
|
62
71
|
const util_1 = __importDefault(require("util"));
|
|
@@ -109,14 +118,22 @@ app.use('/api', (req, res, next) => {
|
|
|
109
118
|
return next();
|
|
110
119
|
}
|
|
111
120
|
const token = req.headers['x-nyxora-token'];
|
|
112
|
-
|
|
113
|
-
|
|
121
|
+
const validation = (0, state_1.validateToken)(token);
|
|
122
|
+
if (!validation.valid) {
|
|
123
|
+
console.error(`[Auth] Rejected ${req.method} ${req.originalUrl} - Received invalid token.`);
|
|
114
124
|
return res.status(401).json({ error: `Unauthorized: Invalid or missing token.` });
|
|
115
125
|
}
|
|
116
126
|
next();
|
|
117
127
|
});
|
|
118
128
|
// Serve Static Dashboard
|
|
119
|
-
|
|
129
|
+
let rootDir = __dirname;
|
|
130
|
+
while (!fs_1.default.existsSync(path_1.default.join(rootDir, 'packages', 'dashboard'))) {
|
|
131
|
+
const nextDir = path_1.default.dirname(rootDir);
|
|
132
|
+
if (nextDir === rootDir || rootDir === '/' || rootDir === 'C:\\')
|
|
133
|
+
break;
|
|
134
|
+
rootDir = nextDir;
|
|
135
|
+
}
|
|
136
|
+
const dashboardPath = path_1.default.join(rootDir, 'packages', 'dashboard', 'dist');
|
|
120
137
|
app.use(express_1.default.static(dashboardPath));
|
|
121
138
|
app.get('/', (req, res) => {
|
|
122
139
|
res.sendFile(path_1.default.join(dashboardPath, 'index.html'));
|
|
@@ -260,7 +277,12 @@ app.get('/api/skills', (req, res) => {
|
|
|
260
277
|
manageCustomTokens_1.manageCustomTokensDefinition,
|
|
261
278
|
limitOrderManager_2.createLimitOrderToolDefinition,
|
|
262
279
|
limitOrderManager_2.listLimitOrdersToolDefinition,
|
|
263
|
-
limitOrderManager_2.cancelLimitOrderToolDefinition
|
|
280
|
+
limitOrderManager_2.cancelLimitOrderToolDefinition,
|
|
281
|
+
defiLending_1.aaveSupplyToolDefinition,
|
|
282
|
+
revokeApprovals_1.revokeApprovalToolDefinition,
|
|
283
|
+
yieldVault_1.vaultDepositToolDefinition,
|
|
284
|
+
provideLiquidity_1.provideLiquidityToolDefinition,
|
|
285
|
+
getTxHistory_1.getTxHistoryToolDefinition
|
|
264
286
|
];
|
|
265
287
|
const skillsWithStatus = allSkills.map(skill => ({
|
|
266
288
|
...skill,
|
|
@@ -273,6 +295,7 @@ app.get('/api/skills/system', (req, res) => {
|
|
|
273
295
|
executeShell_1.runTerminalCommandToolDefinition,
|
|
274
296
|
readFile_1.readLocalFileToolDefinition,
|
|
275
297
|
writeFile_1.writeLocalFileToolDefinition,
|
|
298
|
+
generateExcel_1.generateExcelToolDefinition,
|
|
276
299
|
browseWeb_1.browseWebsiteToolDefinition,
|
|
277
300
|
updateSecurityPolicy_1.updateSecurityPolicyToolDefinition,
|
|
278
301
|
installSkill_1.installExternalSkillToolDefinition,
|
|
@@ -333,16 +356,37 @@ app.delete('/api/auth/google', async (req, res) => {
|
|
|
333
356
|
const success = await (0, googleAuthModule_1.logoutGoogle)();
|
|
334
357
|
res.json({ success });
|
|
335
358
|
});
|
|
359
|
+
let lastUnlockRequest = 0;
|
|
360
|
+
app.post('/api/status/unlock', (req, res) => {
|
|
361
|
+
lastUnlockRequest = Date.now();
|
|
362
|
+
res.json({ success: true });
|
|
363
|
+
});
|
|
364
|
+
app.get('/api/status/lock', (req, res) => {
|
|
365
|
+
res.json({ lastUnlockRequest });
|
|
366
|
+
});
|
|
336
367
|
app.get('/api/transactions', (req, res) => {
|
|
337
368
|
res.json(transactionManager_1.txManager.getPending());
|
|
338
369
|
});
|
|
339
370
|
app.post('/api/transactions/:id/approve', async (req, res) => {
|
|
340
371
|
try {
|
|
341
372
|
const id = req.params.id;
|
|
342
|
-
const { sessionId } = req.body || {};
|
|
373
|
+
const { sessionId, nonce } = req.body || {};
|
|
343
374
|
const tx = transactionManager_1.txManager.getTransaction(id);
|
|
344
375
|
if (!tx || tx.status !== 'pending')
|
|
345
376
|
return res.status(404).json({ error: 'Transaction not found or not pending' });
|
|
377
|
+
if (tx.nonce !== nonce) {
|
|
378
|
+
return res.status(403).json({ error: 'Invalid or missing nonce. Replay attack detected.' });
|
|
379
|
+
}
|
|
380
|
+
// --- Arbitrum Registry Kill-Switch Interceptor ---
|
|
381
|
+
const registryCheck = await (0, checkRegistryStatus_1.checkRegistryStatus)();
|
|
382
|
+
if (!registryCheck.isActive) {
|
|
383
|
+
transactionManager_1.txManager.updateStatus(id, 'failed', registryCheck.reason);
|
|
384
|
+
reasoning_1.logger.addEntry({ role: 'assistant', content: `❌ **Security Blocked:** ${registryCheck.reason}` }, sessionId);
|
|
385
|
+
return res.status(403).json({ error: `[On-Chain Policy] ${registryCheck.reason}` });
|
|
386
|
+
}
|
|
387
|
+
// ------------------------------------------------
|
|
388
|
+
// Invalidate the nonce immediately to prevent replay
|
|
389
|
+
tx.nonce = 'used_' + Date.now();
|
|
346
390
|
transactionManager_1.txManager.updateStatus(id, 'approved', 'Executing on-chain...');
|
|
347
391
|
res.json({ success: true, status: 'processing', message: 'Transaction submitted to background processing.' });
|
|
348
392
|
// Execute in background
|
|
@@ -592,6 +636,17 @@ app.get('/api/portfolio', async (req, res) => {
|
|
|
592
636
|
res.status(500).json({ error: err.message });
|
|
593
637
|
}
|
|
594
638
|
});
|
|
639
|
+
// --- Memory Triggers ---
|
|
640
|
+
let messageCounter = 0;
|
|
641
|
+
let idleTimer = null;
|
|
642
|
+
function resetIdleTimer() {
|
|
643
|
+
if (idleTimer)
|
|
644
|
+
clearTimeout(idleTimer);
|
|
645
|
+
idleTimer = setTimeout(() => {
|
|
646
|
+
console.log('[Memory] Idle trigger activated. Running Reflection Engine...');
|
|
647
|
+
reflection_1.ReflectionEngine.runReflection();
|
|
648
|
+
}, 3 * 60 * 1000); // 3 minutes idle
|
|
649
|
+
}
|
|
595
650
|
app.post('/api/chat', async (req, res) => {
|
|
596
651
|
try {
|
|
597
652
|
const { message, session_id } = req.body;
|
|
@@ -600,12 +655,45 @@ app.post('/api/chat', async (req, res) => {
|
|
|
600
655
|
}
|
|
601
656
|
// Process input (this will automatically add to memory)
|
|
602
657
|
const response = await (0, reasoning_1.processUserInput)(message, 'user', undefined, session_id);
|
|
658
|
+
// Memory Triggers
|
|
659
|
+
resetIdleTimer();
|
|
660
|
+
messageCounter++;
|
|
661
|
+
if (messageCounter >= 5) {
|
|
662
|
+
console.log('[Memory] N-Message threshold reached. Running Reflection Engine...');
|
|
663
|
+
messageCounter = 0;
|
|
664
|
+
// Run asynchronously
|
|
665
|
+
reflection_1.ReflectionEngine.runReflection();
|
|
666
|
+
}
|
|
603
667
|
res.json({ response });
|
|
604
668
|
}
|
|
605
669
|
catch (error) {
|
|
606
670
|
res.status(500).json({ error: error.message });
|
|
607
671
|
}
|
|
608
672
|
});
|
|
673
|
+
// --- Memory API Endpoints ---
|
|
674
|
+
app.get('/api/memory', (req, res) => {
|
|
675
|
+
try {
|
|
676
|
+
const memories = episodic_1.episodicDB.getMemories();
|
|
677
|
+
res.json(memories);
|
|
678
|
+
}
|
|
679
|
+
catch (error) {
|
|
680
|
+
res.status(500).json({ error: error.message });
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
app.delete('/api/memory/:id', (req, res) => {
|
|
684
|
+
try {
|
|
685
|
+
const id = parseInt(req.params.id, 10);
|
|
686
|
+
episodic_1.episodicDB.deleteMemory(id);
|
|
687
|
+
// When memory is deleted manually, trigger promotion engine to resync user.md
|
|
688
|
+
// To avoid circular dependency inside server.ts, we import here or assume it updates next cycle
|
|
689
|
+
const { PromotionEngine } = require('../memory/promotionEngine');
|
|
690
|
+
PromotionEngine.runPromotionAndDecay();
|
|
691
|
+
res.json({ success: true });
|
|
692
|
+
}
|
|
693
|
+
catch (error) {
|
|
694
|
+
res.status(500).json({ error: error.message });
|
|
695
|
+
}
|
|
696
|
+
});
|
|
609
697
|
// Fallback for React Router (Single Page Application)
|
|
610
698
|
app.use((req, res, next) => {
|
|
611
699
|
if (req.method === 'GET' && !req.path.startsWith('/api')) {
|
|
@@ -652,11 +740,36 @@ function startServer() {
|
|
|
652
740
|
});
|
|
653
741
|
limitOrderManager_1.limitOrderManager.startMonitor();
|
|
654
742
|
const PORT = Number(process.env.PORT || 3000);
|
|
655
|
-
app.listen(PORT, '0.0.0.0', () => {
|
|
743
|
+
const server = app.listen(PORT, '0.0.0.0', () => {
|
|
656
744
|
console.log(`🤖 Nyxora API Server running on port ${PORT}`);
|
|
657
745
|
// Start the Telegram bot listener
|
|
658
746
|
(0, telegram_1.startTelegramBot)();
|
|
659
747
|
});
|
|
748
|
+
server.on('error', (e) => {
|
|
749
|
+
if (e.code === 'EADDRINUSE') {
|
|
750
|
+
console.error(`[Nyxora Gateway] Port ${PORT} is already in use. Is Nyxora already running?`);
|
|
751
|
+
process.exit(1);
|
|
752
|
+
}
|
|
753
|
+
else {
|
|
754
|
+
console.error(`[Nyxora Gateway] Server error:`, e);
|
|
755
|
+
process.exit(1);
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
const gracefulShutdown = () => {
|
|
759
|
+
console.log('[Nyxora Gateway] Received shutdown signal. Closing server...');
|
|
760
|
+
server.close(() => {
|
|
761
|
+
console.log('[Nyxora Gateway] HTTP server closed.');
|
|
762
|
+
reasoning_1.logger.close();
|
|
763
|
+
process.exit(0);
|
|
764
|
+
});
|
|
765
|
+
// Force exit after 10s if stuck
|
|
766
|
+
setTimeout(() => {
|
|
767
|
+
console.error('[Nyxora Gateway] Forced shutdown after 10s.');
|
|
768
|
+
process.exit(1);
|
|
769
|
+
}, 10000);
|
|
770
|
+
};
|
|
771
|
+
process.on('SIGTERM', gracefulShutdown);
|
|
772
|
+
process.on('SIGINT', gracefulShutdown);
|
|
660
773
|
}
|
|
661
774
|
// Start server if this file is run directly
|
|
662
775
|
if (require.main === module) {
|
|
@@ -231,6 +231,9 @@ Provider: ${config.llm.provider}`;
|
|
|
231
231
|
{ value: 'optimism', label: 'OP Mainnet' },
|
|
232
232
|
{ value: 'polygon', label: 'Polygon (Matic)' },
|
|
233
233
|
{ value: 'sepolia', label: 'Sepolia (Testnet)' },
|
|
234
|
+
{ value: 'base_sepolia', label: 'Base Sepolia (Testnet)' },
|
|
235
|
+
{ value: 'arbitrum_sepolia', label: 'Arbitrum Sepolia (Testnet)' },
|
|
236
|
+
{ value: 'optimism_sepolia', label: 'OP Sepolia (Testnet)' },
|
|
234
237
|
],
|
|
235
238
|
});
|
|
236
239
|
if ((0, prompts_1.isCancel)(defaultChain))
|