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 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
- [![Version](https://img.shields.io/badge/version-1.6.3-blue.svg)](https://github.com/perasyudha/Nyxora)
4
+ [![Version](https://img.shields.io/badge/version-1.6.5-blue.svg)](https://github.com/perasyudha/Nyxora)
5
+ [![MCP Supported](https://img.shields.io/badge/MCP-Supported-blue.svg)](#)
5
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
7
  [![Security: Production-Grade](https://img.shields.io/badge/Security-Production--Grade-blue.svg)](#️-advanced-security-threat-model)
7
8
  [![Execution: Cryptographic Approval](https://img.shields.io/badge/Execution-Cryptographic--Approval-orange.svg)](#️-advanced-security-threat-model)
8
9
  [![Privacy: Local-Only Keys](https://img.shields.io/badge/Privacy-Local--Only--Keys-success.svg)](#️-advanced-security-threat-model)
9
10
 
10
- Nyxora (v1.6.3) 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.
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 (v1.6.3)
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",
3
+ "version": "1.6.5",
4
4
  "license": "MIT",
5
5
  "workspaces": [
6
6
  "packages/*"
7
7
  ],
8
8
  "bin": {
9
- "nyxora": "./bin/nyxora.mjs"
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
- "keytar": "^7.9.0",
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": "@nyxora/core",
3
- "version": "1.6.3",
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",
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { initSafeLogger } from '../utils/safeLogger';
4
+ initSafeLogger();
5
+
3
6
  import fs from 'fs';
4
7
  import path from 'path';
5
8
  import os from 'os';
@@ -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 keytar = require('keytar');
288
- await keytar.setPassword('nyxora', 'wallet', privateKey as string);
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 Database from 'better-sqlite3';
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: Database.Database;
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 Database(fullPath);
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 = this.db.transaction((entries: any[]) => {
90
- for (const entry of entries) {
91
- insert.run({
92
- role: entry.role,
93
- content: entry.content || '',
94
- name: entry.name || null,
95
- tool_call_id: entry.tool_call_id || null,
96
- tool_calls: entry.tool_calls ? JSON.stringify(entry.tool_calls) : null
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
+ }