hedgequantx 2.5.12 → 2.5.13
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/services/ai/index.js +30 -30
- package/src/services/ai/token-scanner.js +25 -3
package/package.json
CHANGED
package/src/services/ai/index.js
CHANGED
|
@@ -156,40 +156,30 @@ const validateAnthropic = async (credentials) => {
|
|
|
156
156
|
const isOAuthToken = token && token.startsWith('sk-ant-oat');
|
|
157
157
|
|
|
158
158
|
if (isOAuthToken) {
|
|
159
|
-
// OAuth tokens
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (response.ok) {
|
|
170
|
-
return { valid: true, tokenType: 'oauth', subscriptionType: credentials.subscriptionType || 'max' };
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Try alternate endpoint
|
|
174
|
-
const altResponse = await fetch('https://claude.ai/api/auth/session', {
|
|
175
|
-
method: 'GET',
|
|
176
|
-
headers: {
|
|
177
|
-
'Authorization': `Bearer ${token}`,
|
|
178
|
-
'Cookie': `sessionKey=${token}`
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
if (altResponse.ok) {
|
|
183
|
-
return { valid: true, tokenType: 'oauth', subscriptionType: credentials.subscriptionType || 'max' };
|
|
159
|
+
// For OAuth tokens from Keychain/SecureStorage, trust them directly
|
|
160
|
+
// No need to validate - they come from a trusted source (OS secure storage)
|
|
161
|
+
if (credentials.fromKeychain) {
|
|
162
|
+
return {
|
|
163
|
+
valid: true,
|
|
164
|
+
tokenType: 'oauth',
|
|
165
|
+
subscriptionType: credentials.subscriptionType || 'max',
|
|
166
|
+
trusted: true
|
|
167
|
+
};
|
|
184
168
|
}
|
|
185
169
|
|
|
186
|
-
// For OAuth tokens
|
|
187
|
-
//
|
|
188
|
-
|
|
189
|
-
|
|
170
|
+
// For manually entered OAuth tokens, we can't validate them easily
|
|
171
|
+
// Claude doesn't have a public API for OAuth token validation
|
|
172
|
+
// Just check the format and accept
|
|
173
|
+
if (token.length > 50) {
|
|
174
|
+
return {
|
|
175
|
+
valid: true,
|
|
176
|
+
tokenType: 'oauth',
|
|
177
|
+
subscriptionType: 'max',
|
|
178
|
+
warning: 'Token format looks valid, but could not verify online'
|
|
179
|
+
};
|
|
190
180
|
}
|
|
191
181
|
|
|
192
|
-
return { valid: false, error: 'OAuth token
|
|
182
|
+
return { valid: false, error: 'Invalid OAuth token format' };
|
|
193
183
|
}
|
|
194
184
|
|
|
195
185
|
// Standard API key validation
|
|
@@ -214,6 +204,16 @@ const validateAnthropic = async (credentials) => {
|
|
|
214
204
|
const error = await response.json();
|
|
215
205
|
return { valid: false, error: error.error?.message || 'Invalid API key' };
|
|
216
206
|
} catch (e) {
|
|
207
|
+
// If validation fails but token is from Keychain, still trust it
|
|
208
|
+
if (credentials.fromKeychain) {
|
|
209
|
+
return {
|
|
210
|
+
valid: true,
|
|
211
|
+
tokenType: 'oauth',
|
|
212
|
+
subscriptionType: credentials.subscriptionType || 'max',
|
|
213
|
+
trusted: true,
|
|
214
|
+
warning: 'Could not validate online, but trusted from Keychain'
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
217
|
return { valid: false, error: e.message };
|
|
218
218
|
}
|
|
219
219
|
};
|
|
@@ -657,14 +657,32 @@ const parseCredentialJson = (output, entry) => {
|
|
|
657
657
|
|
|
658
658
|
/**
|
|
659
659
|
* Read tokens from macOS Keychain
|
|
660
|
+
* Optimized: stops after finding first valid token per provider to minimize password prompts
|
|
660
661
|
*/
|
|
661
662
|
const readMacOSKeychain = () => {
|
|
662
663
|
if (platform !== 'darwin') return [];
|
|
663
664
|
|
|
664
665
|
const results = [];
|
|
665
666
|
const { execSync } = require('child_process');
|
|
667
|
+
const foundProviders = new Set(); // Track which providers we already found
|
|
668
|
+
|
|
669
|
+
// Sort entries to prioritize most common ones first
|
|
670
|
+
const priorityOrder = ['Claude Code-credentials', 'Cursor-credentials', 'Claude Safe Storage'];
|
|
671
|
+
const sortedEntries = [...CREDENTIAL_ENTRIES].sort((a, b) => {
|
|
672
|
+
const aIdx = priorityOrder.indexOf(a.service);
|
|
673
|
+
const bIdx = priorityOrder.indexOf(b.service);
|
|
674
|
+
if (aIdx === -1 && bIdx === -1) return 0;
|
|
675
|
+
if (aIdx === -1) return 1;
|
|
676
|
+
if (bIdx === -1) return -1;
|
|
677
|
+
return aIdx - bIdx;
|
|
678
|
+
});
|
|
666
679
|
|
|
667
|
-
for (const entry of
|
|
680
|
+
for (const entry of sortedEntries) {
|
|
681
|
+
// Skip if we already found a token for this provider
|
|
682
|
+
if (foundProviders.has(entry.provider)) {
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
|
|
668
686
|
try {
|
|
669
687
|
const output = execSync(
|
|
670
688
|
`security find-generic-password -s "${entry.service}" -w 2>/dev/null`,
|
|
@@ -672,10 +690,14 @@ const readMacOSKeychain = () => {
|
|
|
672
690
|
).trim();
|
|
673
691
|
|
|
674
692
|
if (output) {
|
|
675
|
-
|
|
693
|
+
const tokens = parseCredentialJson(output, entry);
|
|
694
|
+
if (tokens.length > 0) {
|
|
695
|
+
results.push(...tokens);
|
|
696
|
+
foundProviders.add(entry.provider); // Mark this provider as found
|
|
697
|
+
}
|
|
676
698
|
}
|
|
677
699
|
} catch {
|
|
678
|
-
// Entry not found or access denied
|
|
700
|
+
// Entry not found or access denied - no password prompt for missing entries
|
|
679
701
|
}
|
|
680
702
|
}
|
|
681
703
|
|