erosolar-cli 1.7.428 → 1.7.430
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/capabilities/enhancedGitCapability.js +3 -3
- package/dist/capabilities/enhancedGitCapability.js.map +1 -1
- package/dist/capabilities/learnCapability.d.ts +1 -1
- package/dist/capabilities/learnCapability.d.ts.map +1 -1
- package/dist/capabilities/learnCapability.js +1 -1
- package/dist/capabilities/learnCapability.js.map +1 -1
- package/dist/core/checkpoint.d.ts +1 -1
- package/dist/core/checkpoint.js +1 -1
- package/dist/core/costTracker.d.ts +1 -1
- package/dist/core/costTracker.js +1 -1
- package/dist/core/hooks.d.ts +1 -1
- package/dist/core/hooks.js +1 -1
- package/dist/core/memorySystem.d.ts +2 -2
- package/dist/core/memorySystem.js +2 -2
- package/dist/core/outputStyles.d.ts +2 -2
- package/dist/core/outputStyles.js +2 -2
- package/dist/core/validationRunner.d.ts +1 -1
- package/dist/core/validationRunner.js +1 -1
- package/dist/shell/interactiveShell.d.ts +6 -1
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +129 -92
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/systemPrompt.d.ts.map +1 -1
- package/dist/shell/systemPrompt.js +13 -33
- package/dist/shell/systemPrompt.js.map +1 -1
- package/dist/shell/terminalInputAdapter.d.ts +75 -83
- package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
- package/dist/shell/terminalInputAdapter.js +159 -220
- package/dist/shell/terminalInputAdapter.js.map +1 -1
- package/dist/shell/vimMode.d.ts +1 -1
- package/dist/shell/vimMode.js +1 -1
- package/dist/tools/buildTools.d.ts +1 -1
- package/dist/tools/buildTools.js +1 -1
- package/dist/tools/diffUtils.d.ts +2 -2
- package/dist/tools/diffUtils.js +2 -2
- package/dist/tools/editTools.js +4 -4
- package/dist/tools/editTools.js.map +1 -1
- package/dist/tools/localExplore.d.ts +3 -3
- package/dist/tools/localExplore.js +3 -3
- package/dist/tools/skillTools.js +2 -2
- package/dist/tools/skillTools.js.map +1 -1
- package/dist/tools/validationTools.js +1 -1
- package/dist/ui/DisplayEventQueue.d.ts +99 -0
- package/dist/ui/DisplayEventQueue.d.ts.map +1 -0
- package/dist/ui/DisplayEventQueue.js +167 -0
- package/dist/ui/DisplayEventQueue.js.map +1 -0
- package/dist/ui/SequentialRenderer.d.ts +69 -0
- package/dist/ui/SequentialRenderer.d.ts.map +1 -0
- package/dist/ui/SequentialRenderer.js +137 -0
- package/dist/ui/SequentialRenderer.js.map +1 -0
- package/dist/ui/ShellUIAdapter.d.ts +19 -12
- package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
- package/dist/ui/ShellUIAdapter.js +73 -56
- package/dist/ui/ShellUIAdapter.js.map +1 -1
- package/dist/ui/UnifiedUIRenderer.d.ts +184 -0
- package/dist/ui/UnifiedUIRenderer.d.ts.map +1 -0
- package/dist/ui/UnifiedUIRenderer.js +567 -0
- package/dist/ui/UnifiedUIRenderer.js.map +1 -0
- package/dist/ui/display.d.ts +100 -173
- package/dist/ui/display.d.ts.map +1 -1
- package/dist/ui/display.js +359 -926
- package/dist/ui/display.js.map +1 -1
- package/dist/ui/errorFormatter.d.ts +1 -1
- package/dist/ui/errorFormatter.js +1 -1
- package/dist/ui/shortcutsHelp.d.ts +6 -6
- package/dist/ui/shortcutsHelp.js +6 -6
- package/dist/ui/streamingFormatter.d.ts +2 -10
- package/dist/ui/streamingFormatter.d.ts.map +1 -1
- package/dist/ui/streamingFormatter.js +9 -59
- package/dist/ui/streamingFormatter.js.map +1 -1
- package/dist/ui/textHighlighter.d.ts +8 -8
- package/dist/ui/textHighlighter.js +9 -9
- package/dist/ui/textHighlighter.js.map +1 -1
- package/dist/ui/theme.d.ts +2 -2
- package/dist/ui/theme.js +4 -4
- package/dist/ui/theme.js.map +1 -1
- package/dist/ui/toolDisplay.d.ts +8 -8
- package/dist/ui/toolDisplay.js +8 -8
- package/package.json +1 -1
- package/dist/shell/terminalInput.d.ts +0 -619
- package/dist/shell/terminalInput.d.ts.map +0 -1
- package/dist/shell/terminalInput.js +0 -2699
- package/dist/shell/terminalInput.js.map +0 -1
|
@@ -4,9 +4,9 @@ import { promisify } from 'node:util';
|
|
|
4
4
|
import { existsSync, readFileSync } from 'node:fs';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
6
|
import { display } from '../ui/display.js';
|
|
7
|
-
import { isPlainOutputMode } from '../ui/outputMode.js';
|
|
8
7
|
import { theme } from '../ui/theme.js';
|
|
9
8
|
import { StreamingResponseFormatter } from '../ui/streamingFormatter.js';
|
|
9
|
+
import { UnifiedUIRenderer } from '../ui/UnifiedUIRenderer.js';
|
|
10
10
|
import { getContextWindowTokens } from '../core/contextWindow.js';
|
|
11
11
|
import { ensureSecretForProvider, getSecretDefinitionForProvider, getSecretValue, listSecretDefinitions, maskSecret, setSecretValue, } from '../core/secretStore.js';
|
|
12
12
|
import { saveActiveProfilePreference, saveModelPreference, loadToolSettings, saveToolSettings, clearToolSettings, clearActiveProfilePreference, loadSessionPreferences, saveSessionPreferences, loadFeatureFlags, saveFeatureFlags, toggleFeatureFlag, FEATURE_FLAG_INFO, } from '../core/preferences.js';
|
|
@@ -174,6 +174,8 @@ export class InteractiveShell {
|
|
|
174
174
|
alternateScreenEnabled;
|
|
175
175
|
welcomeShown = false;
|
|
176
176
|
scrollbackRestored = false;
|
|
177
|
+
uiRenderer;
|
|
178
|
+
useUnifiedRenderer;
|
|
177
179
|
constructor(config) {
|
|
178
180
|
this.profile = config.profile;
|
|
179
181
|
this.profileLabel = config.profileLabel;
|
|
@@ -270,6 +272,10 @@ export class InteractiveShell {
|
|
|
270
272
|
onToggleThinking: () => this.cycleThinkingMode(),
|
|
271
273
|
onClearContext: () => this.handleClearContext(),
|
|
272
274
|
});
|
|
275
|
+
const canUseRenderer = output.isTTY;
|
|
276
|
+
this.uiRenderer = canUseRenderer ? new UnifiedUIRenderer(output, input) : null;
|
|
277
|
+
this.useUnifiedRenderer = !!this.uiRenderer;
|
|
278
|
+
display.setRenderer(this.uiRenderer);
|
|
273
279
|
// Initialize Alpha Zero 2 metrics tracking
|
|
274
280
|
this.alphaZeroMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
|
|
275
281
|
this.setupStatusTracking();
|
|
@@ -292,7 +298,8 @@ export class InteractiveShell {
|
|
|
292
298
|
}
|
|
293
299
|
// Render chat box immediately using the streaming UI lifecycle
|
|
294
300
|
this.refreshControlBar();
|
|
295
|
-
this.
|
|
301
|
+
this.syncRendererInput();
|
|
302
|
+
this.uiRenderer?.render();
|
|
296
303
|
this.rebuildAgent();
|
|
297
304
|
this.setupHandlers();
|
|
298
305
|
this.refreshSessionContext();
|
|
@@ -383,19 +390,38 @@ export class InteractiveShell {
|
|
|
383
390
|
if (this.welcomeShown && !force) {
|
|
384
391
|
return;
|
|
385
392
|
}
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
const profileLine = `${theme.fields.profile(this.profileLabel)} ${theme.ui.muted(`(${this.profile})`)}`;
|
|
389
|
-
const workspaceLine = theme.fields.workspace(this.workingDir);
|
|
390
|
-
const versionLine = this.version ? theme.ui.muted(`v${this.version} · support@ero.solar`) : null;
|
|
391
|
-
const hintLine = theme.ui.muted('/help for commands · /model to switch · /secrets for keys');
|
|
392
|
-
const message = [header, modelLine, profileLine, workspaceLine, versionLine, hintLine]
|
|
393
|
-
.filter(Boolean)
|
|
394
|
-
.join('\n');
|
|
395
|
-
this.streamEventBlock(message);
|
|
393
|
+
const banner = this.buildClaudeStyleBanner();
|
|
394
|
+
this.streamEventBlock(banner);
|
|
396
395
|
this.welcomeShown = true;
|
|
397
396
|
this.requestPromptRefresh(true);
|
|
398
397
|
}
|
|
398
|
+
buildClaudeStyleBanner() {
|
|
399
|
+
const welcome = `Welcome back ${this.profileLabel}!`;
|
|
400
|
+
const model = `${this.sessionState.model} @ ${this.providerLabel(this.sessionState.provider)}`;
|
|
401
|
+
const workspace = this.workingDir;
|
|
402
|
+
const lines = [
|
|
403
|
+
'Erosolar-CLI',
|
|
404
|
+
welcome,
|
|
405
|
+
model,
|
|
406
|
+
workspace,
|
|
407
|
+
'/help for commands · /model to switch · /secrets for keys',
|
|
408
|
+
];
|
|
409
|
+
return lines.join('\n');
|
|
410
|
+
}
|
|
411
|
+
syncRendererInput() {
|
|
412
|
+
// No-op: UnifiedUIRenderer handles its own input state now
|
|
413
|
+
// The new architecture doesn't require separate input syncing
|
|
414
|
+
}
|
|
415
|
+
pushUiEvent(type, content) {
|
|
416
|
+
if (!content) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
if (this.useUnifiedRenderer && this.uiRenderer) {
|
|
420
|
+
this.uiRenderer.addEvent(type, content);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
display.stream(content);
|
|
424
|
+
}
|
|
399
425
|
/**
|
|
400
426
|
* Stream a content block as a single event, isolating it from adjacent output.
|
|
401
427
|
*/
|
|
@@ -404,6 +430,10 @@ export class InteractiveShell {
|
|
|
404
430
|
if (!normalized) {
|
|
405
431
|
return;
|
|
406
432
|
}
|
|
433
|
+
if (this.useUnifiedRenderer && this.uiRenderer) {
|
|
434
|
+
this.uiRenderer.addEvent('banner', normalized);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
407
437
|
const bullet = `${theme.info('⏺')} `;
|
|
408
438
|
const indent = ' ';
|
|
409
439
|
const lines = normalized.split('\n').map(line => line.trimEnd());
|
|
@@ -411,11 +441,18 @@ export class InteractiveShell {
|
|
|
411
441
|
.map((line, index) => (index === 0 ? `${bullet}${line}` : `${indent}${line}`))
|
|
412
442
|
.join('\n');
|
|
413
443
|
const block = `\n${formatted}\n`;
|
|
414
|
-
this.
|
|
444
|
+
this.pushUiEvent('raw', block);
|
|
415
445
|
}
|
|
416
446
|
async start(initialPrompt) {
|
|
417
447
|
// Always use the scroll-region streaming layout from the outset
|
|
418
|
-
this.
|
|
448
|
+
if (this.useUnifiedRenderer && this.uiRenderer) {
|
|
449
|
+
this.uiRenderer.initialize();
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
this.terminalInput.clearScreen();
|
|
453
|
+
this.terminalInput.resetContentPosition();
|
|
454
|
+
}
|
|
455
|
+
this.syncRendererInput();
|
|
419
456
|
this.showWelcomeBanner();
|
|
420
457
|
if (initialPrompt) {
|
|
421
458
|
await this.processInputBlock(initialPrompt);
|
|
@@ -423,7 +460,7 @@ export class InteractiveShell {
|
|
|
423
460
|
}
|
|
424
461
|
this.showLaunchCommandPalette();
|
|
425
462
|
// Ensure the terminal input is visible
|
|
426
|
-
this.
|
|
463
|
+
this.syncRendererInput();
|
|
427
464
|
}
|
|
428
465
|
showLaunchCommandPalette() {
|
|
429
466
|
// Disabled: Quick commands palette takes up too much space
|
|
@@ -542,6 +579,7 @@ export class InteractiveShell {
|
|
|
542
579
|
*/
|
|
543
580
|
handleInputChange(text) {
|
|
544
581
|
this.currentInput = text;
|
|
582
|
+
this.syncRendererInput();
|
|
545
583
|
if (text.length > 0) {
|
|
546
584
|
this.resetCtrlCSequence();
|
|
547
585
|
}
|
|
@@ -563,7 +601,7 @@ export class InteractiveShell {
|
|
|
563
601
|
display.showSystemMessage('✏️ Display edits mode enabled.');
|
|
564
602
|
}
|
|
565
603
|
}
|
|
566
|
-
this.
|
|
604
|
+
this.syncRendererInput();
|
|
567
605
|
}
|
|
568
606
|
toggleVerificationMode() {
|
|
569
607
|
this.setVerificationMode(!this.verificationEnabled, 'shortcut');
|
|
@@ -684,7 +722,7 @@ export class InteractiveShell {
|
|
|
684
722
|
if (['n', 'no', 'cancel', '/cancel'].includes(lower)) {
|
|
685
723
|
this.pendingPermissionInput = null;
|
|
686
724
|
display.showInfo('Request cancelled.');
|
|
687
|
-
this.
|
|
725
|
+
this.syncRendererInput();
|
|
688
726
|
return null;
|
|
689
727
|
}
|
|
690
728
|
// Treat any other input as a replacement request that also needs confirmation
|
|
@@ -702,7 +740,7 @@ export class InteractiveShell {
|
|
|
702
740
|
]
|
|
703
741
|
.filter(Boolean)
|
|
704
742
|
.join('\n'));
|
|
705
|
-
this.
|
|
743
|
+
this.syncRendererInput();
|
|
706
744
|
}
|
|
707
745
|
/**
|
|
708
746
|
* Handle Ctrl+C presses in three stages:
|
|
@@ -767,6 +805,7 @@ export class InteractiveShell {
|
|
|
767
805
|
this.stopStreamingHeartbeat('quit', { quiet: true });
|
|
768
806
|
this.endAiRuntime();
|
|
769
807
|
this.uiUpdates.dispose();
|
|
808
|
+
this.uiRenderer?.cleanup();
|
|
770
809
|
this.clearPromptRefreshTimer();
|
|
771
810
|
this.teardownStatusTracking();
|
|
772
811
|
// Clear global AI enhancer (explore tool will work offline after this)
|
|
@@ -826,26 +865,26 @@ export class InteractiveShell {
|
|
|
826
865
|
const trimmed = input.trim();
|
|
827
866
|
if (!trimmed) {
|
|
828
867
|
display.showWarning('Enter a number, "save", "defaults", or "cancel".');
|
|
829
|
-
this.
|
|
868
|
+
this.syncRendererInput();
|
|
830
869
|
return;
|
|
831
870
|
}
|
|
832
871
|
const normalized = trimmed.toLowerCase();
|
|
833
872
|
if (normalized === 'cancel') {
|
|
834
873
|
this.pendingInteraction = null;
|
|
835
874
|
display.showInfo('Tool selection cancelled.');
|
|
836
|
-
this.
|
|
875
|
+
this.syncRendererInput();
|
|
837
876
|
return;
|
|
838
877
|
}
|
|
839
878
|
if (normalized === 'defaults') {
|
|
840
879
|
pending.selection = buildEnabledToolSet(null);
|
|
841
880
|
this.renderToolMenu(pending);
|
|
842
|
-
this.
|
|
881
|
+
this.syncRendererInput();
|
|
843
882
|
return;
|
|
844
883
|
}
|
|
845
884
|
if (normalized === 'save') {
|
|
846
885
|
await this.persistToolSelection(pending);
|
|
847
886
|
this.pendingInteraction = null;
|
|
848
|
-
this.
|
|
887
|
+
this.syncRendererInput();
|
|
849
888
|
return;
|
|
850
889
|
}
|
|
851
890
|
const choice = Number.parseInt(trimmed, 10);
|
|
@@ -868,11 +907,11 @@ export class InteractiveShell {
|
|
|
868
907
|
}
|
|
869
908
|
this.renderToolMenu(pending);
|
|
870
909
|
}
|
|
871
|
-
this.
|
|
910
|
+
this.syncRendererInput();
|
|
872
911
|
return;
|
|
873
912
|
}
|
|
874
913
|
display.showWarning('Enter a number, "save", "defaults", or "cancel".');
|
|
875
|
-
this.
|
|
914
|
+
this.syncRendererInput();
|
|
876
915
|
}
|
|
877
916
|
async persistToolSelection(interaction) {
|
|
878
917
|
if (setsEqual(interaction.selection, interaction.initialSelection)) {
|
|
@@ -900,36 +939,36 @@ export class InteractiveShell {
|
|
|
900
939
|
if (!this.agentMenu) {
|
|
901
940
|
this.pendingInteraction = null;
|
|
902
941
|
display.showWarning('Agent selection is unavailable in this CLI.');
|
|
903
|
-
this.
|
|
942
|
+
this.syncRendererInput();
|
|
904
943
|
return;
|
|
905
944
|
}
|
|
906
945
|
const trimmed = input.trim();
|
|
907
946
|
if (!trimmed) {
|
|
908
947
|
display.showWarning('Enter a number or type "cancel".');
|
|
909
|
-
this.
|
|
948
|
+
this.syncRendererInput();
|
|
910
949
|
return;
|
|
911
950
|
}
|
|
912
951
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
913
952
|
this.pendingInteraction = null;
|
|
914
953
|
display.showInfo('Agent selection cancelled.');
|
|
915
|
-
this.
|
|
954
|
+
this.syncRendererInput();
|
|
916
955
|
return;
|
|
917
956
|
}
|
|
918
957
|
const choice = Number.parseInt(trimmed, 10);
|
|
919
958
|
if (!Number.isFinite(choice)) {
|
|
920
959
|
display.showWarning('Please enter a valid number.');
|
|
921
|
-
this.
|
|
960
|
+
this.syncRendererInput();
|
|
922
961
|
return;
|
|
923
962
|
}
|
|
924
963
|
const option = pending.options[choice - 1];
|
|
925
964
|
if (!option) {
|
|
926
965
|
display.showWarning('That option is not available.');
|
|
927
|
-
this.
|
|
966
|
+
this.syncRendererInput();
|
|
928
967
|
return;
|
|
929
968
|
}
|
|
930
969
|
await this.persistAgentSelection(option.name);
|
|
931
970
|
this.pendingInteraction = null;
|
|
932
|
-
this.
|
|
971
|
+
this.syncRendererInput();
|
|
933
972
|
}
|
|
934
973
|
async persistAgentSelection(profileName) {
|
|
935
974
|
if (!this.agentMenu) {
|
|
@@ -1002,7 +1041,7 @@ export class InteractiveShell {
|
|
|
1002
1041
|
lines.push(` ${theme.primary('[text]')} Submit your own solution instead`);
|
|
1003
1042
|
lines.push('');
|
|
1004
1043
|
display.showSystemMessage(lines.join('\n'));
|
|
1005
|
-
this.
|
|
1044
|
+
this.syncRendererInput();
|
|
1006
1045
|
}
|
|
1007
1046
|
async handlePlanApprovalInput(input) {
|
|
1008
1047
|
const pending = this.pendingInteraction;
|
|
@@ -1011,7 +1050,7 @@ export class InteractiveShell {
|
|
|
1011
1050
|
const trimmed = input.trim();
|
|
1012
1051
|
if (!trimmed) {
|
|
1013
1052
|
display.showWarning('Enter a command or your own solution.');
|
|
1014
|
-
this.
|
|
1053
|
+
this.syncRendererInput();
|
|
1015
1054
|
return;
|
|
1016
1055
|
}
|
|
1017
1056
|
const lower = trimmed.toLowerCase();
|
|
@@ -1019,7 +1058,7 @@ export class InteractiveShell {
|
|
|
1019
1058
|
if (lower === 'cancel' || lower === 'c') {
|
|
1020
1059
|
this.pendingInteraction = null;
|
|
1021
1060
|
display.showInfo('Plan cancelled. You can continue with a different approach.');
|
|
1022
|
-
this.
|
|
1061
|
+
this.syncRendererInput();
|
|
1023
1062
|
return;
|
|
1024
1063
|
}
|
|
1025
1064
|
// Select all
|
|
@@ -1039,7 +1078,7 @@ export class InteractiveShell {
|
|
|
1039
1078
|
const selectedSteps = pending.steps.filter(s => pending.selectedSteps.has(s.id));
|
|
1040
1079
|
if (selectedSteps.length === 0) {
|
|
1041
1080
|
display.showWarning('No steps selected. Select steps or enter your own solution.');
|
|
1042
|
-
this.
|
|
1081
|
+
this.syncRendererInput();
|
|
1043
1082
|
return;
|
|
1044
1083
|
}
|
|
1045
1084
|
this.pendingInteraction = null;
|
|
@@ -1072,7 +1111,7 @@ export class InteractiveShell {
|
|
|
1072
1111
|
return;
|
|
1073
1112
|
}
|
|
1074
1113
|
display.showWarning('Invalid input. Enter a step number, command (go/cancel/all/none), or your own solution.');
|
|
1075
|
-
this.
|
|
1114
|
+
this.syncRendererInput();
|
|
1076
1115
|
}
|
|
1077
1116
|
setupHandlers() {
|
|
1078
1117
|
// Handle terminal resize
|
|
@@ -1080,7 +1119,7 @@ export class InteractiveShell {
|
|
|
1080
1119
|
this.terminalInput.handleResize();
|
|
1081
1120
|
});
|
|
1082
1121
|
// Show initial input UI
|
|
1083
|
-
this.
|
|
1122
|
+
this.syncRendererInput();
|
|
1084
1123
|
}
|
|
1085
1124
|
/**
|
|
1086
1125
|
* Set up command autocomplete with all available slash commands.
|
|
@@ -1193,7 +1232,7 @@ export class InteractiveShell {
|
|
|
1193
1232
|
thinkingHotkey: 'tab',
|
|
1194
1233
|
});
|
|
1195
1234
|
this.refreshStatusLine();
|
|
1196
|
-
this.
|
|
1235
|
+
this.syncRendererInput();
|
|
1197
1236
|
}
|
|
1198
1237
|
writeLocked(content) {
|
|
1199
1238
|
if (!content) {
|
|
@@ -1231,7 +1270,7 @@ export class InteractiveShell {
|
|
|
1231
1270
|
/**
|
|
1232
1271
|
* Refresh the status line in the persistent input area.
|
|
1233
1272
|
* Uses combined status display: streaming label + override + main status.
|
|
1234
|
-
* All three can be shown simultaneously (
|
|
1273
|
+
* All three can be shown simultaneously (Erosolar-CLI style).
|
|
1235
1274
|
*/
|
|
1236
1275
|
refreshStatusLine(forceRender = false) {
|
|
1237
1276
|
// Set streaming label (spinner + label) - shows during streaming
|
|
@@ -1258,8 +1297,10 @@ export class InteractiveShell {
|
|
|
1258
1297
|
model: this.sessionState.model,
|
|
1259
1298
|
provider: this.providerLabel(this.sessionState.provider),
|
|
1260
1299
|
});
|
|
1300
|
+
this.syncRendererInput();
|
|
1261
1301
|
if (forceRender) {
|
|
1262
|
-
this.
|
|
1302
|
+
this.syncRendererInput();
|
|
1303
|
+
this.uiRenderer?.render();
|
|
1263
1304
|
}
|
|
1264
1305
|
}
|
|
1265
1306
|
/**
|
|
@@ -1318,7 +1359,8 @@ export class InteractiveShell {
|
|
|
1318
1359
|
}
|
|
1319
1360
|
requestPromptRefresh(force = false) {
|
|
1320
1361
|
if (force) {
|
|
1321
|
-
this.
|
|
1362
|
+
this.syncRendererInput();
|
|
1363
|
+
this.uiRenderer?.render();
|
|
1322
1364
|
return;
|
|
1323
1365
|
}
|
|
1324
1366
|
if (this.promptRefreshTimer) {
|
|
@@ -1326,7 +1368,7 @@ export class InteractiveShell {
|
|
|
1326
1368
|
}
|
|
1327
1369
|
this.promptRefreshTimer = setTimeout(() => {
|
|
1328
1370
|
this.promptRefreshTimer = null;
|
|
1329
|
-
this.
|
|
1371
|
+
this.syncRendererInput();
|
|
1330
1372
|
}, 48);
|
|
1331
1373
|
}
|
|
1332
1374
|
clearPromptRefreshTimer() {
|
|
@@ -1340,7 +1382,6 @@ export class InteractiveShell {
|
|
|
1340
1382
|
// Enter global streaming mode - blocks all non-streaming UI output
|
|
1341
1383
|
enterStreamingMode();
|
|
1342
1384
|
// Set up scroll region for streaming content
|
|
1343
|
-
this.terminalInput.enterStreamingScrollRegion();
|
|
1344
1385
|
this.uiUpdates.setMode('streaming');
|
|
1345
1386
|
this.streamingHeartbeatStart = Date.now();
|
|
1346
1387
|
this.streamingHeartbeatFrame = 0;
|
|
@@ -1407,19 +1448,14 @@ export class InteractiveShell {
|
|
|
1407
1448
|
if (!chunk) {
|
|
1408
1449
|
return;
|
|
1409
1450
|
}
|
|
1410
|
-
// Preserve raw output in plain/CI modes or non-TTY environments
|
|
1411
|
-
if (isPlainOutputMode() || !output.isTTY) {
|
|
1412
|
-
this.terminalInput.streamContent(chunk);
|
|
1413
|
-
return;
|
|
1414
|
-
}
|
|
1415
1451
|
if (!this.streamingFormatter) {
|
|
1416
1452
|
this.streamingFormatter = new StreamingResponseFormatter(output.columns ?? undefined);
|
|
1417
|
-
this.
|
|
1453
|
+
this.pushUiEvent('streaming', this.streamingFormatter.header());
|
|
1418
1454
|
}
|
|
1419
1455
|
const formatted = this.streamingFormatter.formatChunk(chunk);
|
|
1420
1456
|
this.captureStreamingThought(chunk);
|
|
1421
1457
|
if (formatted) {
|
|
1422
|
-
this.
|
|
1458
|
+
this.pushUiEvent('streaming', formatted);
|
|
1423
1459
|
}
|
|
1424
1460
|
}
|
|
1425
1461
|
finishStreamingFormatter(note, options) {
|
|
@@ -1431,7 +1467,7 @@ export class InteractiveShell {
|
|
|
1431
1467
|
mode: options?.mode ?? 'complete',
|
|
1432
1468
|
});
|
|
1433
1469
|
if (closing) {
|
|
1434
|
-
this.
|
|
1470
|
+
this.pushUiEvent('streaming', closing);
|
|
1435
1471
|
}
|
|
1436
1472
|
if (this.streamingThoughtBuffer.trim()) {
|
|
1437
1473
|
this.ui.controller.recordAssistantThought(this.streamingThoughtBuffer.trim());
|
|
@@ -1483,7 +1519,7 @@ export class InteractiveShell {
|
|
|
1483
1519
|
else {
|
|
1484
1520
|
this.setIdleStatus();
|
|
1485
1521
|
}
|
|
1486
|
-
this.
|
|
1522
|
+
this.syncRendererInput();
|
|
1487
1523
|
}
|
|
1488
1524
|
enqueueFollowUpAction(action) {
|
|
1489
1525
|
this.followUpQueue.push(action);
|
|
@@ -1502,7 +1538,7 @@ export class InteractiveShell {
|
|
|
1502
1538
|
this.refreshQueueIndicators();
|
|
1503
1539
|
this.scheduleQueueProcessing();
|
|
1504
1540
|
// Re-show the prompt so user can continue typing more follow-ups
|
|
1505
|
-
this.
|
|
1541
|
+
this.syncRendererInput();
|
|
1506
1542
|
}
|
|
1507
1543
|
scheduleQueueProcessing() {
|
|
1508
1544
|
if (!this.followUpQueue.length) {
|
|
@@ -1557,12 +1593,12 @@ export class InteractiveShell {
|
|
|
1557
1593
|
}
|
|
1558
1594
|
if (lower === 'clear') {
|
|
1559
1595
|
display.clear();
|
|
1560
|
-
this.
|
|
1596
|
+
this.syncRendererInput();
|
|
1561
1597
|
return;
|
|
1562
1598
|
}
|
|
1563
1599
|
if (lower === 'help') {
|
|
1564
1600
|
this.showHelp();
|
|
1565
|
-
this.
|
|
1601
|
+
this.syncRendererInput();
|
|
1566
1602
|
return;
|
|
1567
1603
|
}
|
|
1568
1604
|
if (trimmed.startsWith('/')) {
|
|
@@ -1572,12 +1608,12 @@ export class InteractiveShell {
|
|
|
1572
1608
|
// Check for continuous/infinite loop commands
|
|
1573
1609
|
if (this.isContinuousCommand(trimmed)) {
|
|
1574
1610
|
await this.processContinuousRequest(trimmed);
|
|
1575
|
-
this.
|
|
1611
|
+
this.syncRendererInput();
|
|
1576
1612
|
return;
|
|
1577
1613
|
}
|
|
1578
1614
|
// Direct execution for all inputs, including multi-line pastes
|
|
1579
1615
|
await this.processRequest(trimmed);
|
|
1580
|
-
this.
|
|
1616
|
+
this.syncRendererInput();
|
|
1581
1617
|
}
|
|
1582
1618
|
/**
|
|
1583
1619
|
* Check if the command is a continuous/infinite loop command
|
|
@@ -1622,7 +1658,7 @@ export class InteractiveShell {
|
|
|
1622
1658
|
switch (this.pendingInteraction.type) {
|
|
1623
1659
|
case 'model-loading':
|
|
1624
1660
|
display.showInfo('Still fetching model options. Please wait a moment.');
|
|
1625
|
-
this.
|
|
1661
|
+
this.syncRendererInput();
|
|
1626
1662
|
return true;
|
|
1627
1663
|
case 'model-provider':
|
|
1628
1664
|
await this.handleModelProviderSelection(input);
|
|
@@ -1653,7 +1689,7 @@ export class InteractiveShell {
|
|
|
1653
1689
|
const [command] = input.split(/\s+/);
|
|
1654
1690
|
if (!command) {
|
|
1655
1691
|
display.showWarning('Enter a slash command.');
|
|
1656
|
-
this.
|
|
1692
|
+
this.syncRendererInput();
|
|
1657
1693
|
return;
|
|
1658
1694
|
}
|
|
1659
1695
|
switch (command) {
|
|
@@ -1756,7 +1792,7 @@ export class InteractiveShell {
|
|
|
1756
1792
|
case '/discover':
|
|
1757
1793
|
await this.discoverModelsCommand();
|
|
1758
1794
|
break;
|
|
1759
|
-
//
|
|
1795
|
+
// Erosolar-CLI style commands
|
|
1760
1796
|
case '/rewind':
|
|
1761
1797
|
await this.handleRewindCommand(input);
|
|
1762
1798
|
break;
|
|
@@ -1811,7 +1847,7 @@ export class InteractiveShell {
|
|
|
1811
1847
|
}
|
|
1812
1848
|
break;
|
|
1813
1849
|
}
|
|
1814
|
-
this.
|
|
1850
|
+
this.syncRendererInput();
|
|
1815
1851
|
}
|
|
1816
1852
|
async tryCustomSlashCommand(command, fullInput) {
|
|
1817
1853
|
const custom = this.customCommandMap.get(command);
|
|
@@ -2137,7 +2173,7 @@ export class InteractiveShell {
|
|
|
2137
2173
|
display.showSystemMessage(`${headline}\n${theme.ui.muted(descriptions[this.thinkingMode])}`);
|
|
2138
2174
|
}
|
|
2139
2175
|
handleShortcutsCommand() {
|
|
2140
|
-
// Display keyboard shortcuts help (
|
|
2176
|
+
// Display keyboard shortcuts help (Erosolar-CLI style)
|
|
2141
2177
|
display.showSystemMessage(formatShortcutsHelp());
|
|
2142
2178
|
}
|
|
2143
2179
|
showFileChangeSummary() {
|
|
@@ -3460,7 +3496,7 @@ export class InteractiveShell {
|
|
|
3460
3496
|
}
|
|
3461
3497
|
this.setAutoContinueMode(value === 'on', 'command');
|
|
3462
3498
|
}
|
|
3463
|
-
// ====================
|
|
3499
|
+
// ==================== Erosolar-CLI Style Commands ====================
|
|
3464
3500
|
async handleRewindCommand(_input) {
|
|
3465
3501
|
const lines = [];
|
|
3466
3502
|
lines.push(theme.bold('Rewind / Checkpoint System'));
|
|
@@ -3619,7 +3655,7 @@ export class InteractiveShell {
|
|
|
3619
3655
|
display.clear();
|
|
3620
3656
|
clearAutosaveSnapshot(this.profile);
|
|
3621
3657
|
display.showInfo('Conversation cleared. Starting fresh.');
|
|
3622
|
-
this.
|
|
3658
|
+
this.syncRendererInput();
|
|
3623
3659
|
}
|
|
3624
3660
|
async handleResumeCommand(input) {
|
|
3625
3661
|
const tokens = input.split(/\s+/).slice(1);
|
|
@@ -3747,7 +3783,7 @@ export class InteractiveShell {
|
|
|
3747
3783
|
display.showInfo('Compacting conversation context...');
|
|
3748
3784
|
await this.performContextCompaction('Manual /compact request');
|
|
3749
3785
|
}
|
|
3750
|
-
// ==================== End
|
|
3786
|
+
// ==================== End Erosolar-CLI Style Commands ====================
|
|
3751
3787
|
updateActiveSession(summary, remember = false) {
|
|
3752
3788
|
this.activeSessionId = summary?.id ?? null;
|
|
3753
3789
|
this.activeSessionTitle = summary?.title ?? null;
|
|
@@ -3922,7 +3958,7 @@ export class InteractiveShell {
|
|
|
3922
3958
|
if (!providerOptions.length) {
|
|
3923
3959
|
display.showWarning('No providers are available.');
|
|
3924
3960
|
this.pendingInteraction = null;
|
|
3925
|
-
this.
|
|
3961
|
+
this.syncRendererInput();
|
|
3926
3962
|
return;
|
|
3927
3963
|
}
|
|
3928
3964
|
const lines = [
|
|
@@ -3943,7 +3979,7 @@ export class InteractiveShell {
|
|
|
3943
3979
|
catch (error) {
|
|
3944
3980
|
display.showError('Failed to load model list. Try again in a moment.', error);
|
|
3945
3981
|
this.pendingInteraction = null;
|
|
3946
|
-
this.
|
|
3982
|
+
this.syncRendererInput();
|
|
3947
3983
|
}
|
|
3948
3984
|
}
|
|
3949
3985
|
buildProviderOptions() {
|
|
@@ -4498,29 +4534,29 @@ export class InteractiveShell {
|
|
|
4498
4534
|
const trimmed = input.trim();
|
|
4499
4535
|
if (!trimmed) {
|
|
4500
4536
|
display.showWarning('Enter a number or type cancel.');
|
|
4501
|
-
this.
|
|
4537
|
+
this.syncRendererInput();
|
|
4502
4538
|
return;
|
|
4503
4539
|
}
|
|
4504
4540
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
4505
4541
|
this.pendingInteraction = null;
|
|
4506
4542
|
display.showInfo('Model selection cancelled.');
|
|
4507
|
-
this.
|
|
4543
|
+
this.syncRendererInput();
|
|
4508
4544
|
return;
|
|
4509
4545
|
}
|
|
4510
4546
|
const choice = Number.parseInt(trimmed, 10);
|
|
4511
4547
|
if (!Number.isFinite(choice)) {
|
|
4512
4548
|
display.showWarning('Please enter a valid number.');
|
|
4513
|
-
this.
|
|
4549
|
+
this.syncRendererInput();
|
|
4514
4550
|
return;
|
|
4515
4551
|
}
|
|
4516
4552
|
const option = pending.options[choice - 1];
|
|
4517
4553
|
if (!option) {
|
|
4518
4554
|
display.showWarning('That option is not available.');
|
|
4519
|
-
this.
|
|
4555
|
+
this.syncRendererInput();
|
|
4520
4556
|
return;
|
|
4521
4557
|
}
|
|
4522
4558
|
this.showProviderModels(option);
|
|
4523
|
-
this.
|
|
4559
|
+
this.syncRendererInput();
|
|
4524
4560
|
}
|
|
4525
4561
|
async handleModelSelection(input) {
|
|
4526
4562
|
const pending = this.pendingInteraction;
|
|
@@ -4530,35 +4566,35 @@ export class InteractiveShell {
|
|
|
4530
4566
|
const trimmed = input.trim();
|
|
4531
4567
|
if (!trimmed) {
|
|
4532
4568
|
display.showWarning('Enter a number, type "back", or type "cancel".');
|
|
4533
|
-
this.
|
|
4569
|
+
this.syncRendererInput();
|
|
4534
4570
|
return;
|
|
4535
4571
|
}
|
|
4536
4572
|
if (trimmed.toLowerCase() === 'back') {
|
|
4537
4573
|
this.showModelMenu();
|
|
4538
|
-
this.
|
|
4574
|
+
this.syncRendererInput();
|
|
4539
4575
|
return;
|
|
4540
4576
|
}
|
|
4541
4577
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
4542
4578
|
this.pendingInteraction = null;
|
|
4543
4579
|
display.showInfo('Model selection cancelled.');
|
|
4544
|
-
this.
|
|
4580
|
+
this.syncRendererInput();
|
|
4545
4581
|
return;
|
|
4546
4582
|
}
|
|
4547
4583
|
const choice = Number.parseInt(trimmed, 10);
|
|
4548
4584
|
if (!Number.isFinite(choice)) {
|
|
4549
4585
|
display.showWarning('Please enter a valid number.');
|
|
4550
|
-
this.
|
|
4586
|
+
this.syncRendererInput();
|
|
4551
4587
|
return;
|
|
4552
4588
|
}
|
|
4553
4589
|
const preset = pending.options[choice - 1];
|
|
4554
4590
|
if (!preset) {
|
|
4555
4591
|
display.showWarning('That option is not available.');
|
|
4556
|
-
this.
|
|
4592
|
+
this.syncRendererInput();
|
|
4557
4593
|
return;
|
|
4558
4594
|
}
|
|
4559
4595
|
this.pendingInteraction = null;
|
|
4560
4596
|
await this.applyModelPreset(preset);
|
|
4561
|
-
this.
|
|
4597
|
+
this.syncRendererInput();
|
|
4562
4598
|
}
|
|
4563
4599
|
async applyModelPreset(preset) {
|
|
4564
4600
|
try {
|
|
@@ -4591,30 +4627,30 @@ export class InteractiveShell {
|
|
|
4591
4627
|
const trimmed = input.trim();
|
|
4592
4628
|
if (!trimmed) {
|
|
4593
4629
|
display.showWarning('Enter a number or type cancel.');
|
|
4594
|
-
this.
|
|
4630
|
+
this.syncRendererInput();
|
|
4595
4631
|
return;
|
|
4596
4632
|
}
|
|
4597
4633
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
4598
4634
|
this.pendingInteraction = null;
|
|
4599
4635
|
display.showInfo('Secret management cancelled.');
|
|
4600
|
-
this.
|
|
4636
|
+
this.syncRendererInput();
|
|
4601
4637
|
return;
|
|
4602
4638
|
}
|
|
4603
4639
|
const choice = Number.parseInt(trimmed, 10);
|
|
4604
4640
|
if (!Number.isFinite(choice)) {
|
|
4605
4641
|
display.showWarning('Please enter a valid number.');
|
|
4606
|
-
this.
|
|
4642
|
+
this.syncRendererInput();
|
|
4607
4643
|
return;
|
|
4608
4644
|
}
|
|
4609
4645
|
const secret = pending.options[choice - 1];
|
|
4610
4646
|
if (!secret) {
|
|
4611
4647
|
display.showWarning('That option is not available.');
|
|
4612
|
-
this.
|
|
4648
|
+
this.syncRendererInput();
|
|
4613
4649
|
return;
|
|
4614
4650
|
}
|
|
4615
4651
|
display.showSystemMessage(`Enter a new value for ${secret.label} or type "cancel".`);
|
|
4616
4652
|
this.pendingInteraction = { type: 'secret-input', secret };
|
|
4617
|
-
this.
|
|
4653
|
+
this.syncRendererInput();
|
|
4618
4654
|
}
|
|
4619
4655
|
async handleSecretInput(input) {
|
|
4620
4656
|
const pending = this.pendingInteraction;
|
|
@@ -4624,14 +4660,14 @@ export class InteractiveShell {
|
|
|
4624
4660
|
const trimmed = input.trim();
|
|
4625
4661
|
if (!trimmed) {
|
|
4626
4662
|
display.showWarning('Enter a value or type cancel.');
|
|
4627
|
-
this.
|
|
4663
|
+
this.syncRendererInput();
|
|
4628
4664
|
return;
|
|
4629
4665
|
}
|
|
4630
4666
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
4631
4667
|
this.pendingInteraction = null;
|
|
4632
4668
|
this.pendingSecretRetry = null;
|
|
4633
4669
|
display.showInfo('Secret unchanged.');
|
|
4634
|
-
this.
|
|
4670
|
+
this.syncRendererInput();
|
|
4635
4671
|
return;
|
|
4636
4672
|
}
|
|
4637
4673
|
try {
|
|
@@ -4655,7 +4691,7 @@ export class InteractiveShell {
|
|
|
4655
4691
|
this.pendingInteraction = null;
|
|
4656
4692
|
this.pendingSecretRetry = null;
|
|
4657
4693
|
}
|
|
4658
|
-
this.
|
|
4694
|
+
this.syncRendererInput();
|
|
4659
4695
|
}
|
|
4660
4696
|
async processRequest(request) {
|
|
4661
4697
|
if (this.isProcessing) {
|
|
@@ -4675,7 +4711,8 @@ export class InteractiveShell {
|
|
|
4675
4711
|
this.uiUpdates.setMode('processing');
|
|
4676
4712
|
this.terminalInput.setStreaming(true);
|
|
4677
4713
|
// Keep the persistent input/control bar active as we transition into streaming.
|
|
4678
|
-
this.
|
|
4714
|
+
this.syncRendererInput();
|
|
4715
|
+
this.uiRenderer?.render();
|
|
4679
4716
|
const requestStartTime = Date.now(); // Alpha Zero 2 timing
|
|
4680
4717
|
// Clear previous parallel agents and start fresh for new request
|
|
4681
4718
|
const parallelManager = getParallelAgentManager();
|
|
@@ -4761,7 +4798,7 @@ export class InteractiveShell {
|
|
|
4761
4798
|
this.updateStatusMessage(null);
|
|
4762
4799
|
queueMicrotask(() => this.uiUpdates.setMode('idle'));
|
|
4763
4800
|
// CRITICAL: Ensure readline prompt is active for user input
|
|
4764
|
-
//
|
|
4801
|
+
// Erosolar-CLI style: New prompt naturally appears at bottom
|
|
4765
4802
|
this.ensureReadlineReady();
|
|
4766
4803
|
this.scheduleQueueProcessing();
|
|
4767
4804
|
this.refreshQueueIndicators();
|
|
@@ -4991,7 +5028,7 @@ What's the next action?`;
|
|
|
4991
5028
|
this.updateStatusMessage(null);
|
|
4992
5029
|
queueMicrotask(() => this.uiUpdates.setMode('idle'));
|
|
4993
5030
|
// CRITICAL: Ensure readline prompt is active for user input
|
|
4994
|
-
//
|
|
5031
|
+
// Erosolar-CLI style: New prompt naturally appears at bottom
|
|
4995
5032
|
this.ensureReadlineReady();
|
|
4996
5033
|
this.scheduleQueueProcessing();
|
|
4997
5034
|
this.refreshQueueIndicators();
|
|
@@ -5602,7 +5639,7 @@ Return ONLY JSON array:
|
|
|
5602
5639
|
void this.runAutoQualityChecks('final-response', finalContent);
|
|
5603
5640
|
}
|
|
5604
5641
|
else {
|
|
5605
|
-
// Non-final message = narrative text before tool calls (
|
|
5642
|
+
// Non-final message = narrative text before tool calls (Erosolar-CLI style)
|
|
5606
5643
|
// Stop spinner and show the narrative text directly
|
|
5607
5644
|
display.stopThinking();
|
|
5608
5645
|
// Skip display if content was already streamed to avoid double-display
|
|
@@ -5649,19 +5686,19 @@ Return ONLY JSON array:
|
|
|
5649
5686
|
this.updateContextUsage(percentage);
|
|
5650
5687
|
}
|
|
5651
5688
|
// Ensure prompt remains visible at bottom after context messages
|
|
5652
|
-
this.
|
|
5689
|
+
this.syncRendererInput();
|
|
5653
5690
|
},
|
|
5654
5691
|
onContinueAfterRecovery: () => {
|
|
5655
5692
|
// Update UI to show we're continuing after context recovery
|
|
5656
5693
|
display.showSystemMessage(`🔄 Continuing after context recovery...`);
|
|
5657
5694
|
this.updateStatusMessage('Retrying with reduced context...');
|
|
5658
|
-
this.
|
|
5695
|
+
this.syncRendererInput();
|
|
5659
5696
|
},
|
|
5660
5697
|
onAutoContinue: (attempt, maxAttempts, _message) => {
|
|
5661
5698
|
// Show auto-continue progress in UI
|
|
5662
5699
|
display.showSystemMessage(`🔄 Auto-continue (${attempt}/${maxAttempts}): Model expressed intent, prompting to act...`);
|
|
5663
5700
|
this.updateStatusMessage('Auto-continuing...');
|
|
5664
|
-
this.
|
|
5701
|
+
this.syncRendererInput();
|
|
5665
5702
|
},
|
|
5666
5703
|
onCancelled: () => {
|
|
5667
5704
|
// Update UI to show operation was cancelled
|