erosolar-cli 1.7.391 → 1.7.393
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/toolPreconditions.d.ts.map +1 -1
- package/dist/core/toolPreconditions.js +56 -8
- package/dist/core/toolPreconditions.js.map +1 -1
- package/dist/core/toolRuntime.d.ts +0 -6
- package/dist/core/toolRuntime.d.ts.map +1 -1
- package/dist/core/toolRuntime.js +0 -7
- package/dist/core/toolRuntime.js.map +1 -1
- package/dist/plugins/tools/nodeDefaults.js +2 -2
- package/dist/plugins/tools/nodeDefaults.js.map +1 -1
- package/dist/runtime/agentHost.d.ts +1 -3
- package/dist/runtime/agentHost.d.ts.map +1 -1
- package/dist/runtime/agentHost.js +0 -3
- package/dist/runtime/agentHost.js.map +1 -1
- package/dist/runtime/agentSession.d.ts +1 -2
- package/dist/runtime/agentSession.d.ts.map +1 -1
- package/dist/runtime/agentSession.js +0 -1
- package/dist/runtime/agentSession.js.map +1 -1
- package/dist/runtime/universal.d.ts +1 -2
- package/dist/runtime/universal.d.ts.map +1 -1
- package/dist/runtime/universal.js +0 -1
- package/dist/runtime/universal.js.map +1 -1
- package/dist/shell/interactiveShell.d.ts +5 -23
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +109 -218
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/shellApp.d.ts.map +1 -1
- package/dist/shell/shellApp.js +0 -5
- package/dist/shell/shellApp.js.map +1 -1
- package/dist/shell/systemPrompt.d.ts.map +1 -1
- package/dist/shell/systemPrompt.js +0 -1
- package/dist/shell/systemPrompt.js.map +1 -1
- package/dist/shell/terminalInput.d.ts +8 -16
- package/dist/shell/terminalInput.d.ts.map +1 -1
- package/dist/shell/terminalInput.js +78 -132
- package/dist/shell/terminalInput.js.map +1 -1
- package/dist/shell/terminalInputAdapter.d.ts +0 -9
- package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
- package/dist/shell/terminalInputAdapter.js +0 -6
- package/dist/shell/terminalInputAdapter.js.map +1 -1
- package/dist/tools/fileTools.d.ts.map +1 -1
- package/dist/tools/fileTools.js +21 -26
- package/dist/tools/fileTools.js.map +1 -1
- package/dist/tools/grepTools.js +4 -3
- package/dist/tools/grepTools.js.map +1 -1
- package/dist/tools/searchTools.d.ts.map +1 -1
- package/dist/tools/searchTools.js +13 -47
- package/dist/tools/searchTools.js.map +1 -1
- package/dist/tools/webTools.d.ts.map +1 -1
- package/dist/tools/webTools.js +10 -30
- package/dist/tools/webTools.js.map +1 -1
- package/dist/ui/display.d.ts +8 -12
- package/dist/ui/display.d.ts.map +1 -1
- package/dist/ui/display.js +62 -122
- package/dist/ui/display.js.map +1 -1
- package/dist/ui/layout.js +7 -8
- package/dist/ui/layout.js.map +1 -1
- package/dist/ui/toolDisplay.d.ts.map +1 -1
- package/dist/ui/toolDisplay.js +2 -1
- package/dist/ui/toolDisplay.js.map +1 -1
- package/dist/ui/unified/layout.js +2 -2
- package/dist/ui/unified/layout.js.map +1 -1
- package/package.json +1 -1
- package/dist/plugins/tools/build/buildPlugin.d.ts +0 -3
- package/dist/plugins/tools/build/buildPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/build/buildPlugin.js +0 -14
- package/dist/plugins/tools/build/buildPlugin.js.map +0 -1
|
@@ -152,15 +152,10 @@ export class InteractiveShell {
|
|
|
152
152
|
// Auto-build tracking
|
|
153
153
|
autoBuildInFlight = false;
|
|
154
154
|
lastAutoBuildRun = null;
|
|
155
|
-
// Tool usage tracking for per-run summaries
|
|
156
|
-
toolHistoryOffset = 0;
|
|
157
155
|
// Streaming UX tracking
|
|
158
|
-
batchedOutputMode;
|
|
159
156
|
streamingHeartbeatStart = null;
|
|
160
157
|
streamingHeartbeatFrame = 0;
|
|
161
158
|
streamingStatusLabel = null;
|
|
162
|
-
streamingUiActive = false;
|
|
163
|
-
pendingStreamBuffer = '';
|
|
164
159
|
lastStreamingElapsedSeconds = null; // Preserve final elapsed time
|
|
165
160
|
statusLineState = null;
|
|
166
161
|
statusMessageOverride = null;
|
|
@@ -182,11 +177,6 @@ export class InteractiveShell {
|
|
|
182
177
|
this.sessionRestoreConfig = config.sessionRestore ?? { mode: 'none' };
|
|
183
178
|
this._enabledPlugins = config.enabledPlugins ?? [];
|
|
184
179
|
this.version = config.version ?? '0.0.0';
|
|
185
|
-
const streamingEnv = process.env['EROSOLAR_STREAMING_UI']?.toLowerCase();
|
|
186
|
-
// Default to live streaming for immediate thought/tool/response visibility; opt out with EROSOLAR_STREAMING_UI=off/false/0/batch/batched
|
|
187
|
-
const streamingDisabled = streamingEnv === 'off' || streamingEnv === 'false' || streamingEnv === '0' ||
|
|
188
|
-
streamingEnv === 'batch' || streamingEnv === 'batched';
|
|
189
|
-
this.batchedOutputMode = streamingDisabled;
|
|
190
180
|
// Alternate screen disabled - use terminal-native mode for proper scrollback and text selection
|
|
191
181
|
this.alternateScreenEnabled = false;
|
|
192
182
|
this.initializeSessionHistory();
|
|
@@ -289,7 +279,7 @@ export class InteractiveShell {
|
|
|
289
279
|
}
|
|
290
280
|
// Stream banner first - this sets up scroll region dynamically
|
|
291
281
|
const banner = this.buildBanner();
|
|
292
|
-
this.terminalInput.streamContent(banner + '\n');
|
|
282
|
+
this.terminalInput.streamContent(banner + '\n\n');
|
|
293
283
|
// Render chat box after banner is streamed
|
|
294
284
|
this.refreshControlBar();
|
|
295
285
|
this.terminalInput.forceRender();
|
|
@@ -789,21 +779,6 @@ export class InteractiveShell {
|
|
|
789
779
|
// During streaming we still want the spinner prefix; when idle force a fast refresh.
|
|
790
780
|
this.refreshStatusLine(!this.isProcessing);
|
|
791
781
|
}
|
|
792
|
-
/**
|
|
793
|
-
* Inline menu/panel helpers (rendered in TerminalInput, not in scrollback).
|
|
794
|
-
*/
|
|
795
|
-
showInlineMenu(title, lines, tone = 'info', hint) {
|
|
796
|
-
const merged = [...lines];
|
|
797
|
-
if (hint) {
|
|
798
|
-
merged.push('', tone === 'error' ? theme.error(hint) : theme.warning(hint));
|
|
799
|
-
}
|
|
800
|
-
this.terminalInput.setInlinePanel({ title, lines: merged, tone });
|
|
801
|
-
this.terminalInput.render();
|
|
802
|
-
}
|
|
803
|
-
clearInlineMenu() {
|
|
804
|
-
this.terminalInput.setInlinePanel(null);
|
|
805
|
-
this.terminalInput.render();
|
|
806
|
-
}
|
|
807
782
|
async handleToolSettingsInput(input) {
|
|
808
783
|
const pending = this.pendingInteraction;
|
|
809
784
|
if (!pending || pending.type !== 'tool-settings') {
|
|
@@ -1103,6 +1078,7 @@ export class InteractiveShell {
|
|
|
1103
1078
|
}
|
|
1104
1079
|
});
|
|
1105
1080
|
this.setIdleStatus();
|
|
1081
|
+
this.startStatusHeartbeat();
|
|
1106
1082
|
}
|
|
1107
1083
|
teardownStatusTracking() {
|
|
1108
1084
|
if (this.statusSubscription) {
|
|
@@ -1114,8 +1090,6 @@ export class InteractiveShell {
|
|
|
1114
1090
|
this.statusTracker.reset();
|
|
1115
1091
|
}
|
|
1116
1092
|
setIdleStatus(detail) {
|
|
1117
|
-
// Reset streaming timer display when returning to idle so elapsed doesn't linger
|
|
1118
|
-
this.lastStreamingElapsedSeconds = null;
|
|
1119
1093
|
this.statusTracker.setBase('Ready for prompts', {
|
|
1120
1094
|
detail: this.describeStatusDetail(detail),
|
|
1121
1095
|
tone: 'success',
|
|
@@ -1228,6 +1202,26 @@ export class InteractiveShell {
|
|
|
1228
1202
|
this.terminalInput.render();
|
|
1229
1203
|
}
|
|
1230
1204
|
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Keep the bottom meta/status line ticking so elapsed time updates even when idle.
|
|
1207
|
+
* Streaming heartbeat already refreshes once per second; skip duplicate work there.
|
|
1208
|
+
*/
|
|
1209
|
+
startStatusHeartbeat() {
|
|
1210
|
+
this.uiUpdates.startHeartbeat('status:meta', {
|
|
1211
|
+
intervalMs: 1000,
|
|
1212
|
+
lane: 'heartbeat',
|
|
1213
|
+
priority: 'low',
|
|
1214
|
+
coalesceKey: 'heartbeat:status-meta',
|
|
1215
|
+
description: 'status/meta refresh',
|
|
1216
|
+
mode: ['idle', 'processing', 'streaming', 'tooling', 'mcp', 'external'],
|
|
1217
|
+
run: () => {
|
|
1218
|
+
if (this.uiUpdates.isHeartbeatActive('streaming')) {
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
this.refreshStatusLine(true);
|
|
1222
|
+
},
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1231
1225
|
formatStatusLine(state) {
|
|
1232
1226
|
if (!state) {
|
|
1233
1227
|
return null;
|
|
@@ -1315,49 +1309,17 @@ export class InteractiveShell {
|
|
|
1315
1309
|
this.promptRefreshTimer = null;
|
|
1316
1310
|
}
|
|
1317
1311
|
}
|
|
1318
|
-
resetStreamBuffer() {
|
|
1319
|
-
this.pendingStreamBuffer = '';
|
|
1320
|
-
}
|
|
1321
|
-
captureStreamChunk(chunk) {
|
|
1322
|
-
if (!this.batchedOutputMode || !chunk) {
|
|
1323
|
-
return;
|
|
1324
|
-
}
|
|
1325
|
-
this.pendingStreamBuffer += chunk;
|
|
1326
|
-
}
|
|
1327
|
-
consumeStreamBuffer(fallback) {
|
|
1328
|
-
if (!this.batchedOutputMode) {
|
|
1329
|
-
return fallback;
|
|
1330
|
-
}
|
|
1331
|
-
const buffered = this.pendingStreamBuffer;
|
|
1332
|
-
this.pendingStreamBuffer = '';
|
|
1333
|
-
return buffered || fallback;
|
|
1334
|
-
}
|
|
1335
|
-
currentRunElapsedMs() {
|
|
1336
|
-
if (!this.streamingHeartbeatStart) {
|
|
1337
|
-
return undefined;
|
|
1338
|
-
}
|
|
1339
|
-
return Date.now() - this.streamingHeartbeatStart;
|
|
1340
|
-
}
|
|
1341
1312
|
startStreamingHeartbeat(label = 'Streaming') {
|
|
1342
1313
|
this.stopStreamingHeartbeat();
|
|
1343
|
-
|
|
1344
|
-
|
|
1314
|
+
// Enter global streaming mode - blocks all non-streaming UI output
|
|
1315
|
+
enterStreamingMode();
|
|
1316
|
+
// Set up scroll region for streaming content
|
|
1317
|
+
this.terminalInput.enterStreamingScrollRegion();
|
|
1318
|
+
this.uiUpdates.setMode('streaming');
|
|
1345
1319
|
this.streamingHeartbeatStart = Date.now();
|
|
1346
1320
|
this.streamingHeartbeatFrame = 0;
|
|
1347
1321
|
const initialFrame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
|
|
1348
1322
|
this.streamingStatusLabel = this.buildStreamingStatus(`${initialFrame} ${label}`, 0);
|
|
1349
|
-
if (this.batchedOutputMode) {
|
|
1350
|
-
this.streamingUiActive = false;
|
|
1351
|
-
this.uiUpdates.setMode('processing');
|
|
1352
|
-
}
|
|
1353
|
-
else {
|
|
1354
|
-
// Enter global streaming mode - blocks all non-streaming UI output
|
|
1355
|
-
enterStreamingMode();
|
|
1356
|
-
// Set up scroll region for streaming content
|
|
1357
|
-
this.terminalInput.enterStreamingScrollRegion();
|
|
1358
|
-
this.streamingUiActive = true;
|
|
1359
|
-
this.uiUpdates.setMode('streaming');
|
|
1360
|
-
}
|
|
1361
1323
|
display.updateStreamingStatus(this.streamingStatusLabel);
|
|
1362
1324
|
this.refreshStatusLine(true);
|
|
1363
1325
|
// Periodically refresh the pinned input/status region while streaming so
|
|
@@ -1387,21 +1349,18 @@ export class InteractiveShell {
|
|
|
1387
1349
|
});
|
|
1388
1350
|
}
|
|
1389
1351
|
stopStreamingHeartbeat() {
|
|
1352
|
+
// Exit global streaming mode - allows UI to render again
|
|
1353
|
+
exitStreamingMode();
|
|
1390
1354
|
// Preserve final elapsed time before clearing heartbeat start
|
|
1391
1355
|
if (this.streamingHeartbeatStart) {
|
|
1392
1356
|
this.lastStreamingElapsedSeconds = Math.max(0, Math.floor((Date.now() - this.streamingHeartbeatStart) / 1000));
|
|
1393
1357
|
}
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
exitStreamingMode();
|
|
1397
|
-
// Exit scroll region mode
|
|
1398
|
-
this.terminalInput.exitStreamingScrollRegion();
|
|
1399
|
-
}
|
|
1358
|
+
// Exit scroll region mode
|
|
1359
|
+
this.terminalInput.exitStreamingScrollRegion();
|
|
1400
1360
|
this.uiUpdates.stopHeartbeat('streaming');
|
|
1401
1361
|
this.streamingHeartbeatStart = null;
|
|
1402
1362
|
this.streamingHeartbeatFrame = 0;
|
|
1403
1363
|
this.streamingStatusLabel = null;
|
|
1404
|
-
this.streamingUiActive = false;
|
|
1405
1364
|
// Clear streaming label specifically (keeps override and main status if set)
|
|
1406
1365
|
this.terminalInput.setStreamingLabel(null);
|
|
1407
1366
|
// Clear streaming status from display
|
|
@@ -3709,22 +3668,36 @@ export class InteractiveShell {
|
|
|
3709
3668
|
async showModelMenu() {
|
|
3710
3669
|
// Hold input immediately so numeric selections don't get queued as prompts while we fetch
|
|
3711
3670
|
this.pendingInteraction = { type: 'model-loading' };
|
|
3712
|
-
|
|
3671
|
+
display.showSystemMessage(theme.ui.muted('Fetching latest models from providers...'));
|
|
3713
3672
|
try {
|
|
3714
3673
|
// Fetch live models from all configured providers
|
|
3715
3674
|
const providerStatuses = await quickCheckProviders();
|
|
3716
3675
|
const providerOptions = this.buildProviderOptionsWithDiscovery(providerStatuses);
|
|
3717
3676
|
if (!providerOptions.length) {
|
|
3677
|
+
display.showWarning('No providers are available.');
|
|
3718
3678
|
this.pendingInteraction = null;
|
|
3719
|
-
this.
|
|
3679
|
+
this.terminalInput.render();
|
|
3720
3680
|
return;
|
|
3721
3681
|
}
|
|
3682
|
+
const lines = [
|
|
3683
|
+
theme.bold('Select a provider:'),
|
|
3684
|
+
...providerOptions.map((option, index) => {
|
|
3685
|
+
const isCurrent = option.provider === this.sessionState.provider;
|
|
3686
|
+
const countLabel = `${option.modelCount} model${option.modelCount === 1 ? '' : 's'}`;
|
|
3687
|
+
const latestLabel = option.latestModel ? theme.success(` (latest: ${option.latestModel})`) : '';
|
|
3688
|
+
const label = this.colorizeDropdownLine(`${index + 1}. ${option.label} — ${countLabel}${latestLabel}`, index);
|
|
3689
|
+
const suffix = isCurrent ? ` ${theme.primary('• current')}` : '';
|
|
3690
|
+
return `${label}${suffix}`;
|
|
3691
|
+
}),
|
|
3692
|
+
'Type the number of the provider to continue, or type "cancel".',
|
|
3693
|
+
];
|
|
3694
|
+
display.showSystemMessage(lines.join('\n'));
|
|
3722
3695
|
this.pendingInteraction = { type: 'model-provider', options: providerOptions };
|
|
3723
|
-
this.renderProviderMenu(providerOptions);
|
|
3724
3696
|
}
|
|
3725
3697
|
catch (error) {
|
|
3698
|
+
display.showError('Failed to load model list. Try again in a moment.', error);
|
|
3726
3699
|
this.pendingInteraction = null;
|
|
3727
|
-
this.
|
|
3700
|
+
this.terminalInput.render();
|
|
3728
3701
|
}
|
|
3729
3702
|
}
|
|
3730
3703
|
buildProviderOptions() {
|
|
@@ -3815,21 +3788,6 @@ export class InteractiveShell {
|
|
|
3815
3788
|
};
|
|
3816
3789
|
});
|
|
3817
3790
|
}
|
|
3818
|
-
renderProviderMenu(options, hint) {
|
|
3819
|
-
const lines = [
|
|
3820
|
-
theme.bold('Select a provider:'),
|
|
3821
|
-
...options.map((option, index) => {
|
|
3822
|
-
const isCurrent = option.provider === this.sessionState.provider;
|
|
3823
|
-
const countLabel = `${option.modelCount} model${option.modelCount === 1 ? '' : 's'}`;
|
|
3824
|
-
const latestLabel = option.latestModel ? theme.success(` (latest: ${option.latestModel})`) : '';
|
|
3825
|
-
const label = this.colorizeDropdownLine(`${index + 1}. ${option.label} — ${countLabel}${latestLabel}`, index);
|
|
3826
|
-
const suffix = isCurrent ? ` ${theme.primary('• current')}` : '';
|
|
3827
|
-
return `${label}${suffix}`;
|
|
3828
|
-
}),
|
|
3829
|
-
'Type the number of the provider to continue, or type "cancel".',
|
|
3830
|
-
];
|
|
3831
|
-
this.showInlineMenu('Model provider', lines, 'info', hint);
|
|
3832
|
-
}
|
|
3833
3791
|
showProviderModels(option) {
|
|
3834
3792
|
// Start with static presets
|
|
3835
3793
|
const staticModels = MODEL_PRESETS.filter((preset) => preset.provider === option.provider);
|
|
@@ -3869,17 +3827,13 @@ export class InteractiveShell {
|
|
|
3869
3827
|
}
|
|
3870
3828
|
}
|
|
3871
3829
|
if (!allModels.length) {
|
|
3872
|
-
|
|
3830
|
+
display.showWarning(`No models available for ${option.label}.`);
|
|
3873
3831
|
this.pendingInteraction = null;
|
|
3874
3832
|
return;
|
|
3875
3833
|
}
|
|
3876
|
-
this.renderModelSelection(allModels, option, null);
|
|
3877
|
-
this.pendingInteraction = { type: 'model', provider: option.provider, options: allModels };
|
|
3878
|
-
}
|
|
3879
|
-
renderModelSelection(models, option, hint) {
|
|
3880
3834
|
const lines = [
|
|
3881
3835
|
theme.bold(`Select a model from ${option.label}:`),
|
|
3882
|
-
...
|
|
3836
|
+
...allModels.map((preset, index) => {
|
|
3883
3837
|
const isCurrent = preset.id === this.sessionState.model;
|
|
3884
3838
|
const isLatest = preset.id === option.latestModel;
|
|
3885
3839
|
const latestBadge = isLatest ? theme.success(' ★ LATEST') : '';
|
|
@@ -3890,23 +3844,11 @@ export class InteractiveShell {
|
|
|
3890
3844
|
}),
|
|
3891
3845
|
'Type the number of the model to select it, type "back" to change provider, or type "cancel".',
|
|
3892
3846
|
];
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
buildProviderContext(provider, models) {
|
|
3896
|
-
return {
|
|
3897
|
-
provider,
|
|
3898
|
-
label: this.providerLabel(provider),
|
|
3899
|
-
modelCount: models.length,
|
|
3900
|
-
latestModel: models[0]?.id,
|
|
3901
|
-
discoveredModels: [],
|
|
3902
|
-
};
|
|
3847
|
+
display.showSystemMessage(lines.join('\n'));
|
|
3848
|
+
this.pendingInteraction = { type: 'model', provider: option.provider, options: allModels };
|
|
3903
3849
|
}
|
|
3904
3850
|
showSecretsMenu() {
|
|
3905
3851
|
const definitions = listSecretDefinitions();
|
|
3906
|
-
this.pendingInteraction = { type: 'secret-select', options: definitions };
|
|
3907
|
-
this.renderSecretsMenu(definitions);
|
|
3908
|
-
}
|
|
3909
|
-
renderSecretsMenu(definitions, hint) {
|
|
3910
3852
|
const lines = [
|
|
3911
3853
|
theme.bold('Manage Secrets:'),
|
|
3912
3854
|
...definitions.map((definition, index) => {
|
|
@@ -3918,18 +3860,8 @@ export class InteractiveShell {
|
|
|
3918
3860
|
}),
|
|
3919
3861
|
'Enter the number to update a key, or type "cancel".',
|
|
3920
3862
|
];
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
renderSecretInput(secret, hint) {
|
|
3924
|
-
const value = getSecretValue(secret.id);
|
|
3925
|
-
const status = value ? maskSecret(value) : theme.warning('not set');
|
|
3926
|
-
const providers = secret.providers.map((id) => this.providerLabel(id)).join(', ');
|
|
3927
|
-
const lines = [
|
|
3928
|
-
`${secret.label} (${providers})`,
|
|
3929
|
-
`Current: ${status}`,
|
|
3930
|
-
'Enter a new value or type "cancel".',
|
|
3931
|
-
];
|
|
3932
|
-
this.showInlineMenu('Update secret', lines, 'info', hint);
|
|
3863
|
+
display.showSystemMessage(lines.join('\n'));
|
|
3864
|
+
this.pendingInteraction = { type: 'secret-select', options: definitions };
|
|
3933
3865
|
}
|
|
3934
3866
|
showToolsMenu() {
|
|
3935
3867
|
const options = getToolToggleOptions();
|
|
@@ -4309,23 +4241,26 @@ export class InteractiveShell {
|
|
|
4309
4241
|
}
|
|
4310
4242
|
const trimmed = input.trim();
|
|
4311
4243
|
if (!trimmed) {
|
|
4312
|
-
|
|
4244
|
+
display.showWarning('Enter a number or type cancel.');
|
|
4245
|
+
this.terminalInput.render();
|
|
4313
4246
|
return;
|
|
4314
4247
|
}
|
|
4315
4248
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
4316
4249
|
this.pendingInteraction = null;
|
|
4317
|
-
|
|
4318
|
-
this.
|
|
4250
|
+
display.showInfo('Model selection cancelled.');
|
|
4251
|
+
this.terminalInput.render();
|
|
4319
4252
|
return;
|
|
4320
4253
|
}
|
|
4321
4254
|
const choice = Number.parseInt(trimmed, 10);
|
|
4322
4255
|
if (!Number.isFinite(choice)) {
|
|
4323
|
-
|
|
4256
|
+
display.showWarning('Please enter a valid number.');
|
|
4257
|
+
this.terminalInput.render();
|
|
4324
4258
|
return;
|
|
4325
4259
|
}
|
|
4326
4260
|
const option = pending.options[choice - 1];
|
|
4327
4261
|
if (!option) {
|
|
4328
|
-
|
|
4262
|
+
display.showWarning('That option is not available.');
|
|
4263
|
+
this.terminalInput.render();
|
|
4329
4264
|
return;
|
|
4330
4265
|
}
|
|
4331
4266
|
this.showProviderModels(option);
|
|
@@ -4336,10 +4271,10 @@ export class InteractiveShell {
|
|
|
4336
4271
|
if (!pending || pending.type !== 'model') {
|
|
4337
4272
|
return;
|
|
4338
4273
|
}
|
|
4339
|
-
const providerContext = this.buildProviderContext(pending.provider, pending.options);
|
|
4340
4274
|
const trimmed = input.trim();
|
|
4341
4275
|
if (!trimmed) {
|
|
4342
|
-
|
|
4276
|
+
display.showWarning('Enter a number, type "back", or type "cancel".');
|
|
4277
|
+
this.terminalInput.render();
|
|
4343
4278
|
return;
|
|
4344
4279
|
}
|
|
4345
4280
|
if (trimmed.toLowerCase() === 'back') {
|
|
@@ -4349,18 +4284,20 @@ export class InteractiveShell {
|
|
|
4349
4284
|
}
|
|
4350
4285
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
4351
4286
|
this.pendingInteraction = null;
|
|
4352
|
-
|
|
4353
|
-
this.
|
|
4287
|
+
display.showInfo('Model selection cancelled.');
|
|
4288
|
+
this.terminalInput.render();
|
|
4354
4289
|
return;
|
|
4355
4290
|
}
|
|
4356
4291
|
const choice = Number.parseInt(trimmed, 10);
|
|
4357
4292
|
if (!Number.isFinite(choice)) {
|
|
4358
|
-
|
|
4293
|
+
display.showWarning('Please enter a valid number.');
|
|
4294
|
+
this.terminalInput.render();
|
|
4359
4295
|
return;
|
|
4360
4296
|
}
|
|
4361
4297
|
const preset = pending.options[choice - 1];
|
|
4362
4298
|
if (!preset) {
|
|
4363
|
-
|
|
4299
|
+
display.showWarning('That option is not available.');
|
|
4300
|
+
this.terminalInput.render();
|
|
4364
4301
|
return;
|
|
4365
4302
|
}
|
|
4366
4303
|
this.pendingInteraction = null;
|
|
@@ -4384,14 +4321,11 @@ export class InteractiveShell {
|
|
|
4384
4321
|
};
|
|
4385
4322
|
this.applyPresetReasoningDefaults();
|
|
4386
4323
|
if (this.rebuildAgent()) {
|
|
4387
|
-
|
|
4324
|
+
display.showInfo(`Switched to ${preset.label}.`);
|
|
4388
4325
|
this.refreshBannerSessionInfo();
|
|
4389
4326
|
this.persistSessionPreference();
|
|
4390
4327
|
this.resetChatBoxAfterModelSwap();
|
|
4391
4328
|
}
|
|
4392
|
-
else {
|
|
4393
|
-
this.showInlineMenu('Model updated', [`Using ${preset.label}.`], 'info');
|
|
4394
|
-
}
|
|
4395
4329
|
}
|
|
4396
4330
|
async handleSecretSelection(input) {
|
|
4397
4331
|
const pending = this.pendingInteraction;
|
|
@@ -4400,27 +4334,30 @@ export class InteractiveShell {
|
|
|
4400
4334
|
}
|
|
4401
4335
|
const trimmed = input.trim();
|
|
4402
4336
|
if (!trimmed) {
|
|
4403
|
-
|
|
4337
|
+
display.showWarning('Enter a number or type cancel.');
|
|
4338
|
+
this.terminalInput.render();
|
|
4404
4339
|
return;
|
|
4405
4340
|
}
|
|
4406
4341
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
4407
4342
|
this.pendingInteraction = null;
|
|
4408
|
-
|
|
4409
|
-
this.
|
|
4343
|
+
display.showInfo('Secret management cancelled.');
|
|
4344
|
+
this.terminalInput.render();
|
|
4410
4345
|
return;
|
|
4411
4346
|
}
|
|
4412
4347
|
const choice = Number.parseInt(trimmed, 10);
|
|
4413
4348
|
if (!Number.isFinite(choice)) {
|
|
4414
|
-
|
|
4349
|
+
display.showWarning('Please enter a valid number.');
|
|
4350
|
+
this.terminalInput.render();
|
|
4415
4351
|
return;
|
|
4416
4352
|
}
|
|
4417
4353
|
const secret = pending.options[choice - 1];
|
|
4418
4354
|
if (!secret) {
|
|
4419
|
-
|
|
4355
|
+
display.showWarning('That option is not available.');
|
|
4356
|
+
this.terminalInput.render();
|
|
4420
4357
|
return;
|
|
4421
4358
|
}
|
|
4359
|
+
display.showSystemMessage(`Enter a new value for ${secret.label} or type "cancel".`);
|
|
4422
4360
|
this.pendingInteraction = { type: 'secret-input', secret };
|
|
4423
|
-
this.renderSecretInput(secret);
|
|
4424
4361
|
this.terminalInput.render();
|
|
4425
4362
|
}
|
|
4426
4363
|
async handleSecretInput(input) {
|
|
@@ -4430,20 +4367,20 @@ export class InteractiveShell {
|
|
|
4430
4367
|
}
|
|
4431
4368
|
const trimmed = input.trim();
|
|
4432
4369
|
if (!trimmed) {
|
|
4433
|
-
|
|
4370
|
+
display.showWarning('Enter a value or type cancel.');
|
|
4371
|
+
this.terminalInput.render();
|
|
4434
4372
|
return;
|
|
4435
4373
|
}
|
|
4436
4374
|
if (trimmed.toLowerCase() === 'cancel') {
|
|
4437
4375
|
this.pendingInteraction = null;
|
|
4438
4376
|
this.pendingSecretRetry = null;
|
|
4439
|
-
|
|
4440
|
-
this.updateStatusMessage('Secret unchanged.');
|
|
4377
|
+
display.showInfo('Secret unchanged.');
|
|
4441
4378
|
this.terminalInput.render();
|
|
4442
4379
|
return;
|
|
4443
4380
|
}
|
|
4444
4381
|
try {
|
|
4445
4382
|
setSecretValue(pending.secret.id, trimmed);
|
|
4446
|
-
|
|
4383
|
+
display.showInfo(`${pending.secret.label} updated.`);
|
|
4447
4384
|
this.pendingInteraction = null;
|
|
4448
4385
|
const deferred = this.pendingSecretRetry;
|
|
4449
4386
|
this.pendingSecretRetry = null;
|
|
@@ -4458,7 +4395,7 @@ export class InteractiveShell {
|
|
|
4458
4395
|
}
|
|
4459
4396
|
catch (error) {
|
|
4460
4397
|
const message = error instanceof Error ? error.message : String(error);
|
|
4461
|
-
|
|
4398
|
+
display.showError(message);
|
|
4462
4399
|
this.pendingInteraction = null;
|
|
4463
4400
|
this.pendingSecretRetry = null;
|
|
4464
4401
|
}
|
|
@@ -4496,10 +4433,8 @@ export class InteractiveShell {
|
|
|
4496
4433
|
this.setProcessingStatus();
|
|
4497
4434
|
let responseText = '';
|
|
4498
4435
|
try {
|
|
4499
|
-
this.captureToolHistoryOffset();
|
|
4500
4436
|
// Start streaming - no header needed, the input area already provides context
|
|
4501
|
-
|
|
4502
|
-
this.startStreamingHeartbeat(heartbeatLabel);
|
|
4437
|
+
this.startStreamingHeartbeat('Streaming response');
|
|
4503
4438
|
responseText = await agent.send(request, true);
|
|
4504
4439
|
await this.awaitPendingCleanup();
|
|
4505
4440
|
this.captureHistorySnapshot();
|
|
@@ -4615,8 +4550,7 @@ export class InteractiveShell {
|
|
|
4615
4550
|
this.uiAdapter.startProcessing('Continuous execution mode');
|
|
4616
4551
|
this.setProcessingStatus();
|
|
4617
4552
|
// No streaming header - just start streaming directly
|
|
4618
|
-
|
|
4619
|
-
this.startStreamingHeartbeat(continuousLabel);
|
|
4553
|
+
this.startStreamingHeartbeat('Streaming');
|
|
4620
4554
|
let iteration = 0;
|
|
4621
4555
|
let lastResponse = '';
|
|
4622
4556
|
let consecutiveNoProgress = 0;
|
|
@@ -4644,11 +4578,9 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
|
|
|
4644
4578
|
display.showSystemMessage(`\n📍 Iteration ${iteration}/${MAX_ITERATIONS}`);
|
|
4645
4579
|
this.updateStatusMessage(`Working on iteration ${iteration}...`);
|
|
4646
4580
|
try {
|
|
4647
|
-
|
|
4648
|
-
// Send the request and capture the response as a single block
|
|
4581
|
+
// Send the request and capture the response (streaming disabled)
|
|
4649
4582
|
display.showThinking('Responding...');
|
|
4650
4583
|
this.refreshStatusLine(true);
|
|
4651
|
-
this.resetStreamBuffer();
|
|
4652
4584
|
const response = await agent.send(currentPrompt, true);
|
|
4653
4585
|
await this.awaitPendingCleanup();
|
|
4654
4586
|
this.captureHistorySnapshot();
|
|
@@ -5149,7 +5081,6 @@ What's the next action?`;
|
|
|
5149
5081
|
// Send the error to the agent for fixing
|
|
5150
5082
|
display.showThinking('Analyzing build errors');
|
|
5151
5083
|
this.refreshStatusLine(true);
|
|
5152
|
-
this.resetStreamBuffer();
|
|
5153
5084
|
const response = await this.agent.send(prompt, true);
|
|
5154
5085
|
display.stopThinking();
|
|
5155
5086
|
this.refreshStatusLine(true);
|
|
@@ -5179,37 +5110,30 @@ What's the next action?`;
|
|
|
5179
5110
|
};
|
|
5180
5111
|
this.agent = this.runtimeSession.createAgent(selection, {
|
|
5181
5112
|
onStreamChunk: (chunk) => {
|
|
5182
|
-
if (this.batchedOutputMode) {
|
|
5183
|
-
this.captureStreamChunk(chunk);
|
|
5184
|
-
return;
|
|
5185
|
-
}
|
|
5186
5113
|
// Stream output using clean streamContent() - chat box floats below
|
|
5187
5114
|
this.terminalInput.streamContent(chunk);
|
|
5188
5115
|
},
|
|
5189
5116
|
onStreamFallback: (info) => this.handleStreamingFallback(info),
|
|
5190
5117
|
onAssistantMessage: (content, metadata) => {
|
|
5191
5118
|
const enriched = this.buildDisplayMetadata(metadata);
|
|
5192
|
-
const alreadyStreamedToUi = !this.batchedOutputMode && metadata.wasStreamed;
|
|
5193
|
-
const bufferedContent = this.consumeStreamBuffer(content);
|
|
5194
5119
|
// Update spinner based on message type
|
|
5195
5120
|
if (metadata.isFinal) {
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5121
|
+
// Skip display if content was already streamed to avoid double-display
|
|
5122
|
+
if (!metadata.wasStreamed) {
|
|
5123
|
+
const parsed = this.splitThinkingResponse(content);
|
|
5124
|
+
if (parsed?.thinking) {
|
|
5125
|
+
const summary = this.extractThoughtSummary(parsed.thinking);
|
|
5126
|
+
if (summary) {
|
|
5127
|
+
display.updateThinking(`💭 ${summary}`);
|
|
5128
|
+
}
|
|
5129
|
+
display.showAssistantMessage(parsed.thinking, { ...enriched, isFinal: false });
|
|
5130
|
+
}
|
|
5131
|
+
const finalContent = parsed?.response?.trim() || content;
|
|
5132
|
+
if (finalContent) {
|
|
5133
|
+
display.showAssistantMessage(finalContent, enriched);
|
|
5204
5134
|
}
|
|
5205
5135
|
}
|
|
5206
|
-
|
|
5207
|
-
display.showThoughtAndResponse({
|
|
5208
|
-
thinking: thinkingContent,
|
|
5209
|
-
response: finalContent || null,
|
|
5210
|
-
metadata: { ...enriched, isFinal: true, toolsUsed },
|
|
5211
|
-
});
|
|
5212
|
-
}
|
|
5136
|
+
// Status shown in mode controls bar - no separate status line needed
|
|
5213
5137
|
display.stopThinking();
|
|
5214
5138
|
// Update context usage for mode controls display
|
|
5215
5139
|
if (enriched.contextWindowTokens && metadata.usage) {
|
|
@@ -5228,13 +5152,8 @@ What's the next action?`;
|
|
|
5228
5152
|
// Stop spinner and show the narrative text directly
|
|
5229
5153
|
display.stopThinking();
|
|
5230
5154
|
// Skip display if content was already streamed to avoid double-display
|
|
5231
|
-
if (!
|
|
5232
|
-
|
|
5233
|
-
const thoughtContent = parsed?.thinking ?? parsed?.response ?? bufferedContent;
|
|
5234
|
-
const trimmed = thoughtContent.trim();
|
|
5235
|
-
if (trimmed) {
|
|
5236
|
-
display.showThinkingBlock(trimmed, enriched.elapsedMs ?? this.currentRunElapsedMs());
|
|
5237
|
-
}
|
|
5155
|
+
if (!metadata.wasStreamed) {
|
|
5156
|
+
display.showNarrative(content.trim());
|
|
5238
5157
|
}
|
|
5239
5158
|
// The isProcessing flag already shows "⏳ Processing..." - no need for duplicate status
|
|
5240
5159
|
this.requestPromptRefresh();
|
|
@@ -5587,25 +5506,6 @@ What's the next action?`;
|
|
|
5587
5506
|
return false;
|
|
5588
5507
|
}
|
|
5589
5508
|
}
|
|
5590
|
-
captureToolHistoryOffset() {
|
|
5591
|
-
this.toolHistoryOffset = this.runtimeSession.toolRuntime.getToolHistory?.().length ?? 0;
|
|
5592
|
-
}
|
|
5593
|
-
getToolNamesSinceOffset() {
|
|
5594
|
-
const history = this.runtimeSession.toolRuntime.getToolHistory?.();
|
|
5595
|
-
if (!history?.length) {
|
|
5596
|
-
return [];
|
|
5597
|
-
}
|
|
5598
|
-
const start = Math.max(0, this.toolHistoryOffset);
|
|
5599
|
-
const recent = history.slice(start);
|
|
5600
|
-
const names = [];
|
|
5601
|
-
for (const entry of recent) {
|
|
5602
|
-
const name = entry.toolName;
|
|
5603
|
-
if (name && !names.includes(name)) {
|
|
5604
|
-
names.push(name);
|
|
5605
|
-
}
|
|
5606
|
-
}
|
|
5607
|
-
return names;
|
|
5608
|
-
}
|
|
5609
5509
|
getContextWarningLevel(percentage) {
|
|
5610
5510
|
if (percentage >= 90) {
|
|
5611
5511
|
return 'danger';
|
|
@@ -5812,12 +5712,7 @@ What's the next action?`;
|
|
|
5812
5712
|
const reason = info.reason ? ` (${info.reason.replace(/-/g, ' ')})` : '';
|
|
5813
5713
|
const partialNote = info.partialResponse ? ' Received partial stream before failure.' : '';
|
|
5814
5714
|
display.showWarning(`Streaming failed${reason}, retrying without streaming.${detail}${partialNote}`);
|
|
5815
|
-
|
|
5816
|
-
if (this.batchedOutputMode && bufferedPartial.trim()) {
|
|
5817
|
-
display.showThinkingBlock(bufferedPartial.trim(), this.currentRunElapsedMs());
|
|
5818
|
-
}
|
|
5819
|
-
const fallbackLabel = this.batchedOutputMode ? 'Retrying (batched)' : 'Fallback in progress';
|
|
5820
|
-
this.startStreamingHeartbeat(fallbackLabel);
|
|
5715
|
+
this.startStreamingHeartbeat('Fallback in progress');
|
|
5821
5716
|
this.requestPromptRefresh(true);
|
|
5822
5717
|
}
|
|
5823
5718
|
handleProviderError(error, retryAction) {
|
|
@@ -5828,9 +5723,9 @@ What's the next action?`;
|
|
|
5828
5723
|
this.handleApiKeyIssue(apiKeyIssue, retryAction);
|
|
5829
5724
|
return true;
|
|
5830
5725
|
}
|
|
5831
|
-
handleApiKeyIssue(info, retryAction
|
|
5726
|
+
handleApiKeyIssue(info, retryAction) {
|
|
5832
5727
|
const secret = info.secret ?? null;
|
|
5833
|
-
const providerLabel =
|
|
5728
|
+
const providerLabel = info.provider ? this.providerLabel(info.provider) : 'the selected provider';
|
|
5834
5729
|
if (!secret) {
|
|
5835
5730
|
this.pendingSecretRetry = null;
|
|
5836
5731
|
const guidance = 'Run "/secrets" to configure the required API key or export it (e.g., EXPORT KEY=value) before launching the CLI.';
|
|
@@ -5852,10 +5747,6 @@ What's the next action?`;
|
|
|
5852
5747
|
this.pendingInteraction = { type: 'secret-input', secret };
|
|
5853
5748
|
this.showSecretGuidance(secret, isMissing);
|
|
5854
5749
|
}
|
|
5855
|
-
handleToolApiKeyIssue(info, call) {
|
|
5856
|
-
const label = call?.name ? `${call.name} tool` : 'web tools';
|
|
5857
|
-
this.handleApiKeyIssue(info, undefined, label);
|
|
5858
|
-
}
|
|
5859
5750
|
showSecretGuidance(secret, promptForInput) {
|
|
5860
5751
|
const lines = [];
|
|
5861
5752
|
if (promptForInput) {
|
|
@@ -5865,7 +5756,7 @@ What's the next action?`;
|
|
|
5865
5756
|
lines.push(`Update the stored value for ${secret.label} or type "cancel".`);
|
|
5866
5757
|
}
|
|
5867
5758
|
lines.push(`Tip: run "/secrets" anytime to manage credentials or export ${secret.envVar}=<value> before launching the CLI.`);
|
|
5868
|
-
|
|
5759
|
+
display.showSystemMessage(lines.join('\n'));
|
|
5869
5760
|
}
|
|
5870
5761
|
colorizeDropdownLine(text, index) {
|
|
5871
5762
|
if (!DROPDOWN_COLORS.length) {
|