hedgequantx 2.7.83 → 2.7.85
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
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const chalk = require('chalk');
|
|
8
8
|
const { centerText, visibleLength } = require('../ui');
|
|
9
|
+
const cliproxy = require('../services/cliproxy');
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Draw a 2-column row with perfect alignment
|
|
@@ -94,6 +95,9 @@ const drawProvidersTable = (providers, config, boxWidth) => {
|
|
|
94
95
|
const W = boxWidth - 2;
|
|
95
96
|
const colWidth = Math.floor(W / 2);
|
|
96
97
|
|
|
98
|
+
// Get connected providers (have auth files)
|
|
99
|
+
const connected = cliproxy.getConnectedProviders();
|
|
100
|
+
|
|
97
101
|
// New rectangle (banner is always closed)
|
|
98
102
|
console.log(chalk.cyan('╔' + '═'.repeat(W) + '╗'));
|
|
99
103
|
console.log(chalk.cyan('║') + chalk.yellow.bold(centerText('AI AGENTS CONFIGURATION', W)) + chalk.cyan('║'));
|
|
@@ -104,9 +108,9 @@ const drawProvidersTable = (providers, config, boxWidth) => {
|
|
|
104
108
|
// Find max name length across ALL providers for consistent alignment
|
|
105
109
|
const maxNameLen = Math.max(...providers.map(p => p.name.length));
|
|
106
110
|
|
|
107
|
-
// Fixed format: "[N] NAME" where
|
|
108
|
-
// Total content width = 3 ([N]) + 1 (space) + maxNameLen
|
|
109
|
-
const contentWidth = 3 + 1 + maxNameLen
|
|
111
|
+
// Fixed format: "● [N] NAME" where ● is yellow if connected (has auth file)
|
|
112
|
+
// Total content width = 2 (● ) + 3 ([N]) + 1 (space) + maxNameLen
|
|
113
|
+
const contentWidth = 2 + 3 + 1 + maxNameLen;
|
|
110
114
|
const leftPad = Math.floor((colWidth - contentWidth) / 2);
|
|
111
115
|
const rightPad = Math.floor(((W - colWidth) - contentWidth) / 2);
|
|
112
116
|
|
|
@@ -118,12 +122,13 @@ const drawProvidersTable = (providers, config, boxWidth) => {
|
|
|
118
122
|
let leftCol = '';
|
|
119
123
|
if (leftP) {
|
|
120
124
|
const num = row + 1;
|
|
121
|
-
|
|
122
|
-
const
|
|
125
|
+
// Show yellow dot if provider has auth file (connected via OAuth)
|
|
126
|
+
const isConnected = connected[leftP.id] || config.providers[leftP.id]?.active;
|
|
127
|
+
const status = isConnected ? chalk.yellow('● ') : ' ';
|
|
123
128
|
const name = leftP.provider ? leftP.provider.name : leftP.name;
|
|
124
129
|
const namePadded = name.toUpperCase().padEnd(maxNameLen);
|
|
125
|
-
const content = chalk.cyan(`[${num}]`) + ' ' + chalk[leftP.color](namePadded)
|
|
126
|
-
const contentLen = 3 + 1 + maxNameLen
|
|
130
|
+
const content = status + chalk.cyan(`[${num}]`) + ' ' + chalk[leftP.color](namePadded);
|
|
131
|
+
const contentLen = 2 + 3 + 1 + maxNameLen;
|
|
127
132
|
const padR = colWidth - leftPad - contentLen;
|
|
128
133
|
leftCol = ' '.repeat(leftPad) + content + ' '.repeat(Math.max(0, padR));
|
|
129
134
|
} else {
|
|
@@ -135,11 +140,13 @@ const drawProvidersTable = (providers, config, boxWidth) => {
|
|
|
135
140
|
const rightColWidth = W - colWidth;
|
|
136
141
|
if (rightP) {
|
|
137
142
|
const num = row + rows + 1;
|
|
138
|
-
|
|
143
|
+
// Show yellow dot if provider has auth file (connected via OAuth)
|
|
144
|
+
const isConnected = connected[rightP.id] || config.providers[rightP.id]?.active;
|
|
145
|
+
const status = isConnected ? chalk.yellow('● ') : ' ';
|
|
139
146
|
const name = rightP.provider ? rightP.provider.name : rightP.name;
|
|
140
147
|
const namePadded = name.toUpperCase().padEnd(maxNameLen);
|
|
141
|
-
const content = chalk.cyan(`[${num}]`) + ' ' + chalk[rightP.color](namePadded)
|
|
142
|
-
const contentLen = 3 + 1 + maxNameLen
|
|
148
|
+
const content = status + chalk.cyan(`[${num}]`) + ' ' + chalk[rightP.color](namePadded);
|
|
149
|
+
const contentLen = 2 + 3 + 1 + maxNameLen;
|
|
143
150
|
const padR2 = rightColWidth - rightPad - contentLen;
|
|
144
151
|
rightCol = ' '.repeat(rightPad) + content + ' '.repeat(Math.max(0, padR2));
|
|
145
152
|
} else {
|
package/src/pages/ai-agents.js
CHANGED
|
@@ -95,11 +95,8 @@ const selectModel = async (provider, apiKey) => {
|
|
|
95
95
|
return selectModelFromList(provider, result.models, boxWidth);
|
|
96
96
|
};
|
|
97
97
|
|
|
98
|
-
/**
|
|
98
|
+
/** Activate a provider (multiple providers can be active at the same time) */
|
|
99
99
|
const activateProvider = (config, providerId, data) => {
|
|
100
|
-
Object.keys(config.providers).forEach(id => {
|
|
101
|
-
if (config.providers[id]) config.providers[id].active = false;
|
|
102
|
-
});
|
|
103
100
|
if (!config.providers[providerId]) config.providers[providerId] = {};
|
|
104
101
|
Object.assign(config.providers[providerId], data, { active: true, configuredAt: new Date().toISOString() });
|
|
105
102
|
};
|
|
@@ -150,6 +150,29 @@ const fetchProviderModels = async (providerId) => {
|
|
|
150
150
|
};
|
|
151
151
|
};
|
|
152
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Check which providers have auth files (are connected)
|
|
155
|
+
* @returns {Object} { anthropic: true/false, google: true/false, openai: true/false, qwen: true/false }
|
|
156
|
+
*/
|
|
157
|
+
const getConnectedProviders = () => {
|
|
158
|
+
const fs = require('fs');
|
|
159
|
+
const connected = { anthropic: false, google: false, openai: false, qwen: false };
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
if (!fs.existsSync(AUTH_DIR)) return connected;
|
|
163
|
+
|
|
164
|
+
const files = fs.readdirSync(AUTH_DIR);
|
|
165
|
+
for (const file of files) {
|
|
166
|
+
if (file.startsWith('claude-') && file.endsWith('.json')) connected.anthropic = true;
|
|
167
|
+
if (file.startsWith('gemini-') && file.endsWith('.json')) connected.google = true;
|
|
168
|
+
if (file.startsWith('codex-') && file.endsWith('.json')) connected.openai = true;
|
|
169
|
+
if (file.startsWith('qwen-') && file.endsWith('.json')) connected.qwen = true;
|
|
170
|
+
}
|
|
171
|
+
} catch (e) { /* ignore */ }
|
|
172
|
+
|
|
173
|
+
return connected;
|
|
174
|
+
};
|
|
175
|
+
|
|
153
176
|
/**
|
|
154
177
|
* Chat completion request
|
|
155
178
|
* @param {string} model - Model ID
|
|
@@ -197,5 +220,6 @@ module.exports = {
|
|
|
197
220
|
fetchLocal,
|
|
198
221
|
fetchModels,
|
|
199
222
|
fetchProviderModels,
|
|
223
|
+
getConnectedProviders,
|
|
200
224
|
chatCompletion
|
|
201
225
|
};
|
|
@@ -294,8 +294,14 @@ const getLoginUrl = async (provider) => {
|
|
|
294
294
|
if (!flag) return { success: false, url: null, childProcess: null, isHeadless: false, error: 'Provider not supported for OAuth' };
|
|
295
295
|
|
|
296
296
|
const headless = isHeadless();
|
|
297
|
+
const isGemini = (provider === 'google');
|
|
298
|
+
|
|
297
299
|
return new Promise((resolve) => {
|
|
298
|
-
|
|
300
|
+
// For Gemini: use 'pipe' stdin so we can send default project selection
|
|
301
|
+
const child = spawn(BINARY_PATH, [flag, '-no-browser'], {
|
|
302
|
+
cwd: INSTALL_DIR,
|
|
303
|
+
stdio: isGemini ? ['pipe', 'pipe', 'pipe'] : ['ignore', 'pipe', 'pipe']
|
|
304
|
+
});
|
|
299
305
|
let output = '', resolved = false;
|
|
300
306
|
|
|
301
307
|
const checkForUrl = () => {
|
|
@@ -303,14 +309,29 @@ const getLoginUrl = async (provider) => {
|
|
|
303
309
|
const urlMatch = output.match(/https?:\/\/[^\s]+/);
|
|
304
310
|
if (urlMatch) {
|
|
305
311
|
resolved = true;
|
|
306
|
-
resolve({ success: true, url: urlMatch[0], childProcess: child, isHeadless: headless, error: null });
|
|
312
|
+
resolve({ success: true, url: urlMatch[0], childProcess: child, isHeadless: headless, isGemini, error: null });
|
|
307
313
|
}
|
|
308
314
|
};
|
|
309
315
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
316
|
+
// For Gemini: auto-select default project when prompted
|
|
317
|
+
if (isGemini && child.stdout) {
|
|
318
|
+
child.stdout.on('data', (data) => {
|
|
319
|
+
output += data.toString();
|
|
320
|
+
checkForUrl();
|
|
321
|
+
// When Gemini asks for project selection, send Enter (default) or ALL
|
|
322
|
+
if (data.toString().includes('Enter project ID') && child.stdin) {
|
|
323
|
+
child.stdin.write('\n'); // Select default project
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
} else if (child.stdout) {
|
|
327
|
+
child.stdout.on('data', (data) => { output += data.toString(); checkForUrl(); });
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (child.stderr) {
|
|
331
|
+
child.stderr.on('data', (data) => { output += data.toString(); checkForUrl(); });
|
|
332
|
+
}
|
|
333
|
+
child.on('error', (err) => { if (!resolved) { resolved = true; resolve({ success: false, url: null, childProcess: null, isHeadless: headless, isGemini: false, error: err.message }); }});
|
|
334
|
+
child.on('close', (code) => { if (!resolved) { resolved = true; resolve({ success: false, url: null, childProcess: null, isHeadless: headless, isGemini: false, error: `Process exited with code ${code}` }); }});
|
|
314
335
|
});
|
|
315
336
|
};
|
|
316
337
|
|