hedgequantx 1.2.143 → 1.2.144

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/app.js +111 -77
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "1.2.143",
3
+ "version": "1.2.144",
4
4
  "description": "Prop Futures Algo Trading CLI - Connect to Topstep, Alpha Futures, and other prop firms",
5
5
  "main": "src/app.js",
6
6
  "bin": {
package/src/app.js CHANGED
@@ -46,6 +46,27 @@ const restoreTerminal = () => {
46
46
  }
47
47
  };
48
48
 
49
+ /**
50
+ * Ensure stdin is ready for inquirer prompts
51
+ * This fixes input leaking to bash after session restore
52
+ */
53
+ const prepareStdin = () => {
54
+ try {
55
+ // Remove any raw mode that might be left from previous operations
56
+ if (process.stdin.isTTY && process.stdin.isRaw) {
57
+ process.stdin.setRawMode(false);
58
+ }
59
+ // Remove any lingering keypress listeners
60
+ process.stdin.removeAllListeners('keypress');
61
+ process.stdin.removeAllListeners('data');
62
+ // Pause stdin so inquirer can take control
63
+ process.stdin.pause();
64
+ // Small delay to let event loop settle
65
+ } catch (e) {
66
+ // Ignore errors
67
+ }
68
+ };
69
+
49
70
  // Register global handlers to restore terminal on exit/crash
50
71
  process.on('exit', restoreTerminal);
51
72
  process.on('SIGINT', () => { restoreTerminal(); process.exit(0); });
@@ -802,89 +823,102 @@ const handleUpdate = async () => {
802
823
  * Main application loop
803
824
  */
804
825
  const run = async () => {
805
- await banner();
806
-
807
- // Try to restore session
808
- const spinner = ora('Restoring session...').start();
809
- const restored = await connections.restoreFromStorage();
810
-
811
- if (restored) {
812
- spinner.succeed('Session restored');
813
- currentService = connections.getAll()[0].service;
814
- } else {
815
- spinner.info('No active session');
816
- }
817
-
818
- // Main loop
819
- while (true) {
820
- // Refresh banner with stats
826
+ try {
821
827
  await banner();
822
828
 
823
- if (!connections.isConnected()) {
824
- const choice = await mainMenu();
825
-
826
- if (choice === 'exit') {
827
- console.log(chalk.gray('Goodbye!'));
828
- process.exit(0);
829
- }
830
-
831
- if (choice === 'projectx') {
832
- const service = await projectXMenu();
833
- if (service) currentService = service;
834
- }
835
-
836
- if (choice === 'rithmic') {
837
- const service = await rithmicMenu();
838
- if (service) currentService = service;
839
- }
840
-
841
- if (choice === 'tradovate') {
842
- const service = await tradovateMenu();
843
- if (service) currentService = service;
844
- }
829
+ // Try to restore session
830
+ const spinner = ora('Restoring session...').start();
831
+ const restored = await connections.restoreFromStorage();
832
+
833
+ if (restored) {
834
+ spinner.succeed('Session restored');
835
+ currentService = connections.getAll()[0].service;
845
836
  } else {
846
- const action = await dashboardMenu(currentService);
847
-
848
- switch (action) {
849
- case 'accounts':
850
- await showAccounts(currentService);
851
- break;
852
-
853
- case 'stats':
854
- await showStats(currentService);
855
- break;
856
- case 'add_prop_account':
857
- // Show platform selection menu
858
- const platformChoice = await addPropAccountMenu();
859
- if (platformChoice === 'projectx') {
860
- const newService = await projectXMenu();
861
- if (newService) currentService = newService;
862
- } else if (platformChoice === 'rithmic') {
863
- const newService = await rithmicMenu();
864
- if (newService) currentService = newService;
865
- } else if (platformChoice === 'tradovate') {
866
- const newService = await tradovateMenu();
867
- if (newService) currentService = newService;
837
+ spinner.info('No active session');
838
+ }
839
+
840
+ // Main loop
841
+ while (true) {
842
+ try {
843
+ // Ensure stdin is ready for prompts (fixes input leaking to bash)
844
+ prepareStdin();
845
+
846
+ // Refresh banner with stats
847
+ await banner();
848
+
849
+ if (!connections.isConnected()) {
850
+ const choice = await mainMenu();
851
+
852
+ if (choice === 'exit') {
853
+ console.log(chalk.gray('Goodbye!'));
854
+ process.exit(0);
855
+ }
856
+
857
+ if (choice === 'projectx') {
858
+ const service = await projectXMenu();
859
+ if (service) currentService = service;
860
+ }
861
+
862
+ if (choice === 'rithmic') {
863
+ const service = await rithmicMenu();
864
+ if (service) currentService = service;
868
865
  }
869
- break;
870
- case 'algotrading':
871
- await algoTradingMenu(currentService);
872
- break;
873
- case 'update':
874
- const updateResult = await handleUpdate();
875
- if (updateResult === 'restart') return; // Stop loop, new process spawned
876
- break;
877
- case 'disconnect':
878
- const connCount = connections.count();
879
- connections.disconnectAll();
880
- currentService = null;
881
- console.log(chalk.yellow(`Disconnected ${connCount} connection${connCount > 1 ? 's' : ''}`));
882
- break;
883
- case 'exit':
884
- console.log(chalk.gray('Goodbye!'));
885
- process.exit(0);
866
+
867
+ if (choice === 'tradovate') {
868
+ const service = await tradovateMenu();
869
+ if (service) currentService = service;
870
+ }
871
+ } else {
872
+ const action = await dashboardMenu(currentService);
873
+
874
+ switch (action) {
875
+ case 'accounts':
876
+ await showAccounts(currentService);
877
+ break;
878
+
879
+ case 'stats':
880
+ await showStats(currentService);
881
+ break;
882
+ case 'add_prop_account':
883
+ // Show platform selection menu
884
+ const platformChoice = await addPropAccountMenu();
885
+ if (platformChoice === 'projectx') {
886
+ const newService = await projectXMenu();
887
+ if (newService) currentService = newService;
888
+ } else if (platformChoice === 'rithmic') {
889
+ const newService = await rithmicMenu();
890
+ if (newService) currentService = newService;
891
+ } else if (platformChoice === 'tradovate') {
892
+ const newService = await tradovateMenu();
893
+ if (newService) currentService = newService;
894
+ }
895
+ break;
896
+ case 'algotrading':
897
+ await algoTradingMenu(currentService);
898
+ break;
899
+ case 'update':
900
+ const updateResult = await handleUpdate();
901
+ if (updateResult === 'restart') return; // Stop loop, new process spawned
902
+ break;
903
+ case 'disconnect':
904
+ const connCount = connections.count();
905
+ connections.disconnectAll();
906
+ currentService = null;
907
+ console.log(chalk.yellow(`Disconnected ${connCount} connection${connCount > 1 ? 's' : ''}`));
908
+ break;
909
+ case 'exit':
910
+ console.log(chalk.gray('Goodbye!'));
911
+ process.exit(0);
912
+ }
913
+ }
914
+ } catch (loopError) {
915
+ console.error(chalk.red('Error in main loop:'), loopError.message);
916
+ // Continue the loop
886
917
  }
887
918
  }
919
+ } catch (error) {
920
+ console.error(chalk.red('Fatal error:'), error.message);
921
+ process.exit(1);
888
922
  }
889
923
  };
890
924