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.
- package/dist/core/agent.d.ts +3 -0
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +109 -18
- package/dist/core/agent.js.map +1 -1
- package/dist/core/toolPreconditions.js +1 -1
- package/dist/core/toolPreconditions.js.map +1 -1
- package/dist/core/toolRuntime.js +1 -1
- package/dist/core/toolRuntime.js.map +1 -1
- package/dist/core/toolValidation.js +1 -1
- package/dist/core/toolValidation.js.map +1 -1
- package/dist/shell/interactiveShell.d.ts +18 -0
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +102 -24
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/terminalInput.d.ts +16 -1
- package/dist/shell/terminalInput.d.ts.map +1 -1
- package/dist/shell/terminalInput.js +86 -31
- package/dist/shell/terminalInput.js.map +1 -1
- package/dist/shell/terminalInputAdapter.d.ts +12 -0
- package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
- package/dist/shell/terminalInputAdapter.js +14 -0
- package/dist/shell/terminalInputAdapter.js.map +1 -1
- package/dist/tools/fileTools.d.ts.map +1 -1
- package/dist/tools/fileTools.js +102 -39
- package/dist/tools/fileTools.js.map +1 -1
- package/dist/ui/display.d.ts +25 -1
- package/dist/ui/display.d.ts.map +1 -1
- package/dist/ui/display.js +105 -22
- package/dist/ui/display.js.map +1 -1
- package/dist/ui/keyboardShortcuts.js +1 -1
- package/dist/ui/keyboardShortcuts.js.map +1 -1
- package/dist/ui/persistentPrompt.d.ts +50 -0
- package/dist/ui/persistentPrompt.d.ts.map +1 -0
- package/dist/ui/persistentPrompt.js +92 -0
- package/dist/ui/persistentPrompt.js.map +1 -0
- package/dist/ui/shortcutsHelp.js +2 -2
- package/dist/ui/shortcutsHelp.js.map +1 -1
- 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
|
-
*
|
|
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
|
-
|
|
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('
|
|
414
|
+
display.showWarning('Pausing AI execution... (Press Ctrl+C again to quit)');
|
|
351
415
|
return;
|
|
352
416
|
}
|
|
353
|
-
|
|
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
|
-
|
|
645
|
-
this.requestPromptRefresh();
|
|
729
|
+
this.terminalInput.setStatusMessage(`${frame} ${label}${suffix}`);
|
|
646
730
|
};
|
|
647
731
|
tick();
|
|
648
|
-
this.streamingHeartbeat = setInterval(tick,
|
|
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
|
-
|
|
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.
|
|
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
|
-
//
|
|
2526
|
-
//
|
|
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
|
-
|
|
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
|
}
|