nyxora 26.7.2 → 26.7.4
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 +112 -47
- package/README.md +25 -21
- package/bin/nyxora.mjs +4 -6
- package/dist/launcher.js +44 -8
- package/dist/packages/core/src/agent/bridgeWatcher.js +3 -2
- package/dist/packages/core/src/agent/cronManager.js +2 -2
- package/dist/packages/core/src/agent/llmProvider.js +245 -0
- package/dist/packages/core/src/agent/nyxDaemon.js +97 -0
- package/dist/packages/core/src/agent/osAgent.js +351 -29
- package/dist/packages/core/src/agent/reasoning.js +353 -60
- package/dist/packages/core/src/agent/reasoningScratchpad.js +47 -0
- package/dist/packages/core/src/agent/transactionManager.js +36 -31
- package/dist/packages/core/src/agent/web3Agent.js +263 -37
- package/dist/packages/core/src/cognitive/cognitiveManager.js +63 -10
- package/dist/packages/core/src/config/parser.js +10 -4
- package/dist/packages/core/src/gateway/chat.js +56 -13
- package/dist/packages/core/src/gateway/cli.js +3 -0
- package/dist/packages/core/src/gateway/discordAdapter.js +81 -0
- package/dist/packages/core/src/gateway/googleAuthModule.js +2 -0
- package/dist/packages/core/src/gateway/server.js +58 -9
- package/dist/packages/core/src/gateway/setup-ml.js +64 -0
- package/dist/packages/core/src/gateway/setup.js +39 -3
- package/dist/packages/core/src/gateway/telegram.js +123 -27
- package/dist/packages/core/src/memory/episodic.js +58 -3
- package/dist/packages/core/src/memory/logger.js +120 -2
- package/dist/packages/core/src/memory/promotionEngine.js +18 -5
- package/dist/packages/core/src/system/agentskills.js +10 -0
- package/dist/packages/core/src/system/plugins/GoogleWorkspacePlugin.js +10 -2
- package/dist/packages/core/src/system/plugins/SystemCorePlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemExternalPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemPluginInstallerPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemSocialPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemWebPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemWorkspacePlugin.js +3 -3
- package/dist/packages/core/src/system/plugins/createSkill.js +1 -1
- package/dist/packages/core/src/system/skillExtractor.js +16 -5
- package/dist/packages/core/src/system/skills/executeShell.js +31 -4
- package/dist/packages/core/src/system/skills/forgetMemory.js +6 -4
- package/dist/packages/core/src/system/skills/googleWorkspace.js +106 -1
- package/dist/packages/core/src/system/skills/scheduleTask.js +7 -2
- package/dist/packages/core/src/system/skills/searchWeb.js +13 -6
- package/dist/packages/core/src/test_mainnet.js +45 -0
- package/dist/packages/core/src/utils/contextSummarizer.js +82 -0
- package/dist/packages/core/src/utils/skillManager.js +1 -1
- package/dist/packages/core/src/utils/streamSimulator.js +85 -0
- package/dist/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.js +28 -11
- package/dist/packages/core/src/web3/aggregator/providers/OpBridgeProvider.js +41 -27
- package/dist/packages/core/src/web3/aggregator/providers/TestnetSwapProvider.js +65 -0
- package/dist/packages/core/src/web3/aggregator/routeSelector.js +7 -1
- package/dist/packages/core/src/web3/plugins/Web3DefiPlugin.js +1 -1
- package/dist/packages/core/src/web3/plugins/Web3MarketPlugin.js +5 -125
- package/dist/packages/core/src/web3/plugins/Web3SecurityPlugin.js +1 -1
- package/dist/packages/core/src/web3/plugins/Web3WalletPlugin.js +1 -1
- package/dist/packages/core/src/web3/skills/bridgeToken.js +19 -4
- package/dist/packages/core/src/web3/skills/checkAddress.js +2 -0
- package/dist/packages/core/src/web3/skills/checkPortfolio.js +22 -2
- package/dist/packages/core/src/web3/skills/checkSecurity.js +2 -0
- package/dist/packages/core/src/web3/skills/confirmPendingTx.js +1 -1
- package/dist/packages/core/src/web3/skills/createLimitOrder.js +15 -1
- package/dist/packages/core/src/web3/skills/customTx.js +3 -0
- package/dist/packages/core/src/web3/skills/defiLending.js +2 -0
- package/dist/packages/core/src/web3/skills/getBalance.js +2 -0
- package/dist/packages/core/src/web3/skills/getPrice.js +134 -27
- package/dist/packages/core/src/web3/skills/getTxHistory.js +2 -0
- package/dist/packages/core/src/web3/skills/marketAnalysis.js +28 -191
- package/dist/packages/core/src/web3/skills/mintNft.js +3 -0
- package/dist/packages/core/src/web3/skills/provideLiquidity.js +16 -12
- package/dist/packages/core/src/web3/skills/revokeApprovals.js +2 -0
- package/dist/packages/core/src/web3/skills/swapToken.js +20 -2
- package/dist/packages/core/src/web3/skills/transfer.js +2 -0
- package/dist/packages/core/src/web3/skills/yieldVault.js +2 -0
- package/dist/packages/core/src/web3/utils/chains.js +19 -0
- package/dist/packages/core/src/web3/utils/marketEngine.js +26 -33
- package/dist/packages/signer/src/NyxoraSigner.js +181 -0
- package/dist/packages/signer/src/index.js +17 -0
- package/dist/packages/signer/src/server.js +25 -161
- package/launcher.ts +38 -9
- package/package.json +8 -3
- package/packages/core/package.json +21 -10
- package/packages/core/src/agent/bridgeWatcher.ts +3 -2
- package/packages/core/src/agent/cronManager.ts +2 -2
- package/packages/core/src/agent/llmProvider.ts +221 -0
- package/packages/core/src/agent/nyxDaemon.ts +104 -0
- package/packages/core/src/agent/osAgent.ts +381 -32
- package/packages/core/src/agent/reasoning.ts +376 -64
- package/packages/core/src/agent/reasoningScratchpad.ts +45 -0
- package/packages/core/src/agent/transactionManager.ts +36 -28
- package/packages/core/src/agent/web3Agent.ts +291 -40
- package/packages/core/src/cognitive/cognitiveManager.ts +65 -10
- package/packages/core/src/cognitive/prompts/web3/market-analysis.md +24 -0
- package/packages/core/src/cognitive/prompts/web3/portfolio-review.md +29 -0
- package/packages/core/src/cognitive/prompts/web3/risk-assessment.md +28 -0
- package/packages/core/src/cognitive/prompts/web3/trade-planning.md +30 -0
- package/packages/core/src/config/parser.ts +15 -4
- package/packages/core/src/gateway/chat.ts +57 -15
- package/packages/core/src/gateway/cli.ts +4 -0
- package/packages/core/src/gateway/discordAdapter.ts +87 -0
- package/packages/core/src/gateway/googleAuthModule.ts +2 -0
- package/packages/core/src/gateway/server.ts +66 -10
- package/packages/core/src/gateway/setup-ml.ts +68 -0
- package/packages/core/src/gateway/setup.ts +41 -3
- package/packages/core/src/gateway/telegram.ts +141 -30
- package/packages/core/src/memory/episodic.ts +76 -3
- package/packages/core/src/memory/logger.ts +142 -2
- package/packages/core/src/memory/promotionEngine.ts +19 -5
- package/packages/core/src/system/agentskills.ts +10 -0
- package/packages/core/src/system/plugins/GoogleWorkspacePlugin.ts +15 -3
- package/packages/core/src/system/plugins/SystemCorePlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemExternalPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemPluginInstallerPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemSocialPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemWebPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemWorkspacePlugin.ts +3 -3
- package/packages/core/src/system/plugins/createSkill.ts +1 -1
- package/packages/core/src/system/skillExtractor.ts +16 -5
- package/packages/core/src/system/skills/executeShell.ts +38 -7
- package/packages/core/src/system/skills/forgetMemory.ts +7 -4
- package/packages/core/src/system/skills/googleWorkspace.ts +109 -0
- package/packages/core/src/system/skills/scheduleTask.ts +7 -2
- package/packages/core/src/system/skills/searchWeb.ts +12 -6
- package/packages/core/src/utils/contextSummarizer.ts +100 -0
- package/packages/core/src/utils/skillManager.ts +1 -1
- package/packages/core/src/utils/streamSimulator.ts +88 -0
- package/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.ts +30 -11
- package/packages/core/src/web3/aggregator/providers/OpBridgeProvider.ts +43 -29
- package/packages/core/src/web3/aggregator/routeSelector.ts +6 -1
- package/packages/core/src/web3/plugins/Web3DefiPlugin.ts +1 -1
- package/packages/core/src/web3/plugins/Web3MarketPlugin.ts +6 -125
- package/packages/core/src/web3/plugins/Web3SecurityPlugin.ts +1 -1
- package/packages/core/src/web3/plugins/Web3WalletPlugin.ts +1 -1
- package/packages/core/src/web3/skills/bridgeToken.ts +21 -7
- package/packages/core/src/web3/skills/checkAddress.ts +2 -0
- package/packages/core/src/web3/skills/checkPortfolio.ts +23 -2
- package/packages/core/src/web3/skills/checkSecurity.ts +2 -0
- package/packages/core/src/web3/skills/confirmPendingTx.ts +1 -1
- package/packages/core/src/web3/skills/createLimitOrder.ts +17 -2
- package/packages/core/src/web3/skills/customTx.ts +3 -0
- package/packages/core/src/web3/skills/defiLending.ts +2 -0
- package/packages/core/src/web3/skills/getBalance.ts +2 -0
- package/packages/core/src/web3/skills/getPrice.ts +134 -30
- package/packages/core/src/web3/skills/getTxHistory.ts +2 -0
- package/packages/core/src/web3/skills/marketAnalysis.ts +45 -188
- package/packages/core/src/web3/skills/mintNft.ts +3 -0
- package/packages/core/src/web3/skills/provideLiquidity.ts +16 -10
- package/packages/core/src/web3/skills/revokeApprovals.ts +2 -0
- package/packages/core/src/web3/skills/swapToken.ts +20 -3
- package/packages/core/src/web3/skills/transfer.ts +2 -0
- package/packages/core/src/web3/skills/yieldVault.ts +2 -0
- package/packages/core/src/web3/utils/chains.ts +12 -0
- package/packages/core/src/web3/utils/marketEngine.ts +27 -33
- package/packages/dashboard/dist/assets/index-Czxksiao.js +18 -0
- package/packages/dashboard/dist/assets/index-DK2sTU47.css +1 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/package.json +10 -10
- package/packages/mcp-server/dist/server.js +5 -1
- package/packages/mcp-server/package.json +6 -6
- package/packages/mcp-server/src/server.ts +11 -7
- package/packages/ml-engine/__pycache__/config.cpython-313.pyc +0 -0
- package/packages/ml-engine/__pycache__/main.cpython-313.pyc +0 -0
- package/packages/ml-engine/config.py +59 -0
- package/packages/ml-engine/main.py +34 -0
- package/packages/ml-engine/requirements.txt +22 -0
- package/packages/ml-engine/routers/__init__.py +1 -0
- package/packages/ml-engine/routers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/packages/ml-engine/routers/__pycache__/cognitive.cpython-313.pyc +0 -0
- package/packages/ml-engine/routers/__pycache__/critic.cpython-313.pyc +0 -0
- package/packages/ml-engine/routers/__pycache__/llm.cpython-313.pyc +0 -0
- package/packages/ml-engine/routers/__pycache__/market.cpython-313.pyc +0 -0
- package/packages/ml-engine/routers/__pycache__/memory.cpython-313.pyc +0 -0
- package/packages/ml-engine/routers/cognitive.py +98 -0
- package/packages/ml-engine/routers/critic.py +111 -0
- package/packages/ml-engine/routers/llm.py +38 -0
- package/packages/ml-engine/routers/market.py +332 -0
- package/packages/ml-engine/routers/memory.py +125 -0
- package/packages/policy/package.json +3 -3
- package/packages/signer/package.json +16 -6
- package/packages/signer/src/NyxoraSigner.ts +161 -0
- package/packages/signer/src/index.ts +1 -0
- package/packages/signer/src/server.ts +25 -135
- package/dist/packages/core/src/agent/honchoDaemon.js +0 -91
- package/dist/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -54
- package/dist/packages/core/src/gateway/test.js +0 -15
- package/dist/packages/core/src/web3/Web3DefiPlugin.js +0 -28
- package/dist/packages/core/src/web3/aggregator/aggregatorMainnet.js +0 -260
- package/dist/packages/core/src/web3/aggregator/aggregatorTestnet.js +0 -119
- package/dist/packages/core/src/web3/skills/nativeOpBridge.js +0 -71
- package/packages/core/src/agent/honchoDaemon.ts +0 -96
- package/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -41
- package/packages/core/src/plugin/registry.test.ts +0 -46
- package/packages/core/src/utils/formatter.test.ts +0 -41
- package/packages/dashboard/dist/assets/index-CSoNa5cx.css +0 -1
- package/packages/dashboard/dist/assets/index-DbRWEoSr.js +0 -16
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Market Analysis Skill
|
|
2
|
+
|
|
3
|
+
<skill_instructions>
|
|
4
|
+
You are now in Market Analysis Mode. Apply this structured framework before forming any market opinion:
|
|
5
|
+
|
|
6
|
+
1. PRICE ACTION: Assess the current price vs MA50. Is it trading above (bullish) or below (bearish)? By what percentage?
|
|
7
|
+
|
|
8
|
+
2. MOMENTUM (RSI):
|
|
9
|
+
- RSI > 70: Overbought — warn user, suggest caution or partial exit.
|
|
10
|
+
- RSI < 30: Oversold — potential entry opportunity, confirm with volume.
|
|
11
|
+
- RSI 40-60: Neutral — wait for a breakout signal.
|
|
12
|
+
|
|
13
|
+
3. MULTI-EXCHANGE CONSENSUS: If momentum data comes from multiple exchanges, weight your signal by how many agreed. 3+ exchanges aligned = high conviction signal.
|
|
14
|
+
|
|
15
|
+
4. LIQUIDITY CHECK: Low liquidity (<$50k) = high manipulation risk. Always flag this explicitly.
|
|
16
|
+
|
|
17
|
+
5. CONFIDENCE DECLARATION: At the end of your analysis, always state:
|
|
18
|
+
- `Signal: [BULLISH / BEARISH / NEUTRAL]`
|
|
19
|
+
- `Conviction: [HIGH / MEDIUM / LOW]`
|
|
20
|
+
- `Reason: one sentence`
|
|
21
|
+
|
|
22
|
+
NEVER give a recommendation without stating the signal and conviction level.
|
|
23
|
+
NEVER fabricate price data — always call analyze_market tool first.
|
|
24
|
+
</skill_instructions>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Portfolio Review Skill
|
|
2
|
+
|
|
3
|
+
<skill_instructions>
|
|
4
|
+
You are now in Portfolio Review Mode. Follow this structured review process:
|
|
5
|
+
|
|
6
|
+
1. FETCH PORTFOLIO: Always call check_portfolio first. Never guess holdings.
|
|
7
|
+
|
|
8
|
+
2. ASSET BREAKDOWN:
|
|
9
|
+
- List all assets with: token, quantity, USD value, % of portfolio
|
|
10
|
+
- Identify the top 3 positions by value
|
|
11
|
+
|
|
12
|
+
3. CONCENTRATION ANALYSIS:
|
|
13
|
+
- If any single asset > 50% of portfolio: flag as OVER-CONCENTRATED. Suggest diversification.
|
|
14
|
+
- If all assets on 1 chain: flag as CHAIN RISK. Suggest cross-chain diversification.
|
|
15
|
+
|
|
16
|
+
4. PERFORMANCE TRIAGE (if price change data available):
|
|
17
|
+
- Assets down >20% in 24h: flag for review — "is this a dip or a dump?"
|
|
18
|
+
- Assets up >30% in 24h: flag for partial profit-taking consideration
|
|
19
|
+
|
|
20
|
+
5. REBALANCING SUGGESTION:
|
|
21
|
+
- If user asks "should I rebalance?", suggest based on their risk_level from user profile.
|
|
22
|
+
- Conservative: target 60% stable / 40% volatile
|
|
23
|
+
- Moderate: 40% stable / 60% volatile
|
|
24
|
+
- Aggressive: 20% stable / 80% volatile
|
|
25
|
+
|
|
26
|
+
6. ACTIONABLE SUMMARY: End with a bullet list of max 3 concrete actions user can take now.
|
|
27
|
+
|
|
28
|
+
NEVER fabricate portfolio values. Always use live data from tools.
|
|
29
|
+
</skill_instructions>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Risk Assessment Skill
|
|
2
|
+
|
|
3
|
+
<skill_instructions>
|
|
4
|
+
You are now in Risk Assessment Mode. Evaluate risk systematically before advising any action:
|
|
5
|
+
|
|
6
|
+
1. LIQUIDITY RISK: Score from market data.
|
|
7
|
+
- Score < 3: CRITICAL — warn strongly. Token can be rugged or dumped.
|
|
8
|
+
- Score 3-6: MODERATE — acceptable for small positions only.
|
|
9
|
+
- Score > 6: LOW — standard caution applies.
|
|
10
|
+
|
|
11
|
+
2. CONCENTRATION RISK:
|
|
12
|
+
- Top 10 holders > 60%: HIGH manipulation risk. Explicitly warn.
|
|
13
|
+
- Top 10 holders 30-60%: MODERATE. Note it.
|
|
14
|
+
- Top 10 holders < 30%: DISTRIBUTED. Safer.
|
|
15
|
+
|
|
16
|
+
3. MOMENTUM RISK (RSI):
|
|
17
|
+
- Overbought (>70): Chasing risk. User is buying at a local top.
|
|
18
|
+
- Oversold (<30): Could be a falling knife. Ask if user has conviction.
|
|
19
|
+
|
|
20
|
+
4. SECURITY CHECK: If contract address is provided, ALWAYS call check_token_security before advising entry.
|
|
21
|
+
|
|
22
|
+
5. POSITION SIZE GUIDANCE (based on overall risk score):
|
|
23
|
+
- Overall < 4: "This is high-risk. Position size should be < 1% of portfolio."
|
|
24
|
+
- Overall 4-7: "This is moderate-risk. Max 3-5% portfolio allocation."
|
|
25
|
+
- Overall > 7: "This is lower-risk. Standard 5-10% allocation is reasonable."
|
|
26
|
+
|
|
27
|
+
MANDATORY: Always end risk assessment with a 1-line "Risk Verdict" before any recommendation.
|
|
28
|
+
</skill_instructions>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Trade Planning Skill
|
|
2
|
+
|
|
3
|
+
<skill_instructions>
|
|
4
|
+
You are now in Trade Planning Mode. Before executing or recommending any trade, build an explicit plan:
|
|
5
|
+
|
|
6
|
+
1. DEFINE THE THESIS: In one sentence, why does this trade make sense right now? (e.g., "RSI oversold + price above MA50 = momentum recovery play")
|
|
7
|
+
|
|
8
|
+
2. ENTRY PLAN:
|
|
9
|
+
- Suggested entry price / range
|
|
10
|
+
- Entry type: market vs. limit (prefer limit for DEX to avoid slippage)
|
|
11
|
+
|
|
12
|
+
3. EXIT PLAN (MANDATORY — never plan entry without exit):
|
|
13
|
+
- Take profit target: at what price? What % gain?
|
|
14
|
+
- Stop loss: at what price? What % drawdown is acceptable?
|
|
15
|
+
- Time-based exit: if no movement in X days, reassess
|
|
16
|
+
|
|
17
|
+
4. POSITION SIZE: Based on risk profile. Never suggest more than the user's stated risk tolerance.
|
|
18
|
+
|
|
19
|
+
5. EXECUTION SEQUENCE:
|
|
20
|
+
- If swap: confirm chain, token pair, slippage tolerance before calling swap_token.
|
|
21
|
+
- If bridge: confirm source chain, destination chain, and estimated fees.
|
|
22
|
+
- If limit order: use create_limit_order, not swap_token.
|
|
23
|
+
|
|
24
|
+
6. FINAL SANITY CHECK before calling any execution tool:
|
|
25
|
+
- "Am I buying a honeypot?" → if contract address, call check_token_security first.
|
|
26
|
+
- "Is liquidity sufficient?" → check liquidityUsd from market data.
|
|
27
|
+
- "Am I OK with the fee?" → confirm gas estimate with user if >$5.
|
|
28
|
+
|
|
29
|
+
DO NOT execute any trade without completing steps 1-3 first.
|
|
30
|
+
</skill_instructions>
|
|
@@ -79,7 +79,9 @@ export function loadRpcConfig(): Record<string, string | string[]> {
|
|
|
79
79
|
export function saveRpcConfig(rpcUrls: Record<string, string | string[]>): void {
|
|
80
80
|
const rpcPath = getPath('rpc_key.yaml');
|
|
81
81
|
try {
|
|
82
|
-
|
|
82
|
+
const tempPath = rpcPath + '.tmp.' + Date.now();
|
|
83
|
+
fs.writeFileSync(tempPath, yaml.stringify(rpcUrls), 'utf8');
|
|
84
|
+
fs.renameSync(tempPath, rpcPath);
|
|
83
85
|
} catch (error) {
|
|
84
86
|
console.error('Failed to save rpc_key.yaml', error);
|
|
85
87
|
}
|
|
@@ -141,6 +143,11 @@ export interface NyxoraConfig {
|
|
|
141
143
|
bot_token?: string;
|
|
142
144
|
authorized_chat_id?: number;
|
|
143
145
|
};
|
|
146
|
+
discord?: {
|
|
147
|
+
enabled: boolean;
|
|
148
|
+
bot_token?: string;
|
|
149
|
+
client_id?: string;
|
|
150
|
+
};
|
|
144
151
|
};
|
|
145
152
|
security?: {
|
|
146
153
|
dashboard_password?: string;
|
|
@@ -248,7 +255,8 @@ export function loadConfig(): NyxoraConfig {
|
|
|
248
255
|
memory: parsed.memory || { type: 'file', path: './memory.json' },
|
|
249
256
|
web3: { ...parsed.web3, rpc_urls: rpcUrls },
|
|
250
257
|
integrations: parsed.integrations || {
|
|
251
|
-
telegram: { enabled: false }
|
|
258
|
+
telegram: { enabled: false },
|
|
259
|
+
discord: { enabled: false }
|
|
252
260
|
},
|
|
253
261
|
security: parsed.security || { dashboard_password: '123456' },
|
|
254
262
|
skills: parsed.skills
|
|
@@ -287,7 +295,8 @@ export function loadConfig(): NyxoraConfig {
|
|
|
287
295
|
memory: { type: 'file', path: './memory.json' },
|
|
288
296
|
web3: { rpc_urls: rpcUrls },
|
|
289
297
|
integrations: {
|
|
290
|
-
telegram: { enabled: false }
|
|
298
|
+
telegram: { enabled: false },
|
|
299
|
+
discord: { enabled: false }
|
|
291
300
|
}
|
|
292
301
|
};
|
|
293
302
|
|
|
@@ -310,7 +319,9 @@ export function saveConfig(newConfig: NyxoraConfig): void {
|
|
|
310
319
|
// Keys are no longer encrypted before saving. They are stored in plain text.
|
|
311
320
|
|
|
312
321
|
const yamlStr = yaml.stringify(configToSave);
|
|
313
|
-
|
|
322
|
+
const tempPath = configPath + '.tmp.' + Date.now();
|
|
323
|
+
fs.writeFileSync(tempPath, yamlStr, 'utf8');
|
|
324
|
+
fs.renameSync(tempPath, configPath);
|
|
314
325
|
} catch (error) {
|
|
315
326
|
console.error('Failed to save config.yaml', error);
|
|
316
327
|
}
|
|
@@ -49,13 +49,15 @@ export async function chatInteractive() {
|
|
|
49
49
|
s.start('Thinking...');
|
|
50
50
|
|
|
51
51
|
try {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
// Use SSE streaming endpoint for real-time token output
|
|
53
|
+
const params = new URLSearchParams({
|
|
54
|
+
message: messageStr,
|
|
55
|
+
session_id: 'cli-chat',
|
|
56
|
+
token,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const response = await fetch(`http://localhost:3000/api/chat/stream?${params}`, {
|
|
60
|
+
headers: { 'x-nyxora-token': token },
|
|
59
61
|
});
|
|
60
62
|
|
|
61
63
|
if (!response.ok) {
|
|
@@ -69,14 +71,54 @@ export async function chatInteractive() {
|
|
|
69
71
|
continue;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
let firstChunk = true;
|
|
75
|
+
let finalReply = '';
|
|
76
|
+
|
|
77
|
+
// Read SSE stream line by line
|
|
78
|
+
const reader = response.body?.getReader();
|
|
79
|
+
const decoder = new TextDecoder();
|
|
80
|
+
|
|
81
|
+
if (reader) {
|
|
82
|
+
let buffer = '';
|
|
83
|
+
while (true) {
|
|
84
|
+
const { done, value } = await reader.read();
|
|
85
|
+
if (done) break;
|
|
86
|
+
buffer += decoder.decode(value, { stream: true });
|
|
87
|
+
const lines = buffer.split('\n');
|
|
88
|
+
buffer = lines.pop() || '';
|
|
89
|
+
for (const line of lines) {
|
|
90
|
+
if (!line.startsWith('data: ')) continue;
|
|
91
|
+
const raw = line.slice(6).trim();
|
|
92
|
+
if (raw === '[DONE]') break;
|
|
93
|
+
try {
|
|
94
|
+
const data = JSON.parse(raw);
|
|
95
|
+
if (data.progress) {
|
|
96
|
+
// Show tool progress on same line, overwriting previous
|
|
97
|
+
if (firstChunk) {
|
|
98
|
+
s.stop(pc.cyan('Nyxora:'));
|
|
99
|
+
firstChunk = false;
|
|
100
|
+
}
|
|
101
|
+
process.stdout.write(`\r${pc.italic(pc.gray(data.progress))} `);
|
|
102
|
+
}
|
|
103
|
+
if (data.chunk) {
|
|
104
|
+
if (firstChunk) {
|
|
105
|
+
s.stop(pc.green('Nyxora:'));
|
|
106
|
+
process.stdout.write('\n');
|
|
107
|
+
firstChunk = false;
|
|
108
|
+
}
|
|
109
|
+
// Clear progress line if any, then write chunk
|
|
110
|
+
finalReply += data.chunk;
|
|
111
|
+
process.stdout.write(data.chunk);
|
|
112
|
+
}
|
|
113
|
+
} catch {}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Newline after streaming completes
|
|
119
|
+
if (!firstChunk) process.stdout.write('\n\n');
|
|
120
|
+
|
|
121
|
+
|
|
80
122
|
|
|
81
123
|
// Check for pending transactions
|
|
82
124
|
try {
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
import { initSafeLogger } from '../utils/safeLogger';
|
|
4
4
|
initSafeLogger();
|
|
5
5
|
|
|
6
|
+
import dns from 'dns';
|
|
7
|
+
// Fix Node 18+ native fetch randomly failing on dual-stack VPS (IPv6 issues)
|
|
8
|
+
dns.setDefaultResultOrder('ipv4first');
|
|
9
|
+
|
|
6
10
|
import fs from 'fs';
|
|
7
11
|
import path from 'path';
|
|
8
12
|
import os from 'os';
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Client, GatewayIntentBits, Message, TextChannel } from 'discord.js';
|
|
2
|
+
import { processUserInput } from '../agent/reasoning';
|
|
3
|
+
import { loadConfig } from '../config/parser';
|
|
4
|
+
|
|
5
|
+
let discordClient: Client | null = null;
|
|
6
|
+
|
|
7
|
+
export function startDiscordBot() {
|
|
8
|
+
const config = loadConfig();
|
|
9
|
+
const token = config.integrations?.discord?.bot_token;
|
|
10
|
+
|
|
11
|
+
if (!token || !config.integrations?.discord?.enabled) {
|
|
12
|
+
console.log('[Discord] Bot is disabled or missing bot_token in config.yaml.');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
discordClient = new Client({
|
|
17
|
+
intents: [
|
|
18
|
+
GatewayIntentBits.Guilds,
|
|
19
|
+
GatewayIntentBits.GuildMessages,
|
|
20
|
+
GatewayIntentBits.MessageContent,
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
discordClient.once('ready', () => {
|
|
25
|
+
console.log(`🤖 Discord Bot is online and logged in as ${discordClient?.user?.tag}`);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
discordClient.on('messageCreate', async (message: Message) => {
|
|
29
|
+
// Ignore messages from bots
|
|
30
|
+
if (message.author.bot) return;
|
|
31
|
+
|
|
32
|
+
// Check if the bot is mentioned
|
|
33
|
+
if (discordClient?.user && message.mentions.has(discordClient.user)) {
|
|
34
|
+
// Strip the mention from the message
|
|
35
|
+
const prompt = message.content.replace(new RegExp(`<@!?${discordClient.user.id}>`, 'g'), '').trim();
|
|
36
|
+
|
|
37
|
+
if (!prompt) return;
|
|
38
|
+
|
|
39
|
+
console.log(`[Discord] Received mention from ${message.author.username} in #${(message.channel as TextChannel).name}: ${prompt}`);
|
|
40
|
+
|
|
41
|
+
// Send initial thinking indicator
|
|
42
|
+
let replyMessage: Message | null = null;
|
|
43
|
+
try {
|
|
44
|
+
replyMessage = await message.reply('⏳ *Thinking...*');
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.error('[Discord] Failed to send initial reply', err);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const onProgress = async (progressText: string) => {
|
|
51
|
+
try {
|
|
52
|
+
if (replyMessage) {
|
|
53
|
+
await replyMessage.edit(`*${progressText}*`);
|
|
54
|
+
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
// Ignore minor edit errors
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const sessionId = `discord_${message.author.id}`;
|
|
62
|
+
const response = await processUserInput(prompt, 'user', onProgress, sessionId);
|
|
63
|
+
|
|
64
|
+
// Clean up thought blocks if any
|
|
65
|
+
let finalResponse = response.replace(/<thought>[\s\S]*?<\/thought>\n?/g, '').replace(/<think>[\s\S]*?<\/think>\n?/g, '');
|
|
66
|
+
|
|
67
|
+
if (replyMessage) {
|
|
68
|
+
// Discord has a 2000 character limit per message
|
|
69
|
+
if (finalResponse.length > 2000) {
|
|
70
|
+
await replyMessage.edit(finalResponse.slice(0, 1997) + '...');
|
|
71
|
+
} else {
|
|
72
|
+
await replyMessage.edit(finalResponse);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
} catch (error: any) {
|
|
76
|
+
console.error('[Discord] Error processing message:', error);
|
|
77
|
+
if (replyMessage) {
|
|
78
|
+
await replyMessage.edit('❌ Sorry, I encountered an error while processing your request.');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
discordClient.login(token).catch(err => {
|
|
85
|
+
console.error('[Discord] Failed to login:', err);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
@@ -7,7 +7,9 @@ const FALLBACK_TOKEN_PATH = getPath('google-tokens.json');
|
|
|
7
7
|
|
|
8
8
|
const SCOPES = [
|
|
9
9
|
'https://www.googleapis.com/auth/gmail.readonly',
|
|
10
|
+
'https://www.googleapis.com/auth/gmail.send',
|
|
10
11
|
'https://www.googleapis.com/auth/calendar.readonly',
|
|
12
|
+
'https://www.googleapis.com/auth/calendar.events',
|
|
11
13
|
'https://www.googleapis.com/auth/documents.readonly',
|
|
12
14
|
'https://www.googleapis.com/auth/spreadsheets',
|
|
13
15
|
'https://www.googleapis.com/auth/forms.responses.readonly',
|
|
@@ -27,7 +27,7 @@ import { validateToken, getSessionToken } from '../utils/state';
|
|
|
27
27
|
import { initWebSocket } from './WebSocketManager';
|
|
28
28
|
import fs from 'fs';
|
|
29
29
|
import yaml from 'yaml';
|
|
30
|
-
import { processUserInput, logger } from '../agent/reasoning';
|
|
30
|
+
import { processUserInput, processUserInputStream, logger } from '../agent/reasoning';
|
|
31
31
|
import { loadConfig, saveConfig, loadRpcConfig, saveRpcConfig } from '../config/parser';
|
|
32
32
|
import { loadDefiKeys, saveDefiKeys } from '../config/defiConfigManager';
|
|
33
33
|
import { loadMarketKeys, saveMarketKeys } from '../config/marketConfigManager';
|
|
@@ -52,6 +52,7 @@ import { executeCustomTx } from '../web3/skills/customTx';
|
|
|
52
52
|
import { executeApprove, executeAaveSupply, executeVaultDeposit, executeUniv3Mint } from '../web3/skills/executeDefi';
|
|
53
53
|
import { executeRevokeApproval } from '../web3/skills/revokeApprovals';
|
|
54
54
|
import { startTelegramBot } from './telegram';
|
|
55
|
+
import { startDiscordBot } from './discordAdapter';
|
|
55
56
|
import { startBridgeWatcher } from '../agent/bridgeWatcher';
|
|
56
57
|
import { eventListener } from '../web3/eventListener';
|
|
57
58
|
import { formatTransactionSuccess, formatTransactionError } from '../utils/formatter';
|
|
@@ -60,17 +61,20 @@ import { generatePrivacyPolicyHtml, generateTosHtml } from './legalGenerator';
|
|
|
60
61
|
import { episodicDB } from '../memory/episodic';
|
|
61
62
|
import { ReflectionEngine } from '../memory/reflection';
|
|
62
63
|
|
|
63
|
-
import {
|
|
64
|
+
import { nyxDaemon } from '../agent/nyxDaemon';
|
|
64
65
|
|
|
65
66
|
// Initialize Google Auth
|
|
66
67
|
initGoogleAuth();
|
|
67
68
|
|
|
68
|
-
// Start Background
|
|
69
|
-
|
|
69
|
+
// Start Background Nyx Daemon
|
|
70
|
+
nyxDaemon.start();
|
|
70
71
|
|
|
71
72
|
// Synchronize all active skills to config.yaml on startup
|
|
72
73
|
syncAllSkillsToConfig();
|
|
73
74
|
|
|
75
|
+
// Start messaging adapters
|
|
76
|
+
startDiscordBot();
|
|
77
|
+
|
|
74
78
|
import util from 'util';
|
|
75
79
|
|
|
76
80
|
// Intercept console.log and console.error
|
|
@@ -129,7 +133,7 @@ app.use('/api', (req, res, next) => {
|
|
|
129
133
|
return next();
|
|
130
134
|
}
|
|
131
135
|
|
|
132
|
-
const token = req.headers['x-nyxora-token'] as string;
|
|
136
|
+
const token = (req.headers['x-nyxora-token'] as string) || (req.query.token as string);
|
|
133
137
|
const validation = validateToken(token);
|
|
134
138
|
|
|
135
139
|
if (!validation.valid) {
|
|
@@ -198,7 +202,9 @@ app.post('/api/upload-google-credentials', (req, res) => {
|
|
|
198
202
|
// The format needs to wrap it in "web" or "installed"
|
|
199
203
|
const finalPayload = credentials.client_id ? { installed: credentials } : credentials;
|
|
200
204
|
|
|
201
|
-
|
|
205
|
+
const tempPath = credsPath + '.tmp.' + Date.now();
|
|
206
|
+
fs.writeFileSync(tempPath, JSON.stringify(finalPayload, null, 2));
|
|
207
|
+
fs.renameSync(tempPath, credsPath);
|
|
202
208
|
|
|
203
209
|
// Re-initialize google auth module
|
|
204
210
|
initGoogleAuth();
|
|
@@ -672,7 +678,7 @@ app.post('/api/transactions/:id/approve', async (req, res) => {
|
|
|
672
678
|
res.json({ success: true, status: 'processing', message: 'Transaction submitted to background processing.' });
|
|
673
679
|
|
|
674
680
|
// Execute in background
|
|
675
|
-
(async () => {
|
|
681
|
+
const txPromise = (async () => {
|
|
676
682
|
try {
|
|
677
683
|
let result = '';
|
|
678
684
|
if (tx.type === 'transfer') {
|
|
@@ -744,6 +750,8 @@ app.post('/api/transactions/:id/approve', async (req, res) => {
|
|
|
744
750
|
logger.addEntry({ role: 'assistant', content: `❌ **Transaction Failed**\n\n${err.message}` }, sessionId);
|
|
745
751
|
}
|
|
746
752
|
})();
|
|
753
|
+
|
|
754
|
+
txManager.trackPromise(txPromise);
|
|
747
755
|
} catch (err: any) {
|
|
748
756
|
txManager.updateStatus(req.params.id, 'failed', err.message);
|
|
749
757
|
res.status(500).json({ error: err.message });
|
|
@@ -1049,7 +1057,51 @@ app.post('/api/chat', async (req, res) => {
|
|
|
1049
1057
|
}
|
|
1050
1058
|
});
|
|
1051
1059
|
|
|
1052
|
-
// ---
|
|
1060
|
+
// --- Streaming Chat Endpoint (SSE) ---
|
|
1061
|
+
// Sends LLM tokens to the client as they arrive via Server-Sent Events.
|
|
1062
|
+
// The old /api/chat endpoint remains untouched for backward compatibility.
|
|
1063
|
+
app.get('/api/chat/stream', async (req, res) => {
|
|
1064
|
+
const { message, session_id } = req.query as Record<string, string>;
|
|
1065
|
+
if (!message) {
|
|
1066
|
+
res.status(400).json({ error: 'Message is required' });
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// Setup SSE headers
|
|
1071
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
1072
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
1073
|
+
res.setHeader('Connection', 'keep-alive');
|
|
1074
|
+
res.setHeader('X-Accel-Buffering', 'no'); // Disable Nginx buffering
|
|
1075
|
+
res.flushHeaders();
|
|
1076
|
+
|
|
1077
|
+
const sendEvent = (data: object) => {
|
|
1078
|
+
res.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
1079
|
+
};
|
|
1080
|
+
|
|
1081
|
+
const onChunk = (text: string) => sendEvent({ chunk: text });
|
|
1082
|
+
const onProgress = (msg: string) => sendEvent({ progress: msg });
|
|
1083
|
+
|
|
1084
|
+
try {
|
|
1085
|
+
await processUserInputStream(message, onChunk, onProgress, session_id);
|
|
1086
|
+
// Trigger memory mechanisms after response completes
|
|
1087
|
+
resetIdleTimer(session_id);
|
|
1088
|
+
messageCounter++;
|
|
1089
|
+
if (messageCounter >= 5) {
|
|
1090
|
+
messageCounter = 0;
|
|
1091
|
+
ReflectionEngine.runReflection(session_id).then(() => {
|
|
1092
|
+
const { PromotionEngine } = require('../memory/promotionEngine');
|
|
1093
|
+
PromotionEngine.runPromotionAndDecay();
|
|
1094
|
+
}).catch(console.error);
|
|
1095
|
+
}
|
|
1096
|
+
} catch (err: any) {
|
|
1097
|
+
sendEvent({ error: err.message });
|
|
1098
|
+
} finally {
|
|
1099
|
+
res.write('data: [DONE]\n\n');
|
|
1100
|
+
res.end();
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
|
|
1053
1105
|
app.get('/api/memory', (req, res) => {
|
|
1054
1106
|
try {
|
|
1055
1107
|
const memories = episodicDB.getMemories();
|
|
@@ -1062,9 +1114,10 @@ app.get('/api/memory', (req, res) => {
|
|
|
1062
1114
|
app.delete('/api/memory/all', (req, res) => {
|
|
1063
1115
|
try {
|
|
1064
1116
|
episodicDB.clearAllMemories();
|
|
1117
|
+
episodicDB.clearAllPersonas();
|
|
1065
1118
|
const { PromotionEngine } = require('../memory/promotionEngine');
|
|
1066
1119
|
PromotionEngine.runPromotionAndDecay();
|
|
1067
|
-
res.json({ success: true, message: "Episodic memory wiped completely." });
|
|
1120
|
+
res.json({ success: true, message: "Episodic memory and persona traits wiped completely." });
|
|
1068
1121
|
} catch (error: any) {
|
|
1069
1122
|
res.status(500).json({ error: error.message });
|
|
1070
1123
|
}
|
|
@@ -1241,11 +1294,14 @@ export async function startServer() {
|
|
|
1241
1294
|
});
|
|
1242
1295
|
|
|
1243
1296
|
let isShuttingDown = false;
|
|
1244
|
-
const gracefulShutdown = () => {
|
|
1297
|
+
const gracefulShutdown = async () => {
|
|
1245
1298
|
if (isShuttingDown) return;
|
|
1246
1299
|
isShuttingDown = true;
|
|
1247
1300
|
console.log('[Nyxora Gateway] Received shutdown signal. Closing server...');
|
|
1248
1301
|
|
|
1302
|
+
// Wait for active transactions
|
|
1303
|
+
await txManager.waitForAll(10000);
|
|
1304
|
+
|
|
1249
1305
|
if (server.closeAllConnections) {
|
|
1250
1306
|
server.closeAllConnections();
|
|
1251
1307
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import pc from 'picocolors';
|
|
6
|
+
import { spinner, note, outro } from '@clack/prompts';
|
|
7
|
+
|
|
8
|
+
const appDir = path.join(os.homedir(), '.nyxora');
|
|
9
|
+
const mlEngineDir = path.join(appDir, 'ml-engine');
|
|
10
|
+
const venvDir = path.join(mlEngineDir, 'venv');
|
|
11
|
+
const sourceReqPath = path.join(process.cwd(), 'packages', 'ml-engine', 'requirements.txt');
|
|
12
|
+
|
|
13
|
+
function runCommand(command: string, args: string[], cwd: string): Promise<void> {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
const child = spawn(command, args, { cwd, stdio: 'ignore' });
|
|
16
|
+
child.on('close', (code) => {
|
|
17
|
+
if (code === 0) resolve();
|
|
18
|
+
else reject(new Error(`Command ${command} ${args.join(' ')} failed with code ${code}`));
|
|
19
|
+
});
|
|
20
|
+
child.on('error', reject);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function setupMlEngine() {
|
|
25
|
+
console.log(pc.cyan('\n⚙️ Initializing Universal Python ML Engine...\n'));
|
|
26
|
+
const s = spinner();
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
if (!fs.existsSync(mlEngineDir)) {
|
|
30
|
+
fs.mkdirSync(mlEngineDir, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
s.start('Creating Python Virtual Environment (venv)...');
|
|
34
|
+
if (!fs.existsSync(venvDir)) {
|
|
35
|
+
await runCommand('python3', ['-m', 'venv', venvDir], mlEngineDir);
|
|
36
|
+
}
|
|
37
|
+
s.stop(pc.green('Virtual Environment created successfully.'));
|
|
38
|
+
|
|
39
|
+
s.start('Installing heavy Data Science & AI dependencies (this may take a while)...');
|
|
40
|
+
const pipPath = path.join(venvDir, 'bin', 'pip');
|
|
41
|
+
|
|
42
|
+
// Upgrade pip
|
|
43
|
+
await runCommand(pipPath, ['install', '--upgrade', 'pip'], mlEngineDir);
|
|
44
|
+
|
|
45
|
+
// Install requirements
|
|
46
|
+
if (fs.existsSync(sourceReqPath)) {
|
|
47
|
+
await runCommand(pipPath, ['install', '-r', sourceReqPath], mlEngineDir);
|
|
48
|
+
s.stop(pc.green('Dependencies installed successfully.'));
|
|
49
|
+
} else {
|
|
50
|
+
s.stop(pc.yellow('requirements.txt not found. Skipping dependency installation.'));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
note(
|
|
54
|
+
'The Python Sidecar is ready.\nIt will automatically start in the background when you run `nyxora start`.',
|
|
55
|
+
'ML Engine Configured'
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
} catch (error: any) {
|
|
59
|
+
s.stop(pc.red('Failed to setup ML Engine.'));
|
|
60
|
+
console.error(pc.red(`Error: ${error.message}`));
|
|
61
|
+
console.log(pc.yellow('\nPlease ensure python3 and python3-venv are installed on your system.'));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Allow running directly
|
|
66
|
+
if (require.main === module) {
|
|
67
|
+
setupMlEngine().then(() => process.exit(0));
|
|
68
|
+
}
|
|
@@ -25,6 +25,28 @@ export async function runSetupWizard() {
|
|
|
25
25
|
console.log(pc.cyan(logo));
|
|
26
26
|
intro(pc.inverse(' Nyxora CLI Setup '));
|
|
27
27
|
|
|
28
|
+
try {
|
|
29
|
+
const nodeVersion = parseInt(process.versions.node.split('.')[0], 10);
|
|
30
|
+
if (nodeVersion < 18) {
|
|
31
|
+
console.error(pc.red(`\n❌ Unsupported Node.js version. Nyxora requires Node.js 18 or higher. You are running v${process.versions.node}`));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { execSync } = require('child_process');
|
|
36
|
+
const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
|
|
37
|
+
const pyVersionStr = execSync(`${pythonCmd} -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
38
|
+
const [major, minor] = pyVersionStr.split('.').map(Number);
|
|
39
|
+
|
|
40
|
+
if (major < 3 || (major === 3 && minor < 10)) {
|
|
41
|
+
console.error(pc.red(`\n❌ Unsupported Python version. Nyxora ML Engine requires Python 3.10+. You are running v${pyVersionStr}`));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
note(`Node.js: v${process.versions.node}\nPython: v${pyVersionStr}`, 'System Requirements Met');
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error(pc.red(`\n❌ Python 3 is not installed or not in your PATH. Nyxora requires Python 3.10+ for the ML Engine.`));
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
28
50
|
const appDir = getAppDir();
|
|
29
51
|
const config = loadConfig();
|
|
30
52
|
|
|
@@ -32,8 +54,8 @@ export async function runSetupWizard() {
|
|
|
32
54
|
`Nyxora is a Web3 Assistant that operates with full access under your control.
|
|
33
55
|
|
|
34
56
|
Critical Precautions:
|
|
35
|
-
- Your Private Key is the lifeblood of your assets. NEVER copy or share
|
|
36
|
-
- Any instructions you provide via Telegram or Dashboard can trigger on-chain transactions.
|
|
57
|
+
- Your Private Key is the lifeblood of your assets. NEVER copy or share your vault.key file or OS Keyring password.
|
|
58
|
+
- Any instructions you provide via Telegram, Discord, or the Dashboard can trigger on-chain transactions.
|
|
37
59
|
- It is recommended to use a smart AI model for maximum accuracy.
|
|
38
60
|
|
|
39
61
|
By using Nyxora, you retain full control over your own keys.`;
|
|
@@ -311,6 +333,7 @@ Provider: ${config.llm.provider}`;
|
|
|
311
333
|
message: '💬 Select Integration Channels to enable:',
|
|
312
334
|
options: [
|
|
313
335
|
{ value: 'telegram', label: 'Telegram Bot', hint: 'Requires Token' },
|
|
336
|
+
{ value: 'discord', label: 'Discord Bot', hint: 'Requires Token' },
|
|
314
337
|
{ value: 'dashboard', label: 'Local Web Dashboard', hint: 'enabled by default' },
|
|
315
338
|
],
|
|
316
339
|
initialValues: ['dashboard'],
|
|
@@ -417,6 +440,15 @@ Provider: ${config.llm.provider}`;
|
|
|
417
440
|
}
|
|
418
441
|
}
|
|
419
442
|
|
|
443
|
+
const setupDiscord = activeChannels.includes('discord');
|
|
444
|
+
let discordToken = '';
|
|
445
|
+
if (setupDiscord) {
|
|
446
|
+
discordToken = (await password({
|
|
447
|
+
message: 'Enter Discord Bot Token (Leave empty if already set):',
|
|
448
|
+
})) as string;
|
|
449
|
+
if (isCancel(discordToken)) return process.exit(0);
|
|
450
|
+
}
|
|
451
|
+
|
|
420
452
|
|
|
421
453
|
|
|
422
454
|
// --- SAVING ---
|
|
@@ -470,6 +502,12 @@ Provider: ${config.llm.provider}`;
|
|
|
470
502
|
delete config.integrations.telegram.authorized_chat_id;
|
|
471
503
|
}
|
|
472
504
|
|
|
505
|
+
if (!config.integrations.discord) config.integrations.discord = { enabled: false };
|
|
506
|
+
config.integrations.discord.enabled = setupDiscord as boolean;
|
|
507
|
+
if (setupDiscord && discordToken) {
|
|
508
|
+
config.integrations.discord.bot_token = discordToken as string;
|
|
509
|
+
}
|
|
510
|
+
|
|
473
511
|
saveConfig(config);
|
|
474
512
|
|
|
475
513
|
|
|
@@ -527,7 +565,7 @@ Provider: ${config.llm.provider}`;
|
|
|
527
565
|
getBalance: 'get_balance',
|
|
528
566
|
getMyAddress: 'get_my_address',
|
|
529
567
|
checkPortfolio: 'check_portfolio',
|
|
530
|
-
getPrice: '
|
|
568
|
+
getPrice: 'get_price_and_fiat_value',
|
|
531
569
|
marketAnalysis: 'analyze_market',
|
|
532
570
|
getTxHistory: 'get_tx_history',
|
|
533
571
|
checkSecurity: 'check_token_security',
|