hedgequantx 2.6.162 → 2.7.0

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 (138) hide show
  1. package/README.md +15 -88
  2. package/bin/cli.js +0 -11
  3. package/dist/lib/api.jsc +0 -0
  4. package/dist/lib/api2.jsc +0 -0
  5. package/dist/lib/core.jsc +0 -0
  6. package/dist/lib/core2.jsc +0 -0
  7. package/dist/lib/data.js +1 -1
  8. package/dist/lib/data.jsc +0 -0
  9. package/dist/lib/data2.jsc +0 -0
  10. package/dist/lib/decoder.jsc +0 -0
  11. package/dist/lib/m/mod1.jsc +0 -0
  12. package/dist/lib/m/mod2.jsc +0 -0
  13. package/dist/lib/n/r1.jsc +0 -0
  14. package/dist/lib/n/r2.jsc +0 -0
  15. package/dist/lib/n/r3.jsc +0 -0
  16. package/dist/lib/n/r4.jsc +0 -0
  17. package/dist/lib/n/r5.jsc +0 -0
  18. package/dist/lib/n/r6.jsc +0 -0
  19. package/dist/lib/n/r7.jsc +0 -0
  20. package/dist/lib/o/util1.jsc +0 -0
  21. package/dist/lib/o/util2.jsc +0 -0
  22. package/package.json +6 -3
  23. package/src/app.js +40 -162
  24. package/src/config/constants.js +31 -33
  25. package/src/config/propfirms.js +13 -217
  26. package/src/config/settings.js +0 -43
  27. package/src/lib/api.js +198 -0
  28. package/src/lib/api2.js +353 -0
  29. package/src/lib/core.js +539 -0
  30. package/src/lib/core2.js +341 -0
  31. package/src/lib/data.js +555 -0
  32. package/src/lib/data2.js +492 -0
  33. package/src/lib/decoder.js +599 -0
  34. package/src/lib/m/s1.js +804 -0
  35. package/src/lib/m/s2.js +34 -0
  36. package/src/lib/n/r1.js +454 -0
  37. package/src/lib/n/r2.js +514 -0
  38. package/src/lib/n/r3.js +631 -0
  39. package/src/lib/n/r4.js +401 -0
  40. package/src/lib/n/r5.js +335 -0
  41. package/src/lib/n/r6.js +425 -0
  42. package/src/lib/n/r7.js +530 -0
  43. package/src/lib/o/l1.js +44 -0
  44. package/src/lib/o/l2.js +427 -0
  45. package/src/lib/python-bridge.js +206 -0
  46. package/src/menus/connect.js +14 -176
  47. package/src/menus/dashboard.js +65 -110
  48. package/src/pages/accounts.js +18 -18
  49. package/src/pages/algo/copy-trading.js +210 -240
  50. package/src/pages/algo/index.js +41 -104
  51. package/src/pages/algo/one-account.js +386 -33
  52. package/src/pages/algo/ui.js +312 -151
  53. package/src/pages/orders.js +3 -3
  54. package/src/pages/positions.js +3 -3
  55. package/src/pages/stats/chart.js +74 -0
  56. package/src/pages/stats/display.js +228 -0
  57. package/src/pages/stats/index.js +236 -0
  58. package/src/pages/stats/metrics.js +213 -0
  59. package/src/pages/user.js +6 -6
  60. package/src/services/hqx-server/constants.js +55 -0
  61. package/src/services/hqx-server/index.js +401 -0
  62. package/src/services/hqx-server/latency.js +81 -0
  63. package/src/services/index.js +12 -3
  64. package/src/services/rithmic/accounts.js +7 -32
  65. package/src/services/rithmic/connection.js +1 -204
  66. package/src/services/rithmic/contracts.js +235 -0
  67. package/src/services/rithmic/handlers.js +21 -196
  68. package/src/services/rithmic/index.js +60 -291
  69. package/src/services/rithmic/market.js +31 -0
  70. package/src/services/rithmic/orders.js +5 -361
  71. package/src/services/rithmic/protobuf.js +5 -195
  72. package/src/services/session.js +22 -173
  73. package/src/ui/box.js +10 -18
  74. package/src/ui/index.js +1 -3
  75. package/src/ui/menu.js +1 -1
  76. package/src/utils/prompts.js +2 -2
  77. package/dist/lib/m/s1.js +0 -1
  78. package/src/menus/ai-agent-connect.js +0 -181
  79. package/src/menus/ai-agent-models.js +0 -219
  80. package/src/menus/ai-agent-oauth.js +0 -292
  81. package/src/menus/ai-agent-ui.js +0 -141
  82. package/src/menus/ai-agent.js +0 -484
  83. package/src/pages/algo/algo-config.js +0 -195
  84. package/src/pages/algo/algo-multi.js +0 -801
  85. package/src/pages/algo/algo-utils.js +0 -58
  86. package/src/pages/algo/copy-engine.js +0 -449
  87. package/src/pages/algo/custom-strategy.js +0 -459
  88. package/src/pages/algo/logger.js +0 -245
  89. package/src/pages/algo/smart-logs-data.js +0 -218
  90. package/src/pages/algo/smart-logs.js +0 -387
  91. package/src/pages/algo/ui-constants.js +0 -144
  92. package/src/pages/algo/ui-summary.js +0 -184
  93. package/src/pages/stats-calculations.js +0 -191
  94. package/src/pages/stats-ui.js +0 -381
  95. package/src/pages/stats.js +0 -339
  96. package/src/services/ai/client-analysis.js +0 -194
  97. package/src/services/ai/client-models.js +0 -333
  98. package/src/services/ai/client.js +0 -343
  99. package/src/services/ai/index.js +0 -384
  100. package/src/services/ai/oauth-anthropic.js +0 -265
  101. package/src/services/ai/oauth-gemini.js +0 -223
  102. package/src/services/ai/oauth-iflow.js +0 -269
  103. package/src/services/ai/oauth-openai.js +0 -233
  104. package/src/services/ai/oauth-qwen.js +0 -279
  105. package/src/services/ai/providers/index.js +0 -526
  106. package/src/services/ai/proxy-install.js +0 -249
  107. package/src/services/ai/proxy-manager.js +0 -494
  108. package/src/services/ai/proxy-remote.js +0 -161
  109. package/src/services/ai/strategy-supervisor.js +0 -1312
  110. package/src/services/ai/supervisor-data.js +0 -195
  111. package/src/services/ai/supervisor-optimize.js +0 -215
  112. package/src/services/ai/supervisor-sync.js +0 -178
  113. package/src/services/ai/supervisor-utils.js +0 -158
  114. package/src/services/ai/supervisor.js +0 -484
  115. package/src/services/ai/validation.js +0 -250
  116. package/src/services/hqx-server-events.js +0 -110
  117. package/src/services/hqx-server-handlers.js +0 -217
  118. package/src/services/hqx-server-latency.js +0 -136
  119. package/src/services/hqx-server.js +0 -403
  120. package/src/services/position-constants.js +0 -28
  121. package/src/services/position-manager.js +0 -528
  122. package/src/services/position-momentum.js +0 -206
  123. package/src/services/projectx/accounts.js +0 -142
  124. package/src/services/projectx/index.js +0 -443
  125. package/src/services/projectx/market.js +0 -172
  126. package/src/services/projectx/stats.js +0 -110
  127. package/src/services/projectx/trading.js +0 -180
  128. package/src/services/rithmic/latency-tracker.js +0 -182
  129. package/src/services/rithmic/market-data.js +0 -549
  130. package/src/services/rithmic/specs.js +0 -146
  131. package/src/services/rithmic/trade-history.js +0 -254
  132. package/src/services/session-history.js +0 -475
  133. package/src/services/strategy/hft-tick.js +0 -507
  134. package/src/services/strategy/recovery-math.js +0 -402
  135. package/src/services/tradovate/constants.js +0 -109
  136. package/src/services/tradovate/index.js +0 -505
  137. package/src/services/tradovate/market.js +0 -47
  138. package/src/services/tradovate/websocket.js +0 -97
@@ -1,384 +0,0 @@
1
- /**
2
- * AI Service Manager
3
- * Manages multiple AI provider connections
4
- */
5
-
6
- const { getProviders, getProvider } = require('./providers');
7
- const { storage } = require('../session');
8
- const AISupervisor = require('./supervisor');
9
- const StrategySupervisor = require('./strategy-supervisor');
10
- const { validateConnection } = require('./validation');
11
-
12
- // In-memory cache of connections
13
- let connectionsCache = null;
14
-
15
- /**
16
- * Get AI settings from storage
17
- */
18
- const getAISettings = () => {
19
- try {
20
- const sessions = storage.load();
21
- const aiSettings = sessions.find(s => s.type === 'ai') || { type: 'ai', agents: [] };
22
-
23
- // Migrate old single-agent format to multi-agent
24
- if (aiSettings.provider && !aiSettings.agents) {
25
- return {
26
- type: 'ai',
27
- agents: [{
28
- id: generateAgentId(),
29
- provider: aiSettings.provider,
30
- option: aiSettings.option,
31
- credentials: aiSettings.credentials,
32
- model: aiSettings.model,
33
- name: getProvider(aiSettings.provider)?.name || 'AI Agent',
34
- createdAt: Date.now()
35
- }],
36
- activeAgentId: null
37
- };
38
- }
39
- return aiSettings;
40
- } catch {
41
- return { type: 'ai', agents: [] };
42
- }
43
- };
44
-
45
- /**
46
- * Save AI settings to storage
47
- */
48
- const saveAISettings = (aiSettings) => {
49
- try {
50
- const sessions = storage.load();
51
- const otherSessions = sessions.filter(s => s.type !== 'ai');
52
-
53
- aiSettings.type = 'ai';
54
- otherSessions.push(aiSettings);
55
-
56
- storage.save(otherSessions);
57
- connectionsCache = null; // Invalidate cache
58
- } catch (e) {
59
- // Silent fail
60
- }
61
- };
62
-
63
- /**
64
- * Generate unique agent ID
65
- */
66
- const generateAgentId = () => {
67
- return 'agent_' + Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
68
- };
69
-
70
- /**
71
- * Get all connected agents
72
- * IMPORTANT: Includes credentials for API calls in StrategySupervisor
73
- */
74
- const getAgents = () => {
75
- const aiSettings = getAISettings();
76
- const agents = aiSettings.agents || [];
77
-
78
- return agents.map(agent => {
79
- const provider = getProvider(agent.provider);
80
- return {
81
- id: agent.id,
82
- name: agent.name || provider?.name || 'Unknown',
83
- provider: provider,
84
- providerId: agent.provider,
85
- option: agent.option,
86
- model: agent.model || provider?.defaultModel,
87
- credentials: agent.credentials, // CRITICAL: Required for API calls
88
- createdAt: agent.createdAt,
89
- isActive: agent.id === aiSettings.activeAgentId
90
- };
91
- }).filter(a => a.provider); // Filter out invalid providers
92
- };
93
-
94
- /**
95
- * Get agent count
96
- */
97
- const getAgentCount = () => {
98
- const aiSettings = getAISettings();
99
- return (aiSettings.agents || []).length;
100
- };
101
-
102
- /**
103
- * Check if any AI is connected
104
- */
105
- const isConnected = () => {
106
- return getAgentCount() > 0;
107
- };
108
-
109
- /**
110
- * Get active agent (or first agent if none active)
111
- */
112
- const getActiveAgent = () => {
113
- const aiSettings = getAISettings();
114
- const agents = aiSettings.agents || [];
115
-
116
- if (agents.length === 0) return null;
117
-
118
- // Find active agent or use first one
119
- const activeId = aiSettings.activeAgentId;
120
- const agent = activeId
121
- ? agents.find(a => a.id === activeId)
122
- : agents[0];
123
-
124
- if (!agent) return null;
125
-
126
- const provider = getProvider(agent.provider);
127
- if (!provider) return null;
128
-
129
- return {
130
- id: agent.id,
131
- name: agent.name || provider.name,
132
- provider: provider,
133
- providerId: agent.provider,
134
- option: agent.option,
135
- model: agent.model || provider.defaultModel,
136
- credentials: agent.credentials,
137
- connected: true
138
- };
139
- };
140
-
141
- /**
142
- * Get agent by ID
143
- */
144
- const getAgent = (agentId) => {
145
- const aiSettings = getAISettings();
146
- const agents = aiSettings.agents || [];
147
- const agent = agents.find(a => a.id === agentId);
148
-
149
- if (!agent) return null;
150
-
151
- const provider = getProvider(agent.provider);
152
- if (!provider) return null;
153
-
154
- return {
155
- id: agent.id,
156
- name: agent.name || provider.name,
157
- provider: provider,
158
- providerId: agent.provider,
159
- option: agent.option,
160
- model: agent.model || provider.defaultModel,
161
- credentials: agent.credentials,
162
- connected: true
163
- };
164
- };
165
-
166
- /**
167
- * Get agent credentials by ID
168
- * @param {string} agentId - Agent ID
169
- * @returns {Object|null} Credentials object or null
170
- */
171
- const getAgentCredentials = (agentId) => {
172
- const aiSettings = getAISettings();
173
- const agents = aiSettings.agents || [];
174
- const agent = agents.find(a => a.id === agentId);
175
-
176
- if (!agent) return null;
177
- return agent.credentials || null;
178
- };
179
-
180
- /**
181
- * Set active agent
182
- */
183
- const setActiveAgent = (agentId) => {
184
- const aiSettings = getAISettings();
185
- const agents = aiSettings.agents || [];
186
-
187
- if (!agents.find(a => a.id === agentId)) {
188
- throw new Error('Agent not found');
189
- }
190
-
191
- aiSettings.activeAgentId = agentId;
192
- saveAISettings(aiSettings);
193
- };
194
-
195
- /**
196
- * Add a new agent (connect to provider)
197
- */
198
- const addAgent = async (providerId, optionId, credentials, model = null, customName = null) => {
199
- const provider = getProvider(providerId);
200
- if (!provider) {
201
- throw new Error('Invalid provider');
202
- }
203
-
204
- const option = provider.options.find(o => o.id === optionId);
205
- if (!option) {
206
- throw new Error('Invalid option');
207
- }
208
-
209
- const aiSettings = getAISettings();
210
- if (!aiSettings.agents) {
211
- aiSettings.agents = [];
212
- }
213
-
214
- // Create new agent
215
- const agentId = generateAgentId();
216
- const newAgent = {
217
- id: agentId,
218
- provider: providerId,
219
- option: optionId,
220
- credentials: credentials,
221
- model: model || provider.defaultModel,
222
- name: customName || provider.name,
223
- createdAt: Date.now()
224
- };
225
-
226
- aiSettings.agents.push(newAgent);
227
-
228
- // Set as active if first agent
229
- if (aiSettings.agents.length === 1) {
230
- aiSettings.activeAgentId = agentId;
231
- }
232
-
233
- saveAISettings(aiSettings);
234
-
235
- // Get the full agent object
236
- const agent = getAgent(agentId);
237
-
238
- // Notify StrategySupervisor if algo is running
239
- // This ensures new agents are immediately connected to live trading
240
- try {
241
- StrategySupervisor.addAgent(agent);
242
- } catch (e) {
243
- // Supervisor might not be active - that's OK
244
- }
245
-
246
- return agent;
247
- };
248
-
249
- /**
250
- * Remove an agent
251
- */
252
- const removeAgent = (agentId) => {
253
- const aiSettings = getAISettings();
254
- const agents = aiSettings.agents || [];
255
-
256
- const index = agents.findIndex(a => a.id === agentId);
257
- if (index === -1) {
258
- throw new Error('Agent not found');
259
- }
260
-
261
- agents.splice(index, 1);
262
- aiSettings.agents = agents;
263
-
264
- // Stop AI supervision for this agent
265
- AISupervisor.stop(agentId);
266
-
267
- // Notify StrategySupervisor to remove agent from live trading
268
- try {
269
- StrategySupervisor.removeAgent(agentId);
270
- } catch (e) {
271
- // Supervisor might not be active - that's OK
272
- }
273
-
274
- // If removed agent was active, set new active
275
- if (aiSettings.activeAgentId === agentId) {
276
- aiSettings.activeAgentId = agents.length > 0 ? agents[0].id : null;
277
- }
278
-
279
- saveAISettings(aiSettings);
280
- };
281
-
282
- /**
283
- * Update agent settings
284
- */
285
- const updateAgent = (agentId, updates) => {
286
- const aiSettings = getAISettings();
287
- const agents = aiSettings.agents || [];
288
-
289
- const agent = agents.find(a => a.id === agentId);
290
- if (!agent) {
291
- throw new Error('Agent not found');
292
- }
293
-
294
- // Apply updates
295
- if (updates.name) agent.name = updates.name;
296
- if (updates.model) agent.model = updates.model;
297
- if (updates.credentials) agent.credentials = updates.credentials;
298
-
299
- saveAISettings(aiSettings);
300
- return getAgent(agentId);
301
- };
302
-
303
- /**
304
- * Disconnect all agents
305
- */
306
- const disconnectAll = () => {
307
- // Stop all AI supervision sessions
308
- AISupervisor.stopAll();
309
-
310
- // Refresh StrategySupervisor to clear agents
311
- try {
312
- StrategySupervisor.refreshAgents();
313
- } catch (e) {
314
- // Supervisor might not be active
315
- }
316
-
317
- saveAISettings({ agents: [] });
318
- };
319
-
320
- /**
321
- * Legacy: Get current connection (returns active agent)
322
- * @deprecated Use getActiveAgent() instead
323
- */
324
- const getConnection = () => {
325
- return getActiveAgent();
326
- };
327
-
328
- /**
329
- * Legacy: Connect to a provider (adds new agent)
330
- * @deprecated Use addAgent() instead
331
- */
332
- const connect = async (providerId, optionId, credentials, model = null) => {
333
- return addAgent(providerId, optionId, credentials, model);
334
- };
335
-
336
- /**
337
- * Legacy: Disconnect (removes all agents)
338
- * @deprecated Use removeAgent() or disconnectAll() instead
339
- */
340
- const disconnect = () => {
341
- disconnectAll();
342
- };
343
-
344
- /**
345
- * Get credentials for active agent
346
- */
347
- const getCredentials = () => {
348
- const agent = getActiveAgent();
349
- return agent?.credentials || null;
350
- };
351
-
352
- // validateConnection imported from ./validation
353
-
354
- module.exports = {
355
- // Provider info
356
- getProviders,
357
- getProvider,
358
-
359
- // Multi-agent API
360
- getAgents,
361
- getAgentCount,
362
- getAgent,
363
- getAgentCredentials,
364
- getActiveAgent,
365
- setActiveAgent,
366
- addAgent,
367
- removeAgent,
368
- updateAgent,
369
- disconnectAll,
370
-
371
- // Legacy API (for backwards compatibility)
372
- isConnected,
373
- getConnection,
374
- connect,
375
- disconnect,
376
- getCredentials,
377
-
378
- // Validation
379
- validateConnection,
380
-
381
- // Settings
382
- getAISettings,
383
- saveAISettings
384
- };
@@ -1,265 +0,0 @@
1
- /**
2
- * Anthropic OAuth Authentication
3
- *
4
- * Implements OAuth 2.0 with PKCE for Anthropic Claude Pro/Max plans.
5
- * Based on the public OAuth flow used by OpenCode.
6
- *
7
- * Data source: Anthropic OAuth API (https://console.anthropic.com/v1/oauth/token)
8
- */
9
-
10
- const crypto = require('crypto');
11
- const https = require('https');
12
-
13
- // Public OAuth Client ID (same as OpenCode - registered with Anthropic)
14
- const CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e';
15
- const REDIRECT_URI = 'https://console.anthropic.com/oauth/code/callback';
16
-
17
- /**
18
- * Generate PKCE code verifier and challenge
19
- * @returns {Object} { verifier: string, challenge: string }
20
- */
21
- const generatePKCE = () => {
22
- // Generate a random 32-byte code verifier (base64url encoded)
23
- const verifier = crypto.randomBytes(32)
24
- .toString('base64')
25
- .replace(/\+/g, '-')
26
- .replace(/\//g, '_')
27
- .replace(/=/g, '');
28
-
29
- // Generate SHA256 hash of verifier, then base64url encode it
30
- const challenge = crypto.createHash('sha256')
31
- .update(verifier)
32
- .digest('base64')
33
- .replace(/\+/g, '-')
34
- .replace(/\//g, '_')
35
- .replace(/=/g, '');
36
-
37
- return { verifier, challenge };
38
- };
39
-
40
- /**
41
- * Generate OAuth authorization URL
42
- * @param {'max' | 'console'} mode - 'max' for Claude Pro/Max, 'console' for API key creation
43
- * @returns {Object} { url: string, verifier: string }
44
- */
45
- const authorize = (mode = 'max') => {
46
- const pkce = generatePKCE();
47
-
48
- const baseUrl = mode === 'max'
49
- ? 'https://claude.ai/oauth/authorize'
50
- : 'https://console.anthropic.com/oauth/authorize';
51
-
52
- const url = new URL(baseUrl);
53
- url.searchParams.set('code', 'true');
54
- url.searchParams.set('client_id', CLIENT_ID);
55
- url.searchParams.set('response_type', 'code');
56
- url.searchParams.set('redirect_uri', REDIRECT_URI);
57
- url.searchParams.set('scope', 'org:create_api_key user:profile user:inference');
58
- url.searchParams.set('code_challenge', pkce.challenge);
59
- url.searchParams.set('code_challenge_method', 'S256');
60
- url.searchParams.set('state', pkce.verifier);
61
-
62
- return {
63
- url: url.toString(),
64
- verifier: pkce.verifier
65
- };
66
- };
67
-
68
- /**
69
- * Make HTTPS request
70
- * @param {string} url - Full URL
71
- * @param {Object} options - Request options
72
- * @returns {Promise<Object>} Response JSON
73
- */
74
- const makeRequest = (url, options) => {
75
- return new Promise((resolve, reject) => {
76
- const req = https.request(url, {
77
- method: options.method || 'POST',
78
- headers: options.headers || {}
79
- }, (res) => {
80
- let data = '';
81
- res.on('data', chunk => data += chunk);
82
- res.on('end', () => {
83
- try {
84
- const json = JSON.parse(data);
85
- if (res.statusCode >= 200 && res.statusCode < 300) {
86
- resolve(json);
87
- } else {
88
- reject(new Error(json.error?.message || `HTTP ${res.statusCode}: ${data}`));
89
- }
90
- } catch (e) {
91
- reject(new Error(`Invalid JSON response: ${data.substring(0, 200)}`));
92
- }
93
- });
94
- });
95
-
96
- req.on('error', reject);
97
-
98
- if (options.body) {
99
- req.write(JSON.stringify(options.body));
100
- }
101
- req.end();
102
- });
103
- };
104
-
105
- /**
106
- * Exchange authorization code for tokens
107
- * @param {string} code - Authorization code from callback (format: code#state)
108
- * @param {string} verifier - PKCE code verifier
109
- * @returns {Promise<Object>} { type: 'success', access: string, refresh: string, expires: number } or { type: 'failed' }
110
- *
111
- * Data source: https://console.anthropic.com/v1/oauth/token (POST)
112
- */
113
- const exchange = async (code, verifier) => {
114
- try {
115
- // Code format from callback: "authorization_code#state"
116
- const splits = code.split('#');
117
- const authCode = splits[0];
118
- const state = splits[1] || '';
119
-
120
- const response = await makeRequest('https://console.anthropic.com/v1/oauth/token', {
121
- method: 'POST',
122
- headers: {
123
- 'Content-Type': 'application/json'
124
- },
125
- body: {
126
- code: authCode,
127
- state: state,
128
- grant_type: 'authorization_code',
129
- client_id: CLIENT_ID,
130
- redirect_uri: REDIRECT_URI,
131
- code_verifier: verifier
132
- }
133
- });
134
-
135
- return {
136
- type: 'success',
137
- access: response.access_token,
138
- refresh: response.refresh_token,
139
- expires: Date.now() + (response.expires_in * 1000)
140
- };
141
- } catch (error) {
142
- return {
143
- type: 'failed',
144
- error: error.message
145
- };
146
- }
147
- };
148
-
149
- /**
150
- * Refresh access token using refresh token
151
- * @param {string} refreshToken - The refresh token
152
- * @returns {Promise<Object>} { type: 'success', access: string, refresh: string, expires: number } or { type: 'failed' }
153
- *
154
- * Data source: https://console.anthropic.com/v1/oauth/token (POST)
155
- */
156
- const refreshToken = async (refreshToken) => {
157
- try {
158
- const response = await makeRequest('https://console.anthropic.com/v1/oauth/token', {
159
- method: 'POST',
160
- headers: {
161
- 'Content-Type': 'application/json'
162
- },
163
- body: {
164
- grant_type: 'refresh_token',
165
- refresh_token: refreshToken,
166
- client_id: CLIENT_ID
167
- }
168
- });
169
-
170
- return {
171
- type: 'success',
172
- access: response.access_token,
173
- refresh: response.refresh_token,
174
- expires: Date.now() + (response.expires_in * 1000)
175
- };
176
- } catch (error) {
177
- return {
178
- type: 'failed',
179
- error: error.message
180
- };
181
- }
182
- };
183
-
184
- /**
185
- * Create an API key using OAuth token (for console mode)
186
- * @param {string} accessToken - The access token
187
- * @returns {Promise<Object>} { type: 'success', key: string } or { type: 'failed' }
188
- *
189
- * Data source: https://api.anthropic.com/api/oauth/claude_cli/create_api_key (POST)
190
- */
191
- const createApiKey = async (accessToken) => {
192
- try {
193
- const response = await makeRequest('https://api.anthropic.com/api/oauth/claude_cli/create_api_key', {
194
- method: 'POST',
195
- headers: {
196
- 'Content-Type': 'application/json',
197
- 'Authorization': `Bearer ${accessToken}`
198
- }
199
- });
200
-
201
- return {
202
- type: 'success',
203
- key: response.raw_key
204
- };
205
- } catch (error) {
206
- return {
207
- type: 'failed',
208
- error: error.message
209
- };
210
- }
211
- };
212
-
213
- /**
214
- * Get valid access token (refresh if expired)
215
- * @param {Object} oauthData - OAuth data { access, refresh, expires }
216
- * @returns {Promise<Object>} { access: string, refresh: string, expires: number, refreshed: boolean }
217
- */
218
- const getValidToken = async (oauthData) => {
219
- if (!oauthData || !oauthData.refresh) {
220
- return null;
221
- }
222
-
223
- // Check if token is expired or will expire in the next 5 minutes
224
- const expirationBuffer = 5 * 60 * 1000; // 5 minutes
225
- if (oauthData.expires && oauthData.expires > Date.now() + expirationBuffer) {
226
- return {
227
- ...oauthData,
228
- refreshed: false
229
- };
230
- }
231
-
232
- // Token expired or about to expire, refresh it
233
- const result = await refreshToken(oauthData.refresh);
234
- if (result.type === 'success') {
235
- return {
236
- access: result.access,
237
- refresh: result.refresh,
238
- expires: result.expires,
239
- refreshed: true
240
- };
241
- }
242
-
243
- return null;
244
- };
245
-
246
- /**
247
- * Check if credentials are OAuth tokens
248
- * @param {Object} credentials - Agent credentials
249
- * @returns {boolean}
250
- */
251
- const isOAuthCredentials = (credentials) => {
252
- return credentials && credentials.oauth && credentials.oauth.refresh;
253
- };
254
-
255
- module.exports = {
256
- CLIENT_ID,
257
- REDIRECT_URI,
258
- generatePKCE,
259
- authorize,
260
- exchange,
261
- refreshToken,
262
- createApiKey,
263
- getValidToken,
264
- isOAuthCredentials
265
- };