erosolar-cli 1.7.258 → 1.7.259
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/README.md +148 -22
- package/dist/core/aiFlowOptimizer.d.ts +26 -0
- package/dist/core/aiFlowOptimizer.d.ts.map +1 -0
- package/dist/core/aiFlowOptimizer.js +31 -0
- package/dist/core/aiFlowOptimizer.js.map +1 -0
- package/dist/core/aiOptimizationEngine.d.ts +158 -0
- package/dist/core/aiOptimizationEngine.d.ts.map +1 -0
- package/dist/core/aiOptimizationEngine.js +428 -0
- package/dist/core/aiOptimizationEngine.js.map +1 -0
- package/dist/core/aiOptimizationIntegration.d.ts +93 -0
- package/dist/core/aiOptimizationIntegration.d.ts.map +1 -0
- package/dist/core/aiOptimizationIntegration.js +250 -0
- package/dist/core/aiOptimizationIntegration.js.map +1 -0
- package/dist/core/customCommands.d.ts +0 -1
- package/dist/core/customCommands.d.ts.map +1 -1
- package/dist/core/customCommands.js +0 -3
- package/dist/core/customCommands.js.map +1 -1
- package/dist/core/enhancedErrorRecovery.d.ts +100 -0
- package/dist/core/enhancedErrorRecovery.d.ts.map +1 -0
- package/dist/core/enhancedErrorRecovery.js +345 -0
- package/dist/core/enhancedErrorRecovery.js.map +1 -0
- package/dist/core/toolPreconditions.d.ts.map +1 -1
- package/dist/core/toolPreconditions.js +14 -0
- package/dist/core/toolPreconditions.js.map +1 -1
- package/dist/core/toolRuntime.d.ts.map +1 -1
- package/dist/core/toolRuntime.js +5 -0
- package/dist/core/toolRuntime.js.map +1 -1
- package/dist/core/toolValidation.d.ts.map +1 -1
- package/dist/core/toolValidation.js +3 -14
- package/dist/core/toolValidation.js.map +1 -1
- package/dist/core/validationRunner.d.ts +3 -1
- package/dist/core/validationRunner.d.ts.map +1 -1
- package/dist/core/validationRunner.js.map +1 -1
- package/dist/mcp/sseClient.d.ts.map +1 -1
- package/dist/mcp/sseClient.js +18 -9
- package/dist/mcp/sseClient.js.map +1 -1
- package/dist/plugins/tools/build/buildPlugin.d.ts +6 -0
- package/dist/plugins/tools/build/buildPlugin.d.ts.map +1 -1
- package/dist/plugins/tools/build/buildPlugin.js +10 -4
- package/dist/plugins/tools/build/buildPlugin.js.map +1 -1
- package/dist/shell/claudeCodeStreamHandler.d.ts +145 -0
- package/dist/shell/claudeCodeStreamHandler.d.ts.map +1 -0
- package/dist/shell/claudeCodeStreamHandler.js +322 -0
- package/dist/shell/claudeCodeStreamHandler.js.map +1 -0
- package/dist/shell/inputQueueManager.d.ts +144 -0
- package/dist/shell/inputQueueManager.d.ts.map +1 -0
- package/dist/shell/inputQueueManager.js +290 -0
- package/dist/shell/inputQueueManager.js.map +1 -0
- package/dist/shell/interactiveShell.d.ts +2 -10
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +35 -190
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/streamingOutputManager.d.ts +115 -0
- package/dist/shell/streamingOutputManager.d.ts.map +1 -0
- package/dist/shell/streamingOutputManager.js +225 -0
- package/dist/shell/streamingOutputManager.js.map +1 -0
- package/dist/shell/terminalInput.d.ts +136 -66
- package/dist/shell/terminalInput.d.ts.map +1 -1
- package/dist/shell/terminalInput.js +662 -409
- package/dist/shell/terminalInput.js.map +1 -1
- package/dist/shell/terminalInputAdapter.d.ts +15 -20
- package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
- package/dist/shell/terminalInputAdapter.js +22 -14
- package/dist/shell/terminalInputAdapter.js.map +1 -1
- package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
- package/dist/ui/ShellUIAdapter.js +12 -13
- package/dist/ui/ShellUIAdapter.js.map +1 -1
- package/dist/ui/display.d.ts +0 -19
- package/dist/ui/display.d.ts.map +1 -1
- package/dist/ui/display.js +22 -135
- package/dist/ui/display.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/terminalUISchema.d.ts +195 -0
- package/dist/ui/terminalUISchema.d.ts.map +1 -0
- package/dist/ui/terminalUISchema.js +113 -0
- package/dist/ui/terminalUISchema.js.map +1 -0
- package/dist/ui/theme.d.ts.map +1 -1
- package/dist/ui/theme.js +8 -6
- package/dist/ui/theme.js.map +1 -1
- package/dist/ui/toolDisplay.d.ts +158 -0
- package/dist/ui/toolDisplay.d.ts.map +1 -1
- package/dist/ui/toolDisplay.js +348 -0
- package/dist/ui/toolDisplay.js.map +1 -1
- package/dist/ui/unified/layout.d.ts +0 -1
- package/dist/ui/unified/layout.d.ts.map +1 -1
- package/dist/ui/unified/layout.js +25 -15
- package/dist/ui/unified/layout.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import { stdin as input, stdout as output, exit } from 'node:process';
|
|
|
2
2
|
import { exec } from 'node:child_process';
|
|
3
3
|
import { promisify } from 'node:util';
|
|
4
4
|
import { display } from '../ui/display.js';
|
|
5
|
-
import { theme } from '../ui/theme.js';
|
|
5
|
+
import { theme, formatUserPrompt } from '../ui/theme.js';
|
|
6
6
|
import { getContextWindowTokens } from '../core/contextWindow.js';
|
|
7
7
|
import { ensureSecretForProvider, getSecretDefinitionForProvider, getSecretValue, listSecretDefinitions, maskSecret, setSecretValue, } from '../core/secretStore.js';
|
|
8
8
|
import { saveActiveProfilePreference, saveModelPreference, loadToolSettings, saveToolSettings, clearToolSettings, clearActiveProfilePreference, loadSessionPreferences, saveSessionPreferences, } from '../core/preferences.js';
|
|
@@ -34,7 +34,6 @@ const DROPDOWN_COLORS = [
|
|
|
34
34
|
theme.success,
|
|
35
35
|
theme.warning,
|
|
36
36
|
];
|
|
37
|
-
const STREAMING_SPINNER_FRAMES = ['◐', '◓', '◑', '◒'];
|
|
38
37
|
// Load MODEL_PRESETS from centralized schema
|
|
39
38
|
const MODEL_PRESETS = getModels().map((model) => ({
|
|
40
39
|
id: model.id,
|
|
@@ -49,13 +48,11 @@ const MODEL_PRESETS = getModels().map((model) => ({
|
|
|
49
48
|
const BASE_SLASH_COMMANDS = getSlashCommands().map((cmd) => ({
|
|
50
49
|
command: cmd.command,
|
|
51
50
|
description: cmd.description,
|
|
52
|
-
category: cmd.category,
|
|
53
51
|
}));
|
|
54
52
|
// Load PROVIDER_LABELS from centralized schema
|
|
55
53
|
const PROVIDER_LABELS = Object.fromEntries(getProviders().map((provider) => [provider.id, provider.label]));
|
|
56
54
|
// Allow enough time for paste detection to kick in before flushing buffered lines
|
|
57
55
|
const CONTEXT_USAGE_THRESHOLD = 0.9;
|
|
58
|
-
const CONTEXT_AUTOCOMPACT_PERCENT = Math.round(CONTEXT_USAGE_THRESHOLD * 100);
|
|
59
56
|
const CONTEXT_RECENT_MESSAGE_COUNT = 12;
|
|
60
57
|
const CONTEXT_CLEANUP_CHARS_PER_CHUNK = 6000;
|
|
61
58
|
const CONTEXT_CLEANUP_MAX_OUTPUT_TOKENS = 800;
|
|
@@ -101,7 +98,6 @@ export class InteractiveShell {
|
|
|
101
98
|
followUpQueue = [];
|
|
102
99
|
isDrainingQueue = false;
|
|
103
100
|
activeContextWindowTokens = null;
|
|
104
|
-
latestTokenUsage = { used: null, limit: null };
|
|
105
101
|
sessionPreferences;
|
|
106
102
|
autosaveEnabled;
|
|
107
103
|
autoContinueEnabled;
|
|
@@ -132,7 +128,6 @@ export class InteractiveShell {
|
|
|
132
128
|
statusLineState = null;
|
|
133
129
|
statusMessageOverride = null;
|
|
134
130
|
promptRefreshTimer = null;
|
|
135
|
-
launchPaletteShown = false;
|
|
136
131
|
constructor(config) {
|
|
137
132
|
this.profile = config.profile;
|
|
138
133
|
this.profileLabel = config.profileLabel;
|
|
@@ -166,7 +161,6 @@ export class InteractiveShell {
|
|
|
166
161
|
this.slashCommands.push({
|
|
167
162
|
command: '/agents',
|
|
168
163
|
description: 'Select the default agent profile (applies on next launch)',
|
|
169
|
-
category: 'configuration',
|
|
170
164
|
});
|
|
171
165
|
}
|
|
172
166
|
this.customCommands = loadCustomSlashCommands();
|
|
@@ -175,21 +169,18 @@ export class InteractiveShell {
|
|
|
175
169
|
this.slashCommands.push({
|
|
176
170
|
command: custom.command,
|
|
177
171
|
description: `${custom.description} (custom)`,
|
|
178
|
-
category: custom.category ?? 'other',
|
|
179
172
|
});
|
|
180
173
|
}
|
|
181
174
|
if (!this.slashCommands.some((cmd) => cmd.command === '/exit')) {
|
|
182
175
|
this.slashCommands.push({
|
|
183
176
|
command: '/exit',
|
|
184
177
|
description: 'Quit the CLI immediately',
|
|
185
|
-
category: 'other',
|
|
186
178
|
});
|
|
187
179
|
}
|
|
188
180
|
// Add /plugins command
|
|
189
181
|
this.slashCommands.push({
|
|
190
182
|
command: '/plugins',
|
|
191
183
|
description: 'Show available and loaded plugins',
|
|
192
|
-
category: 'configuration',
|
|
193
184
|
});
|
|
194
185
|
this.statusTracker = config.statusTracker;
|
|
195
186
|
this.ui = config.ui;
|
|
@@ -224,6 +215,9 @@ export class InteractiveShell {
|
|
|
224
215
|
});
|
|
225
216
|
// Register output interceptor for cursor positioning during streaming
|
|
226
217
|
this.terminalInput.registerOutputInterceptor(display);
|
|
218
|
+
// Use flow mode: input renders inline after content for a unified layout
|
|
219
|
+
// This eliminates the blank space between banner and input area
|
|
220
|
+
this.terminalInput.setFlowMode(true);
|
|
227
221
|
// Initialize Alpha Zero 2 metrics tracking
|
|
228
222
|
this.alphaZeroMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
|
|
229
223
|
this.setupStatusTracking();
|
|
@@ -281,24 +275,9 @@ export class InteractiveShell {
|
|
|
281
275
|
await this.processInputBlock(initialPrompt);
|
|
282
276
|
return;
|
|
283
277
|
}
|
|
284
|
-
this.showLaunchCommandPalette();
|
|
285
278
|
// Ensure the terminal input is visible
|
|
286
279
|
this.terminalInput.render();
|
|
287
280
|
}
|
|
288
|
-
showLaunchCommandPalette() {
|
|
289
|
-
if (this.launchPaletteShown) {
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
const palette = this.buildLaunchCommandPalette();
|
|
293
|
-
if (!palette.length) {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
display.showCommandPalette(palette, {
|
|
297
|
-
title: 'Quick commands',
|
|
298
|
-
intro: 'Describe a task or run a slash command to get started:',
|
|
299
|
-
});
|
|
300
|
-
this.launchPaletteShown = true;
|
|
301
|
-
}
|
|
302
281
|
/**
|
|
303
282
|
* TerminalInputAdapter submit handler
|
|
304
283
|
*/
|
|
@@ -312,8 +291,9 @@ export class InteractiveShell {
|
|
|
312
291
|
this.handleInputChange('');
|
|
313
292
|
return;
|
|
314
293
|
}
|
|
315
|
-
//
|
|
316
|
-
//
|
|
294
|
+
// Enter streaming mode BEFORE logging prompt - this positions cursor correctly
|
|
295
|
+
// so content appears right after the banner, not at bottom with blank space above
|
|
296
|
+
this.terminalInput.setStreaming(true);
|
|
317
297
|
this.logUserPrompt(approved);
|
|
318
298
|
void this.processInputBlock(approved).catch((err) => {
|
|
319
299
|
display.showError(err instanceof Error ? err.message : String(err), err);
|
|
@@ -515,9 +495,10 @@ export class InteractiveShell {
|
|
|
515
495
|
// Dispose unified UI adapter
|
|
516
496
|
this.uiAdapter.dispose();
|
|
517
497
|
display.newLine();
|
|
518
|
-
console.log(theme.
|
|
519
|
-
console.log(theme.
|
|
520
|
-
console.log(theme.ui.muted('
|
|
498
|
+
console.log(theme.gradient.warm('━'.repeat(50)));
|
|
499
|
+
console.log(` ${theme.gradient.cool('✨ Goodbye!')} ${theme.ui.muted('·')} ${theme.info('support@ero.solar')}`);
|
|
500
|
+
console.log(` ${theme.ui.muted('Read:')} ${theme.accent('anthropic.com/news/disrupting-AI-espionage')}`);
|
|
501
|
+
console.log(theme.gradient.warm('━'.repeat(50)));
|
|
521
502
|
exit(0);
|
|
522
503
|
}
|
|
523
504
|
/**
|
|
@@ -687,14 +668,13 @@ export class InteractiveShell {
|
|
|
687
668
|
});
|
|
688
669
|
}
|
|
689
670
|
setProcessingStatus(detail) {
|
|
690
|
-
this.latestTokenUsage = { used: null, limit: this.latestTokenUsage.limit };
|
|
691
671
|
this.statusTracker.setBase('Working on your request', {
|
|
692
672
|
detail: this.describeStatusDetail(detail),
|
|
693
673
|
tone: 'info',
|
|
694
674
|
});
|
|
695
675
|
}
|
|
696
676
|
describeStatusDetail(detail) {
|
|
697
|
-
const parts = detail?.trim()
|
|
677
|
+
const parts = [detail?.trim() || this.describeModelDetail()];
|
|
698
678
|
const queued = this.followUpQueue.length;
|
|
699
679
|
if (queued > 0) {
|
|
700
680
|
parts.push(`${queued} follow-up${queued === 1 ? '' : 's'} queued`);
|
|
@@ -707,18 +687,12 @@ export class InteractiveShell {
|
|
|
707
687
|
}
|
|
708
688
|
refreshContextGauge() {
|
|
709
689
|
const tokens = getContextWindowTokens(this.sessionState.model);
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
if (normalizedTokens !== null) {
|
|
713
|
-
this.latestTokenUsage = {
|
|
714
|
-
used: this.latestTokenUsage.used,
|
|
715
|
-
limit: normalizedTokens,
|
|
716
|
-
};
|
|
717
|
-
}
|
|
690
|
+
this.activeContextWindowTokens =
|
|
691
|
+
typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
|
|
718
692
|
}
|
|
719
693
|
updateContextUsage(percentage) {
|
|
720
694
|
this.uiAdapter.updateContextUsage(percentage);
|
|
721
|
-
this.terminalInput.setContextUsage(percentage
|
|
695
|
+
this.terminalInput.setContextUsage(percentage);
|
|
722
696
|
}
|
|
723
697
|
refreshControlBar() {
|
|
724
698
|
this.terminalInput.setModeToggles({
|
|
@@ -726,8 +700,6 @@ export class InteractiveShell {
|
|
|
726
700
|
autoContinueEnabled: this.autoContinueEnabled,
|
|
727
701
|
verificationHotkey: 'alt+v',
|
|
728
702
|
autoContinueHotkey: 'alt+c',
|
|
729
|
-
thinkingModeLabel: this.thinkingMode,
|
|
730
|
-
thinkingHotkey: '/thinking',
|
|
731
703
|
});
|
|
732
704
|
this.refreshStatusLine();
|
|
733
705
|
this.terminalInput.render();
|
|
@@ -759,25 +731,6 @@ export class InteractiveShell {
|
|
|
759
731
|
// Set main status (tool execution, etc.) - shown when not overridden
|
|
760
732
|
const statusText = this.formatStatusLine(this.statusLineState);
|
|
761
733
|
this.terminalInput.setStatusMessage(statusText);
|
|
762
|
-
// Surface meta header (elapsed + context usage) above the divider
|
|
763
|
-
const elapsedSeconds = this.statusLineState
|
|
764
|
-
? Math.max(0, Math.floor((Date.now() - this.statusLineState.startedAt) / 1000))
|
|
765
|
-
: null;
|
|
766
|
-
const thinkingMs = display.isSpinnerActive() ? display.getThinkingElapsedMs() : null;
|
|
767
|
-
const tokensUsed = this.latestTokenUsage.used;
|
|
768
|
-
const tokenLimit = this.latestTokenUsage.limit ?? this.activeContextWindowTokens;
|
|
769
|
-
this.terminalInput.setMetaStatus({
|
|
770
|
-
elapsedSeconds,
|
|
771
|
-
tokensUsed,
|
|
772
|
-
tokenLimit,
|
|
773
|
-
thinkingMs,
|
|
774
|
-
thinkingHasContent: display.isSpinnerActive(),
|
|
775
|
-
});
|
|
776
|
-
// Keep model/provider visible in the controls bar
|
|
777
|
-
this.terminalInput.setModelContext({
|
|
778
|
-
model: this.sessionState.model,
|
|
779
|
-
provider: this.providerLabel(this.sessionState.provider),
|
|
780
|
-
});
|
|
781
734
|
if (forceRender) {
|
|
782
735
|
this.terminalInput.render();
|
|
783
736
|
}
|
|
@@ -837,11 +790,13 @@ export class InteractiveShell {
|
|
|
837
790
|
this.terminalInput.render();
|
|
838
791
|
}
|
|
839
792
|
/**
|
|
840
|
-
*
|
|
841
|
-
*
|
|
793
|
+
* Log the user's prompt as a visible message in the conversation.
|
|
794
|
+
* This creates a persistent log entry that remains visible during and after streaming.
|
|
842
795
|
*/
|
|
843
|
-
logUserPrompt(
|
|
844
|
-
//
|
|
796
|
+
logUserPrompt(text) {
|
|
797
|
+
// Display the user's prompt with the standard prefix
|
|
798
|
+
const prefix = formatUserPrompt();
|
|
799
|
+
display.stream(`\n${prefix}${text}\n\n`);
|
|
845
800
|
}
|
|
846
801
|
requestPromptRefresh(force = false) {
|
|
847
802
|
if (force) {
|
|
@@ -869,29 +824,9 @@ export class InteractiveShell {
|
|
|
869
824
|
this.uiUpdates.setMode('streaming');
|
|
870
825
|
this.streamingHeartbeatStart = Date.now();
|
|
871
826
|
this.streamingHeartbeatFrame = 0;
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
this.refreshStatusLine(true);
|
|
876
|
-
// Periodically refresh the pinned input/status region while streaming so
|
|
877
|
-
// elapsed time remains visible without interrupting the scroll region.
|
|
878
|
-
this.uiUpdates.startHeartbeat('streaming', {
|
|
879
|
-
intervalMs: 1000,
|
|
880
|
-
lane: 'heartbeat',
|
|
881
|
-
mode: ['streaming', 'processing'],
|
|
882
|
-
coalesceKey: 'streaming:heartbeat',
|
|
883
|
-
run: () => {
|
|
884
|
-
const elapsedSeconds = this.streamingHeartbeatStart
|
|
885
|
-
? Math.max(0, Math.floor((Date.now() - this.streamingHeartbeatStart) / 1000))
|
|
886
|
-
: 0;
|
|
887
|
-
this.streamingHeartbeatFrame =
|
|
888
|
-
(this.streamingHeartbeatFrame + 1) % STREAMING_SPINNER_FRAMES.length;
|
|
889
|
-
const frame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
|
|
890
|
-
this.streamingStatusLabel = this.buildStreamingStatus(`${frame} ${label}`, elapsedSeconds);
|
|
891
|
-
display.updateStreamingStatus(this.streamingStatusLabel);
|
|
892
|
-
this.refreshStatusLine(true);
|
|
893
|
-
},
|
|
894
|
-
});
|
|
827
|
+
// Note: We don't start a heartbeat during streaming anymore
|
|
828
|
+
// because the UI shouldn't be rendering during streaming.
|
|
829
|
+
// The streaming status is shown in the streaming header instead.
|
|
895
830
|
}
|
|
896
831
|
stopStreamingHeartbeat() {
|
|
897
832
|
// Exit global streaming mode - allows UI to render again
|
|
@@ -907,28 +842,10 @@ export class InteractiveShell {
|
|
|
907
842
|
// Force refresh to update the input area now that streaming has ended
|
|
908
843
|
this.refreshStatusLine(true);
|
|
909
844
|
}
|
|
910
|
-
buildStreamingStatus(label
|
|
845
|
+
buildStreamingStatus(label) {
|
|
911
846
|
const detail = this.describeModelDetail();
|
|
912
|
-
const
|
|
913
|
-
|
|
914
|
-
: null;
|
|
915
|
-
const prefix = theme.info('⏺');
|
|
916
|
-
const parts = [label];
|
|
917
|
-
if (detail) {
|
|
918
|
-
parts.push(theme.ui.muted('·'), detail);
|
|
919
|
-
}
|
|
920
|
-
if (elapsedLabel) {
|
|
921
|
-
parts.push(theme.ui.muted('·'), elapsedLabel);
|
|
922
|
-
}
|
|
923
|
-
return `${prefix} ${parts.join(' ')}`.trim();
|
|
924
|
-
}
|
|
925
|
-
formatElapsedShort(seconds) {
|
|
926
|
-
if (seconds < 60) {
|
|
927
|
-
return `${seconds}s`;
|
|
928
|
-
}
|
|
929
|
-
const minutes = Math.floor(seconds / 60);
|
|
930
|
-
const remaining = seconds % 60;
|
|
931
|
-
return remaining > 0 ? `${minutes}m ${remaining}s` : `${minutes}m`;
|
|
847
|
+
const prefix = theme.info('●');
|
|
848
|
+
return detail ? `${prefix} ${label} ${theme.ui.muted('·')} ${detail}` : `${prefix} ${label}`;
|
|
932
849
|
}
|
|
933
850
|
refreshQueueIndicators() {
|
|
934
851
|
if (this.isProcessing) {
|
|
@@ -1822,75 +1739,6 @@ export class InteractiveShell {
|
|
|
1822
1739
|
}
|
|
1823
1740
|
return `${warning.label}: ${warning.reason}.`;
|
|
1824
1741
|
}
|
|
1825
|
-
buildLaunchCommandPalette() {
|
|
1826
|
-
const entries = [];
|
|
1827
|
-
const secretsSummary = this.summarizeSecretsForPalette();
|
|
1828
|
-
const toolSummary = this.getToolSelectionSummary();
|
|
1829
|
-
const autosaveLabel = this.autosaveEnabled ? 'on' : 'off';
|
|
1830
|
-
for (const command of this.slashCommands) {
|
|
1831
|
-
const entry = {
|
|
1832
|
-
command: command.command,
|
|
1833
|
-
description: command.description,
|
|
1834
|
-
category: command.category ?? 'other',
|
|
1835
|
-
};
|
|
1836
|
-
switch (command.command) {
|
|
1837
|
-
case '/secrets':
|
|
1838
|
-
if (secretsSummary.text) {
|
|
1839
|
-
entry.description = `${command.description} (${secretsSummary.text})`;
|
|
1840
|
-
entry.tone = secretsSummary.tone;
|
|
1841
|
-
}
|
|
1842
|
-
break;
|
|
1843
|
-
case '/tools':
|
|
1844
|
-
if (toolSummary) {
|
|
1845
|
-
entry.description = `${command.description} (${toolSummary})`;
|
|
1846
|
-
}
|
|
1847
|
-
break;
|
|
1848
|
-
case '/sessions':
|
|
1849
|
-
entry.description = `${command.description} (autosave ${autosaveLabel})`;
|
|
1850
|
-
break;
|
|
1851
|
-
case '/model':
|
|
1852
|
-
entry.description = `${command.description} (current: ${this.sessionState.model})`;
|
|
1853
|
-
break;
|
|
1854
|
-
case '/provider':
|
|
1855
|
-
entry.description = `${command.description} (current: ${this.providerLabel(this.sessionState.provider)})`;
|
|
1856
|
-
break;
|
|
1857
|
-
default:
|
|
1858
|
-
break;
|
|
1859
|
-
}
|
|
1860
|
-
entries.push(entry);
|
|
1861
|
-
}
|
|
1862
|
-
return entries;
|
|
1863
|
-
}
|
|
1864
|
-
summarizeSecretsForPalette() {
|
|
1865
|
-
const definitions = listSecretDefinitions();
|
|
1866
|
-
if (!definitions.length) {
|
|
1867
|
-
return { text: null };
|
|
1868
|
-
}
|
|
1869
|
-
const missing = definitions.filter((definition) => !getSecretValue(definition.id));
|
|
1870
|
-
if (missing.length === 0) {
|
|
1871
|
-
return { text: 'all configured', tone: 'success' };
|
|
1872
|
-
}
|
|
1873
|
-
const labels = missing.map((definition) => definition.label ?? definition.id);
|
|
1874
|
-
return { text: `missing ${this.formatList(labels)}`, tone: 'warn' };
|
|
1875
|
-
}
|
|
1876
|
-
getToolSelectionSummary() {
|
|
1877
|
-
const toolSettings = loadToolSettings();
|
|
1878
|
-
const selection = buildEnabledToolSet(toolSettings);
|
|
1879
|
-
const options = getToolToggleOptions();
|
|
1880
|
-
if (!options.length) {
|
|
1881
|
-
return null;
|
|
1882
|
-
}
|
|
1883
|
-
const enabledCount = options.filter((option) => selection.has(option.id)).length;
|
|
1884
|
-
return `${enabledCount}/${options.length} enabled`;
|
|
1885
|
-
}
|
|
1886
|
-
formatList(values, maxItems = 3) {
|
|
1887
|
-
if (!values.length) {
|
|
1888
|
-
return '';
|
|
1889
|
-
}
|
|
1890
|
-
const shown = values.slice(0, maxItems);
|
|
1891
|
-
const suffix = values.length > maxItems ? ', …' : '';
|
|
1892
|
-
return `${shown.join(', ')}${suffix}`;
|
|
1893
|
-
}
|
|
1894
1742
|
buildSlashCommandList(header) {
|
|
1895
1743
|
const lines = [theme.gradient.primary(header), ''];
|
|
1896
1744
|
for (const command of this.slashCommands) {
|
|
@@ -2381,6 +2229,9 @@ export class InteractiveShell {
|
|
|
2381
2229
|
this.setIdleStatus();
|
|
2382
2230
|
display.newLine();
|
|
2383
2231
|
this.updateStatusMessage(null);
|
|
2232
|
+
// Claude Code style: Show unified status bar before prompt
|
|
2233
|
+
// This creates consistent UI between startup and post-streaming
|
|
2234
|
+
this.showUnifiedStatusBar();
|
|
2384
2235
|
queueMicrotask(() => this.uiUpdates.setMode('idle'));
|
|
2385
2236
|
// CRITICAL: Ensure readline prompt is active for user input
|
|
2386
2237
|
// Claude Code style: New prompt naturally appears at bottom
|
|
@@ -2457,7 +2308,6 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
|
|
|
2457
2308
|
try {
|
|
2458
2309
|
// Send the request and capture the response (streaming disabled)
|
|
2459
2310
|
display.showThinking('Responding...');
|
|
2460
|
-
this.refreshStatusLine(true);
|
|
2461
2311
|
const response = await agent.send(currentPrompt, true);
|
|
2462
2312
|
await this.awaitPendingCleanup();
|
|
2463
2313
|
this.captureHistorySnapshot();
|
|
@@ -2957,10 +2807,8 @@ What's the next action?`;
|
|
|
2957
2807
|
try {
|
|
2958
2808
|
// Send the error to the agent for fixing
|
|
2959
2809
|
display.showThinking('Analyzing build errors');
|
|
2960
|
-
this.refreshStatusLine(true);
|
|
2961
2810
|
const response = await this.agent.send(prompt, true);
|
|
2962
2811
|
display.stopThinking();
|
|
2963
|
-
this.refreshStatusLine(true);
|
|
2964
2812
|
if (response) {
|
|
2965
2813
|
display.showAssistantMessage(response, { isFinal: true });
|
|
2966
2814
|
}
|
|
@@ -3010,16 +2858,18 @@ What's the next action?`;
|
|
|
3010
2858
|
display.showAssistantMessage(finalContent, enriched);
|
|
3011
2859
|
}
|
|
3012
2860
|
}
|
|
3013
|
-
//
|
|
2861
|
+
// Show status line at end (Claude Code style: "• Context X% used • Ready for prompts (2s)")
|
|
3014
2862
|
display.stopThinking();
|
|
3015
|
-
//
|
|
2863
|
+
// Calculate context usage
|
|
2864
|
+
let contextInfo;
|
|
3016
2865
|
if (enriched.contextWindowTokens && metadata.usage) {
|
|
3017
2866
|
const total = this.totalTokens(metadata.usage);
|
|
3018
2867
|
if (total && total > 0) {
|
|
3019
2868
|
const percentage = Math.round((total / enriched.contextWindowTokens) * 100);
|
|
3020
|
-
|
|
2869
|
+
contextInfo = { percentage, tokens: total };
|
|
3021
2870
|
}
|
|
3022
2871
|
}
|
|
2872
|
+
display.showStatusLine('Ready for prompts', enriched.elapsedMs, contextInfo);
|
|
3023
2873
|
// Auto-verify changes: build first (catches type errors), then tests
|
|
3024
2874
|
void this.enforceAutoBuild('final-response');
|
|
3025
2875
|
void this.enforceAutoTests('final-response');
|
|
@@ -3189,14 +3039,9 @@ What's the next action?`;
|
|
|
3189
3039
|
return null;
|
|
3190
3040
|
}
|
|
3191
3041
|
const usageRatio = total / windowTokens;
|
|
3192
|
-
this.latestTokenUsage = {
|
|
3193
|
-
used: total,
|
|
3194
|
-
limit: windowTokens,
|
|
3195
|
-
};
|
|
3196
3042
|
// Always update context usage in the UI
|
|
3197
3043
|
const percentUsed = Math.round(usageRatio * 100);
|
|
3198
3044
|
this.updateContextUsage(percentUsed);
|
|
3199
|
-
this.refreshStatusLine(true);
|
|
3200
3045
|
if (usageRatio < CONTEXT_USAGE_THRESHOLD) {
|
|
3201
3046
|
return null;
|
|
3202
3047
|
}
|