hedgequantx 2.6.97 → 2.6.99

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/menus/ai-agent.js +36 -227
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "2.6.97",
3
+ "version": "2.6.99",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -782,9 +782,7 @@ const getOAuthConfig = (providerId) => {
782
782
 
783
783
  /**
784
784
  * Setup OAuth connection for any provider with OAuth support
785
- * Automatically detects environment and uses the appropriate method:
786
- * - Local (PC/Mac): Uses CLIProxyAPI for automatic token management
787
- * - Remote (VPS/Server): Uses cli.hedgequantx.com as OAuth relay
785
+ * Unified flow: copy code from URL (works on local and VPS)
788
786
  */
789
787
  const setupOAuthConnection = async (provider) => {
790
788
  const config = getOAuthConfig(provider.id);
@@ -794,52 +792,13 @@ const setupOAuthConnection = async (provider) => {
794
792
  return await selectProviderOption(provider);
795
793
  }
796
794
 
797
- // Check if we can open a browser locally
798
- const canUseBrowser = proxyManager.canOpenBrowser();
799
- const isServer = proxyManager.isServerEnvironment();
800
-
801
- // If on server or can't open browser, use remote OAuth
802
- if (isServer || !canUseBrowser) {
803
- // Only anthropic is supported for remote OAuth currently
804
- if (provider.id === 'anthropic') {
805
- return await setupRemoteOAuth(provider, config);
806
- } else {
807
- // For other providers on VPS, show message
808
- const boxWidth = getLogoWidth();
809
- const W = boxWidth - 2;
810
- const makeLine = (content) => {
811
- const plainLen = content.replace(/\x1b\[[0-9;]*m/g, '').length;
812
- const padding = W - plainLen;
813
- return chalk.cyan('║') + ' ' + content + ' '.repeat(Math.max(0, padding - 1)) + chalk.cyan('║');
814
- };
815
-
816
- console.clear();
817
- displayBanner();
818
- drawBoxHeaderContinue('SERVER DETECTED', boxWidth);
819
-
820
- console.log(makeLine(chalk.yellow('VPS/SERVER ENVIRONMENT DETECTED')));
821
- console.log(makeLine(''));
822
- console.log(makeLine(chalk.white('OAuth for this provider requires a browser.')));
823
- console.log(makeLine(''));
824
- console.log(makeLine(chalk.white('OPTIONS:')));
825
- console.log(makeLine(chalk.cyan('1. Use Claude (supports remote OAuth)')));
826
- console.log(makeLine(chalk.cyan('2. Use API Key instead of OAuth')));
827
- console.log(makeLine(chalk.cyan('3. Run this on a local machine first')));
828
- console.log(makeLine(''));
829
-
830
- drawBoxFooter(boxWidth);
831
- await prompts.waitForEnter();
832
- return await selectProviderOption(provider);
833
- }
834
- }
835
-
836
- // Local machine - use CLIProxyAPI
837
- return await setupProxyOAuth(provider, config);
795
+ // Use unified manual flow for all providers and environments
796
+ return await setupRemoteOAuth(provider, config);
838
797
  };
839
798
 
840
799
  /**
841
- * Setup OAuth via Manual Code Entry (for VPS/Server users)
842
- * User copies the authorization code from the browser
800
+ * Setup OAuth via Manual Code Entry (unified flow for local and VPS)
801
+ * User copies the authorization code from the URL or page
843
802
  */
844
803
  const setupRemoteOAuth = async (provider, config) => {
845
804
  const boxWidth = getLogoWidth();
@@ -851,31 +810,46 @@ const setupRemoteOAuth = async (provider, config) => {
851
810
  return chalk.cyan('║') + ' ' + content + ' '.repeat(Math.max(0, padding - 1)) + chalk.cyan('║');
852
811
  };
853
812
 
854
- // Generate OAuth URL using the existing oauth module
855
- const authResult = oauthAnthropic.authorize('max');
813
+ // Get the right OAuth module for this provider
814
+ const oauthModules = {
815
+ anthropic: oauthAnthropic,
816
+ openai: oauthOpenai,
817
+ gemini: oauthGemini,
818
+ qwen: oauthQwen,
819
+ iflow: oauthIflow
820
+ };
821
+
822
+ const oauthModule = oauthModules[provider.id];
823
+ if (!oauthModule) {
824
+ console.log(chalk.red(`OAuth not supported for ${provider.id}`));
825
+ await prompts.waitForEnter();
826
+ return await selectProviderOption(provider);
827
+ }
828
+
829
+ // Generate OAuth URL using the provider's oauth module
830
+ const authResult = oauthModule.authorize(config.optionId || 'max');
856
831
  const url = authResult.url;
857
832
  const verifier = authResult.verifier;
858
833
 
859
834
  // Show instructions
860
835
  console.clear();
861
836
  displayBanner();
862
- drawBoxHeaderContinue(`CONNECT ${config.name} (VPS MODE)`, boxWidth);
837
+ drawBoxHeaderContinue(`CONNECT ${config.name}`, boxWidth);
863
838
 
864
- console.log(makeLine(chalk.yellow('MANUAL AUTHORIZATION')));
839
+ console.log(makeLine(chalk.yellow('CONNECT YOUR ACCOUNT')));
865
840
  console.log(makeLine(''));
866
- console.log(makeLine(chalk.white('1. OPEN THE LINK BELOW IN ANY BROWSER')));
867
- console.log(makeLine(chalk.white(' (Phone, laptop, any device)')));
841
+ console.log(makeLine(chalk.white('1. OPEN THE LINK BELOW IN YOUR BROWSER')));
868
842
  console.log(makeLine(''));
869
843
  console.log(makeLine(chalk.white(`2. LOGIN WITH YOUR ${config.accountName.toUpperCase()} ACCOUNT`)));
870
844
  console.log(makeLine(''));
871
845
  console.log(makeLine(chalk.white('3. CLICK "AUTHORIZE"')));
872
846
  console.log(makeLine(''));
873
- console.log(makeLine(chalk.green('4. COPY THE CODE SHOWN ON SCREEN')));
874
- console.log(makeLine(chalk.white(' (Format: abc123...#xyz789...)')));
847
+ console.log(makeLine(chalk.green('4. COPY THE CODE FROM THE URL BAR')));
848
+ console.log(makeLine(chalk.white(' Look for: code=XXXXXX in the URL')));
849
+ console.log(makeLine(chalk.white(' Copy everything after code= until &')));
875
850
  console.log(makeLine(''));
876
851
  console.log(makeLine(chalk.white('5. PASTE THE CODE BELOW')));
877
852
  console.log(makeLine(''));
878
- console.log(makeLine(chalk.white('TYPE < TO CANCEL')));
879
853
 
880
854
  drawBoxFooter(boxWidth);
881
855
 
@@ -896,7 +870,7 @@ const setupRemoteOAuth = async (provider, config) => {
896
870
  // Exchange code for tokens
897
871
  const spinner = ora({ text: 'Exchanging code for tokens...', color: 'cyan' }).start();
898
872
 
899
- const result = await oauthAnthropic.exchange(code.trim(), verifier);
873
+ const result = await oauthModule.exchange(code.trim(), verifier);
900
874
 
901
875
  if (result.type === 'failed') {
902
876
  spinner.fail(`Authentication failed: ${result.error || 'Invalid code'}`);
@@ -923,8 +897,8 @@ const setupRemoteOAuth = async (provider, config) => {
923
897
 
924
898
  let models = [];
925
899
  try {
926
- const { fetchAnthropicModelsOAuth } = require('../services/ai/client');
927
- models = await fetchAnthropicModelsOAuth(result.access);
900
+ const { fetchModelsWithOAuth } = require('../services/ai/client');
901
+ models = await fetchModelsWithOAuth(provider.id, result.access);
928
902
  } catch (e) {
929
903
  // Ignore - will use defaults
930
904
  }
@@ -988,177 +962,12 @@ const getDefaultModelsForProvider = (providerId) => {
988
962
  };
989
963
 
990
964
  /**
991
- * Setup OAuth via CLIProxyAPI (automatic local proxy)
992
- * This is the simplified flow for users with subscription plans on local machines
965
+ * Setup OAuth via Manual Code Entry (unified flow for local and VPS)
966
+ * User copies the authorization code from the URL or page
993
967
  */
994
968
  const setupProxyOAuth = async (provider, config) => {
995
- const boxWidth = getLogoWidth();
996
- const W = boxWidth - 2;
997
-
998
- const makeLine = (content) => {
999
- const plainLen = content.replace(/\x1b\[[0-9;]*m/g, '').length;
1000
- const padding = W - plainLen;
1001
- return chalk.cyan('║') + ' ' + content + ' '.repeat(Math.max(0, padding - 1)) + chalk.cyan('║');
1002
- };
1003
-
1004
- console.clear();
1005
- displayBanner();
1006
- drawBoxHeaderContinue(`CONNECT ${config.name}`, boxWidth);
1007
-
1008
- console.log(makeLine(chalk.yellow('AUTOMATIC SETUP')));
1009
- console.log(makeLine(''));
1010
- console.log(makeLine(chalk.white('PREPARING CONNECTION...')));
1011
-
1012
- drawBoxFooter(boxWidth);
1013
-
1014
- // Ensure proxy is running (will install if needed)
1015
- const spinner = ora({ text: 'Setting up AI connection...', color: 'cyan' }).start();
1016
-
1017
- try {
1018
- await proxyManager.ensureRunning((msg) => {
1019
- spinner.text = msg;
1020
- });
1021
- } catch (error) {
1022
- spinner.fail(`Setup failed: ${error.message}`);
1023
- await prompts.waitForEnter();
1024
- return await selectProviderOption(provider);
1025
- }
1026
-
1027
- // Get OAuth URL from proxy
1028
- spinner.text = 'Generating authorization link...';
1029
-
1030
- let authData;
1031
- try {
1032
- authData = await proxyManager.getAuthUrl(provider.id);
1033
- } catch (error) {
1034
- spinner.fail(`Failed to get auth URL: ${error.message}`);
1035
- await prompts.waitForEnter();
1036
- return await selectProviderOption(provider);
1037
- }
1038
-
1039
- spinner.stop();
1040
-
1041
- // Show URL to user
1042
- console.clear();
1043
- displayBanner();
1044
- drawBoxHeaderContinue(`CONNECT ${config.name}`, boxWidth);
1045
-
1046
- console.log(makeLine(chalk.yellow('LOGIN TO YOUR ACCOUNT')));
1047
- console.log(makeLine(''));
1048
- console.log(makeLine(chalk.white('1. OPEN THE LINK BELOW IN YOUR BROWSER')));
1049
- console.log(makeLine(chalk.white(`2. LOGIN WITH YOUR ${config.accountName.toUpperCase()} ACCOUNT`)));
1050
- console.log(makeLine(chalk.white('3. AUTHORIZE THE APPLICATION')));
1051
- console.log(makeLine(''));
1052
- console.log(makeLine(chalk.green('THE CONNECTION WILL BE AUTOMATIC!')));
1053
- console.log(makeLine(chalk.white('NO CODE TO COPY - JUST LOGIN AND AUTHORIZE')));
1054
- console.log(makeLine(''));
1055
- console.log(makeLine(chalk.white('PRESS ENTER AFTER YOU AUTHORIZED...')));
1056
-
1057
- drawBoxFooter(boxWidth);
1058
-
1059
- // Display URL outside the box for easy copy
1060
- console.log();
1061
- console.log(chalk.yellow(' OPEN THIS URL IN YOUR BROWSER:'));
1062
- console.log();
1063
- console.log(chalk.cyan(` ${authData.url}`));
1064
- console.log();
1065
-
1066
- // Try to open browser automatically
1067
- const browserOpened = await openBrowser(authData.url);
1068
- if (browserOpened) {
1069
- console.log(chalk.green(' Browser opened automatically!'));
1070
- console.log();
1071
- }
1072
-
1073
- // Wait for user to press enter
1074
- await prompts.waitForEnter();
1075
-
1076
- // Check if auth was successful
1077
- const authSpinner = ora({ text: 'Checking authorization...', color: 'cyan' }).start();
1078
-
1079
- try {
1080
- // Poll for auth status (with timeout)
1081
- const startTime = Date.now();
1082
- const timeout = 60000; // 1 minute
1083
-
1084
- while (Date.now() - startTime < timeout) {
1085
- const status = await proxyManager.pollAuthStatus(authData.state);
1086
-
1087
- if (status.status === 'ok') {
1088
- authSpinner.succeed('Authorization successful!');
1089
- break;
1090
- } else if (status.status === 'error') {
1091
- authSpinner.fail(`Authorization failed: ${status.error}`);
1092
- await prompts.waitForEnter();
1093
- return await selectProviderOption(provider);
1094
- }
1095
-
1096
- // Still waiting
1097
- await new Promise(resolve => setTimeout(resolve, 2000));
1098
- }
1099
- } catch (error) {
1100
- // If polling fails, try to get models anyway (user might have authorized)
1101
- authSpinner.text = 'Verifying connection...';
1102
- }
1103
-
1104
- // Fetch available models from proxy
1105
- authSpinner.text = 'Fetching available models...';
1106
-
1107
- let models = [];
1108
- try {
1109
- models = await proxyManager.getModels();
1110
- } catch (e) {
1111
- // Try again
1112
- await new Promise(resolve => setTimeout(resolve, 2000));
1113
- models = await proxyManager.getModels();
1114
- }
1115
-
1116
- if (!models || models.length === 0) {
1117
- authSpinner.fail('No models available - authorization may have failed');
1118
- console.log(chalk.red('\n Please try again and make sure to complete the login.'));
1119
- await prompts.waitForEnter();
1120
- return await selectProviderOption(provider);
1121
- }
1122
-
1123
- // Filter models for this provider
1124
- const providerModels = models.filter(m => {
1125
- const modelLower = m.toLowerCase();
1126
- if (provider.id === 'anthropic') return modelLower.includes('claude');
1127
- if (provider.id === 'openai') return modelLower.includes('gpt') || modelLower.includes('o1') || modelLower.includes('o3');
1128
- if (provider.id === 'gemini') return modelLower.includes('gemini');
1129
- if (provider.id === 'qwen') return modelLower.includes('qwen');
1130
- if (provider.id === 'iflow') return true; // iFlow has various models
1131
- return true;
1132
- });
1133
-
1134
- const finalModels = providerModels.length > 0 ? providerModels : models;
1135
-
1136
- authSpinner.succeed(`Found ${finalModels.length} models`);
1137
-
1138
- // Let user select model
1139
- const selectedModel = await selectModelFromList(finalModels, config.name);
1140
- if (!selectedModel) {
1141
- return await selectProviderOption(provider);
1142
- }
1143
-
1144
- // Save agent configuration (using proxy)
1145
- const credentials = {
1146
- useProxy: true,
1147
- proxyPort: proxyManager.PROXY_PORT
1148
- };
1149
-
1150
- try {
1151
- await aiService.addAgent(provider.id, config.optionId, credentials, selectedModel, config.agentName);
1152
-
1153
- console.log(chalk.green(`\n CONNECTED TO ${config.name}`));
1154
- console.log(chalk.white(` MODEL: ${selectedModel}`));
1155
- console.log(chalk.white(' UNLIMITED USAGE WITH YOUR SUBSCRIPTION'));
1156
- } catch (error) {
1157
- console.log(chalk.red(`\n FAILED TO SAVE: ${error.message}`));
1158
- }
1159
-
1160
- await prompts.waitForEnter();
1161
- return await aiAgentMenu();
969
+ // Use the same flow as VPS - it works everywhere
970
+ return await setupRemoteOAuth(provider, config);
1162
971
  };
1163
972
 
1164
973
  /**