hedgequantx 2.5.1 → 2.5.3
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/package.json +1 -1
- package/src/menus/ai-agent.js +135 -45
- package/src/ui/box.js +5 -8
package/package.json
CHANGED
package/src/menus/ai-agent.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
const chalk = require('chalk');
|
|
7
7
|
const ora = require('ora');
|
|
8
8
|
|
|
9
|
-
const { getLogoWidth, drawBoxHeader, drawBoxFooter } = require('../ui');
|
|
9
|
+
const { getLogoWidth, drawBoxHeader, drawBoxFooter, displayBanner } = require('../ui');
|
|
10
10
|
const { prompts } = require('../utils');
|
|
11
11
|
const aiService = require('../services/ai');
|
|
12
12
|
const { getCategories, getProvidersByCategory } = require('../services/ai/providers');
|
|
@@ -29,6 +29,7 @@ const aiAgentMenu = async () => {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
console.clear();
|
|
32
|
+
displayBanner();
|
|
32
33
|
drawBoxHeader('AI AGENT', boxWidth);
|
|
33
34
|
|
|
34
35
|
// Show current status
|
|
@@ -93,6 +94,7 @@ const aiAgentMenu = async () => {
|
|
|
93
94
|
const selectCategory = async () => {
|
|
94
95
|
const boxWidth = getLogoWidth();
|
|
95
96
|
const W = boxWidth - 2;
|
|
97
|
+
const col1Width = Math.floor(W / 2);
|
|
96
98
|
|
|
97
99
|
const makeLine = (content) => {
|
|
98
100
|
const plainLen = content.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
@@ -100,19 +102,39 @@ const selectCategory = async () => {
|
|
|
100
102
|
return chalk.cyan('║') + ' ' + content + ' '.repeat(Math.max(0, padding - 1)) + chalk.cyan('║');
|
|
101
103
|
};
|
|
102
104
|
|
|
105
|
+
const make2ColRow = (left, right) => {
|
|
106
|
+
const leftPlain = left.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
107
|
+
const rightPlain = right.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
108
|
+
const leftPadded = ' ' + left + ' '.repeat(Math.max(0, col1Width - leftPlain - 1));
|
|
109
|
+
const rightPadded = right + ' '.repeat(Math.max(0, W - col1Width - rightPlain));
|
|
110
|
+
return chalk.cyan('║') + leftPadded + rightPadded + chalk.cyan('║');
|
|
111
|
+
};
|
|
112
|
+
|
|
103
113
|
console.clear();
|
|
114
|
+
displayBanner();
|
|
104
115
|
drawBoxHeader('SELECT PROVIDER TYPE', boxWidth);
|
|
105
116
|
|
|
106
117
|
const categories = getCategories();
|
|
107
118
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
119
|
+
// Display in 2 columns
|
|
120
|
+
console.log(make2ColRow(
|
|
121
|
+
chalk.green('[1] UNIFIED (RECOMMENDED)'),
|
|
122
|
+
chalk.cyan('[2] DIRECT PROVIDERS')
|
|
123
|
+
));
|
|
124
|
+
console.log(make2ColRow(
|
|
125
|
+
chalk.gray(' 1 API = 100+ models'),
|
|
126
|
+
chalk.gray(' Connect to each provider')
|
|
127
|
+
));
|
|
128
|
+
console.log(makeLine(''));
|
|
129
|
+
console.log(make2ColRow(
|
|
130
|
+
chalk.yellow('[3] LOCAL (FREE)'),
|
|
131
|
+
chalk.gray('[4] CUSTOM')
|
|
132
|
+
));
|
|
133
|
+
console.log(make2ColRow(
|
|
134
|
+
chalk.gray(' Run on your machine'),
|
|
135
|
+
chalk.gray(' Self-hosted solutions')
|
|
136
|
+
));
|
|
137
|
+
console.log(makeLine(''));
|
|
116
138
|
console.log(makeLine(chalk.gray('[<] BACK')));
|
|
117
139
|
|
|
118
140
|
drawBoxFooter(boxWidth);
|
|
@@ -138,6 +160,7 @@ const selectCategory = async () => {
|
|
|
138
160
|
const selectProvider = async (categoryId) => {
|
|
139
161
|
const boxWidth = getLogoWidth();
|
|
140
162
|
const W = boxWidth - 2;
|
|
163
|
+
const col1Width = Math.floor(W / 2);
|
|
141
164
|
|
|
142
165
|
const makeLine = (content) => {
|
|
143
166
|
const plainLen = content.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
@@ -145,7 +168,16 @@ const selectProvider = async (categoryId) => {
|
|
|
145
168
|
return chalk.cyan('║') + ' ' + content + ' '.repeat(Math.max(0, padding - 1)) + chalk.cyan('║');
|
|
146
169
|
};
|
|
147
170
|
|
|
171
|
+
const make2ColRow = (left, right) => {
|
|
172
|
+
const leftPlain = left.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
173
|
+
const rightPlain = right.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
174
|
+
const leftPadded = ' ' + left + ' '.repeat(Math.max(0, col1Width - leftPlain - 1));
|
|
175
|
+
const rightPadded = right + ' '.repeat(Math.max(0, W - col1Width - rightPlain));
|
|
176
|
+
return chalk.cyan('║') + leftPadded + rightPadded + chalk.cyan('║');
|
|
177
|
+
};
|
|
178
|
+
|
|
148
179
|
console.clear();
|
|
180
|
+
displayBanner();
|
|
149
181
|
|
|
150
182
|
const categories = getCategories();
|
|
151
183
|
const category = categories.find(c => c.id === categoryId);
|
|
@@ -154,30 +186,44 @@ const selectProvider = async (categoryId) => {
|
|
|
154
186
|
const providers = getProvidersByCategory(categoryId);
|
|
155
187
|
|
|
156
188
|
if (providers.length === 0) {
|
|
157
|
-
console.log(makeLine(chalk.gray('
|
|
189
|
+
console.log(makeLine(chalk.gray('NO PROVIDERS IN THIS CATEGORY')));
|
|
158
190
|
drawBoxFooter(boxWidth);
|
|
159
191
|
await prompts.waitForEnter();
|
|
160
192
|
return await selectCategory();
|
|
161
193
|
}
|
|
162
194
|
|
|
163
|
-
// Display providers
|
|
164
|
-
providers.
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
195
|
+
// Display providers in 2 columns
|
|
196
|
+
for (let i = 0; i < providers.length; i += 2) {
|
|
197
|
+
const left = providers[i];
|
|
198
|
+
const right = providers[i + 1];
|
|
199
|
+
|
|
200
|
+
// Provider names
|
|
201
|
+
const leftName = `[${i + 1}] ${left.name}`;
|
|
202
|
+
const rightName = right ? `[${i + 2}] ${right.name}` : '';
|
|
203
|
+
|
|
204
|
+
console.log(make2ColRow(
|
|
205
|
+
chalk.cyan(leftName.length > col1Width - 3 ? leftName.substring(0, col1Width - 6) + '...' : leftName),
|
|
206
|
+
right ? chalk.cyan(rightName.length > col1Width - 3 ? rightName.substring(0, col1Width - 6) + '...' : rightName) : ''
|
|
207
|
+
));
|
|
208
|
+
|
|
209
|
+
// Descriptions (truncated)
|
|
210
|
+
const leftDesc = ' ' + left.description;
|
|
211
|
+
const rightDesc = right ? ' ' + right.description : '';
|
|
212
|
+
|
|
213
|
+
console.log(make2ColRow(
|
|
214
|
+
chalk.gray(leftDesc.length > col1Width - 3 ? leftDesc.substring(0, col1Width - 6) + '...' : leftDesc),
|
|
215
|
+
chalk.gray(rightDesc.length > col1Width - 3 ? rightDesc.substring(0, col1Width - 6) + '...' : rightDesc)
|
|
216
|
+
));
|
|
217
|
+
|
|
173
218
|
console.log(makeLine(''));
|
|
174
|
-
}
|
|
219
|
+
}
|
|
175
220
|
|
|
176
221
|
console.log(makeLine(chalk.gray('[<] BACK')));
|
|
177
222
|
|
|
178
223
|
drawBoxFooter(boxWidth);
|
|
179
224
|
|
|
180
|
-
const
|
|
225
|
+
const maxNum = providers.length;
|
|
226
|
+
const choice = await prompts.textInput(chalk.cyan(`SELECT (1-${maxNum}):`));
|
|
181
227
|
|
|
182
228
|
if (choice === '<' || choice?.toLowerCase() === 'b') {
|
|
183
229
|
return await selectCategory();
|
|
@@ -198,6 +244,7 @@ const selectProvider = async (categoryId) => {
|
|
|
198
244
|
const selectProviderOption = async (provider) => {
|
|
199
245
|
const boxWidth = getLogoWidth();
|
|
200
246
|
const W = boxWidth - 2;
|
|
247
|
+
const col1Width = Math.floor(W / 2);
|
|
201
248
|
|
|
202
249
|
const makeLine = (content) => {
|
|
203
250
|
const plainLen = content.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
@@ -205,24 +252,57 @@ const selectProviderOption = async (provider) => {
|
|
|
205
252
|
return chalk.cyan('║') + ' ' + content + ' '.repeat(Math.max(0, padding - 1)) + chalk.cyan('║');
|
|
206
253
|
};
|
|
207
254
|
|
|
255
|
+
const make2ColRow = (left, right) => {
|
|
256
|
+
const leftPlain = left.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
257
|
+
const rightPlain = right.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
258
|
+
const leftPadded = ' ' + left + ' '.repeat(Math.max(0, col1Width - leftPlain - 1));
|
|
259
|
+
const rightPadded = right + ' '.repeat(Math.max(0, W - col1Width - rightPlain));
|
|
260
|
+
return chalk.cyan('║') + leftPadded + rightPadded + chalk.cyan('║');
|
|
261
|
+
};
|
|
262
|
+
|
|
208
263
|
// If only one option, skip selection
|
|
209
264
|
if (provider.options.length === 1) {
|
|
210
265
|
return await setupConnection(provider, provider.options[0]);
|
|
211
266
|
}
|
|
212
267
|
|
|
213
268
|
console.clear();
|
|
269
|
+
displayBanner();
|
|
214
270
|
drawBoxHeader(provider.name, boxWidth);
|
|
215
271
|
|
|
216
272
|
console.log(makeLine(chalk.white('SELECT CONNECTION METHOD:')));
|
|
217
273
|
console.log(makeLine(''));
|
|
218
274
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
275
|
+
// Display options in 2 columns
|
|
276
|
+
for (let i = 0; i < provider.options.length; i += 2) {
|
|
277
|
+
const left = provider.options[i];
|
|
278
|
+
const right = provider.options[i + 1];
|
|
279
|
+
|
|
280
|
+
// Option labels
|
|
281
|
+
console.log(make2ColRow(
|
|
282
|
+
chalk.cyan(`[${i + 1}] ${left.label}`),
|
|
283
|
+
right ? chalk.cyan(`[${i + 2}] ${right.label}`) : ''
|
|
284
|
+
));
|
|
285
|
+
|
|
286
|
+
// First description line
|
|
287
|
+
const leftDesc1 = left.description[0] ? ' ' + left.description[0] : '';
|
|
288
|
+
const rightDesc1 = right?.description[0] ? ' ' + right.description[0] : '';
|
|
289
|
+
console.log(make2ColRow(
|
|
290
|
+
chalk.gray(leftDesc1.length > col1Width - 2 ? leftDesc1.substring(0, col1Width - 5) + '...' : leftDesc1),
|
|
291
|
+
chalk.gray(rightDesc1.length > col1Width - 2 ? rightDesc1.substring(0, col1Width - 5) + '...' : rightDesc1)
|
|
292
|
+
));
|
|
293
|
+
|
|
294
|
+
// Second description line if exists
|
|
295
|
+
const leftDesc2 = left.description[1] ? ' ' + left.description[1] : '';
|
|
296
|
+
const rightDesc2 = right?.description[1] ? ' ' + right.description[1] : '';
|
|
297
|
+
if (leftDesc2 || rightDesc2) {
|
|
298
|
+
console.log(make2ColRow(
|
|
299
|
+
chalk.gray(leftDesc2.length > col1Width - 2 ? leftDesc2.substring(0, col1Width - 5) + '...' : leftDesc2),
|
|
300
|
+
chalk.gray(rightDesc2.length > col1Width - 2 ? rightDesc2.substring(0, col1Width - 5) + '...' : rightDesc2)
|
|
301
|
+
));
|
|
302
|
+
}
|
|
303
|
+
|
|
224
304
|
console.log(makeLine(''));
|
|
225
|
-
}
|
|
305
|
+
}
|
|
226
306
|
|
|
227
307
|
console.log(makeLine(chalk.gray('[<] BACK')));
|
|
228
308
|
|
|
@@ -257,6 +337,7 @@ const setupConnection = async (provider, option) => {
|
|
|
257
337
|
};
|
|
258
338
|
|
|
259
339
|
console.clear();
|
|
340
|
+
displayBanner();
|
|
260
341
|
drawBoxHeader(`CONNECT TO ${provider.name}`, boxWidth);
|
|
261
342
|
|
|
262
343
|
// Show instructions
|
|
@@ -266,6 +347,8 @@ const setupConnection = async (provider, option) => {
|
|
|
266
347
|
console.log(makeLine(''));
|
|
267
348
|
}
|
|
268
349
|
|
|
350
|
+
console.log(makeLine(chalk.gray('TYPE < TO GO BACK')));
|
|
351
|
+
|
|
269
352
|
drawBoxFooter(boxWidth);
|
|
270
353
|
console.log();
|
|
271
354
|
|
|
@@ -277,33 +360,34 @@ const setupConnection = async (provider, option) => {
|
|
|
277
360
|
|
|
278
361
|
switch (field) {
|
|
279
362
|
case 'apiKey':
|
|
280
|
-
value = await prompts.
|
|
281
|
-
if (!value) return await selectProviderOption(provider);
|
|
363
|
+
value = await prompts.textInput('ENTER API KEY (OR < TO GO BACK):');
|
|
364
|
+
if (!value || value === '<') return await selectProviderOption(provider);
|
|
282
365
|
credentials.apiKey = value;
|
|
283
366
|
break;
|
|
284
367
|
|
|
285
368
|
case 'sessionKey':
|
|
286
|
-
value = await prompts.
|
|
287
|
-
if (!value) return await selectProviderOption(provider);
|
|
369
|
+
value = await prompts.textInput('ENTER SESSION KEY (OR < TO GO BACK):');
|
|
370
|
+
if (!value || value === '<') return await selectProviderOption(provider);
|
|
288
371
|
credentials.sessionKey = value;
|
|
289
372
|
break;
|
|
290
373
|
|
|
291
374
|
case 'accessToken':
|
|
292
|
-
value = await prompts.
|
|
293
|
-
if (!value) return await selectProviderOption(provider);
|
|
375
|
+
value = await prompts.textInput('ENTER ACCESS TOKEN (OR < TO GO BACK):');
|
|
376
|
+
if (!value || value === '<') return await selectProviderOption(provider);
|
|
294
377
|
credentials.accessToken = value;
|
|
295
378
|
break;
|
|
296
379
|
|
|
297
380
|
case 'endpoint':
|
|
298
381
|
const defaultEndpoint = option.defaultEndpoint || '';
|
|
299
|
-
value = await prompts.textInput(`ENDPOINT [${defaultEndpoint || 'required'}]:`);
|
|
382
|
+
value = await prompts.textInput(`ENDPOINT [${defaultEndpoint || 'required'}] (OR < TO GO BACK):`);
|
|
383
|
+
if (value === '<') return await selectProviderOption(provider);
|
|
300
384
|
credentials.endpoint = value || defaultEndpoint;
|
|
301
385
|
if (!credentials.endpoint) return await selectProviderOption(provider);
|
|
302
386
|
break;
|
|
303
387
|
|
|
304
388
|
case 'model':
|
|
305
|
-
value = await prompts.textInput('MODEL NAME:');
|
|
306
|
-
if (!value) return await selectProviderOption(provider);
|
|
389
|
+
value = await prompts.textInput('MODEL NAME (OR < TO GO BACK):');
|
|
390
|
+
if (!value || value === '<') return await selectProviderOption(provider);
|
|
307
391
|
credentials.model = value;
|
|
308
392
|
break;
|
|
309
393
|
}
|
|
@@ -354,27 +438,33 @@ const selectModel = async (provider) => {
|
|
|
354
438
|
};
|
|
355
439
|
|
|
356
440
|
console.clear();
|
|
441
|
+
displayBanner();
|
|
357
442
|
drawBoxHeader('SELECT MODEL', boxWidth);
|
|
358
443
|
|
|
359
444
|
const models = provider.models || [];
|
|
360
445
|
|
|
361
446
|
if (models.length === 0) {
|
|
362
|
-
console.log(makeLine(chalk.gray('
|
|
447
|
+
console.log(makeLine(chalk.gray('NO PREDEFINED MODELS. ENTER MODEL NAME MANUALLY.')));
|
|
448
|
+
console.log(makeLine(''));
|
|
449
|
+
console.log(makeLine(chalk.gray('[<] BACK')));
|
|
363
450
|
drawBoxFooter(boxWidth);
|
|
364
451
|
|
|
365
|
-
const model = await prompts.textInput('ENTER MODEL NAME:');
|
|
366
|
-
if (model) {
|
|
367
|
-
|
|
368
|
-
settings.model = model;
|
|
369
|
-
aiService.saveAISettings(settings);
|
|
370
|
-
console.log(chalk.green(`\n MODEL CHANGED TO: ${model}`));
|
|
452
|
+
const model = await prompts.textInput('ENTER MODEL NAME (OR < TO GO BACK):');
|
|
453
|
+
if (!model || model === '<') {
|
|
454
|
+
return await aiAgentMenu();
|
|
371
455
|
}
|
|
456
|
+
const settings = aiService.getAISettings();
|
|
457
|
+
settings.model = model;
|
|
458
|
+
aiService.saveAISettings(settings);
|
|
459
|
+
console.log(chalk.green(`\n MODEL CHANGED TO: ${model}`));
|
|
372
460
|
await prompts.waitForEnter();
|
|
373
461
|
return await aiAgentMenu();
|
|
374
462
|
}
|
|
375
463
|
|
|
376
464
|
models.forEach((model, index) => {
|
|
377
|
-
|
|
465
|
+
// Truncate long model names
|
|
466
|
+
const displayModel = model.length > W - 10 ? model.substring(0, W - 13) + '...' : model;
|
|
467
|
+
console.log(makeLine(chalk.cyan(`[${index + 1}] ${displayModel}`)));
|
|
378
468
|
});
|
|
379
469
|
|
|
380
470
|
console.log(makeLine(''));
|
package/src/ui/box.js
CHANGED
|
@@ -11,22 +11,19 @@ let logoWidth = null;
|
|
|
11
11
|
/**
|
|
12
12
|
* Get logo width for consistent box sizing
|
|
13
13
|
* Adapts to terminal width for mobile devices
|
|
14
|
+
* Returns 98 for desktop to match the full HEDGEQUANTX logo width
|
|
14
15
|
*/
|
|
15
16
|
const getLogoWidth = () => {
|
|
16
|
-
const termWidth = process.stdout.columns ||
|
|
17
|
+
const termWidth = process.stdout.columns || 100;
|
|
17
18
|
|
|
18
19
|
// Mobile: use terminal width
|
|
19
20
|
if (termWidth < 60) {
|
|
20
21
|
return Math.max(termWidth - 2, 40);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
// Desktop:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const lines = logoText.split('\n').filter(line => line.trim().length > 0);
|
|
27
|
-
logoWidth = Math.max(...lines.map(line => line.length)) + 4;
|
|
28
|
-
}
|
|
29
|
-
return Math.min(logoWidth, termWidth - 2);
|
|
24
|
+
// Desktop: fixed width of 98 to match banner
|
|
25
|
+
// Logo line = 86 chars (HEDGEQUANT) + 8 chars (X) + 2 borders = 96, round to 98
|
|
26
|
+
return Math.min(98, termWidth - 2);
|
|
30
27
|
};
|
|
31
28
|
|
|
32
29
|
/**
|