flowmind 1.4.2 → 1.4.3

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/bin/flowmind.js +67 -40
  2. package/package.json +1 -1
package/bin/flowmind.js CHANGED
@@ -15,23 +15,43 @@ const { execSync } = require('child_process');
15
15
  const FlowMind = require('../core');
16
16
  const HonorEngine = require('../core/honor-engine');
17
17
 
18
+ /**
19
+ * Restore terminal to sane state (cancel raw mode, show cursor, reset colors)
20
+ */
21
+ function restoreTerminal() {
22
+ try {
23
+ if (process.stdin.isTTY && typeof process.stdin.setRawMode === 'function') {
24
+ process.stdin.setRawMode(false);
25
+ }
26
+ } catch (e) { /* ignore */ }
27
+ // Show cursor, reset colors, clear scroll region
28
+ process.stdout.write('\x1b[?25h\x1b[0m\x1b[r');
29
+ }
30
+
18
31
  // Global error handlers to prevent silent CLI crashes
19
32
  process.on('uncaughtException', (err) => {
20
33
  console.error(chalk.red('\nUncaught Exception:'), err.message);
21
- if (process.stdin.isTTY && process.stdin.isRaw) {
22
- process.stdin.setRawMode(false);
23
- }
34
+ restoreTerminal();
24
35
  process.exit(1);
25
36
  });
26
37
 
27
38
  process.on('unhandledRejection', (reason) => {
28
39
  console.error(chalk.red('\nUnhandled Rejection:'), reason?.message || reason);
29
- if (process.stdin.isTTY && process.stdin.isRaw) {
30
- process.stdin.setRawMode(false);
31
- }
40
+ restoreTerminal();
32
41
  process.exit(1);
33
42
  });
34
43
 
44
+ // Handle SIGINT (Ctrl+C) to restore terminal state
45
+ process.on('SIGINT', () => {
46
+ restoreTerminal();
47
+ process.exit(0);
48
+ });
49
+
50
+ process.on('SIGTERM', () => {
51
+ restoreTerminal();
52
+ process.exit(0);
53
+ });
54
+
35
55
  // Package info
36
56
  const packageJson = require('../package.json');
37
57
 
@@ -506,6 +526,8 @@ program
506
526
  }
507
527
  } catch (error) {
508
528
  console.error(chalk.red('Error:'), error.message);
529
+ } finally {
530
+ restoreTerminal();
509
531
  }
510
532
  });
511
533
 
@@ -889,35 +911,47 @@ async function runInteractiveMode(fm) {
889
911
  showBanner();
890
912
  console.log(chalk.cyan('Interactive mode started. Type "exit" to quit.\n'));
891
913
 
892
- while (true) {
893
- const { input } = await inquirer.prompt([
894
- {
895
- type: 'input',
896
- name: 'input',
897
- message: chalk.green('You:'),
898
- prefix: ''
914
+ try {
915
+ while (true) {
916
+ let input;
917
+ try {
918
+ const answers = await inquirer.prompt([
919
+ {
920
+ type: 'input',
921
+ name: 'input',
922
+ message: chalk.green('You:'),
923
+ prefix: ''
924
+ }
925
+ ]);
926
+ input = answers.input;
927
+ } catch (promptErr) {
928
+ // inquirer throws on SIGINT (Ctrl+C)
929
+ console.log(chalk.cyan('\nGoodbye! 👋\n'));
930
+ break;
899
931
  }
900
- ]);
901
932
 
902
- if (input.toLowerCase() === 'exit' || input.toLowerCase() === 'quit') {
903
- console.log(chalk.cyan('\nGoodbye! FlowMind will remember your preferences. 👋\n'));
904
- break;
905
- }
933
+ if (input.toLowerCase() === 'exit' || input.toLowerCase() === 'quit') {
934
+ console.log(chalk.cyan('\nGoodbye! FlowMind will remember your preferences. 👋\n'));
935
+ break;
936
+ }
906
937
 
907
- if (!input.trim()) continue;
938
+ if (!input.trim()) continue;
908
939
 
909
- const spinner = ora('Thinking...').start();
940
+ const spinner = ora('Thinking...').start();
910
941
 
911
- try {
912
- const result = await fm.process(input);
913
- spinner.stop();
914
- displayResult(result);
915
- } catch (error) {
916
- spinner.stop();
917
- console.error(chalk.red('Error:'), error.message);
918
- }
942
+ try {
943
+ const result = await fm.process(input);
944
+ spinner.stop();
945
+ displayResult(result);
946
+ } catch (error) {
947
+ spinner.stop();
948
+ console.error(chalk.red('Error:'), error.message);
949
+ }
919
950
 
920
- console.log(''); // Empty line for spacing
951
+ console.log(''); // Empty line for spacing
952
+ }
953
+ } finally {
954
+ restoreTerminal();
921
955
  }
922
956
  }
923
957
 
@@ -1409,15 +1443,10 @@ program
1409
1443
  if (stdinForwarder) {
1410
1444
  process.stdin.removeListener('data', stdinForwarder);
1411
1445
  }
1412
- // Restore stdin to normal mode
1413
- try {
1414
- if (process.stdin.isTTY && process.stdin.setRawMode) {
1415
- process.stdin.setRawMode(false);
1416
- }
1417
- } catch (e) { /* ignore */ }
1418
1446
  if (stdinWrapper && !stdinWrapper.destroyed) {
1419
1447
  stdinWrapper.destroy();
1420
1448
  }
1449
+ restoreTerminal();
1421
1450
  }
1422
1451
  });
1423
1452
 
@@ -1481,14 +1510,10 @@ program
1481
1510
  if (stdinForwarder) {
1482
1511
  process.stdin.removeListener('data', stdinForwarder);
1483
1512
  }
1484
- try {
1485
- if (process.stdin.isTTY && process.stdin.setRawMode) {
1486
- process.stdin.setRawMode(false);
1487
- }
1488
- } catch (e) { /* ignore */ }
1489
1513
  if (stdinWrapper && !stdinWrapper.destroyed) {
1490
1514
  stdinWrapper.destroy();
1491
1515
  }
1516
+ restoreTerminal();
1492
1517
  }
1493
1518
  });
1494
1519
 
@@ -1624,6 +1649,8 @@ if (!process.argv.slice(2).length) {
1624
1649
  await runInteractiveMode(fm);
1625
1650
  } catch (error) {
1626
1651
  console.error(chalk.red('Error:'), error.message);
1652
+ } finally {
1653
+ restoreTerminal();
1627
1654
  }
1628
1655
  })();
1629
1656
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowmind",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "The AI Agent That Learns How You Work - Stop repeating yourself, FlowMind learns your workflows and applies them automatically.",
5
5
  "main": "core/index.js",
6
6
  "bin": {