fleetbo-cockpit-cli 1.0.111 → 1.0.112

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 +90 -41
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -630,59 +630,108 @@ if (command === 'alex') {
630
630
  console.log('\x1b[32mAlex ❯\x1b[0m Describe your feature.');
631
631
  console.log('');
632
632
 
633
- const rl = readline.createInterface({
634
- input: process.stdin,
635
- output: process.stdout,
636
- prompt: `\x1b[34m${dynamicUsername} \x1b[0m`
637
- });
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.
638
637
 
639
- process.stdout.write('\n\x1b[F');
640
- rl.prompt();
638
+ process.stdin.setRawMode(true);
639
+ process.stdin.resume();
640
+ process.stdin.setEncoding('utf8');
641
641
 
642
- let inputBuffer = "";
642
+ let inputBuffer = ""; // ce qui est affiché à l'écran
643
643
  let isProcessing = false;
644
+ let pasteChunk = ""; // accumule le burst de données
645
+ let pasteTimer = null;
646
+
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);
655
+ };
656
+
657
+ const submitInput = async () => {
658
+ const finalPrompt = inputBuffer.trim();
659
+ inputBuffer = "";
660
+ if (!finalPrompt) { process.stdout.write('\n'); showPrompt(); return; }
661
+
662
+ 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();
665
+ return;
666
+ }
644
667
 
645
- rl.on('line', async (line) => {
646
- if (isProcessing) return;
668
+ process.stdout.write('\n');
669
+ isProcessing = true;
670
+ await processAlexRequest(finalPrompt);
671
+ isProcessing = false;
672
+ console.log('');
673
+ showPrompt();
674
+ };
647
675
 
648
- const trimmedLine = line.trim();
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;
649
681
 
650
- if (['exit', 'quit'].includes(trimmedLine.toLowerCase())) {
651
- console.log('\n\x1b[90m Alex session closed.\x1b[0m');
652
- rl.close();
653
- return;
654
- }
682
+ // Affiche le texte collé tel quel à l'écran
683
+ process.stdout.write(pasted);
684
+ inputBuffer += pasted;
655
685
 
656
- if (trimmedLine !== "") {
657
- // Accumule + invite à confirmer
658
- inputBuffer += (inputBuffer ? "\n" : "") + line;
659
- rl.setPrompt(" \x1b[90m↵ to confirm · type more to add lines\x1b[0m\n ");
660
- rl.prompt();
661
- } else {
662
- if (inputBuffer.trim() !== "") {
663
- const finalPrompt = inputBuffer.trim();
664
- inputBuffer = "";
665
-
666
- if (finalPrompt.length > 1000) {
667
- console.log(`\n\x1b[31m⛔ [Alex Safety] Mission rejected: Excessive size (${finalPrompt.length}/1000 characters).\x1b[0m`);
668
- rl.setPrompt(`\x1b[34m${dynamicUsername} ❯ \x1b[0m`);
669
- rl.prompt();
670
- return;
671
- }
686
+ // Affiche le hint de confirmation
687
+ showConfirmHint();
688
+ };
689
+
690
+ showPrompt();
691
+
692
+ process.stdin.on('data', (key) => {
693
+ if (isProcessing) return;
672
694
 
673
- isProcessing = true;
674
- rl.setPrompt("");
675
- await processAlexRequest(finalPrompt);
676
- isProcessing = false;
695
+ // Ctrl+C
696
+ if (key === '\u0003') {
697
+ console.log('\n\x1b[90mAlex session closed.\x1b[0m');
698
+ process.exit(0);
699
+ }
677
700
 
678
- console.log('');
679
- rl.setPrompt(`\x1b[34m${dynamicUsername} \x1b[0m`);
680
- rl.prompt();
701
+ // Entrée
702
+ if (key === '\r' || key === '\n') {
703
+ if (inputBuffer.trim() !== "") {
704
+ // Déjà du contenu → soumettre
705
+ submitInput();
681
706
  } else {
682
- rl.setPrompt(`\x1b[34m${dynamicUsername} \x1b[0m`);
683
- rl.prompt();
707
+ // Buffer vide → juste nouvelle ligne
708
+ process.stdout.write('\n');
709
+ showPrompt();
710
+ }
711
+ return;
712
+ }
713
+
714
+ // Backspace
715
+ if (key === '\u007f') {
716
+ if (inputBuffer.length > 0) {
717
+ inputBuffer = inputBuffer.slice(0, -1);
718
+ process.stdout.write('\b \b');
684
719
  }
720
+ return;
721
+ }
722
+
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);
728
+ return;
685
729
  }
730
+
731
+ // Frappe normale : un seul caractère
732
+ if (key === '\t') return; // ignore tab
733
+ inputBuffer += key;
734
+ process.stdout.write(key);
686
735
  });
687
736
  };
688
737
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbo-cockpit-cli",
3
- "version": "1.0.111",
3
+ "version": "1.0.112",
4
4
  "description": "Fleetbo CLI - Build native mobile apps with React",
5
5
  "author": "Fleetbo",
6
6
  "license": "MIT",