fleetbo-cockpit-cli 1.0.112 → 1.0.113

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/cli.js +72 -65
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -630,109 +630,116 @@ if (command === 'alex') {
630
630
  console.log('\x1b[32mAlex ❯\x1b[0m Describe your feature.');
631
631
  console.log('');
632
632
 
633
- // ── Lecture raw stdin pour détecter le paste ──
634
- // Un paste arrive en un seul burst de données en <30ms.
635
- // Une frappe manuelle arrive caractère par caractère avec >30ms entre chaque.
636
- // On accumule tout le burst, puis on affiche et attend confirmation.
633
+ const rl = readline.createInterface({
634
+ input: process.stdin,
635
+ output: process.stdout,
636
+ prompt: `\x1b[34m${dynamicUsername} \x1b[0m`
637
+ });
637
638
 
638
- process.stdin.setRawMode(true);
639
- process.stdin.resume();
640
- process.stdin.setEncoding('utf8');
639
+ // Active les events keypress sur stdin pour détecter le paste
640
+ readline.emitKeypressEvents(process.stdin, rl);
641
+ if (process.stdin.isTTY) process.stdin.setRawMode(true);
641
642
 
642
- let inputBuffer = ""; // ce qui est affiché à l'écran
643
+ let inputBuffer = "";
643
644
  let isProcessing = false;
644
- let pasteChunk = ""; // accumule le burst de données
645
+ let currentLine = "";
646
+ let isPasting = false;
645
647
  let pasteTimer = null;
646
648
 
647
- const showPrompt = () => {
648
- process.stdout.write(`\x1b[34m${dynamicUsername} ❯ \x1b[0m`);
649
- };
650
-
651
- const showConfirmHint = () => {
652
- process.stdout.write(`\n\x1b[90m↵ to send · keep typing to add more\x1b[0m\n`);
653
- showPrompt();
654
- process.stdout.write(inputBuffer);
649
+ const resetPrompt = () => {
650
+ rl.setPrompt(`\x1b[34m${dynamicUsername} ❯ \x1b[0m`);
651
+ rl.prompt(true);
655
652
  };
656
653
 
657
- const submitInput = async () => {
654
+ const submit = async () => {
658
655
  const finalPrompt = inputBuffer.trim();
659
656
  inputBuffer = "";
660
- if (!finalPrompt) { process.stdout.write('\n'); showPrompt(); return; }
657
+ currentLine = "";
658
+
659
+ if (!finalPrompt) { resetPrompt(); return; }
661
660
 
662
661
  if (finalPrompt.length > 1000) {
663
- process.stdout.write(`\n\x1b[31m⛔ [Alex Safety] Mission rejected: Excessive size (${finalPrompt.length}/1000 characters).\x1b[0m\n`);
664
- showPrompt();
662
+ console.log(`\n\x1b[31m⛔ [Alex Safety] Mission rejected: Excessive size (${finalPrompt.length}/1000 characters).\x1b[0m`);
663
+ resetPrompt();
665
664
  return;
666
665
  }
667
666
 
668
- process.stdout.write('\n');
669
667
  isProcessing = true;
668
+ rl.setPrompt("");
669
+ process.stdout.write('\n');
670
670
  await processAlexRequest(finalPrompt);
671
671
  isProcessing = false;
672
672
  console.log('');
673
- showPrompt();
674
- };
675
-
676
- const flushPaste = () => {
677
- // Le burst est terminé — on l'ajoute au buffer et on affiche
678
- const pasted = pasteChunk;
679
- pasteChunk = "";
680
- pasteTimer = null;
681
-
682
- // Affiche le texte collé tel quel à l'écran
683
- process.stdout.write(pasted);
684
- inputBuffer += pasted;
685
-
686
- // Affiche le hint de confirmation
687
- showConfirmHint();
673
+ resetPrompt();
688
674
  };
689
675
 
690
- showPrompt();
691
-
692
- process.stdin.on('data', (key) => {
676
+ // Keypress : détecte si c'est un paste (chunk > 1 char) ou frappe normale
677
+ process.stdin.on('keypress', (char, key) => {
693
678
  if (isProcessing) return;
694
679
 
695
680
  // Ctrl+C
696
- if (key === '\u0003') {
681
+ if (key && key.ctrl && key.name === 'c') {
697
682
  console.log('\n\x1b[90mAlex session closed.\x1b[0m');
698
683
  process.exit(0);
699
684
  }
700
685
 
701
- // Entrée
702
- if (key === '\r' || key === '\n') {
686
+ // Entrée : soumettre si buffer non vide
687
+ if (key && (key.name === 'return' || key.name === 'enter')) {
703
688
  if (inputBuffer.trim() !== "") {
704
- // Déjà du contenu → soumettre
705
- submitInput();
706
- } else {
707
- // Buffer vide → juste nouvelle ligne
708
- process.stdout.write('\n');
709
- showPrompt();
689
+ submit();
710
690
  }
711
691
  return;
712
692
  }
713
693
 
714
- // Backspace
715
- if (key === '\u007f') {
716
- if (inputBuffer.length > 0) {
717
- inputBuffer = inputBuffer.slice(0, -1);
718
- process.stdout.write('\b \b');
719
- }
720
- return;
694
+ // Paste : char arrive avec plusieurs caractères d'un coup
695
+ if (char && char.length > 1) {
696
+ isPasting = true;
697
+ if (pasteTimer) clearTimeout(pasteTimer);
698
+ // Accumule dans inputBuffer via readline line event
699
+ pasteTimer = setTimeout(() => {
700
+ isPasting = false;
701
+ // Affiche le hint après le paste
702
+ process.stdout.write(`\n\x1b[90m↵ to send · keep typing to add more\x1b[0m`);
703
+ rl.setPrompt(`\n\x1b[34m${dynamicUsername} ❯ \x1b[0m`);
704
+ rl.prompt(true);
705
+ }, 50);
721
706
  }
707
+ });
722
708
 
723
- // Paste détecté : plusieurs caractères arrivent en un seul chunk
724
- if (key.length > 1) {
725
- pasteChunk += key;
726
- if (pasteTimer) clearTimeout(pasteTimer);
727
- pasteTimer = setTimeout(flushPaste, 30);
709
+ // Line event : accumule les lignes dans le buffer
710
+ rl.on('line', (line) => {
711
+ if (isProcessing) return;
712
+
713
+ if (isPasting) {
714
+ // Pendant un paste : accumule sans soumettre
715
+ inputBuffer += (inputBuffer ? "\n" : "") + line;
728
716
  return;
729
717
  }
730
718
 
731
- // Frappe normale : un seul caractère
732
- if (key === '\t') return; // ignore tab
733
- inputBuffer += key;
734
- process.stdout.write(key);
719
+ const trimmed = line.trim();
720
+ if (['exit', 'quit'].includes(trimmed.toLowerCase())) {
721
+ console.log('\n\x1b[90mAlex session closed.\x1b[0m');
722
+ process.exit(0);
723
+ }
724
+
725
+ if (trimmed !== "") {
726
+ inputBuffer += (inputBuffer ? "\n" : "") + line;
727
+ // Hint de confirmation après frappe normale
728
+ process.stdout.write(`\x1b[90m ↵ to send · keep typing to add more\x1b[0m\n`);
729
+ rl.setPrompt(`\x1b[34m${dynamicUsername} ❯ \x1b[0m`);
730
+ rl.prompt(true);
731
+ } else {
732
+ // Ligne vide = soumettre
733
+ if (inputBuffer.trim()) {
734
+ submit();
735
+ } else {
736
+ resetPrompt();
737
+ }
738
+ }
735
739
  });
740
+
741
+ process.stdout.write('\n');
742
+ resetPrompt();
736
743
  };
737
744
 
738
745
  if (!initialPrompt || initialPrompt === '?') startAlexSession();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbo-cockpit-cli",
3
- "version": "1.0.112",
3
+ "version": "1.0.113",
4
4
  "description": "Fleetbo CLI - Build native mobile apps with React",
5
5
  "author": "Fleetbo",
6
6
  "license": "MIT",