pnpfucius 2.0.0
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 +396 -0
- package/bin/claude-predict.js +5 -0
- package/bin/pnpfucius.js +8 -0
- package/package.json +71 -0
- package/src/agent.js +1037 -0
- package/src/ai/index.js +6 -0
- package/src/ai/market-generator.js +186 -0
- package/src/ai/resolver.js +172 -0
- package/src/ai/scorer.js +184 -0
- package/src/analytics/aggregator.js +198 -0
- package/src/cli.js +948 -0
- package/src/collateral/privacy-tokens.js +183 -0
- package/src/config.js +128 -0
- package/src/daemon/index.js +321 -0
- package/src/daemon/lifecycle.js +168 -0
- package/src/daemon/scheduler.js +252 -0
- package/src/events/emitter.js +147 -0
- package/src/helius/client.js +221 -0
- package/src/helius/transaction-tracker.js +192 -0
- package/src/helius/webhooks.js +233 -0
- package/src/index.js +139 -0
- package/src/monitoring/news-monitor.js +262 -0
- package/src/monitoring/news-scorer.js +236 -0
- package/src/predict/agent.js +291 -0
- package/src/predict/prompts.js +69 -0
- package/src/predict/slash-commands.js +361 -0
- package/src/predict/tools/analytics-tools.js +83 -0
- package/src/predict/tools/bash-tool.js +87 -0
- package/src/predict/tools/file-tools.js +140 -0
- package/src/predict/tools/index.js +120 -0
- package/src/predict/tools/market-tools.js +851 -0
- package/src/predict/tools/news-tools.js +130 -0
- package/src/predict/ui/renderer.js +215 -0
- package/src/predict/ui/welcome.js +146 -0
- package/src/privacy-markets.js +194 -0
- package/src/storage/market-store.js +418 -0
- package/src/utils/spinner.js +172 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// Dashboard data aggregation for market analytics
|
|
2
|
+
// Collects and formats metrics for display and API endpoints
|
|
3
|
+
|
|
4
|
+
import { agentEvents, AgentEvents } from '../events/emitter.js';
|
|
5
|
+
|
|
6
|
+
export class DashboardAggregator {
|
|
7
|
+
constructor(store) {
|
|
8
|
+
this.store = store;
|
|
9
|
+
this.cache = null;
|
|
10
|
+
this.cacheExpiry = 60000; // 1 minute cache
|
|
11
|
+
this.lastUpdate = 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async getOverview() {
|
|
15
|
+
// Use cache if fresh
|
|
16
|
+
if (this.cache && Date.now() - this.lastUpdate < this.cacheExpiry) {
|
|
17
|
+
return this.cache;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const stats = await this.store.getStats();
|
|
21
|
+
const recent = await this.store.getAllMarkets({ limit: 10 });
|
|
22
|
+
const performance = await this.store.getPerformanceMetrics();
|
|
23
|
+
|
|
24
|
+
const overview = {
|
|
25
|
+
summary: {
|
|
26
|
+
totalMarkets: stats.total,
|
|
27
|
+
activeMarkets: stats.active,
|
|
28
|
+
resolvedMarkets: stats.resolved,
|
|
29
|
+
cancelledMarkets: stats.cancelled,
|
|
30
|
+
recentWeek: stats.recentCount
|
|
31
|
+
},
|
|
32
|
+
categoryBreakdown: stats.byCategory.map(c => ({
|
|
33
|
+
category: c.category,
|
|
34
|
+
key: c.category_key,
|
|
35
|
+
count: c.count,
|
|
36
|
+
percentage: Math.round((c.count / stats.total) * 100)
|
|
37
|
+
})),
|
|
38
|
+
performance: {
|
|
39
|
+
totalVolume: performance.totalVolume,
|
|
40
|
+
averageDuration: performance.averageDuration,
|
|
41
|
+
resolutionRate: performance.resolutionRate,
|
|
42
|
+
resolvedCount: performance.marketCount
|
|
43
|
+
},
|
|
44
|
+
recentMarkets: recent.map(m => ({
|
|
45
|
+
address: m.address,
|
|
46
|
+
question: m.question,
|
|
47
|
+
category: m.category,
|
|
48
|
+
status: m.status,
|
|
49
|
+
createdAt: m.creationTime,
|
|
50
|
+
endTime: m.endTime
|
|
51
|
+
})),
|
|
52
|
+
lastUpdated: Date.now()
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Update cache
|
|
56
|
+
this.cache = overview;
|
|
57
|
+
this.lastUpdate = Date.now();
|
|
58
|
+
|
|
59
|
+
agentEvents.emitTyped(AgentEvents.STATS_UPDATED, { overview });
|
|
60
|
+
|
|
61
|
+
return overview;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async getPerformanceMetrics() {
|
|
65
|
+
return this.store.getPerformanceMetrics();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async getCategoryStats() {
|
|
69
|
+
const stats = await this.store.getStats();
|
|
70
|
+
return stats.byCategory;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async getTimeSeriesData(period = '7d') {
|
|
74
|
+
const now = Date.now();
|
|
75
|
+
let since;
|
|
76
|
+
|
|
77
|
+
switch (period) {
|
|
78
|
+
case '24h':
|
|
79
|
+
since = now - 24 * 60 * 60 * 1000;
|
|
80
|
+
break;
|
|
81
|
+
case '7d':
|
|
82
|
+
since = now - 7 * 24 * 60 * 60 * 1000;
|
|
83
|
+
break;
|
|
84
|
+
case '30d':
|
|
85
|
+
since = now - 30 * 24 * 60 * 60 * 1000;
|
|
86
|
+
break;
|
|
87
|
+
default:
|
|
88
|
+
since = now - 7 * 24 * 60 * 60 * 1000;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const markets = await this.store.getAllMarkets({ since });
|
|
92
|
+
|
|
93
|
+
// Group by day
|
|
94
|
+
const dailyData = {};
|
|
95
|
+
|
|
96
|
+
for (const market of markets) {
|
|
97
|
+
const day = new Date(market.creationTime).toISOString().split('T')[0];
|
|
98
|
+
|
|
99
|
+
if (!dailyData[day]) {
|
|
100
|
+
dailyData[day] = {
|
|
101
|
+
date: day,
|
|
102
|
+
created: 0,
|
|
103
|
+
volume: 0n
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
dailyData[day].created++;
|
|
108
|
+
|
|
109
|
+
if (market.volume) {
|
|
110
|
+
dailyData[day].volume += BigInt(market.volume);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Convert to array and sort
|
|
115
|
+
return Object.values(dailyData)
|
|
116
|
+
.map(d => ({
|
|
117
|
+
...d,
|
|
118
|
+
volume: d.volume.toString()
|
|
119
|
+
}))
|
|
120
|
+
.sort((a, b) => a.date.localeCompare(b.date));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async getActiveMarketsSummary() {
|
|
124
|
+
const active = await this.store.getAllMarkets({ status: 'active' });
|
|
125
|
+
|
|
126
|
+
// Sort by end time (closest to expiry first)
|
|
127
|
+
active.sort((a, b) => a.endTime - b.endTime);
|
|
128
|
+
|
|
129
|
+
return active.map(m => {
|
|
130
|
+
const timeLeft = m.endTime - Date.now();
|
|
131
|
+
const daysLeft = Math.ceil(timeLeft / (24 * 60 * 60 * 1000));
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
address: m.address,
|
|
135
|
+
question: m.question,
|
|
136
|
+
category: m.category,
|
|
137
|
+
daysLeft: Math.max(0, daysLeft),
|
|
138
|
+
endTime: m.endTime,
|
|
139
|
+
status: daysLeft <= 0 ? 'expired' : daysLeft <= 7 ? 'expiring_soon' : 'active'
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async getResolutionPendingMarkets() {
|
|
145
|
+
const active = await this.store.getAllMarkets({ status: 'active' });
|
|
146
|
+
const now = Date.now();
|
|
147
|
+
|
|
148
|
+
// Filter markets past their end time
|
|
149
|
+
return active
|
|
150
|
+
.filter(m => m.endTime < now)
|
|
151
|
+
.map(m => ({
|
|
152
|
+
address: m.address,
|
|
153
|
+
question: m.question,
|
|
154
|
+
endedAt: new Date(m.endTime).toISOString(),
|
|
155
|
+
daysPastEnd: Math.floor((now - m.endTime) / (24 * 60 * 60 * 1000))
|
|
156
|
+
}));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Invalidate cache
|
|
160
|
+
invalidateCache() {
|
|
161
|
+
this.cache = null;
|
|
162
|
+
this.lastUpdate = 0;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function createAggregator(store) {
|
|
167
|
+
return new DashboardAggregator(store);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Format large numbers for display
|
|
171
|
+
export function formatNumber(num) {
|
|
172
|
+
const n = BigInt(num);
|
|
173
|
+
|
|
174
|
+
if (n >= 1000000000n) {
|
|
175
|
+
return `${Number(n / 1000000000n).toFixed(1)}B`;
|
|
176
|
+
}
|
|
177
|
+
if (n >= 1000000n) {
|
|
178
|
+
return `${Number(n / 1000000n).toFixed(1)}M`;
|
|
179
|
+
}
|
|
180
|
+
if (n >= 1000n) {
|
|
181
|
+
return `${Number(n / 1000n).toFixed(1)}K`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return n.toString();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Format time duration
|
|
188
|
+
export function formatDuration(ms) {
|
|
189
|
+
const seconds = Math.floor(ms / 1000);
|
|
190
|
+
const minutes = Math.floor(seconds / 60);
|
|
191
|
+
const hours = Math.floor(minutes / 60);
|
|
192
|
+
const days = Math.floor(hours / 24);
|
|
193
|
+
|
|
194
|
+
if (days > 0) return `${days}d`;
|
|
195
|
+
if (hours > 0) return `${hours}h`;
|
|
196
|
+
if (minutes > 0) return `${minutes}m`;
|
|
197
|
+
return `${seconds}s`;
|
|
198
|
+
}
|