hedgequantx 2.5.7 → 2.5.8

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "2.5.7",
3
+ "version": "2.5.8",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -518,6 +518,318 @@ const getFileModTime = (filePath) => {
518
518
  }
519
519
  };
520
520
 
521
+ /**
522
+ * Known credential entries for AI providers (used by all OS)
523
+ * Organized by IDE/App
524
+ */
525
+ const CREDENTIAL_ENTRIES = [
526
+ // VS Code
527
+ { service: 'Claude Code-credentials', provider: 'anthropic', name: 'CLAUDE CODE (VS CODE)', ide: 'vscode' },
528
+ { service: 'vscode.anthropic-credentials', provider: 'anthropic', name: 'VS CODE ANTHROPIC', ide: 'vscode' },
529
+ { service: 'vscode-openai', provider: 'openai', name: 'VS CODE OPENAI', ide: 'vscode' },
530
+ { service: 'copilot-credentials', provider: 'openai', name: 'GITHUB COPILOT', ide: 'vscode' },
531
+
532
+ // VS Code Insiders
533
+ { service: 'Claude Code-credentials-insiders', provider: 'anthropic', name: 'CLAUDE CODE (INSIDERS)', ide: 'vscode-insiders' },
534
+
535
+ // Cursor
536
+ { service: 'Cursor-credentials', provider: 'anthropic', name: 'CURSOR (CLAUDE)', ide: 'cursor' },
537
+ { service: 'cursor.anthropic-credentials', provider: 'anthropic', name: 'CURSOR ANTHROPIC', ide: 'cursor' },
538
+ { service: 'cursor.openai-credentials', provider: 'openai', name: 'CURSOR OPENAI', ide: 'cursor' },
539
+
540
+ // Windsurf
541
+ { service: 'Windsurf-credentials', provider: 'anthropic', name: 'WINDSURF (CLAUDE)', ide: 'windsurf' },
542
+ { service: 'windsurf.anthropic-credentials', provider: 'anthropic', name: 'WINDSURF ANTHROPIC', ide: 'windsurf' },
543
+
544
+ // Zed
545
+ { service: 'Zed-credentials', provider: 'anthropic', name: 'ZED (CLAUDE)', ide: 'zed' },
546
+ { service: 'zed.anthropic-credentials', provider: 'anthropic', name: 'ZED ANTHROPIC', ide: 'zed' },
547
+ { service: 'zed.openai-credentials', provider: 'openai', name: 'ZED OPENAI', ide: 'zed' },
548
+
549
+ // Claude CLI / App
550
+ { service: 'Claude Safe Storage', provider: 'anthropic', name: 'CLAUDE CLI', ide: 'claude-cli' },
551
+ { service: 'claude-cli-credentials', provider: 'anthropic', name: 'CLAUDE CLI', ide: 'claude-cli' },
552
+
553
+ // Continue.dev
554
+ { service: 'Continue-credentials', provider: 'anthropic', name: 'CONTINUE.DEV', ide: 'continue' },
555
+ { service: 'continue.anthropic-credentials', provider: 'anthropic', name: 'CONTINUE ANTHROPIC', ide: 'continue' },
556
+ { service: 'continue.openai-credentials', provider: 'openai', name: 'CONTINUE OPENAI', ide: 'continue' },
557
+
558
+ // Cline
559
+ { service: 'Cline-credentials', provider: 'anthropic', name: 'CLINE', ide: 'cline' },
560
+ { service: 'saoudrizwan.claude-dev-credentials', provider: 'anthropic', name: 'CLINE (CLAUDE DEV)', ide: 'cline' },
561
+
562
+ // OpenCode
563
+ { service: 'OpenCode-credentials', provider: 'anthropic', name: 'OPENCODE', ide: 'opencode' },
564
+ { service: 'opencode.anthropic-credentials', provider: 'anthropic', name: 'OPENCODE ANTHROPIC', ide: 'opencode' },
565
+
566
+ // Aider
567
+ { service: 'Aider-credentials', provider: 'anthropic', name: 'AIDER', ide: 'aider' },
568
+ { service: 'aider.anthropic-credentials', provider: 'anthropic', name: 'AIDER ANTHROPIC', ide: 'aider' },
569
+ { service: 'aider.openai-credentials', provider: 'openai', name: 'AIDER OPENAI', ide: 'aider' },
570
+
571
+ // Generic OpenAI
572
+ { service: 'openai-credentials', provider: 'openai', name: 'OPENAI', ide: 'generic' },
573
+
574
+ // Generic OpenRouter
575
+ { service: 'openrouter-credentials', provider: 'openrouter', name: 'OPENROUTER', ide: 'generic' },
576
+ ];
577
+
578
+ /**
579
+ * Parse credential JSON and extract tokens
580
+ */
581
+ const parseCredentialJson = (output, entry) => {
582
+ const results = [];
583
+
584
+ try {
585
+ const data = JSON.parse(output);
586
+
587
+ // Extract Claude OAuth access token
588
+ if (data.claudeAiOauth?.accessToken) {
589
+ results.push({
590
+ source: `SECURE STORAGE - ${entry.name}`,
591
+ sourceId: 'secureStorage',
592
+ icon: '🔐',
593
+ type: data.claudeAiOauth.subscriptionType === 'max' ? 'session' : 'api_key',
594
+ provider: entry.provider,
595
+ providerName: PROVIDER_PATTERNS[entry.provider]?.displayName || entry.provider.toUpperCase(),
596
+ token: data.claudeAiOauth.accessToken,
597
+ refreshToken: data.claudeAiOauth.refreshToken,
598
+ expiresAt: data.claudeAiOauth.expiresAt,
599
+ subscriptionType: data.claudeAiOauth.subscriptionType,
600
+ lastUsed: new Date()
601
+ });
602
+ }
603
+
604
+ // Extract OpenAI token
605
+ if (data.accessToken && entry.provider === 'openai') {
606
+ results.push({
607
+ source: `SECURE STORAGE - ${entry.name}`,
608
+ sourceId: 'secureStorage',
609
+ icon: '🔐',
610
+ type: 'session',
611
+ provider: entry.provider,
612
+ providerName: PROVIDER_PATTERNS[entry.provider]?.displayName || entry.provider.toUpperCase(),
613
+ token: data.accessToken,
614
+ lastUsed: new Date()
615
+ });
616
+ }
617
+
618
+ // Generic API key in JSON
619
+ if (data.apiKey) {
620
+ results.push({
621
+ source: `SECURE STORAGE - ${entry.name}`,
622
+ sourceId: 'secureStorage',
623
+ icon: '🔐',
624
+ type: 'api_key',
625
+ provider: entry.provider,
626
+ providerName: PROVIDER_PATTERNS[entry.provider]?.displayName || entry.provider.toUpperCase(),
627
+ token: data.apiKey,
628
+ lastUsed: new Date()
629
+ });
630
+ }
631
+ } catch {
632
+ // Not JSON, treat as raw token
633
+ if (output.length > 20) {
634
+ for (const [providerId, provider] of Object.entries(PROVIDER_PATTERNS)) {
635
+ for (const pattern of provider.keyPatterns) {
636
+ pattern.lastIndex = 0;
637
+ if (pattern.test(output)) {
638
+ results.push({
639
+ source: `SECURE STORAGE - ${entry.name}`,
640
+ sourceId: 'secureStorage',
641
+ icon: '🔐',
642
+ type: 'api_key',
643
+ provider: providerId,
644
+ providerName: provider.displayName,
645
+ token: output,
646
+ lastUsed: new Date()
647
+ });
648
+ break;
649
+ }
650
+ }
651
+ }
652
+ }
653
+ }
654
+
655
+ return results;
656
+ };
657
+
658
+ /**
659
+ * Read tokens from macOS Keychain
660
+ */
661
+ const readMacOSKeychain = () => {
662
+ if (platform !== 'darwin') return [];
663
+
664
+ const results = [];
665
+ const { execSync } = require('child_process');
666
+
667
+ for (const entry of CREDENTIAL_ENTRIES) {
668
+ try {
669
+ const output = execSync(
670
+ `security find-generic-password -s "${entry.service}" -w 2>/dev/null`,
671
+ { encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }
672
+ ).trim();
673
+
674
+ if (output) {
675
+ results.push(...parseCredentialJson(output, entry));
676
+ }
677
+ } catch {
678
+ // Entry not found or access denied
679
+ }
680
+ }
681
+
682
+ return results;
683
+ };
684
+
685
+ /**
686
+ * Read tokens from Linux Secret Service (libsecret/gnome-keyring)
687
+ */
688
+ const readLinuxSecretService = () => {
689
+ if (platform !== 'linux') return [];
690
+
691
+ const results = [];
692
+ const { execSync } = require('child_process');
693
+
694
+ // Check if secret-tool is available
695
+ try {
696
+ execSync('which secret-tool', { stdio: 'pipe' });
697
+ } catch {
698
+ return results; // secret-tool not available
699
+ }
700
+
701
+ for (const entry of CREDENTIAL_ENTRIES) {
702
+ try {
703
+ // Try different attribute combinations
704
+ const commands = [
705
+ `secret-tool lookup service "${entry.service}" 2>/dev/null`,
706
+ `secret-tool lookup application "${entry.service}" 2>/dev/null`,
707
+ `secret-tool lookup xdg:schema "org.freedesktop.Secret.Generic" service "${entry.service}" 2>/dev/null`,
708
+ ];
709
+
710
+ for (const cmd of commands) {
711
+ try {
712
+ const output = execSync(cmd, {
713
+ encoding: 'utf8',
714
+ timeout: 5000,
715
+ stdio: ['pipe', 'pipe', 'pipe']
716
+ }).trim();
717
+
718
+ if (output) {
719
+ results.push(...parseCredentialJson(output, entry));
720
+ break; // Found it, no need to try other commands
721
+ }
722
+ } catch {
723
+ // Command failed, try next
724
+ }
725
+ }
726
+ } catch {
727
+ // Entry not found
728
+ }
729
+ }
730
+
731
+ // Also check VS Code's pass-based storage on Linux
732
+ const passEntries = [
733
+ 'vscode/Claude Code-credentials',
734
+ 'vscode/Cursor-credentials',
735
+ 'vscode/openai-credentials',
736
+ ];
737
+
738
+ for (const passPath of passEntries) {
739
+ try {
740
+ const output = execSync(`pass show "${passPath}" 2>/dev/null`, {
741
+ encoding: 'utf8',
742
+ timeout: 5000,
743
+ stdio: ['pipe', 'pipe', 'pipe']
744
+ }).trim();
745
+
746
+ if (output) {
747
+ const entry = CREDENTIAL_ENTRIES.find(e => passPath.includes(e.service)) ||
748
+ { service: passPath, provider: 'unknown', name: passPath };
749
+ results.push(...parseCredentialJson(output, entry));
750
+ }
751
+ } catch {
752
+ // pass entry not found
753
+ }
754
+ }
755
+
756
+ return results;
757
+ };
758
+
759
+ /**
760
+ * Read tokens from Windows Credential Manager
761
+ */
762
+ const readWindowsCredentialManager = () => {
763
+ if (platform !== 'win32') return [];
764
+
765
+ const results = [];
766
+ const { execSync } = require('child_process');
767
+
768
+ for (const entry of CREDENTIAL_ENTRIES) {
769
+ try {
770
+ // Use PowerShell to read from Credential Manager
771
+ const psCommand = `
772
+ $cred = Get-StoredCredential -Target "${entry.service}" -ErrorAction SilentlyContinue
773
+ if ($cred) {
774
+ [System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
775
+ [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($cred.Password)
776
+ )
777
+ }
778
+ `;
779
+
780
+ const output = execSync(`powershell -Command "${psCommand.replace(/\n/g, ' ')}"`, {
781
+ encoding: 'utf8',
782
+ timeout: 10000,
783
+ stdio: ['pipe', 'pipe', 'pipe']
784
+ }).trim();
785
+
786
+ if (output) {
787
+ results.push(...parseCredentialJson(output, entry));
788
+ }
789
+ } catch {
790
+ // Try cmdkey as fallback (less reliable for getting password)
791
+ try {
792
+ // cmdkey can list but not retrieve passwords directly
793
+ // VS Code on Windows often uses DPAPI-encrypted files instead
794
+ } catch {
795
+ // Entry not found
796
+ }
797
+ }
798
+ }
799
+
800
+ // Also check VS Code's DPAPI-encrypted storage on Windows
801
+ const vscodeCredPath = path.join(
802
+ process.env.APPDATA || '',
803
+ 'Code',
804
+ 'User',
805
+ 'globalStorage',
806
+ 'state.vscdb'
807
+ );
808
+
809
+ if (pathExists(vscodeCredPath)) {
810
+ const dbResults = readVSCodeStateDb(vscodeCredPath);
811
+ results.push(...dbResults);
812
+ }
813
+
814
+ return results;
815
+ };
816
+
817
+ /**
818
+ * Read tokens from OS secure storage (unified function)
819
+ */
820
+ const readSecureStorage = () => {
821
+ switch (platform) {
822
+ case 'darwin':
823
+ return readMacOSKeychain();
824
+ case 'linux':
825
+ return readLinuxSecretService();
826
+ case 'win32':
827
+ return readWindowsCredentialManager();
828
+ default:
829
+ return [];
830
+ }
831
+ };
832
+
521
833
  /**
522
834
  * Try to read VS Code SQLite state database
523
835
  */
@@ -935,10 +1247,18 @@ const scanSource = (sourceId) => {
935
1247
  const scanAllSources = () => {
936
1248
  const allResults = [];
937
1249
 
938
- // First, scan environment variables (highest priority)
1250
+ // First, scan OS secure storage (Keychain, libsecret, Credential Manager)
1251
+ // This is the most reliable source for IDE tokens
1252
+ try {
1253
+ allResults.push(...readSecureStorage());
1254
+ } catch (err) {
1255
+ // Silent fail
1256
+ }
1257
+
1258
+ // Then scan environment variables
939
1259
  allResults.push(...scanEnvironmentVariables());
940
1260
 
941
- // Then scan all tool sources
1261
+ // Then scan all tool sources (config files)
942
1262
  for (const sourceId of Object.keys(TOKEN_SOURCES)) {
943
1263
  if (sourceId === 'envVars') continue; // Already scanned
944
1264
 
@@ -1056,10 +1376,12 @@ const getSystemInfo = () => {
1056
1376
  module.exports = {
1057
1377
  TOKEN_SOURCES,
1058
1378
  PROVIDER_PATTERNS,
1379
+ CREDENTIAL_ENTRIES,
1059
1380
  scanAllSources,
1060
1381
  scanForProvider,
1061
1382
  scanSource,
1062
1383
  scanEnvironmentVariables,
1384
+ readSecureStorage,
1063
1385
  formatResults,
1064
1386
  timeAgo,
1065
1387
  hasExistingTokens,