erosolar-cli 1.7.198 → 1.7.200

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 (38) hide show
  1. package/dist/core/agent.d.ts +3 -0
  2. package/dist/core/agent.d.ts.map +1 -1
  3. package/dist/core/agent.js +109 -18
  4. package/dist/core/agent.js.map +1 -1
  5. package/dist/core/toolPreconditions.js +1 -1
  6. package/dist/core/toolPreconditions.js.map +1 -1
  7. package/dist/core/toolRuntime.js +1 -1
  8. package/dist/core/toolRuntime.js.map +1 -1
  9. package/dist/core/toolValidation.js +1 -1
  10. package/dist/core/toolValidation.js.map +1 -1
  11. package/dist/shell/interactiveShell.d.ts +18 -0
  12. package/dist/shell/interactiveShell.d.ts.map +1 -1
  13. package/dist/shell/interactiveShell.js +102 -24
  14. package/dist/shell/interactiveShell.js.map +1 -1
  15. package/dist/shell/terminalInput.d.ts +16 -1
  16. package/dist/shell/terminalInput.d.ts.map +1 -1
  17. package/dist/shell/terminalInput.js +86 -31
  18. package/dist/shell/terminalInput.js.map +1 -1
  19. package/dist/shell/terminalInputAdapter.d.ts +12 -0
  20. package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
  21. package/dist/shell/terminalInputAdapter.js +14 -0
  22. package/dist/shell/terminalInputAdapter.js.map +1 -1
  23. package/dist/tools/fileTools.d.ts.map +1 -1
  24. package/dist/tools/fileTools.js +102 -39
  25. package/dist/tools/fileTools.js.map +1 -1
  26. package/dist/ui/display.d.ts +25 -1
  27. package/dist/ui/display.d.ts.map +1 -1
  28. package/dist/ui/display.js +105 -22
  29. package/dist/ui/display.js.map +1 -1
  30. package/dist/ui/keyboardShortcuts.js +1 -1
  31. package/dist/ui/keyboardShortcuts.js.map +1 -1
  32. package/dist/ui/persistentPrompt.d.ts +50 -0
  33. package/dist/ui/persistentPrompt.d.ts.map +1 -0
  34. package/dist/ui/persistentPrompt.js +92 -0
  35. package/dist/ui/persistentPrompt.js.map +1 -0
  36. package/dist/ui/shortcutsHelp.js +2 -2
  37. package/dist/ui/shortcutsHelp.js.map +1 -1
  38. package/package.json +1 -1
@@ -74,6 +74,8 @@ export class InteractiveShell {
74
74
  pendingSecretRetry = null;
75
75
  terminalInput;
76
76
  currentInput = '';
77
+ ctrlCPressCount = 0;
78
+ ctrlCHandledThisPress = false;
77
79
  pendingCleanup = null;
78
80
  cleanupInProgress = false;
79
81
  slashPreviewVisible = false;
@@ -94,6 +96,7 @@ export class InteractiveShell {
94
96
  sessionPreferences;
95
97
  autosaveEnabled;
96
98
  autoContinueEnabled;
99
+ verificationEnabled = true;
97
100
  editGuardMode = 'display-edits';
98
101
  pendingPermissionInput = null;
99
102
  pendingHistoryLoad = null;
@@ -184,9 +187,12 @@ export class InteractiveShell {
184
187
  this.terminalInput = new TerminalInputAdapter(input, output, {
185
188
  onSubmit: (text) => this.processInput(text),
186
189
  onQueue: (text) => this.handleQueuedInput(text),
190
+ onCtrlC: ({ hadBuffer }) => this.handleCtrlCPress(hadBuffer),
187
191
  onInterrupt: () => this.handleInterrupt(),
188
192
  onChange: (text) => this.handleInputChange(text),
189
193
  onEditModeChange: (mode) => this.handleEditModeChange(mode),
194
+ onToggleVerify: () => this.toggleVerificationMode(),
195
+ onToggleAutoContinue: () => this.toggleAutoContinueMode(),
190
196
  });
191
197
  // Register output interceptor for cursor positioning during streaming
192
198
  this.terminalInput.registerOutputInterceptor(display);
@@ -195,6 +201,7 @@ export class InteractiveShell {
195
201
  this.setupStatusTracking();
196
202
  this.refreshContextGauge();
197
203
  this.terminalInput.start();
204
+ this.refreshControlBar();
198
205
  this.rebuildAgent();
199
206
  this.setupHandlers();
200
207
  this.refreshBannerSessionInfo();
@@ -281,6 +288,9 @@ export class InteractiveShell {
281
288
  */
282
289
  handleInputChange(text) {
283
290
  this.currentInput = text;
291
+ if (text.length > 0) {
292
+ this.resetCtrlCSequence();
293
+ }
284
294
  this.handleSlashCommandPreviewChange();
285
295
  }
286
296
  /**
@@ -297,6 +307,41 @@ export class InteractiveShell {
297
307
  }
298
308
  this.terminalInput.render();
299
309
  }
310
+ toggleVerificationMode() {
311
+ this.setVerificationMode(!this.verificationEnabled, 'shortcut');
312
+ }
313
+ setVerificationMode(enabled, source) {
314
+ const changed = this.verificationEnabled !== enabled;
315
+ this.verificationEnabled = enabled;
316
+ this.refreshControlBar();
317
+ if (!changed && source === 'shortcut') {
318
+ return;
319
+ }
320
+ const message = enabled
321
+ ? '✅ Verification on. Auto-tests will run after edits. (alt+v to toggle)'
322
+ : '⏭️ Verification off. Skipping auto-tests until re-enabled. (alt+v to toggle)';
323
+ display.showSystemMessage(message);
324
+ }
325
+ toggleAutoContinueMode() {
326
+ this.setAutoContinueMode(!this.autoContinueEnabled, 'shortcut');
327
+ }
328
+ setAutoContinueMode(enabled, source) {
329
+ const changed = this.autoContinueEnabled !== enabled;
330
+ this.autoContinueEnabled = enabled;
331
+ saveSessionPreferences({ autoContinue: this.autoContinueEnabled });
332
+ if (this.agent) {
333
+ this.agent.setAutoContinue(this.autoContinueEnabled);
334
+ }
335
+ this.refreshControlBar();
336
+ if (!changed && source === 'shortcut') {
337
+ return;
338
+ }
339
+ display.showInfo(`Auto-continue ${this.autoContinueEnabled ? 'enabled' : 'disabled'}. ` +
340
+ (this.autoContinueEnabled
341
+ ? 'The model will be auto-prompted to continue when it expresses intent but does not use tools.'
342
+ : 'The model will not be auto-prompted to continue.') +
343
+ ' Toggle with alt+c.');
344
+ }
300
345
  /**
301
346
  * Gate submissions when edit permission mode is active.
302
347
  * Returns the text to send when approved, or null when waiting for confirmation.
@@ -342,15 +387,51 @@ export class InteractiveShell {
342
387
  this.terminalInput.render();
343
388
  }
344
389
  /**
345
- * TerminalInputAdapter interrupt handler (Ctrl+C with empty buffer)
390
+ * Handle Ctrl+C presses in three stages:
391
+ * 1) Clear chat box text
392
+ * 2) Pause/interrupt AI execution (even while streaming)
393
+ * 3) Quit the program
346
394
  */
347
- handleInterrupt() {
395
+ handleCtrlCPress(hadBuffer) {
396
+ this.ctrlCHandledThisPress = true;
397
+ this.ctrlCPressCount = Math.min(this.ctrlCPressCount + 1, 3);
398
+ if (this.ctrlCPressCount === 1) {
399
+ this.clearChatInput();
400
+ const prefix = hadBuffer ? 'Input cleared.' : 'Nothing to clear.';
401
+ display.showSystemMessage(`${prefix} Press Ctrl+C again to pause the AI; a third time quits.`);
402
+ this.terminalInput.render();
403
+ return;
404
+ }
405
+ if (this.ctrlCPressCount === 2) {
406
+ this.pauseAiExecution();
407
+ return;
408
+ }
409
+ this.shutdown();
410
+ }
411
+ pauseAiExecution() {
348
412
  if (this.isProcessing && this.agent) {
349
413
  this.agent.requestCancellation();
350
- display.showWarning('Cancelling current operation... (Ctrl+C again to force quit)');
414
+ display.showWarning('Pausing AI execution... (Press Ctrl+C again to quit)');
351
415
  return;
352
416
  }
353
- this.shutdown();
417
+ display.showInfo('No active AI execution to pause. Press Ctrl+C again to quit.');
418
+ }
419
+ resetCtrlCSequence() {
420
+ this.ctrlCPressCount = 0;
421
+ this.ctrlCHandledThisPress = false;
422
+ }
423
+ clearChatInput() {
424
+ this.pendingPermissionInput = null;
425
+ this.handleInputChange('');
426
+ }
427
+ /**
428
+ * TerminalInputAdapter interrupt handler (Ctrl+C with empty buffer)
429
+ */
430
+ handleInterrupt() {
431
+ if (!this.ctrlCHandledThisPress) {
432
+ this.handleCtrlCPress(false);
433
+ }
434
+ this.ctrlCHandledThisPress = false;
354
435
  }
355
436
  /**
356
437
  * Gracefully tear down the shell and exit
@@ -570,6 +651,10 @@ export class InteractiveShell {
570
651
  this.uiAdapter.updateContextUsage(percentage);
571
652
  this.terminalInput.setContextUsage(percentage);
572
653
  }
654
+ refreshControlBar() {
655
+ // Status indicators are now shown inline in the prompt
656
+ this.terminalInput.render();
657
+ }
573
658
  handleSlashCommandPreviewChange() {
574
659
  if (this.pendingInteraction) {
575
660
  this.slashPreviewVisible = false;
@@ -641,11 +726,10 @@ export class InteractiveShell {
641
726
  ? Math.floor((Date.now() - this.streamingHeartbeatStart) / 1000)
642
727
  : 0;
643
728
  const suffix = elapsed > 0 ? ` • ${elapsed}s` : '';
644
- display.updateStreamingStatus(`${theme.info(frame)} ${label}${suffix}`);
645
- this.requestPromptRefresh();
729
+ this.terminalInput.setStatusMessage(`${frame} ${label}${suffix}`);
646
730
  };
647
731
  tick();
648
- this.streamingHeartbeat = setInterval(tick, 2000);
732
+ this.streamingHeartbeat = setInterval(tick, 500);
649
733
  }
650
734
  stopStreamingHeartbeat() {
651
735
  if (this.streamingHeartbeat) {
@@ -653,8 +737,7 @@ export class InteractiveShell {
653
737
  this.streamingHeartbeat = null;
654
738
  }
655
739
  this.streamingHeartbeatStart = null;
656
- display.clearStreamingStatus();
657
- this.requestPromptRefresh();
740
+ this.terminalInput.setStatusMessage(null);
658
741
  }
659
742
  refreshQueueIndicators() {
660
743
  if (this.isProcessing) {
@@ -1439,23 +1522,14 @@ export class InteractiveShell {
1439
1522
  if (!value) {
1440
1523
  // Show current status
1441
1524
  display.showInfo(`Auto-continue is ${this.autoContinueEnabled ? 'enabled' : 'disabled'}. ` +
1442
- `Use /autocontinue on|off to toggle.`);
1525
+ `Use /autocontinue on|off or alt+c to toggle.`);
1443
1526
  return;
1444
1527
  }
1445
1528
  if (value !== 'on' && value !== 'off') {
1446
1529
  display.showWarning('Usage: /autocontinue on|off');
1447
1530
  return;
1448
1531
  }
1449
- this.autoContinueEnabled = value === 'on';
1450
- saveSessionPreferences({ autoContinue: this.autoContinueEnabled });
1451
- // Update the current agent if it exists
1452
- if (this.agent) {
1453
- this.agent.setAutoContinue(this.autoContinueEnabled);
1454
- }
1455
- display.showInfo(`Auto-continue ${this.autoContinueEnabled ? 'enabled' : 'disabled'}. ` +
1456
- (this.autoContinueEnabled
1457
- ? 'The model will be auto-prompted to continue when it expresses intent but does not use tools.'
1458
- : 'The model will not be auto-prompted to continue.'));
1532
+ this.setAutoContinueMode(value === 'on', 'command');
1459
1533
  }
1460
1534
  updateActiveSession(summary, remember = false) {
1461
1535
  this.activeSessionId = summary?.id ?? null;
@@ -2462,6 +2536,9 @@ What's the next action?`;
2462
2536
  if (this.autoTestInFlight) {
2463
2537
  return;
2464
2538
  }
2539
+ if (!this.verificationEnabled) {
2540
+ return;
2541
+ }
2465
2542
  const latestChange = this.getLatestFileChangeTimestamp();
2466
2543
  if (!latestChange) {
2467
2544
  return;
@@ -2522,9 +2599,8 @@ What's the next action?`;
2522
2599
  this.agent = this.runtimeSession.createAgent(selection, {
2523
2600
  onStreamChunk: (chunk) => {
2524
2601
  // Claude Code style: Stream output through display module
2525
- // Stop the streaming heartbeat once content starts arriving to prevent
2526
- // cursor conflicts between the status bar and streaming content
2527
- this.stopStreamingHeartbeat();
2602
+ // With scroll regions, heartbeat continues animating at bottom while
2603
+ // content streams in the scroll region above - no conflicts
2528
2604
  if (display.isSpinnerActive()) {
2529
2605
  display.stopThinking(false);
2530
2606
  display.stream('\n');
@@ -2929,7 +3005,9 @@ What's the next action?`;
2929
3005
  handleStreamingFallback(info) {
2930
3006
  const detailText = info.message.trim();
2931
3007
  const detail = detailText ? ` Error: ${detailText}` : '';
2932
- display.showWarning(`Streaming failed, retrying without streaming.${detail}`);
3008
+ const reason = info.reason ? ` (${info.reason.replace(/-/g, ' ')})` : '';
3009
+ const partialNote = info.partialResponse ? ' Received partial stream before failure.' : '';
3010
+ display.showWarning(`Streaming failed${reason}, retrying without streaming.${detail}${partialNote}`);
2933
3011
  this.startStreamingHeartbeat('Fallback in progress');
2934
3012
  this.requestPromptRefresh(true);
2935
3013
  }