hedgequantx 2.6.96 → 2.6.98

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 +60 -219
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "2.6.96",
3
+ "version": "2.6.98",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -838,8 +838,8 @@ const setupOAuthConnection = async (provider) => {
838
838
  };
839
839
 
840
840
  /**
841
- * Setup OAuth via Remote Relay (for VPS/Server users)
842
- * Uses cli.hedgequantx.com to receive OAuth callbacks
841
+ * Setup OAuth via Manual Code Entry (unified flow for local and VPS)
842
+ * User copies the authorization code from the URL or page
843
843
  */
844
844
  const setupRemoteOAuth = async (provider, config) => {
845
845
  const boxWidth = getLogoWidth();
@@ -851,44 +851,29 @@ const setupRemoteOAuth = async (provider, config) => {
851
851
  return chalk.cyan('║') + ' ' + content + ' '.repeat(Math.max(0, padding - 1)) + chalk.cyan('║');
852
852
  };
853
853
 
854
- console.clear();
855
- displayBanner();
856
- drawBoxHeaderContinue(`CONNECT ${config.name}`, boxWidth);
857
-
858
- console.log(makeLine(chalk.yellow('REMOTE AUTHENTICATION (VPS/SERVER)')));
859
- console.log(makeLine(''));
860
- console.log(makeLine(chalk.white('CREATING SECURE SESSION...')));
861
-
862
- drawBoxFooter(boxWidth);
863
-
864
- const spinner = ora({ text: 'Creating OAuth session...', color: 'cyan' }).start();
865
-
866
- let sessionData;
867
- try {
868
- sessionData = await proxyManager.createRemoteSession(provider.id);
869
- } catch (error) {
870
- spinner.fail(`Failed to create session: ${error.message}`);
871
- await prompts.waitForEnter();
872
- return await selectProviderOption(provider);
873
- }
874
-
875
- spinner.stop();
854
+ // Generate OAuth URL using the existing oauth module
855
+ const authResult = oauthAnthropic.authorize('max');
856
+ const url = authResult.url;
857
+ const verifier = authResult.verifier;
876
858
 
877
- // Show URL to user
859
+ // Show instructions
878
860
  console.clear();
879
861
  displayBanner();
880
862
  drawBoxHeaderContinue(`CONNECT ${config.name}`, boxWidth);
881
863
 
882
- console.log(makeLine(chalk.yellow('LOGIN TO YOUR ACCOUNT')));
864
+ console.log(makeLine(chalk.yellow('CONNECT YOUR ACCOUNT')));
883
865
  console.log(makeLine(''));
884
- console.log(makeLine(chalk.white('1. OPEN THE LINK BELOW IN ANY BROWSER')));
885
- console.log(makeLine(chalk.white(' (Phone, laptop, any device)')));
866
+ console.log(makeLine(chalk.white('1. OPEN THE LINK BELOW IN YOUR BROWSER')));
886
867
  console.log(makeLine(''));
887
868
  console.log(makeLine(chalk.white(`2. LOGIN WITH YOUR ${config.accountName.toUpperCase()} ACCOUNT`)));
888
869
  console.log(makeLine(''));
889
- console.log(makeLine(chalk.white('3. AUTHORIZE THE APPLICATION')));
870
+ console.log(makeLine(chalk.white('3. CLICK "AUTHORIZE"')));
890
871
  console.log(makeLine(''));
891
- console.log(makeLine(chalk.green('THE CLI WILL DETECT WHEN YOU AUTHORIZE')));
872
+ console.log(makeLine(chalk.green('4. COPY THE CODE FROM THE URL BAR')));
873
+ console.log(makeLine(chalk.white(' Look for: code=XXXXXX in the URL')));
874
+ console.log(makeLine(chalk.white(' Copy everything after code= until &')));
875
+ console.log(makeLine(''));
876
+ console.log(makeLine(chalk.white('5. PASTE THE CODE BELOW')));
892
877
  console.log(makeLine(''));
893
878
 
894
879
  drawBoxFooter(boxWidth);
@@ -897,40 +882,61 @@ const setupRemoteOAuth = async (provider, config) => {
897
882
  console.log();
898
883
  console.log(chalk.yellow(' OPEN THIS URL IN YOUR BROWSER:'));
899
884
  console.log();
900
- console.log(chalk.cyan(` ${sessionData.authUrl}`));
885
+ console.log(chalk.cyan(` ${url}`));
901
886
  console.log();
902
887
 
903
- // Poll for completion
904
- const authSpinner = ora({ text: 'Waiting for authorization...', color: 'cyan' }).start();
888
+ // Get code from user
889
+ const code = await prompts.textInput(chalk.cyan('PASTE AUTHORIZATION CODE:'));
905
890
 
906
- let tokenData;
907
- try {
908
- tokenData = await proxyManager.waitForRemoteAuth(sessionData.sessionId, 300000, (msg) => {
909
- authSpinner.text = msg;
910
- });
911
- } catch (error) {
912
- authSpinner.fail(`Authorization failed: ${error.message}`);
891
+ if (!code || code.trim() === '<' || code.trim() === '') {
892
+ return await selectProviderOption(provider);
893
+ }
894
+
895
+ // Exchange code for tokens
896
+ const spinner = ora({ text: 'Exchanging code for tokens...', color: 'cyan' }).start();
897
+
898
+ const result = await oauthAnthropic.exchange(code.trim(), verifier);
899
+
900
+ if (result.type === 'failed') {
901
+ spinner.fail(`Authentication failed: ${result.error || 'Invalid code'}`);
913
902
  await prompts.waitForEnter();
914
903
  return await selectProviderOption(provider);
915
904
  }
916
905
 
917
- authSpinner.succeed('Authorization successful!');
906
+ spinner.succeed('Authorization successful!');
918
907
 
919
908
  // Save credentials
920
909
  const credentials = {
921
910
  oauth: {
922
- access: tokenData.tokens.access,
923
- refresh: tokenData.tokens.refresh,
924
- expires: tokenData.tokens.expires || Date.now() + 3600000
925
- },
926
- useRemoteOAuth: true
911
+ access: result.access,
912
+ refresh: result.refresh,
913
+ expires: result.expires,
914
+ apiKey: result.apiKey,
915
+ email: result.email
916
+ }
927
917
  };
928
918
 
929
- // For remote OAuth, we need to use the tokens directly with the provider API
930
- // Let user select a model (use a default list since we can't query without local proxy)
931
- const defaultModels = getDefaultModelsForProvider(provider.id);
919
+ // Try to fetch models with the new token
920
+ spinner.text = 'Fetching available models...';
921
+ spinner.start();
932
922
 
933
- const selectedModel = await selectModelFromList(defaultModels, config.name);
923
+ let models = [];
924
+ try {
925
+ const { fetchAnthropicModelsOAuth } = require('../services/ai/client');
926
+ models = await fetchAnthropicModelsOAuth(result.access);
927
+ } catch (e) {
928
+ // Ignore - will use defaults
929
+ }
930
+
931
+ // Use defaults if API doesn't return models
932
+ if (!models || models.length === 0) {
933
+ models = getDefaultModelsForProvider(provider.id);
934
+ }
935
+
936
+ spinner.succeed(`Found ${models.length} models`);
937
+
938
+ // Let user select model
939
+ const selectedModel = await selectModelFromList(models, config.name);
934
940
  if (!selectedModel) {
935
941
  return await selectProviderOption(provider);
936
942
  }
@@ -981,177 +987,12 @@ const getDefaultModelsForProvider = (providerId) => {
981
987
  };
982
988
 
983
989
  /**
984
- * Setup OAuth via CLIProxyAPI (automatic local proxy)
985
- * This is the simplified flow for users with subscription plans on local machines
990
+ * Setup OAuth via Manual Code Entry (unified flow for local and VPS)
991
+ * User copies the authorization code from the URL or page
986
992
  */
987
993
  const setupProxyOAuth = async (provider, config) => {
988
- const boxWidth = getLogoWidth();
989
- const W = boxWidth - 2;
990
-
991
- const makeLine = (content) => {
992
- const plainLen = content.replace(/\x1b\[[0-9;]*m/g, '').length;
993
- const padding = W - plainLen;
994
- return chalk.cyan('║') + ' ' + content + ' '.repeat(Math.max(0, padding - 1)) + chalk.cyan('║');
995
- };
996
-
997
- console.clear();
998
- displayBanner();
999
- drawBoxHeaderContinue(`CONNECT ${config.name}`, boxWidth);
1000
-
1001
- console.log(makeLine(chalk.yellow('AUTOMATIC SETUP')));
1002
- console.log(makeLine(''));
1003
- console.log(makeLine(chalk.white('PREPARING CONNECTION...')));
1004
-
1005
- drawBoxFooter(boxWidth);
1006
-
1007
- // Ensure proxy is running (will install if needed)
1008
- const spinner = ora({ text: 'Setting up AI connection...', color: 'cyan' }).start();
1009
-
1010
- try {
1011
- await proxyManager.ensureRunning((msg) => {
1012
- spinner.text = msg;
1013
- });
1014
- } catch (error) {
1015
- spinner.fail(`Setup failed: ${error.message}`);
1016
- await prompts.waitForEnter();
1017
- return await selectProviderOption(provider);
1018
- }
1019
-
1020
- // Get OAuth URL from proxy
1021
- spinner.text = 'Generating authorization link...';
1022
-
1023
- let authData;
1024
- try {
1025
- authData = await proxyManager.getAuthUrl(provider.id);
1026
- } catch (error) {
1027
- spinner.fail(`Failed to get auth URL: ${error.message}`);
1028
- await prompts.waitForEnter();
1029
- return await selectProviderOption(provider);
1030
- }
1031
-
1032
- spinner.stop();
1033
-
1034
- // Show URL to user
1035
- console.clear();
1036
- displayBanner();
1037
- drawBoxHeaderContinue(`CONNECT ${config.name}`, boxWidth);
1038
-
1039
- console.log(makeLine(chalk.yellow('LOGIN TO YOUR ACCOUNT')));
1040
- console.log(makeLine(''));
1041
- console.log(makeLine(chalk.white('1. OPEN THE LINK BELOW IN YOUR BROWSER')));
1042
- console.log(makeLine(chalk.white(`2. LOGIN WITH YOUR ${config.accountName.toUpperCase()} ACCOUNT`)));
1043
- console.log(makeLine(chalk.white('3. AUTHORIZE THE APPLICATION')));
1044
- console.log(makeLine(''));
1045
- console.log(makeLine(chalk.green('THE CONNECTION WILL BE AUTOMATIC!')));
1046
- console.log(makeLine(chalk.white('NO CODE TO COPY - JUST LOGIN AND AUTHORIZE')));
1047
- console.log(makeLine(''));
1048
- console.log(makeLine(chalk.white('PRESS ENTER AFTER YOU AUTHORIZED...')));
1049
-
1050
- drawBoxFooter(boxWidth);
1051
-
1052
- // Display URL outside the box for easy copy
1053
- console.log();
1054
- console.log(chalk.yellow(' OPEN THIS URL IN YOUR BROWSER:'));
1055
- console.log();
1056
- console.log(chalk.cyan(` ${authData.url}`));
1057
- console.log();
1058
-
1059
- // Try to open browser automatically
1060
- const browserOpened = await openBrowser(authData.url);
1061
- if (browserOpened) {
1062
- console.log(chalk.green(' Browser opened automatically!'));
1063
- console.log();
1064
- }
1065
-
1066
- // Wait for user to press enter
1067
- await prompts.waitForEnter();
1068
-
1069
- // Check if auth was successful
1070
- const authSpinner = ora({ text: 'Checking authorization...', color: 'cyan' }).start();
1071
-
1072
- try {
1073
- // Poll for auth status (with timeout)
1074
- const startTime = Date.now();
1075
- const timeout = 60000; // 1 minute
1076
-
1077
- while (Date.now() - startTime < timeout) {
1078
- const status = await proxyManager.pollAuthStatus(authData.state);
1079
-
1080
- if (status.status === 'ok') {
1081
- authSpinner.succeed('Authorization successful!');
1082
- break;
1083
- } else if (status.status === 'error') {
1084
- authSpinner.fail(`Authorization failed: ${status.error}`);
1085
- await prompts.waitForEnter();
1086
- return await selectProviderOption(provider);
1087
- }
1088
-
1089
- // Still waiting
1090
- await new Promise(resolve => setTimeout(resolve, 2000));
1091
- }
1092
- } catch (error) {
1093
- // If polling fails, try to get models anyway (user might have authorized)
1094
- authSpinner.text = 'Verifying connection...';
1095
- }
1096
-
1097
- // Fetch available models from proxy
1098
- authSpinner.text = 'Fetching available models...';
1099
-
1100
- let models = [];
1101
- try {
1102
- models = await proxyManager.getModels();
1103
- } catch (e) {
1104
- // Try again
1105
- await new Promise(resolve => setTimeout(resolve, 2000));
1106
- models = await proxyManager.getModels();
1107
- }
1108
-
1109
- if (!models || models.length === 0) {
1110
- authSpinner.fail('No models available - authorization may have failed');
1111
- console.log(chalk.red('\n Please try again and make sure to complete the login.'));
1112
- await prompts.waitForEnter();
1113
- return await selectProviderOption(provider);
1114
- }
1115
-
1116
- // Filter models for this provider
1117
- const providerModels = models.filter(m => {
1118
- const modelLower = m.toLowerCase();
1119
- if (provider.id === 'anthropic') return modelLower.includes('claude');
1120
- if (provider.id === 'openai') return modelLower.includes('gpt') || modelLower.includes('o1') || modelLower.includes('o3');
1121
- if (provider.id === 'gemini') return modelLower.includes('gemini');
1122
- if (provider.id === 'qwen') return modelLower.includes('qwen');
1123
- if (provider.id === 'iflow') return true; // iFlow has various models
1124
- return true;
1125
- });
1126
-
1127
- const finalModels = providerModels.length > 0 ? providerModels : models;
1128
-
1129
- authSpinner.succeed(`Found ${finalModels.length} models`);
1130
-
1131
- // Let user select model
1132
- const selectedModel = await selectModelFromList(finalModels, config.name);
1133
- if (!selectedModel) {
1134
- return await selectProviderOption(provider);
1135
- }
1136
-
1137
- // Save agent configuration (using proxy)
1138
- const credentials = {
1139
- useProxy: true,
1140
- proxyPort: proxyManager.PROXY_PORT
1141
- };
1142
-
1143
- try {
1144
- await aiService.addAgent(provider.id, config.optionId, credentials, selectedModel, config.agentName);
1145
-
1146
- console.log(chalk.green(`\n CONNECTED TO ${config.name}`));
1147
- console.log(chalk.white(` MODEL: ${selectedModel}`));
1148
- console.log(chalk.white(' UNLIMITED USAGE WITH YOUR SUBSCRIPTION'));
1149
- } catch (error) {
1150
- console.log(chalk.red(`\n FAILED TO SAVE: ${error.message}`));
1151
- }
1152
-
1153
- await prompts.waitForEnter();
1154
- return await aiAgentMenu();
994
+ // Use the same flow as VPS - it works everywhere
995
+ return await setupRemoteOAuth(provider, config);
1155
996
  };
1156
997
 
1157
998
  /**