nyxora 1.6.3 → 1.6.5
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 +23 -0
- package/README.md +13 -3
- package/launcher.ts +9 -0
- package/package.json +3 -4
- package/packages/core/package.json +2 -3
- package/packages/core/src/gateway/cli.ts +3 -0
- package/packages/core/src/gateway/setup.ts +3 -2
- package/packages/core/src/memory/logger.ts +21 -14
- package/packages/core/src/utils/safeLogger.js +59 -0
- package/packages/core/src/utils/safeLogger.ts +60 -0
- package/packages/dashboard/dist/assets/index-CfIids2e.js +170 -0
- package/packages/dashboard/dist/index.html +1 -1
- package/packages/dashboard/package.json +7 -7
- package/packages/mcp-server/dist/server.js +111 -0
- package/packages/mcp-server/package.json +19 -0
- package/packages/mcp-server/src/server.ts +124 -0
- package/packages/mcp-server/tsconfig.json +15 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -0
- package/packages/policy/package.json +2 -2
- package/packages/policy/src/server.ts +3 -0
- package/packages/signer/package.json +2 -2
- package/packages/signer/src/server.ts +18 -2
- package/test-db.ts +3 -0
- package/packages/dashboard/dist/assets/index-BTP1WrFj.js +0 -194
- package/packages/dashboard/package-lock.json +0 -2748
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.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
|
+
## [1.6.4]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Node.js Native Database Engine**: Migrated the core `logger.ts` memory subsystem to use the built-in `node:sqlite` engine (Node 22+), maintaining ultra-fast 100% synchronous operations while dramatically reducing dependency bloat.
|
|
12
|
+
- **Next-Gen OS Keyring (N-API)**: Migrated `keytar` to `@napi-rs/keyring`. This replaces legacy C++ bindings with modern Rust/NAPI-RS, retaining identical OS-level security (Mac Keychain, Windows Credential Manager) while eliminating the `prebuild-install` deprecation warning and streamlining global installation.
|
|
13
|
+
|
|
14
|
+
### Removed
|
|
15
|
+
- `better-sqlite3` and `keytar` dependencies entirely removed from the monorepo architecture.
|
|
16
|
+
|
|
17
|
+
## [1.6.3]
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- Implemented **Zero-Click Multi-Session** for instantaneous chat creation and switching.
|
|
21
|
+
- Introduced **Smart Auto-Naming** for automatic contextual session titles.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- **Redesigned Sidebar Architecture**: enhanced utility-centric design, significantly reducing gaps for a compact, elegant look.
|
|
25
|
+
- Integrated **OS-Native Keyring**, replacing legacy AES-256-GCM and Master Password mechanics.
|
|
26
|
+
- Updated and cleaned up legacy cryptography references in VitePress guides and README.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- Resolved deeply-nested monorepo CI/CD deployment failures by isolating `package-lock.json` and mitigating peer-dependency conflicts.
|
|
30
|
+
|
|
8
31
|
## [1.4.5]
|
|
9
32
|
|
|
10
33
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# Nyxora Agent 🤖
|
|
2
2
|
**Production-Grade Secure AI Execution Framework for Web3 Agents.**
|
|
3
3
|
|
|
4
|
-
[](https://github.com/perasyudha/Nyxora)
|
|
5
|
+
[](#)
|
|
5
6
|
[](https://opensource.org/licenses/MIT)
|
|
6
7
|
[](#️-advanced-security-threat-model)
|
|
7
8
|
[](#️-advanced-security-threat-model)
|
|
8
9
|
[](#️-advanced-security-threat-model)
|
|
9
10
|
|
|
10
|
-
Nyxora (v1.6.
|
|
11
|
+
Nyxora (v1.6.5) is a **secure, non-custodial runtime infrastructure for autonomous onchain agents** built with a robust Monorepo architecture (Node.js & React). Designed for autonomous workflows with a premium Glassmorphism UI dashboard and strict client-side key isolation.
|
|
12
|
+
|
|
13
|
+
**Nyxora now natively supports the Model Context Protocol (MCP)**. You can transform your external AI agents (like Claude Desktop and Cursor) into secure Web3 actors that execute swaps and fetch balances using Nyxora's secure signer vault. [View the MCP Integration Guide](https://perasyudha.github.io/Nyxora/guide/mcp-integration)
|
|
11
14
|
|
|
12
15
|
It operates under an institutional-grade **Cryptographically Bound Human-in-the-Loop** execution model, ensuring that Remote AIs (LLMs) never have unilateral access to your funds.
|
|
13
16
|
|
|
@@ -15,7 +18,7 @@ It operates under an institutional-grade **Cryptographically Bound Human-in-the-
|
|
|
15
18
|
|
|
16
19
|
## 🔥 Key Features
|
|
17
20
|
|
|
18
|
-
### Advanced Security Architecture
|
|
21
|
+
### Advanced Security Architecture
|
|
19
22
|
* **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).
|
|
20
23
|
* **Cryptographically Bound Approval**: Policy changes and transactions requested by the AI are drafted as hashes (`sha256`). Approval via the UI requires a challenge nonce, preventing Man-in-the-Middle (MITM) attacks.
|
|
21
24
|
* **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.
|
|
@@ -111,5 +114,12 @@ For complete technical deep-dives into our Cryptographic Architecture, please vi
|
|
|
111
114
|
|
|
112
115
|
*(Includes guides on Secure Wallet Imports, Architecture Blueprints, Troubleshooting, and Custom Skill Development).*
|
|
113
116
|
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
**❤️ Support the Project**
|
|
120
|
+
|
|
121
|
+
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:
|
|
122
|
+
- **EVM:** `0x18a30d5db50d287dba669c5672cd71246cc4c4c6`
|
|
123
|
+
|
|
114
124
|
---
|
|
115
125
|
**License:** MIT License
|
package/launcher.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { initSafeLogger } from './packages/core/src/utils/safeLogger';
|
|
2
|
+
initSafeLogger();
|
|
3
|
+
|
|
1
4
|
import { spawn } from 'child_process';
|
|
2
5
|
import crypto from 'crypto';
|
|
3
6
|
import fs from 'fs';
|
|
@@ -6,6 +9,12 @@ import path from 'path';
|
|
|
6
9
|
const INTERNAL_AUTH_TOKEN = crypto.randomBytes(64).toString('hex');
|
|
7
10
|
console.log(`[Launcher] Generated Internal Auth Token: ${INTERNAL_AUTH_TOKEN.substring(0, 8)}...`);
|
|
8
11
|
|
|
12
|
+
const nyxoraDir = path.join(process.env.HOME || process.env.USERPROFILE || '', '.nyxora');
|
|
13
|
+
if (!fs.existsSync(nyxoraDir)) fs.mkdirSync(nyxoraDir, { recursive: true, mode: 0o700 });
|
|
14
|
+
const tokenPath = path.join(nyxoraDir, 'runtime.token');
|
|
15
|
+
fs.writeFileSync(tokenPath, INTERNAL_AUTH_TOKEN, { mode: 0o600 });
|
|
16
|
+
console.log(`[Launcher] Secured runtime token at ${tokenPath} (0600)`);
|
|
17
|
+
|
|
9
18
|
const env = {
|
|
10
19
|
...process.env,
|
|
11
20
|
INTERNAL_AUTH_TOKEN,
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nyxora",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
"packages/*"
|
|
7
7
|
],
|
|
8
8
|
"bin": {
|
|
9
|
-
"nyxora": "
|
|
9
|
+
"nyxora": "bin/nyxora.mjs"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"start": "node ./bin/nyxora.mjs start",
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@clack/prompts": "^1.4.0",
|
|
22
|
-
"better-sqlite3": "^12.10.0",
|
|
23
22
|
"concurrently": "^9.2.1",
|
|
24
23
|
"cors": "^2.8.6",
|
|
25
24
|
"dotenv": "^17.4.2",
|
|
@@ -27,7 +26,7 @@
|
|
|
27
26
|
"express-rate-limit": "^7.5.0",
|
|
28
27
|
"helmet": "^8.0.0",
|
|
29
28
|
"jsonwebtoken": "^9.0.2",
|
|
30
|
-
"
|
|
29
|
+
"@napi-rs/keyring": "^1.3.0",
|
|
31
30
|
"open": "^11.0.0",
|
|
32
31
|
"openai": "^6.39.0",
|
|
33
32
|
"picocolors": "^1.1.1",
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
3
|
-
"version": "1.6.
|
|
2
|
+
"name": "nyxora-agent-core",
|
|
3
|
+
"version": "1.6.5",
|
|
4
4
|
"private": true,
|
|
5
5
|
"main": "src/gateway/server.ts",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@clack/prompts": "^1.4.0",
|
|
8
|
-
"better-sqlite3": "^12.10.0",
|
|
9
8
|
"cors": "^2.8.6",
|
|
10
9
|
"express": "^5.2.1",
|
|
11
10
|
"express-rate-limit": "^7.5.0",
|
|
@@ -284,8 +284,9 @@ Provider: ${config.llm.provider}`;
|
|
|
284
284
|
// Save Private Key to OS Keyring or fallback to .env
|
|
285
285
|
if (privateKey) {
|
|
286
286
|
try {
|
|
287
|
-
const
|
|
288
|
-
|
|
287
|
+
const { Entry } = require('@napi-rs/keyring');
|
|
288
|
+
const entry = new Entry('nyxora', 'wallet');
|
|
289
|
+
await entry.setPassword(privateKey as string);
|
|
289
290
|
console.log(pc.green('Private key saved securely to OS Keyring.'));
|
|
290
291
|
} catch (error) {
|
|
291
292
|
console.warn(pc.yellow('Failed to save to OS Keyring (Module mismatch or headless server). Falling back to local vault.key'));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import crypto from 'crypto';
|
|
4
|
-
import
|
|
4
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
5
5
|
import { loadConfig } from '../config/parser';
|
|
6
6
|
import { getPath } from '../config/paths';
|
|
7
7
|
|
|
@@ -21,7 +21,7 @@ export interface ChatSession {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export class Logger {
|
|
24
|
-
private db:
|
|
24
|
+
private db: DatabaseSync;
|
|
25
25
|
|
|
26
26
|
constructor() {
|
|
27
27
|
const config = loadConfig() || {};
|
|
@@ -37,7 +37,7 @@ export class Logger {
|
|
|
37
37
|
fs.mkdirSync(dir, { recursive: true });
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
this.db = new
|
|
40
|
+
this.db = new DatabaseSync(fullPath);
|
|
41
41
|
this.initDb();
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -86,17 +86,24 @@ export class Logger {
|
|
|
86
86
|
VALUES (@role, @content, @name, @tool_call_id, @tool_calls)
|
|
87
87
|
`);
|
|
88
88
|
|
|
89
|
-
const insertMany =
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
89
|
+
const insertMany = (entries: any[]) => {
|
|
90
|
+
this.db.exec('BEGIN TRANSACTION');
|
|
91
|
+
try {
|
|
92
|
+
for (const entry of entries) {
|
|
93
|
+
insert.run({
|
|
94
|
+
role: entry.role,
|
|
95
|
+
content: entry.content || '',
|
|
96
|
+
name: entry.name || null,
|
|
97
|
+
tool_call_id: entry.tool_call_id || null,
|
|
98
|
+
tool_calls: entry.tool_calls ? JSON.stringify(entry.tool_calls) : null
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
this.db.exec('COMMIT');
|
|
102
|
+
} catch (e) {
|
|
103
|
+
this.db.exec('ROLLBACK');
|
|
104
|
+
throw e;
|
|
98
105
|
}
|
|
99
|
-
}
|
|
106
|
+
};
|
|
100
107
|
|
|
101
108
|
insertMany(oldMemory);
|
|
102
109
|
console.log('[Nyxora Memory] Successfully migrated memory.json to SQLite database (Atomic Storage).');
|
|
@@ -112,7 +119,7 @@ export class Logger {
|
|
|
112
119
|
|
|
113
120
|
public getSessions(): ChatSession[] {
|
|
114
121
|
const rows = this.db.prepare('SELECT id, title, timestamp FROM sessions ORDER BY timestamp DESC').all();
|
|
115
|
-
return rows as ChatSession[];
|
|
122
|
+
return rows as unknown as ChatSession[];
|
|
116
123
|
}
|
|
117
124
|
|
|
118
125
|
public createSession(title: string): string {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initSafeLogger = initSafeLogger;
|
|
4
|
+
exports.safeLog = safeLog;
|
|
5
|
+
exports.safeError = safeError;
|
|
6
|
+
exports.safeWarn = safeWarn;
|
|
7
|
+
const PRIVATE_KEY_REGEX = /0x[a-fA-F0-9]{64}/g;
|
|
8
|
+
const JWT_REGEX = /eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/g;
|
|
9
|
+
function sanitize(args) {
|
|
10
|
+
return args.map(arg => {
|
|
11
|
+
if (typeof arg === 'string') {
|
|
12
|
+
return arg
|
|
13
|
+
.replace(PRIVATE_KEY_REGEX, '[REDACTED_PRIVATE_KEY]')
|
|
14
|
+
.replace(JWT_REGEX, '[REDACTED_JWT]');
|
|
15
|
+
}
|
|
16
|
+
if (arg instanceof Error) {
|
|
17
|
+
const sanitizedError = new Error(arg.message
|
|
18
|
+
.replace(PRIVATE_KEY_REGEX, '[REDACTED_PRIVATE_KEY]')
|
|
19
|
+
.replace(JWT_REGEX, '[REDACTED_JWT]'));
|
|
20
|
+
sanitizedError.stack = arg.stack?.replace(PRIVATE_KEY_REGEX, '[REDACTED_PRIVATE_KEY]').replace(JWT_REGEX, '[REDACTED_JWT]');
|
|
21
|
+
return sanitizedError;
|
|
22
|
+
}
|
|
23
|
+
if (typeof arg === 'object' && arg !== null) {
|
|
24
|
+
try {
|
|
25
|
+
const str = JSON.stringify(arg);
|
|
26
|
+
const sanitizedStr = str
|
|
27
|
+
.replace(PRIVATE_KEY_REGEX, '[REDACTED_PRIVATE_KEY]')
|
|
28
|
+
.replace(JWT_REGEX, '[REDACTED_JWT]');
|
|
29
|
+
return JSON.parse(sanitizedStr);
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
return arg;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return arg;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const originalLog = console.log.bind(console);
|
|
39
|
+
const originalError = console.error.bind(console);
|
|
40
|
+
const originalWarn = console.warn.bind(console);
|
|
41
|
+
function initSafeLogger() {
|
|
42
|
+
// @ts-ignore
|
|
43
|
+
if (console.__isSafe)
|
|
44
|
+
return;
|
|
45
|
+
console.log = (...args) => originalLog(...sanitize(args));
|
|
46
|
+
console.error = (...args) => originalError(...sanitize(args));
|
|
47
|
+
console.warn = (...args) => originalWarn(...sanitize(args));
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
console.__isSafe = true;
|
|
50
|
+
}
|
|
51
|
+
function safeLog(...args) {
|
|
52
|
+
originalLog(...sanitize(args));
|
|
53
|
+
}
|
|
54
|
+
function safeError(...args) {
|
|
55
|
+
originalError(...sanitize(args));
|
|
56
|
+
}
|
|
57
|
+
function safeWarn(...args) {
|
|
58
|
+
originalWarn(...sanitize(args));
|
|
59
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const PRIVATE_KEY_REGEX = /0x[a-fA-F0-9]{64}/g;
|
|
2
|
+
const JWT_REGEX = /eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/g;
|
|
3
|
+
|
|
4
|
+
function sanitize(args: any[]): any[] {
|
|
5
|
+
return args.map(arg => {
|
|
6
|
+
if (typeof arg === 'string') {
|
|
7
|
+
return arg
|
|
8
|
+
.replace(PRIVATE_KEY_REGEX, '[REDACTED_PRIVATE_KEY]')
|
|
9
|
+
.replace(JWT_REGEX, '[REDACTED_JWT]');
|
|
10
|
+
}
|
|
11
|
+
if (arg instanceof Error) {
|
|
12
|
+
const sanitizedError = new Error(arg.message
|
|
13
|
+
.replace(PRIVATE_KEY_REGEX, '[REDACTED_PRIVATE_KEY]')
|
|
14
|
+
.replace(JWT_REGEX, '[REDACTED_JWT]')
|
|
15
|
+
);
|
|
16
|
+
sanitizedError.stack = arg.stack?.replace(PRIVATE_KEY_REGEX, '[REDACTED_PRIVATE_KEY]').replace(JWT_REGEX, '[REDACTED_JWT]');
|
|
17
|
+
return sanitizedError;
|
|
18
|
+
}
|
|
19
|
+
if (typeof arg === 'object' && arg !== null) {
|
|
20
|
+
try {
|
|
21
|
+
const str = JSON.stringify(arg);
|
|
22
|
+
const sanitizedStr = str
|
|
23
|
+
.replace(PRIVATE_KEY_REGEX, '[REDACTED_PRIVATE_KEY]')
|
|
24
|
+
.replace(JWT_REGEX, '[REDACTED_JWT]');
|
|
25
|
+
return JSON.parse(sanitizedStr);
|
|
26
|
+
} catch (e) {
|
|
27
|
+
return arg;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return arg;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const originalLog = console.log.bind(console);
|
|
35
|
+
const originalError = console.error.bind(console);
|
|
36
|
+
const originalWarn = console.warn.bind(console);
|
|
37
|
+
|
|
38
|
+
export function initSafeLogger() {
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
if (console.__isSafe) return;
|
|
41
|
+
|
|
42
|
+
console.log = (...args: any[]) => originalLog(...sanitize(args));
|
|
43
|
+
console.error = (...args: any[]) => originalError(...sanitize(args));
|
|
44
|
+
console.warn = (...args: any[]) => originalWarn(...sanitize(args));
|
|
45
|
+
|
|
46
|
+
// @ts-ignore
|
|
47
|
+
console.__isSafe = true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function safeLog(...args: any[]) {
|
|
51
|
+
originalLog(...sanitize(args));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function safeError(...args: any[]) {
|
|
55
|
+
originalError(...sanitize(args));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function safeWarn(...args: any[]) {
|
|
59
|
+
originalWarn(...sanitize(args));
|
|
60
|
+
}
|