erosolar-cli 1.7.161 → 1.7.164

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 (53) hide show
  1. package/dist/contracts/unified-schema.json +6 -6
  2. package/dist/core/unified/tools.d.ts.map +1 -1
  3. package/dist/core/unified/tools.js +12 -34
  4. package/dist/core/unified/tools.js.map +1 -1
  5. package/dist/security/tool-security-wrapper.js +3 -3
  6. package/dist/security/tool-security-wrapper.js.map +1 -1
  7. package/dist/shell/claudeCodeStreamHandler.d.ts +145 -0
  8. package/dist/shell/claudeCodeStreamHandler.d.ts.map +1 -0
  9. package/dist/shell/claudeCodeStreamHandler.js +312 -0
  10. package/dist/shell/claudeCodeStreamHandler.js.map +1 -0
  11. package/dist/shell/inputQueueManager.d.ts +144 -0
  12. package/dist/shell/inputQueueManager.d.ts.map +1 -0
  13. package/dist/shell/inputQueueManager.js +290 -0
  14. package/dist/shell/inputQueueManager.js.map +1 -0
  15. package/dist/shell/interactiveShell.d.ts +21 -0
  16. package/dist/shell/interactiveShell.d.ts.map +1 -1
  17. package/dist/shell/interactiveShell.js +140 -51
  18. package/dist/shell/interactiveShell.js.map +1 -1
  19. package/dist/shell/streamingOutputManager.d.ts +88 -0
  20. package/dist/shell/streamingOutputManager.d.ts.map +1 -0
  21. package/dist/shell/streamingOutputManager.js +155 -0
  22. package/dist/shell/streamingOutputManager.js.map +1 -0
  23. package/dist/shell/systemPrompt.js +2 -2
  24. package/dist/shell/systemPrompt.js.map +1 -1
  25. package/dist/shell/taskCompletionDetector.d.ts.map +1 -1
  26. package/dist/shell/taskCompletionDetector.js +1 -3
  27. package/dist/shell/taskCompletionDetector.js.map +1 -1
  28. package/dist/shell/unifiedChatBox.d.ts +178 -0
  29. package/dist/shell/unifiedChatBox.d.ts.map +1 -0
  30. package/dist/shell/unifiedChatBox.js +539 -0
  31. package/dist/shell/unifiedChatBox.js.map +1 -0
  32. package/dist/tools/diffUtils.d.ts +1 -1
  33. package/dist/tools/diffUtils.d.ts.map +1 -1
  34. package/dist/tools/diffUtils.js +19 -3
  35. package/dist/tools/diffUtils.js.map +1 -1
  36. package/dist/tools/editTools.d.ts +11 -0
  37. package/dist/tools/editTools.d.ts.map +1 -1
  38. package/dist/tools/editTools.js +141 -98
  39. package/dist/tools/editTools.js.map +1 -1
  40. package/dist/tools/fileTools.d.ts.map +1 -1
  41. package/dist/tools/fileTools.js +2 -126
  42. package/dist/tools/fileTools.js.map +1 -1
  43. package/dist/tools/softwareEngineeringTools.d.ts +7 -0
  44. package/dist/tools/softwareEngineeringTools.d.ts.map +1 -0
  45. package/dist/tools/softwareEngineeringTools.js +338 -0
  46. package/dist/tools/softwareEngineeringTools.js.map +1 -0
  47. package/dist/ui/toolDisplay.d.ts.map +1 -1
  48. package/dist/ui/toolDisplay.js +1 -3
  49. package/dist/ui/toolDisplay.js.map +1 -1
  50. package/dist/ui/toolDisplayAdapter.d.ts.map +1 -1
  51. package/dist/ui/toolDisplayAdapter.js +0 -3
  52. package/dist/ui/toolDisplayAdapter.js.map +1 -1
  53. package/package.json +1 -1
@@ -23,6 +23,8 @@ import { PersistentPrompt, PinnedChatBox } from '../ui/persistentPrompt.js';
23
23
  import { formatShortcutsHelp } from '../ui/shortcutsHelp.js';
24
24
  import { MetricsTracker } from '../alpha-zero/index.js';
25
25
  import { listAvailablePlugins } from '../plugins/index.js';
26
+ import { getClaudeCodeStreamHandler } from './claudeCodeStreamHandler.js';
27
+ import { getUnifiedChatBox } from './unifiedChatBox.js';
26
28
  const DROPDOWN_COLORS = [
27
29
  theme.primary,
28
30
  theme.info,
@@ -114,6 +116,8 @@ export class InteractiveShell {
114
116
  pinnedChatBox;
115
117
  readlineOutputSuppressed = false;
116
118
  originalStdoutWrite = null;
119
+ streamHandler;
120
+ unifiedChatBox;
117
121
  constructor(config) {
118
122
  this.profile = config.profile;
119
123
  this.profileLabel = config.profileLabel;
@@ -226,6 +230,17 @@ export class InteractiveShell {
226
230
  // This ensures the pinned area is cleared before output and re-rendered after,
227
231
  // preventing ghost lines when the terminal scrolls
228
232
  this.pinnedChatBox.registerOutputInterceptor(display);
233
+ // Initialize Claude Code style stream handler for natural output flow
234
+ // Key insight: No cursor manipulation during streaming - output just appends
235
+ this.streamHandler = getClaudeCodeStreamHandler();
236
+ this.streamHandler.attachToReadline(this.rl);
237
+ // Initialize UnifiedChatBox - Claude Code exact style
238
+ // The chat box is always at the bottom naturally through readline
239
+ // During streaming: output flows up, typed input queued invisibly
240
+ // After streaming: new prompt appears at bottom naturally
241
+ this.unifiedChatBox = getUnifiedChatBox();
242
+ this.unifiedChatBox.attachToReadline(this.rl);
243
+ this.unifiedChatBox.setPrompt(formatUserPrompt(this.profileLabel || this.profile));
229
244
  // Initialize Alpha Zero 2 metrics tracking
230
245
  this.alphaZeroMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
231
246
  this.setupStatusTracking();
@@ -278,15 +293,16 @@ export class InteractiveShell {
278
293
  this.sessionResumeNotice = null;
279
294
  }
280
295
  async start(initialPrompt) {
281
- // Always render the pinned chat box at startup so it's visible from the beginning
282
- this.pinnedChatBox.show();
283
- this.pinnedChatBox.forceRender();
296
+ // Claude Code style: Just use readline's prompt
297
+ // The prompt naturally appears at the bottom
298
+ // No complex UI rendering needed - terminal handles it naturally
284
299
  if (initialPrompt) {
285
300
  display.newLine();
286
301
  console.log(`${formatUserPrompt(this.profileLabel || this.profile)}${initialPrompt}`);
287
302
  await this.processInputBlock(initialPrompt);
288
303
  return;
289
304
  }
305
+ // Show readline prompt - naturally at bottom of terminal
290
306
  this.rl.prompt();
291
307
  }
292
308
  async handleToolSettingsInput(input) {
@@ -482,6 +498,10 @@ export class InteractiveShell {
482
498
  this.pendingCleanup = null;
483
499
  // Dispose persistent prompt
484
500
  this.persistentPrompt.dispose();
501
+ // Dispose Claude Code stream handler
502
+ this.streamHandler.dispose();
503
+ // Dispose unified chat box
504
+ this.unifiedChatBox.dispose();
485
505
  // Dispose unified UI adapter
486
506
  this.uiAdapter.dispose();
487
507
  display.newLine();
@@ -786,14 +806,25 @@ export class InteractiveShell {
786
806
  }
787
807
  }
788
808
  // Restore readline output if it was suppressed
789
- this.restoreReadlineOutput();
809
+ // Note: Stream handler manages its own state, this is for legacy compatibility
810
+ if (!this.streamHandler.isStreaming()) {
811
+ this.restoreReadlineOutput();
812
+ }
790
813
  }
791
814
  /**
792
815
  * Suppress readline's character echo during streaming.
793
816
  * Characters typed will be captured but not echoed to the main output.
794
817
  * Instead, they appear only in the persistent input box at the bottom.
818
+ *
819
+ * @deprecated Use streamHandler.startStreaming() instead - kept for backwards compatibility
820
+ * @internal Kept for legacy code paths that may still reference this method
795
821
  */
822
+ // @ts-expect-error - Legacy method kept for backwards compatibility, unused in favor of streamHandler
796
823
  suppressReadlineOutput() {
824
+ // Delegate to stream handler if it's not already streaming
825
+ if (this.streamHandler.isStreaming()) {
826
+ return;
827
+ }
797
828
  if (this.readlineOutputSuppressed || !output.isTTY) {
798
829
  return;
799
830
  }
@@ -850,6 +881,8 @@ export class InteractiveShell {
850
881
  }
851
882
  /**
852
883
  * Restore normal readline output after streaming completes.
884
+ *
885
+ * @deprecated Use streamHandler.endStreaming() instead
853
886
  */
854
887
  restoreReadlineOutput() {
855
888
  if (!this.readlineOutputSuppressed || !this.originalStdoutWrite) {
@@ -1080,6 +1113,72 @@ export class InteractiveShell {
1080
1113
  void this.processQueuedActions();
1081
1114
  });
1082
1115
  }
1116
+ /**
1117
+ * Process any inputs that were queued during streaming.
1118
+ * Claude Code style: User can type while streaming, input is stored in queue,
1119
+ * processed after streaming ends.
1120
+ *
1121
+ * @deprecated Use processUnifiedChatBoxQueue() instead
1122
+ */
1123
+ // @ts-expect-error - Legacy method kept for backwards compatibility
1124
+ processQueuedInputs() {
1125
+ if (!this.streamHandler.hasQueuedInput()) {
1126
+ return;
1127
+ }
1128
+ // Transfer queued inputs from stream handler to follow-up queue
1129
+ while (this.streamHandler.hasQueuedInput()) {
1130
+ const input = this.streamHandler.getNextQueuedInput();
1131
+ if (!input) {
1132
+ break;
1133
+ }
1134
+ // Handle interrupts specially
1135
+ if (input.type === 'interrupt') {
1136
+ // Interrupt was already processed during capture
1137
+ continue;
1138
+ }
1139
+ // Add to follow-up queue for processing
1140
+ const actionType = input.type === 'command' ? 'request' : 'request';
1141
+ this.followUpQueue.push({
1142
+ type: actionType,
1143
+ text: input.text,
1144
+ });
1145
+ }
1146
+ // Show queue summary if there are items
1147
+ const summary = this.streamHandler.getQueueSummary();
1148
+ if (summary) {
1149
+ display.showInfo(`📝 ${summary}`);
1150
+ }
1151
+ }
1152
+ /**
1153
+ * Process any inputs that were queued in UnifiedChatBox during streaming.
1154
+ * Claude Code style: User can type while streaming, input is stored invisibly,
1155
+ * processed after streaming ends.
1156
+ */
1157
+ processUnifiedChatBoxQueue() {
1158
+ if (!this.unifiedChatBox.hasQueuedInput()) {
1159
+ return;
1160
+ }
1161
+ // Transfer queued inputs from unified chat box to follow-up queue
1162
+ while (this.unifiedChatBox.hasQueuedInput()) {
1163
+ const input = this.unifiedChatBox.dequeue();
1164
+ if (!input) {
1165
+ break;
1166
+ }
1167
+ // Handle interrupts specially - they cancel current operation
1168
+ if (input.type === 'interrupt') {
1169
+ // Request cancellation if agent is running
1170
+ if (this.agent) {
1171
+ this.agent.requestCancellation();
1172
+ }
1173
+ continue;
1174
+ }
1175
+ // Add to follow-up queue for processing
1176
+ this.followUpQueue.push({
1177
+ type: 'request',
1178
+ text: input.text,
1179
+ });
1180
+ }
1181
+ }
1083
1182
  async processQueuedActions() {
1084
1183
  if (this.isDrainingQueue || this.isProcessing || !this.followUpQueue.length) {
1085
1184
  return;
@@ -2415,25 +2514,20 @@ export class InteractiveShell {
2415
2514
  }
2416
2515
  this.isProcessing = true;
2417
2516
  const requestStartTime = Date.now(); // Alpha Zero 2 timing
2418
- // Keep persistent prompt visible during processing so users can type follow-up requests
2419
- // The prompt will show a "processing" indicator but remain interactive
2420
- this.persistentPrompt.updateStatusBar({ message: '⏳ Processing... (type to queue follow-up)' });
2421
- // Update pinned chat box to show processing state
2422
- // Clear the input display since the request was already submitted
2423
- // Note: Don't set statusMessage here - the isProcessing flag already shows "⏳ Processing..."
2424
- this.pinnedChatBox.setProcessing(true);
2425
- this.pinnedChatBox.setStatusMessage(null); // Clear any previous status to avoid duplication
2426
- this.pinnedChatBox.clearInput();
2517
+ // Claude Code style: Update status (optional, won't interfere with streaming)
2518
+ this.persistentPrompt.updateStatusBar({ message: '⏳ Processing...' });
2427
2519
  this.uiAdapter.startProcessing('Working on your request');
2428
2520
  this.setProcessingStatus();
2429
2521
  try {
2430
2522
  // Add visual separator between user prompt and AI response
2431
2523
  display.newLine();
2432
2524
  display.newLine();
2433
- // Enable scroll region so streaming output scrolls while input stays at bottom
2434
- this.pinnedChatBox.enableScrollRegion();
2435
- // Suppress readline echo so typed characters only appear in persistent input box
2436
- this.suppressReadlineOutput();
2525
+ // Claude Code style: Start streaming mode using UnifiedChatBox
2526
+ // - Output flows naturally to stdout (NO cursor manipulation)
2527
+ // - User input is captured invisibly and queued
2528
+ // - Prompt scrolls up naturally with output
2529
+ // - After streaming ends, new prompt appears at bottom
2530
+ this.unifiedChatBox.startStreaming();
2437
2531
  // Enable streaming for real-time text output (Claude Code style)
2438
2532
  await agent.send(request, true);
2439
2533
  await this.awaitPendingCleanup();
@@ -2451,24 +2545,24 @@ export class InteractiveShell {
2451
2545
  }
2452
2546
  }
2453
2547
  finally {
2454
- // Restore readline echo before other cleanup
2455
- this.restoreReadlineOutput();
2456
- // Disable scroll region before any other output to restore normal terminal behavior
2457
- this.pinnedChatBox.disableScrollRegion();
2548
+ // Claude Code style: End streaming mode using UnifiedChatBox
2549
+ // This restores readline echo and returns queue info
2550
+ const streamResult = this.unifiedChatBox.endStreaming();
2551
+ // Process any queued inputs that came in during streaming
2552
+ this.processUnifiedChatBoxQueue();
2553
+ // Show queue indicator if there were queued inputs
2554
+ if (streamResult.queuedCount > 0) {
2555
+ this.unifiedChatBox.showQueueIndicator();
2556
+ }
2458
2557
  display.stopThinking(false);
2459
2558
  this.isProcessing = false;
2460
2559
  this.uiAdapter.endProcessing('Ready for prompts');
2461
2560
  this.setIdleStatus();
2462
2561
  display.newLine();
2463
- // Clear the processing status and ensure persistent prompt is visible
2562
+ // Clear the processing status
2464
2563
  this.persistentPrompt.updateStatusBar({ message: undefined });
2465
- this.persistentPrompt.show();
2466
- // Update pinned chat box to show ready state and force render
2467
- this.pinnedChatBox.setProcessing(false);
2468
- this.pinnedChatBox.setStatusMessage(null);
2469
- this.pinnedChatBox.forceRender();
2470
2564
  // CRITICAL: Ensure readline prompt is active for user input
2471
- // Call ensureReadlineReady to resume stdin if paused and re-enable keypress
2565
+ // Claude Code style: New prompt naturally appears at bottom
2472
2566
  this.ensureReadlineReady();
2473
2567
  this.rl.prompt();
2474
2568
  this.scheduleQueueProcessing();
@@ -2506,21 +2600,17 @@ export class InteractiveShell {
2506
2600
  // Initialize the task completion detector
2507
2601
  const completionDetector = getTaskCompletionDetector();
2508
2602
  completionDetector.reset();
2509
- // Keep persistent prompt visible during processing so users can type follow-up requests
2510
- this.persistentPrompt.updateStatusBar({ message: '🔄 Continuous mode... (type to queue follow-up)' });
2511
- // Update pinned chat box for continuous mode
2512
- // Clear the input display since the request was already submitted
2513
- this.pinnedChatBox.setProcessing(true);
2514
- this.pinnedChatBox.setStatusMessage('Continuous execution mode...');
2515
- this.pinnedChatBox.clearInput();
2603
+ // Claude Code style: Update status
2604
+ this.persistentPrompt.updateStatusBar({ message: '🔄 Continuous mode...' });
2516
2605
  display.showSystemMessage(`🔄 Starting continuous execution mode. Press Ctrl+C to stop.`);
2517
2606
  display.showSystemMessage(`📊 Using intelligent task completion detection with AI verification.`);
2518
2607
  this.uiAdapter.startProcessing('Continuous execution mode');
2519
2608
  this.setProcessingStatus();
2520
- // Enable scroll region so streaming output scrolls while input stays at bottom
2521
- this.pinnedChatBox.enableScrollRegion();
2522
- // Suppress readline echo so typed characters only appear in persistent input box
2523
- this.suppressReadlineOutput();
2609
+ // Claude Code style: Start streaming mode using UnifiedChatBox
2610
+ // - Output flows naturally to stdout (NO cursor manipulation)
2611
+ // - User input is captured invisibly and queued
2612
+ // - Prompt scrolls up naturally with output
2613
+ this.unifiedChatBox.startStreaming();
2524
2614
  let iteration = 0;
2525
2615
  let lastResponse = '';
2526
2616
  let consecutiveNoProgress = 0;
@@ -2682,23 +2772,22 @@ What's the next action?`;
2682
2772
  display.showSystemMessage(`\n🏁 Continuous execution completed: ${iteration} iterations, ${minutes}m ${seconds}s total`);
2683
2773
  // Reset completion detector for next task
2684
2774
  resetTaskCompletionDetector();
2685
- // Restore readline echo before other cleanup
2686
- this.restoreReadlineOutput();
2775
+ // Claude Code style: End streaming mode using UnifiedChatBox
2776
+ const streamResult = this.unifiedChatBox.endStreaming();
2777
+ // Process any queued inputs that came in during streaming
2778
+ this.processUnifiedChatBoxQueue();
2779
+ // Show queue indicator if there were queued inputs
2780
+ if (streamResult.queuedCount > 0) {
2781
+ this.unifiedChatBox.showQueueIndicator();
2782
+ }
2687
2783
  this.isProcessing = false;
2688
2784
  this.uiAdapter.endProcessing('Ready for prompts');
2689
2785
  this.setIdleStatus();
2690
- // Disable scroll region before output to restore normal terminal behavior
2691
- this.pinnedChatBox.disableScrollRegion();
2692
2786
  display.newLine();
2693
- // Clear the processing status and ensure persistent prompt is visible
2787
+ // Clear the processing status
2694
2788
  this.persistentPrompt.updateStatusBar({ message: undefined });
2695
- this.persistentPrompt.show();
2696
- // Update pinned chat box to show ready state and force render
2697
- this.pinnedChatBox.setProcessing(false);
2698
- this.pinnedChatBox.setStatusMessage(null);
2699
- this.pinnedChatBox.forceRender();
2700
2789
  // CRITICAL: Ensure readline prompt is active for user input
2701
- // Call ensureReadlineReady to resume stdin if paused and re-enable keypress
2790
+ // Claude Code style: New prompt naturally appears at bottom
2702
2791
  this.ensureReadlineReady();
2703
2792
  this.rl.prompt();
2704
2793
  this.scheduleQueueProcessing();
@@ -2805,7 +2894,7 @@ What's the next action?`;
2805
2894
  /(?:running|executing|called?|using)\s+(?:the\s+)?(\w+(?:_\w+)*)\s+tool/gi,
2806
2895
  /tool[:\s]+(\w+(?:_\w+)*)/gi,
2807
2896
  /⎿\s*(\w+)/g, // Tool result prefix pattern
2808
- /(?:read_file|write_file|edit_file|bash|grep|glob|search)/gi,
2897
+ /(?:read_file|edit_file|Edit|bash|grep|glob|search)/gi,
2809
2898
  ];
2810
2899
  for (const pattern of toolPatterns) {
2811
2900
  let match;