hedgequantx 2.7.59 → 2.7.61

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "2.7.59",
3
+ "version": "2.7.61",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -85,29 +85,68 @@ const draw2ColRowCentered = (leftText, rightText, W) => {
85
85
  };
86
86
 
87
87
  /**
88
- * Draw providers table
88
+ * Draw providers table with vertically aligned columns
89
89
  * @param {Array} providers - List of AI providers
90
90
  * @param {Object} config - Current config
91
91
  * @param {number} boxWidth - Box width
92
92
  */
93
93
  const drawProvidersTable = (providers, config, boxWidth) => {
94
94
  const W = boxWidth - 2;
95
+ const colWidth = Math.floor(W / 2);
95
96
 
96
97
  // New rectangle (banner is always closed)
97
98
  console.log(chalk.cyan('╔' + '═'.repeat(W) + '╗'));
98
99
  console.log(chalk.cyan('║') + chalk.yellow.bold(centerText('AI AGENTS CONFIGURATION', W)) + chalk.cyan('║'));
99
100
  console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
100
101
 
101
- const items = providers.map((p, i) => {
102
- const status = config.providers[p.id]?.active ? chalk.green(' ●') : '';
103
- return chalk.cyan(`[${i + 1}]`) + ' ' + chalk[p.color](p.name.toUpperCase()) + status;
104
- });
102
+ const rows = Math.ceil(providers.length / 2);
103
+
104
+ // Find max name length across ALL providers for consistent alignment
105
+ const maxNameLen = Math.max(...providers.map(p => p.name.length));
106
+
107
+ // Fixed format: "[N] NAME" where N is always same width, NAME padded to maxNameLen
108
+ // Total content width = 3 ([N]) + 1 (space) + maxNameLen + 2 (possible " ●")
109
+ const contentWidth = 3 + 1 + maxNameLen + 2;
110
+ const leftPad = Math.floor((colWidth - contentWidth) / 2);
111
+ const rightPad = Math.floor(((W - colWidth) - contentWidth) / 2);
105
112
 
106
- const rows = Math.ceil(items.length / 2);
107
113
  for (let row = 0; row < rows; row++) {
108
- const left = items[row];
109
- const right = items[row + rows];
110
- draw2ColRowCentered(left || '', right || '', W);
114
+ const leftP = providers[row];
115
+ const rightP = providers[row + rows];
116
+
117
+ // Left column
118
+ let leftCol = '';
119
+ if (leftP) {
120
+ const num = row + 1;
121
+ const status = config.providers[leftP.id]?.active ? chalk.green(' ●') : ' ';
122
+ const statusRaw = config.providers[leftP.id]?.active ? ' ●' : ' ';
123
+ const name = leftP.provider ? leftP.provider.name : leftP.name;
124
+ const namePadded = name.toUpperCase().padEnd(maxNameLen);
125
+ const content = chalk.cyan(`[${num}]`) + ' ' + chalk[leftP.color](namePadded) + status;
126
+ const contentLen = 3 + 1 + maxNameLen + 2;
127
+ const padR = colWidth - leftPad - contentLen;
128
+ leftCol = ' '.repeat(leftPad) + content + ' '.repeat(Math.max(0, padR));
129
+ } else {
130
+ leftCol = ' '.repeat(colWidth);
131
+ }
132
+
133
+ // Right column
134
+ let rightCol = '';
135
+ const rightColWidth = W - colWidth;
136
+ if (rightP) {
137
+ const num = row + rows + 1;
138
+ const status = config.providers[rightP.id]?.active ? chalk.green(' ●') : ' ';
139
+ const name = rightP.provider ? rightP.provider.name : rightP.name;
140
+ const namePadded = name.toUpperCase().padEnd(maxNameLen);
141
+ const content = chalk.cyan(`[${num}]`) + ' ' + chalk[rightP.color](namePadded) + status;
142
+ const contentLen = 3 + 1 + maxNameLen + 2;
143
+ const padR2 = rightColWidth - rightPad - contentLen;
144
+ rightCol = ' '.repeat(rightPad) + content + ' '.repeat(Math.max(0, padR2));
145
+ } else {
146
+ rightCol = ' '.repeat(rightColWidth);
147
+ }
148
+
149
+ console.log(chalk.cyan('║') + leftCol + rightCol + chalk.cyan('║'));
111
150
  }
112
151
 
113
152
  console.log(chalk.cyan('╠' + '─'.repeat(W) + '╣'));
@@ -144,18 +183,12 @@ const drawProviderWindow = (provider, config, boxWidth) => {
144
183
  console.log(chalk.cyan('║') + chalk[provider.color].bold(centerText(provider.name.toUpperCase(), W)) + chalk.cyan('║'));
145
184
  console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
146
185
 
147
- // Empty line
148
- console.log(chalk.cyan('║') + ' '.repeat(W) + chalk.cyan('║'));
149
-
150
- // Options in 2 columns
151
- const opt1Title = '[1] CONNECT VIA PAID PLAN';
152
- const opt1Desc = 'USES CLIPROXY - NO API KEY NEEDED';
153
- const opt2Title = '[2] CONNECT VIA API KEY';
154
- const opt2Desc = 'ENTER YOUR OWN API KEY';
186
+ // Options in 2 columns (centered)
187
+ const opt1 = '[1] CONNECT VIA PAID PLAN';
188
+ const opt2 = '[2] CONNECT VIA API KEY';
155
189
 
156
- // Row 1: Titles
157
- const left1 = chalk.green(opt1Title);
158
- const right1 = chalk.yellow(opt2Title);
190
+ const left1 = chalk.green(opt1);
191
+ const right1 = chalk.yellow(opt2);
159
192
  const left1Len = visibleLength(left1);
160
193
  const right1Len = visibleLength(right1);
161
194
  const left1PadTotal = col1Width - left1Len;
@@ -172,28 +205,6 @@ const drawProviderWindow = (provider, config, boxWidth) => {
172
205
  chalk.cyan('║')
173
206
  );
174
207
 
175
- // Row 2: Descriptions
176
- const left2 = chalk.gray(opt1Desc);
177
- const right2 = chalk.gray(opt2Desc);
178
- const left2Len = visibleLength(left2);
179
- const right2Len = visibleLength(right2);
180
- const left2PadTotal = col1Width - left2Len;
181
- const left2PadL = Math.floor(left2PadTotal / 2);
182
- const left2PadR = left2PadTotal - left2PadL;
183
- const right2PadTotal = col2Width - right2Len;
184
- const right2PadL = Math.floor(right2PadTotal / 2);
185
- const right2PadR = right2PadTotal - right2PadL;
186
-
187
- console.log(
188
- chalk.cyan('║') +
189
- ' '.repeat(left2PadL) + left2 + ' '.repeat(left2PadR) +
190
- ' '.repeat(right2PadL) + right2 + ' '.repeat(right2PadR) +
191
- chalk.cyan('║')
192
- );
193
-
194
- // Empty line
195
- console.log(chalk.cyan('║') + ' '.repeat(W) + chalk.cyan('║'));
196
-
197
208
  // Status bar
198
209
  console.log(chalk.cyan('╠' + '─'.repeat(W) + '╣'));
199
210
 
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  const chalk = require('chalk');
6
- const { getSeparator } = require('../../ui');
6
+ const { getLogoWidth, centerText, displayBanner } = require('../../ui');
7
7
  const { logger, prompts } = require('../../utils');
8
8
 
9
9
  const log = logger.scope('AlgoMenu');
@@ -18,39 +18,59 @@ const algoTradingMenu = async (service) => {
18
18
  log.info('Algo Trading menu opened');
19
19
 
20
20
  try {
21
- console.log();
22
- console.log(chalk.gray(getSeparator()));
23
- console.log(chalk.yellow.bold(' Algo-Trading'));
24
- console.log(chalk.gray(getSeparator()));
25
- console.log();
21
+ // Clear screen and show banner
22
+ console.clear();
23
+ displayBanner();
24
+
25
+ const boxWidth = getLogoWidth();
26
+ const W = boxWidth - 2;
27
+
28
+ // Draw menu rectangle
29
+ console.log(chalk.cyan('╔' + '═'.repeat(W) + '╗'));
30
+ console.log(chalk.cyan('║') + chalk.magenta.bold(centerText('ALGO-TRADING', W)) + chalk.cyan('║'));
31
+ console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
32
+
33
+ // Options centered in 2 columns
34
+ const col1 = '[1] ONE ACCOUNT';
35
+ const col2 = '[2] COPY TRADING';
36
+ const colWidth = Math.floor(W / 2);
37
+ const pad1 = Math.floor((colWidth - col1.length) / 2);
38
+ const pad2 = Math.floor((colWidth - col2.length) / 2);
39
+ const line = ' '.repeat(pad1) + chalk.cyan(col1) + ' '.repeat(colWidth - col1.length - pad1) +
40
+ ' '.repeat(pad2) + chalk.cyan(col2) + ' '.repeat(colWidth - col2.length - pad2);
41
+ console.log(chalk.cyan('║') + line + chalk.cyan('║'));
42
+
43
+ console.log(chalk.cyan('╠' + '─'.repeat(W) + '╣'));
44
+ console.log(chalk.cyan('║') + chalk.red(centerText('[B] BACK', W)) + chalk.cyan('║'));
45
+ console.log(chalk.cyan('╚' + '═'.repeat(W) + '╝'));
26
46
 
27
- const action = await prompts.selectOption(chalk.yellow('Select Mode:'), [
28
- { value: 'one_account', label: 'One Account' },
29
- { value: 'copy_trading', label: 'Copy Trading' },
30
- { value: 'back', label: '< Back' }
31
- ]);
47
+ const input = await prompts.textInput(chalk.cyan('SELECT (1/2/B): '));
48
+ const choice = (input || '').toLowerCase().trim();
32
49
 
33
- log.debug('Algo mode selected', { action });
50
+ log.debug('Algo mode selected', { choice });
34
51
 
35
- if (!action || action === 'back') {
52
+ if (choice === 'b' || choice === '') {
36
53
  return 'back';
37
54
  }
38
55
 
39
- switch (action) {
40
- case 'one_account':
56
+ switch (choice) {
57
+ case '1':
41
58
  log.info('Starting One Account mode');
42
59
  await oneAccountMenu(service);
43
60
  break;
44
- case 'copy_trading':
61
+ case '2':
45
62
  log.info('Starting Copy Trading mode');
46
63
  await copyTradingMenu();
47
64
  break;
65
+ default:
66
+ console.log(chalk.red(' INVALID OPTION'));
67
+ await new Promise(r => setTimeout(r, 1000));
48
68
  }
49
69
 
50
- return action;
70
+ return choice;
51
71
  } catch (err) {
52
72
  log.error('Algo menu error:', err.message);
53
- console.log(chalk.red(` Error: ${err.message}`));
73
+ console.log(chalk.red(` ERROR: ${err.message.toUpperCase()}`));
54
74
  await prompts.waitForEnter();
55
75
  return 'back';
56
76
  }
package/src/pages/user.js CHANGED
@@ -6,13 +6,17 @@ const chalk = require('chalk');
6
6
  const ora = require('ora');
7
7
 
8
8
  const { connections } = require('../services');
9
- const { getLogoWidth, getColWidths, drawBoxHeader, drawBoxFooter, draw2ColHeader, visibleLength, padText } = require('../ui');
9
+ const { getLogoWidth, getColWidths, drawBoxHeader, drawBoxFooter, draw2ColHeader, visibleLength, padText, displayBanner } = require('../ui');
10
10
  const { prompts } = require('../utils');
11
11
 
12
12
  /**
13
13
  * Show user info
14
14
  */
15
15
  const showUserInfo = async (service) => {
16
+ // Clear screen and show banner
17
+ console.clear();
18
+ displayBanner();
19
+
16
20
  const boxWidth = getLogoWidth();
17
21
  const { col1, col2 } = getColWidths(boxWidth);
18
22
  let spinner;