erosolar-cli 1.7.101 → 1.7.103

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.
@@ -112,6 +112,8 @@ export class InteractiveShell {
112
112
  sessionRestoreConfig;
113
113
  _enabledPlugins;
114
114
  pinnedChatBox;
115
+ readlineOutputSuppressed = false;
116
+ originalStdoutWrite = null;
115
117
  constructor(config) {
116
118
  this.profile = config.profile;
117
119
  this.profileLabel = config.profileLabel;
@@ -623,7 +625,11 @@ export class InteractiveShell {
623
625
  const cursorPos = this.rl.cursor || 0;
624
626
  this.persistentPrompt.updateInput(currentLine, cursorPos);
625
627
  // Sync to pinned chat box for display only
626
- this.pinnedChatBox.setInput(currentLine);
628
+ this.pinnedChatBox.setInput(currentLine, cursorPos);
629
+ // During processing, update the persistent input display so user can see what they're typing
630
+ if (this.isProcessing) {
631
+ this.pinnedChatBox.updatePersistentInput();
632
+ }
627
633
  if (this.composableMessage.hasContent()) {
628
634
  this.composableMessage.setDraft(currentLine);
629
635
  this.updateComposeStatusSummary();
@@ -779,6 +785,66 @@ export class InteractiveShell {
779
785
  inputStream.on('keypress', this.keypressHandler);
780
786
  }
781
787
  }
788
+ // Restore readline output if it was suppressed
789
+ this.restoreReadlineOutput();
790
+ }
791
+ /**
792
+ * Suppress readline's character echo during streaming.
793
+ * Characters typed will be captured but not echoed to the main output.
794
+ * Instead, they appear only in the persistent input box at the bottom.
795
+ */
796
+ suppressReadlineOutput() {
797
+ if (this.readlineOutputSuppressed || !output.isTTY) {
798
+ return;
799
+ }
800
+ this.originalStdoutWrite = output.write.bind(output);
801
+ const self = this;
802
+ // Replace stdout.write to filter readline echo
803
+ // Readline writes single characters for echo - we filter those out
804
+ // but allow multi-character writes (actual output) through
805
+ output.write = function (chunk, encodingOrCallback, callback) {
806
+ if (!self.originalStdoutWrite) {
807
+ return true;
808
+ }
809
+ const str = typeof chunk === 'string' ? chunk : chunk.toString();
810
+ // Filter out readline echo patterns:
811
+ // - Single printable characters (user typing)
812
+ // - Cursor movement sequences for single chars
813
+ // - Backspace sequences
814
+ // But allow through:
815
+ // - Multi-character content (actual AI output)
816
+ // - Newlines and control sequences for formatting
817
+ // If it's a single printable char or simple cursor move, suppress it
818
+ if (str.length === 1 && str.charCodeAt(0) >= 32 && str.charCodeAt(0) < 127) {
819
+ // Single printable character - this is readline echo, suppress it
820
+ return true;
821
+ }
822
+ // Suppress backspace + space + backspace (readline's delete char sequence)
823
+ if (str === '\b \b' || str === '\x1b[D \x1b[D') {
824
+ return true;
825
+ }
826
+ // Suppress cursor-right after character (readline sometimes does this)
827
+ if (/^\x1b\[\d*C$/.test(str)) {
828
+ return true;
829
+ }
830
+ // Allow everything else through
831
+ if (typeof encodingOrCallback === 'function') {
832
+ return self.originalStdoutWrite(chunk, encodingOrCallback);
833
+ }
834
+ return self.originalStdoutWrite(chunk, encodingOrCallback, callback);
835
+ };
836
+ this.readlineOutputSuppressed = true;
837
+ }
838
+ /**
839
+ * Restore normal readline output after streaming completes.
840
+ */
841
+ restoreReadlineOutput() {
842
+ if (!this.readlineOutputSuppressed || !this.originalStdoutWrite) {
843
+ return;
844
+ }
845
+ output.write = this.originalStdoutWrite;
846
+ this.originalStdoutWrite = null;
847
+ this.readlineOutputSuppressed = false;
782
848
  }
783
849
  enqueueUserInput(line, flushImmediately = false) {
784
850
  this.bufferedInputLines.push(line);
@@ -2349,11 +2415,10 @@ export class InteractiveShell {
2349
2415
  this.setProcessingStatus();
2350
2416
  try {
2351
2417
  display.newLine();
2352
- // Pinned chat box already shows processing state - skip redundant spinner
2353
- // which would conflict with the pinned area at terminal bottom
2354
- // display.showThinking('Working on your request...');
2355
- // Force render the pinned chat box to ensure it's visible during processing
2356
- this.pinnedChatBox.forceRender();
2418
+ // Enable scroll region so streaming output scrolls while input stays at bottom
2419
+ this.pinnedChatBox.enableScrollRegion();
2420
+ // Suppress readline echo so typed characters only appear in persistent input box
2421
+ this.suppressReadlineOutput();
2357
2422
  // Enable streaming for real-time text output (Claude Code style)
2358
2423
  await agent.send(request, true);
2359
2424
  await this.awaitPendingCleanup();
@@ -2371,6 +2436,10 @@ export class InteractiveShell {
2371
2436
  }
2372
2437
  }
2373
2438
  finally {
2439
+ // Restore readline echo before other cleanup
2440
+ this.restoreReadlineOutput();
2441
+ // Disable scroll region before any other output to restore normal terminal behavior
2442
+ this.pinnedChatBox.disableScrollRegion();
2374
2443
  display.stopThinking(false);
2375
2444
  this.isProcessing = false;
2376
2445
  this.uiAdapter.endProcessing('Ready for prompts');
@@ -2433,6 +2502,10 @@ export class InteractiveShell {
2433
2502
  display.showSystemMessage(`šŸ“Š Using intelligent task completion detection with AI verification.`);
2434
2503
  this.uiAdapter.startProcessing('Continuous execution mode');
2435
2504
  this.setProcessingStatus();
2505
+ // Enable scroll region so streaming output scrolls while input stays at bottom
2506
+ this.pinnedChatBox.enableScrollRegion();
2507
+ // Suppress readline echo so typed characters only appear in persistent input box
2508
+ this.suppressReadlineOutput();
2436
2509
  let iteration = 0;
2437
2510
  let lastResponse = '';
2438
2511
  let consecutiveNoProgress = 0;
@@ -2594,6 +2667,8 @@ What's the next action?`;
2594
2667
  display.showSystemMessage(`\nšŸ Continuous execution completed: ${iteration} iterations, ${minutes}m ${seconds}s total`);
2595
2668
  // Reset completion detector for next task
2596
2669
  resetTaskCompletionDetector();
2670
+ // Restore readline echo before other cleanup
2671
+ this.restoreReadlineOutput();
2597
2672
  this.isProcessing = false;
2598
2673
  this.uiAdapter.endProcessing('Ready for prompts');
2599
2674
  this.setIdleStatus();