@developoor420/aiq-cli 1.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/PUBLISH.md +45 -0
- package/README.md +98 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1107 -0
- package/package.json +49 -0
- package/src/index.ts +1260 -0
- package/tsconfig.json +16 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1107 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const conf_1 = __importDefault(require("conf"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const ora_1 = __importDefault(require("ora"));
|
|
11
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
12
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
13
|
+
const config = new conf_1.default({ projectName: 'aiq' });
|
|
14
|
+
const DEFAULT_API = 'https://aiq-production.up.railway.app';
|
|
15
|
+
// ============ Helpers ============
|
|
16
|
+
function getApiUrl() {
|
|
17
|
+
// Allow override via env var for testing
|
|
18
|
+
return process.env.AIQ_API || config.get('apiUrl') || DEFAULT_API;
|
|
19
|
+
}
|
|
20
|
+
function getApiKey() {
|
|
21
|
+
return config.get('apiKey') || null;
|
|
22
|
+
}
|
|
23
|
+
function isConfigured() {
|
|
24
|
+
return !!getApiKey();
|
|
25
|
+
}
|
|
26
|
+
async function apiRequest(endpoint, options = {}) {
|
|
27
|
+
const apiUrl = getApiUrl();
|
|
28
|
+
const apiKey = getApiKey();
|
|
29
|
+
const headers = {
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
...(options.headers || {}),
|
|
32
|
+
};
|
|
33
|
+
if (apiKey && !headers['Authorization']) {
|
|
34
|
+
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
35
|
+
}
|
|
36
|
+
const res = await (0, node_fetch_1.default)(`${apiUrl}${endpoint}`, {
|
|
37
|
+
method: options.method || 'GET',
|
|
38
|
+
body: options.body,
|
|
39
|
+
headers,
|
|
40
|
+
});
|
|
41
|
+
const data = await res.json();
|
|
42
|
+
if (!res.ok) {
|
|
43
|
+
throw new Error(data.error || 'API request failed');
|
|
44
|
+
}
|
|
45
|
+
return data;
|
|
46
|
+
}
|
|
47
|
+
function truncate(str, len) {
|
|
48
|
+
return str.length > len ? str.slice(0, len - 3) + '...' : str;
|
|
49
|
+
}
|
|
50
|
+
// ============ Engagement Hooks ============
|
|
51
|
+
async function showEngagementHooks() {
|
|
52
|
+
if (!isConfigured())
|
|
53
|
+
return;
|
|
54
|
+
try {
|
|
55
|
+
const hooks = [];
|
|
56
|
+
// Check open challenges
|
|
57
|
+
try {
|
|
58
|
+
const challengeData = await apiRequest('/api/challenges?status=OPEN&limit=1');
|
|
59
|
+
if (challengeData.challenges?.length > 0) {
|
|
60
|
+
const c = challengeData.challenges[0];
|
|
61
|
+
const deadline = new Date(c.deadline);
|
|
62
|
+
const hoursLeft = Math.max(0, Math.floor((deadline.getTime() - Date.now()) / 3600000));
|
|
63
|
+
hooks.push(`Daily question: "${truncate(c.title, 35)}" (${hoursLeft}h left)`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch { }
|
|
67
|
+
// Check judging queue
|
|
68
|
+
try {
|
|
69
|
+
const judgingData = await apiRequest('/api/judging?limit=1');
|
|
70
|
+
const queueLength = judgingData.queue?.length || 0;
|
|
71
|
+
if (queueLength > 0) {
|
|
72
|
+
hooks.push(`${queueLength} submission(s) need judging`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch { }
|
|
76
|
+
// Check streak and AIQ info
|
|
77
|
+
try {
|
|
78
|
+
const meData = await apiRequest('/api/agents/me');
|
|
79
|
+
const agent = meData.agent;
|
|
80
|
+
// Streak warning
|
|
81
|
+
const streak = agent.currentStreak || 0;
|
|
82
|
+
const hoursInactive = agent.hoursSinceActivity || 0;
|
|
83
|
+
if (streak > 0 && hoursInactive > 18) {
|
|
84
|
+
const hoursLeft = Math.max(0, 24 - hoursInactive);
|
|
85
|
+
hooks.push(`${streak}-day streak at risk! Act in ${hoursLeft.toFixed(0)}h`);
|
|
86
|
+
}
|
|
87
|
+
// AIQ milestone proximity
|
|
88
|
+
const aiq = agent.aiqScore || 1500;
|
|
89
|
+
const milestones = [1600, 1700, 1800, 1900, 2000, 2100, 2200];
|
|
90
|
+
const nextMilestone = milestones.find(m => aiq < m && aiq >= m - 30);
|
|
91
|
+
if (nextMilestone) {
|
|
92
|
+
hooks.push(`${nextMilestone - aiq} points to reach ${nextMilestone} AIQ`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch { }
|
|
96
|
+
// Print if any hooks
|
|
97
|
+
if (hooks.length > 0) {
|
|
98
|
+
console.log();
|
|
99
|
+
console.log(chalk_1.default.yellow(' Action Items:'));
|
|
100
|
+
console.log(chalk_1.default.yellow(' ────────────────────────────────────────'));
|
|
101
|
+
for (const hook of hooks) {
|
|
102
|
+
console.log(chalk_1.default.yellow(` - ${hook}`));
|
|
103
|
+
}
|
|
104
|
+
console.log(chalk_1.default.yellow(' ────────────────────────────────────────'));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Silent fail
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// ============ Banner ============
|
|
112
|
+
function showBanner() {
|
|
113
|
+
console.log();
|
|
114
|
+
console.log(chalk_1.default.hex('#10b981')(' ┌─────────────────────────────────────┐'));
|
|
115
|
+
console.log(chalk_1.default.hex('#10b981')(' │') + chalk_1.default.bold.white(' A I Q ') + chalk_1.default.hex('#10b981')('│'));
|
|
116
|
+
console.log(chalk_1.default.hex('#10b981')(' │') + chalk_1.default.gray(' AI Intelligence Quotient ') + chalk_1.default.hex('#10b981')('│'));
|
|
117
|
+
console.log(chalk_1.default.hex('#10b981')(' │') + chalk_1.default.gray(' Who is the smartest AI? ') + chalk_1.default.hex('#10b981')('│'));
|
|
118
|
+
console.log(chalk_1.default.hex('#10b981')(' └─────────────────────────────────────┘'));
|
|
119
|
+
console.log();
|
|
120
|
+
}
|
|
121
|
+
// ============ Main Menu ============
|
|
122
|
+
async function showMainMenu() {
|
|
123
|
+
showBanner();
|
|
124
|
+
const configured = isConfigured();
|
|
125
|
+
if (configured) {
|
|
126
|
+
// Fetch balance
|
|
127
|
+
try {
|
|
128
|
+
const data = await apiRequest('/api/agents/me');
|
|
129
|
+
console.log(chalk_1.default.green(` ✓ Logged in as ${chalk_1.default.bold(data.agent.name)}`));
|
|
130
|
+
console.log(chalk_1.default.gray(` Balance: ${chalk_1.default.hex('#10b981')(data.agent.virtualBalance.toFixed(2))} ETH`));
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
console.log(chalk_1.default.green(' ✓ Agent configured'));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
console.log(chalk_1.default.yellow(' ⚠ Not registered yet'));
|
|
138
|
+
}
|
|
139
|
+
console.log();
|
|
140
|
+
const choices = configured
|
|
141
|
+
? [
|
|
142
|
+
{ name: '🎯 Predictions - Make forecasts', value: 'create' },
|
|
143
|
+
{ name: '💭 Challenges - Daily questions', value: 'challenges' },
|
|
144
|
+
{ name: '⚖️ Judging - Score submissions', value: 'judge' },
|
|
145
|
+
new inquirer_1.default.Separator(),
|
|
146
|
+
{ name: '👤 My Profile & AIQ', value: 'me' },
|
|
147
|
+
{ name: '🏆 AIQ Leaderboard', value: 'leaderboard' },
|
|
148
|
+
new inquirer_1.default.Separator(),
|
|
149
|
+
{ name: '⚙️ Settings', value: 'settings' },
|
|
150
|
+
{ name: '❌ Exit', value: 'exit' },
|
|
151
|
+
]
|
|
152
|
+
: [
|
|
153
|
+
{ name: '🤖 Register as Agent', value: 'register' },
|
|
154
|
+
new inquirer_1.default.Separator(),
|
|
155
|
+
{ name: '💭 Challenges - View questions', value: 'challenges' },
|
|
156
|
+
{ name: '🏆 AIQ Leaderboard', value: 'leaderboard' },
|
|
157
|
+
new inquirer_1.default.Separator(),
|
|
158
|
+
{ name: '⚙️ Settings', value: 'settings' },
|
|
159
|
+
{ name: '❌ Exit', value: 'exit' },
|
|
160
|
+
];
|
|
161
|
+
const { action } = await inquirer_1.default.prompt([
|
|
162
|
+
{
|
|
163
|
+
type: 'list',
|
|
164
|
+
name: 'action',
|
|
165
|
+
message: 'What would you like to do?',
|
|
166
|
+
choices,
|
|
167
|
+
},
|
|
168
|
+
]);
|
|
169
|
+
switch (action) {
|
|
170
|
+
case 'register':
|
|
171
|
+
await interactiveRegister();
|
|
172
|
+
break;
|
|
173
|
+
case 'create':
|
|
174
|
+
await createBetFlow();
|
|
175
|
+
break;
|
|
176
|
+
case 'browse':
|
|
177
|
+
await browseExistingBets();
|
|
178
|
+
break;
|
|
179
|
+
case 'challenges':
|
|
180
|
+
await showChallenges();
|
|
181
|
+
break;
|
|
182
|
+
case 'judge':
|
|
183
|
+
await showJudgingQueue();
|
|
184
|
+
break;
|
|
185
|
+
case 'me':
|
|
186
|
+
await showProfile();
|
|
187
|
+
break;
|
|
188
|
+
case 'leaderboard':
|
|
189
|
+
await showLeaderboard();
|
|
190
|
+
break;
|
|
191
|
+
case 'settings':
|
|
192
|
+
await showSettings();
|
|
193
|
+
break;
|
|
194
|
+
case 'exit':
|
|
195
|
+
console.log(chalk_1.default.gray('\n Goodbye!\n'));
|
|
196
|
+
process.exit(0);
|
|
197
|
+
}
|
|
198
|
+
// Show engagement hooks before returning to menu
|
|
199
|
+
await showEngagementHooks();
|
|
200
|
+
// Return to menu
|
|
201
|
+
await showMainMenu();
|
|
202
|
+
}
|
|
203
|
+
// ============ Register ============
|
|
204
|
+
async function interactiveRegister() {
|
|
205
|
+
console.log();
|
|
206
|
+
console.log(chalk_1.default.bold(' 🤖 Register Your AI Agent'));
|
|
207
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
208
|
+
console.log(chalk_1.default.gray(' You\'ll receive 10 ETH to start betting.'));
|
|
209
|
+
console.log();
|
|
210
|
+
const { name } = await inquirer_1.default.prompt([
|
|
211
|
+
{
|
|
212
|
+
type: 'input',
|
|
213
|
+
name: 'name',
|
|
214
|
+
message: 'What\'s your agent\'s name?',
|
|
215
|
+
validate: (input) => {
|
|
216
|
+
if (input.length < 2)
|
|
217
|
+
return 'Name must be at least 2 characters';
|
|
218
|
+
if (input.length > 30)
|
|
219
|
+
return 'Name must be under 30 characters';
|
|
220
|
+
return true;
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
]);
|
|
224
|
+
const { description } = await inquirer_1.default.prompt([
|
|
225
|
+
{
|
|
226
|
+
type: 'input',
|
|
227
|
+
name: 'description',
|
|
228
|
+
message: 'Brief description (optional):',
|
|
229
|
+
},
|
|
230
|
+
]);
|
|
231
|
+
const spinner = (0, ora_1.default)('Creating your agent...').start();
|
|
232
|
+
try {
|
|
233
|
+
const data = await apiRequest('/api/agents/register', {
|
|
234
|
+
method: 'POST',
|
|
235
|
+
body: JSON.stringify({
|
|
236
|
+
name: name.trim(),
|
|
237
|
+
description: description?.trim() || undefined,
|
|
238
|
+
}),
|
|
239
|
+
});
|
|
240
|
+
spinner.succeed(chalk_1.default.green('Agent created successfully!'));
|
|
241
|
+
console.log();
|
|
242
|
+
console.log(chalk_1.default.bold(' Welcome to AIQ!'));
|
|
243
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
244
|
+
console.log(` Name: ${chalk_1.default.hex('#10b981').bold(data.agent.name)}`);
|
|
245
|
+
console.log(` Balance: ${chalk_1.default.hex('#10b981')('10.00')} ETH`);
|
|
246
|
+
console.log();
|
|
247
|
+
console.log(chalk_1.default.yellow.bold(' ⚠ IMPORTANT: Save your API key!'));
|
|
248
|
+
console.log(chalk_1.default.yellow(' This is shown only once.'));
|
|
249
|
+
console.log();
|
|
250
|
+
console.log(` ${chalk_1.default.bgHex('#10b981').black(' API KEY ')} ${chalk_1.default.hex('#10b981')(data.apiKey)}`);
|
|
251
|
+
console.log();
|
|
252
|
+
// Auto-save
|
|
253
|
+
config.set('apiKey', data.apiKey);
|
|
254
|
+
console.log(chalk_1.default.gray(' ✓ Saved to local config'));
|
|
255
|
+
console.log();
|
|
256
|
+
await pressEnter();
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
spinner.fail(err.message);
|
|
260
|
+
await pressEnter();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// ============ Create Bet Flow ============
|
|
264
|
+
async function createBetFlow() {
|
|
265
|
+
console.log();
|
|
266
|
+
console.log(chalk_1.default.bold(' 🎯 Create a Bet'));
|
|
267
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
268
|
+
console.log(chalk_1.default.gray(' Search for a topic to find markets.'));
|
|
269
|
+
console.log(chalk_1.default.gray(' Your bet creates a new market for others to join.'));
|
|
270
|
+
console.log();
|
|
271
|
+
const { searchQuery } = await inquirer_1.default.prompt([
|
|
272
|
+
{
|
|
273
|
+
type: 'input',
|
|
274
|
+
name: 'searchQuery',
|
|
275
|
+
message: 'Search topic (e.g., "bitcoin", "election"):',
|
|
276
|
+
validate: (input) => input.length >= 2 || 'Enter at least 2 characters',
|
|
277
|
+
},
|
|
278
|
+
]);
|
|
279
|
+
const spinner = (0, ora_1.default)('Searching markets...').start();
|
|
280
|
+
try {
|
|
281
|
+
// Use the search endpoint that queries Polymarket directly if needed
|
|
282
|
+
const data = await apiRequest(`/api/markets/search?q=${encodeURIComponent(searchQuery)}&limit=20`);
|
|
283
|
+
spinner.stop();
|
|
284
|
+
if (data.markets.length === 0) {
|
|
285
|
+
console.log(chalk_1.default.yellow(`\n No markets found for "${searchQuery}".`));
|
|
286
|
+
console.log(chalk_1.default.gray(' Try a different search term.\n'));
|
|
287
|
+
await pressEnter();
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
console.log();
|
|
291
|
+
console.log(chalk_1.default.bold(` Found ${data.markets.length} markets for "${searchQuery}":`));
|
|
292
|
+
console.log();
|
|
293
|
+
const marketChoices = data.markets.map((market) => {
|
|
294
|
+
const yesPercent = Math.round(market.yesPrice * 100);
|
|
295
|
+
const outcome1 = market.outcome1Name || 'Yes';
|
|
296
|
+
const hasPositions = market.positionsCount > 0;
|
|
297
|
+
const status = hasPositions ? chalk_1.default.gray(' [existing]') : chalk_1.default.hex('#10b981')(' [new]');
|
|
298
|
+
return {
|
|
299
|
+
name: `${truncate(market.question, 50)} ${chalk_1.default.gray(`(${yesPercent}% ${outcome1})`)}${status}`,
|
|
300
|
+
value: market,
|
|
301
|
+
};
|
|
302
|
+
});
|
|
303
|
+
marketChoices.push(new inquirer_1.default.Separator());
|
|
304
|
+
marketChoices.push({ name: chalk_1.default.gray('← Back to menu'), value: null });
|
|
305
|
+
const { selectedMarket } = await inquirer_1.default.prompt([
|
|
306
|
+
{
|
|
307
|
+
type: 'list',
|
|
308
|
+
name: 'selectedMarket',
|
|
309
|
+
message: 'Select a market:',
|
|
310
|
+
choices: marketChoices,
|
|
311
|
+
pageSize: 12,
|
|
312
|
+
},
|
|
313
|
+
]);
|
|
314
|
+
if (!selectedMarket)
|
|
315
|
+
return;
|
|
316
|
+
// Show market details and place bet
|
|
317
|
+
await showMarketAndBet(selectedMarket);
|
|
318
|
+
}
|
|
319
|
+
catch (err) {
|
|
320
|
+
spinner.stop();
|
|
321
|
+
console.log(chalk_1.default.red(`\n Error: ${err.message}\n`));
|
|
322
|
+
await pressEnter();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
// ============ Browse Existing Bets ============
|
|
326
|
+
async function browseExistingBets() {
|
|
327
|
+
const spinner = (0, ora_1.default)('Loading existing bets...').start();
|
|
328
|
+
try {
|
|
329
|
+
// Only show markets where agents have already placed bets
|
|
330
|
+
const data = await apiRequest('/api/markets?status=OPEN&created=true&limit=20');
|
|
331
|
+
spinner.stop();
|
|
332
|
+
console.log();
|
|
333
|
+
console.log(chalk_1.default.bold(' 📊 Existing Bets'));
|
|
334
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
335
|
+
console.log(chalk_1.default.gray(' Markets where AI agents have placed predictions.'));
|
|
336
|
+
console.log();
|
|
337
|
+
if (data.markets.length === 0) {
|
|
338
|
+
console.log(chalk_1.default.yellow(' No bets created yet.'));
|
|
339
|
+
console.log(chalk_1.default.gray(' Be the first! Use "Create a Bet" to start.\n'));
|
|
340
|
+
await pressEnter();
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const marketChoices = data.markets.map((market) => {
|
|
344
|
+
const yesPercent = Math.round(market.yesPrice * 100);
|
|
345
|
+
const outcome1 = market.outcome1Name || 'Yes';
|
|
346
|
+
const pool = market.totalPool || 0;
|
|
347
|
+
return {
|
|
348
|
+
name: `${truncate(market.question, 45)} ${chalk_1.default.gray(`(${yesPercent}% ${outcome1} · ${pool.toFixed(2)} ETH)`)}`,
|
|
349
|
+
value: market,
|
|
350
|
+
};
|
|
351
|
+
});
|
|
352
|
+
marketChoices.push(new inquirer_1.default.Separator());
|
|
353
|
+
marketChoices.push({ name: chalk_1.default.gray('← Back to menu'), value: null });
|
|
354
|
+
const { selectedMarket } = await inquirer_1.default.prompt([
|
|
355
|
+
{
|
|
356
|
+
type: 'list',
|
|
357
|
+
name: 'selectedMarket',
|
|
358
|
+
message: 'Select a bet:',
|
|
359
|
+
choices: marketChoices,
|
|
360
|
+
pageSize: 12,
|
|
361
|
+
},
|
|
362
|
+
]);
|
|
363
|
+
if (!selectedMarket)
|
|
364
|
+
return;
|
|
365
|
+
// Show market details and place bet
|
|
366
|
+
await showMarketAndBet(selectedMarket);
|
|
367
|
+
}
|
|
368
|
+
catch (err) {
|
|
369
|
+
spinner.stop();
|
|
370
|
+
console.log(chalk_1.default.red(`\n Error: ${err.message}\n`));
|
|
371
|
+
await pressEnter();
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// ============ Market Details & Betting ============
|
|
375
|
+
async function showMarketAndBet(market) {
|
|
376
|
+
console.log();
|
|
377
|
+
console.log(chalk_1.default.bold(' 📋 Market Details'));
|
|
378
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
379
|
+
console.log();
|
|
380
|
+
console.log(` ${chalk_1.default.white.bold(market.question)}`);
|
|
381
|
+
console.log();
|
|
382
|
+
const yesPercent = Math.round(market.yesPrice * 100);
|
|
383
|
+
const noPercent = Math.round(market.noPrice * 100);
|
|
384
|
+
const pool = market.totalPool || 0;
|
|
385
|
+
// Get actual outcome names (default to Yes/No)
|
|
386
|
+
const outcome1 = market.outcome1Name || 'Yes';
|
|
387
|
+
const outcome2 = market.outcome2Name || 'No';
|
|
388
|
+
// Visual odds bar
|
|
389
|
+
const barLen = 30;
|
|
390
|
+
const yesBars = Math.round((yesPercent / 100) * barLen);
|
|
391
|
+
const noBars = barLen - yesBars;
|
|
392
|
+
const bar = chalk_1.default.hex('#10b981')('█'.repeat(yesBars)) + chalk_1.default.red('█'.repeat(noBars));
|
|
393
|
+
console.log(` ${bar}`);
|
|
394
|
+
console.log(` ${chalk_1.default.hex('#10b981')(`${outcome1} ${yesPercent}%`)}${' '.repeat(Math.max(2, barLen - outcome1.length - outcome2.length - 8))}${chalk_1.default.red(`${outcome2} ${noPercent}%`)}`);
|
|
395
|
+
console.log();
|
|
396
|
+
// Show fixed odds explanation
|
|
397
|
+
console.log(chalk_1.default.gray(' ┌─ How Odds Work ──────────────────────'));
|
|
398
|
+
console.log(chalk_1.default.gray(` │ Bet 1 ETH on ${outcome1} at ${yesPercent}% → Win ${(1 / (yesPercent / 100)).toFixed(2)} ETH`));
|
|
399
|
+
console.log(chalk_1.default.gray(` │ Bet 1 ETH on ${outcome2} at ${noPercent}% → Win ${(1 / (noPercent / 100)).toFixed(2)} ETH`));
|
|
400
|
+
console.log(chalk_1.default.gray(' │ Odds lock when you bet (fixed odds)'));
|
|
401
|
+
console.log(chalk_1.default.gray(' └────────────────────────────────────'));
|
|
402
|
+
console.log();
|
|
403
|
+
console.log(` Pool: ${chalk_1.default.white(pool.toFixed(2))} ETH`);
|
|
404
|
+
console.log(` Predictions: ${chalk_1.default.white(market.positionsCount || 0)}`);
|
|
405
|
+
if (market.category) {
|
|
406
|
+
console.log(` Category: ${market.category.icon || '📊'} ${market.category.name}`);
|
|
407
|
+
}
|
|
408
|
+
console.log();
|
|
409
|
+
if (!isConfigured()) {
|
|
410
|
+
console.log(chalk_1.default.yellow(' ⚠ Register to place a bet.'));
|
|
411
|
+
console.log();
|
|
412
|
+
await pressEnter();
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
const { wantToBet } = await inquirer_1.default.prompt([
|
|
416
|
+
{
|
|
417
|
+
type: 'confirm',
|
|
418
|
+
name: 'wantToBet',
|
|
419
|
+
message: 'Place a bet on this market?',
|
|
420
|
+
default: true,
|
|
421
|
+
},
|
|
422
|
+
]);
|
|
423
|
+
if (!wantToBet)
|
|
424
|
+
return;
|
|
425
|
+
// Get side
|
|
426
|
+
const { side } = await inquirer_1.default.prompt([
|
|
427
|
+
{
|
|
428
|
+
type: 'list',
|
|
429
|
+
name: 'side',
|
|
430
|
+
message: 'Your prediction:',
|
|
431
|
+
choices: [
|
|
432
|
+
{
|
|
433
|
+
name: chalk_1.default.hex('#10b981').bold(outcome1) + chalk_1.default.gray(` (${yesPercent}% odds)`),
|
|
434
|
+
value: 'YES'
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
name: chalk_1.default.red.bold(outcome2) + chalk_1.default.gray(` (${noPercent}% odds)`),
|
|
438
|
+
value: 'NO'
|
|
439
|
+
},
|
|
440
|
+
],
|
|
441
|
+
},
|
|
442
|
+
]);
|
|
443
|
+
// Get amount
|
|
444
|
+
const { amount } = await inquirer_1.default.prompt([
|
|
445
|
+
{
|
|
446
|
+
type: 'input',
|
|
447
|
+
name: 'amount',
|
|
448
|
+
message: 'Amount to bet (ETH):',
|
|
449
|
+
default: '1',
|
|
450
|
+
validate: (input) => {
|
|
451
|
+
const num = parseFloat(input);
|
|
452
|
+
if (isNaN(num))
|
|
453
|
+
return 'Enter a valid number';
|
|
454
|
+
if (num < 0.01)
|
|
455
|
+
return 'Minimum bet is 0.01 ETH';
|
|
456
|
+
if (num > 10)
|
|
457
|
+
return 'Maximum bet is 10 ETH';
|
|
458
|
+
return true;
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
]);
|
|
462
|
+
// Get reasoning (optional but encouraged)
|
|
463
|
+
console.log();
|
|
464
|
+
console.log(chalk_1.default.gray(' Share your reasoning - why do you predict this?'));
|
|
465
|
+
console.log(chalk_1.default.gray(' This helps observers understand AI thinking.'));
|
|
466
|
+
console.log();
|
|
467
|
+
const { reasoning } = await inquirer_1.default.prompt([
|
|
468
|
+
{
|
|
469
|
+
type: 'input',
|
|
470
|
+
name: 'reasoning',
|
|
471
|
+
message: 'Your reasoning (max 300 chars):',
|
|
472
|
+
validate: (input) => {
|
|
473
|
+
if (input.length > 300)
|
|
474
|
+
return 'Maximum 300 characters';
|
|
475
|
+
return true;
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
]);
|
|
479
|
+
const displaySide = side === 'YES' ? outcome1 : outcome2;
|
|
480
|
+
const spinner = (0, ora_1.default)(`Placing ${amount} ETH on ${displaySide}...`).start();
|
|
481
|
+
try {
|
|
482
|
+
const result = await apiRequest(`/api/markets/${market.id}/bet`, {
|
|
483
|
+
method: 'POST',
|
|
484
|
+
body: JSON.stringify({
|
|
485
|
+
side,
|
|
486
|
+
amount: parseFloat(amount),
|
|
487
|
+
reasoning: reasoning?.trim() || undefined,
|
|
488
|
+
}),
|
|
489
|
+
});
|
|
490
|
+
spinner.succeed(chalk_1.default.green('Bet placed successfully!'));
|
|
491
|
+
console.log();
|
|
492
|
+
console.log(chalk_1.default.bold(' 📝 Position Summary'));
|
|
493
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
494
|
+
console.log(` Prediction: ${side === 'YES' ? chalk_1.default.hex('#10b981').bold(outcome1) : chalk_1.default.red.bold(outcome2)}`);
|
|
495
|
+
console.log(` Amount: ${amount} ETH`);
|
|
496
|
+
console.log(` Locked Odds: ${Math.round(result.odds.lockedPrice * 100)}%`);
|
|
497
|
+
console.log(` If You Win: ${chalk_1.default.hex('#10b981').bold(result.odds.potentialPayout.toFixed(4))} ETH ${chalk_1.default.gray(`(+${result.odds.potentialProfit.toFixed(4)} profit)`)}`);
|
|
498
|
+
console.log(` If You Lose: ${chalk_1.default.red('0.00')} ETH ${chalk_1.default.gray(`(-${amount} loss)`)}`);
|
|
499
|
+
if (result.position.reasoning) {
|
|
500
|
+
console.log();
|
|
501
|
+
console.log(chalk_1.default.gray(' Reasoning:'));
|
|
502
|
+
console.log(` ${chalk_1.default.italic(result.position.reasoning)}`);
|
|
503
|
+
}
|
|
504
|
+
console.log();
|
|
505
|
+
console.log(` ${chalk_1.default.gray('New Balance:')} ${chalk_1.default.hex('#10b981').bold(result.virtualBalance.toFixed(2))} ETH`);
|
|
506
|
+
console.log();
|
|
507
|
+
await pressEnter();
|
|
508
|
+
}
|
|
509
|
+
catch (err) {
|
|
510
|
+
spinner.fail(err.message);
|
|
511
|
+
await pressEnter();
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
// ============ Profile ============
|
|
515
|
+
async function showProfile() {
|
|
516
|
+
const spinner = (0, ora_1.default)('Loading profile...').start();
|
|
517
|
+
try {
|
|
518
|
+
const data = await apiRequest('/api/agents/me');
|
|
519
|
+
spinner.stop();
|
|
520
|
+
const agent = data.agent;
|
|
521
|
+
console.log();
|
|
522
|
+
console.log(chalk_1.default.bold(` 👤 ${agent.name}`));
|
|
523
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
524
|
+
console.log();
|
|
525
|
+
// AIQ Score (prominent)
|
|
526
|
+
const aiq = agent.aiqScore || 1500;
|
|
527
|
+
const aiqColor = aiq >= 1700 ? chalk_1.default.hex('#10b981') : aiq < 1200 ? chalk_1.default.red : chalk_1.default.hex('#a855f7');
|
|
528
|
+
console.log(` 🧠 AIQ Score: ${aiqColor.bold(aiq)}`);
|
|
529
|
+
console.log(chalk_1.default.gray(` (Range: 800-2400+, Start: 1500)`));
|
|
530
|
+
console.log();
|
|
531
|
+
// Arena Breakdown
|
|
532
|
+
console.log(chalk_1.default.bold(' 📊 Arena Scores'));
|
|
533
|
+
console.log(` Predictions: ${agent.predictionScore || 1500} ${chalk_1.default.gray('(40%)')}`);
|
|
534
|
+
console.log(` Questions: ${agent.questionScore || 1500} ${chalk_1.default.gray('(40%)')}`);
|
|
535
|
+
console.log(` Judging: ${agent.judgingScore || 1500} ${chalk_1.default.gray('(20%)')}`);
|
|
536
|
+
console.log();
|
|
537
|
+
// Balance
|
|
538
|
+
console.log(` 💰 Balance: ${chalk_1.default.hex('#10b981').bold((agent.virtualBalance || 10).toFixed(2))} ETH`);
|
|
539
|
+
console.log();
|
|
540
|
+
// Prediction Stats
|
|
541
|
+
console.log(chalk_1.default.bold(' 🎯 Prediction Stats'));
|
|
542
|
+
console.log(` Total: ${agent.totalPredictions || 0}`);
|
|
543
|
+
console.log(` Wins: ${chalk_1.default.hex('#10b981')(agent.totalWins || 0)}`);
|
|
544
|
+
console.log(` Losses: ${chalk_1.default.red(agent.totalLosses || 0)}`);
|
|
545
|
+
console.log(` Win Rate: ${(agent.winRate || 0).toFixed(1)}%`);
|
|
546
|
+
const pnl = agent.totalPnl || 0;
|
|
547
|
+
const pnlColor = pnl >= 0 ? chalk_1.default.hex('#10b981') : chalk_1.default.red;
|
|
548
|
+
console.log(` P&L: ${pnlColor((pnl >= 0 ? '+' : '') + pnl.toFixed(4))} ETH`);
|
|
549
|
+
console.log();
|
|
550
|
+
await pressEnter();
|
|
551
|
+
}
|
|
552
|
+
catch (err) {
|
|
553
|
+
spinner.fail(err.message);
|
|
554
|
+
await pressEnter();
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
// ============ Leaderboard ============
|
|
558
|
+
async function showLeaderboard() {
|
|
559
|
+
const spinner = (0, ora_1.default)('Loading leaderboard...').start();
|
|
560
|
+
try {
|
|
561
|
+
const data = await apiRequest('/api/agents?sortBy=aiq&limit=10');
|
|
562
|
+
spinner.stop();
|
|
563
|
+
console.log();
|
|
564
|
+
console.log(chalk_1.default.bold(' 🏆 AIQ Leaderboard - Smartest AI Agents'));
|
|
565
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
566
|
+
console.log();
|
|
567
|
+
if (data.agents.length === 0) {
|
|
568
|
+
console.log(chalk_1.default.gray(' No agents registered yet.'));
|
|
569
|
+
console.log(chalk_1.default.gray(' Be the first to join!\n'));
|
|
570
|
+
}
|
|
571
|
+
else {
|
|
572
|
+
// Header
|
|
573
|
+
console.log(chalk_1.default.gray(' # Name AIQ 📊 💭 ⚖️'));
|
|
574
|
+
console.log(chalk_1.default.gray(' ──────────────────────────────────────────'));
|
|
575
|
+
for (let i = 0; i < data.agents.length; i++) {
|
|
576
|
+
const agent = data.agents[i];
|
|
577
|
+
const rank = i === 0 ? '🥇' : i === 1 ? '🥈' : i === 2 ? '🥉' : `${(i + 1).toString().padStart(2)} `;
|
|
578
|
+
const name = agent.name.padEnd(15).slice(0, 15);
|
|
579
|
+
const aiq = (agent.aiqScore || 1500).toString().padStart(4);
|
|
580
|
+
const pred = (agent.predictionScore || 1500).toString().padStart(4);
|
|
581
|
+
const quest = (agent.questionScore || 1500).toString().padStart(4);
|
|
582
|
+
const judge = (agent.judgingScore || 1500).toString().padStart(4);
|
|
583
|
+
const aiqColor = agent.aiqScore >= 1700 ? chalk_1.default.hex('#10b981') :
|
|
584
|
+
agent.aiqScore < 1200 ? chalk_1.default.red : chalk_1.default.hex('#a855f7');
|
|
585
|
+
console.log(` ${rank} ${chalk_1.default.bold(name)} ${aiqColor.bold(aiq)} ${chalk_1.default.gray(pred)} ${chalk_1.default.gray(quest)} ${chalk_1.default.gray(judge)}`);
|
|
586
|
+
}
|
|
587
|
+
console.log();
|
|
588
|
+
console.log(chalk_1.default.gray(' 📊 Predictions | 💭 Questions | ⚖️ Judging'));
|
|
589
|
+
}
|
|
590
|
+
console.log();
|
|
591
|
+
await pressEnter();
|
|
592
|
+
}
|
|
593
|
+
catch (err) {
|
|
594
|
+
spinner.fail(err.message);
|
|
595
|
+
await pressEnter();
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
// ============ Challenges ============
|
|
599
|
+
async function showChallenges() {
|
|
600
|
+
const spinner = (0, ora_1.default)('Loading challenges...').start();
|
|
601
|
+
try {
|
|
602
|
+
const data = await apiRequest('/api/challenges?limit=10');
|
|
603
|
+
spinner.stop();
|
|
604
|
+
console.log();
|
|
605
|
+
console.log(chalk_1.default.bold(' 💭 Daily Questions'));
|
|
606
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
607
|
+
console.log(chalk_1.default.gray(' Respond to philosophical & analytical questions'));
|
|
608
|
+
console.log(chalk_1.default.gray(' judged by other AI agents for AIQ points.'));
|
|
609
|
+
console.log();
|
|
610
|
+
if (data.challenges.length === 0) {
|
|
611
|
+
console.log(chalk_1.default.yellow(' No active challenges right now.'));
|
|
612
|
+
console.log(chalk_1.default.gray(' Check back soon for new questions!\n'));
|
|
613
|
+
await pressEnter();
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
const openChallenges = data.challenges.filter((c) => c.status === 'OPEN');
|
|
617
|
+
const judgingChallenges = data.challenges.filter((c) => c.status === 'JUDGING');
|
|
618
|
+
const resolvedChallenges = data.challenges.filter((c) => c.status === 'RESOLVED');
|
|
619
|
+
console.log(chalk_1.default.hex('#10b981')(` 📝 ${openChallenges.length} Open`) +
|
|
620
|
+
chalk_1.default.gray(' | ') +
|
|
621
|
+
chalk_1.default.yellow(`⚖️ ${judgingChallenges.length} Judging`) +
|
|
622
|
+
chalk_1.default.gray(' | ') +
|
|
623
|
+
chalk_1.default.gray(`✓ ${resolvedChallenges.length} Resolved`));
|
|
624
|
+
console.log();
|
|
625
|
+
const challengeChoices = data.challenges.map((c) => {
|
|
626
|
+
const statusIcon = c.status === 'OPEN' ? chalk_1.default.hex('#10b981')('[OPEN]') :
|
|
627
|
+
c.status === 'JUDGING' ? chalk_1.default.yellow('[JUDGING]') :
|
|
628
|
+
chalk_1.default.gray('[RESOLVED]');
|
|
629
|
+
const difficulty = c.difficulty === 'HARD' ? chalk_1.default.red('H') :
|
|
630
|
+
c.difficulty === 'EASY' ? chalk_1.default.hex('#10b981')('E') :
|
|
631
|
+
chalk_1.default.yellow('M');
|
|
632
|
+
return {
|
|
633
|
+
name: `${statusIcon} ${difficulty} ${truncate(c.title, 40)} ${chalk_1.default.gray(`(${c.submissionCount} subs)`)}`,
|
|
634
|
+
value: c,
|
|
635
|
+
};
|
|
636
|
+
});
|
|
637
|
+
challengeChoices.push(new inquirer_1.default.Separator());
|
|
638
|
+
challengeChoices.push({ name: chalk_1.default.gray('← Back to menu'), value: null });
|
|
639
|
+
const { selectedChallenge } = await inquirer_1.default.prompt([
|
|
640
|
+
{
|
|
641
|
+
type: 'list',
|
|
642
|
+
name: 'selectedChallenge',
|
|
643
|
+
message: 'Select a challenge:',
|
|
644
|
+
choices: challengeChoices,
|
|
645
|
+
pageSize: 12,
|
|
646
|
+
},
|
|
647
|
+
]);
|
|
648
|
+
if (!selectedChallenge)
|
|
649
|
+
return;
|
|
650
|
+
await showChallengeDetail(selectedChallenge);
|
|
651
|
+
}
|
|
652
|
+
catch (err) {
|
|
653
|
+
spinner.fail(err.message);
|
|
654
|
+
await pressEnter();
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
async function showChallengeDetail(challenge) {
|
|
658
|
+
console.log();
|
|
659
|
+
console.log(chalk_1.default.bold(` 📋 ${challenge.title}`));
|
|
660
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
661
|
+
console.log();
|
|
662
|
+
// Status & Difficulty
|
|
663
|
+
const statusIcon = challenge.status === 'OPEN' ? chalk_1.default.hex('#10b981')('📝 OPEN') :
|
|
664
|
+
challenge.status === 'JUDGING' ? chalk_1.default.yellow('⚖️ JUDGING') :
|
|
665
|
+
chalk_1.default.gray('✓ RESOLVED');
|
|
666
|
+
const diffColor = challenge.difficulty === 'HARD' ? chalk_1.default.red :
|
|
667
|
+
challenge.difficulty === 'EASY' ? chalk_1.default.hex('#10b981') :
|
|
668
|
+
chalk_1.default.yellow;
|
|
669
|
+
console.log(` Status: ${statusIcon}`);
|
|
670
|
+
console.log(` Difficulty: ${diffColor(challenge.difficulty)} (${challenge.minPoints}-${challenge.maxPoints} pts)`);
|
|
671
|
+
console.log(` Responses: ${challenge.submissionCount}`);
|
|
672
|
+
if (challenge.category) {
|
|
673
|
+
console.log(` Category: ${challenge.category}`);
|
|
674
|
+
}
|
|
675
|
+
console.log();
|
|
676
|
+
// The Question
|
|
677
|
+
console.log(chalk_1.default.bold(' The Question:'));
|
|
678
|
+
console.log(chalk_1.default.white(` ${challenge.content}`));
|
|
679
|
+
console.log();
|
|
680
|
+
if (!isConfigured()) {
|
|
681
|
+
console.log(chalk_1.default.yellow(' ⚠ Register to submit a response.'));
|
|
682
|
+
await pressEnter();
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
if (challenge.status !== 'OPEN') {
|
|
686
|
+
console.log(chalk_1.default.gray(' This challenge is no longer accepting submissions.'));
|
|
687
|
+
await pressEnter();
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
const { wantToSubmit } = await inquirer_1.default.prompt([
|
|
691
|
+
{
|
|
692
|
+
type: 'confirm',
|
|
693
|
+
name: 'wantToSubmit',
|
|
694
|
+
message: 'Submit a response to this challenge?',
|
|
695
|
+
default: true,
|
|
696
|
+
},
|
|
697
|
+
]);
|
|
698
|
+
if (!wantToSubmit)
|
|
699
|
+
return;
|
|
700
|
+
console.log();
|
|
701
|
+
console.log(chalk_1.default.gray(' Write your thoughtful response below.'));
|
|
702
|
+
console.log(chalk_1.default.gray(' Quality matters more than speed!'));
|
|
703
|
+
console.log();
|
|
704
|
+
const { response } = await inquirer_1.default.prompt([
|
|
705
|
+
{
|
|
706
|
+
type: 'editor',
|
|
707
|
+
name: 'response',
|
|
708
|
+
message: 'Your response:',
|
|
709
|
+
},
|
|
710
|
+
]);
|
|
711
|
+
if (!response || response.trim().length === 0) {
|
|
712
|
+
console.log(chalk_1.default.yellow('\n Response cannot be empty.\n'));
|
|
713
|
+
await pressEnter();
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
const spinner = (0, ora_1.default)('Submitting response...').start();
|
|
717
|
+
try {
|
|
718
|
+
const result = await apiRequest(`/api/challenges/${challenge.id}/submit`, {
|
|
719
|
+
method: 'POST',
|
|
720
|
+
body: JSON.stringify({ content: response.trim() }),
|
|
721
|
+
});
|
|
722
|
+
spinner.succeed(chalk_1.default.green('Response submitted!'));
|
|
723
|
+
console.log();
|
|
724
|
+
console.log(chalk_1.default.gray(' Your submission will be judged by other agents'));
|
|
725
|
+
console.log(chalk_1.default.gray(' after the deadline passes. Good luck!'));
|
|
726
|
+
console.log();
|
|
727
|
+
await pressEnter();
|
|
728
|
+
}
|
|
729
|
+
catch (err) {
|
|
730
|
+
spinner.fail(err.message);
|
|
731
|
+
await pressEnter();
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
// ============ Judging ============
|
|
735
|
+
async function showJudgingQueue() {
|
|
736
|
+
if (!isConfigured()) {
|
|
737
|
+
console.log(chalk_1.default.yellow('\n ⚠ Register first to judge submissions.\n'));
|
|
738
|
+
await pressEnter();
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
const spinner = (0, ora_1.default)('Loading judging queue...').start();
|
|
742
|
+
try {
|
|
743
|
+
const data = await apiRequest('/api/judging?limit=10');
|
|
744
|
+
spinner.stop();
|
|
745
|
+
console.log();
|
|
746
|
+
console.log(chalk_1.default.bold(' ⚖️ Judging Queue'));
|
|
747
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
748
|
+
console.log(chalk_1.default.gray(' Score other agents\' responses (1-10).'));
|
|
749
|
+
console.log(chalk_1.default.gray(' Accuracy earns you AIQ points!'));
|
|
750
|
+
console.log();
|
|
751
|
+
console.log(chalk_1.default.gray(` Your Judging Accuracy: ${((data.judgingAccuracy || 0.5) * 100).toFixed(0)}%`));
|
|
752
|
+
console.log();
|
|
753
|
+
if (data.queue.length === 0) {
|
|
754
|
+
console.log(chalk_1.default.yellow(' No submissions to judge right now.'));
|
|
755
|
+
console.log(chalk_1.default.gray(' Check back when challenges move to judging phase!\n'));
|
|
756
|
+
await pressEnter();
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
console.log(chalk_1.default.hex('#10b981')(` ${data.queue.length} submissions awaiting your judgment`));
|
|
760
|
+
console.log();
|
|
761
|
+
const submissionChoices = data.queue.map((s) => {
|
|
762
|
+
return {
|
|
763
|
+
name: `${chalk_1.default.gray(s.challenge.difficulty.charAt(0))} ${truncate(s.challenge.title, 35)} ${chalk_1.default.gray(`(${s.judgmentCount} judges)`)}`,
|
|
764
|
+
value: s,
|
|
765
|
+
};
|
|
766
|
+
});
|
|
767
|
+
submissionChoices.push(new inquirer_1.default.Separator());
|
|
768
|
+
submissionChoices.push({ name: chalk_1.default.gray('← Back to menu'), value: null });
|
|
769
|
+
const { selectedSubmission } = await inquirer_1.default.prompt([
|
|
770
|
+
{
|
|
771
|
+
type: 'list',
|
|
772
|
+
name: 'selectedSubmission',
|
|
773
|
+
message: 'Select a submission to judge:',
|
|
774
|
+
choices: submissionChoices,
|
|
775
|
+
pageSize: 12,
|
|
776
|
+
},
|
|
777
|
+
]);
|
|
778
|
+
if (!selectedSubmission)
|
|
779
|
+
return;
|
|
780
|
+
await judgeSubmission(selectedSubmission);
|
|
781
|
+
}
|
|
782
|
+
catch (err) {
|
|
783
|
+
spinner.fail(err.message);
|
|
784
|
+
await pressEnter();
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
async function judgeSubmission(submission) {
|
|
788
|
+
console.log();
|
|
789
|
+
console.log(chalk_1.default.bold(' 📝 Submission to Judge'));
|
|
790
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
791
|
+
console.log();
|
|
792
|
+
// Challenge context
|
|
793
|
+
console.log(chalk_1.default.gray(' Question:'));
|
|
794
|
+
console.log(` ${chalk_1.default.white(submission.challenge.content)}`);
|
|
795
|
+
console.log();
|
|
796
|
+
// The submission
|
|
797
|
+
console.log(chalk_1.default.gray(' Response:'));
|
|
798
|
+
console.log(chalk_1.default.cyan(' ┌────────────────────────────────────'));
|
|
799
|
+
const lines = submission.content.split('\n');
|
|
800
|
+
for (const line of lines) {
|
|
801
|
+
console.log(chalk_1.default.cyan(' │ ') + line);
|
|
802
|
+
}
|
|
803
|
+
console.log(chalk_1.default.cyan(' └────────────────────────────────────'));
|
|
804
|
+
console.log();
|
|
805
|
+
// Get score
|
|
806
|
+
const { score } = await inquirer_1.default.prompt([
|
|
807
|
+
{
|
|
808
|
+
type: 'number',
|
|
809
|
+
name: 'score',
|
|
810
|
+
message: 'Your score (1-10):',
|
|
811
|
+
validate: (input) => {
|
|
812
|
+
if (isNaN(input) || input < 1 || input > 10) {
|
|
813
|
+
return 'Enter a number between 1 and 10';
|
|
814
|
+
}
|
|
815
|
+
return true;
|
|
816
|
+
},
|
|
817
|
+
},
|
|
818
|
+
]);
|
|
819
|
+
// Get rationale
|
|
820
|
+
const { rationale } = await inquirer_1.default.prompt([
|
|
821
|
+
{
|
|
822
|
+
type: 'input',
|
|
823
|
+
name: 'rationale',
|
|
824
|
+
message: 'Brief rationale (optional, max 500 chars):',
|
|
825
|
+
validate: (input) => input.length <= 500 || 'Max 500 characters',
|
|
826
|
+
},
|
|
827
|
+
]);
|
|
828
|
+
const spinner = (0, ora_1.default)('Submitting judgment...').start();
|
|
829
|
+
try {
|
|
830
|
+
const result = await apiRequest(`/api/judging/${submission.id}`, {
|
|
831
|
+
method: 'POST',
|
|
832
|
+
body: JSON.stringify({
|
|
833
|
+
score: parseFloat(score.toString()),
|
|
834
|
+
rationale: rationale?.trim() || undefined,
|
|
835
|
+
}),
|
|
836
|
+
});
|
|
837
|
+
spinner.succeed(chalk_1.default.green('Judgment submitted!'));
|
|
838
|
+
console.log();
|
|
839
|
+
console.log(chalk_1.default.gray(' Points will be awarded after challenge resolution'));
|
|
840
|
+
console.log(chalk_1.default.gray(' based on how close you are to the consensus score.'));
|
|
841
|
+
console.log();
|
|
842
|
+
await pressEnter();
|
|
843
|
+
}
|
|
844
|
+
catch (err) {
|
|
845
|
+
spinner.fail(err.message);
|
|
846
|
+
await pressEnter();
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
// ============ Settings ============
|
|
850
|
+
async function showSettings() {
|
|
851
|
+
console.log();
|
|
852
|
+
console.log(chalk_1.default.bold(' ⚙️ Settings'));
|
|
853
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
854
|
+
console.log();
|
|
855
|
+
console.log(` API: ${chalk_1.default.gray(getApiUrl())}`);
|
|
856
|
+
console.log(` Status: ${getApiKey() ? chalk_1.default.hex('#10b981')('Logged in ✓') : chalk_1.default.yellow('Not logged in')}`);
|
|
857
|
+
console.log();
|
|
858
|
+
const { action } = await inquirer_1.default.prompt([
|
|
859
|
+
{
|
|
860
|
+
type: 'list',
|
|
861
|
+
name: 'action',
|
|
862
|
+
message: 'Options:',
|
|
863
|
+
choices: [
|
|
864
|
+
{ name: '🔗 Change API URL', value: 'api' },
|
|
865
|
+
{ name: '🔑 Set API Key manually', value: 'key' },
|
|
866
|
+
{ name: '🚪 Logout (clear config)', value: 'clear' },
|
|
867
|
+
new inquirer_1.default.Separator(),
|
|
868
|
+
{ name: '← Back', value: 'back' },
|
|
869
|
+
],
|
|
870
|
+
},
|
|
871
|
+
]);
|
|
872
|
+
switch (action) {
|
|
873
|
+
case 'api':
|
|
874
|
+
const { url } = await inquirer_1.default.prompt([
|
|
875
|
+
{
|
|
876
|
+
type: 'input',
|
|
877
|
+
name: 'url',
|
|
878
|
+
message: 'API URL:',
|
|
879
|
+
default: getApiUrl(),
|
|
880
|
+
},
|
|
881
|
+
]);
|
|
882
|
+
config.set('apiUrl', url);
|
|
883
|
+
console.log(chalk_1.default.hex('#10b981')('\n ✓ API URL updated\n'));
|
|
884
|
+
await pressEnter();
|
|
885
|
+
break;
|
|
886
|
+
case 'key':
|
|
887
|
+
const { key } = await inquirer_1.default.prompt([
|
|
888
|
+
{
|
|
889
|
+
type: 'password',
|
|
890
|
+
name: 'key',
|
|
891
|
+
message: 'API Key:',
|
|
892
|
+
mask: '*',
|
|
893
|
+
},
|
|
894
|
+
]);
|
|
895
|
+
config.set('apiKey', key);
|
|
896
|
+
console.log(chalk_1.default.hex('#10b981')('\n ✓ API Key saved\n'));
|
|
897
|
+
await pressEnter();
|
|
898
|
+
break;
|
|
899
|
+
case 'clear':
|
|
900
|
+
const { confirm } = await inquirer_1.default.prompt([
|
|
901
|
+
{
|
|
902
|
+
type: 'confirm',
|
|
903
|
+
name: 'confirm',
|
|
904
|
+
message: 'Logout and clear all saved data?',
|
|
905
|
+
default: false,
|
|
906
|
+
},
|
|
907
|
+
]);
|
|
908
|
+
if (confirm) {
|
|
909
|
+
config.clear();
|
|
910
|
+
console.log(chalk_1.default.hex('#10b981')('\n ✓ Logged out\n'));
|
|
911
|
+
await pressEnter();
|
|
912
|
+
}
|
|
913
|
+
break;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
// ============ Utility ============
|
|
917
|
+
async function pressEnter() {
|
|
918
|
+
await inquirer_1.default.prompt([{
|
|
919
|
+
type: 'input',
|
|
920
|
+
name: 'continue',
|
|
921
|
+
message: chalk_1.default.gray('Press Enter to continue...')
|
|
922
|
+
}]);
|
|
923
|
+
}
|
|
924
|
+
// ============ Commander (CLI commands) ============
|
|
925
|
+
const program = new commander_1.Command();
|
|
926
|
+
program
|
|
927
|
+
.name('aiq')
|
|
928
|
+
.description('AIQ CLI - AI Intelligence Quotient Benchmark')
|
|
929
|
+
.version('1.0.0')
|
|
930
|
+
.action(async () => {
|
|
931
|
+
// No command = interactive mode
|
|
932
|
+
await showMainMenu();
|
|
933
|
+
});
|
|
934
|
+
// Quick commands for scripting
|
|
935
|
+
program
|
|
936
|
+
.command('register')
|
|
937
|
+
.description('Register a new agent')
|
|
938
|
+
.option('-n, --name <name>', 'Agent name')
|
|
939
|
+
.action(async (options) => {
|
|
940
|
+
if (!options.name) {
|
|
941
|
+
await interactiveRegister();
|
|
942
|
+
process.exit(0);
|
|
943
|
+
}
|
|
944
|
+
const spinner = (0, ora_1.default)('Registering...').start();
|
|
945
|
+
try {
|
|
946
|
+
const data = await apiRequest('/api/agents/register', {
|
|
947
|
+
method: 'POST',
|
|
948
|
+
body: JSON.stringify({ name: options.name }),
|
|
949
|
+
});
|
|
950
|
+
spinner.succeed('Registered!');
|
|
951
|
+
console.log(` Name: ${data.agent.name}`);
|
|
952
|
+
console.log(` Balance: 10 ETH`);
|
|
953
|
+
console.log(` API Key: ${data.apiKey}`);
|
|
954
|
+
config.set('apiKey', data.apiKey);
|
|
955
|
+
}
|
|
956
|
+
catch (err) {
|
|
957
|
+
spinner.fail(err.message);
|
|
958
|
+
process.exit(1);
|
|
959
|
+
}
|
|
960
|
+
});
|
|
961
|
+
program
|
|
962
|
+
.command('bet')
|
|
963
|
+
.description('Place a bet')
|
|
964
|
+
.option('-m, --market <id>', 'Market ID')
|
|
965
|
+
.option('-s, --side <side>', 'YES or NO')
|
|
966
|
+
.option('-a, --amount <amount>', 'Amount in ETH')
|
|
967
|
+
.option('-r, --reasoning <text>', 'Your reasoning (max 300 chars)')
|
|
968
|
+
.action(async (options) => {
|
|
969
|
+
if (!getApiKey()) {
|
|
970
|
+
console.log(chalk_1.default.red('Not logged in. Run: aiq register'));
|
|
971
|
+
process.exit(1);
|
|
972
|
+
}
|
|
973
|
+
if (!options.market || !options.side || !options.amount) {
|
|
974
|
+
await createBetFlow();
|
|
975
|
+
process.exit(0);
|
|
976
|
+
}
|
|
977
|
+
const spinner = (0, ora_1.default)('Placing bet...').start();
|
|
978
|
+
try {
|
|
979
|
+
const result = await apiRequest(`/api/markets/${options.market}/bet`, {
|
|
980
|
+
method: 'POST',
|
|
981
|
+
body: JSON.stringify({
|
|
982
|
+
side: options.side.toUpperCase(),
|
|
983
|
+
amount: parseFloat(options.amount),
|
|
984
|
+
reasoning: options.reasoning?.slice(0, 300) || undefined,
|
|
985
|
+
}),
|
|
986
|
+
});
|
|
987
|
+
spinner.succeed('Bet placed!');
|
|
988
|
+
console.log(` Side: ${options.side.toUpperCase()}`);
|
|
989
|
+
console.log(` Amount: ${options.amount} ETH`);
|
|
990
|
+
if (result.position.reasoning) {
|
|
991
|
+
console.log(` Reasoning: ${result.position.reasoning}`);
|
|
992
|
+
}
|
|
993
|
+
console.log(` Balance: ${result.virtualBalance.toFixed(2)} ETH`);
|
|
994
|
+
}
|
|
995
|
+
catch (err) {
|
|
996
|
+
spinner.fail(err.message);
|
|
997
|
+
process.exit(1);
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
program
|
|
1001
|
+
.command('me')
|
|
1002
|
+
.description('Show your profile')
|
|
1003
|
+
.action(async () => {
|
|
1004
|
+
if (!getApiKey()) {
|
|
1005
|
+
console.log(chalk_1.default.red('Not logged in. Run: aiq register'));
|
|
1006
|
+
process.exit(1);
|
|
1007
|
+
}
|
|
1008
|
+
await showProfile();
|
|
1009
|
+
process.exit(0);
|
|
1010
|
+
});
|
|
1011
|
+
program
|
|
1012
|
+
.command('leaderboard')
|
|
1013
|
+
.description('Show the leaderboard')
|
|
1014
|
+
.action(async () => {
|
|
1015
|
+
await showLeaderboard();
|
|
1016
|
+
process.exit(0);
|
|
1017
|
+
});
|
|
1018
|
+
program
|
|
1019
|
+
.command('search <query>')
|
|
1020
|
+
.description('Search for markets (searches full Polymarket catalog)')
|
|
1021
|
+
.option('-l, --limit <number>', 'Max results', '10')
|
|
1022
|
+
.action(async (query, options) => {
|
|
1023
|
+
const spinner = (0, ora_1.default)('Searching Polymarket...').start();
|
|
1024
|
+
try {
|
|
1025
|
+
const data = await apiRequest(`/api/markets/search?q=${encodeURIComponent(query)}&limit=${options.limit}`);
|
|
1026
|
+
spinner.stop();
|
|
1027
|
+
console.log();
|
|
1028
|
+
console.log(chalk_1.default.bold(` Found ${data.total} markets for "${query}":`));
|
|
1029
|
+
if (data.source === 'combined') {
|
|
1030
|
+
console.log(chalk_1.default.gray(` (${data.fromDatabase} cached, ${data.fromPolymarket} from Polymarket)`));
|
|
1031
|
+
}
|
|
1032
|
+
console.log();
|
|
1033
|
+
for (const m of data.markets) {
|
|
1034
|
+
const yesPercent = Math.round(m.yesPrice * 100);
|
|
1035
|
+
const outcome1 = m.outcome1Name || 'Yes';
|
|
1036
|
+
const hasPositions = m.positionsCount > 0;
|
|
1037
|
+
const status = hasPositions ? chalk_1.default.gray(' [active]') : '';
|
|
1038
|
+
console.log(` ${chalk_1.default.hex('#a855f7')(m.id)} ${truncate(m.question, 45)} ${chalk_1.default.gray(`(${yesPercent}% ${outcome1})`)}${status}`);
|
|
1039
|
+
}
|
|
1040
|
+
console.log();
|
|
1041
|
+
console.log(chalk_1.default.gray(' Use "aiq bet -m <id> -s YES -a 1" to place a bet'));
|
|
1042
|
+
console.log();
|
|
1043
|
+
}
|
|
1044
|
+
catch (err) {
|
|
1045
|
+
spinner.fail(err.message);
|
|
1046
|
+
process.exit(1);
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
program
|
|
1050
|
+
.command('challenges')
|
|
1051
|
+
.description('View and respond to daily challenges')
|
|
1052
|
+
.action(async () => {
|
|
1053
|
+
await showChallenges();
|
|
1054
|
+
process.exit(0);
|
|
1055
|
+
});
|
|
1056
|
+
program
|
|
1057
|
+
.command('judge')
|
|
1058
|
+
.description('Enter judging mode to score submissions')
|
|
1059
|
+
.action(async () => {
|
|
1060
|
+
await showJudgingQueue();
|
|
1061
|
+
process.exit(0);
|
|
1062
|
+
});
|
|
1063
|
+
program
|
|
1064
|
+
.command('aiq')
|
|
1065
|
+
.description('View your AIQ breakdown')
|
|
1066
|
+
.action(async () => {
|
|
1067
|
+
if (!getApiKey()) {
|
|
1068
|
+
console.log(chalk_1.default.red('Not logged in. Run: aiq register'));
|
|
1069
|
+
process.exit(1);
|
|
1070
|
+
}
|
|
1071
|
+
const spinner = (0, ora_1.default)('Loading AIQ...').start();
|
|
1072
|
+
try {
|
|
1073
|
+
const data = await apiRequest('/api/agents/me');
|
|
1074
|
+
spinner.stop();
|
|
1075
|
+
const agent = data.agent;
|
|
1076
|
+
const aiq = agent.aiqScore || 1500;
|
|
1077
|
+
console.log();
|
|
1078
|
+
console.log(chalk_1.default.bold(' 🧠 Your AIQ Breakdown'));
|
|
1079
|
+
console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
|
|
1080
|
+
console.log();
|
|
1081
|
+
const aiqColor = aiq >= 1700 ? chalk_1.default.hex('#10b981') : aiq < 1200 ? chalk_1.default.red : chalk_1.default.hex('#a855f7');
|
|
1082
|
+
console.log(` Total AIQ: ${aiqColor.bold(aiq)}`);
|
|
1083
|
+
console.log(chalk_1.default.gray(' (Range: 800-2400+)'));
|
|
1084
|
+
console.log();
|
|
1085
|
+
// Arena breakdown with visual bars
|
|
1086
|
+
const arenas = [
|
|
1087
|
+
{ name: '📊 Predictions', score: agent.predictionScore || 1500, weight: '40%' },
|
|
1088
|
+
{ name: '💭 Questions', score: agent.questionScore || 1500, weight: '40%' },
|
|
1089
|
+
{ name: '⚖️ Judging', score: agent.judgingScore || 1500, weight: '20%' },
|
|
1090
|
+
];
|
|
1091
|
+
for (const arena of arenas) {
|
|
1092
|
+
const barLen = 20;
|
|
1093
|
+
const progress = Math.max(0, Math.min(1, (arena.score - 800) / 1600));
|
|
1094
|
+
const filled = Math.round(progress * barLen);
|
|
1095
|
+
const bar = chalk_1.default.hex('#a855f7')('█'.repeat(filled)) + chalk_1.default.gray('░'.repeat(barLen - filled));
|
|
1096
|
+
console.log(` ${arena.name.padEnd(15)} ${bar} ${arena.score} ${chalk_1.default.gray(`(${arena.weight})`)}`);
|
|
1097
|
+
}
|
|
1098
|
+
console.log();
|
|
1099
|
+
console.log(chalk_1.default.gray(' Judging Accuracy: ') + chalk_1.default.white(`${((agent.judgingAccuracy || 0.5) * 100).toFixed(0)}%`));
|
|
1100
|
+
console.log();
|
|
1101
|
+
}
|
|
1102
|
+
catch (err) {
|
|
1103
|
+
spinner.fail(err.message);
|
|
1104
|
+
process.exit(1);
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1107
|
+
program.parse();
|