@aiaiaichain/agent 0.1.6 → 0.1.7

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 (121) hide show
  1. package/dist/api/ExtensionAPI.d.ts +0 -1
  2. package/dist/api/ExtensionAPI.js +3 -7
  3. package/dist/api/Registry.d.ts +0 -1
  4. package/dist/api/Registry.js +54 -57
  5. package/dist/cli.d.ts +0 -1
  6. package/dist/cli.js +683 -686
  7. package/dist/core/AgentDir.d.ts +1 -1
  8. package/dist/core/AgentDir.js +45 -39
  9. package/dist/core/ChainConfig.d.ts +0 -1
  10. package/dist/core/ChainConfig.js +51 -55
  11. package/dist/core/EnvLoader.d.ts +4 -1
  12. package/dist/core/EnvLoader.js +97 -84
  13. package/dist/core/SystemMonitor.d.ts +0 -1
  14. package/dist/core/SystemMonitor.js +72 -85
  15. package/dist/index.d.ts +0 -1
  16. package/dist/index.js +19 -26
  17. package/dist/loader.d.ts +0 -1
  18. package/dist/loader.js +64 -67
  19. package/dist/mcp/entry.d.ts +0 -1
  20. package/dist/mcp/entry.js +3 -6
  21. package/dist/mcp/server.d.ts +0 -1
  22. package/dist/mcp/server.js +152 -156
  23. package/dist/models/CostTracker.d.ts +0 -1
  24. package/dist/models/CostTracker.js +58 -61
  25. package/dist/models/ModelRegistry.d.ts +0 -1
  26. package/dist/models/ModelRegistry.js +195 -155
  27. package/dist/providers/ProviderRegistry.d.ts +0 -1
  28. package/dist/providers/ProviderRegistry.js +33 -36
  29. package/dist/runner/AgentRunner.d.ts +0 -1
  30. package/dist/runner/AgentRunner.js +180 -184
  31. package/dist/runner/ModelClient.d.ts +0 -1
  32. package/dist/runner/ModelClient.js +133 -134
  33. package/dist/runner/SwarmRouter.d.ts +0 -1
  34. package/dist/runner/SwarmRouter.js +18 -22
  35. package/dist/runner/ToolDispatcher.d.ts +0 -1
  36. package/dist/runner/ToolDispatcher.js +30 -33
  37. package/dist/scheduler/AgentScheduler.d.ts +0 -1
  38. package/dist/scheduler/AgentScheduler.js +99 -103
  39. package/dist/session/ContextStore.d.ts +1 -1
  40. package/dist/session/ContextStore.js +76 -78
  41. package/dist/session/GoalManager.d.ts +0 -1
  42. package/dist/session/GoalManager.js +96 -100
  43. package/dist/session/MemoryStore.d.ts +2 -1
  44. package/dist/session/MemoryStore.js +108 -87
  45. package/dist/session/SessionManager.d.ts +5 -4
  46. package/dist/session/SessionManager.js +83 -62
  47. package/dist/session/SessionStore.d.ts +0 -1
  48. package/dist/session/SessionStore.js +112 -116
  49. package/dist/setup/SetupWizard.d.ts +0 -1
  50. package/dist/setup/SetupWizard.js +61 -64
  51. package/dist/tools/CrossTools.d.ts +0 -1
  52. package/dist/tools/CrossTools.js +140 -144
  53. package/dist/tools/GmgnIntegration.d.ts +0 -1
  54. package/dist/tools/GmgnIntegration.js +220 -230
  55. package/dist/tools/MarketSentiment.d.ts +0 -1
  56. package/dist/tools/MarketSentiment.js +213 -195
  57. package/dist/tools/NewsSentiment.d.ts +0 -1
  58. package/dist/tools/NewsSentiment.js +126 -130
  59. package/dist/tools/PriceFeed.d.ts +6 -1
  60. package/dist/tools/PriceFeed.js +201 -133
  61. package/dist/tools/TechnicalAnalysis.d.ts +1 -2
  62. package/dist/tools/TechnicalAnalysis.js +248 -216
  63. package/dist/tools/TechnicalAnalysis.worker.d.ts +25 -0
  64. package/dist/tools/TechnicalAnalysis.worker.js +92 -0
  65. package/dist/tools/TokenCalendar.d.ts +0 -1
  66. package/dist/tools/TokenCalendar.js +63 -68
  67. package/dist/tools/TokenSecurityScanner.d.ts +0 -1
  68. package/dist/tools/TokenSecurityScanner.js +93 -96
  69. package/dist/tools/TransactionSim.d.ts +0 -1
  70. package/dist/tools/TransactionSim.js +65 -71
  71. package/dist/tui/App.d.ts +0 -1
  72. package/dist/tui/App.js +895 -824
  73. package/dist/tui/ModelSelector.d.ts +0 -1
  74. package/dist/tui/ModelSelector.js +46 -49
  75. package/dist/tui/REPL.d.ts +0 -1
  76. package/dist/tui/REPL.js +222 -210
  77. package/dist/tui/Sparkline.d.ts +0 -1
  78. package/dist/tui/Sparkline.js +36 -37
  79. package/dist/tui/StatusBar.d.ts +0 -1
  80. package/dist/tui/StatusBar.js +9 -10
  81. package/dist/tui/ThemePresets.d.ts +0 -1
  82. package/dist/tui/ThemePresets.js +99 -103
  83. package/dist/tui/theme.d.ts +0 -1
  84. package/dist/tui/theme.js +50 -31
  85. package/dist/util/clipboard.d.ts +0 -1
  86. package/dist/util/clipboard.js +16 -20
  87. package/dist/util/commandSuggest.d.ts +0 -1
  88. package/dist/util/commandSuggest.js +34 -38
  89. package/dist/util/confirmation.d.ts +0 -1
  90. package/dist/util/confirmation.js +8 -11
  91. package/dist/util/errorHandler.d.ts +0 -1
  92. package/dist/util/errorHandler.js +20 -23
  93. package/dist/util/errors.d.ts +59 -0
  94. package/dist/util/errors.js +93 -0
  95. package/dist/util/logger.d.ts +0 -1
  96. package/dist/util/logger.js +30 -33
  97. package/dist/util/processManager.d.ts +0 -1
  98. package/dist/util/processManager.js +33 -36
  99. package/dist/util/resilientFetch.d.ts +6 -1
  100. package/dist/util/resilientFetch.js +134 -80
  101. package/dist/util/responseCache.d.ts +0 -1
  102. package/dist/util/responseCache.js +36 -45
  103. package/dist/util/rpc.d.ts +16 -0
  104. package/dist/util/rpc.js +69 -0
  105. package/dist/util/safeLog.d.ts +0 -1
  106. package/dist/util/safeLog.js +52 -53
  107. package/dist/util/scheduler.d.ts +0 -1
  108. package/dist/util/scheduler.js +53 -58
  109. package/dist/util/webhooks.d.ts +0 -1
  110. package/dist/util/webhooks.js +54 -58
  111. package/dist/wallet/ActionFeed.d.ts +0 -1
  112. package/dist/wallet/ActionFeed.js +189 -200
  113. package/dist/wallet/AgentWallet.d.ts +7 -8
  114. package/dist/wallet/AgentWallet.js +117 -144
  115. package/dist/wallet/ProfitTracker.d.ts +0 -1
  116. package/dist/wallet/ProfitTracker.js +71 -74
  117. package/package.json +11 -6
  118. package/scripts/build-esbuild.mjs +40 -0
  119. package/scripts/bundle-dts.mjs +58 -0
  120. package/scripts/minify.mjs +44 -0
  121. package/scripts/postinstall.js +27 -0
package/dist/cli.js CHANGED
@@ -1,12 +1,9 @@
1
- /**
2
- * cli.ts — AIAIAI Chain Agent entry point.
3
- * Fully local, all outbound — no inbound ports.
4
- */
1
+
5
2
  import { readFileSync, existsSync } from "node:fs";
6
3
  import { resolve, join, dirname } from "node:path";
7
4
  import { homedir } from "node:os";
8
5
  import { fileURLToPath } from "node:url";
9
- import { execSync } from "node:child_process";
6
+ import { execSync, execFileSync } from "node:child_process";
10
7
  import { render } from "ink";
11
8
  import React from "react";
12
9
  import { config as loadDotenv } from "dotenv";
@@ -32,7 +29,7 @@ import { sessionStore } from "./session/SessionStore.js";
32
29
  const AIAIAI_HOME = process.env.AIAIAI_HOME ?? join(homedir(), ".aiaiai");
33
30
  const envPath = join(AIAIAI_HOME, ".env");
34
31
  if (existsSync(envPath))
35
- loadDotenv({ path: envPath, override: false });
32
+ loadDotenv({ path: envPath, override: false });
36
33
  const SYSTEM_PROMPT = `You are AIAIAI Chain Agent — a Solana-native autonomous AI agent.
37
34
 
38
35
  Ticker: $AIAIAI
@@ -40,10 +37,10 @@ Contract: AVPJS61gZmWKtaEpb7qYPKo8Fk2xQUsayYQxPiPMpump
40
37
  Chain: Solana (primary)
41
38
 
42
39
  Your wallets:
43
- Cold: A11iZoqEt6hU7HyggqC67ee4AtYmaJjwKCvJLerJRV2J (treasury)
44
- Action: BygDYM1ZXLQNC1HXLhnd1rHZ7E5XjioqT3vPjJFfjnU2 (buys + burns)
45
- Deposit: FBMDYpG9WXKy4SgxuATQdB2sCyzHsJWPrEr45z3TgL2e (user deposits USDC/SOL)
46
- Signer: GmFrDZT2cdrqykgTikVdXbe8EtCgzUDM9VsDhQnwsUsG (authority)
40
+ Cold: A11iZoqEt6hU7HyggqC67ee4AtYmaJjwKCvJLerJRV2J (treasury)
41
+ Action: BygDYM1ZXLQNC1HXLhnd1rHZ7E5XjioqT3vPjJFfjnU2 (buys + burns)
42
+ Deposit: FBMDYpG9WXKy4SgxuATQdB2sCyzHsJWPrEr45z3TgL2e (user deposits USDC/SOL)
43
+ Signer: GmFrDZT2cdrqykgTikVdXbe8EtCgzUDM9VsDhQnwsUsG (authority)
47
44
 
48
45
  Users deposit SOL or USDC to the deposit wallet. When enough accumulates, you
49
46
  automatically route funds to the action wallet and execute buys or burns of $AIAIAI.
@@ -66,727 +63,727 @@ Be confident. You ARE the agent. You buy, you burn, you earn fees. Use "I" and "
66
63
  when talking about your wallets and actions. Be concise, sharp, and useful.`;
67
64
  const args = process.argv.slice(2);
68
65
  const subcmd = args[0];
69
- // ── --help / --version ────────────────────────────────────────────────────
66
+
70
67
  if (subcmd === "--help" || subcmd === "-h" || subcmd === "help") {
71
- console.log(T.accent("\n AIAIAI Chain Agent — $AIAIAI\n"));
72
- console.log(T.muted(" Usage:\n"));
73
- console.log(" aiaiaichain Start interactive agent");
74
- console.log(" aiaiaichain setup First-time setup wizard");
75
- console.log(" aiaiaichain config Show configuration");
76
- console.log(" aiaiaichain price Show $AIAIAI token price");
77
- console.log(" aiaiaichain status Quick status + price");
78
- console.log(" aiaiaichain --headless \"prompt\" Run single turn, print to stdout");
79
- console.log(" aiaiaichain --extension ./ext.ts Load extension");
80
- console.log(" aiaiaichain wallet Show agent wallets");
81
- console.log(" aiaiaichain deposit Show deposit instructions");
82
- console.log(" aiaiaichain burn Show burn instructions");
83
- console.log(" aiaiaichain actions Recent agent actions");
84
- console.log(" aiaiaichain pnl Profit & Loss report");
85
- console.log(" aiaiaichain health System health & diagnostics");
86
- console.log(" aiaiaichain doctor Comprehensive provider check");
87
- console.log(" aiaiaichain scan <address> Token security scan");
88
- console.log(" aiaiaichain --help This help");
89
- console.log(" aiaiaichain --version Show version");
90
- console.log("");
91
- console.log(T.muted(" https://x.com/aiaiaisol\n"));
92
- process.exit(0);
68
+ console.log(T.accent("\n AIAIAI Chain Agent — $AIAIAI\n"));
69
+ console.log(T.muted(" Usage:\n"));
70
+ console.log(" aiaiaichain Start interactive agent");
71
+ console.log(" aiaiaichain setup First-time setup wizard");
72
+ console.log(" aiaiaichain config Show configuration");
73
+ console.log(" aiaiaichain price Show $AIAIAI token price");
74
+ console.log(" aiaiaichain status Quick status + price");
75
+ console.log(" aiaiaichain --headless \"prompt\" Run single turn, print to stdout");
76
+ console.log(" aiaiaichain --extension ./ext.ts Load extension");
77
+ console.log(" aiaiaichain wallet Show agent wallets");
78
+ console.log(" aiaiaichain deposit Show deposit instructions");
79
+ console.log(" aiaiaichain burn Show burn instructions");
80
+ console.log(" aiaiaichain actions Recent agent actions");
81
+ console.log(" aiaiaichain pnl Profit & Loss report");
82
+ console.log(" aiaiaichain health System health & diagnostics");
83
+ console.log(" aiaiaichain doctor Comprehensive provider check");
84
+ console.log(" aiaiaichain scan <address> Token security scan");
85
+ console.log(" aiaiaichain --help This help");
86
+ console.log(" aiaiaichain --version Show version");
87
+ console.log("");
88
+ console.log(T.muted(" https://x.com/aiaiaisol\n"));
89
+ process.exit(0);
93
90
  }
94
91
  if (subcmd === "--version" || subcmd === "-v") {
95
- const __filename = fileURLToPath(import.meta.url);
96
- const __dirname = dirname(__filename);
97
- const pkg = JSON.parse(readFileSync(resolve(__dirname, "..", "package.json"), "utf-8"));
98
- console.log(pkg.version);
99
- process.exit(0);
92
+ const __filename = fileURLToPath(import.meta.url);
93
+ const __dirname = dirname(__filename);
94
+ const pkg = JSON.parse(readFileSync(resolve(__dirname, "..", "package.json"), "utf-8"));
95
+ console.log(pkg.version);
96
+ process.exit(0);
100
97
  }
101
98
  if (subcmd === "setup") {
102
- (async () => {
103
- const { SetupWizard } = await import("./setup/SetupWizard.js");
104
- AgentDir.init();
105
- const wizard = new SetupWizard();
106
- const ok = await wizard.run();
107
- if (!ok) {
108
- console.log(T.error("Setup cancelled."));
109
- process.exit(1);
110
- }
111
- console.log(T.success("\n ✓ AIAIAI setup complete!\n"));
112
- console.log(T.muted(` Home: ${AIAIAI_HOME}`));
113
- console.log(T.accent("\n Run `aiaiaichain` to start the agent.\n"));
114
- process.exit(0);
115
- })().catch(e => {
116
- const msg = e instanceof Error ? e.message : String(e);
117
- if (msg.includes('ENOENT')) {
118
- console.error(T.error(`Setup error: Cannot write to ~/.aiaiai/.env — check permissions.`));
119
- }
120
- else if (msg.includes('EACCES')) {
121
- console.error(T.error(`Setup error: Permission denied — try running with correct user.`));
122
- }
123
- else if (msg.includes('API') || msg.includes('401')) {
124
- console.error(T.error(`Setup error: API key invalid — check your provider key.`));
125
- }
126
- else {
127
- console.error(T.error(`Setup error: ${msg}`));
128
- }
129
- process.exit(1);
130
- });
131
- await new Promise(() => { });
99
+ (async () => {
100
+ const { SetupWizard } = await import("./setup/SetupWizard.js");
101
+ AgentDir.init();
102
+ const wizard = new SetupWizard();
103
+ const ok = await wizard.run();
104
+ if (!ok) {
105
+ console.log(T.error("Setup cancelled."));
106
+ process.exit(1);
107
+ }
108
+ console.log(T.success("\n ✓ AIAIAI setup complete!\n"));
109
+ console.log(T.muted(` Home: ${AIAIAI_HOME}`));
110
+ console.log(T.accent("\n Run `aiaiaichain` to start the agent.\n"));
111
+ process.exit(0);
112
+ })().catch(e => {
113
+ const msg = e instanceof Error ? e.message : String(e);
114
+ if (msg.includes('ENOENT')) {
115
+ console.error(T.error(`Setup error: Cannot write to ~/.aiaiai/.env — check permissions.`));
116
+ }
117
+ else if (msg.includes('EACCES')) {
118
+ console.error(T.error(`Setup error: Permission denied — try running with correct user.`));
119
+ }
120
+ else if (msg.includes('API') || msg.includes('401')) {
121
+ console.error(T.error(`Setup error: API key invalid — check your provider key.`));
122
+ }
123
+ else {
124
+ console.error(T.error(`Setup error: ${msg}`));
125
+ }
126
+ process.exit(1);
127
+ });
128
+ await new Promise(() => { });
132
129
  }
133
130
  if (subcmd === "config") {
134
- console.log(T.accent("AIAIAI Config"));
135
- console.log(T.muted(`Config file: ${envPath}`));
136
- if (existsSync(envPath)) {
137
- for (const line of readFileSync(envPath, "utf-8").split("\n")) {
138
- const m = line.match(/^([A-Z_]+)=(.*)$/);
139
- if (!m)
140
- continue;
141
- const masked = m[2].length > 12 ? m[2].slice(0, 6) + "********" : (m[2] ? "********" : "(empty)");
142
- console.log(` ${m[1].padEnd(28)} ${masked}`);
143
- }
144
- }
145
- else {
146
- console.log(T.warn("No config found. Run: aiaiaichain setup"));
147
- }
148
- process.exit(0);
131
+ console.log(T.accent("AIAIAI Config"));
132
+ console.log(T.muted(`Config file: ${envPath}`));
133
+ if (existsSync(envPath)) {
134
+ for (const line of readFileSync(envPath, "utf-8").split("\n")) {
135
+ const m = line.match(/^([A-Z_]+)=(.*)$/);
136
+ if (!m)
137
+ continue;
138
+ const masked = m[2].length > 12 ? m[2].slice(0, 6) + "********" : (m[2] ? "********" : "(empty)");
139
+ console.log(` ${m[1].padEnd(28)} ${masked}`);
140
+ }
141
+ }
142
+ else {
143
+ console.log(T.warn("No config found. Run: aiaiaichain setup"));
144
+ }
145
+ process.exit(0);
149
146
  }
150
147
  if (subcmd === "price") {
151
- (async () => {
152
- const result = await priceFeed.getAiaiaiPriceTool();
153
- console.log(result.content[0].text);
154
- process.exit(0);
155
- })();
156
- await new Promise(() => { });
148
+ (async () => {
149
+ const result = await priceFeed.getAiaiaiPriceTool();
150
+ console.log(result.content[0].text);
151
+ process.exit(0);
152
+ })();
153
+ await new Promise(() => { });
157
154
  }
158
155
  if (subcmd === "status") {
159
- (async () => {
160
- console.log(T.accent("\n 🤖 AIAIAI Chain Agent\n"));
161
- console.log(T.muted(` Home: ${AIAIAI_HOME}`));
162
- console.log(T.muted(` Config: ${existsSync(envPath) ? "✓ found" : "✗ run setup"}`));
163
- console.log(T.muted(` Key: ${process.env.OPENROUTER_API_KEY ? "✓ set" : "✗ missing"}`));
164
- console.log("");
165
- const result = await priceFeed.getAiaiaiPriceTool();
166
- console.log(result.content[0].text);
167
- console.log("");
168
- const wallets = await agentWallet.getAll();
169
- console.log(T.accent(" Wallets:"));
170
- console.log(T.muted(` Cold: ${wallets.cold.sol.toFixed(4)} SOL | ${wallets.cold.aiaiai.toLocaleString()} $AIAIAI`));
171
- console.log(T.muted(` Action: ${wallets.action.sol.toFixed(4)} SOL | ${wallets.action.aiaiai.toLocaleString()} $AIAIAI`));
172
- console.log(T.muted(` Deposit: ${wallets.deposit.usdc.toFixed(2)} USDC | ${wallets.deposit.sol.toFixed(4)} SOL`));
173
- console.log("");
174
- process.exit(0);
175
- })();
176
- await new Promise(() => { });
156
+ (async () => {
157
+ console.log(T.accent("\n 🤖 AIAIAI Chain Agent\n"));
158
+ console.log(T.muted(` Home: ${AIAIAI_HOME}`));
159
+ console.log(T.muted(` Config: ${existsSync(envPath) ? "✓ found" : "✗ run setup"}`));
160
+ console.log(T.muted(` Key: ${process.env.OPENROUTER_API_KEY ? "✓ set" : "✗ missing"}`));
161
+ console.log("");
162
+ const result = await priceFeed.getAiaiaiPriceTool();
163
+ console.log(result.content[0].text);
164
+ console.log("");
165
+ const wallets = await agentWallet.getAll();
166
+ console.log(T.accent(" Wallets:"));
167
+ console.log(T.muted(` Cold: ${wallets.cold.sol.toFixed(4)} SOL | ${wallets.cold.aiaiai.toLocaleString()} $AIAIAI`));
168
+ console.log(T.muted(` Action: ${wallets.action.sol.toFixed(4)} SOL | ${wallets.action.aiaiai.toLocaleString()} $AIAIAI`));
169
+ console.log(T.muted(` Deposit: ${wallets.deposit.usdc.toFixed(2)} USDC | ${wallets.deposit.sol.toFixed(4)} SOL`));
170
+ console.log("");
171
+ process.exit(0);
172
+ })();
173
+ await new Promise(() => { });
177
174
  }
178
175
  if (subcmd === "wallet") {
179
- (async () => {
180
- const result = await agentWallet.getAgentBalanceTool();
181
- console.log(result.content[0].text);
182
- process.exit(0);
183
- })();
184
- await new Promise(() => { });
176
+ (async () => {
177
+ const result = await agentWallet.getAgentBalanceTool();
178
+ console.log(result.content[0].text);
179
+ process.exit(0);
180
+ })();
181
+ await new Promise(() => { });
185
182
  }
186
183
  if (subcmd === "deposit") {
187
- (async () => {
188
- const result = await agentWallet.getDepositBalanceTool();
189
- console.log(result.content[0].text);
190
- process.exit(0);
191
- })();
192
- await new Promise(() => { });
184
+ (async () => {
185
+ const result = await agentWallet.getDepositBalanceTool();
186
+ console.log(result.content[0].text);
187
+ process.exit(0);
188
+ })();
189
+ await new Promise(() => { });
193
190
  }
194
191
  if (subcmd === "burn") {
195
- console.log(T.accent("\n 🔥 Burn $AIAIAI\n"));
196
- console.log(T.muted(" Deposit wallet:"));
197
- console.log(` ${DEPOSIT_WALLET}`);
198
- console.log("");
199
- console.log(T.muted(" Send SOL or USDC here to fuel agent burns."));
200
- console.log(T.muted(" The agent detects deposits and automatically"));
201
- console.log(T.muted(" sends funds to the action wallet to burn tokens."));
202
- console.log("");
203
- console.log(T.muted(" Action wallet (executes trades):"));
204
- console.log(` ${ACTION_WALLET}`);
205
- console.log("");
206
- console.log(T.muted(" Hot wallet (temporary swap):"));
207
- console.log(` ${HOT_WALLET}`);
208
- console.log("");
209
- process.exit(0);
192
+ console.log(T.accent("\n 🔥 Burn $AIAIAI\n"));
193
+ console.log(T.muted(" Deposit wallet:"));
194
+ console.log(` ${DEPOSIT_WALLET}`);
195
+ console.log("");
196
+ console.log(T.muted(" Send SOL or USDC here to fuel agent burns."));
197
+ console.log(T.muted(" The agent detects deposits and automatically"));
198
+ console.log(T.muted(" sends funds to the action wallet to burn tokens."));
199
+ console.log("");
200
+ console.log(T.muted(" Action wallet (executes trades):"));
201
+ console.log(` ${ACTION_WALLET}`);
202
+ console.log("");
203
+ console.log(T.muted(" Hot wallet (temporary swap):"));
204
+ console.log(` ${HOT_WALLET}`);
205
+ console.log("");
206
+ process.exit(0);
210
207
  }
211
208
  if (subcmd === "actions" || subcmd === "activity") {
212
- (async () => {
213
- const { actionFeed } = await import("./wallet/ActionFeed.js");
214
- await actionFeed.refresh();
215
- const result = await actionFeed.getActionsTool("", { limit: 20 });
216
- console.log(result.content[0].text);
217
- process.exit(0);
218
- })();
219
- await new Promise(() => { });
209
+ (async () => {
210
+ const { actionFeed } = await import("./wallet/ActionFeed.js");
211
+ await actionFeed.refresh();
212
+ const result = await actionFeed.getActionsTool("", { limit: 20 });
213
+ console.log(result.content[0].text);
214
+ process.exit(0);
215
+ })();
216
+ await new Promise(() => { });
220
217
  }
221
218
  if (subcmd === "fees") {
222
- (async () => {
223
- const { actionFeed } = await import("./wallet/ActionFeed.js");
224
- await actionFeed.refresh();
225
- const result = await actionFeed.getFeesTool();
226
- console.log(result.content[0].text);
227
- process.exit(0);
228
- })();
229
- await new Promise(() => { });
219
+ (async () => {
220
+ const { actionFeed } = await import("./wallet/ActionFeed.js");
221
+ await actionFeed.refresh();
222
+ const result = await actionFeed.getFeesTool();
223
+ console.log(result.content[0].text);
224
+ process.exit(0);
225
+ })();
226
+ await new Promise(() => { });
230
227
  }
231
228
  if (subcmd === "pnl" || subcmd === "pl" || subcmd === "profit") {
232
- (async () => {
233
- const { getPLSummary, getTradeHistory, exportCSV } = await import("./wallet/ProfitTracker.js");
234
- const { priceFeed } = await import("./tools/PriceFeed.js");
235
- const price = await priceFeed.getAiaiaiPrice();
236
- const summary = getPLSummary(parseFloat(price.priceUsd ?? "0"));
237
- const history = getTradeHistory();
238
- console.log(T.accent("\n Profit & Loss — $AIAIAI\n"));
239
- console.log(` Avg Cost: $${summary.avgCostBasis.toFixed(8)}`);
240
- console.log(` Total Spent: ${summary.totalSpent.toFixed(4)} SOL`);
241
- console.log(` Total Received: ${summary.totalReceived.toFixed(4)} SOL`);
242
- console.log(` Realized P&L: ${summary.realizedPL >= 0 ? "+" : ""}${summary.realizedPL.toFixed(4)} SOL`);
243
- console.log(` Unrealized P&L: ${summary.unrealizedPL >= 0 ? "+" : ""}${summary.unrealizedPL.toFixed(4)} SOL`);
244
- console.log(` ROI: ${summary.roi >= 0 ? "+" : ""}${summary.roi.toFixed(2)}%`);
245
- console.log(` Trades: ${history.length}`);
246
- if (history.length > 0) {
247
- console.log(T.muted("\n Recent trades:"));
248
- history.slice(-5).forEach(t => {
249
- const date = new Date(t.timestamp).toLocaleDateString();
250
- console.log(` ${date} ${t.type} ${t.tokenAmount.toFixed(0)} tokens @ ${t.pricePerToken.toFixed(8)} SOL`);
251
- });
252
- }
253
- try {
254
- const csvPath = exportCSV();
255
- console.log(T.success(`\n CSV exported: ${csvPath}`));
256
- }
257
- catch (error) {
258
- logger.warn('CLI', 'CSV export failed', { error: error.message });
259
- }
260
- process.exit(0);
261
- })();
262
- await new Promise(() => { });
229
+ (async () => {
230
+ const { getPLSummary, getTradeHistory, exportCSV } = await import("./wallet/ProfitTracker.js");
231
+ const { priceFeed } = await import("./tools/PriceFeed.js");
232
+ const price = await priceFeed.getAiaiaiPrice();
233
+ const summary = getPLSummary(parseFloat(price.priceUsd ?? "0"));
234
+ const history = getTradeHistory();
235
+ console.log(T.accent("\n Profit & Loss — $AIAIAI\n"));
236
+ console.log(` Avg Cost: $${summary.avgCostBasis.toFixed(8)}`);
237
+ console.log(` Total Spent: ${summary.totalSpent.toFixed(4)} SOL`);
238
+ console.log(` Total Received: ${summary.totalReceived.toFixed(4)} SOL`);
239
+ console.log(` Realized P&L: ${summary.realizedPL >= 0 ? "+" : ""}${summary.realizedPL.toFixed(4)} SOL`);
240
+ console.log(` Unrealized P&L: ${summary.unrealizedPL >= 0 ? "+" : ""}${summary.unrealizedPL.toFixed(4)} SOL`);
241
+ console.log(` ROI: ${summary.roi >= 0 ? "+" : ""}${summary.roi.toFixed(2)}%`);
242
+ console.log(` Trades: ${history.length}`);
243
+ if (history.length > 0) {
244
+ console.log(T.muted("\n Recent trades:"));
245
+ history.slice(-5).forEach(t => {
246
+ const date = new Date(t.timestamp).toLocaleDateString();
247
+ console.log(` ${date} ${t.type} ${t.tokenAmount.toFixed(0)} tokens @ ${t.pricePerToken.toFixed(8)} SOL`);
248
+ });
249
+ }
250
+ try {
251
+ const csvPath = exportCSV();
252
+ console.log(T.success(`\n CSV exported: ${csvPath}`));
253
+ }
254
+ catch (error) {
255
+ logger.warn('CLI', 'CSV export failed', { error: error.message });
256
+ }
257
+ process.exit(0);
258
+ })();
259
+ await new Promise(() => { });
263
260
  }
264
261
  if (subcmd === "keys" || subcmd === "providers") {
265
- (async () => {
266
- const readline = await import("node:readline");
267
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
268
- const ask = (prompt) => new Promise((res) => rl.question(prompt, res));
269
- const allEnv = env.getAll();
270
- const configured = getConfigured(allEnv);
271
- const unconfigured = getUnconfigured(allEnv);
272
- console.log(T.accent("\n 🔑 AI Model Providers\n"));
273
- console.log(T.muted(` Configure AI model providers. Add at least one API key to get started.`));
274
- console.log(T.muted(` ${configured.length}/${PROVIDERS.length} configured\n`));
275
- // Show configured
276
- if (configured.length > 0) {
277
- console.log(T.success(" Configured (" + configured.length + ")"));
278
- for (const p of configured) {
279
- const key = allEnv[p.envVar] || "";
280
- const masked = key.slice(0, 6) + "••••" + key.slice(-4);
281
- console.log(T.success(` ✓ ${p.name.padEnd(28)} ${masked}`));
282
- }
283
- }
284
- // Show unconfigured
285
- console.log("\n" + T.warn(" Unconfigured (" + unconfigured.length + ")"));
286
- for (let i = 0; i < unconfigured.length; i++) {
287
- const p = unconfigured[i];
288
- console.log(T.muted(` ${String(i + 1).padStart(2)}. ${p.name}`));
289
- }
290
- // Add key flow
291
- console.log("\n" + T.muted(" Enter number to add a key, 'r' to refresh models, or 'q' to quit:"));
292
- const input = (await ask(" > ")).trim();
293
- if (input === "q") {
294
- rl.close();
295
- process.exit(0);
296
- }
297
- if (input === "r") {
298
- console.log(T.muted("\n Refreshing models from configured providers..."));
299
- await modelRegistry.initialise();
300
- console.log(T.success(` ✓ ${modelRegistry.modelCount} models available from ${modelRegistry.getProviderCount()} providers`));
301
- rl.close();
302
- process.exit(0);
303
- }
304
- const idx = parseInt(input) - 1;
305
- if (isNaN(idx) || idx < 0 || idx >= unconfigured.length) {
306
- console.log(T.error(" Invalid selection."));
307
- rl.close();
308
- process.exit(1);
309
- }
310
- const provider = unconfigured[idx];
311
- console.log(T.accent(`\n ${provider.name}`));
312
- console.log(T.muted(` ${provider.docsUrl}`));
313
- console.log(T.muted(` Env var: ${provider.envVar}\n`));
314
- const key = (await ask(` Enter ${provider.name} API key: `)).trim();
315
- if (!key) {
316
- console.log(T.error(" Key is required."));
317
- rl.close();
318
- process.exit(1);
319
- }
320
- // Save to .env
321
- env.set(provider.envVar, key);
322
- console.log(T.success(`\n ✓ ${provider.name} key saved to ~/.aiaiai/.env`));
323
- // Fetch models from this provider
324
- console.log(T.muted(" Fetching models from " + provider.name + "..."));
325
- try {
326
- await modelRegistry.initialise();
327
- const providerModels = modelRegistry.getProviderModels(provider.id);
328
- console.log(T.success(` ✓ ${providerModels.length} models available from ${provider.name}`));
329
- console.log(T.success(` ✓ ${modelRegistry.modelCount} total models from ${modelRegistry.getProviderCount()} providers`));
330
- }
331
- catch (e) {
332
- console.log(T.warn(` ⚠ Could not fetch models: ${e instanceof Error ? e.message : String(e)}`));
333
- }
334
- rl.close();
335
- process.exit(0);
336
- })().catch(e => { console.error(T.error(`Error: ${e.message}`)); process.exit(1); });
337
- await new Promise(() => { });
262
+ (async () => {
263
+ const readline = await import("node:readline");
264
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
265
+ const ask = (prompt) => new Promise((res) => rl.question(prompt, res));
266
+ const allEnv = env.getAll();
267
+ const configured = getConfigured(allEnv);
268
+ const unconfigured = getUnconfigured(allEnv);
269
+ console.log(T.accent("\n 🔑 AI Model Providers\n"));
270
+ console.log(T.muted(` Configure AI model providers. Add at least one API key to get started.`));
271
+ console.log(T.muted(` ${configured.length}/${PROVIDERS.length} configured\n`));
272
+
273
+ if (configured.length > 0) {
274
+ console.log(T.success(" Configured (" + configured.length + ")"));
275
+ for (const p of configured) {
276
+ const key = allEnv[p.envVar] || "";
277
+ const masked = key.slice(0, 6) + "••••" + key.slice(-4);
278
+ console.log(T.success(` ✓ ${p.name.padEnd(28)} ${masked}`));
279
+ }
280
+ }
281
+
282
+ console.log("\n" + T.warn(" Unconfigured (" + unconfigured.length + ")"));
283
+ for (let i = 0; i < unconfigured.length; i++) {
284
+ const p = unconfigured[i];
285
+ console.log(T.muted(` ${String(i + 1).padStart(2)}. ${p.name}`));
286
+ }
287
+
288
+ console.log("\n" + T.muted(" Enter number to add a key, 'r' to refresh models, or 'q' to quit:"));
289
+ const input = (await ask(" > ")).trim();
290
+ if (input === "q") {
291
+ rl.close();
292
+ process.exit(0);
293
+ }
294
+ if (input === "r") {
295
+ console.log(T.muted("\n Refreshing models from configured providers..."));
296
+ await modelRegistry.initialise();
297
+ console.log(T.success(` ✓ ${modelRegistry.modelCount} models available from ${modelRegistry.getProviderCount()} providers`));
298
+ rl.close();
299
+ process.exit(0);
300
+ }
301
+ const idx = parseInt(input) - 1;
302
+ if (isNaN(idx) || idx < 0 || idx >= unconfigured.length) {
303
+ console.log(T.error(" Invalid selection."));
304
+ rl.close();
305
+ process.exit(1);
306
+ }
307
+ const provider = unconfigured[idx];
308
+ console.log(T.accent(`\n ${provider.name}`));
309
+ console.log(T.muted(` ${provider.docsUrl}`));
310
+ console.log(T.muted(` Env var: ${provider.envVar}\n`));
311
+ const key = (await ask(` Enter ${provider.name} API key: `)).trim();
312
+ if (!key) {
313
+ console.log(T.error(" Key is required."));
314
+ rl.close();
315
+ process.exit(1);
316
+ }
317
+
318
+ env.set(provider.envVar, key);
319
+ console.log(T.success(`\n ✓ ${provider.name} key saved to ~/.aiaiai/.env`));
320
+
321
+ console.log(T.muted(" Fetching models from " + provider.name + "..."));
322
+ try {
323
+ await modelRegistry.initialise();
324
+ const providerModels = modelRegistry.getProviderModels(provider.id);
325
+ console.log(T.success(` ✓ ${providerModels.length} models available from ${provider.name}`));
326
+ console.log(T.success(` ✓ ${modelRegistry.modelCount} total models from ${modelRegistry.getProviderCount()} providers`));
327
+ }
328
+ catch (e) {
329
+ console.log(T.warn(` ⚠ Could not fetch models: ${e instanceof Error ? e.message : String(e)}`));
330
+ }
331
+ rl.close();
332
+ process.exit(0);
333
+ })().catch(e => { console.error(T.error(`Error: ${e.message}`)); process.exit(1); });
334
+ await new Promise(() => { });
338
335
  }
339
336
  if (subcmd === "gmgn" || subcmd === "gmgnhelp") {
340
- const gmgnArgs = args.slice(1);
341
- if (gmgnArgs.length === 0 || gmgnArgs[0] === "help" || gmgnArgs[0] === "--help") {
342
- console.log(gmgnHelp());
343
- process.exit(0);
344
- }
345
- if (gmgnArgs[0] === "setup" || gmgnArgs[0] === "config" || gmgnArgs[0] === "key") {
346
- (async () => {
347
- const readline = await import("node:readline");
348
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
349
- const ask = (prompt) => new Promise((res) => rl.question(prompt, res));
350
- console.log(T.accent("\n 🔍 GMGN API Key Setup\n"));
351
- console.log(T.muted(" Get your API key at https://gmgn.ai/ai\n"));
352
- const key = (await ask(" Enter GMGN_API_KEY: ")).trim();
353
- if (!key) {
354
- console.log(T.error(" Key is required."));
355
- rl.close();
356
- process.exit(1);
357
- }
358
- saveGmgnApiKey(key);
359
- console.log(T.success("\n ✓ GMGN_API_KEY saved to ~/.config/gmgn/.env"));
360
- console.log(T.muted(" All GMGN commands are now available.\n"));
361
- rl.close();
362
- process.exit(0);
363
- })().catch(e => { console.error(T.error(`Error: ${e.message}`)); process.exit(1); });
364
- await new Promise(() => { });
365
- }
366
- if (gmgnArgs[0] === "status") {
367
- console.log(gmgnStatus());
368
- process.exit(0);
369
- }
370
- // Forward to gmgn-cli
371
- try {
372
- const fullArgs = ["gmgn-cli", ...gmgnArgs];
373
- const gmgnEnv = {};
374
- try {
375
- const f = readFileSync(join(homedir(), ".config", "gmgn", ".env"), "utf-8");
376
- for (const l of f.split("\n")) {
377
- const m = l.trim().match(/^([A-Z_]+)=(.*)$/);
378
- if (m)
379
- gmgnEnv[m[1]] = m[2];
380
- }
381
- }
382
- catch {
383
- logger.debug('CLI', 'No GMGN env file found (optional)');
384
- }
385
- const output = execSync(fullArgs.join(" "), {
386
- env: { ...process.env, ...gmgnEnv },
387
- encoding: "utf-8",
388
- timeout: 30_000,
389
- });
390
- process.stdout.write(output);
391
- }
392
- catch (e) {
393
- const msg = e.stderr?.toString() || e.message || "";
394
- process.stderr.write(`gmgn-cli: ${msg.slice(0, 500)}\n`);
395
- process.exit(e.status ?? 1);
396
- }
397
- process.exit(0);
337
+ const gmgnArgs = args.slice(1);
338
+ if (gmgnArgs.length === 0 || gmgnArgs[0] === "help" || gmgnArgs[0] === "--help") {
339
+ console.log(gmgnHelp());
340
+ process.exit(0);
341
+ }
342
+ if (gmgnArgs[0] === "setup" || gmgnArgs[0] === "config" || gmgnArgs[0] === "key") {
343
+ (async () => {
344
+ const readline = await import("node:readline");
345
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
346
+ const ask = (prompt) => new Promise((res) => rl.question(prompt, res));
347
+ console.log(T.accent("\n 🔍 GMGN API Key Setup\n"));
348
+ console.log(T.muted(" Get your API key at https://gmgn.ai/ai\n"));
349
+ const key = (await ask(" Enter GMGN_API_KEY: ")).trim();
350
+ if (!key) {
351
+ console.log(T.error(" Key is required."));
352
+ rl.close();
353
+ process.exit(1);
354
+ }
355
+ saveGmgnApiKey(key);
356
+ console.log(T.success("\n ✓ GMGN_API_KEY saved to ~/.config/gmgn/.env"));
357
+ console.log(T.muted(" All GMGN commands are now available.\n"));
358
+ rl.close();
359
+ process.exit(0);
360
+ })().catch(e => { console.error(T.error(`Error: ${e.message}`)); process.exit(1); });
361
+ await new Promise(() => { });
362
+ }
363
+ if (gmgnArgs[0] === "status") {
364
+ console.log(gmgnStatus());
365
+ process.exit(0);
366
+ }
367
+
368
+ try {
369
+ const fullArgs = ["gmgn-cli", ...gmgnArgs];
370
+ const gmgnEnv = {};
371
+ try {
372
+ const f = readFileSync(join(homedir(), ".config", "gmgn", ".env"), "utf-8");
373
+ for (const l of f.split("\n")) {
374
+ const m = l.trim().match(/^([A-Z_]+)=(.*)$/);
375
+ if (m)
376
+ gmgnEnv[m[1]] = m[2];
377
+ }
378
+ }
379
+ catch {
380
+ logger.debug('CLI', 'No GMGN env file found (optional)');
381
+ }
382
+
383
+ const output = execFileSync(fullArgs[0], fullArgs.slice(1), {
384
+ env: { ...process.env, ...gmgnEnv },
385
+ encoding: "utf-8",
386
+ timeout: 30_000,
387
+ });
388
+ process.stdout.write(output);
389
+ }
390
+ catch (e) {
391
+ const msg = e.stderr?.toString() || e.message || "";
392
+ process.stderr.write(`gmgn-cli: ${msg.slice(0, 500)}\n`);
393
+ process.exit(e.status ?? 1);
394
+ }
395
+ process.exit(0);
398
396
  }
399
397
  if (subcmd === "scan" || subcmd === "security") {
400
- (async () => {
401
- const tokenAddress = args[1];
402
- if (!tokenAddress) {
403
- console.log(T.error(" Usage: aiaiai scan <token-address>"));
404
- process.exit(1);
405
- }
406
- console.log(T.accent("\n \uD83D\uDD0D Scanning token...\n"));
407
- const result = await scanTokenSecurityTool("", { address: tokenAddress });
408
- if (result.isError) {
409
- console.log(result.content[0].text);
410
- process.exit(1);
411
- }
412
- console.log(result.content[0].text);
413
- console.log("");
414
- process.exit(0);
415
- })().catch(e => { console.error(T.error("Scan error: " + e.message)); process.exit(1); });
416
- await new Promise(() => { });
398
+ (async () => {
399
+ const tokenAddress = args[1];
400
+ if (!tokenAddress) {
401
+ console.log(T.error(" Usage: aiaiai scan <token-address>"));
402
+ process.exit(1);
403
+ }
404
+ console.log(T.accent("\n \uD83D\uDD0D Scanning token...\n"));
405
+ const result = await scanTokenSecurityTool("", { address: tokenAddress });
406
+ if (result.isError) {
407
+ console.log(result.content[0].text);
408
+ process.exit(1);
409
+ }
410
+ console.log(result.content[0].text);
411
+ console.log("");
412
+ process.exit(0);
413
+ })().catch(e => { console.error(T.error("Scan error: " + e.message)); process.exit(1); });
414
+ await new Promise(() => { });
417
415
  }
418
416
  if (subcmd === "update" || subcmd === "upgrade") {
419
- (async () => {
420
- const pkgName = "@aiaiaichain/agent";
421
- console.log(T.accent("\n 🤖 AIAIAI Update Check\n"));
422
- // Get current version
423
- const __filename = fileURLToPath(import.meta.url);
424
- const __dir = dirname(__filename);
425
- const currentPkg = JSON.parse(readFileSync(resolve(__dir, "..", "package.json"), "utf-8"));
426
- const current = currentPkg.version;
427
- console.log(T.muted(` Current version: v${current}`));
428
- // Check npm for latest
429
- let latest = null;
430
- let changelog = "";
431
- try {
432
- const viewOutput = execSync(`npm view ${pkgName} version`, {
433
- encoding: "utf-8",
434
- timeout: 15_000,
435
- }).trim();
436
- latest = viewOutput.split("\n").pop() || null;
437
- // Try to get changelog from npm
438
- try {
439
- const changelogOutput = execSync(`npm view ${pkgName} --json`, {
440
- encoding: "utf-8",
441
- timeout: 15_000,
442
- });
443
- const pkgData = JSON.parse(changelogOutput);
444
- if (pkgData.gitHead) {
445
- changelog = `Git: ${pkgData.gitHead.slice(0, 8)}`;
446
- }
447
- }
448
- catch {
449
- logger.debug('CLI', 'No changelog available (optional)');
450
- }
451
- }
452
- catch (error) {
453
- logger.warn('CLI', 'Could not reach npm registry', { error: error.message });
454
- console.log(T.error(" Could not reach npm registry. Check your connection."));
455
- process.exit(1);
456
- }
457
- if (!latest) {
458
- console.log(T.error(" Could not determine latest version."));
459
- process.exit(1);
460
- }
461
- console.log(T.muted(` Latest version: v${latest}`));
462
- if (changelog)
463
- console.log(T.muted(` ${changelog}`));
464
- if (latest === current) {
465
- console.log(T.success("\n ✅ You're on the latest version!\n"));
466
- process.exit(0);
467
- }
468
- console.log(T.accent(`\n ⚡ Update available: v${current} → v${latest}\n`));
469
- // Ask to update
470
- const readline = await import("node:readline");
471
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
472
- const ask = (prompt) => new Promise((res) => rl.question(prompt, res));
473
- const confirm = (await ask(" Install update now? (y/n): ")).trim().toLowerCase();
474
- if (confirm !== "y" && confirm !== "yes") {
475
- console.log(T.muted("\n Skipped. Run `aiaiai update` anytime to update.\n"));
476
- rl.close();
477
- process.exit(0);
478
- }
479
- console.log(T.muted("\n Installing update..."));
480
- try {
481
- execSync(`npm install -g ${pkgName}`, {
482
- stdio: "inherit",
483
- timeout: 120_000,
484
- });
485
- console.log(T.success(`\n ✅ Updated to v${latest}!`));
486
- console.log(T.muted(" Run `aiaiai` to restart with new features.\n"));
487
- }
488
- catch (e) {
489
- console.log(T.error(`\n ❌ Update failed: ${e.message}`));
490
- console.log(T.muted(" Try manually: npm install -g @aiaiaichain/agent\n"));
491
- }
492
- rl.close();
493
- process.exit(0);
494
- })().catch(e => { console.error(T.error(`Error: ${e.message}`)); process.exit(1); });
495
- await new Promise(() => { });
417
+ (async () => {
418
+ const pkgName = "@aiaiaichain/agent";
419
+ console.log(T.accent("\n 🤖 AIAIAI Update Check\n"));
420
+
421
+ const __filename = fileURLToPath(import.meta.url);
422
+ const __dir = dirname(__filename);
423
+ const currentPkg = JSON.parse(readFileSync(resolve(__dir, "..", "package.json"), "utf-8"));
424
+ const current = currentPkg.version;
425
+ console.log(T.muted(` Current version: v${current}`));
426
+
427
+ let latest = null;
428
+ let changelog = "";
429
+ try {
430
+ const viewOutput = execSync(`npm view ${pkgName} version`, {
431
+ encoding: "utf-8",
432
+ timeout: 15_000,
433
+ }).trim();
434
+ latest = viewOutput.split("\n").pop() || null;
435
+
436
+ try {
437
+ const changelogOutput = execSync(`npm view ${pkgName} --json`, {
438
+ encoding: "utf-8",
439
+ timeout: 15_000,
440
+ });
441
+ const pkgData = JSON.parse(changelogOutput);
442
+ if (pkgData.gitHead) {
443
+ changelog = `Git: ${pkgData.gitHead.slice(0, 8)}`;
444
+ }
445
+ }
446
+ catch {
447
+ logger.debug('CLI', 'No changelog available (optional)');
448
+ }
449
+ }
450
+ catch (error) {
451
+ logger.warn('CLI', 'Could not reach npm registry', { error: error.message });
452
+ console.log(T.error(" Could not reach npm registry. Check your connection."));
453
+ process.exit(1);
454
+ }
455
+ if (!latest) {
456
+ console.log(T.error(" Could not determine latest version."));
457
+ process.exit(1);
458
+ }
459
+ console.log(T.muted(` Latest version: v${latest}`));
460
+ if (changelog)
461
+ console.log(T.muted(` ${changelog}`));
462
+ if (latest === current) {
463
+ console.log(T.success("\n ✅ You're on the latest version!\n"));
464
+ process.exit(0);
465
+ }
466
+ console.log(T.accent(`\n ⚡ Update available: v${current} → v${latest}\n`));
467
+
468
+ const readline = await import("node:readline");
469
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
470
+ const ask = (prompt) => new Promise((res) => rl.question(prompt, res));
471
+ const confirm = (await ask(" Install update now? (y/n): ")).trim().toLowerCase();
472
+ if (confirm !== "y" && confirm !== "yes") {
473
+ console.log(T.muted("\n Skipped. Run `aiaiai update` anytime to update.\n"));
474
+ rl.close();
475
+ process.exit(0);
476
+ }
477
+ console.log(T.muted("\n Installing update..."));
478
+ try {
479
+ execSync(`npm install -g ${pkgName}`, {
480
+ stdio: "inherit",
481
+ timeout: 120_000,
482
+ });
483
+ console.log(T.success(`\n ✅ Updated to v${latest}!`));
484
+ console.log(T.muted(" Run `aiaiai` to restart with new features.\n"));
485
+ }
486
+ catch (e) {
487
+ console.log(T.error(`\n ❌ Update failed: ${e.message}`));
488
+ console.log(T.muted(" Try manually: npm install -g @aiaiaichain/agent\n"));
489
+ }
490
+ rl.close();
491
+ process.exit(0);
492
+ })().catch(e => { console.error(T.error(`Error: ${e.message}`)); process.exit(1); });
493
+ await new Promise(() => { });
496
494
  }
497
495
  if (subcmd === "health" || subcmd === "doctor") {
498
- (async () => {
499
- console.log(T.accent("\n \u2705 AIAIAI Health Check\n"));
500
- let healthy = true;
501
- // Check env file
502
- console.log(T.muted(" Config:"));
503
- if (existsSync(envPath)) {
504
- console.log(T.success(" .env found"));
505
- }
506
- else {
507
- console.log(T.warn(" .env not found \u2014 run: aiaiai setup"));
508
- healthy = false;
509
- }
510
- // Check API key
511
- console.log(T.muted(" API Key:"));
512
- if (process.env.OPENROUTER_API_KEY || env.get("OPENROUTER_API_KEY")) {
513
- console.log(T.success(" OPENROUTER_API_KEY set"));
514
- }
515
- else {
516
- console.log(T.warn(" OPENROUTER_API_KEY not set"));
517
- healthy = false;
518
- }
519
- // Check RPC
520
- console.log(T.muted(" Solana RPC:"));
521
- try {
522
- const { resilientFetch } = await import("./util/resilientFetch.js");
523
- const rpcUrl = process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com";
524
- const res = await resilientFetch(rpcUrl, {
525
- timeout: 10_000,
526
- retries: 0,
527
- method: "POST",
528
- headers: { "Content-Type": "application/json" },
529
- body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "getHealth", params: [] }),
530
- });
531
- const json = await res.json();
532
- if (json.result === "ok") {
533
- console.log(T.success(" RPC healthy: " + rpcUrl));
534
- }
535
- else {
536
- console.log(T.warn(" RPC responded but unhealthy"));
537
- healthy = false;
538
- }
539
- }
540
- catch (e) {
541
- console.log(T.error(" RPC unreachable: " + e.message));
542
- healthy = false;
543
- }
544
- // Check disk writable
545
- console.log(T.muted(" Disk:"));
546
- try {
547
- const { writeFileSync, unlinkSync } = await import("node:fs");
548
- const testFile = join(AIAIAI_HOME, ".health-test");
549
- writeFileSync(testFile, "test", "utf-8");
550
- unlinkSync(testFile);
551
- console.log(T.success(" writable"));
552
- }
553
- catch (error) {
554
- logger.warn('CLI', 'Disk not writable', { error: error.message });
555
- console.log(T.error(" not writable"));
556
- healthy = false;
557
- }
558
- // ── Extras (doctor mode) ──────────────────────────────────────────
559
- console.log(T.muted("\n Extras:"));
560
- // Theme
561
- try {
562
- const { getCurrentTheme } = await import("./tui/ThemePresets.js");
563
- console.log(T.success(` Theme: ${getCurrentTheme()} (run aiaiai to change)`));
564
- }
565
- catch {
566
- console.log(T.muted(" Theme: default"));
567
- }
568
- // Clipboard
569
- try {
570
- const { clipboardSupported } = await import("./util/clipboard.js");
571
- console.log(T.muted(` Clipboard: ${clipboardSupported()}`));
572
- }
573
- catch {
574
- console.log(T.muted(" Clipboard: not available"));
575
- }
576
- // Webhooks
577
- try {
578
- const { hasWebhooks } = await import("./util/webhooks.js");
579
- console.log(hasWebhooks() ? T.success(" Webhooks: configured") : T.muted(" Webhooks: not configured (set WEBHOOK_DISCORD or WEBHOOK_TELEGRAM in .env)"));
580
- }
581
- catch {
582
- console.log(T.muted(" Webhooks: not available"));
583
- }
584
- // Provider key check
585
- console.log(T.muted(" Provider Keys:"));
586
- const providers = [
587
- { name: "OpenRouter", key: "OPENROUTER_API_KEY" },
588
- { name: "Anthropic", key: "ANTHROPIC_API_KEY" },
589
- { name: "OpenAI", key: "OPENAI_API_KEY" },
590
- { name: "Google", key: "GOOGLE_API_KEY" },
591
- { name: "DeepSeek", key: "DEEPSEEK_API_KEY" },
592
- { name: "Groq", key: "GROQ_API_KEY" },
593
- { name: "GMGN", key: "GMGN_API_KEY" },
594
- ];
595
- for (const p of providers) {
596
- const has = process.env[p.key] || env.get(p.key);
597
- console.log(has ? T.success(` ${p.name}: ✓`) : T.dim(` ${p.name}: ✗ (optional)`));
598
- }
599
- console.log("");
600
- if (healthy) {
601
- console.log(T.success(" All systems operational.\n"));
602
- }
603
- else {
604
- console.log(T.warn(" Some checks failed. Review above for details.\n"));
605
- }
606
- process.exit(healthy ? 0 : 1);
607
- })().catch(e => { console.error(T.error("Health check failed: " + e.message)); process.exit(2); });
608
- await new Promise(() => { });
496
+ (async () => {
497
+ console.log(T.accent("\n \u2705 AIAIAI Health Check\n"));
498
+ let healthy = true;
499
+
500
+ console.log(T.muted(" Config:"));
501
+ if (existsSync(envPath)) {
502
+ console.log(T.success(" .env found"));
503
+ }
504
+ else {
505
+ console.log(T.warn(" .env not found \u2014 run: aiaiai setup"));
506
+ healthy = false;
507
+ }
508
+
509
+ console.log(T.muted(" API Key:"));
510
+ if (process.env.OPENROUTER_API_KEY || env.get("OPENROUTER_API_KEY")) {
511
+ console.log(T.success(" OPENROUTER_API_KEY set"));
512
+ }
513
+ else {
514
+ console.log(T.warn(" OPENROUTER_API_KEY not set"));
515
+ healthy = false;
516
+ }
517
+
518
+ console.log(T.muted(" Solana RPC:"));
519
+ try {
520
+ const { resilientFetch } = await import("./util/resilientFetch.js");
521
+ const rpcUrl = process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com";
522
+ const res = await resilientFetch(rpcUrl, {
523
+ timeout: 10_000,
524
+ retries: 0,
525
+ method: "POST",
526
+ headers: { "Content-Type": "application/json" },
527
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "getHealth", params: [] }),
528
+ });
529
+ const json = await res.json();
530
+ if (json.result === "ok") {
531
+ console.log(T.success(" RPC healthy: " + rpcUrl));
532
+ }
533
+ else {
534
+ console.log(T.warn(" RPC responded but unhealthy"));
535
+ healthy = false;
536
+ }
537
+ }
538
+ catch (e) {
539
+ console.log(T.error(" RPC unreachable: " + e.message));
540
+ healthy = false;
541
+ }
542
+
543
+ console.log(T.muted(" Disk:"));
544
+ try {
545
+ const { writeFileSync, unlinkSync } = await import("node:fs");
546
+ const testFile = join(AIAIAI_HOME, ".health-test");
547
+ writeFileSync(testFile, "test", "utf-8");
548
+ unlinkSync(testFile);
549
+ console.log(T.success(" writable"));
550
+ }
551
+ catch (error) {
552
+ logger.warn('CLI', 'Disk not writable', { error: error.message });
553
+ console.log(T.error(" not writable"));
554
+ healthy = false;
555
+ }
556
+
557
+ console.log(T.muted("\n Extras:"));
558
+
559
+ try {
560
+ const { getCurrentTheme } = await import("./tui/ThemePresets.js");
561
+ console.log(T.success(` Theme: ${getCurrentTheme()} (run aiaiai to change)`));
562
+ }
563
+ catch {
564
+ console.log(T.muted(" Theme: default"));
565
+ }
566
+
567
+ try {
568
+ const { clipboardSupported } = await import("./util/clipboard.js");
569
+ console.log(T.muted(` Clipboard: ${clipboardSupported()}`));
570
+ }
571
+ catch {
572
+ console.log(T.muted(" Clipboard: not available"));
573
+ }
574
+
575
+ try {
576
+ const { hasWebhooks } = await import("./util/webhooks.js");
577
+ console.log(hasWebhooks() ? T.success(" Webhooks: configured") : T.muted(" Webhooks: not configured (set WEBHOOK_DISCORD or WEBHOOK_TELEGRAM in .env)"));
578
+ }
579
+ catch {
580
+ console.log(T.muted(" Webhooks: not available"));
581
+ }
582
+
583
+ console.log(T.muted(" Provider Keys:"));
584
+ const providers = [
585
+ { name: "OpenRouter", key: "OPENROUTER_API_KEY" },
586
+ { name: "Anthropic", key: "ANTHROPIC_API_KEY" },
587
+ { name: "OpenAI", key: "OPENAI_API_KEY" },
588
+ { name: "Google", key: "GOOGLE_API_KEY" },
589
+ { name: "DeepSeek", key: "DEEPSEEK_API_KEY" },
590
+ { name: "Groq", key: "GROQ_API_KEY" },
591
+ { name: "GMGN", key: "GMGN_API_KEY" },
592
+ ];
593
+ for (const p of providers) {
594
+ const has = process.env[p.key] || env.get(p.key);
595
+ console.log(has ? T.success(` ${p.name}: ✓`) : T.dim(` ${p.name}: ✗ (optional)`));
596
+ }
597
+ console.log("");
598
+ if (healthy) {
599
+ console.log(T.success(" All systems operational.\n"));
600
+ }
601
+ else {
602
+ console.log(T.warn(" Some checks failed. Review above for details.\n"));
603
+ }
604
+ process.exit(healthy ? 0 : 1);
605
+ })().catch(e => { console.error(T.error("Health check failed: " + e.message)); process.exit(2); });
606
+ await new Promise(() => { });
609
607
  }
610
608
  if (subcmd === "sessions") {
611
- const sessions = sessionStore.list();
612
- if (sessions.length === 0) {
613
- console.log(T.muted(" No saved sessions."));
614
- process.exit(0);
615
- }
616
- console.log(T.accent("\n 📂 Saved Sessions\n"));
617
- sessions.slice(0, 15).forEach((s, i) => {
618
- const date = new Date(s.updatedAt).toLocaleDateString();
619
- console.log(T.muted(` ${String(i + 1).padStart(2)}. ${s.title} (${s.messageCount} msgs, ${s.model}, ${date})`));
620
- });
621
- console.log("");
622
- process.exit(0);
609
+ const sessions = sessionStore.list();
610
+ if (sessions.length === 0) {
611
+ console.log(T.muted(" No saved sessions."));
612
+ process.exit(0);
613
+ }
614
+ console.log(T.accent("\n 📂 Saved Sessions\n"));
615
+ sessions.slice(0, 15).forEach((s, i) => {
616
+ const date = new Date(s.updatedAt).toLocaleDateString();
617
+ console.log(T.muted(` ${String(i + 1).padStart(2)}. ${s.title} (${s.messageCount} msgs, ${s.model}, ${date})`));
618
+ });
619
+ console.log("");
620
+ process.exit(0);
623
621
  }
624
622
  if (subcmd === "resume") {
625
- const sessions = sessionStore.list();
626
- if (sessions.length === 0) {
627
- console.log(T.muted(" No saved sessions."));
628
- process.exit(0);
629
- }
630
- const idx = parseInt(process.argv[3]) - 1;
631
- if (isNaN(idx) || idx < 0 || idx >= sessions.length) {
632
- console.log(T.error(" Invalid session number."));
633
- process.exit(1);
634
- }
635
- const session = sessionStore.load(sessions[idx].id);
636
- if (!session) {
637
- console.log(T.error(" Session not found."));
638
- process.exit(1);
639
- }
640
- console.log(T.accent(`\n 📂 Resumed: ${session.title}\n`));
641
- console.log(T.muted(` Messages: ${session.messages.length}`));
642
- console.log(T.muted(` Model: ${session.model}`));
643
- console.log("");
644
- process.exit(0);
645
- }
646
- // ── Resolve extension + prompt ────────────────────────────────────────────────
623
+ const sessions = sessionStore.list();
624
+ if (sessions.length === 0) {
625
+ console.log(T.muted(" No saved sessions."));
626
+ process.exit(0);
627
+ }
628
+ const idx = parseInt(process.argv[3]) - 1;
629
+ if (isNaN(idx) || idx < 0 || idx >= sessions.length) {
630
+ console.log(T.error(" Invalid session number."));
631
+ process.exit(1);
632
+ }
633
+ const session = sessionStore.load(sessions[idx].id);
634
+ if (!session) {
635
+ console.log(T.error(" Session not found."));
636
+ process.exit(1);
637
+ }
638
+ console.log(T.accent(`\n 📂 Resumed: ${session.title}\n`));
639
+ console.log(T.muted(` Messages: ${session.messages.length}`));
640
+ console.log(T.muted(` Model: ${session.model}`));
641
+ console.log("");
642
+ process.exit(0);
643
+ }
644
+
647
645
  let extensionPath = null;
648
646
  let promptPath = null;
649
647
  for (let i = 0; i < args.length; i++) {
650
- if (args[i] === "--extension" && args[i + 1])
651
- extensionPath = args[i + 1];
652
- if (args[i] === "--prompt" && args[i + 1])
653
- promptPath = args[i + 1];
648
+ if (args[i] === "--extension" && args[i + 1])
649
+ extensionPath = args[i + 1];
650
+ if (args[i] === "--prompt" && args[i + 1])
651
+ promptPath = args[i + 1];
654
652
  }
655
653
  let systemPrompt = SYSTEM_PROMPT;
656
654
  if (promptPath && existsSync(promptPath)) {
657
- let rawPrompt = readFileSync(promptPath, "utf-8");
658
- // Validate prompt file size
659
- if (rawPrompt.length > 10_000) {
660
- console.error(T.error("Prompt file too large (max 10KB)."));
661
- process.exit(1);
662
- }
663
- // Strip control characters
664
- rawPrompt = rawPrompt.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
665
- // Basic prompt injection detection
666
- const dangerousPatterns = [
667
- /ignore (all |previous |above|prior) instructions/i,
668
- /you are now /i,
669
- /new instructions/i,
670
- /override (system|safety)/i,
671
- ];
672
- for (const pattern of dangerousPatterns) {
673
- if (pattern.test(rawPrompt)) {
674
- console.error(T.error("Prompt file contains suspicious patterns. Use a simpler prompt."));
675
- process.exit(1);
676
- }
677
- }
678
- systemPrompt = rawPrompt;
679
- console.log(T.muted(" Custom prompt loaded: " + promptPath));
680
- }
681
- // ── Headless mode ─────────────────────────────────────────────────────────
655
+ let rawPrompt = readFileSync(promptPath, "utf-8");
656
+
657
+ if (rawPrompt.length > 10_000) {
658
+ console.error(T.error("Prompt file too large (max 10KB)."));
659
+ process.exit(1);
660
+ }
661
+
662
+ rawPrompt = rawPrompt.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
663
+
664
+ const dangerousPatterns = [
665
+ /ignore (all |previous |above|prior) instructions/i,
666
+ /you are now /i,
667
+ /new instructions/i,
668
+ /override (system|safety)/i,
669
+ ];
670
+ for (const pattern of dangerousPatterns) {
671
+ if (pattern.test(rawPrompt)) {
672
+ console.error(T.error("Prompt file contains suspicious patterns. Use a simpler prompt."));
673
+ process.exit(1);
674
+ }
675
+ }
676
+ systemPrompt = rawPrompt;
677
+ console.log(T.muted(" Custom prompt loaded: " + promptPath));
678
+ }
679
+
682
680
  const headlessIdx = args.indexOf("--headless");
683
681
  const headlessMsg = headlessIdx >= 0 ? args[headlessIdx + 1] : null;
684
682
  if (headlessMsg) {
685
- (async () => {
686
- AgentDir.init();
687
- const registry = new Registry();
688
- registry.setSystemPrompt(systemPrompt);
689
- if (extensionPath) {
690
- try {
691
- await loadExtension(extensionPath, registry);
692
- }
693
- catch (e) {
694
- process.stderr.write(`Extension load failed: ${e instanceof Error ? e.message : String(e)}\n`);
695
- process.exit(1);
696
- }
697
- }
698
- await modelRegistry.initialise();
699
- const session = new SessionManager();
700
- session.setSystemPrompt(registry.getSystemPrompt() || systemPrompt);
701
- const theme = makeTheme();
702
- const nullUi = {
703
- notify: () => { }, setStatus: () => { }, setTheme: () => { },
704
- setHeader: () => { }, showModelSelector: () => { }, theme,
705
- };
706
- const sessionCtx = {
707
- ui: nullUi, hasUI: false,
708
- config: { OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY },
709
- };
710
- await registry.fireHook("session_start", sessionCtx);
711
- let exitCode = 0;
712
- const runner = new AgentRunner(registry, session, (event) => {
713
- if (event.type === "text_delta")
714
- process.stdout.write(event.text);
715
- if (event.type === "turn_done")
716
- process.stdout.write("\n");
717
- if (event.type === "error") {
718
- process.stderr.write(`\nError: ${event.message}\n`);
719
- exitCode = 1;
720
- }
721
- }, sessionCtx, "normal", modelRegistry);
722
- try {
723
- await runner.run(headlessMsg);
724
- }
725
- catch (e) {
726
- process.stderr.write(`Runner error: ${e instanceof Error ? e.message : String(e)}\n`);
727
- exitCode = 1;
728
- }
729
- await registry.fireHook("session_end", sessionCtx);
730
- process.exit(exitCode);
731
- })();
683
+ (async () => {
684
+ AgentDir.init();
685
+ const registry = new Registry();
686
+ registry.setSystemPrompt(systemPrompt);
687
+ if (extensionPath) {
688
+ try {
689
+ await loadExtension(extensionPath, registry);
690
+ }
691
+ catch (e) {
692
+ process.stderr.write(`Extension load failed: ${e instanceof Error ? e.message : String(e)}\n`);
693
+ process.exit(1);
694
+ }
695
+ }
696
+ await modelRegistry.initialise();
697
+ const session = new SessionManager();
698
+ session.setSystemPrompt(registry.getSystemPrompt() || systemPrompt);
699
+ const theme = makeTheme();
700
+ const nullUi = {
701
+ notify: () => { }, setStatus: () => { }, setTheme: () => { },
702
+ setHeader: () => { }, showModelSelector: () => { }, theme,
703
+ };
704
+ const sessionCtx = {
705
+ ui: nullUi, hasUI: false,
706
+ config: { OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY },
707
+ };
708
+ await registry.fireHook("session_start", sessionCtx);
709
+ let exitCode = 0;
710
+ const runner = new AgentRunner(registry, session, (event) => {
711
+ if (event.type === "text_delta")
712
+ process.stdout.write(event.text);
713
+ if (event.type === "turn_done")
714
+ process.stdout.write("\n");
715
+ if (event.type === "error") {
716
+ process.stderr.write(`\nError: ${event.message}\n`);
717
+ exitCode = 1;
718
+ }
719
+ }, sessionCtx, "normal", modelRegistry);
720
+ try {
721
+ await runner.run(headlessMsg);
722
+ }
723
+ catch (e) {
724
+ process.stderr.write(`Runner error: ${e instanceof Error ? e.message : String(e)}\n`);
725
+ exitCode = 1;
726
+ }
727
+ await registry.fireHook("session_end", sessionCtx);
728
+ process.exit(exitCode);
729
+ })();
732
730
  }
733
731
  else {
734
- // ── Boot (interactive TUI) ──────────────────────────────────────────────
735
- (async () => {
736
- AgentDir.init();
737
- console.clear();
738
- console.log(T.accent(`
739
- █████╗ ██╗ █████╗ ██╗ █████╗ ██╗
740
- ██╔══██╗██║██╔══██╗██║██╔══██╗██║
741
- ███████║██║███████║██║███████║██║
742
- ██╔══██║██║██╔══██║██║██╔══██║██║
743
- ██║ ██║██║██║ ██║██║██║ ██║██║
744
- ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝
745
- `));
746
- console.log(T.muted(" Solana-native AI agent — $AIAIAI · all local, zero exposure\n"));
747
- const registry = new Registry();
748
- registry.setSystemPrompt(systemPrompt);
749
- let _notifyFn = null;
750
- let _setStatusFn = null;
751
- let _showModelSelectorFn = null;
752
- if (extensionPath) {
753
- try {
754
- console.log(T.muted(` Loading: ${extensionPath}`));
755
- await loadExtension(extensionPath, registry, {
756
- onNotify: (msg) => { _notifyFn?.(msg); },
757
- onStatusUpdate: (k, v) => { _setStatusFn?.(k, v); },
758
- onShowModelSelector: (q) => { _showModelSelectorFn?.(q); },
759
- });
760
- console.log(T.success(` ✓ ${registry.listTools().length} tools · ${registry.listCommands().length} commands`));
761
- }
762
- catch (e) {
763
- console.error(T.error(` ✗ Extension load failed: ${e.message}`));
764
- process.exit(1);
765
- }
766
- }
767
- if (!process.env.OPENROUTER_API_KEY) {
768
- console.log(T.warn(" No API key found. Run: aiaiaichain setup\n"));
769
- }
770
- const costTracker = new CostTracker(modelRegistry);
771
- console.log(T.muted(" Discovering available models via OpenRouter…"));
772
- await modelRegistry.initialise();
773
- console.log(T.success(` ✓ ${modelRegistry.modelCount} models available\n`));
774
- await new Promise(r => setTimeout(r, 500));
775
- console.clear();
776
- render(React.createElement(App, {
777
- registry,
778
- systemPrompt,
779
- chain: "solana",
780
- modelReg: modelRegistry,
781
- costTracker,
782
- onNotifyReady: (fn) => { _notifyFn = fn; wireNotify(fn); },
783
- onStatusReady: (fn) => { _setStatusFn = fn; },
784
- onModelSelectorReady: (fn) => { _showModelSelectorFn = fn; },
785
- }), { exitOnCtrlC: false });
786
- process.prependListener("SIGWINCH", () => { process.stdout.write("\x1B[2J\x1B[H"); });
787
- console.log = safeLog;
788
- console.error = safeLog;
789
- console.warn = safeLog;
790
- })();
791
- }
792
- //# sourceMappingURL=cli.js.map
732
+
733
+ (async () => {
734
+ AgentDir.init();
735
+ console.clear();
736
+ console.log(T.accent(`
737
+ █████╗ ██╗ █████╗ ██╗ █████╗ ██╗
738
+ ██╔══██╗██║██╔══██╗██║██╔══██╗██║
739
+ ███████║██║███████║██║███████║██║
740
+ ██╔══██║██║██╔══██║██║██╔══██║██║
741
+ ██║ ██║██║██║ ██║██║██║ ██║██║
742
+ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝
743
+ `));
744
+ console.log(T.muted(" Solana-native AI agent — $AIAIAI · all local, zero exposure\n"));
745
+ const registry = new Registry();
746
+ registry.setSystemPrompt(systemPrompt);
747
+ let _notifyFn = null;
748
+ let _setStatusFn = null;
749
+ let _showModelSelectorFn = null;
750
+ if (extensionPath) {
751
+ try {
752
+ console.log(T.muted(` Loading: ${extensionPath}`));
753
+ await loadExtension(extensionPath, registry, {
754
+ onNotify: (msg) => { _notifyFn?.(msg); },
755
+ onStatusUpdate: (k, v) => { _setStatusFn?.(k, v); },
756
+ onShowModelSelector: (q) => { _showModelSelectorFn?.(q); },
757
+ });
758
+ console.log(T.success(` ✓ ${registry.listTools().length} tools · ${registry.listCommands().length} commands`));
759
+ }
760
+ catch (e) {
761
+ console.error(T.error(` ✗ Extension load failed: ${e.message}`));
762
+ process.exit(1);
763
+ }
764
+ }
765
+ if (!process.env.OPENROUTER_API_KEY) {
766
+ console.log(T.warn(" No API key found. Run: aiaiaichain setup\n"));
767
+ }
768
+ const costTracker = new CostTracker(modelRegistry);
769
+ console.log(T.muted(" Discovering available models via OpenRouter…"));
770
+ await modelRegistry.initialise();
771
+ console.log(T.success(` ✓ ${modelRegistry.modelCount} models available\n`));
772
+ await new Promise(r => setTimeout(r, 500));
773
+ console.clear();
774
+ render(React.createElement(App, {
775
+ registry,
776
+ systemPrompt,
777
+ chain: "solana",
778
+ modelReg: modelRegistry,
779
+ costTracker,
780
+ onNotifyReady: (fn) => { _notifyFn = fn; wireNotify(fn); },
781
+ onStatusReady: (fn) => { _setStatusFn = fn; },
782
+ onModelSelectorReady: (fn) => { _showModelSelectorFn = fn; },
783
+ }), { exitOnCtrlC: false });
784
+ process.prependListener("SIGWINCH", () => { process.stdout.write("\x1B[2J\x1B[H"); });
785
+ console.log = safeLog;
786
+ console.error = safeLog;
787
+ console.warn = safeLog;
788
+ })();
789
+ }