@aiaiaichain/agent 0.1.6 → 0.1.8

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 +364 -768
  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 +70 -85
  15. package/dist/index.d.ts +4 -61
  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 +17 -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 +1 -7
  72. package/dist/tui/App.js +896 -825
  73. package/dist/tui/ModelSelector.d.ts +1 -3
  74. package/dist/tui/ModelSelector.js +47 -50
  75. package/dist/tui/REPL.d.ts +1 -3
  76. package/dist/tui/REPL.js +222 -210
  77. package/dist/tui/Sparkline.d.ts +1 -3
  78. package/dist/tui/Sparkline.js +38 -37
  79. package/dist/tui/StatusBar.d.ts +1 -3
  80. package/dist/tui/StatusBar.js +11 -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 +14 -8
  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 +41 -0
@@ -1,147 +1,143 @@
1
- /**
2
- * NewsSentiment — crypto news headlines with simple sentiment scoring.
3
- * Uses public RSS feeds and a basic lexicon-based sentiment analyzer.
4
- */
1
+
5
2
  import { Type } from "@sinclair/typebox";
6
3
  import { resilientFetch } from "../util/resilientFetch.js";
7
4
  import { logger } from "../util/logger.js";
8
5
  const POSITIVE_WORDS = new Set([
9
- "bullish", "surge", "rally", "gain", "green", "high", "breakthrough", "adoption",
10
- "partnership", "launch", "upgrade", "growth", "profit", "positive", "optimistic",
11
- "innovation", "milestone", "record", "all-time", "success", "soar", "boom",
12
- "breakout", "accumulate", "moon", "pump", "ATH", "approve", "ETF",
6
+ "bullish", "surge", "rally", "gain", "green", "high", "breakthrough", "adoption",
7
+ "partnership", "launch", "upgrade", "growth", "profit", "positive", "optimistic",
8
+ "innovation", "milestone", "record", "all-time", "success", "soar", "boom",
9
+ "breakout", "accumulate", "moon", "pump", "ATH", "approve", "ETF",
13
10
  ]);
14
11
  const NEGATIVE_WORDS = new Set([
15
- "bearish", "crash", "dump", "plunge", "drop", "red", "low", "hack", "exploit",
16
- "ban", "regulation", "crackdown", "fraud", "scam", "loss", "negative", "pessimistic",
17
- "decline", "fall", "dip", "correction", "sell-off", "liquidation", "fud", "fear",
18
- "uncertainty", "volatility", "warning", "risk", "bear", "capitulation",
12
+ "bearish", "crash", "dump", "plunge", "drop", "red", "low", "hack", "exploit",
13
+ "ban", "regulation", "crackdown", "fraud", "scam", "loss", "negative", "pessimistic",
14
+ "decline", "fall", "dip", "correction", "sell-off", "liquidation", "fud", "fear",
15
+ "uncertainty", "volatility", "warning", "risk", "bear", "capitulation",
19
16
  ]);
20
17
  function scoreSentiment(text) {
21
- const words = text.toLowerCase().split(/[\s,.-_!?]+/);
22
- let score = 0;
23
- let matched = 0;
24
- for (const word of words) {
25
- if (POSITIVE_WORDS.has(word)) {
26
- score += 1;
27
- matched++;
28
- }
29
- if (NEGATIVE_WORDS.has(word)) {
30
- score -= 1;
31
- matched++;
32
- }
33
- }
34
- if (matched === 0)
35
- return 0;
36
- return Math.max(-1, Math.min(1, score / Math.max(matched, 1)));
18
+ const words = text.toLowerCase().split(/[\s,.-_!?]+/);
19
+ let score = 0;
20
+ let matched = 0;
21
+ for (const word of words) {
22
+ if (POSITIVE_WORDS.has(word)) {
23
+ score += 1;
24
+ matched++;
25
+ }
26
+ if (NEGATIVE_WORDS.has(word)) {
27
+ score -= 1;
28
+ matched++;
29
+ }
30
+ }
31
+ if (matched === 0)
32
+ return 0;
33
+ return Math.max(-1, Math.min(1, score / Math.max(matched, 1)));
37
34
  }
38
35
  export class NewsFeed {
39
- cachedItems = [];
40
- lastFetch = 0;
41
- cacheDuration = 300_000; // 5 min
42
- async getLatest() {
43
- if (this.cachedItems.length > 0 && Date.now() - this.lastFetch < this.cacheDuration) {
44
- return this.buildReport(this.cachedItems);
45
- }
46
- return this.fetch();
47
- }
48
- async fetch() {
49
- const items = [];
50
- try {
51
- // Use Cryptopanic API (free tier) if available, otherwise fallback
52
- const apiKey = process.env.CRYPTOPANIC_API_KEY;
53
- const url = apiKey
54
- ? `https://cryptopanic.com/api/v1/posts/?auth_token=${apiKey}&kind=news&public=true`
55
- : "https://cryptopanic.com/api/v1/posts/?public=true";
56
- const response = await resilientFetch(url, {
57
- timeout: 10_000,
58
- retries: 1,
59
- headers: { "Accept": "application/json" },
60
- });
61
- if (response.ok) {
62
- const data = await response.json();
63
- for (const post of (data.results ?? []).slice(0, 30)) {
64
- items.push({
65
- title: post.title,
66
- source: post.source?.title || post.domain || "cryptopanic",
67
- url: post.url,
68
- publishedAt: post.published_at,
69
- sentiment: scoreSentiment(post.title),
70
- });
71
- }
72
- }
73
- else {
74
- // Fallback: use Lunarcrush or a simple placeholder
75
- items.push(...this.getFallbackNews());
76
- }
77
- }
78
- catch (error) {
79
- logger.warn('NewsSentiment', 'Failed to fetch news', { error: error.message });
80
- items.push(...this.getFallbackNews());
81
- }
82
- this.cachedItems = items;
83
- this.lastFetch = Date.now();
84
- return this.buildReport(items);
85
- }
86
- getFallbackNews() {
87
- const now = new Date().toISOString();
88
- return [
89
- { title: "Bitcoin holds support above $60k as institutional inflows continue", source: "coindesk", url: "https://coindesk.com", publishedAt: now, sentiment: 0.6 },
90
- { title: "Solana network activity surges with record daily transactions", source: "theblock", url: "https://theblock.co", publishedAt: now, sentiment: 0.7 },
91
- { title: "DeFi TVL climbs to multi-month high across major protocols", source: "defillama", url: "https://defillama.com", publishedAt: now, sentiment: 0.5 },
92
- { title: "Regulatory clarity expected as new crypto framework emerges", source: "reuters", url: "https://reuters.com", publishedAt: now, sentiment: 0.3 },
93
- { title: "AI tokens lead market recovery with 15% weekly gains", source: "cointelegraph", url: "https://cointelegraph.com", publishedAt: now, sentiment: 0.8 },
94
- ];
95
- }
96
- buildReport(items) {
97
- const sentiments = items.map(i => i.sentiment ?? 0);
98
- const avg = sentiments.length > 0
99
- ? sentiments.reduce((a, b) => a + b, 0) / sentiments.length
100
- : 0;
101
- const sorted = [...items].sort((a, b) => (b.sentiment ?? 0) - (a.sentiment ?? 0));
102
- return {
103
- items,
104
- averageSentiment: avg,
105
- topPositive: sorted.slice(0, 3),
106
- topNegative: sorted.slice(-3).reverse(),
107
- };
108
- }
109
- statusBadge() {
110
- try {
111
- const report = this.buildReport(this.cachedItems);
112
- if (report.items.length === 0)
113
- return "";
114
- const emoji = report.averageSentiment > 0.2 ? "📈" : report.averageSentiment < -0.2 ? "📉" : "📊";
115
- return `${emoji} ${(report.averageSentiment * 100).toFixed(0)}%`;
116
- }
117
- catch (error) {
118
- logger.debug('NewsSentiment', 'statusBadge failed', { error: error.message });
119
- return "";
120
- }
121
- }
36
+ cachedItems = [];
37
+ lastFetch = 0;
38
+ cacheDuration = 300_000;
39
+ async getLatest() {
40
+ if (this.cachedItems.length > 0 && Date.now() - this.lastFetch < this.cacheDuration) {
41
+ return this.buildReport(this.cachedItems);
42
+ }
43
+ return this.fetch();
44
+ }
45
+ async fetch() {
46
+ const items = [];
47
+ try {
48
+
49
+ const apiKey = process.env.CRYPTOPANIC_API_KEY;
50
+ const url = apiKey
51
+ ? `https://cryptopanic.com/api/v1/posts/?auth_token=${apiKey}&kind=news&public=true`
52
+ : "https://cryptopanic.com/api/v1/posts/?public=true";
53
+ const response = await resilientFetch(url, {
54
+ timeout: 10_000,
55
+ retries: 1,
56
+ headers: { "Accept": "application/json" },
57
+ });
58
+ if (response.ok) {
59
+ const data = await response.json();
60
+ for (const post of (data.results ?? []).slice(0, 30)) {
61
+ items.push({
62
+ title: post.title,
63
+ source: post.source?.title || post.domain || "cryptopanic",
64
+ url: post.url,
65
+ publishedAt: post.published_at,
66
+ sentiment: scoreSentiment(post.title),
67
+ });
68
+ }
69
+ }
70
+ else {
71
+
72
+ items.push(...this.getFallbackNews());
73
+ }
74
+ }
75
+ catch (error) {
76
+ logger.warn('NewsSentiment', 'Failed to fetch news', { error: error.message });
77
+ items.push(...this.getFallbackNews());
78
+ }
79
+ this.cachedItems = items;
80
+ this.lastFetch = Date.now();
81
+ return this.buildReport(items);
82
+ }
83
+ getFallbackNews() {
84
+ const now = new Date().toISOString();
85
+ return [
86
+ { title: "Bitcoin holds support above $60k as institutional inflows continue", source: "coindesk", url: "https://coindesk.com", publishedAt: now, sentiment: 0.6 },
87
+ { title: "Solana network activity surges with record daily transactions", source: "theblock", url: "https://theblock.co", publishedAt: now, sentiment: 0.7 },
88
+ { title: "DeFi TVL climbs to multi-month high across major protocols", source: "defillama", url: "https://defillama.com", publishedAt: now, sentiment: 0.5 },
89
+ { title: "Regulatory clarity expected as new crypto framework emerges", source: "reuters", url: "https://reuters.com", publishedAt: now, sentiment: 0.3 },
90
+ { title: "AI tokens lead market recovery with 15% weekly gains", source: "cointelegraph", url: "https://cointelegraph.com", publishedAt: now, sentiment: 0.8 },
91
+ ];
92
+ }
93
+ buildReport(items) {
94
+ const sentiments = items.map(i => i.sentiment ?? 0);
95
+ const avg = sentiments.length > 0
96
+ ? sentiments.reduce((a, b) => a + b, 0) / sentiments.length
97
+ : 0;
98
+ const sorted = [...items].sort((a, b) => (b.sentiment ?? 0) - (a.sentiment ?? 0));
99
+ return {
100
+ items,
101
+ averageSentiment: avg,
102
+ topPositive: sorted.slice(0, 3),
103
+ topNegative: sorted.slice(-3).reverse(),
104
+ };
105
+ }
106
+ statusBadge() {
107
+ try {
108
+ const report = this.buildReport(this.cachedItems);
109
+ if (report.items.length === 0)
110
+ return "";
111
+ const emoji = report.averageSentiment > 0.2 ? "📈" : report.averageSentiment < -0.2 ? "📉" : "📊";
112
+ return `${emoji} ${(report.averageSentiment * 100).toFixed(0)}%`;
113
+ }
114
+ catch (error) {
115
+ logger.debug('NewsSentiment', 'statusBadge failed', { error: error.message });
116
+ return "";
117
+ }
118
+ }
122
119
  }
123
120
  export const newsFeed = new NewsFeed();
124
121
  export const getNewsParams = Type.Object({
125
- limit: Type.Optional(Type.Number({ description: "Number of news items" })),
122
+ limit: Type.Optional(Type.Number({ description: "Number of news items" })),
126
123
  });
127
124
  export async function getNewsTool(_id, params) {
128
- const report = await newsFeed.getLatest();
129
- const limit = params.limit || 10;
130
- const items = report.items.slice(0, limit);
131
- const lines = items.map(i => {
132
- const sent = i.sentiment ?? 0;
133
- const icon = sent > 0.3 ? "🟢" : sent < -0.3 ? "🔴" : "⚪";
134
- return `${icon} [${(sent * 100).toFixed(0)}%] ${i.title} — ${i.source}`;
135
- });
136
- return {
137
- content: [{
138
- type: "text",
139
- text: [
140
- `News (${report.items.length} items, avg sentiment: ${(report.averageSentiment * 100).toFixed(0)}%)`,
141
- ...lines,
142
- ].join("\n"),
143
- }],
144
- };
125
+ const report = await newsFeed.getLatest();
126
+ const limit = params.limit || 10;
127
+ const items = report.items.slice(0, limit);
128
+ const lines = items.map(i => {
129
+ const sent = i.sentiment ?? 0;
130
+ const icon = sent > 0.3 ? "🟢" : sent < -0.3 ? "🔴" : "⚪";
131
+ return `${icon} [${(sent * 100).toFixed(0)}%] ${i.title} — ${i.source}`;
132
+ });
133
+ return {
134
+ content: [{
135
+ type: "text",
136
+ text: [
137
+ `News (${report.items.length} items, avg sentiment: ${(report.averageSentiment * 100).toFixed(0)}%)`,
138
+ ...lines,
139
+ ].join("\n"),
140
+ }],
141
+ };
145
142
  }
146
143
  export { scoreSentiment };
147
- //# sourceMappingURL=NewsSentiment.js.map
@@ -68,6 +68,8 @@ export declare class PriceFeed {
68
68
  private cachedAiaiPrice;
69
69
  private lastFetch;
70
70
  private cacheDuration;
71
+ private _cachedTicker;
72
+ private _cachedTickerPrice;
71
73
  getAiaiaiPrice(): Promise<PriceResult>;
72
74
  fetchToken(tokenAddress: string): Promise<PriceResult>;
73
75
  private fallbackPrice;
@@ -80,6 +82,9 @@ export declare class PriceFeed {
80
82
  }>;
81
83
  getAiaiaiPriceTool(): Promise<ToolResult>;
82
84
  getTokenPriceTool(_id: string, params: Record<string, unknown>): Promise<ToolResult>;
85
+ private ws;
86
+ private wsReconnectTimer;
87
+ connectWebSocket(): void;
88
+ disconnectWebSocket(): void;
83
89
  }
84
90
  export declare const priceFeed: PriceFeed;
85
- //# sourceMappingURL=PriceFeed.d.ts.map
@@ -1,141 +1,209 @@
1
- /**
2
- * PriceFeed — real-time price aggregation via DexScreener API.
3
- * Primary: AIAIAI token price (hardcoded address).
4
- * Secondary: query any token by address.
5
- */
1
+
6
2
  import { Type } from "@sinclair/typebox";
7
3
  import { resilientFetch } from "../util/resilientFetch.js";
8
4
  import { logger } from "../util/logger.js";
9
5
  const AIAIAI_TOKEN = "AVPJS61gZmWKtaEpb7qYPKo8Fk2xQUsayYQxPiPMpump";
10
6
  export class PriceFeed {
11
- cachedAiaiPrice = null;
12
- lastFetch = 0;
13
- cacheDuration = 30_000; // 30s cache
14
- async getAiaiaiPrice() {
15
- if (this.cachedAiaiPrice && Date.now() - this.lastFetch < this.cacheDuration) {
16
- return this.cachedAiaiPrice;
17
- }
18
- return this.fetchToken(AIAIAI_TOKEN);
19
- }
20
- async fetchToken(tokenAddress) {
21
- const url = `https://api.dexscreener.com/tokens/v1/solana/${tokenAddress}`;
22
- try {
23
- const response = await resilientFetch(url, { timeout: 10_000, retries: 1 });
24
- if (!response.ok) {
25
- return this.fallbackPrice(tokenAddress);
26
- }
27
- const data = await response.json();
28
- if (!data || data.length === 0) {
29
- return this.fallbackPrice(tokenAddress);
30
- }
31
- const pair = data[0];
32
- const result = {
33
- tokenAddress,
34
- symbol: pair.baseToken.symbol,
35
- name: pair.baseToken.name,
36
- priceUsd: pair.priceUsd,
37
- priceNative: pair.priceNative,
38
- liquidityUsd: pair.liquidity?.usd ?? 0,
39
- fdv: pair.fdv ?? null,
40
- marketCap: pair.marketCap ?? null,
41
- volume24h: pair.volume?.["h24"] ?? 0,
42
- priceChange24h: pair.priceChange?.["h24"] ?? 0,
43
- buys24h: pair.txns?.["h24"]?.buys ?? 0,
44
- sells24h: pair.txns?.["h24"]?.sells ?? 0,
45
- dexUrl: pair.url,
46
- };
47
- if (tokenAddress === AIAIAI_TOKEN) {
48
- this.cachedAiaiPrice = result;
49
- this.lastFetch = Date.now();
50
- }
51
- return result;
52
- }
53
- catch (error) {
54
- logger.warn('PriceFeed', 'fetchToken failed', { tokenAddress, error: error.message });
55
- return this.fallbackPrice(tokenAddress);
56
- }
57
- }
58
- fallbackPrice(tokenAddress) {
59
- return {
60
- tokenAddress,
61
- symbol: tokenAddress === AIAIAI_TOKEN ? "AIAIAI" : "UNKNOWN",
62
- name: tokenAddress === AIAIAI_TOKEN ? "AIAIAI Chain" : "Unknown Token",
63
- priceUsd: null,
64
- priceNative: "0",
65
- liquidityUsd: 0,
66
- fdv: null,
67
- marketCap: null,
68
- volume24h: 0,
69
- priceChange24h: 0,
70
- buys24h: 0,
71
- sells24h: 0,
72
- dexUrl: `https://dexscreener.com/solana/${tokenAddress}`,
73
- };
74
- }
75
- tickerLine(maxLength = 6) {
76
- try {
77
- const p = this.cachedAiaiPrice;
78
- if (!p || !p.priceUsd)
79
- return "";
80
- const price = parseFloat(p.priceUsd).toFixed(6);
81
- const change = p.priceChange24h;
82
- const arrow = change > 0 ? "▲" : change < 0 ? "▼" : "─";
83
- return `$AIAIAI $${price} ${arrow}${Math.abs(change).toFixed(2)}%`.slice(0, 40);
84
- }
85
- catch (error) {
86
- // Log error in case of debug needed
87
- console.error('Error in tickerLine:', error);
88
- return "";
89
- }
90
- }
91
- getAiaiaiPriceSync() {
92
- return this.cachedAiaiPrice;
93
- }
94
- priceLine() {
95
- const p = this.getAiaiaiPriceSync();
96
- if (!p || !p.priceUsd)
97
- return "$AIAIAI: loading...";
98
- return `$AIAIAI $${parseFloat(p.priceUsd).toFixed(6)} | ${p.priceChange24h > 0 ? "+" : ""}${p.priceChange24h.toFixed(2)}%`;
99
- }
100
- // ── Tools ───────────────────────────────────────────────────────────────
101
- getAiaiaiPriceParams = Type.Object({});
102
- getTokenPriceParams = Type.Object({
103
- address: Type.String({ description: "Token contract address on Solana" }),
104
- });
105
- async getAiaiaiPriceTool() {
106
- const p = await this.getAiaiaiPrice();
107
- const lines = [
108
- `Token: $${p.symbol} (${p.name})`,
109
- `Address: ${p.tokenAddress}`,
110
- `Price USD: ${p.priceUsd ? `$${parseFloat(p.priceUsd).toFixed(8)}` : "N/A"}`,
111
- `Price SOL: ${parseFloat(p.priceNative).toFixed(8)} SOL`,
112
- `24h Change: ${p.priceChange24h > 0 ? "+" : ""}${p.priceChange24h.toFixed(2)}%`,
113
- `24h Volume: $${p.volume24h.toLocaleString()}`,
114
- `24h Buys: ${p.buys24h} | Sells: ${p.sells24h}`,
115
- `Liquidity: $${p.liquidityUsd.toLocaleString()}`,
116
- `FDV: ${p.fdv ? `$${p.fdv.toLocaleString()}` : "N/A"}`,
117
- `Market Cap: ${p.marketCap ? `$${p.marketCap.toLocaleString()}` : "N/A"}`,
118
- `DEX: ${p.dexUrl}`,
119
- ];
120
- return { content: [{ type: "text", text: lines.join("\n") }] };
121
- }
122
- async getTokenPriceTool(_id, params) {
123
- const address = params.address;
124
- const p = await this.fetchToken(address);
125
- const lines = [
126
- `Token: $${p.symbol} (${p.name})`,
127
- `Address: ${p.tokenAddress}`,
128
- `Price USD: ${p.priceUsd ? `$${parseFloat(p.priceUsd).toFixed(8)}` : "N/A"}`,
129
- `Price NATIVE: ${parseFloat(p.priceNative).toFixed(8)}`,
130
- `24h Change: ${p.priceChange24h > 0 ? "+" : ""}${p.priceChange24h.toFixed(2)}%`,
131
- `24h Volume: $${p.volume24h.toLocaleString()}`,
132
- `Buys/Sells: ${p.buys24h}/${p.sells24h}`,
133
- `Liquidity: $${p.liquidityUsd.toLocaleString()}`,
134
- ];
135
- return { content: [{ type: "text", text: lines.join("\n") }] };
136
- }
7
+ cachedAiaiPrice = null;
8
+ lastFetch = 0;
9
+ cacheDuration = 30_000;
10
+ _cachedTicker = "";
11
+ _cachedTickerPrice = "";
12
+ async getAiaiaiPrice() {
13
+ if (this.cachedAiaiPrice && Date.now() - this.lastFetch < this.cacheDuration) {
14
+ return this.cachedAiaiPrice;
15
+ }
16
+ return this.fetchToken(AIAIAI_TOKEN);
17
+ }
18
+ async fetchToken(tokenAddress) {
19
+ const url = `https://api.dexscreener.com/tokens/v1/solana/${tokenAddress}`;
20
+ try {
21
+ const response = await resilientFetch(url, { timeout: 10_000, retries: 1 });
22
+ if (!response.ok) {
23
+ return this.fallbackPrice(tokenAddress);
24
+ }
25
+ const data = await response.json();
26
+ if (!data || data.length === 0) {
27
+ return this.fallbackPrice(tokenAddress);
28
+ }
29
+ const pair = data[0];
30
+ const result = {
31
+ tokenAddress,
32
+ symbol: pair.baseToken.symbol,
33
+ name: pair.baseToken.name,
34
+ priceUsd: pair.priceUsd,
35
+ priceNative: pair.priceNative,
36
+ liquidityUsd: pair.liquidity?.usd ?? 0,
37
+ fdv: pair.fdv ?? null,
38
+ marketCap: pair.marketCap ?? null,
39
+ volume24h: pair.volume?.["h24"] ?? 0,
40
+ priceChange24h: pair.priceChange?.["h24"] ?? 0,
41
+ buys24h: pair.txns?.["h24"]?.buys ?? 0,
42
+ sells24h: pair.txns?.["h24"]?.sells ?? 0,
43
+ dexUrl: pair.url,
44
+ };
45
+ if (tokenAddress === AIAIAI_TOKEN) {
46
+ this.cachedAiaiPrice = result;
47
+ this.lastFetch = Date.now();
48
+
49
+ this._cachedTicker = "";
50
+ this._cachedTickerPrice = "";
51
+ }
52
+ return result;
53
+ }
54
+ catch (error) {
55
+ logger.warn('PriceFeed', 'fetchToken failed', { tokenAddress, error: error.message });
56
+ return this.fallbackPrice(tokenAddress);
57
+ }
58
+ }
59
+ fallbackPrice(tokenAddress) {
60
+ return {
61
+ tokenAddress,
62
+ symbol: tokenAddress === AIAIAI_TOKEN ? "AIAIAI" : "UNKNOWN",
63
+ name: tokenAddress === AIAIAI_TOKEN ? "AIAIAI Chain" : "Unknown Token",
64
+ priceUsd: null,
65
+ priceNative: "0",
66
+ liquidityUsd: 0,
67
+ fdv: null,
68
+ marketCap: null,
69
+ volume24h: 0,
70
+ priceChange24h: 0,
71
+ buys24h: 0,
72
+ sells24h: 0,
73
+ dexUrl: `https://dexscreener.com/solana/${tokenAddress}`,
74
+ };
75
+ }
76
+ tickerLine(maxLength = 6) {
77
+ try {
78
+ const p = this.cachedAiaiPrice;
79
+ if (!p || !p.priceUsd)
80
+ return this._cachedTicker;
81
+ const price = parseFloat(p.priceUsd).toFixed(6);
82
+
83
+ if (this._cachedTicker && price === this._cachedTickerPrice)
84
+ return this._cachedTicker;
85
+ const change = p.priceChange24h;
86
+ const arrow = change > 0 ? "▲" : change < 0 ? "▼" : "─";
87
+ this._cachedTickerPrice = price;
88
+ this._cachedTicker = `$AIAIAI $${price} ${arrow}${Math.abs(change).toFixed(2)}%`.slice(0, 40);
89
+ return this._cachedTicker;
90
+ }
91
+ catch (error) {
92
+ logger.error('PriceFeed', 'tickerLine error', { error: error.message });
93
+ return this._cachedTicker;
94
+ }
95
+ }
96
+ getAiaiaiPriceSync() {
97
+ return this.cachedAiaiPrice;
98
+ }
99
+ priceLine() {
100
+ const p = this.getAiaiaiPriceSync();
101
+ if (!p || !p.priceUsd)
102
+ return "$AIAIAI: loading...";
103
+ return `$AIAIAI $${parseFloat(p.priceUsd).toFixed(6)} | ${p.priceChange24h > 0 ? "+" : ""}${p.priceChange24h.toFixed(2)}%`;
104
+ }
105
+
106
+ getAiaiaiPriceParams = Type.Object({});
107
+ getTokenPriceParams = Type.Object({
108
+ address: Type.String({ description: "Token contract address on Solana" }),
109
+ });
110
+ async getAiaiaiPriceTool() {
111
+ const p = await this.getAiaiaiPrice();
112
+ const lines = [
113
+ `Token: $${p.symbol} (${p.name})`,
114
+ `Address: ${p.tokenAddress}`,
115
+ `Price USD: ${p.priceUsd ? `$${parseFloat(p.priceUsd).toFixed(8)}` : "N/A"}`,
116
+ `Price SOL: ${parseFloat(p.priceNative).toFixed(8)} SOL`,
117
+ `24h Change: ${p.priceChange24h > 0 ? "+" : ""}${p.priceChange24h.toFixed(2)}%`,
118
+ `24h Volume: $${p.volume24h.toLocaleString()}`,
119
+ `24h Buys: ${p.buys24h} | Sells: ${p.sells24h}`,
120
+ `Liquidity: $${p.liquidityUsd.toLocaleString()}`,
121
+ `FDV: ${p.fdv ? `$${p.fdv.toLocaleString()}` : "N/A"}`,
122
+ `Market Cap: ${p.marketCap ? `$${p.marketCap.toLocaleString()}` : "N/A"}`,
123
+ `DEX: ${p.dexUrl}`,
124
+ ];
125
+ return { content: [{ type: "text", text: lines.join("\n") }] };
126
+ }
127
+ async getTokenPriceTool(_id, params) {
128
+ const address = params.address;
129
+ const p = await this.fetchToken(address);
130
+ const lines = [
131
+ `Token: $${p.symbol} (${p.name})`,
132
+ `Address: ${p.tokenAddress}`,
133
+ `Price USD: ${p.priceUsd ? `$${parseFloat(p.priceUsd).toFixed(8)}` : "N/A"}`,
134
+ `Price NATIVE: ${parseFloat(p.priceNative).toFixed(8)}`,
135
+ `24h Change: ${p.priceChange24h > 0 ? "+" : ""}${p.priceChange24h.toFixed(2)}%`,
136
+ `24h Volume: $${p.volume24h.toLocaleString()}`,
137
+ `Buys/Sells: ${p.buys24h}/${p.sells24h}`,
138
+ `Liquidity: $${p.liquidityUsd.toLocaleString()}`,
139
+ ];
140
+ return { content: [{ type: "text", text: lines.join("\n") }] };
141
+ }
142
+
143
+ ws = null;
144
+ wsReconnectTimer = null;
145
+ connectWebSocket() {
146
+ if (this.ws?.readyState === 1)
147
+ return;
148
+ try {
149
+ const WebSocket = globalThis.WebSocket || require("ws");
150
+ if (!WebSocket)
151
+ return;
152
+ this.ws = new WebSocket("wss://io.dexscreener.com/dex/screener/pairs/solana/AVPJS61gZmWKtaEpb7qYPKo8Fk2xQUsayYQxPiPMpump");
153
+ this.ws.onmessage = (event) => {
154
+ try {
155
+ const data = JSON.parse(event.data);
156
+ if (data?.priceUsd) {
157
+ const result = {
158
+ tokenAddress: AIAIAI_TOKEN,
159
+ symbol: "AIAIAI",
160
+ name: "AIAIAI Chain",
161
+ priceUsd: data.priceUsd,
162
+ priceNative: data.priceNative ?? "0",
163
+ liquidityUsd: data.liquidityUsd ?? 0,
164
+ fdv: data.fdv ?? null,
165
+ marketCap: data.marketCap ?? null,
166
+ volume24h: data.volume24h ?? 0,
167
+ priceChange24h: data.priceChange24h ?? 0,
168
+ buys24h: 0,
169
+ sells24h: 0,
170
+ dexUrl: `https://dexscreener.com/solana/${AIAIAI_TOKEN}`,
171
+ };
172
+ this.cachedAiaiPrice = result;
173
+ this.lastFetch = Date.now();
174
+ this._cachedTicker = "";
175
+ this._cachedTickerPrice = "";
176
+ }
177
+ }
178
+ catch { }
179
+ };
180
+ this.ws.onclose = () => {
181
+
182
+ this.wsReconnectTimer = setTimeout(() => this.connectWebSocket(), 30_000);
183
+ };
184
+ this.ws.onerror = () => {
185
+ try {
186
+ this.ws?.close();
187
+ }
188
+ catch { }
189
+ };
190
+ }
191
+ catch {
192
+
193
+ }
194
+ }
195
+ disconnectWebSocket() {
196
+ if (this.wsReconnectTimer)
197
+ clearTimeout(this.wsReconnectTimer);
198
+ try {
199
+ this.ws?.close();
200
+ }
201
+ catch { }
202
+ this.ws = null;
203
+ }
137
204
  }
138
205
  export const priceFeed = new PriceFeed();
139
- // Eagerly initialize the price cache so sidebar shows price immediately
206
+
140
207
  priceFeed.getAiaiaiPrice().catch(() => { });
141
- //# sourceMappingURL=PriceFeed.js.map
208
+
209
+ priceFeed.connectWebSocket();