hedgequantx 2.9.19 → 2.9.20
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/app.js +42 -64
- package/src/lib/m/hqx-2b.js +7 -0
- package/src/lib/m/index.js +138 -0
- package/src/lib/m/ultra-scalping.js +7 -0
- package/src/menus/connect.js +14 -17
- package/src/menus/dashboard.js +58 -76
- package/src/pages/accounts.js +38 -49
- package/src/pages/algo/copy-trading.js +546 -178
- package/src/pages/algo/index.js +18 -75
- package/src/pages/algo/one-account.js +322 -57
- package/src/pages/algo/ui.js +15 -15
- package/src/pages/orders.js +19 -22
- package/src/pages/positions.js +19 -22
- package/src/pages/stats/index.js +15 -16
- package/src/pages/user.js +7 -11
- package/src/services/ai-supervision/health.js +35 -47
- package/src/services/index.js +1 -9
- package/src/services/rithmic/accounts.js +8 -6
- package/src/ui/box.js +9 -5
- package/src/ui/index.js +5 -18
- package/src/ui/menu.js +4 -4
- package/src/pages/ai-agents-ui.js +0 -388
- package/src/pages/ai-agents.js +0 -494
- package/src/pages/ai-models.js +0 -389
- package/src/pages/algo/algo-executor.js +0 -307
- package/src/pages/algo/copy-executor.js +0 -331
- package/src/pages/algo/custom-strategy.js +0 -313
- package/src/services/ai-supervision/consensus.js +0 -284
- package/src/services/ai-supervision/context.js +0 -275
- package/src/services/ai-supervision/directive.js +0 -167
- package/src/services/ai-supervision/index.js +0 -359
- package/src/services/ai-supervision/parser.js +0 -278
- package/src/services/ai-supervision/symbols.js +0 -259
- package/src/services/cliproxy/index.js +0 -256
- package/src/services/cliproxy/installer.js +0 -111
- package/src/services/cliproxy/manager.js +0 -387
- package/src/services/llmproxy/index.js +0 -166
- package/src/services/llmproxy/manager.js +0 -411
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLIProxy Service
|
|
3
|
-
*
|
|
4
|
-
* Provides OAuth connections to paid AI plans (Claude Pro, ChatGPT Plus, etc.)
|
|
5
|
-
* via the embedded CLIProxyAPI binary.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const http = require('http');
|
|
9
|
-
const manager = require('./manager');
|
|
10
|
-
|
|
11
|
-
// Re-export manager functions
|
|
12
|
-
const {
|
|
13
|
-
CLIPROXY_VERSION,
|
|
14
|
-
INSTALL_DIR,
|
|
15
|
-
AUTH_DIR,
|
|
16
|
-
DEFAULT_PORT,
|
|
17
|
-
CALLBACK_PORTS,
|
|
18
|
-
CALLBACK_PATHS,
|
|
19
|
-
isInstalled,
|
|
20
|
-
isHeadless,
|
|
21
|
-
install,
|
|
22
|
-
isRunning,
|
|
23
|
-
start,
|
|
24
|
-
stop,
|
|
25
|
-
ensureRunning,
|
|
26
|
-
getLoginUrl,
|
|
27
|
-
getCallbackPort,
|
|
28
|
-
processCallback
|
|
29
|
-
} = manager;
|
|
30
|
-
|
|
31
|
-
// Internal API key (must match config.yaml)
|
|
32
|
-
const API_KEY = 'hqx-internal-key';
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Make HTTP request to local CLIProxyAPI
|
|
36
|
-
* @param {string} path - API path
|
|
37
|
-
* @param {string} method - HTTP method
|
|
38
|
-
* @param {Object} body - Request body (optional)
|
|
39
|
-
* @param {number} timeout - Timeout in ms (default 60000 per RULES.md #15)
|
|
40
|
-
* @returns {Promise<Object>} { success, data, error }
|
|
41
|
-
*/
|
|
42
|
-
const fetchLocal = (path, method = 'GET', body = null, timeout = 60000) => {
|
|
43
|
-
return new Promise((resolve) => {
|
|
44
|
-
const options = {
|
|
45
|
-
hostname: '127.0.0.1',
|
|
46
|
-
port: DEFAULT_PORT,
|
|
47
|
-
path,
|
|
48
|
-
method,
|
|
49
|
-
headers: {
|
|
50
|
-
'Content-Type': 'application/json',
|
|
51
|
-
'Authorization': `Bearer ${API_KEY}`
|
|
52
|
-
},
|
|
53
|
-
timeout
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const req = http.request(options, (res) => {
|
|
57
|
-
let data = '';
|
|
58
|
-
res.on('data', chunk => data += chunk);
|
|
59
|
-
res.on('end', () => {
|
|
60
|
-
try {
|
|
61
|
-
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
62
|
-
const parsed = data ? JSON.parse(data) : {};
|
|
63
|
-
resolve({ success: true, data: parsed, error: null });
|
|
64
|
-
} else {
|
|
65
|
-
resolve({ success: false, error: `HTTP ${res.statusCode}`, data: null });
|
|
66
|
-
}
|
|
67
|
-
} catch (error) {
|
|
68
|
-
resolve({ success: false, error: 'Invalid JSON response', data: null });
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
req.on('error', (error) => {
|
|
74
|
-
if (error.code === 'ECONNREFUSED') {
|
|
75
|
-
resolve({ success: false, error: 'CLIProxyAPI not running', data: null });
|
|
76
|
-
} else {
|
|
77
|
-
resolve({ success: false, error: error.message, data: null });
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
req.on('timeout', () => {
|
|
82
|
-
req.destroy();
|
|
83
|
-
resolve({ success: false, error: 'Request timeout', data: null });
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
if (body) {
|
|
87
|
-
req.write(JSON.stringify(body));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
req.end();
|
|
91
|
-
});
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Fetch available models from CLIProxyAPI
|
|
96
|
-
* @returns {Promise<Object>} { success, models, error }
|
|
97
|
-
*/
|
|
98
|
-
const fetchModels = async () => {
|
|
99
|
-
const result = await fetchLocal('/v1/models');
|
|
100
|
-
|
|
101
|
-
if (!result.success) {
|
|
102
|
-
return { success: false, models: [], error: result.error };
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const data = result.data;
|
|
106
|
-
if (!data || !data.data || !Array.isArray(data.data)) {
|
|
107
|
-
return { success: false, models: [], error: 'Invalid response format' };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const models = data.data
|
|
111
|
-
.filter(m => m.id)
|
|
112
|
-
.map(m => ({ id: m.id, name: m.id }));
|
|
113
|
-
|
|
114
|
-
if (models.length === 0) {
|
|
115
|
-
return { success: false, models: [], error: 'No models available' };
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return { success: true, models, error: null };
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Get provider-specific models
|
|
123
|
-
* @param {string} providerId - Provider ID
|
|
124
|
-
* @returns {Promise<Object>} { success, models, error }
|
|
125
|
-
*/
|
|
126
|
-
const fetchProviderModels = async (providerId) => {
|
|
127
|
-
const result = await fetchModels();
|
|
128
|
-
if (!result.success) return result;
|
|
129
|
-
|
|
130
|
-
// Filter by provider prefix
|
|
131
|
-
const prefixMap = {
|
|
132
|
-
anthropic: 'claude',
|
|
133
|
-
openai: 'gpt',
|
|
134
|
-
google: 'gemini',
|
|
135
|
-
qwen: 'qwen'
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const prefix = prefixMap[providerId];
|
|
139
|
-
if (!prefix) return result;
|
|
140
|
-
|
|
141
|
-
const filtered = result.models.filter(m =>
|
|
142
|
-
m.id.toLowerCase().includes(prefix)
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
// Return only filtered models for this provider (empty if none found)
|
|
146
|
-
return {
|
|
147
|
-
success: filtered.length > 0,
|
|
148
|
-
models: filtered,
|
|
149
|
-
error: filtered.length === 0 ? `No ${providerId} models available` : null
|
|
150
|
-
};
|
|
151
|
-
};
|
|
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
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Chat completion request
|
|
178
|
-
* @param {string} model - Model ID
|
|
179
|
-
* @param {Array} messages - Chat messages
|
|
180
|
-
* @param {Object} options - Additional options
|
|
181
|
-
* @returns {Promise<Object>} { success, response, error }
|
|
182
|
-
*/
|
|
183
|
-
const chatCompletion = async (model, messages, options = {}) => {
|
|
184
|
-
const body = {
|
|
185
|
-
model,
|
|
186
|
-
messages,
|
|
187
|
-
stream: false,
|
|
188
|
-
...options
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
const result = await fetchLocal('/v1/chat/completions', 'POST', body);
|
|
192
|
-
|
|
193
|
-
if (!result.success) {
|
|
194
|
-
return { success: false, response: null, error: result.error };
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return { success: true, response: result.data, error: null };
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Simple chat function for AI supervision
|
|
202
|
-
* @param {string} providerId - Provider ID (anthropic, openai, google, etc.)
|
|
203
|
-
* @param {string} modelId - Model ID
|
|
204
|
-
* @param {string} prompt - User prompt
|
|
205
|
-
* @param {number} timeout - Timeout in ms
|
|
206
|
-
* @returns {Promise<Object>} { success, content, error }
|
|
207
|
-
*/
|
|
208
|
-
const chat = async (providerId, modelId, prompt, timeout = 30000) => {
|
|
209
|
-
const messages = [{ role: 'user', content: prompt }];
|
|
210
|
-
|
|
211
|
-
const result = await fetchLocal('/v1/chat/completions', 'POST', {
|
|
212
|
-
model: modelId,
|
|
213
|
-
messages,
|
|
214
|
-
stream: false
|
|
215
|
-
}, timeout);
|
|
216
|
-
|
|
217
|
-
if (!result.success) {
|
|
218
|
-
return { success: false, content: null, error: result.error };
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Extract content from response
|
|
222
|
-
const data = result.data;
|
|
223
|
-
if (data?.choices?.[0]?.message?.content) {
|
|
224
|
-
return { success: true, content: data.choices[0].message.content, error: null };
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return { success: false, content: null, error: 'No content in response' };
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
module.exports = {
|
|
231
|
-
// Manager
|
|
232
|
-
CLIPROXY_VERSION,
|
|
233
|
-
INSTALL_DIR,
|
|
234
|
-
AUTH_DIR,
|
|
235
|
-
DEFAULT_PORT,
|
|
236
|
-
CALLBACK_PORTS,
|
|
237
|
-
CALLBACK_PATHS,
|
|
238
|
-
isInstalled,
|
|
239
|
-
isHeadless,
|
|
240
|
-
install,
|
|
241
|
-
isRunning,
|
|
242
|
-
start,
|
|
243
|
-
stop,
|
|
244
|
-
ensureRunning,
|
|
245
|
-
getLoginUrl,
|
|
246
|
-
getCallbackPort,
|
|
247
|
-
processCallback,
|
|
248
|
-
|
|
249
|
-
// API
|
|
250
|
-
fetchLocal,
|
|
251
|
-
fetchModels,
|
|
252
|
-
fetchProviderModels,
|
|
253
|
-
getConnectedProviders,
|
|
254
|
-
chatCompletion,
|
|
255
|
-
chat
|
|
256
|
-
};
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLIProxyAPI Installer
|
|
3
|
-
*
|
|
4
|
-
* Handles downloading and extracting CLIProxyAPI binary
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const https = require('https');
|
|
9
|
-
const http = require('http');
|
|
10
|
-
const { createGunzip } = require('zlib');
|
|
11
|
-
const tar = require('tar');
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Download file from URL with redirect support
|
|
15
|
-
* @param {string} url - URL to download
|
|
16
|
-
* @param {string} destPath - Destination path
|
|
17
|
-
* @param {Function} onProgress - Progress callback (percent)
|
|
18
|
-
* @returns {Promise<boolean>}
|
|
19
|
-
*/
|
|
20
|
-
const downloadFile = (url, destPath, onProgress = null) => {
|
|
21
|
-
return new Promise((resolve, reject) => {
|
|
22
|
-
const file = fs.createWriteStream(destPath);
|
|
23
|
-
|
|
24
|
-
const request = (url.startsWith('https') ? https : http).get(url, (response) => {
|
|
25
|
-
// Handle redirects
|
|
26
|
-
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
27
|
-
file.close();
|
|
28
|
-
fs.unlinkSync(destPath);
|
|
29
|
-
return downloadFile(response.headers.location, destPath, onProgress)
|
|
30
|
-
.then(resolve)
|
|
31
|
-
.catch(reject);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (response.statusCode !== 200) {
|
|
35
|
-
file.close();
|
|
36
|
-
fs.unlinkSync(destPath);
|
|
37
|
-
return reject(new Error(`HTTP ${response.statusCode}`));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const totalSize = parseInt(response.headers['content-length'], 10);
|
|
41
|
-
let downloadedSize = 0;
|
|
42
|
-
|
|
43
|
-
response.on('data', (chunk) => {
|
|
44
|
-
downloadedSize += chunk.length;
|
|
45
|
-
if (onProgress && totalSize) {
|
|
46
|
-
onProgress(Math.round((downloadedSize / totalSize) * 100));
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
response.pipe(file);
|
|
51
|
-
|
|
52
|
-
file.on('finish', () => {
|
|
53
|
-
file.close();
|
|
54
|
-
resolve(true);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
request.on('error', (err) => {
|
|
59
|
-
file.close();
|
|
60
|
-
if (fs.existsSync(destPath)) fs.unlinkSync(destPath);
|
|
61
|
-
reject(err);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
request.setTimeout(120000, () => {
|
|
65
|
-
request.destroy();
|
|
66
|
-
reject(new Error('Download timeout'));
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Extract tar.gz file
|
|
73
|
-
* @param {string} archivePath - Path to archive
|
|
74
|
-
* @param {string} destDir - Destination directory
|
|
75
|
-
* @returns {Promise<boolean>}
|
|
76
|
-
*/
|
|
77
|
-
const extractTarGz = (archivePath, destDir) => {
|
|
78
|
-
return new Promise((resolve, reject) => {
|
|
79
|
-
fs.createReadStream(archivePath)
|
|
80
|
-
.pipe(createGunzip())
|
|
81
|
-
.pipe(tar.extract({ cwd: destDir }))
|
|
82
|
-
.on('finish', () => resolve(true))
|
|
83
|
-
.on('error', reject);
|
|
84
|
-
});
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Extract zip file (Windows)
|
|
89
|
-
* @param {string} archivePath - Path to archive
|
|
90
|
-
* @param {string} destDir - Destination directory
|
|
91
|
-
* @returns {Promise<boolean>}
|
|
92
|
-
*/
|
|
93
|
-
const extractZip = async (archivePath, destDir) => {
|
|
94
|
-
const { execSync } = require('child_process');
|
|
95
|
-
|
|
96
|
-
if (process.platform === 'win32') {
|
|
97
|
-
execSync(`powershell -Command "Expand-Archive -Path '${archivePath}' -DestinationPath '${destDir}' -Force"`, {
|
|
98
|
-
stdio: 'ignore'
|
|
99
|
-
});
|
|
100
|
-
} else {
|
|
101
|
-
execSync(`unzip -o "${archivePath}" -d "${destDir}"`, { stdio: 'ignore' });
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return true;
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
module.exports = {
|
|
108
|
-
downloadFile,
|
|
109
|
-
extractTarGz,
|
|
110
|
-
extractZip
|
|
111
|
-
};
|