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.
Files changed (192) hide show
  1. package/CHANGELOG.md +112 -47
  2. package/README.md +25 -21
  3. package/bin/nyxora.mjs +4 -6
  4. package/dist/launcher.js +44 -8
  5. package/dist/packages/core/src/agent/bridgeWatcher.js +3 -2
  6. package/dist/packages/core/src/agent/cronManager.js +2 -2
  7. package/dist/packages/core/src/agent/llmProvider.js +245 -0
  8. package/dist/packages/core/src/agent/nyxDaemon.js +97 -0
  9. package/dist/packages/core/src/agent/osAgent.js +351 -29
  10. package/dist/packages/core/src/agent/reasoning.js +353 -60
  11. package/dist/packages/core/src/agent/reasoningScratchpad.js +47 -0
  12. package/dist/packages/core/src/agent/transactionManager.js +36 -31
  13. package/dist/packages/core/src/agent/web3Agent.js +263 -37
  14. package/dist/packages/core/src/cognitive/cognitiveManager.js +63 -10
  15. package/dist/packages/core/src/config/parser.js +10 -4
  16. package/dist/packages/core/src/gateway/chat.js +56 -13
  17. package/dist/packages/core/src/gateway/cli.js +3 -0
  18. package/dist/packages/core/src/gateway/discordAdapter.js +81 -0
  19. package/dist/packages/core/src/gateway/googleAuthModule.js +2 -0
  20. package/dist/packages/core/src/gateway/server.js +58 -9
  21. package/dist/packages/core/src/gateway/setup-ml.js +64 -0
  22. package/dist/packages/core/src/gateway/setup.js +39 -3
  23. package/dist/packages/core/src/gateway/telegram.js +123 -27
  24. package/dist/packages/core/src/memory/episodic.js +58 -3
  25. package/dist/packages/core/src/memory/logger.js +120 -2
  26. package/dist/packages/core/src/memory/promotionEngine.js +18 -5
  27. package/dist/packages/core/src/system/agentskills.js +10 -0
  28. package/dist/packages/core/src/system/plugins/GoogleWorkspacePlugin.js +10 -2
  29. package/dist/packages/core/src/system/plugins/SystemCorePlugin.js +1 -1
  30. package/dist/packages/core/src/system/plugins/SystemExternalPlugin.js +1 -1
  31. package/dist/packages/core/src/system/plugins/SystemPluginInstallerPlugin.js +1 -1
  32. package/dist/packages/core/src/system/plugins/SystemSocialPlugin.js +1 -1
  33. package/dist/packages/core/src/system/plugins/SystemWebPlugin.js +1 -1
  34. package/dist/packages/core/src/system/plugins/SystemWorkspacePlugin.js +3 -3
  35. package/dist/packages/core/src/system/plugins/createSkill.js +1 -1
  36. package/dist/packages/core/src/system/skillExtractor.js +16 -5
  37. package/dist/packages/core/src/system/skills/executeShell.js +31 -4
  38. package/dist/packages/core/src/system/skills/forgetMemory.js +6 -4
  39. package/dist/packages/core/src/system/skills/googleWorkspace.js +106 -1
  40. package/dist/packages/core/src/system/skills/scheduleTask.js +7 -2
  41. package/dist/packages/core/src/system/skills/searchWeb.js +13 -6
  42. package/dist/packages/core/src/test_mainnet.js +45 -0
  43. package/dist/packages/core/src/utils/contextSummarizer.js +82 -0
  44. package/dist/packages/core/src/utils/skillManager.js +1 -1
  45. package/dist/packages/core/src/utils/streamSimulator.js +85 -0
  46. package/dist/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.js +28 -11
  47. package/dist/packages/core/src/web3/aggregator/providers/OpBridgeProvider.js +41 -27
  48. package/dist/packages/core/src/web3/aggregator/providers/TestnetSwapProvider.js +65 -0
  49. package/dist/packages/core/src/web3/aggregator/routeSelector.js +7 -1
  50. package/dist/packages/core/src/web3/plugins/Web3DefiPlugin.js +1 -1
  51. package/dist/packages/core/src/web3/plugins/Web3MarketPlugin.js +5 -125
  52. package/dist/packages/core/src/web3/plugins/Web3SecurityPlugin.js +1 -1
  53. package/dist/packages/core/src/web3/plugins/Web3WalletPlugin.js +1 -1
  54. package/dist/packages/core/src/web3/skills/bridgeToken.js +19 -4
  55. package/dist/packages/core/src/web3/skills/checkAddress.js +2 -0
  56. package/dist/packages/core/src/web3/skills/checkPortfolio.js +22 -2
  57. package/dist/packages/core/src/web3/skills/checkSecurity.js +2 -0
  58. package/dist/packages/core/src/web3/skills/confirmPendingTx.js +1 -1
  59. package/dist/packages/core/src/web3/skills/createLimitOrder.js +15 -1
  60. package/dist/packages/core/src/web3/skills/customTx.js +3 -0
  61. package/dist/packages/core/src/web3/skills/defiLending.js +2 -0
  62. package/dist/packages/core/src/web3/skills/getBalance.js +2 -0
  63. package/dist/packages/core/src/web3/skills/getPrice.js +134 -27
  64. package/dist/packages/core/src/web3/skills/getTxHistory.js +2 -0
  65. package/dist/packages/core/src/web3/skills/marketAnalysis.js +28 -191
  66. package/dist/packages/core/src/web3/skills/mintNft.js +3 -0
  67. package/dist/packages/core/src/web3/skills/provideLiquidity.js +16 -12
  68. package/dist/packages/core/src/web3/skills/revokeApprovals.js +2 -0
  69. package/dist/packages/core/src/web3/skills/swapToken.js +20 -2
  70. package/dist/packages/core/src/web3/skills/transfer.js +2 -0
  71. package/dist/packages/core/src/web3/skills/yieldVault.js +2 -0
  72. package/dist/packages/core/src/web3/utils/chains.js +19 -0
  73. package/dist/packages/core/src/web3/utils/marketEngine.js +26 -33
  74. package/dist/packages/signer/src/NyxoraSigner.js +181 -0
  75. package/dist/packages/signer/src/index.js +17 -0
  76. package/dist/packages/signer/src/server.js +25 -161
  77. package/launcher.ts +38 -9
  78. package/package.json +8 -3
  79. package/packages/core/package.json +21 -10
  80. package/packages/core/src/agent/bridgeWatcher.ts +3 -2
  81. package/packages/core/src/agent/cronManager.ts +2 -2
  82. package/packages/core/src/agent/llmProvider.ts +221 -0
  83. package/packages/core/src/agent/nyxDaemon.ts +104 -0
  84. package/packages/core/src/agent/osAgent.ts +381 -32
  85. package/packages/core/src/agent/reasoning.ts +376 -64
  86. package/packages/core/src/agent/reasoningScratchpad.ts +45 -0
  87. package/packages/core/src/agent/transactionManager.ts +36 -28
  88. package/packages/core/src/agent/web3Agent.ts +291 -40
  89. package/packages/core/src/cognitive/cognitiveManager.ts +65 -10
  90. package/packages/core/src/cognitive/prompts/web3/market-analysis.md +24 -0
  91. package/packages/core/src/cognitive/prompts/web3/portfolio-review.md +29 -0
  92. package/packages/core/src/cognitive/prompts/web3/risk-assessment.md +28 -0
  93. package/packages/core/src/cognitive/prompts/web3/trade-planning.md +30 -0
  94. package/packages/core/src/config/parser.ts +15 -4
  95. package/packages/core/src/gateway/chat.ts +57 -15
  96. package/packages/core/src/gateway/cli.ts +4 -0
  97. package/packages/core/src/gateway/discordAdapter.ts +87 -0
  98. package/packages/core/src/gateway/googleAuthModule.ts +2 -0
  99. package/packages/core/src/gateway/server.ts +66 -10
  100. package/packages/core/src/gateway/setup-ml.ts +68 -0
  101. package/packages/core/src/gateway/setup.ts +41 -3
  102. package/packages/core/src/gateway/telegram.ts +141 -30
  103. package/packages/core/src/memory/episodic.ts +76 -3
  104. package/packages/core/src/memory/logger.ts +142 -2
  105. package/packages/core/src/memory/promotionEngine.ts +19 -5
  106. package/packages/core/src/system/agentskills.ts +10 -0
  107. package/packages/core/src/system/plugins/GoogleWorkspacePlugin.ts +15 -3
  108. package/packages/core/src/system/plugins/SystemCorePlugin.ts +1 -1
  109. package/packages/core/src/system/plugins/SystemExternalPlugin.ts +1 -1
  110. package/packages/core/src/system/plugins/SystemPluginInstallerPlugin.ts +1 -1
  111. package/packages/core/src/system/plugins/SystemSocialPlugin.ts +1 -1
  112. package/packages/core/src/system/plugins/SystemWebPlugin.ts +1 -1
  113. package/packages/core/src/system/plugins/SystemWorkspacePlugin.ts +3 -3
  114. package/packages/core/src/system/plugins/createSkill.ts +1 -1
  115. package/packages/core/src/system/skillExtractor.ts +16 -5
  116. package/packages/core/src/system/skills/executeShell.ts +38 -7
  117. package/packages/core/src/system/skills/forgetMemory.ts +7 -4
  118. package/packages/core/src/system/skills/googleWorkspace.ts +109 -0
  119. package/packages/core/src/system/skills/scheduleTask.ts +7 -2
  120. package/packages/core/src/system/skills/searchWeb.ts +12 -6
  121. package/packages/core/src/utils/contextSummarizer.ts +100 -0
  122. package/packages/core/src/utils/skillManager.ts +1 -1
  123. package/packages/core/src/utils/streamSimulator.ts +88 -0
  124. package/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.ts +30 -11
  125. package/packages/core/src/web3/aggregator/providers/OpBridgeProvider.ts +43 -29
  126. package/packages/core/src/web3/aggregator/routeSelector.ts +6 -1
  127. package/packages/core/src/web3/plugins/Web3DefiPlugin.ts +1 -1
  128. package/packages/core/src/web3/plugins/Web3MarketPlugin.ts +6 -125
  129. package/packages/core/src/web3/plugins/Web3SecurityPlugin.ts +1 -1
  130. package/packages/core/src/web3/plugins/Web3WalletPlugin.ts +1 -1
  131. package/packages/core/src/web3/skills/bridgeToken.ts +21 -7
  132. package/packages/core/src/web3/skills/checkAddress.ts +2 -0
  133. package/packages/core/src/web3/skills/checkPortfolio.ts +23 -2
  134. package/packages/core/src/web3/skills/checkSecurity.ts +2 -0
  135. package/packages/core/src/web3/skills/confirmPendingTx.ts +1 -1
  136. package/packages/core/src/web3/skills/createLimitOrder.ts +17 -2
  137. package/packages/core/src/web3/skills/customTx.ts +3 -0
  138. package/packages/core/src/web3/skills/defiLending.ts +2 -0
  139. package/packages/core/src/web3/skills/getBalance.ts +2 -0
  140. package/packages/core/src/web3/skills/getPrice.ts +134 -30
  141. package/packages/core/src/web3/skills/getTxHistory.ts +2 -0
  142. package/packages/core/src/web3/skills/marketAnalysis.ts +45 -188
  143. package/packages/core/src/web3/skills/mintNft.ts +3 -0
  144. package/packages/core/src/web3/skills/provideLiquidity.ts +16 -10
  145. package/packages/core/src/web3/skills/revokeApprovals.ts +2 -0
  146. package/packages/core/src/web3/skills/swapToken.ts +20 -3
  147. package/packages/core/src/web3/skills/transfer.ts +2 -0
  148. package/packages/core/src/web3/skills/yieldVault.ts +2 -0
  149. package/packages/core/src/web3/utils/chains.ts +12 -0
  150. package/packages/core/src/web3/utils/marketEngine.ts +27 -33
  151. package/packages/dashboard/dist/assets/index-Czxksiao.js +18 -0
  152. package/packages/dashboard/dist/assets/index-DK2sTU47.css +1 -0
  153. package/packages/dashboard/dist/index.html +2 -2
  154. package/packages/dashboard/package.json +10 -10
  155. package/packages/mcp-server/dist/server.js +5 -1
  156. package/packages/mcp-server/package.json +6 -6
  157. package/packages/mcp-server/src/server.ts +11 -7
  158. package/packages/ml-engine/__pycache__/config.cpython-313.pyc +0 -0
  159. package/packages/ml-engine/__pycache__/main.cpython-313.pyc +0 -0
  160. package/packages/ml-engine/config.py +59 -0
  161. package/packages/ml-engine/main.py +34 -0
  162. package/packages/ml-engine/requirements.txt +22 -0
  163. package/packages/ml-engine/routers/__init__.py +1 -0
  164. package/packages/ml-engine/routers/__pycache__/__init__.cpython-313.pyc +0 -0
  165. package/packages/ml-engine/routers/__pycache__/cognitive.cpython-313.pyc +0 -0
  166. package/packages/ml-engine/routers/__pycache__/critic.cpython-313.pyc +0 -0
  167. package/packages/ml-engine/routers/__pycache__/llm.cpython-313.pyc +0 -0
  168. package/packages/ml-engine/routers/__pycache__/market.cpython-313.pyc +0 -0
  169. package/packages/ml-engine/routers/__pycache__/memory.cpython-313.pyc +0 -0
  170. package/packages/ml-engine/routers/cognitive.py +98 -0
  171. package/packages/ml-engine/routers/critic.py +111 -0
  172. package/packages/ml-engine/routers/llm.py +38 -0
  173. package/packages/ml-engine/routers/market.py +332 -0
  174. package/packages/ml-engine/routers/memory.py +125 -0
  175. package/packages/policy/package.json +3 -3
  176. package/packages/signer/package.json +16 -6
  177. package/packages/signer/src/NyxoraSigner.ts +161 -0
  178. package/packages/signer/src/index.ts +1 -0
  179. package/packages/signer/src/server.ts +25 -135
  180. package/dist/packages/core/src/agent/honchoDaemon.js +0 -91
  181. package/dist/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -54
  182. package/dist/packages/core/src/gateway/test.js +0 -15
  183. package/dist/packages/core/src/web3/Web3DefiPlugin.js +0 -28
  184. package/dist/packages/core/src/web3/aggregator/aggregatorMainnet.js +0 -260
  185. package/dist/packages/core/src/web3/aggregator/aggregatorTestnet.js +0 -119
  186. package/dist/packages/core/src/web3/skills/nativeOpBridge.js +0 -71
  187. package/packages/core/src/agent/honchoDaemon.ts +0 -96
  188. package/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -41
  189. package/packages/core/src/plugin/registry.test.ts +0 -46
  190. package/packages/core/src/utils/formatter.test.ts +0 -41
  191. package/packages/dashboard/dist/assets/index-CSoNa5cx.css +0 -1
  192. package/packages/dashboard/dist/assets/index-DbRWEoSr.js +0 -16
@@ -5,32 +5,37 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.txManager = void 0;
7
7
  const crypto_1 = __importDefault(require("crypto"));
8
- const fs_1 = __importDefault(require("fs"));
9
- const paths_1 = require("../config/paths");
8
+ const logger_1 = require("../memory/logger");
10
9
  class TransactionManager {
11
- transactions = new Map();
12
- withdrawals = new Map();
13
- dbPath;
10
+ activePromises = new Set();
14
11
  constructor() {
15
- this.dbPath = (0, paths_1.getPath)('.nyxora_withdrawals.json');
16
- this.loadWithdrawals();
12
+ // Migration: if .nyxora_withdrawals.json exists, we could migrate it, but the plan says we can ignore/leave it.
13
+ // However, a simple migration log is fine if we want to be safe.
17
14
  }
18
- loadWithdrawals() {
19
- if (fs_1.default.existsSync(this.dbPath)) {
20
- try {
21
- const data = fs_1.default.readFileSync(this.dbPath, 'utf8');
22
- const parsed = JSON.parse(data);
23
- parsed.forEach(w => this.withdrawals.set(w.id, w));
24
- }
25
- catch (e) {
26
- console.error("Failed to load withdrawals DB:", e);
27
- }
28
- }
15
+ // --- PROMISE TRACKING (For Graceful Shutdown) ---
16
+ trackPromise(promise) {
17
+ this.activePromises.add(promise);
18
+ promise.finally(() => {
19
+ this.activePromises.delete(promise);
20
+ });
29
21
  }
30
- saveWithdrawals() {
31
- const data = Array.from(this.withdrawals.values());
32
- fs_1.default.writeFileSync(this.dbPath, JSON.stringify(data, null, 2));
22
+ async waitForAll(timeoutMs = 10000) {
23
+ if (this.activePromises.size === 0)
24
+ return;
25
+ console.log(`[TransactionManager] Waiting for ${this.activePromises.size} active Web3 transactions to finish...`);
26
+ const timeout = new Promise(resolve => setTimeout(resolve, timeoutMs));
27
+ await Promise.race([
28
+ Promise.allSettled(Array.from(this.activePromises)),
29
+ timeout
30
+ ]);
31
+ if (this.activePromises.size > 0) {
32
+ console.log(`[TransactionManager] Warning: ${this.activePromises.size} transactions did not finish in time.`);
33
+ }
34
+ else {
35
+ console.log(`[TransactionManager] All transactions finished cleanly.`);
36
+ }
33
37
  }
38
+ // --- TRANSACTIONS (SQLite) ---
34
39
  createPendingTransaction(type, chainName, details) {
35
40
  const id = crypto_1.default.randomUUID();
36
41
  const nonce = crypto_1.default.randomBytes(16).toString('hex');
@@ -43,24 +48,25 @@ class TransactionManager {
43
48
  createdAt: Date.now(),
44
49
  nonce,
45
50
  };
46
- this.transactions.set(id, tx);
51
+ logger_1.logger.savePendingTransaction(tx);
47
52
  return tx;
48
53
  }
49
54
  getPending() {
50
- return Array.from(this.transactions.values()).filter(t => t.status === 'pending');
55
+ return logger_1.logger.getPendingTransactions();
51
56
  }
52
57
  getTransaction(id) {
53
- return this.transactions.get(id);
58
+ return logger_1.logger.getTransaction(id);
54
59
  }
55
60
  updateStatus(id, status, result) {
56
- const tx = this.transactions.get(id);
61
+ const tx = logger_1.logger.getTransaction(id);
57
62
  if (tx) {
58
63
  tx.status = status;
59
64
  if (result)
60
65
  tx.result = result;
66
+ logger_1.logger.savePendingTransaction(tx);
61
67
  }
62
68
  }
63
- // --- WITHDRAWAL LOGIC ---
69
+ // --- WITHDRAWALS (SQLite) ---
64
70
  createPendingWithdrawal(data) {
65
71
  const id = crypto_1.default.randomUUID();
66
72
  const withdrawal = {
@@ -69,18 +75,17 @@ class TransactionManager {
69
75
  status: 'WAITING_FOR_CHALLENGE',
70
76
  createdAt: Date.now()
71
77
  };
72
- this.withdrawals.set(id, withdrawal);
73
- this.saveWithdrawals();
78
+ logger_1.logger.savePendingWithdrawal(withdrawal);
74
79
  return withdrawal;
75
80
  }
76
81
  getPendingWithdrawals() {
77
- return Array.from(this.withdrawals.values()).filter(w => w.status !== 'COMPLETED');
82
+ return logger_1.logger.getPendingWithdrawals();
78
83
  }
79
84
  updateWithdrawalStatus(id, status) {
80
- const w = this.withdrawals.get(id);
85
+ const w = logger_1.logger.getPendingWithdrawals().find(x => x.id === id);
81
86
  if (w) {
82
87
  w.status = status;
83
- this.saveWithdrawals();
88
+ logger_1.logger.savePendingWithdrawal(w);
84
89
  }
85
90
  }
86
91
  }
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.logger = void 0;
7
7
  exports.processWeb3Intent = processWeb3Intent;
8
+ exports.processWeb3IntentStream = processWeb3IntentStream;
9
+ const fs_1 = __importDefault(require("fs"));
8
10
  const parser_1 = require("../config/parser");
9
11
  const logger_1 = require("../memory/logger");
10
12
  const tracker_1 = require("../gateway/tracker");
@@ -12,7 +14,11 @@ const episodic_1 = require("../memory/episodic");
12
14
  const skillManager_1 = require("../utils/skillManager");
13
15
  const registry_1 = require("../plugin/registry");
14
16
  const cognitiveManager_1 = require("../cognitive/cognitiveManager");
17
+ const reasoningScratchpad_1 = require("./reasoningScratchpad");
18
+ const contextSummarizer_1 = require("../utils/contextSummarizer");
15
19
  const EXECUTION_DISCIPLINE = `
20
+
21
+
16
22
  <tool_persistence>
17
23
  Use tools whenever they can increase the accuracy, completeness, or factual correctness of your response.
18
24
  Do NOT stop early if another tool call would materially improve the result.
@@ -21,12 +27,21 @@ Continue using tools until the task is completely finished and verified.
21
27
 
22
28
  <mandatory_tool_use>
23
29
  NEVER answer the following using only your internal memory — ALWAYS use the relevant tool:
30
+ - Cryptocurrency prices, market data, and portfolio values (e.g., use get_price_and_fiat_value)
31
+ - Fiat exchange rates or currency conversions (fetch live rates, never guess)
24
32
  - Arithmetic, math, calculations
25
33
  - System State: OS version, RAM, processes
26
34
  - File contents, file sizes
27
35
  - Real-world current events
28
36
  </mandatory_tool_use>
29
37
 
38
+ <fiat_conversion_rule>
39
+ CRITICAL: If the user asks for the total fiat value of a certain amount of crypto (e.g., "3821 jrny to idr", "2 eth in usd", "cek saldo gue dirupiahin"), you MUST pass that amount into the 'get_price_and_fiat_value' tool's 'amount' parameter.
40
+ You MUST also set the 'currency' parameter in 'get_price_and_fiat_value' ONLY IF the user explicitly requests a specific currency. If no specific currency is requested, LEAVE THE 'currency' PARAMETER BLANK so the system can use the user's default.
41
+ NEVER fetch the price and then manually multiply it by the amount in your head. The LLM is prohibited from performing fiat multiplication. ALWAYS use the 'amount' parameter in 'get_price_and_fiat_value' to guarantee mathematical precision.
42
+ NEVER use the 'analyze_market' tool if the user is only asking to check their balance in fiat/rupiah. 'analyze_market' does not do fiat conversion.
43
+ </fiat_conversion_rule>
44
+
30
45
  <act_dont_ask>
31
46
  When a user's request has a clear, standard interpretation, take immediate ACTION instead of asking for clarification.
32
47
  </act_dont_ask>
@@ -36,21 +51,21 @@ The deliverable must be a working artifact backed by real tool output — not ju
36
51
  NEVER fabricate, hallucinate, or forge tool outputs.
37
52
  </task_completion>
38
53
  `;
54
+ const paths_1 = require("../config/paths");
39
55
  const picocolors_1 = __importDefault(require("picocolors"));
40
56
  exports.logger = new logger_1.Logger();
41
57
  const llmUtils_1 = require("../utils/llmUtils");
42
- function getSystemPrompt(context = 'web3', userInput = '') {
58
+ async function getSystemPrompt(context = 'web3', userInput = '') {
43
59
  const config = (0, parser_1.loadConfig)();
44
- const currentDateTime = new Date().toLocaleString('en-US');
45
60
  let basePrompt = `You are Nyxora's Web3 Agent (DeFi Specialist).
46
- The current real-world date and time is: ${currentDateTime}.
61
+ Current Time: ${new Date().toISOString()}
47
62
  Default Chain: ${config.agent.default_chain}
48
63
 
49
64
  Reason internally. Never reveal private reasoning. Provide only concise conclusions, assumptions, and actionable steps.
50
65
 
51
66
  [WEB3 EXECUTION WORKFLOW]
52
67
  CRITICAL RULE 1: NEVER expose internal JSON tool calls. Explain the outcome naturally.
53
- CRITICAL RULE 2: STRICT LANGUAGE MATCHING. Reply in the exact same language as the user's LATEST prompt.
68
+ CRITICAL RULE 2: STRICT LANGUAGE MATCHING. Reply in the exact same language as the user's LATEST prompt, UNLESS the Episodic Memories or Cognitive Skills specify a strict language preference.
54
69
  CRITICAL RULE 3: DEFAULT CHAIN HANDLING. Default to: ${config.agent.default_chain} unless specified.
55
70
  CRITICAL RULE 4: CONDITIONAL PARALLEL EXECUTION. Parallel tool execution is ONLY allowed if there are zero data dependencies.
56
71
  CRITICAL RULE 5: TRANSACTION EXECUTION. For ALL state-changing transactions (swap, bridge, transfer), execute IMMEDIATELY. It will trigger a secure popup.
@@ -61,54 +76,89 @@ CRITICAL RULE 9: MARKET CONFIDENCE SCORE. Declare a 'Confidence Score (0-100%)'
61
76
 
62
77
  ${EXECUTION_DISCIPLINE}
63
78
  `;
64
- // Inject Episodic Memories
79
+ // Inject Episodic Memories via Python RAG
65
80
  try {
66
- const recentMemories = episodic_1.episodicDB.getMemories().slice(0, 10);
67
- if (recentMemories.length > 0) {
68
- basePrompt += `
69
-
70
- --- EPISODIC MEMORIES (SMART SUGGESTIONS) ---
71
- `;
72
- recentMemories.forEach(mem => {
73
- basePrompt += `- [${mem.category.toUpperCase()}] ${mem.fact} (Confidence: ${(mem.confidence * 100).toFixed(0)}%)
74
- `;
75
- });
81
+ const ragRes = await fetch('http://127.0.0.1:8000/memory/rag', {
82
+ method: 'POST',
83
+ headers: { 'Content-Type': 'application/json' },
84
+ body: JSON.stringify({ query: userInput, top_k: 5 })
85
+ });
86
+ if (ragRes.ok) {
87
+ const ragData = await ragRes.json();
88
+ if (ragData.memories && ragData.memories.length > 0) {
89
+ basePrompt += `\n\n--- EPISODIC MEMORIES (SMART SUGGESTIONS) ---\n`;
90
+ ragData.memories.forEach((mem) => {
91
+ basePrompt += `- ${mem}\n`;
92
+ });
93
+ }
76
94
  }
77
95
  }
78
- catch { }
96
+ catch (e) {
97
+ // Fallback or ignore if Python ML engine is down
98
+ }
79
99
  // Inject Active Cognitive Skills
80
100
  const activeSOP = cognitiveManager_1.cognitiveManager.loadActiveCognitiveSkills(userInput);
81
101
  if (activeSOP) {
82
102
  basePrompt += `\n\n[ACTIVE COGNITIVE SKILLS]\n${activeSOP}\n`;
83
103
  }
104
+ // Inject User Information & Personas from user.md
105
+ try {
106
+ const userMdPath = (0, paths_1.getPath)('user.md');
107
+ if (fs_1.default.existsSync(userMdPath)) {
108
+ const userInstructions = fs_1.default.readFileSync(userMdPath, 'utf8');
109
+ basePrompt += `\n\n--- USER INFORMATION & PREFERENCES ---\n${userInstructions}\n`;
110
+ }
111
+ }
112
+ catch (e) {
113
+ // Ignore error
114
+ }
115
+ // HIGHEST PRIORITY: Inject observed user communication style (NyxDaemon)
116
+ try {
117
+ const strongPersonas = episodic_1.episodicDB.getStrongPersonas(0.5);
118
+ if (strongPersonas.length > 0) {
119
+ basePrompt += `\n\n--- ⚡ OVERRIDE: USER COMMUNICATION STYLE (HIGHEST PRIORITY — OVERRIDES ALL RULES ABOVE) ---\n`;
120
+ basePrompt += `CRITICAL: These are CONFIRMED user preferences observed across multiple conversations. You MUST apply them IMMEDIATELY and CONSISTENTLY, overriding any default tone or style instructions above.\n\n`;
121
+ strongPersonas.forEach(p => {
122
+ const label = p.category ? `[${p.category.toUpperCase()}]` : '[PREFERENCE]';
123
+ basePrompt += `${label} ${p.trait}\n`;
124
+ });
125
+ }
126
+ }
127
+ catch (e) {
128
+ // Ignore
129
+ }
84
130
  return basePrompt;
85
131
  }
86
132
  async function processWeb3Intent(input, role = 'user', onProgress, sessionId) {
87
133
  const config = (0, parser_1.loadConfig)();
88
134
  // Add input to memory
89
135
  exports.logger.addEntry({ role, content: input }, sessionId);
90
- const history = exports.logger.getHistory(sessionId);
91
- // Format messages for OpenAI
92
- // Inject Plugin Tools dynamically
93
136
  const pluginTools = registry_1.pluginManager.getAllToolDefinitions();
94
137
  let activeTools = [...pluginTools];
95
138
  activeTools = activeTools.filter(t => (0, skillManager_1.isSkillActive)(t.function.name));
139
+ // P1: Init reasoning scratchpad for this request
140
+ const scratchpad = new reasoningScratchpad_1.ReasoningScratchpad();
141
+ // P3: Build system prompt ONCE per request — not per turn
142
+ const cachedSystemPrompt = await getSystemPrompt('web3', input);
96
143
  const { sanitizeHistoryForLLM } = require('../utils/historySanitizer');
97
- const sanitizedHistory = sanitizeHistoryForLLM(history, activeTools, config.llm.provider);
98
- let messages = [
99
- { role: 'system', content: getSystemPrompt('web3', input) },
100
- ...sanitizedHistory
101
- ];
102
144
  try {
103
- const context = 'web3';
104
145
  let turnCount = 0;
105
- const MAX_TURNS = 10;
146
+ const MAX_TURNS = 20;
147
+ let consecutiveToolErrors = 0;
106
148
  while (turnCount < MAX_TURNS) {
107
149
  turnCount++;
108
150
  const currentHistory = exports.logger.getHistory(sessionId);
109
- const sanitizedHistory = sanitizeHistoryForLLM(currentHistory, activeTools, config.llm.provider);
151
+ // P6: Compress history if conversation is too long
152
+ const historyToUse = (0, contextSummarizer_1.needsCompression)(currentHistory)
153
+ ? await (0, contextSummarizer_1.compressHistory)(currentHistory)
154
+ : currentHistory;
155
+ const sanitizedHistory = sanitizeHistoryForLLM(historyToUse, activeTools, config.llm.provider);
156
+ // P1: Inject scratchpad into system prompt for turns > 1
157
+ const sysPrompt = turnCount === 1
158
+ ? cachedSystemPrompt
159
+ : cachedSystemPrompt + scratchpad.getInjection();
110
160
  const messages = [
111
- { role: 'system', content: getSystemPrompt('web3', input) },
161
+ { role: 'system', content: sysPrompt },
112
162
  ...sanitizedHistory
113
163
  ];
114
164
  const response = await (0, llmUtils_1.executeWithRetry)(async (client) => {
@@ -127,16 +177,59 @@ async function processWeb3Intent(input, role = 'user', onProgress, sessionId) {
127
177
  tracker_1.Tracker.addTokens(response.usage.total_tokens, config.llm.provider);
128
178
  }
129
179
  tracker_1.Tracker.addEvent('llm.response', { provider: config.llm.provider, tool_calls: responseMessage.tool_calls?.length || 0 });
180
+ // P1: Capture <think> blocks for scratchpad, get clean content
181
+ const cleanedContent = scratchpad.capture(responseMessage.content || '', turnCount);
130
182
  exports.logger.addEntry({
131
183
  role: 'assistant',
132
- content: responseMessage.content || "",
184
+ content: cleanedContent || '',
133
185
  tool_calls: responseMessage.tool_calls,
134
186
  }, sessionId);
187
+ // --- LLM FALLBACK COMMAND PARSER (Minimax/Open-weight fix) ---
188
+ if ((!responseMessage.tool_calls || responseMessage.tool_calls.length === 0) && responseMessage.content) {
189
+ const fallbacks = [];
190
+ const regex = /^\/([a-zA-Z0-9_]+)\s+(.*)$/gm;
191
+ let match;
192
+ while ((match = regex.exec(responseMessage.content)) !== null) {
193
+ const toolName = match[1];
194
+ let argsStr = match[2];
195
+ const argsObj = {};
196
+ const kvRegex = /([a-zA-Z0-9_]+)=(".*?"|'.*?'|[^\s]+)/g;
197
+ let kvMatch;
198
+ while ((kvMatch = kvRegex.exec(argsStr)) !== null) {
199
+ let key = kvMatch[1];
200
+ let val = kvMatch[2].replace(/^["']|["']$/g, '');
201
+ argsObj[key] = val;
202
+ }
203
+ // Map generic names if needed
204
+ let mappedToolName = toolName;
205
+ if (toolName === 'transfer' && argsObj.mode === 'bridge')
206
+ mappedToolName = 'bridge_token';
207
+ if (toolName === 'swap')
208
+ mappedToolName = 'swap_token';
209
+ fallbacks.push({
210
+ id: 'call_fallback_' + Math.random().toString(36).substr(2, 9),
211
+ type: 'function',
212
+ function: {
213
+ name: mappedToolName,
214
+ arguments: JSON.stringify(argsObj)
215
+ }
216
+ });
217
+ }
218
+ if (fallbacks.length > 0) {
219
+ responseMessage.tool_calls = fallbacks;
220
+ responseMessage.content = responseMessage.content.replace(/^\/[a-zA-Z0-9_]+\s+.*$/gm, '').trim();
221
+ console.log(picocolors_1.default.cyan(`[Fallback Parser] Intercepted ${fallbacks.length} raw text commands and converted to tool_calls.`));
222
+ // Update logger entry with the intercepted tool calls
223
+ exports.logger.addEntry({
224
+ role: 'assistant',
225
+ content: responseMessage.content || "",
226
+ tool_calls: responseMessage.tool_calls,
227
+ }, sessionId);
228
+ }
229
+ }
230
+ // -----------------------------------------------------
135
231
  if (!responseMessage.tool_calls || responseMessage.tool_calls.length === 0) {
136
- let finalContent = responseMessage.content || "No response generated.";
137
- finalContent = finalContent.replace(/<(think|thought|thinking|reasoning|analysis|reflection)>[\s\S]*?<\/\1>\n?/gi, '');
138
- finalContent = finalContent.trim();
139
- return finalContent;
232
+ return cleanedContent || 'No response generated.';
140
233
  }
141
234
  let canFastReturnAll = true;
142
235
  let accumulatedResults = [];
@@ -144,7 +237,7 @@ async function processWeb3Intent(input, role = 'user', onProgress, sessionId) {
144
237
  const fastReturnTools = [
145
238
  'transfer_token', 'transfer_native', 'swap_token', 'bridge_token',
146
239
  'mint_nft', 'custom_tx', 'revoke_approval', 'supply_aave',
147
- 'deposit_yield_vault', 'provide_liquidity_v3'
240
+ 'deposit_yield_vault', 'provide_liquidity_v3', 'confirm_pending_tx'
148
241
  ];
149
242
  for (const _toolCall of responseMessage.tool_calls) {
150
243
  const toolCall = _toolCall;
@@ -212,8 +305,26 @@ async function processWeb3Intent(input, role = 'user', onProgress, sessionId) {
212
305
  canFastReturnAll = false;
213
306
  }
214
307
  }
215
- // V2 Optimization (Expanded in v1.7.4): Zero-LLM Fast Return for data-heavy and read-only tools
216
- // If all tools already return perfectly formatted markdown, skip the second LLM call to save 5-10s latency!
308
+ // P4: Self-reflection if ALL tools failed, inject reflection before next turn
309
+ const allFailed = accumulatedResults.length > 0 && accumulatedResults.every(r => r.startsWith('Error') || r.includes('[System Error]') || r.includes('[Security Blocked]'));
310
+ if (allFailed) {
311
+ consecutiveToolErrors++;
312
+ const reflection = `[SELF-REFLECTION] All ${accumulatedResults.length} tool call(s) failed (attempt ${consecutiveToolErrors}). ` +
313
+ `Errors: ${accumulatedResults.join(' | ')}. ` +
314
+ `Analyze WHY each failed. Options: (1) retry with corrected params, (2) use alternative tool, (3) inform user clearly. ` +
315
+ `Do NOT repeat the exact same failed call.`;
316
+ exports.logger.addEntry({ role: 'system', content: reflection }, sessionId);
317
+ console.log(picocolors_1.default.magenta(`[Self-Reflection] Turn ${turnCount}: all tools failed, injecting reflection.`));
318
+ if (consecutiveToolErrors >= 2) {
319
+ const errorSummary = `⚠️ Unable to complete this request after multiple attempts.\n${accumulatedResults.join('\n')}`;
320
+ exports.logger.addEntry({ role: 'assistant', content: errorSummary }, sessionId);
321
+ return errorSummary;
322
+ }
323
+ }
324
+ else {
325
+ consecutiveToolErrors = 0;
326
+ }
327
+ // V2 Optimization: Zero-LLM Fast Return for transaction tools
217
328
  if (canFastReturnAll && accumulatedResults.length > 0) {
218
329
  const finalContent = accumulatedResults.join('\n\n---\n\n');
219
330
  exports.logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
@@ -221,7 +332,7 @@ async function processWeb3Intent(input, role = 'user', onProgress, sessionId) {
221
332
  }
222
333
  // Loop continues, sending tool results in the next turn
223
334
  }
224
- const maxTurnMsg = "⚠️ Reached maximum interaction limit (10 turns). Please be more specific.";
335
+ const maxTurnMsg = "⚠️ Reached maximum interaction limit (20 turns). Please be more specific.";
225
336
  exports.logger.addEntry({ role: 'assistant', content: maxTurnMsg }, sessionId);
226
337
  return maxTurnMsg;
227
338
  }
@@ -236,3 +347,118 @@ async function processWeb3Intent(input, role = 'user', onProgress, sessionId) {
236
347
  return errorMsg;
237
348
  }
238
349
  }
350
+ async function processWeb3IntentStream(input, onChunk, onProgress, sessionId) {
351
+ const config = (0, parser_1.loadConfig)();
352
+ exports.logger.addEntry({ role: 'user', content: input }, sessionId);
353
+ const pluginTools = registry_1.pluginManager.getAllToolDefinitions();
354
+ let activeTools = [...pluginTools].filter(t => (0, skillManager_1.isSkillActive)(t.function.name));
355
+ const { sanitizeHistoryForLLM } = require('../utils/historySanitizer');
356
+ try {
357
+ let turnCount = 0;
358
+ const MAX_TURNS = 20;
359
+ let fullResponse = '';
360
+ while (turnCount < MAX_TURNS) {
361
+ turnCount++;
362
+ const currentHistory = exports.logger.getHistory(sessionId);
363
+ const sanitizedHistory = sanitizeHistoryForLLM(currentHistory, activeTools, config.llm.provider);
364
+ const messages = [
365
+ { role: 'system', content: await getSystemPrompt('web3', input) },
366
+ ...sanitizedHistory
367
+ ];
368
+ let streamedContent = '';
369
+ const response = await (0, llmUtils_1.executeWithRetry)(async (client) => {
370
+ return await client.stream({ model: config.llm.model, temperature: config.llm.temperature, messages, tools: activeTools }, (chunk) => {
371
+ streamedContent += chunk;
372
+ onChunk(chunk);
373
+ });
374
+ });
375
+ const responseMessage = response.message;
376
+ if (turnCount === 1)
377
+ tracker_1.Tracker.addMessage();
378
+ if (response.usage?.total_tokens)
379
+ tracker_1.Tracker.addTokens(response.usage.total_tokens, config.llm.provider);
380
+ tracker_1.Tracker.addEvent('llm.response', { provider: config.llm.provider, tool_calls: responseMessage.tool_calls?.length || 0 });
381
+ exports.logger.addEntry({
382
+ role: 'assistant',
383
+ content: responseMessage.content || '',
384
+ tool_calls: responseMessage.tool_calls,
385
+ }, sessionId);
386
+ if (!responseMessage.tool_calls || responseMessage.tool_calls.length === 0) {
387
+ let finalContent = responseMessage.content || 'No response generated.';
388
+ finalContent = finalContent.replace(/<(think|thought|thinking|reasoning|analysis|reflection)[\s\S]*?<\/\1>\n?/gi, '').trim();
389
+ fullResponse = finalContent;
390
+ break;
391
+ }
392
+ // Tool calls detected — pause stream visually and execute tools
393
+ const fastReturnTools = ['transfer_token', 'transfer_native', 'swap_token', 'bridge_token', 'mint_nft', 'custom_tx', 'revoke_approval', 'supply_aave', 'deposit_yield_vault', 'provide_liquidity_v3', 'confirm_pending_tx'];
394
+ let canFastReturnAll = true;
395
+ const accumulatedResults = [];
396
+ for (const _toolCall of responseMessage.tool_calls) {
397
+ const toolCall = _toolCall;
398
+ const toolName = toolCall.function.name;
399
+ let result = '';
400
+ let args = {};
401
+ console.log(picocolors_1.default.yellow(`[⚡ Tool Execution] AI is calling ${toolName}...`));
402
+ if (onProgress)
403
+ onProgress(`_⚡ Running tool: ${toolName}..._`);
404
+ try {
405
+ let argStr = toolCall.function.arguments;
406
+ if (argStr && !argStr.trim().endsWith('}'))
407
+ argStr += '}';
408
+ args = JSON.parse(argStr);
409
+ }
410
+ catch (parseError) {
411
+ result = `[System Error] Arguments for ${toolName} must be valid JSON. Error: ${parseError.message}`;
412
+ exports.logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, content: result }, sessionId);
413
+ continue;
414
+ }
415
+ if (!(0, skillManager_1.isSkillActive)(toolName)) {
416
+ result = `[System Error] Access denied: Skill '${toolName}' is currently disabled.`;
417
+ exports.logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, content: result }, sessionId);
418
+ continue;
419
+ }
420
+ try {
421
+ const pluginResult = await registry_1.pluginManager.executeTool(toolName, args, { sessionId });
422
+ result = pluginResult !== null ? pluginResult : `Error: Tool ${toolName} is not implemented.`;
423
+ if (result.includes('[Security Blocked]') || result.startsWith('Error:')) {
424
+ console.log(picocolors_1.default.red(`[❌ Failed] Tool ${toolName} returned an error or was blocked.`));
425
+ }
426
+ else {
427
+ console.log(picocolors_1.default.green(`[✅ Success] Tool ${toolName} executed successfully.`));
428
+ }
429
+ }
430
+ catch (toolError) {
431
+ result = `Error executing ${toolName}: ${toolError.message}`;
432
+ console.error(picocolors_1.default.red(`[❌ Error Crash] Execution of ${toolName} failed: ${toolError.message}`));
433
+ }
434
+ exports.logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, name: toolName, content: result }, sessionId);
435
+ accumulatedResults.push(result);
436
+ if (!fastReturnTools.includes(toolName))
437
+ canFastReturnAll = false;
438
+ }
439
+ if (canFastReturnAll && accumulatedResults.length > 0) {
440
+ const finalContent = accumulatedResults.join('\n\n---\n\n');
441
+ exports.logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
442
+ onChunk(finalContent);
443
+ fullResponse = finalContent;
444
+ break;
445
+ }
446
+ }
447
+ if (!fullResponse) {
448
+ const maxTurnMsg = '⚠️ Reached maximum interaction limit (20 turns). Please be more specific.';
449
+ exports.logger.addEntry({ role: 'assistant', content: maxTurnMsg }, sessionId);
450
+ fullResponse = maxTurnMsg;
451
+ }
452
+ return fullResponse;
453
+ }
454
+ catch (error) {
455
+ console.error('LLM Stream Error:', error);
456
+ const status = error?.status || error?.response?.status;
457
+ let errorMsg = '⚠️ All models are temporarily rate-limited. Please try again in a few minutes.';
458
+ if (status === 400 || (error.message && error.message.toLowerCase().includes('invalid'))) {
459
+ errorMsg = '⚠️ Failed to parse instruction. Please describe your command more specifically.';
460
+ }
461
+ exports.logger.addEntry({ role: 'assistant', content: errorMsg }, sessionId);
462
+ return errorMsg;
463
+ }
464
+ }
@@ -14,31 +14,84 @@ class CognitiveManager {
14
14
  loadActiveCognitiveSkills(intent) {
15
15
  const activeSOPs = [];
16
16
  const lowerIntent = intent.toLowerCase();
17
- // Mapping of keywords to SOP paths
18
- const skillMappings = [
17
+ // ── Software Development SOPs ──────────────────────────────────────────
18
+ const devSkillMappings = [
19
19
  {
20
- keywords: ['debug', 'error', 'bug', 'fix', 'crash', 'fail', 'trace'],
20
+ keywords: ['debug', 'error', 'bug', 'fix', 'crash', 'fail', 'trace', 'exception', 'undefined', 'null'],
21
21
  file: 'software-development/systematic-debugging.md'
22
22
  },
23
23
  {
24
- keywords: ['tdd', 'test', 'red green', 'unit test', 'jest', 'mocha'],
24
+ keywords: ['tdd', 'test', 'red green', 'unit test', 'jest', 'mocha', 'vitest'],
25
25
  file: 'software-development/test-driven-development.md'
26
26
  },
27
27
  {
28
- keywords: ['plan', 'architecture', 'design', 'structure', 'blueprint'],
28
+ keywords: ['plan', 'architecture', 'design', 'structure', 'blueprint', 'refactor'],
29
29
  file: 'software-development/plan.md'
30
30
  },
31
+ ];
32
+ // ── Web3 / Trading SOPs ────────────────────────────────────────────────
33
+ //
34
+ // NOTE FOR CONTRIBUTORS: Keyword arrays are intentionally multilingual.
35
+ // Nyxora is a global product used by speakers of many languages.
36
+ // Each array includes English terms (primary) and Indonesian terms (id)
37
+ // as the initial non-English locale. Additional languages can be added
38
+ // to each keywords array without changing any other code.
39
+ //
40
+ const web3SkillMappings = [
31
41
  {
32
- keywords: ['binance', 'spot trading', 'exchange trading', 'cex trading', 'api key'],
33
- file: 'autonomous/binance-trading-integration.md'
34
- }
42
+ // Market analysis: price action, momentum, trend direction
43
+ keywords: [
44
+ // English
45
+ 'analysis', 'market', 'chart', 'rsi', 'ma50', 'momentum',
46
+ 'signal', 'bullish', 'bearish', 'trend', 'price', 'pump', 'dump',
47
+ // Indonesian (id)
48
+ 'analisis', 'harga',
49
+ ],
50
+ file: 'web3/market-analysis.md'
51
+ },
52
+ {
53
+ // Risk assessment: security, liquidity, holder concentration
54
+ keywords: [
55
+ // English
56
+ 'risk', 'safe', 'honeypot', 'rug', 'scam', 'dangerous',
57
+ 'liquidity', 'security', 'holder',
58
+ // Indonesian (id)
59
+ 'risiko', 'aman', 'likuiditas', 'keamanan',
60
+ ],
61
+ file: 'web3/risk-assessment.md'
62
+ },
63
+ {
64
+ // Trade planning: entry/exit strategy, order types
65
+ keywords: [
66
+ // English
67
+ 'trade', 'trading', 'entry', 'exit', 'buy', 'sell',
68
+ 'swap', 'position', 'stop loss', 'take profit', 'tp', 'sl',
69
+ 'strategy', 'dca', 'limit order',
70
+ // Indonesian (id)
71
+ 'beli', 'jual', 'posisi', 'strategi',
72
+ ],
73
+ file: 'web3/trade-planning.md'
74
+ },
75
+ {
76
+ // Portfolio review: holdings, rebalancing, allocation
77
+ keywords: [
78
+ // English
79
+ 'portfolio', 'balance', 'rebalance', 'holdings',
80
+ 'asset', 'diversif', 'allocation',
81
+ // Indonesian (id)
82
+ 'portofolio', 'saldo', 'aset', 'alokasi',
83
+ ],
84
+ file: 'web3/portfolio-review.md'
85
+ },
35
86
  ];
36
- for (const mapping of skillMappings) {
87
+ const allMappings = [...devSkillMappings, ...web3SkillMappings];
88
+ for (const mapping of allMappings) {
37
89
  if (mapping.keywords.some(kw => lowerIntent.includes(kw))) {
38
90
  const fullPath = path_1.default.join(this.promptsPath, mapping.file);
39
91
  if (fs_1.default.existsSync(fullPath)) {
40
92
  const content = fs_1.default.readFileSync(fullPath, 'utf8');
41
- activeSOPs.push(`--- COGNITIVE SKILL: ${path_1.default.basename(mapping.file, '.md').toUpperCase()} ---\n${content}`);
93
+ const skillName = path_1.default.basename(mapping.file, '.md').toUpperCase().replace(/-/g, ' ');
94
+ activeSOPs.push(`--- COGNITIVE SKILL: ${skillName} ---\n${content}`);
42
95
  }
43
96
  }
44
97
  }