@trust-ethos/cli 0.0.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/LICENSE +21 -0
- package/README.md +1791 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/commands/auction/active.d.ts +10 -0
- package/dist/commands/auction/active.js +39 -0
- package/dist/commands/auction/info.d.ts +16 -0
- package/dist/commands/auction/info.js +46 -0
- package/dist/commands/auction/list.d.ts +14 -0
- package/dist/commands/auction/list.js +61 -0
- package/dist/commands/broker/info.d.ts +16 -0
- package/dist/commands/broker/info.js +37 -0
- package/dist/commands/broker/list.d.ts +15 -0
- package/dist/commands/broker/list.js +62 -0
- package/dist/commands/config/get.d.ts +9 -0
- package/dist/commands/config/get.js +29 -0
- package/dist/commands/config/path.d.ts +6 -0
- package/dist/commands/config/path.js +12 -0
- package/dist/commands/config/set.d.ts +9 -0
- package/dist/commands/config/set.js +28 -0
- package/dist/commands/listing/info.d.ts +13 -0
- package/dist/commands/listing/info.js +41 -0
- package/dist/commands/listing/list.d.ts +13 -0
- package/dist/commands/listing/list.js +46 -0
- package/dist/commands/listing/voters.d.ts +19 -0
- package/dist/commands/listing/voters.js +48 -0
- package/dist/commands/market/featured.d.ts +10 -0
- package/dist/commands/market/featured.js +34 -0
- package/dist/commands/market/holders.d.ts +14 -0
- package/dist/commands/market/holders.js +46 -0
- package/dist/commands/market/info.d.ts +14 -0
- package/dist/commands/market/info.js +48 -0
- package/dist/commands/market/list.d.ts +16 -0
- package/dist/commands/market/list.js +55 -0
- package/dist/commands/nft/list.d.ts +15 -0
- package/dist/commands/nft/list.js +64 -0
- package/dist/commands/review/info.d.ts +17 -0
- package/dist/commands/review/info.js +49 -0
- package/dist/commands/review/list.d.ts +16 -0
- package/dist/commands/review/list.js +68 -0
- package/dist/commands/review/votes.d.ts +21 -0
- package/dist/commands/review/votes.js +91 -0
- package/dist/commands/score/status.d.ts +13 -0
- package/dist/commands/score/status.js +54 -0
- package/dist/commands/slash/info.d.ts +16 -0
- package/dist/commands/slash/info.js +42 -0
- package/dist/commands/slash/list.d.ts +15 -0
- package/dist/commands/slash/list.js +50 -0
- package/dist/commands/slash/votes.d.ts +21 -0
- package/dist/commands/slash/votes.js +91 -0
- package/dist/commands/user/activity.d.ts +15 -0
- package/dist/commands/user/activity.js +71 -0
- package/dist/commands/user/info.d.ts +14 -0
- package/dist/commands/user/info.js +51 -0
- package/dist/commands/user/invitations.d.ts +16 -0
- package/dist/commands/user/invitations.js +73 -0
- package/dist/commands/user/search.d.ts +15 -0
- package/dist/commands/user/search.js +59 -0
- package/dist/commands/user/summary.d.ts +14 -0
- package/dist/commands/user/summary.js +134 -0
- package/dist/commands/validator/info.d.ts +13 -0
- package/dist/commands/validator/info.js +53 -0
- package/dist/commands/validator/list.d.ts +13 -0
- package/dist/commands/validator/list.js +64 -0
- package/dist/commands/validator/sales.d.ts +12 -0
- package/dist/commands/validator/sales.js +52 -0
- package/dist/commands/vouch/info.d.ts +17 -0
- package/dist/commands/vouch/info.js +53 -0
- package/dist/commands/vouch/list.d.ts +18 -0
- package/dist/commands/vouch/list.js +89 -0
- package/dist/commands/vouch/mutual.d.ts +15 -0
- package/dist/commands/vouch/mutual.js +68 -0
- package/dist/commands/vouch/votes.d.ts +21 -0
- package/dist/commands/vouch/votes.js +91 -0
- package/dist/commands/xp/rank.d.ts +15 -0
- package/dist/commands/xp/rank.js +74 -0
- package/dist/commands/xp/seasons.d.ts +10 -0
- package/dist/commands/xp/seasons.js +42 -0
- package/dist/hooks/init.d.ts +3 -0
- package/dist/hooks/init.js +40 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/api/echo-client.d.ts +624 -0
- package/dist/lib/api/echo-client.js +408 -0
- package/dist/lib/config/index.d.ts +6 -0
- package/dist/lib/config/index.js +32 -0
- package/dist/lib/errors/cli-error.d.ts +23 -0
- package/dist/lib/errors/cli-error.js +57 -0
- package/dist/lib/formatting/colors.d.ts +13 -0
- package/dist/lib/formatting/colors.js +22 -0
- package/dist/lib/formatting/error.d.ts +1 -0
- package/dist/lib/formatting/error.js +64 -0
- package/dist/lib/formatting/output.d.ts +45 -0
- package/dist/lib/formatting/output.js +753 -0
- package/dist/lib/help.d.ts +4 -0
- package/dist/lib/help.js +28 -0
- package/dist/lib/update/index.d.ts +37 -0
- package/dist/lib/update/index.js +286 -0
- package/dist/lib/validation/userkey.d.ts +11 -0
- package/dist/lib/validation/userkey.js +81 -0
- package/oclif.manifest.json +2224 -0
- package/package.json +87 -0
|
@@ -0,0 +1,753 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
export function output(data) {
|
|
3
|
+
return JSON.stringify(data, null, 2);
|
|
4
|
+
}
|
|
5
|
+
function pluralize(count, singular, plural) {
|
|
6
|
+
return count === 1 ? singular : (plural || `${singular}s`);
|
|
7
|
+
}
|
|
8
|
+
function getScoreLevel(score) {
|
|
9
|
+
if (score < 800)
|
|
10
|
+
return 'untrusted';
|
|
11
|
+
if (score < 1200)
|
|
12
|
+
return 'questionable';
|
|
13
|
+
if (score < 1600)
|
|
14
|
+
return 'neutral';
|
|
15
|
+
if (score < 2000)
|
|
16
|
+
return 'reputable';
|
|
17
|
+
return 'exemplary';
|
|
18
|
+
}
|
|
19
|
+
export function formatUser(user) {
|
|
20
|
+
const displayName = user.displayName || user.username || 'Unknown';
|
|
21
|
+
const lines = [
|
|
22
|
+
pc.bold(pc.cyan(`User Profile: ${displayName}`)),
|
|
23
|
+
'',
|
|
24
|
+
];
|
|
25
|
+
if (user.username) {
|
|
26
|
+
lines.push(`${pc.dim('Username:')} @${user.username}`);
|
|
27
|
+
}
|
|
28
|
+
if (user.profileId) {
|
|
29
|
+
lines.push(`${pc.dim('Profile ID:')} ${user.profileId}`);
|
|
30
|
+
}
|
|
31
|
+
const level = getScoreLevel(user.score);
|
|
32
|
+
const levelColor = LEVEL_COLORS[level] || pc.white;
|
|
33
|
+
lines.push(`${pc.dim('Score:')} ${pc.green(String(user.score))} ${levelColor(`(${level.toUpperCase()})`)}`);
|
|
34
|
+
lines.push(`${pc.dim('Status:')} ${user.status}`);
|
|
35
|
+
lines.push(`${pc.dim('XP:')} ${pc.green(user.xpTotal.toLocaleString())}`);
|
|
36
|
+
if (user.xpStreakDays > 0) {
|
|
37
|
+
const dayWord = pluralize(user.xpStreakDays, 'day');
|
|
38
|
+
lines.push(`${pc.dim('Streak:')} ${user.xpStreakDays} ${dayWord}`);
|
|
39
|
+
}
|
|
40
|
+
if (user.stats) {
|
|
41
|
+
lines.push('');
|
|
42
|
+
lines.push(pc.bold('Stats'));
|
|
43
|
+
const reviews = user.stats.review.received;
|
|
44
|
+
const reviewTotal = reviews.positive + reviews.neutral + reviews.negative;
|
|
45
|
+
if (reviewTotal > 0) {
|
|
46
|
+
lines.push(`${pc.dim('Reviews Received:')} ${pc.green(`${reviews.positive} positive`)}, ${reviews.neutral} neutral, ${pc.red(`${reviews.negative} negative`)}`);
|
|
47
|
+
}
|
|
48
|
+
const vouches = user.stats.vouch;
|
|
49
|
+
if (vouches.received.count > 0 || vouches.given.count > 0) {
|
|
50
|
+
lines.push(`${pc.dim('Vouches:')} ${vouches.received.count} received, ${vouches.given.count} given`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (user.links?.profile) {
|
|
54
|
+
lines.push('');
|
|
55
|
+
lines.push(`${pc.dim('Profile:')} ${user.links.profile}`);
|
|
56
|
+
}
|
|
57
|
+
return lines.join('\n');
|
|
58
|
+
}
|
|
59
|
+
export function formatInvitations(invitations, total) {
|
|
60
|
+
if (!invitations.length) {
|
|
61
|
+
return pc.yellow('No invitations found.');
|
|
62
|
+
}
|
|
63
|
+
const lines = [pc.bold(`Invitations (${total} total)`), ''];
|
|
64
|
+
for (const inv of invitations) {
|
|
65
|
+
const i = inv.invitation;
|
|
66
|
+
const user = inv.invitedUser;
|
|
67
|
+
const statusIcon = i.status === 'ACCEPTED' ? pc.green('✓') : pc.yellow('○');
|
|
68
|
+
const userName = user?.username ? `@${user.username}` : user?.displayName || i.recipientAddress.slice(0, 10) + '...';
|
|
69
|
+
const date = new Date(i.dateInvited).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
70
|
+
lines.push(`${statusIcon} ${pc.bold(userName)} ${pc.dim(`(${i.status})`)}`);
|
|
71
|
+
lines.push(` ${pc.dim('Invited:')} ${date}`);
|
|
72
|
+
if (i.dateAccepted) {
|
|
73
|
+
const acceptedDate = new Date(i.dateAccepted).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
74
|
+
lines.push(` ${pc.dim('Accepted:')} ${acceptedDate}`);
|
|
75
|
+
}
|
|
76
|
+
if (user?.score) {
|
|
77
|
+
lines.push(` ${pc.dim('Score:')} ${user.score}`);
|
|
78
|
+
}
|
|
79
|
+
lines.push('');
|
|
80
|
+
}
|
|
81
|
+
return lines.join('\n');
|
|
82
|
+
}
|
|
83
|
+
export function formatSeasons(seasons, currentSeason) {
|
|
84
|
+
if (!seasons || seasons.length === 0) {
|
|
85
|
+
return pc.yellow('No seasons found');
|
|
86
|
+
}
|
|
87
|
+
const lines = [pc.bold(pc.cyan('XP Seasons')), ''];
|
|
88
|
+
if (currentSeason) {
|
|
89
|
+
lines.push(`${pc.dim('Current:')} Season ${currentSeason.id} (Week ${currentSeason.week || 1})`);
|
|
90
|
+
lines.push('');
|
|
91
|
+
}
|
|
92
|
+
for (const season of seasons) {
|
|
93
|
+
const isCurrent = currentSeason && season.id === currentSeason.id;
|
|
94
|
+
const prefix = isCurrent ? pc.green('*') : ' ';
|
|
95
|
+
lines.push(`${prefix} ${pc.bold(`Season ${season.id}`)}`);
|
|
96
|
+
lines.push(` ${pc.dim('Start:')} ${new Date(season.startDate).toLocaleDateString()}`);
|
|
97
|
+
if (season.endDate) {
|
|
98
|
+
lines.push(` ${pc.dim('End:')} ${new Date(season.endDate).toLocaleDateString()}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return lines.join('\n');
|
|
102
|
+
}
|
|
103
|
+
export function formatRank(data) {
|
|
104
|
+
const lines = [
|
|
105
|
+
pc.bold(pc.cyan('Leaderboard Rank')),
|
|
106
|
+
'',
|
|
107
|
+
`${pc.dim('Rank:')} ${pc.green(`#${data.rank.toLocaleString()}`)}`,
|
|
108
|
+
];
|
|
109
|
+
if (data.totalXp !== undefined) {
|
|
110
|
+
lines.push(`${pc.dim('Total XP:')} ${pc.green(data.totalXp.toLocaleString())}`);
|
|
111
|
+
}
|
|
112
|
+
if (data.seasonXp !== undefined && data.season !== undefined) {
|
|
113
|
+
lines.push(`${pc.dim(`Season ${data.season} XP:`)} ${pc.green(data.seasonXp.toLocaleString())}`);
|
|
114
|
+
}
|
|
115
|
+
if (data.username) {
|
|
116
|
+
lines.push(`${pc.dim('User:')} ${data.username}`);
|
|
117
|
+
}
|
|
118
|
+
else if (data.userkey) {
|
|
119
|
+
lines.push(`${pc.dim('Userkey:')} ${data.userkey}`);
|
|
120
|
+
}
|
|
121
|
+
return lines.join('\n');
|
|
122
|
+
}
|
|
123
|
+
export function formatSearchResults(results) {
|
|
124
|
+
if (!results || results.length === 0) {
|
|
125
|
+
return pc.yellow('No users found');
|
|
126
|
+
}
|
|
127
|
+
const lines = [
|
|
128
|
+
pc.bold(pc.cyan(`Search Results (${results.length} found)`)),
|
|
129
|
+
'',
|
|
130
|
+
];
|
|
131
|
+
for (const user of results) {
|
|
132
|
+
const displayName = user.displayName || user.username || 'Unknown';
|
|
133
|
+
lines.push(pc.bold(displayName));
|
|
134
|
+
if (user.username) {
|
|
135
|
+
lines.push(` ${pc.dim('Username:')} @${user.username}`);
|
|
136
|
+
}
|
|
137
|
+
lines.push(` ${pc.dim('Score:')} ${pc.green(String(user.score))}`);
|
|
138
|
+
lines.push(` ${pc.dim('XP:')} ${user.xpTotal.toLocaleString()}`);
|
|
139
|
+
lines.push('');
|
|
140
|
+
}
|
|
141
|
+
return lines.join('\n');
|
|
142
|
+
}
|
|
143
|
+
function formatTimestamp(ts) {
|
|
144
|
+
const date = new Date(ts * 1000);
|
|
145
|
+
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
146
|
+
}
|
|
147
|
+
function parseMetadata(metadata) {
|
|
148
|
+
if (!metadata)
|
|
149
|
+
return {};
|
|
150
|
+
try {
|
|
151
|
+
return JSON.parse(metadata);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return {};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
export function formatActivities(activities, username) {
|
|
158
|
+
if (!activities || activities.length === 0) {
|
|
159
|
+
return pc.yellow('No activities found');
|
|
160
|
+
}
|
|
161
|
+
const lines = [
|
|
162
|
+
pc.bold(pc.cyan(`Recent Activity${username ? ` for ${username}` : ''}`)),
|
|
163
|
+
'',
|
|
164
|
+
];
|
|
165
|
+
for (const activity of activities) {
|
|
166
|
+
const typeIcon = activity.type === 'vouch' ? '🤝' : activity.type === 'review' ? '📝' : '❌';
|
|
167
|
+
const typeLabel = activity.type.charAt(0).toUpperCase() + activity.type.slice(1);
|
|
168
|
+
const date = formatTimestamp(activity.timestamp);
|
|
169
|
+
lines.push(`${typeIcon} ${pc.bold(typeLabel)} ${pc.dim(`• ${date}`)}`);
|
|
170
|
+
const authorName = activity.author.username ? `@${activity.author.username}` : activity.author.name;
|
|
171
|
+
const subjectName = activity.subject.username ? `@${activity.subject.username}` : activity.subject.name;
|
|
172
|
+
lines.push(` ${pc.dim('From:')} ${authorName} ${pc.dim('→')} ${subjectName}`);
|
|
173
|
+
if (activity.data.comment) {
|
|
174
|
+
const comment = activity.data.comment.length > 60
|
|
175
|
+
? activity.data.comment.substring(0, 57) + '...'
|
|
176
|
+
: activity.data.comment;
|
|
177
|
+
lines.push(` ${pc.dim('Title:')} ${comment}`);
|
|
178
|
+
}
|
|
179
|
+
if (activity.data.score) {
|
|
180
|
+
const scoreColor = activity.data.score === 'positive' ? pc.green :
|
|
181
|
+
activity.data.score === 'negative' ? pc.red : pc.dim;
|
|
182
|
+
lines.push(` ${pc.dim('Score:')} ${scoreColor(activity.data.score)}`);
|
|
183
|
+
}
|
|
184
|
+
const meta = parseMetadata(activity.data.metadata);
|
|
185
|
+
if (meta.description) {
|
|
186
|
+
const desc = meta.description.length > 80
|
|
187
|
+
? meta.description.substring(0, 77) + '...'
|
|
188
|
+
: meta.description;
|
|
189
|
+
lines.push(` ${pc.dim(desc)}`);
|
|
190
|
+
}
|
|
191
|
+
lines.push('');
|
|
192
|
+
}
|
|
193
|
+
return lines.join('\n');
|
|
194
|
+
}
|
|
195
|
+
export function formatSlash(slash) {
|
|
196
|
+
const isOpen = !slash.closedAt && !slash.cancelledAt;
|
|
197
|
+
const statusIcon = isOpen ? pc.red('⚔️ OPEN') : pc.gray('✓ CLOSED');
|
|
198
|
+
const lines = [
|
|
199
|
+
pc.bold(`Slash #${slash.id}`),
|
|
200
|
+
statusIcon,
|
|
201
|
+
'',
|
|
202
|
+
`${pc.dim('Author Profile:')} ${slash.authorProfileId}`,
|
|
203
|
+
`${pc.dim('Subject:')} ${slash.subject || 'Unknown'}`,
|
|
204
|
+
`${pc.dim('Amount:')} ${slash.amount}`,
|
|
205
|
+
`${pc.dim('Type:')} ${slash.slashType}`,
|
|
206
|
+
'',
|
|
207
|
+
pc.dim('Reason:'),
|
|
208
|
+
slash.comment || 'No reason provided',
|
|
209
|
+
];
|
|
210
|
+
lines.push('', `${pc.dim('Created:')} ${new Date(slash.createdAt * 1000).toLocaleString()}`);
|
|
211
|
+
return lines.join('\n');
|
|
212
|
+
}
|
|
213
|
+
export function formatSlashes(slashes, total) {
|
|
214
|
+
if (!slashes.length) {
|
|
215
|
+
return pc.yellow('No slashes found.');
|
|
216
|
+
}
|
|
217
|
+
const lines = [pc.bold(`Slashes (${total} total)`), ''];
|
|
218
|
+
for (const s of slashes) {
|
|
219
|
+
const isOpen = !s.closedAt && !s.cancelledAt;
|
|
220
|
+
const statusIcon = isOpen ? pc.red('⚔️') : pc.gray('✓');
|
|
221
|
+
lines.push(`${statusIcon} ${pc.bold('#' + s.id)} Author: ${s.authorProfileId} → Subject: ${s.subject || 'Unknown'}`);
|
|
222
|
+
const commentPreview = s.comment ? (s.comment.slice(0, 40) + (s.comment.length > 40 ? '...' : '')) : 'No reason';
|
|
223
|
+
lines.push(` ${pc.dim('Amount:')} ${s.amount} ${pc.dim('|')} ${commentPreview}`);
|
|
224
|
+
lines.push('');
|
|
225
|
+
}
|
|
226
|
+
return lines.join('\n');
|
|
227
|
+
}
|
|
228
|
+
const REVIEW_SCORE_COLORS = {
|
|
229
|
+
positive: pc.green,
|
|
230
|
+
neutral: pc.yellow,
|
|
231
|
+
negative: pc.red,
|
|
232
|
+
};
|
|
233
|
+
const REVIEW_SCORE_ICONS = {
|
|
234
|
+
positive: '👍',
|
|
235
|
+
neutral: '😐',
|
|
236
|
+
negative: '👎',
|
|
237
|
+
};
|
|
238
|
+
export function formatReview(review) {
|
|
239
|
+
const score = review.data.score;
|
|
240
|
+
const scoreColor = REVIEW_SCORE_COLORS[score] || pc.white;
|
|
241
|
+
const scoreIcon = REVIEW_SCORE_ICONS[score] || '📝';
|
|
242
|
+
const authorName = review.author?.username ? `@${review.author.username}` : review.author?.name || `Profile #${review.data.authorProfileId}`;
|
|
243
|
+
const subjectName = review.subject?.username ? `@${review.subject.username}` : review.subject?.name || review.data.subject;
|
|
244
|
+
const lines = [
|
|
245
|
+
pc.bold(`${scoreIcon} Review #${review.data.id}`),
|
|
246
|
+
scoreColor(score.toUpperCase()),
|
|
247
|
+
'',
|
|
248
|
+
`${pc.dim('From:')} ${authorName}`,
|
|
249
|
+
`${pc.dim('To:')} ${subjectName}`,
|
|
250
|
+
`${pc.dim('Score:')} ${scoreColor(score)}`,
|
|
251
|
+
];
|
|
252
|
+
if (review.data.comment) {
|
|
253
|
+
lines.push('', pc.dim('Comment:'), review.data.comment);
|
|
254
|
+
}
|
|
255
|
+
lines.push('');
|
|
256
|
+
lines.push(`${pc.dim('Votes:')} 👍 ${review.votes?.upvotes || 0} 👎 ${review.votes?.downvotes || 0}`);
|
|
257
|
+
if (review.replySummary?.count > 0) {
|
|
258
|
+
lines.push(`${pc.dim('Replies:')} ${review.replySummary.count}`);
|
|
259
|
+
}
|
|
260
|
+
lines.push(`${pc.dim('Created:')} ${new Date(review.data.createdAt * 1000).toLocaleString()}`);
|
|
261
|
+
if (review.link) {
|
|
262
|
+
lines.push('', `${pc.dim('Link:')} ${review.link}`);
|
|
263
|
+
}
|
|
264
|
+
return lines.join('\n');
|
|
265
|
+
}
|
|
266
|
+
export function formatReviews(activities, total) {
|
|
267
|
+
const reviews = activities.filter(a => a.type === 'review');
|
|
268
|
+
if (!reviews.length) {
|
|
269
|
+
return pc.yellow('No reviews found.');
|
|
270
|
+
}
|
|
271
|
+
const lines = [pc.bold(`Reviews${total !== undefined ? ` (${total} total)` : ''}`), ''];
|
|
272
|
+
for (const r of reviews) {
|
|
273
|
+
const score = r.data.score || 'neutral';
|
|
274
|
+
const scoreColor = REVIEW_SCORE_COLORS[score] || pc.white;
|
|
275
|
+
const scoreIcon = REVIEW_SCORE_ICONS[score] || '📝';
|
|
276
|
+
const authorName = r.author?.username ? `@${r.author.username}` : r.author?.name || 'Unknown';
|
|
277
|
+
const subjectName = r.subject?.username ? `@${r.subject.username}` : r.subject?.name || 'Unknown';
|
|
278
|
+
const date = new Date(r.timestamp * 1000).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
279
|
+
lines.push(`${scoreIcon} ${pc.bold('#' + r.data.id)} ${authorName} → ${subjectName} ${scoreColor(`[${score.toUpperCase()}]`)}`);
|
|
280
|
+
if (r.data.comment) {
|
|
281
|
+
const preview = r.data.comment.slice(0, 60) + (r.data.comment.length > 60 ? '...' : '');
|
|
282
|
+
lines.push(` ${pc.dim(preview)}`);
|
|
283
|
+
}
|
|
284
|
+
lines.push(` ${pc.dim(date)}`);
|
|
285
|
+
lines.push('');
|
|
286
|
+
}
|
|
287
|
+
return lines.join('\n');
|
|
288
|
+
}
|
|
289
|
+
const BROKER_TYPE_EMOJI = {
|
|
290
|
+
'SELL': '🏷️',
|
|
291
|
+
'BUY': '🛒',
|
|
292
|
+
'HIRE': '👔',
|
|
293
|
+
'FOR_HIRE': '🧑💻',
|
|
294
|
+
'BOUNTY': '🎯',
|
|
295
|
+
};
|
|
296
|
+
const BROKER_STATUS_COLOR = {
|
|
297
|
+
'OPEN': pc.green,
|
|
298
|
+
'COMPLETED': pc.blue,
|
|
299
|
+
'CLOSED': pc.gray,
|
|
300
|
+
'EXPIRED': pc.red,
|
|
301
|
+
};
|
|
302
|
+
export function formatBrokerPost(post) {
|
|
303
|
+
const typeEmoji = BROKER_TYPE_EMOJI[post.type] || '📝';
|
|
304
|
+
const statusColor = BROKER_STATUS_COLOR[post.status] || pc.white;
|
|
305
|
+
const lines = [
|
|
306
|
+
pc.bold(`${typeEmoji} ${post.title}`),
|
|
307
|
+
'',
|
|
308
|
+
`${pc.dim('Type:')} ${post.type} ${post.level === 'PREMIUM' ? pc.yellow('⭐ PREMIUM') : ''}`,
|
|
309
|
+
`${pc.dim('Status:')} ${statusColor(post.status)}`,
|
|
310
|
+
`${pc.dim('Author:')} ${post.author?.username ? '@' + post.author.username : post.author?.displayName || 'Unknown'} (Score: ${post.author?.score || 0})`,
|
|
311
|
+
'',
|
|
312
|
+
pc.dim('Description:'),
|
|
313
|
+
post.description?.slice(0, 300) + (post.description?.length > 300 ? '...' : ''),
|
|
314
|
+
'',
|
|
315
|
+
`${pc.dim('Votes:')} 👍 ${post.votes?.upvotes || 0} 👎 ${post.votes?.downvotes || 0} 💬 ${post.replyCount || 0} replies`,
|
|
316
|
+
];
|
|
317
|
+
if (post.tags?.length) {
|
|
318
|
+
lines.push(`${pc.dim('Tags:')} ${post.tags.map((t) => pc.cyan('#' + t)).join(' ')}`);
|
|
319
|
+
}
|
|
320
|
+
if (post.expiresAt) {
|
|
321
|
+
lines.push(`${pc.dim('Expires:')} ${new Date(post.expiresAt).toLocaleDateString()}`);
|
|
322
|
+
}
|
|
323
|
+
return lines.join('\n');
|
|
324
|
+
}
|
|
325
|
+
export function formatBrokerPosts(posts, total) {
|
|
326
|
+
if (!posts.length) {
|
|
327
|
+
return pc.yellow('No broker posts found.');
|
|
328
|
+
}
|
|
329
|
+
const lines = [
|
|
330
|
+
pc.bold(`Broker Posts (${total} total)`),
|
|
331
|
+
'',
|
|
332
|
+
];
|
|
333
|
+
for (const post of posts) {
|
|
334
|
+
const typeEmoji = BROKER_TYPE_EMOJI[post.type] || '📝';
|
|
335
|
+
const status = post.status === 'OPEN' ? pc.green('●') : pc.gray('○');
|
|
336
|
+
lines.push(`${status} ${typeEmoji} ${pc.bold('#' + post.id)} ${post.title.slice(0, 50)}${post.title.length > 50 ? '...' : ''}`);
|
|
337
|
+
lines.push(` ${pc.dim('by')} ${post.author?.username ? '@' + post.author.username : 'Unknown'} ${pc.dim('|')} 👍 ${post.votes?.upvotes || 0} ${pc.dim('|')} 💬 ${post.replyCount || 0}`);
|
|
338
|
+
lines.push('');
|
|
339
|
+
}
|
|
340
|
+
return lines.join('\n');
|
|
341
|
+
}
|
|
342
|
+
export function formatListing(project) {
|
|
343
|
+
const name = project.user?.displayName || 'Unknown';
|
|
344
|
+
const username = project.user?.username;
|
|
345
|
+
const lines = [
|
|
346
|
+
pc.bold(pc.cyan(name)),
|
|
347
|
+
username ? pc.dim(`@${username}`) : '',
|
|
348
|
+
'',
|
|
349
|
+
`${pc.dim('Status:')} ${project.status === 'ACTIVE' ? pc.green('ACTIVE') : pc.yellow(project.status)}`,
|
|
350
|
+
`${pc.dim('Score:')} ${pc.green(String(project.user?.score || 0))}`,
|
|
351
|
+
];
|
|
352
|
+
if (project.description) {
|
|
353
|
+
lines.push('', pc.dim('Description:'), project.description.slice(0, 300) + (project.description.length > 300 ? '...' : ''));
|
|
354
|
+
}
|
|
355
|
+
if (project.votes) {
|
|
356
|
+
lines.push('', pc.bold('Votes'), ` ${pc.green('Bullish:')} ${project.votes.bullish?.total || 0} (${project.votes.bullish?.percentage || 0}%)`, ` ${pc.red('Bearish:')} ${project.votes.bearish?.total || 0} (${project.votes.bearish?.percentage || 0}%)`, ` ${pc.dim('Total:')} ${project.votes.all?.totalVotes || 0} votes from ${project.votes.all?.totalVoters || 0} voters`);
|
|
357
|
+
}
|
|
358
|
+
if (project.categories?.length) {
|
|
359
|
+
lines.push(`${pc.dim('Categories:')} ${project.categories.join(', ')}`);
|
|
360
|
+
}
|
|
361
|
+
if (project.chains?.length) {
|
|
362
|
+
lines.push(`${pc.dim('Chains:')} ${project.chains.map((c) => c.name).join(', ')}`);
|
|
363
|
+
}
|
|
364
|
+
if (project.user?.links?.profile) {
|
|
365
|
+
lines.push(`${pc.dim('Profile:')} ${project.user.links.profile}`);
|
|
366
|
+
}
|
|
367
|
+
return lines.filter(Boolean).join('\n');
|
|
368
|
+
}
|
|
369
|
+
export function formatListings(projects, total) {
|
|
370
|
+
if (!projects.length) {
|
|
371
|
+
return pc.yellow('No listings found.');
|
|
372
|
+
}
|
|
373
|
+
const lines = [pc.bold(`Listings (${total} total)`), ''];
|
|
374
|
+
for (const p of projects) {
|
|
375
|
+
const name = p.user?.displayName || 'Unknown';
|
|
376
|
+
const username = p.user?.username || 'unknown';
|
|
377
|
+
const score = p.user?.score || 0;
|
|
378
|
+
const bullish = p.votes?.bullish?.percentage || 0;
|
|
379
|
+
const sentiment = bullish >= 60 ? pc.green('>>') : bullish <= 40 ? pc.red('<<') : pc.yellow('==');
|
|
380
|
+
lines.push(`${sentiment} ${pc.bold(name)} ${pc.dim('@' + username)} (Score: ${score})`);
|
|
381
|
+
if (p.votes) {
|
|
382
|
+
lines.push(` ${pc.green(bullish + '% bullish')} | ${p.votes.all?.totalVoters || 0} voters`);
|
|
383
|
+
}
|
|
384
|
+
lines.push('');
|
|
385
|
+
}
|
|
386
|
+
return lines.join('\n');
|
|
387
|
+
}
|
|
388
|
+
export function formatListingVoters(voters, totals) {
|
|
389
|
+
if (!voters.length) {
|
|
390
|
+
return pc.yellow('No voters found.');
|
|
391
|
+
}
|
|
392
|
+
const lines = [
|
|
393
|
+
pc.bold(`Project Voters (${totals.totalVoters} total)`),
|
|
394
|
+
`${pc.green('Bullish Voters:')} ${totals.totalBullishVoters} (${totals.totalBullishVotes} votes)`,
|
|
395
|
+
`${pc.red('Bearish Voters:')} ${totals.totalBearishVoters} (${totals.totalBearishVotes} votes)`,
|
|
396
|
+
'',
|
|
397
|
+
];
|
|
398
|
+
for (const v of voters) {
|
|
399
|
+
const name = v.user?.username ? `@${v.user.username}` : v.user?.displayName || 'Unknown';
|
|
400
|
+
const sentiment = v.bullishCount > v.bearishCount ? pc.green('>>') : pc.red('<<');
|
|
401
|
+
lines.push(`${sentiment} ${pc.bold(name)} (Score: ${v.user?.score || 0})`);
|
|
402
|
+
lines.push(` Bullish: ${v.bullishCount} | Bearish: ${v.bearishCount} | Total: ${v.totalVotes}`);
|
|
403
|
+
const reasons = [...(v.bullishReasons || []), ...(v.bearishReasons || [])];
|
|
404
|
+
if (reasons.length) {
|
|
405
|
+
lines.push(` ${pc.dim('Reasons:')} ${reasons.slice(0, 3).join(', ')}`);
|
|
406
|
+
}
|
|
407
|
+
lines.push('');
|
|
408
|
+
}
|
|
409
|
+
return lines.join('\n');
|
|
410
|
+
}
|
|
411
|
+
export function formatNfts(nfts, total) {
|
|
412
|
+
if (!nfts.length) {
|
|
413
|
+
return pc.yellow('No NFTs found.');
|
|
414
|
+
}
|
|
415
|
+
const lines = [pc.bold(`NFTs (${total} total)`), ''];
|
|
416
|
+
for (const nft of nfts) {
|
|
417
|
+
lines.push(`🖼️ ${pc.bold(nft.name || `Token #${nft.tokenId}`)}`);
|
|
418
|
+
if (nft.contractName)
|
|
419
|
+
lines.push(` ${pc.dim('Collection:')} ${nft.contractName}`);
|
|
420
|
+
lines.push(` ${pc.dim('Token ID:')} ${nft.tokenId}`);
|
|
421
|
+
lines.push('');
|
|
422
|
+
}
|
|
423
|
+
return lines.join('\n');
|
|
424
|
+
}
|
|
425
|
+
export function formatValidatorListings(listings, total) {
|
|
426
|
+
if (!listings.length) {
|
|
427
|
+
return pc.yellow('No validator NFTs listed for sale.');
|
|
428
|
+
}
|
|
429
|
+
const lines = [pc.bold(`🎫 Validator NFTs For Sale (${total} total)`), ''];
|
|
430
|
+
for (const l of listings) {
|
|
431
|
+
lines.push(`🎫 ${pc.bold(l.name || `Validator #${l.tokenId}`)}`);
|
|
432
|
+
lines.push(` ${pc.dim('Price:')} ${pc.green(l.priceEth + ' ETH')}`);
|
|
433
|
+
lines.push(` ${pc.dim('Seller:')} ${l.seller.slice(0, 10)}...`);
|
|
434
|
+
lines.push(` ${pc.dim('OpenSea:')} ${l.openseaUrl}`);
|
|
435
|
+
lines.push('');
|
|
436
|
+
}
|
|
437
|
+
return lines.join('\n');
|
|
438
|
+
}
|
|
439
|
+
export function formatAuction(auction) {
|
|
440
|
+
const statusColors = {
|
|
441
|
+
'PENDING': pc.yellow,
|
|
442
|
+
'ENABLED': pc.green,
|
|
443
|
+
'ENDED': pc.gray,
|
|
444
|
+
'SOLD': pc.blue,
|
|
445
|
+
};
|
|
446
|
+
const statusFn = statusColors[auction.status] || pc.white;
|
|
447
|
+
const reserveEth = formatWeiToEth(auction.reservePrice);
|
|
448
|
+
const startEth = formatWeiToEth(auction.startPrice);
|
|
449
|
+
const lines = [
|
|
450
|
+
pc.bold(`🔨 Auction #${auction.id}`),
|
|
451
|
+
`Validator #${auction.nftTokenId}`,
|
|
452
|
+
'',
|
|
453
|
+
`${pc.dim('Status:')} ${statusFn(auction.status)}`,
|
|
454
|
+
`${pc.dim('Token ID:')} ${auction.nftTokenId}`,
|
|
455
|
+
`${pc.dim('Start Price:')} ${startEth} ETH`,
|
|
456
|
+
`${pc.dim('Reserve Price:')} ${reserveEth} ETH`,
|
|
457
|
+
];
|
|
458
|
+
if (auction.pricePaid) {
|
|
459
|
+
lines.push(`${pc.dim('Sold For:')} ${pc.green(formatWeiToEth(auction.pricePaid) + ' ETH')}`);
|
|
460
|
+
}
|
|
461
|
+
const startTime = new Date(auction.startTime);
|
|
462
|
+
lines.push(`${pc.dim('Starts:')} ${startTime.toLocaleString()}`);
|
|
463
|
+
if (auction.buyerAddress) {
|
|
464
|
+
const buyerName = auction.buyerUser?.username
|
|
465
|
+
? `@${auction.buyerUser.username}`
|
|
466
|
+
: auction.buyerUser?.displayName || `${auction.buyerAddress.slice(0, 10)}...`;
|
|
467
|
+
lines.push('', pc.green(`🏆 Winner: ${buyerName}`));
|
|
468
|
+
}
|
|
469
|
+
return lines.filter(Boolean).join('\n');
|
|
470
|
+
}
|
|
471
|
+
export function formatAuctions(auctions, total) {
|
|
472
|
+
if (!auctions.length) {
|
|
473
|
+
return pc.yellow('No auctions found.');
|
|
474
|
+
}
|
|
475
|
+
const lines = [pc.bold(`🎫 Validator Auctions (${total} total)`), ''];
|
|
476
|
+
for (const a of auctions) {
|
|
477
|
+
const statusColor = a.status === 'ENABLED' ? pc.green : a.status === 'SOLD' ? pc.blue : pc.yellow;
|
|
478
|
+
const startEth = formatWeiToEth(a.startPrice);
|
|
479
|
+
lines.push(`🎫 ${pc.bold(`Validator #${a.nftTokenId}`)} ${statusColor(`[${a.status}]`)}`);
|
|
480
|
+
lines.push(` ${pc.dim('Start Price:')} ${startEth} ETH`);
|
|
481
|
+
if (a.pricePaid) {
|
|
482
|
+
lines.push(` ${pc.dim('Sold For:')} ${pc.green(formatWeiToEth(a.pricePaid) + ' ETH')}`);
|
|
483
|
+
}
|
|
484
|
+
if (a.buyerAddress) {
|
|
485
|
+
const buyerName = a.buyerUser?.username
|
|
486
|
+
? `@${a.buyerUser.username}`
|
|
487
|
+
: a.buyerUser?.displayName || `${a.buyerAddress.slice(0, 10)}...`;
|
|
488
|
+
lines.push(` ${pc.dim('Buyer:')} ${buyerName}`);
|
|
489
|
+
}
|
|
490
|
+
lines.push(` ${pc.dim('Starts:')} ${new Date(a.startTime).toLocaleDateString()}`);
|
|
491
|
+
lines.push('');
|
|
492
|
+
}
|
|
493
|
+
return lines.join('\n');
|
|
494
|
+
}
|
|
495
|
+
function formatWeiToEth(wei) {
|
|
496
|
+
const eth = Number(BigInt(wei)) / 1e18;
|
|
497
|
+
if (eth >= 1)
|
|
498
|
+
return eth.toFixed(4);
|
|
499
|
+
if (eth >= 0.001)
|
|
500
|
+
return eth.toFixed(6);
|
|
501
|
+
return eth.toExponential(4);
|
|
502
|
+
}
|
|
503
|
+
export function formatMarket(market) {
|
|
504
|
+
const name = market.user?.displayName || market.user?.username || 'Unknown';
|
|
505
|
+
const priceChange = market.stats?.priceChange24hPercent || 0;
|
|
506
|
+
const priceChangeColor = priceChange >= 0 ? pc.green : pc.red;
|
|
507
|
+
const positivePrice = formatWeiToEth(market.positivePrice);
|
|
508
|
+
const marketCap = formatWeiToEth(market.stats?.marketCapWei || '0');
|
|
509
|
+
const totalHolders = market.trustVotes + market.distrustVotes;
|
|
510
|
+
const lines = [
|
|
511
|
+
pc.bold(pc.cyan(name)),
|
|
512
|
+
market.user?.username ? pc.dim(`@${market.user.username}`) : '',
|
|
513
|
+
'',
|
|
514
|
+
`${pc.dim('Trust Price:')} ${positivePrice} ETH ${priceChangeColor(`(${priceChange >= 0 ? '+' : ''}${priceChange.toFixed(1)}%)`)}`,
|
|
515
|
+
`${pc.dim('Market Cap:')} ${marketCap} ETH`,
|
|
516
|
+
`${pc.dim('Score:')} ${pc.green(String(market.user?.score || 0))}`,
|
|
517
|
+
`${pc.dim('Trust/Distrust:')} ${pc.green(String(market.trustVotes))} / ${pc.red(String(market.distrustVotes))}`,
|
|
518
|
+
];
|
|
519
|
+
if (market.stats?.volume24hWei) {
|
|
520
|
+
lines.push(`${pc.dim('24h Volume:')} ${formatWeiToEth(market.stats.volume24hWei)} ETH`);
|
|
521
|
+
}
|
|
522
|
+
if (market.stats?.marketCapChange24hPercent !== undefined) {
|
|
523
|
+
const mcChange = market.stats.marketCapChange24hPercent;
|
|
524
|
+
const mcChangeColor = mcChange >= 0 ? pc.green : pc.red;
|
|
525
|
+
lines.push(`${pc.dim('Market Cap 24h:')} ${mcChangeColor(`${mcChange >= 0 ? '+' : ''}${mcChange.toFixed(1)}%`)}`);
|
|
526
|
+
}
|
|
527
|
+
return lines.filter(Boolean).join('\n');
|
|
528
|
+
}
|
|
529
|
+
export function formatMarkets(markets, total) {
|
|
530
|
+
if (!markets.length) {
|
|
531
|
+
return pc.yellow('No markets found.');
|
|
532
|
+
}
|
|
533
|
+
const lines = [pc.bold(`Trust Markets (${total} total)`), ''];
|
|
534
|
+
for (const m of markets) {
|
|
535
|
+
const name = m.user?.displayName || m.user?.username || 'Unknown';
|
|
536
|
+
const priceChange = m.stats?.priceChange24hPercent || 0;
|
|
537
|
+
const priceChangeColor = priceChange >= 0 ? pc.green : pc.red;
|
|
538
|
+
const marketCap = formatWeiToEth(m.stats?.marketCapWei || '0');
|
|
539
|
+
const totalHolders = m.trustVotes + m.distrustVotes;
|
|
540
|
+
lines.push(`${pc.bold(name)} ${m.user?.username ? pc.dim('@' + m.user.username) : ''}`);
|
|
541
|
+
lines.push(` Cap: ${marketCap} ETH | ${priceChangeColor(`${priceChange >= 0 ? '+' : ''}${priceChange.toFixed(1)}%`)} | Score: ${m.user?.score || 0}`);
|
|
542
|
+
lines.push(` Trust: ${pc.green(String(m.trustVotes))} | Distrust: ${pc.red(String(m.distrustVotes))}`);
|
|
543
|
+
lines.push('');
|
|
544
|
+
}
|
|
545
|
+
return lines.join('\n');
|
|
546
|
+
}
|
|
547
|
+
export function formatMarketHolders(holders, total) {
|
|
548
|
+
if (!holders.length) {
|
|
549
|
+
return pc.yellow('No holders found.');
|
|
550
|
+
}
|
|
551
|
+
const lines = [pc.bold(`Market Holders (${total} total)`), ''];
|
|
552
|
+
for (const h of holders) {
|
|
553
|
+
const name = h.user?.displayName || h.user?.username || 'Unknown';
|
|
554
|
+
const voteColor = h.voteType === 'trust' ? pc.green : pc.red;
|
|
555
|
+
const voteIcon = h.voteType === 'trust' ? '📈' : '📉';
|
|
556
|
+
lines.push(`${voteIcon} ${pc.bold(name)} ${h.user?.username ? pc.dim('@' + h.user.username) : ''}`);
|
|
557
|
+
lines.push(` ${voteColor(h.voteType.toUpperCase())}: ${h.total} votes`);
|
|
558
|
+
lines.push(` Score: ${h.user?.score || 0}`);
|
|
559
|
+
lines.push('');
|
|
560
|
+
}
|
|
561
|
+
return lines.join('\n');
|
|
562
|
+
}
|
|
563
|
+
export function formatFeaturedMarkets(response) {
|
|
564
|
+
if (!response.length) {
|
|
565
|
+
return pc.yellow('No featured markets found.');
|
|
566
|
+
}
|
|
567
|
+
const lines = [pc.bold(pc.cyan('Featured Markets')), ''];
|
|
568
|
+
const typeLabels = {
|
|
569
|
+
'top-volume': { label: 'Top Volume', icon: '📈', color: pc.green },
|
|
570
|
+
'undervalued': { label: 'Undervalued', icon: '💎', color: pc.blue },
|
|
571
|
+
'rugging': { label: 'Rugging', icon: '⚠️', color: pc.red },
|
|
572
|
+
};
|
|
573
|
+
for (const featured of response) {
|
|
574
|
+
const m = featured.market;
|
|
575
|
+
const typeInfo = typeLabels[featured.type] || { label: featured.type, icon: '📊', color: pc.white };
|
|
576
|
+
const name = m.user?.displayName || m.user?.username || 'Unknown';
|
|
577
|
+
const priceChange = m.stats?.priceChange24hPercent || 0;
|
|
578
|
+
const marketCap = formatWeiToEth(m.stats?.marketCapWei || '0');
|
|
579
|
+
const mcChange = m.stats?.marketCapChange24hPercent || 0;
|
|
580
|
+
lines.push(`${typeInfo.icon} ${typeInfo.color(pc.bold(typeInfo.label))}`);
|
|
581
|
+
lines.push(` ${pc.bold(name)} ${m.user?.username ? pc.dim('@' + m.user.username) : ''}`);
|
|
582
|
+
lines.push(` Cap: ${marketCap} ETH (${mcChange >= 0 ? pc.green(`+${mcChange}%`) : pc.red(`${mcChange}%`)})`);
|
|
583
|
+
lines.push(` Score: ${m.user?.score || 0} | Price: ${priceChange >= 0 ? '+' : ''}${priceChange.toFixed(1)}%`);
|
|
584
|
+
lines.push('');
|
|
585
|
+
}
|
|
586
|
+
return lines.join('\n');
|
|
587
|
+
}
|
|
588
|
+
const LEVEL_COLORS = {
|
|
589
|
+
untrusted: pc.red,
|
|
590
|
+
questionable: pc.yellow,
|
|
591
|
+
neutral: pc.white,
|
|
592
|
+
reputable: pc.green,
|
|
593
|
+
exemplary: pc.cyan,
|
|
594
|
+
};
|
|
595
|
+
export function formatScore(data) {
|
|
596
|
+
const levelColor = LEVEL_COLORS[data.level] || pc.white;
|
|
597
|
+
const lines = [
|
|
598
|
+
pc.bold(pc.cyan('Reputation Score')),
|
|
599
|
+
'',
|
|
600
|
+
`${pc.dim('Score:')} ${pc.green(String(data.score))}`,
|
|
601
|
+
`${pc.dim('Level:')} ${levelColor(data.level.toUpperCase())}`,
|
|
602
|
+
];
|
|
603
|
+
if (data.identifier) {
|
|
604
|
+
lines.push(`${pc.dim('User:')} ${data.identifier}`);
|
|
605
|
+
}
|
|
606
|
+
return lines.join('\n');
|
|
607
|
+
}
|
|
608
|
+
export function formatScoreStatus(data) {
|
|
609
|
+
const statusColor = data.status === 'idle' ? pc.green : data.status === 'calculating' ? pc.yellow : pc.blue;
|
|
610
|
+
const lines = [
|
|
611
|
+
pc.bold(pc.cyan('Score Calculation Status')),
|
|
612
|
+
'',
|
|
613
|
+
`${pc.dim('Status:')} ${statusColor(data.status.toUpperCase())}`,
|
|
614
|
+
];
|
|
615
|
+
if (data.isPending) {
|
|
616
|
+
lines.push(`${pc.dim('Pending:')} ${pc.yellow('Yes')} (${data.isCalculating ? 'calculating' : 'queued'})`);
|
|
617
|
+
}
|
|
618
|
+
if (data.identifier) {
|
|
619
|
+
lines.push(`${pc.dim('User:')} ${data.identifier}`);
|
|
620
|
+
}
|
|
621
|
+
return lines.join('\n');
|
|
622
|
+
}
|
|
623
|
+
function formatVouchAmount(wei) {
|
|
624
|
+
const cleanWei = wei.replace(/n$/, '');
|
|
625
|
+
const eth = Number(BigInt(cleanWei)) / 1e18;
|
|
626
|
+
if (eth >= 1)
|
|
627
|
+
return eth.toFixed(4) + ' ETH';
|
|
628
|
+
if (eth >= 0.001)
|
|
629
|
+
return eth.toFixed(6) + ' ETH';
|
|
630
|
+
if (eth > 0)
|
|
631
|
+
return eth.toExponential(2) + ' ETH';
|
|
632
|
+
return '0 ETH';
|
|
633
|
+
}
|
|
634
|
+
export function formatVouch(vouch) {
|
|
635
|
+
const authorName = vouch.authorUser?.username ? `@${vouch.authorUser.username}` : vouch.authorUser?.displayName || `Profile #${vouch.authorProfileId}`;
|
|
636
|
+
const subjectName = vouch.subjectUser?.username ? `@${vouch.subjectUser.username}` : vouch.subjectUser?.displayName || `Profile #${vouch.subjectProfileId}`;
|
|
637
|
+
const statusIcon = vouch.archived ? pc.gray('○ Archived') : vouch.unhealthy ? pc.yellow('⚠ Unhealthy') : pc.green('● Active');
|
|
638
|
+
const lines = [
|
|
639
|
+
pc.bold(`Vouch #${vouch.id}`),
|
|
640
|
+
statusIcon,
|
|
641
|
+
'',
|
|
642
|
+
`${pc.dim('From:')} ${authorName}`,
|
|
643
|
+
`${pc.dim('To:')} ${subjectName}`,
|
|
644
|
+
`${pc.dim('Amount:')} ${pc.green(formatVouchAmount(vouch.balance))}`,
|
|
645
|
+
];
|
|
646
|
+
if (vouch.mutualId) {
|
|
647
|
+
lines.push(`${pc.dim('Mutual:')} Yes (Vouch #${vouch.mutualId})`);
|
|
648
|
+
}
|
|
649
|
+
if (vouch.comment) {
|
|
650
|
+
lines.push('', pc.dim('Comment:'), vouch.comment.slice(0, 200) + (vouch.comment.length > 200 ? '...' : ''));
|
|
651
|
+
}
|
|
652
|
+
const vouchedAt = new Date(vouch.activityCheckpoints.vouchedAt * 1000);
|
|
653
|
+
lines.push('', `${pc.dim('Vouched:')} ${vouchedAt.toLocaleDateString()}`);
|
|
654
|
+
return lines.join('\n');
|
|
655
|
+
}
|
|
656
|
+
export function formatVouches(vouches, total) {
|
|
657
|
+
if (!vouches.length) {
|
|
658
|
+
return pc.yellow('No vouches found.');
|
|
659
|
+
}
|
|
660
|
+
const lines = [pc.bold(`Vouches (${total} total)`), ''];
|
|
661
|
+
for (const v of vouches) {
|
|
662
|
+
const authorName = v.authorUser?.username ? `@${v.authorUser.username}` : v.authorUser?.displayName || `Profile #${v.authorProfileId}`;
|
|
663
|
+
const subjectName = v.subjectUser?.username ? `@${v.subjectUser.username}` : v.subjectUser?.displayName || `Profile #${v.subjectProfileId}`;
|
|
664
|
+
const statusIcon = v.archived ? pc.gray('○') : v.unhealthy ? pc.yellow('⚠') : pc.green('●');
|
|
665
|
+
const mutualTag = v.mutualId ? pc.cyan(' [MUTUAL]') : '';
|
|
666
|
+
lines.push(`${statusIcon} ${pc.bold('#' + v.id)} ${authorName} → ${subjectName}${mutualTag}`);
|
|
667
|
+
lines.push(` ${pc.dim('Amount:')} ${formatVouchAmount(v.balance)}`);
|
|
668
|
+
if (v.comment) {
|
|
669
|
+
const preview = v.comment.slice(0, 50) + (v.comment.length > 50 ? '...' : '');
|
|
670
|
+
lines.push(` ${pc.dim(preview)}`);
|
|
671
|
+
}
|
|
672
|
+
lines.push('');
|
|
673
|
+
}
|
|
674
|
+
return lines.join('\n');
|
|
675
|
+
}
|
|
676
|
+
export function formatMutualVouchers(users, total) {
|
|
677
|
+
if (!users.length) {
|
|
678
|
+
return pc.yellow('No mutual vouchers found.');
|
|
679
|
+
}
|
|
680
|
+
const lines = [pc.bold(`Mutual Vouchers (${total} total)`), ''];
|
|
681
|
+
for (const u of users) {
|
|
682
|
+
const name = u.username ? `@${u.username}` : u.displayName || 'Unknown';
|
|
683
|
+
lines.push(`🤝 ${pc.bold(name)}`);
|
|
684
|
+
if (u.score !== undefined) {
|
|
685
|
+
lines.push(` ${pc.dim('Score:')} ${u.score}`);
|
|
686
|
+
}
|
|
687
|
+
lines.push('');
|
|
688
|
+
}
|
|
689
|
+
return lines.join('\n');
|
|
690
|
+
}
|
|
691
|
+
export function formatVotes(votes, total, activityType) {
|
|
692
|
+
if (!votes.length) {
|
|
693
|
+
return pc.yellow('No votes found.');
|
|
694
|
+
}
|
|
695
|
+
const lines = [pc.bold(`Votes${activityType ? ` on ${activityType}` : ''} (${total} total)`), ''];
|
|
696
|
+
for (const v of votes) {
|
|
697
|
+
const voteIcon = v.isUpvote ? pc.green('👍') : pc.red('👎');
|
|
698
|
+
const voterName = v.user.username ? `@${v.user.username}` : v.user.displayName || `Profile #${v.user.profileId}`;
|
|
699
|
+
lines.push(`${voteIcon} ${pc.bold(voterName)} (Score: ${v.user.score})`);
|
|
700
|
+
lines.push(` ${pc.dim('Voted:')} ${new Date(v.createdAt * 1000).toLocaleDateString()}`);
|
|
701
|
+
lines.push('');
|
|
702
|
+
}
|
|
703
|
+
return lines.join('\n');
|
|
704
|
+
}
|
|
705
|
+
export function formatVoteStats(stats, activityType, activityId) {
|
|
706
|
+
const { upvotes, downvotes } = stats.counts;
|
|
707
|
+
const total = upvotes + downvotes;
|
|
708
|
+
const lines = [
|
|
709
|
+
pc.bold(pc.cyan(`Vote Stats${activityId ? ` for ${activityType || 'Activity'} #${activityId}` : ''}`)),
|
|
710
|
+
'',
|
|
711
|
+
`${pc.green('👍 Upvotes:')} ${upvotes}`,
|
|
712
|
+
`${pc.red('👎 Downvotes:')} ${downvotes}`,
|
|
713
|
+
`${pc.dim('Total:')} ${total}`,
|
|
714
|
+
`${pc.dim('Approval:')} ${stats.weights.upvotePercentage}%`,
|
|
715
|
+
];
|
|
716
|
+
return lines.join('\n');
|
|
717
|
+
}
|
|
718
|
+
export function formatValidator(validator) {
|
|
719
|
+
const ownerName = validator.ownerUsername ? `@${validator.ownerUsername}` : validator.ownerDisplayName || `Profile #${validator.ownerProfileId}`;
|
|
720
|
+
const capacityPercent = Math.round((validator.currentXp / validator.xpCap) * 100);
|
|
721
|
+
const capacityColor = validator.isFull ? pc.red : capacityPercent > 80 ? pc.yellow : pc.green;
|
|
722
|
+
const lines = [
|
|
723
|
+
pc.bold(pc.cyan(`🎫 ${validator.name}`)),
|
|
724
|
+
'',
|
|
725
|
+
`${pc.dim('Token ID:')} ${validator.tokenId}`,
|
|
726
|
+
`${pc.dim('Owner:')} ${ownerName}`,
|
|
727
|
+
`${pc.dim('Owner Address:')} ${validator.ownerAddress.slice(0, 10)}...${validator.ownerAddress.slice(-8)}`,
|
|
728
|
+
'',
|
|
729
|
+
pc.bold('Delegated XP'),
|
|
730
|
+
`${pc.dim('Current:')} ${validator.currentXp.toLocaleString()}`,
|
|
731
|
+
`${pc.dim('Cap:')} ${validator.xpCap.toLocaleString()}`,
|
|
732
|
+
`${pc.dim('Remaining:')} ${capacityColor(validator.remainingCapacity.toLocaleString())}`,
|
|
733
|
+
`${pc.dim('Usage:')} ${capacityColor(`${capacityPercent}%`)}${validator.isFull ? pc.red(' (FULL)') : ''}`,
|
|
734
|
+
];
|
|
735
|
+
return lines.join('\n');
|
|
736
|
+
}
|
|
737
|
+
export function formatValidators(validators, total) {
|
|
738
|
+
if (!validators.length) {
|
|
739
|
+
return pc.yellow('No validators found.');
|
|
740
|
+
}
|
|
741
|
+
const lines = [pc.bold(`🎫 Validators (${total} total)`), ''];
|
|
742
|
+
for (const v of validators) {
|
|
743
|
+
const ownerName = v.ownerUsername ? `@${v.ownerUsername}` : v.ownerDisplayName || 'Unknown';
|
|
744
|
+
const capacityPercent = Math.round((v.currentXp / v.xpCap) * 100);
|
|
745
|
+
const capacityColor = v.isFull ? pc.red : capacityPercent > 80 ? pc.yellow : pc.green;
|
|
746
|
+
const fullTag = v.isFull ? pc.red(' [FULL]') : '';
|
|
747
|
+
lines.push(`🎫 ${pc.bold(v.name)} (Token #${v.tokenId})${fullTag}`);
|
|
748
|
+
lines.push(` ${pc.dim('Owner:')} ${ownerName}`);
|
|
749
|
+
lines.push(` ${pc.dim('Delegated:')} ${v.currentXp.toLocaleString()} / ${v.xpCap.toLocaleString()} ${capacityColor(`(${capacityPercent}%)`)}`);
|
|
750
|
+
lines.push('');
|
|
751
|
+
}
|
|
752
|
+
return lines.join('\n');
|
|
753
|
+
}
|