@aiaiaichain/agent 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/cli.js +274 -26
- package/dist/core/ChainConfig.js +1 -1
- package/dist/core/SystemMonitor.d.ts +32 -0
- package/dist/core/SystemMonitor.js +89 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +18 -1
- package/dist/models/ModelRegistry.js +12 -4
- package/dist/runner/AgentRunner.d.ts +2 -0
- package/dist/runner/AgentRunner.js +18 -1
- package/dist/runner/ModelClient.js +109 -48
- package/dist/session/SessionManager.d.ts +1 -0
- package/dist/session/SessionManager.js +8 -2
- package/dist/session/SessionStore.d.ts +45 -0
- package/dist/session/SessionStore.js +128 -0
- package/dist/tools/CrossTools.d.ts +52 -0
- package/dist/tools/CrossTools.js +190 -0
- package/dist/tools/MarketSentiment.js +22 -13
- package/dist/tools/NewsSentiment.js +9 -3
- package/dist/tools/PriceFeed.js +11 -4
- package/dist/tools/TechnicalAnalysis.js +2 -1
- package/dist/tools/TokenCalendar.d.ts +24 -0
- package/dist/tools/TokenCalendar.js +81 -0
- package/dist/tools/TokenSecurityScanner.d.ts +22 -0
- package/dist/tools/TokenSecurityScanner.js +102 -0
- package/dist/tools/TransactionSim.d.ts +17 -0
- package/dist/tools/TransactionSim.js +78 -0
- package/dist/tui/App.d.ts +4 -3
- package/dist/tui/App.js +371 -118
- package/dist/tui/REPL.d.ts +2 -1
- package/dist/tui/REPL.js +190 -16
- package/dist/tui/Sparkline.d.ts +21 -0
- package/dist/tui/Sparkline.js +44 -0
- package/dist/tui/StatusBar.d.ts +5 -1
- package/dist/tui/StatusBar.js +6 -4
- package/dist/tui/ThemePresets.d.ts +25 -0
- package/dist/tui/ThemePresets.js +117 -0
- package/dist/util/clipboard.d.ts +9 -0
- package/dist/util/clipboard.js +26 -0
- package/dist/util/commandSuggest.d.ts +7 -0
- package/dist/util/commandSuggest.js +44 -0
- package/dist/util/confirmation.d.ts +6 -0
- package/dist/util/confirmation.js +16 -0
- package/dist/util/errorHandler.d.ts +3 -0
- package/dist/util/errorHandler.js +28 -0
- package/dist/util/logger.d.ts +11 -0
- package/dist/util/logger.js +43 -0
- package/dist/util/processManager.d.ts +5 -0
- package/dist/util/processManager.js +39 -0
- package/dist/util/resilientFetch.d.ts +21 -0
- package/dist/util/resilientFetch.js +94 -0
- package/dist/util/responseCache.d.ts +27 -0
- package/dist/util/responseCache.js +54 -0
- package/dist/util/safeLog.d.ts +4 -5
- package/dist/util/safeLog.js +68 -30
- package/dist/util/scheduler.d.ts +14 -0
- package/dist/util/scheduler.js +75 -0
- package/dist/util/webhooks.d.ts +9 -0
- package/dist/util/webhooks.js +75 -0
- package/dist/wallet/ActionFeed.js +12 -4
- package/dist/wallet/AgentWallet.d.ts +2 -0
- package/dist/wallet/AgentWallet.js +31 -5
- package/dist/wallet/ProfitTracker.d.ts +30 -0
- package/dist/wallet/ProfitTracker.js +93 -0
- package/docs/COMMANDS.md +40 -9
- package/docs/README.md +2 -0
- package/package.json +5 -3
- package/scripts/postinstall.js +34 -0
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
[](https://nodejs.org)
|
|
18
18
|
[](LICENSE)
|
|
19
19
|
|
|
20
|
-
[X / Twitter](https://x.com/aiaiaisol)
|
|
20
|
+
[X / Twitter](https://x.com/aiaiaisol) · [aiaiaichain.xyz](https://aiaiaichain.xyz)
|
|
21
21
|
|
|
22
22
|
</div>
|
|
23
23
|
|
|
@@ -149,7 +149,7 @@ Get an OpenRouter key at https://openrouter.ai/keys
|
|
|
149
149
|
|
|
150
150
|
## Links
|
|
151
151
|
|
|
152
|
-
- [X / Twitter](https://x.com/aiaiaisol)
|
|
152
|
+
- [X / Twitter](https://x.com/aiaiaisol) · [aiaiaichain.xyz](https://aiaiaichain.xyz)
|
|
153
153
|
- [npm](https://www.npmjs.com/package/@aiaiaichain/agent)
|
|
154
154
|
|
|
155
155
|
## License
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import { readFileSync, existsSync } from "node:fs";
|
|
|
6
6
|
import { resolve, join, dirname } from "node:path";
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { execSync } from "node:child_process";
|
|
9
10
|
import { render } from "ink";
|
|
10
11
|
import React from "react";
|
|
11
12
|
import { config as loadDotenv } from "dotenv";
|
|
@@ -14,6 +15,7 @@ import { loadExtension } from "./loader.js";
|
|
|
14
15
|
import { App } from "./tui/App.js";
|
|
15
16
|
import { T } from "./tui/theme.js";
|
|
16
17
|
import { wireNotify, safeLog } from "./util/safeLog.js";
|
|
18
|
+
import { logger } from "./util/logger.js";
|
|
17
19
|
import { modelRegistry } from "./models/ModelRegistry.js";
|
|
18
20
|
import { CostTracker } from "./models/CostTracker.js";
|
|
19
21
|
import { AgentRunner } from "./runner/AgentRunner.js";
|
|
@@ -25,6 +27,8 @@ import { agentWallet, DEPOSIT_WALLET, ACTION_WALLET, SIGNER } from "./wallet/Age
|
|
|
25
27
|
import { PROVIDERS, getConfigured, getUnconfigured } from "./providers/ProviderRegistry.js";
|
|
26
28
|
import { env } from "./core/EnvLoader.js";
|
|
27
29
|
import { gmgnHelp, gmgnStatus, saveGmgnApiKey } from "./tools/GmgnIntegration.js";
|
|
30
|
+
import { scanTokenSecurityTool } from "./tools/TokenSecurityScanner.js";
|
|
31
|
+
import { sessionStore } from "./session/SessionStore.js";
|
|
28
32
|
const AIAIAI_HOME = process.env.AIAIAI_HOME ?? join(homedir(), ".aiaiai");
|
|
29
33
|
const envPath = join(AIAIAI_HOME, ".env");
|
|
30
34
|
if (existsSync(envPath))
|
|
@@ -77,6 +81,10 @@ if (subcmd === "--help" || subcmd === "-h" || subcmd === "help") {
|
|
|
77
81
|
console.log(" aiaiaichain deposit Show deposit instructions");
|
|
78
82
|
console.log(" aiaiaichain burn Show burn instructions");
|
|
79
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");
|
|
80
88
|
console.log(" aiaiaichain --help This help");
|
|
81
89
|
console.log(" aiaiaichain --version Show version");
|
|
82
90
|
console.log("");
|
|
@@ -104,7 +112,22 @@ if (subcmd === "setup") {
|
|
|
104
112
|
console.log(T.muted(` Home: ${AIAIAI_HOME}`));
|
|
105
113
|
console.log(T.accent("\n Run `aiaiaichain` to start the agent.\n"));
|
|
106
114
|
process.exit(0);
|
|
107
|
-
})().catch(e => {
|
|
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
|
+
});
|
|
108
131
|
await new Promise(() => { });
|
|
109
132
|
}
|
|
110
133
|
if (subcmd === "config") {
|
|
@@ -203,6 +226,39 @@ if (subcmd === "fees") {
|
|
|
203
226
|
})();
|
|
204
227
|
await new Promise(() => { });
|
|
205
228
|
}
|
|
229
|
+
if (subcmd === "pnl" || subcmd === "pl" || subcmd === "profit") {
|
|
230
|
+
(async () => {
|
|
231
|
+
const { getPLSummary, getTradeHistory, exportCSV } = await import("./wallet/ProfitTracker.js");
|
|
232
|
+
const { priceFeed } = await import("./tools/PriceFeed.js");
|
|
233
|
+
const price = await priceFeed.getAiaiaiPrice();
|
|
234
|
+
const summary = getPLSummary(parseFloat(price.priceUsd ?? "0"));
|
|
235
|
+
const history = getTradeHistory();
|
|
236
|
+
console.log(T.accent("\n Profit & Loss — $AIAIAI\n"));
|
|
237
|
+
console.log(` Avg Cost: $${summary.avgCostBasis.toFixed(8)}`);
|
|
238
|
+
console.log(` Total Spent: ${summary.totalSpent.toFixed(4)} SOL`);
|
|
239
|
+
console.log(` Total Received: ${summary.totalReceived.toFixed(4)} SOL`);
|
|
240
|
+
console.log(` Realized P&L: ${summary.realizedPL >= 0 ? "+" : ""}${summary.realizedPL.toFixed(4)} SOL`);
|
|
241
|
+
console.log(` Unrealized P&L: ${summary.unrealizedPL >= 0 ? "+" : ""}${summary.unrealizedPL.toFixed(4)} SOL`);
|
|
242
|
+
console.log(` ROI: ${summary.roi >= 0 ? "+" : ""}${summary.roi.toFixed(2)}%`);
|
|
243
|
+
console.log(` Trades: ${history.length}`);
|
|
244
|
+
if (history.length > 0) {
|
|
245
|
+
console.log(T.muted("\n Recent trades:"));
|
|
246
|
+
history.slice(-5).forEach(t => {
|
|
247
|
+
const date = new Date(t.timestamp).toLocaleDateString();
|
|
248
|
+
console.log(` ${date} ${t.type} ${t.tokenAmount.toFixed(0)} tokens @ ${t.pricePerToken.toFixed(8)} SOL`);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
const csvPath = exportCSV();
|
|
253
|
+
console.log(T.success(`\n CSV exported: ${csvPath}`));
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
logger.warn('CLI', 'CSV export failed', { error: error.message });
|
|
257
|
+
}
|
|
258
|
+
process.exit(0);
|
|
259
|
+
})();
|
|
260
|
+
await new Promise(() => { });
|
|
261
|
+
}
|
|
206
262
|
if (subcmd === "keys" || subcmd === "providers") {
|
|
207
263
|
(async () => {
|
|
208
264
|
const readline = await import("node:readline");
|
|
@@ -310,37 +366,55 @@ if (subcmd === "gmgn" || subcmd === "gmgnhelp") {
|
|
|
310
366
|
process.exit(0);
|
|
311
367
|
}
|
|
312
368
|
// Forward to gmgn-cli
|
|
313
|
-
|
|
314
|
-
const { execSync } = await import("node:child_process");
|
|
369
|
+
try {
|
|
315
370
|
const fullArgs = ["gmgn-cli", ...gmgnArgs];
|
|
371
|
+
const gmgnEnv = {};
|
|
316
372
|
try {
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
e[m[1]] = m[2];
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
catch { } return e; })() },
|
|
327
|
-
encoding: "utf-8",
|
|
328
|
-
timeout: 30_000,
|
|
329
|
-
});
|
|
330
|
-
process.stdout.write(output);
|
|
373
|
+
const f = readFileSync(join(homedir(), ".config", "gmgn", ".env"), "utf-8");
|
|
374
|
+
for (const l of f.split("\n")) {
|
|
375
|
+
const m = l.trim().match(/^([A-Z_]+)=(.*)$/);
|
|
376
|
+
if (m)
|
|
377
|
+
gmgnEnv[m[1]] = m[2];
|
|
378
|
+
}
|
|
331
379
|
}
|
|
332
|
-
catch
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
380
|
+
catch {
|
|
381
|
+
logger.debug('CLI', 'No GMGN env file found (optional)');
|
|
382
|
+
}
|
|
383
|
+
const output = execSync(fullArgs.join(" "), {
|
|
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);
|
|
396
|
+
}
|
|
397
|
+
if (subcmd === "scan" || subcmd === "security") {
|
|
398
|
+
(async () => {
|
|
399
|
+
const tokenAddress = args[1];
|
|
400
|
+
if (!tokenAddress) {
|
|
401
|
+
console.log(T.error(" Usage: aiaiai scan <token-address>"));
|
|
402
|
+
process.exit(1);
|
|
336
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("");
|
|
337
412
|
process.exit(0);
|
|
338
|
-
})();
|
|
413
|
+
})().catch(e => { console.error(T.error("Scan error: " + e.message)); process.exit(1); });
|
|
339
414
|
await new Promise(() => { });
|
|
340
415
|
}
|
|
341
416
|
if (subcmd === "update" || subcmd === "upgrade") {
|
|
342
417
|
(async () => {
|
|
343
|
-
const { execSync } = await import("node:child_process");
|
|
344
418
|
const pkgName = "@aiaiaichain/agent";
|
|
345
419
|
console.log(T.accent("\n 🤖 AIAIAI Update Check\n"));
|
|
346
420
|
// Get current version
|
|
@@ -369,9 +443,12 @@ if (subcmd === "update" || subcmd === "upgrade") {
|
|
|
369
443
|
changelog = `Git: ${pkgData.gitHead.slice(0, 8)}`;
|
|
370
444
|
}
|
|
371
445
|
}
|
|
372
|
-
catch {
|
|
446
|
+
catch {
|
|
447
|
+
logger.debug('CLI', 'No changelog available (optional)');
|
|
448
|
+
}
|
|
373
449
|
}
|
|
374
|
-
catch {
|
|
450
|
+
catch (error) {
|
|
451
|
+
logger.warn('CLI', 'Could not reach npm registry', { error: error.message });
|
|
375
452
|
console.log(T.error(" Could not reach npm registry. Check your connection."));
|
|
376
453
|
process.exit(1);
|
|
377
454
|
}
|
|
@@ -415,6 +492,155 @@ if (subcmd === "update" || subcmd === "upgrade") {
|
|
|
415
492
|
})().catch(e => { console.error(T.error(`Error: ${e.message}`)); process.exit(1); });
|
|
416
493
|
await new Promise(() => { });
|
|
417
494
|
}
|
|
495
|
+
if (subcmd === "health" || subcmd === "doctor") {
|
|
496
|
+
(async () => {
|
|
497
|
+
console.log(T.accent("\n \u2705 AIAIAI Health Check\n"));
|
|
498
|
+
let healthy = true;
|
|
499
|
+
// Check env file
|
|
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
|
+
// Check API key
|
|
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
|
+
// Check RPC
|
|
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
|
+
// Check disk writable
|
|
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
|
+
// ── Extras (doctor mode) ──────────────────────────────────────────
|
|
557
|
+
console.log(T.muted("\n Extras:"));
|
|
558
|
+
// Theme
|
|
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
|
+
// Clipboard
|
|
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
|
+
// Webhooks
|
|
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
|
+
// Provider key check
|
|
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(() => { });
|
|
607
|
+
}
|
|
608
|
+
if (subcmd === "sessions") {
|
|
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);
|
|
621
|
+
}
|
|
622
|
+
if (subcmd === "resume") {
|
|
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
|
+
}
|
|
418
644
|
// ── Resolve extension + prompt ────────────────────────────────────────────────
|
|
419
645
|
let extensionPath = null;
|
|
420
646
|
let promptPath = null;
|
|
@@ -426,7 +652,29 @@ for (let i = 0; i < args.length; i++) {
|
|
|
426
652
|
}
|
|
427
653
|
let systemPrompt = SYSTEM_PROMPT;
|
|
428
654
|
if (promptPath && existsSync(promptPath)) {
|
|
429
|
-
|
|
655
|
+
let rawPrompt = readFileSync(promptPath, "utf-8");
|
|
656
|
+
// Validate prompt file size
|
|
657
|
+
if (rawPrompt.length > 10_000) {
|
|
658
|
+
console.error(T.error("Prompt file too large (max 10KB)."));
|
|
659
|
+
process.exit(1);
|
|
660
|
+
}
|
|
661
|
+
// Strip control characters
|
|
662
|
+
rawPrompt = rawPrompt.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
|
|
663
|
+
// Basic prompt injection detection
|
|
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));
|
|
430
678
|
}
|
|
431
679
|
// ── Headless mode ─────────────────────────────────────────────────────────
|
|
432
680
|
const headlessIdx = args.indexOf("--headless");
|
package/dist/core/ChainConfig.js
CHANGED
|
@@ -7,7 +7,7 @@ export const CHAINS = {
|
|
|
7
7
|
name: 'solana',
|
|
8
8
|
symbol: 'SOL',
|
|
9
9
|
chainId: 101,
|
|
10
|
-
rpcUrl: 'https://api.mainnet-beta.solana.com',
|
|
10
|
+
rpcUrl: process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com',
|
|
11
11
|
explorerUrl: 'https://solscan.io',
|
|
12
12
|
enabled: true,
|
|
13
13
|
primary: true,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SystemMonitor — tracks CPU, RAM, network, and agent stats.
|
|
3
|
+
* Uses Node.js built-in modules only (no external deps).
|
|
4
|
+
*/
|
|
5
|
+
export interface SystemStats {
|
|
6
|
+
cpuPercent: number;
|
|
7
|
+
ramPercent: number;
|
|
8
|
+
ramUsed: string;
|
|
9
|
+
ramTotal: string;
|
|
10
|
+
uptime: string;
|
|
11
|
+
netUp: string;
|
|
12
|
+
netDown: string;
|
|
13
|
+
apiCallsPerMin: number;
|
|
14
|
+
tokensUsed: number;
|
|
15
|
+
}
|
|
16
|
+
export declare class SystemMonitor {
|
|
17
|
+
private apiCallCount;
|
|
18
|
+
private prevCpuTimes;
|
|
19
|
+
/** Track an API call */
|
|
20
|
+
trackApiCall(): void;
|
|
21
|
+
/** Get current system stats */
|
|
22
|
+
getStats(tokenCount?: number): SystemStats;
|
|
23
|
+
private getCpuPercent;
|
|
24
|
+
private getRamPercent;
|
|
25
|
+
private getNetStats;
|
|
26
|
+
private formatBytes;
|
|
27
|
+
private formatUptime;
|
|
28
|
+
/** Reset API call counter (call every minute) */
|
|
29
|
+
resetApiCounter(): number;
|
|
30
|
+
}
|
|
31
|
+
export declare const systemMonitor: SystemMonitor;
|
|
32
|
+
//# sourceMappingURL=SystemMonitor.d.ts.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SystemMonitor — tracks CPU, RAM, network, and agent stats.
|
|
3
|
+
* Uses Node.js built-in modules only (no external deps).
|
|
4
|
+
*/
|
|
5
|
+
import { cpus, totalmem, freemem, uptime } from 'node:os';
|
|
6
|
+
import { logger } from '../util/logger.js';
|
|
7
|
+
export class SystemMonitor {
|
|
8
|
+
apiCallCount = 0;
|
|
9
|
+
prevCpuTimes = { idle: 0, total: 0 };
|
|
10
|
+
/** Track an API call */
|
|
11
|
+
trackApiCall() {
|
|
12
|
+
this.apiCallCount++;
|
|
13
|
+
}
|
|
14
|
+
/** Get current system stats */
|
|
15
|
+
getStats(tokenCount = 0) {
|
|
16
|
+
return {
|
|
17
|
+
cpuPercent: this.getCpuPercent(),
|
|
18
|
+
ramPercent: this.getRamPercent(),
|
|
19
|
+
ramUsed: this.formatBytes(totalmem() - freemem()),
|
|
20
|
+
ramTotal: this.formatBytes(totalmem()),
|
|
21
|
+
uptime: this.formatUptime(uptime()),
|
|
22
|
+
...this.getNetStats(),
|
|
23
|
+
apiCallsPerMin: this.apiCallCount,
|
|
24
|
+
tokensUsed: tokenCount,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
getCpuPercent() {
|
|
28
|
+
try {
|
|
29
|
+
const cpuInfo = cpus();
|
|
30
|
+
let totalIdle = 0, totalTick = 0;
|
|
31
|
+
for (const cpu of cpuInfo) {
|
|
32
|
+
for (const type in cpu.times) {
|
|
33
|
+
totalTick += cpu.times[type];
|
|
34
|
+
}
|
|
35
|
+
totalIdle += cpu.times.idle;
|
|
36
|
+
}
|
|
37
|
+
const idle = totalIdle / cpuInfo.length;
|
|
38
|
+
const total = totalTick / cpuInfo.length;
|
|
39
|
+
// Delta-based: compare against previous sample
|
|
40
|
+
const nowIdle = idle, nowTotal = total;
|
|
41
|
+
if (this.prevCpuTimes.total > 0) {
|
|
42
|
+
const idleDelta = nowIdle - this.prevCpuTimes.idle;
|
|
43
|
+
const totalDelta = nowTotal - this.prevCpuTimes.total;
|
|
44
|
+
this.prevCpuTimes = { idle: nowIdle, total: nowTotal };
|
|
45
|
+
if (totalDelta <= 0)
|
|
46
|
+
return 0;
|
|
47
|
+
return Math.round((1 - idleDelta / totalDelta) * 100);
|
|
48
|
+
}
|
|
49
|
+
this.prevCpuTimes = { idle: nowIdle, total: nowTotal };
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
logger.debug('SystemMonitor', 'CPU measurement failed', { error: error.message });
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
getRamPercent() {
|
|
58
|
+
const used = totalmem() - freemem();
|
|
59
|
+
return Math.round((used / totalmem()) * 100);
|
|
60
|
+
}
|
|
61
|
+
getNetStats() {
|
|
62
|
+
// Node.js doesn't expose per-interface byte counters without native addons.
|
|
63
|
+
// Return N/A rather than pretending zeros are real data.
|
|
64
|
+
return { netUp: 'N/A', netDown: 'N/A' };
|
|
65
|
+
}
|
|
66
|
+
formatBytes(bytes) {
|
|
67
|
+
if (bytes === 0)
|
|
68
|
+
return '0 B';
|
|
69
|
+
const k = 1024;
|
|
70
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
71
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
72
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
|
73
|
+
}
|
|
74
|
+
formatUptime(seconds) {
|
|
75
|
+
const h = Math.floor(seconds / 3600);
|
|
76
|
+
const m = Math.floor((seconds % 3600) / 60);
|
|
77
|
+
if (h > 0)
|
|
78
|
+
return `${h}h ${m}m`;
|
|
79
|
+
return `${m}m`;
|
|
80
|
+
}
|
|
81
|
+
/** Reset API call counter (call every minute) */
|
|
82
|
+
resetApiCounter() {
|
|
83
|
+
const count = this.apiCallCount;
|
|
84
|
+
this.apiCallCount = 0;
|
|
85
|
+
return count;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export const systemMonitor = new SystemMonitor();
|
|
89
|
+
//# sourceMappingURL=SystemMonitor.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export { PriceFeed, priceFeed } from "./tools/PriceFeed.js";
|
|
|
23
23
|
export { NewsFeed, newsFeed, getNewsTool, scoreSentiment } from "./tools/NewsSentiment.js";
|
|
24
24
|
export { getFearGreedTool, getFundingRatesTool, getBtcMempoolTool, getDefiTvlTool, getSolanaStatsTool, } from "./tools/MarketSentiment.js";
|
|
25
25
|
export type { OHLCV, AnalysisResult } from "./tools/TechnicalAnalysis.js";
|
|
26
|
-
export type { PriceResult, DexScreenerPair } from "./tools/PriceFeed.js";
|
|
26
|
+
export type { PriceResult, DexScreenerPair as DexScreenerData } from "./tools/PriceFeed.js";
|
|
27
27
|
export type { NewsItem, SentimentReport } from "./tools/NewsSentiment.js";
|
|
28
28
|
export { SessionManager } from "./session/SessionManager.js";
|
|
29
29
|
export { MemoryStore, memoryStore } from "./session/MemoryStore.js";
|
|
@@ -37,10 +37,25 @@ export { agentWallet, COLD_WALLET, ACTION_WALLET, DEPOSIT_WALLET, SIGNER, AIAIAI
|
|
|
37
37
|
export { actionFeed } from "./wallet/ActionFeed.js";
|
|
38
38
|
export type { WalletBalance, AgentWallets } from "./wallet/AgentWallet.js";
|
|
39
39
|
export type { AgentAction, ActionType, FeeTracker } from "./wallet/ActionFeed.js";
|
|
40
|
-
export { gmgnTool, gmgnHelp, gmgnStatus, hasGmgnApiKey, saveGmgnApiKey, GMGN_SUBCOMMANDS } from "./tools/GmgnIntegration.js";
|
|
40
|
+
export { gmgnTool, gmgnMarketTool, gmgnHelp, gmgnStatus, hasGmgnApiKey, saveGmgnApiKey, GMGN_SUBCOMMANDS } from "./tools/GmgnIntegration.js";
|
|
41
|
+
export { watchTokenTool, removeWatchTool, listWatchTool, addAlertTool, checkAlertsTool, compareTokensTool, portfolioTool, portfolioParams, getWatchList, checkAlerts, addAlert, getActiveAlerts, } from "./tools/CrossTools.js";
|
|
42
|
+
export { sessionStore } from "./session/SessionStore.js";
|
|
43
|
+
export type { Session, SessionMeta } from "./session/SessionStore.js";
|
|
44
|
+
export { systemMonitor } from "./core/SystemMonitor.js";
|
|
45
|
+
export type { SystemStats } from "./core/SystemMonitor.js";
|
|
41
46
|
export { MCPServer } from "./mcp/server.js";
|
|
42
47
|
export { AgentDir } from "./core/AgentDir.js";
|
|
43
48
|
export { EnvLoader, env } from "./core/EnvLoader.js";
|
|
44
49
|
export { CHAINS, getPrimaryChain, getEnabledChains, getChain, getSupportedChains } from "./core/ChainConfig.js";
|
|
45
50
|
export type { ChainInfo } from "./core/ChainConfig.js";
|
|
51
|
+
export { resilientFetch, isReachable } from "./util/resilientFetch.js";
|
|
52
|
+
export { logger } from "./util/logger.js";
|
|
53
|
+
export { getCached, setCache, getOrCompute, clearCache, cacheStats } from "./util/responseCache.js";
|
|
54
|
+
export { addTask, removeTask, pauseTask, resumeTask, pauseAll, resumeAll, startScheduler } from "./util/scheduler.js";
|
|
55
|
+
export { requireConfirmation, isNonInteractive } from "./util/confirmation.js";
|
|
56
|
+
export { ProcessManager } from "./util/processManager.js";
|
|
57
|
+
export { recordTrade, getPLSummary, getTradeHistory, exportCSV } from "./wallet/ProfitTracker.js";
|
|
58
|
+
export type { Trade, ProfitState, PLSummary } from "./wallet/ProfitTracker.js";
|
|
59
|
+
export { scanTokenSecurityTool } from "./tools/TokenSecurityScanner.js";
|
|
60
|
+
export type { TokenSecurityResult } from "./tools/TokenSecurityScanner.js";
|
|
46
61
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -37,11 +37,28 @@ export { AgentScheduler, agentScheduler } from "./scheduler/AgentScheduler.js";
|
|
|
37
37
|
export { agentWallet, COLD_WALLET, ACTION_WALLET, DEPOSIT_WALLET, SIGNER, AIAIAI_MINT } from "./wallet/AgentWallet.js";
|
|
38
38
|
export { actionFeed } from "./wallet/ActionFeed.js";
|
|
39
39
|
// GMGN
|
|
40
|
-
export { gmgnTool, gmgnHelp, gmgnStatus, hasGmgnApiKey, saveGmgnApiKey, GMGN_SUBCOMMANDS } from "./tools/GmgnIntegration.js";
|
|
40
|
+
export { gmgnTool, gmgnMarketTool, gmgnHelp, gmgnStatus, hasGmgnApiKey, saveGmgnApiKey, GMGN_SUBCOMMANDS } from "./tools/GmgnIntegration.js";
|
|
41
|
+
// Cross tools
|
|
42
|
+
export { watchTokenTool, removeWatchTool, listWatchTool, addAlertTool, checkAlertsTool, compareTokensTool, portfolioTool, portfolioParams, getWatchList, checkAlerts, addAlert, getActiveAlerts, } from "./tools/CrossTools.js";
|
|
43
|
+
// Session
|
|
44
|
+
export { sessionStore } from "./session/SessionStore.js";
|
|
45
|
+
// System
|
|
46
|
+
export { systemMonitor } from "./core/SystemMonitor.js";
|
|
41
47
|
// MCP
|
|
42
48
|
export { MCPServer } from "./mcp/server.js";
|
|
43
49
|
// Core
|
|
44
50
|
export { AgentDir } from "./core/AgentDir.js";
|
|
45
51
|
export { EnvLoader, env } from "./core/EnvLoader.js";
|
|
46
52
|
export { CHAINS, getPrimaryChain, getEnabledChains, getChain, getSupportedChains } from "./core/ChainConfig.js";
|
|
53
|
+
// Utilities
|
|
54
|
+
export { resilientFetch, isReachable } from "./util/resilientFetch.js";
|
|
55
|
+
export { logger } from "./util/logger.js";
|
|
56
|
+
export { getCached, setCache, getOrCompute, clearCache, cacheStats } from "./util/responseCache.js";
|
|
57
|
+
export { addTask, removeTask, pauseTask, resumeTask, pauseAll, resumeAll, startScheduler } from "./util/scheduler.js";
|
|
58
|
+
export { requireConfirmation, isNonInteractive } from "./util/confirmation.js";
|
|
59
|
+
export { ProcessManager } from "./util/processManager.js";
|
|
60
|
+
// Profit Tracker
|
|
61
|
+
export { recordTrade, getPLSummary, getTradeHistory, exportCSV } from "./wallet/ProfitTracker.js";
|
|
62
|
+
// Token Security
|
|
63
|
+
export { scanTokenSecurityTool } from "./tools/TokenSecurityScanner.js";
|
|
47
64
|
//# sourceMappingURL=index.js.map
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { env } from "../core/EnvLoader.js";
|
|
6
6
|
import { Type } from "@sinclair/typebox";
|
|
7
|
+
import { logger } from "../util/logger.js";
|
|
8
|
+
import { resilientFetch } from "../util/resilientFetch.js";
|
|
7
9
|
const PROVIDERS_WITH_MODELS = [
|
|
8
10
|
{ id: "openrouter", envVar: "OPENROUTER_API_KEY", baseUrl: "https://openrouter.ai/api/v1/models", mapper: (m) => ({ id: m.id, name: m.name, context: m.context_length ?? 131072, max: m.top_provider?.max_completion_tokens ?? 4096 }) },
|
|
9
11
|
{ id: "anthropic", envVar: "ANTHROPIC_API_KEY", baseUrl: "https://api.anthropic.com/v1/models", mapper: (m) => ({ id: m.id, name: m.name, context: m.context_length ?? 200000, max: m.top_provider?.max_completion_tokens ?? 8192 }) },
|
|
@@ -56,9 +58,11 @@ export class ModelRegistry {
|
|
|
56
58
|
if (provider.id === "google") {
|
|
57
59
|
url = `${provider.baseUrl}?key=${apiKey}`;
|
|
58
60
|
}
|
|
59
|
-
const res = await
|
|
60
|
-
if (!res.ok)
|
|
61
|
+
const res = await resilientFetch(url, { timeout: 15_000, retries: 1, headers });
|
|
62
|
+
if (!res.ok) {
|
|
63
|
+
logger.warn('ModelRegistry', `Provider ${provider.id} returned ${res.status}`);
|
|
61
64
|
continue;
|
|
65
|
+
}
|
|
62
66
|
const data = await res.json();
|
|
63
67
|
const items = data.data ?? data.models ?? data;
|
|
64
68
|
if (!Array.isArray(items))
|
|
@@ -80,10 +84,14 @@ export class ModelRegistry {
|
|
|
80
84
|
this.providerModels.set(provider.id, []);
|
|
81
85
|
this.providerModels.get(provider.id).push(model);
|
|
82
86
|
}
|
|
83
|
-
catch {
|
|
87
|
+
catch (error) {
|
|
88
|
+
logger.debug('ModelRegistry', 'Skipped bad model entry', { error: error.message });
|
|
89
|
+
}
|
|
84
90
|
}
|
|
85
91
|
}
|
|
86
|
-
catch {
|
|
92
|
+
catch (error) {
|
|
93
|
+
logger.warn('ModelRegistry', 'Skipped provider', { error: error.message });
|
|
94
|
+
}
|
|
87
95
|
}
|
|
88
96
|
this.buildTiers();
|
|
89
97
|
this.initialized = true;
|
|
@@ -44,6 +44,8 @@ export declare class AgentRunner {
|
|
|
44
44
|
private contextStore?;
|
|
45
45
|
private abortController;
|
|
46
46
|
private _pendingApproval?;
|
|
47
|
+
private _toolRetries;
|
|
48
|
+
private _maxToolRetries;
|
|
47
49
|
constructor(registry: Registry, session: SessionManager, onEvent: (event: RunnerEvent) => void, sessionCtx: SessionContext, effectLevel: string, modelReg: ModelRegistry, costTracker?: CostTracker, goalManager?: GoalManager, contextStore?: ContextStore);
|
|
48
50
|
setEffectLevel(level: string): void;
|
|
49
51
|
run(input: string): Promise<void>;
|