hedgequantx 2.6.75 → 2.6.77

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.6.75",
3
+ "version": "2.6.77",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -858,13 +858,22 @@ const setupBrowserOAuth = async (provider, config) => {
858
858
  } else {
859
859
  console.log(makeLine(chalk.yellow('COULD NOT OPEN BROWSER (VPS/SSH?)')));
860
860
  console.log(makeLine(''));
861
- console.log(makeLine(chalk.white('AFTER LOGGING IN, YOU WILL SEE A CODE')));
862
- console.log(makeLine(chalk.white('COPY THE ENTIRE CODE AND PASTE IT BELOW')));
863
- console.log(makeLine(''));
864
- if (config.codeFormat) {
865
- console.log(makeLine(chalk.white(`THE CODE LOOKS LIKE: ${config.codeFormat}`)));
861
+
862
+ // Different instructions for different providers
863
+ if (provider.id === 'anthropic') {
864
+ console.log(makeLine(chalk.white('AFTER LOGGING IN, YOU WILL SEE A CODE')));
865
+ console.log(makeLine(chalk.white('COPY THE ENTIRE CODE AND PASTE IT BELOW')));
866
866
  console.log(makeLine(''));
867
+ console.log(makeLine(chalk.white('THE CODE LOOKS LIKE: abc123...#xyz789...')));
868
+ } else {
869
+ // Gemini, OpenAI, iFlow redirect to localhost - need full URL
870
+ console.log(makeLine(chalk.white('AFTER LOGGING IN, YOU WILL SEE A BLANK PAGE')));
871
+ console.log(makeLine(chalk.white('THE URL WILL START WITH: localhost:...')));
872
+ console.log(makeLine(''));
873
+ console.log(makeLine(chalk.green('COPY THE ENTIRE URL FROM THE ADDRESS BAR')));
874
+ console.log(makeLine(chalk.white('AND PASTE IT BELOW')));
867
875
  }
876
+ console.log(makeLine(''));
868
877
  console.log(makeLine(chalk.white('TYPE < TO CANCEL')));
869
878
  drawBoxFooter(boxWidth);
870
879
  // Display URL outside the box for easy copy-paste (no line breaks)
@@ -875,24 +884,41 @@ const setupBrowserOAuth = async (provider, config) => {
875
884
  console.log();
876
885
  }
877
886
 
878
- const code = await prompts.textInput(chalk.cyan('PASTE AUTHORIZATION CODE:'));
887
+ const promptText = provider.id === 'anthropic'
888
+ ? 'PASTE AUTHORIZATION CODE:'
889
+ : 'PASTE FULL CALLBACK URL:';
890
+
891
+ const input = await prompts.textInput(chalk.cyan(promptText));
879
892
 
880
- if (!code || code === '<') {
893
+ if (!input || input === '<') {
881
894
  return await selectProviderOption(provider);
882
895
  }
883
896
 
897
+ // Extract code from URL if user pasted full callback URL
898
+ let code = input.trim();
899
+ if (code.includes('code=')) {
900
+ try {
901
+ const urlObj = new URL(code.replace('localhost', 'http://localhost'));
902
+ code = urlObj.searchParams.get('code') || code;
903
+ } catch (e) {
904
+ // Try regex extraction as fallback
905
+ const match = code.match(/[?&]code=([^&]+)/);
906
+ if (match) code = match[1];
907
+ }
908
+ }
909
+
884
910
  // Exchange code for tokens
885
911
  const spinner = ora({ text: 'EXCHANGING CODE FOR TOKENS...', color: 'cyan' }).start();
886
912
 
887
913
  let result;
888
914
  if (provider.id === 'anthropic') {
889
- result = await config.oauthModule.exchange(code.trim(), verifier);
915
+ result = await config.oauthModule.exchange(code, verifier);
890
916
  } else if (provider.id === 'gemini') {
891
- result = await config.oauthModule.exchange(code.trim());
917
+ result = await config.oauthModule.exchange(code);
892
918
  } else if (provider.id === 'iflow') {
893
- result = await config.oauthModule.exchange(code.trim(), redirectUri);
919
+ result = await config.oauthModule.exchange(code, redirectUri);
894
920
  } else {
895
- result = await config.oauthModule.exchange(code.trim(), verifier);
921
+ result = await config.oauthModule.exchange(code, verifier);
896
922
  }
897
923
 
898
924
  if (result.type === 'failed') {
@@ -981,8 +981,8 @@ const launchAlgo = async (service, account, contract, config) => {
981
981
  };
982
982
 
983
983
  // Start polling and UI refresh
984
- // UI refreshes every 250ms, P&L polling every 10s (WebSocket is primary for P&L)
985
- const refreshInterval = setInterval(() => { if (running) ui.render(stats); }, 250);
984
+ // UI refreshes every 500ms (reduced from 250ms to prevent flicker), P&L polling every 10s
985
+ const refreshInterval = setInterval(() => { if (running) ui.render(stats); }, 500);
986
986
  const pnlInterval = setInterval(() => { if (running) pollPnL(); }, 10000);
987
987
  pollPnL(); // Initial poll
988
988
 
@@ -382,18 +382,22 @@ class AlgoUI {
382
382
  this.buffer = '';
383
383
 
384
384
  if (this.firstDraw) {
385
+ // Enter alternate screen, hide cursor, clear
385
386
  this.buffer += '\x1B[?1049h\x1B[?25l\x1B[2J';
386
387
  this.firstDraw = false;
387
388
  }
388
389
 
390
+ // Move cursor to home position (no clear - reduces flicker)
389
391
  this.buffer += '\x1B[H';
390
392
  this._line('');
391
393
  this._drawHeader();
392
394
  this._drawStats(stats);
393
395
  this._drawLogs();
394
396
 
395
- process.stdout.write(this.buffer);
396
- this.isDrawing = false;
397
+ // Write buffer in one shot, then flush
398
+ process.stdout.write(this.buffer, () => {
399
+ this.isDrawing = false;
400
+ });
397
401
  }
398
402
 
399
403
  cleanup() {