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.
- package/package.json +1 -1
- package/src/menus/ai-agent.js +36 -227
package/package.json
CHANGED
package/src/menus/ai-agent.js
CHANGED
|
@@ -782,9 +782,7 @@ const getOAuthConfig = (providerId) => {
|
|
|
782
782
|
|
|
783
783
|
/**
|
|
784
784
|
* Setup OAuth connection for any provider with OAuth support
|
|
785
|
-
*
|
|
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
|
-
//
|
|
798
|
-
|
|
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
|
|
842
|
-
* User copies the authorization code from the
|
|
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
|
-
//
|
|
855
|
-
const
|
|
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}
|
|
837
|
+
drawBoxHeaderContinue(`CONNECT ${config.name}`, boxWidth);
|
|
863
838
|
|
|
864
|
-
console.log(makeLine(chalk.yellow('
|
|
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
|
|
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
|
|
874
|
-
console.log(makeLine(chalk.white('
|
|
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
|
|
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 {
|
|
927
|
-
models = await
|
|
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
|
|
992
|
-
*
|
|
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
|
-
|
|
996
|
-
|
|
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
|
/**
|