erosolar-cli 1.7.409 → 1.7.411
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 +6 -6
- package/dist/StringUtils.d.ts +1 -4
- package/dist/StringUtils.d.ts.map +1 -1
- package/dist/StringUtils.js +2 -8
- package/dist/StringUtils.js.map +1 -1
- package/dist/browser/BrowserSessionManager.d.ts +1 -3
- package/dist/browser/BrowserSessionManager.d.ts.map +1 -1
- package/dist/browser/BrowserSessionManager.js +4 -24
- package/dist/browser/BrowserSessionManager.js.map +1 -1
- package/dist/capabilities/toolRegistry.d.ts +2 -0
- package/dist/capabilities/toolRegistry.d.ts.map +1 -1
- package/dist/capabilities/toolRegistry.js +40 -5
- package/dist/capabilities/toolRegistry.js.map +1 -1
- package/dist/contracts/agent-profiles.schema.json +5 -5
- package/dist/contracts/agent-schemas.json +6 -16
- package/dist/contracts/schemas/agent.schema.json +1 -5
- package/dist/contracts/schemas/tool-selection.schema.json +1 -7
- package/dist/contracts/tools.schema.json +80 -207
- package/dist/contracts/unified-schema.json +4 -5
- package/dist/contracts/v1/agent.d.ts +0 -3
- package/dist/contracts/v1/agent.d.ts.map +1 -1
- package/dist/contracts/v1/provider.d.ts +1 -2
- package/dist/contracts/v1/provider.d.ts.map +1 -1
- package/dist/contracts/v1/toolAccess.d.ts +1 -1
- package/dist/contracts/v1/toolAccess.d.ts.map +1 -1
- package/dist/core/agent.d.ts +1 -7
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +2 -131
- package/dist/core/agent.js.map +1 -1
- package/dist/core/alphaZeroEngine.d.ts +0 -8
- package/dist/core/alphaZeroEngine.d.ts.map +1 -1
- package/dist/core/alphaZeroEngine.js +35 -149
- package/dist/core/alphaZeroEngine.js.map +1 -1
- package/dist/core/alphaZeroOrchestrator.d.ts +0 -17
- package/dist/core/alphaZeroOrchestrator.d.ts.map +1 -1
- package/dist/core/alphaZeroOrchestrator.js +8 -95
- package/dist/core/alphaZeroOrchestrator.js.map +1 -1
- package/dist/core/cliTestHarness.d.ts +0 -5
- package/dist/core/cliTestHarness.d.ts.map +1 -1
- package/dist/core/cliTestHarness.js +3 -14
- package/dist/core/cliTestHarness.js.map +1 -1
- package/dist/core/contextManager.d.ts +0 -30
- package/dist/core/contextManager.d.ts.map +1 -1
- package/dist/core/contextManager.js +5 -87
- package/dist/core/contextManager.js.map +1 -1
- package/dist/core/contextWindow.d.ts +4 -4
- package/dist/core/contextWindow.js +9 -9
- package/dist/core/contextWindow.js.map +1 -1
- package/dist/core/modelDiscovery.js +3 -3
- package/dist/core/modelDiscovery.js.map +1 -1
- package/dist/core/preferences.d.ts +2 -3
- package/dist/core/preferences.d.ts.map +1 -1
- package/dist/core/preferences.js +11 -18
- package/dist/core/preferences.js.map +1 -1
- package/dist/core/secretStore.d.ts.map +1 -1
- package/dist/core/secretStore.js +31 -0
- package/dist/core/secretStore.js.map +1 -1
- package/dist/core/toolPreconditions.d.ts.map +1 -1
- package/dist/core/toolPreconditions.js +0 -60
- package/dist/core/toolPreconditions.js.map +1 -1
- package/dist/core/toolRuntime.d.ts.map +1 -1
- package/dist/core/toolRuntime.js +0 -17
- package/dist/core/toolRuntime.js.map +1 -1
- package/dist/core/types.d.ts +1 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/plugins/providers/google/index.js +3 -2
- package/dist/plugins/providers/google/index.js.map +1 -1
- package/dist/providers/openaiChatCompletionsProvider.d.ts.map +1 -1
- package/dist/providers/openaiChatCompletionsProvider.js +6 -60
- package/dist/providers/openaiChatCompletionsProvider.js.map +1 -1
- package/dist/runtime/agentController.d.ts.map +1 -1
- package/dist/runtime/agentController.js +6 -27
- package/dist/runtime/agentController.js.map +1 -1
- package/dist/shell/interactiveShell.d.ts +30 -79
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +726 -1519
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/shellApp.d.ts.map +1 -1
- package/dist/shell/shellApp.js +41 -15
- 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 +21 -85
- package/dist/shell/terminalInput.d.ts.map +1 -1
- package/dist/shell/terminalInput.js +60 -517
- package/dist/shell/terminalInput.js.map +1 -1
- package/dist/shell/terminalInputAdapter.d.ts +16 -37
- package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
- package/dist/shell/terminalInputAdapter.js +22 -44
- package/dist/shell/terminalInputAdapter.js.map +1 -1
- package/dist/shell/updateManager.d.ts +1 -8
- package/dist/shell/updateManager.d.ts.map +1 -1
- package/dist/shell/updateManager.js +14 -9
- package/dist/shell/updateManager.js.map +1 -1
- package/dist/subagents/parallelAgentManager.d.ts.map +1 -1
- package/dist/subagents/parallelAgentManager.js +2 -1
- package/dist/subagents/parallelAgentManager.js.map +1 -1
- package/dist/tools/buildTools.d.ts.map +1 -1
- package/dist/tools/buildTools.js +76 -19
- package/dist/tools/buildTools.js.map +1 -1
- package/dist/tools/editTools.js +1 -1
- package/dist/tools/editTools.js.map +1 -1
- package/dist/tools/enhancedCodeIntelligenceTools.js +2 -1
- package/dist/tools/enhancedCodeIntelligenceTools.js.map +1 -1
- package/dist/tools/fileTools.js +0 -3
- package/dist/tools/fileTools.js.map +1 -1
- package/dist/tools/frontendTestingTools.js +1 -1
- package/dist/tools/frontendTestingTools.js.map +1 -1
- package/dist/tools/learnTools.d.ts +0 -2
- package/dist/tools/learnTools.d.ts.map +1 -1
- package/dist/tools/learnTools.js +81 -29
- package/dist/tools/learnTools.js.map +1 -1
- package/dist/tools/localExplore.d.ts.map +1 -1
- package/dist/tools/localExplore.js +1 -0
- package/dist/tools/localExplore.js.map +1 -1
- package/dist/tools/notebookEditTools.js.map +1 -1
- package/dist/tools/repoChecksTools.js +3 -4
- package/dist/tools/repoChecksTools.js.map +1 -1
- package/dist/tools/searchTools.js +0 -4
- package/dist/tools/searchTools.js.map +1 -1
- package/dist/tools/softwareEngineeringTools.d.ts.map +1 -1
- package/dist/tools/softwareEngineeringTools.js +0 -1
- package/dist/tools/softwareEngineeringTools.js.map +1 -1
- package/dist/tools/webTools.d.ts.map +1 -1
- package/dist/tools/webTools.js.map +1 -1
- package/dist/ui/ShellUIAdapter.d.ts +16 -44
- package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
- package/dist/ui/ShellUIAdapter.js +84 -337
- package/dist/ui/ShellUIAdapter.js.map +1 -1
- package/dist/ui/display.d.ts +37 -18
- package/dist/ui/display.d.ts.map +1 -1
- package/dist/ui/display.js +310 -95
- package/dist/ui/display.js.map +1 -1
- package/dist/ui/orchestration/UIUpdateCoordinator.d.ts.map +1 -1
- package/dist/ui/orchestration/UIUpdateCoordinator.js +3 -5
- package/dist/ui/orchestration/UIUpdateCoordinator.js.map +1 -1
- package/dist/ui/shortcutsHelp.d.ts +11 -1
- package/dist/ui/shortcutsHelp.d.ts.map +1 -1
- package/dist/ui/shortcutsHelp.js +54 -8
- package/dist/ui/shortcutsHelp.js.map +1 -1
- package/dist/ui/streamingFormatter.d.ts +16 -0
- package/dist/ui/streamingFormatter.d.ts.map +1 -0
- package/dist/ui/streamingFormatter.js +62 -0
- package/dist/ui/streamingFormatter.js.map +1 -0
- package/dist/ui/theme.d.ts +100 -100
- package/dist/ui/theme.d.ts.map +1 -1
- package/dist/ui/theme.js.map +1 -1
- package/dist/ui/toolDisplay.d.ts +3 -3
- package/dist/ui/toolDisplay.d.ts.map +1 -1
- package/dist/ui/toolDisplay.js +8 -7
- package/dist/ui/toolDisplay.js.map +1 -1
- package/dist/ui/unified/index.d.ts +2 -2
- package/dist/ui/unified/index.d.ts.map +1 -1
- package/dist/ui/unified/index.js.map +1 -1
- package/dist/ui/unified/layout.d.ts +23 -0
- package/dist/ui/unified/layout.d.ts.map +1 -1
- package/dist/ui/unified/layout.js +113 -11
- package/dist/ui/unified/layout.js.map +1 -1
- package/package.json +24 -37
- package/dist/core/alphaZeroConfig.d.ts +0 -11
- package/dist/core/alphaZeroConfig.d.ts.map +0 -1
- package/dist/core/alphaZeroConfig.js +0 -59
- package/dist/core/alphaZeroConfig.js.map +0 -1
- package/dist/core/alphaZeroEnhanced.d.ts +0 -125
- package/dist/core/alphaZeroEnhanced.d.ts.map +0 -1
- package/dist/core/alphaZeroEnhanced.js +0 -386
- package/dist/core/alphaZeroEnhanced.js.map +0 -1
- package/dist/core/autonomousVerification.d.ts +0 -103
- package/dist/core/autonomousVerification.d.ts.map +0 -1
- package/dist/core/autonomousVerification.js +0 -583
- package/dist/core/autonomousVerification.js.map +0 -1
- package/dist/core/offsecAlphaZeroEnhanced.d.ts +0 -98
- package/dist/core/offsecAlphaZeroEnhanced.d.ts.map +0 -1
- package/dist/core/offsecAlphaZeroEnhanced.js +0 -441
- package/dist/core/offsecAlphaZeroEnhanced.js.map +0 -1
- package/dist/core/parallelAgentOrchestrator.d.ts +0 -171
- package/dist/core/parallelAgentOrchestrator.d.ts.map +0 -1
- package/dist/core/parallelAgentOrchestrator.js +0 -459
- package/dist/core/parallelAgentOrchestrator.js.map +0 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -3
- package/dist/index.js.map +0 -1
- package/dist/tools/detectCommands.d.ts +0 -8
- package/dist/tools/detectCommands.d.ts.map +0 -1
- package/dist/tools/detectCommands.js +0 -183
- package/dist/tools/detectCommands.js.map +0 -1
- package/dist/ui/assistantBlockRenderer.d.ts +0 -30
- package/dist/ui/assistantBlockRenderer.d.ts.map +0 -1
- package/dist/ui/assistantBlockRenderer.js +0 -121
- package/dist/ui/assistantBlockRenderer.js.map +0 -1
package/dist/ui/display.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { createSpinner } from 'nanospinner';
|
|
2
2
|
import { clearScreenDown, cursorTo } from 'node:readline';
|
|
3
3
|
import { theme, icons } from './theme.js';
|
|
4
|
+
import { formatRichContent, renderMessagePanel, renderMessageBody } from './richText.js';
|
|
4
5
|
import { getTerminalColumns } from './layout.js';
|
|
5
6
|
import { highlightError } from './textHighlighter.js';
|
|
6
7
|
import { renderSectionHeading } from './designSystem.js';
|
|
8
|
+
import { isPlainOutputMode } from './outputMode.js';
|
|
7
9
|
import { writeLock } from './writeLock.js';
|
|
8
10
|
import { renderStatusLine } from './unified/layout.js';
|
|
9
11
|
import { isStreamingMode } from './globalWriteLock.js';
|
|
@@ -147,8 +149,11 @@ const DISPLAY_CONSTANTS = {
|
|
|
147
149
|
MIN_MESSAGE_WIDTH: 42,
|
|
148
150
|
MAX_MESSAGE_WIDTH: 110,
|
|
149
151
|
MESSAGE_PADDING: 4,
|
|
152
|
+
MIN_ACTION_WIDTH: 40,
|
|
153
|
+
MAX_ACTION_WIDTH: 90,
|
|
150
154
|
MIN_THOUGHT_WIDTH: 48,
|
|
151
155
|
MAX_THOUGHT_WIDTH: 96,
|
|
156
|
+
MIN_CONTENT_WIDTH: 10,
|
|
152
157
|
MIN_WRAP_WIDTH: 12,
|
|
153
158
|
SPINNER_INTERVAL: 80,
|
|
154
159
|
};
|
|
@@ -195,8 +200,6 @@ export class Display {
|
|
|
195
200
|
thinkingElapsedTimer = null;
|
|
196
201
|
thinkingBaseMessage = 'Thinking...';
|
|
197
202
|
pendingCarriageReturn = false;
|
|
198
|
-
captureStack = [];
|
|
199
|
-
mutedOutput = false;
|
|
200
203
|
// Streaming status line (Claude Code style - fixed at bottom using scroll region)
|
|
201
204
|
streamingStatusVisible = false;
|
|
202
205
|
scrollRegionActive = false;
|
|
@@ -259,68 +262,10 @@ export class Display {
|
|
|
259
262
|
interceptors[index]?.afterWrite?.(content);
|
|
260
263
|
}
|
|
261
264
|
}
|
|
262
|
-
/**
|
|
263
|
-
* Capture all display output emitted during the provided function while optionally
|
|
264
|
-
* silencing writes to the terminal. Supports nesting by appending captured output
|
|
265
|
-
* to the parent buffer when present.
|
|
266
|
-
*/
|
|
267
|
-
async captureOutput(fn, options = {}) {
|
|
268
|
-
const scope = {
|
|
269
|
-
buffer: [],
|
|
270
|
-
includeStreaming: options.includeStreaming ?? true,
|
|
271
|
-
suppressTypes: new Set(options.suppressTypes ?? []),
|
|
272
|
-
};
|
|
273
|
-
this.captureStack.push(scope);
|
|
274
|
-
let output = '';
|
|
275
|
-
const previousMute = this.mutedOutput;
|
|
276
|
-
if (options.silenceOutput) {
|
|
277
|
-
this.mutedOutput = true;
|
|
278
|
-
}
|
|
279
|
-
try {
|
|
280
|
-
const result = await fn();
|
|
281
|
-
output = scope.buffer.join('');
|
|
282
|
-
return { output, result };
|
|
283
|
-
}
|
|
284
|
-
catch (error) {
|
|
285
|
-
output = scope.buffer.join('');
|
|
286
|
-
if (error && typeof error === 'object') {
|
|
287
|
-
error.capturedOutput = output;
|
|
288
|
-
}
|
|
289
|
-
throw error;
|
|
290
|
-
}
|
|
291
|
-
finally {
|
|
292
|
-
this.captureStack.pop();
|
|
293
|
-
this.mutedOutput = previousMute;
|
|
294
|
-
if (output && this.captureStack.length > 0) {
|
|
295
|
-
this.captureStack[this.captureStack.length - 1].buffer.push(output);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
appendToCapture(content, type) {
|
|
300
|
-
if (!content || this.captureStack.length === 0) {
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
for (const scope of this.captureStack) {
|
|
304
|
-
if (type === 'stream' && !scope.includeStreaming) {
|
|
305
|
-
continue;
|
|
306
|
-
}
|
|
307
|
-
scope.buffer.push(content);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
shouldSuppressOutput(type) {
|
|
311
|
-
if (this.mutedOutput) {
|
|
312
|
-
return true;
|
|
313
|
-
}
|
|
314
|
-
return this.captureStack.some((scope) => scope.suppressTypes.has(type));
|
|
315
|
-
}
|
|
316
265
|
write(value, target = this.outputStream) {
|
|
317
266
|
// Write directly - this method is called from within locked contexts
|
|
318
267
|
// like withOutput(), so we don't need additional locking here.
|
|
319
268
|
// The globalWriteLock wrapper will handle coordination if needed.
|
|
320
|
-
this.appendToCapture(value, 'normal');
|
|
321
|
-
if (this.shouldSuppressOutput('normal')) {
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
269
|
try {
|
|
325
270
|
target.write(value);
|
|
326
271
|
}
|
|
@@ -347,24 +292,33 @@ export class Display {
|
|
|
347
292
|
if (!normalized) {
|
|
348
293
|
return;
|
|
349
294
|
}
|
|
350
|
-
|
|
351
|
-
|
|
295
|
+
// During streaming, use withLock to prevent interleaving with escape codes.
|
|
296
|
+
// This ensures the before/write/after sequence is atomic.
|
|
297
|
+
if (isStreamingMode()) {
|
|
298
|
+
writeLock.withLock(() => {
|
|
299
|
+
this.notifyBeforeOutput();
|
|
300
|
+
try {
|
|
301
|
+
this.outputStream.write(normalized);
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
// Ignore write failures to keep UI resilient
|
|
305
|
+
}
|
|
306
|
+
finally {
|
|
307
|
+
this.notifyAfterOutput(normalized);
|
|
308
|
+
}
|
|
309
|
+
}, 'display.writeRaw.streaming');
|
|
352
310
|
return;
|
|
353
311
|
}
|
|
354
|
-
|
|
312
|
+
// Outside streaming mode, use locks to coordinate with other UI
|
|
313
|
+
writeLock.withLock(() => {
|
|
355
314
|
this.notifyBeforeOutput();
|
|
356
315
|
try {
|
|
357
|
-
this.
|
|
358
|
-
}
|
|
359
|
-
catch {
|
|
360
|
-
// Ignore write failures to keep UI resilient
|
|
316
|
+
this.write(normalized);
|
|
361
317
|
}
|
|
362
318
|
finally {
|
|
363
319
|
this.notifyAfterOutput(normalized);
|
|
364
320
|
}
|
|
365
|
-
};
|
|
366
|
-
// Use locks in both streaming and non-streaming modes to keep output atomic
|
|
367
|
-
writeLock.withLock(writeStreamChunk, isStreamingMode() ? 'display.writeRaw.streaming' : 'display.writeRaw');
|
|
321
|
+
}, 'display.writeRaw');
|
|
368
322
|
}
|
|
369
323
|
/**
|
|
370
324
|
* Normalize streaming chunks so progress-style carriage returns render cleanly.
|
|
@@ -455,9 +409,6 @@ export class Display {
|
|
|
455
409
|
}
|
|
456
410
|
// Banner is now streamed by the shell - no storage needed
|
|
457
411
|
showThinking(message = 'Thinking…') {
|
|
458
|
-
if (this.shouldSuppressOutput('normal')) {
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
412
|
// If we already have a spinner, just update its text instead of creating a new one
|
|
462
413
|
if (this.activeSpinner) {
|
|
463
414
|
this.thinkingBaseMessage = message;
|
|
@@ -558,9 +509,6 @@ export class Display {
|
|
|
558
509
|
* This allows content to scroll while status stays fixed.
|
|
559
510
|
*/
|
|
560
511
|
setupScrollRegion() {
|
|
561
|
-
if (this.shouldSuppressOutput('normal')) {
|
|
562
|
-
return;
|
|
563
|
-
}
|
|
564
512
|
if (this.scrollRegionActive || !this.isTTY()) {
|
|
565
513
|
return;
|
|
566
514
|
}
|
|
@@ -577,9 +525,6 @@ export class Display {
|
|
|
577
525
|
* Tear down scroll region and restore normal terminal.
|
|
578
526
|
*/
|
|
579
527
|
teardownScrollRegion() {
|
|
580
|
-
if (this.shouldSuppressOutput('normal')) {
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
528
|
if (!this.scrollRegionActive) {
|
|
584
529
|
return;
|
|
585
530
|
}
|
|
@@ -683,43 +628,134 @@ export class Display {
|
|
|
683
628
|
});
|
|
684
629
|
}
|
|
685
630
|
}
|
|
686
|
-
|
|
631
|
+
showAssistantMessage(content, metadata) {
|
|
632
|
+
if (!content.trim()) {
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
687
635
|
this.clearSpinnerIfActive();
|
|
636
|
+
const isThought = metadata?.isFinal === false;
|
|
637
|
+
const body = isThought ? this.buildClaudeStyleThought(content) : this.buildChatBox(content, metadata);
|
|
638
|
+
if (!body.trim()) {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
688
641
|
this.withOutput(() => {
|
|
689
|
-
this.writeLine(
|
|
642
|
+
this.writeLine(); // Ensure clean start for the box
|
|
643
|
+
this.writeLine(body);
|
|
690
644
|
this.writeLine();
|
|
691
645
|
});
|
|
692
646
|
}
|
|
693
|
-
|
|
647
|
+
showNarrative(content) {
|
|
648
|
+
if (!content.trim()) {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
this.showAssistantMessage(content, { isFinal: false });
|
|
652
|
+
}
|
|
653
|
+
showAction(text, status = 'info') {
|
|
654
|
+
if (!text.trim()) {
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
694
657
|
this.clearSpinnerIfActive();
|
|
695
|
-
|
|
658
|
+
// Claude Code style: always use ⏺ prefix for actions
|
|
659
|
+
const icon = this.formatActionIcon(status);
|
|
696
660
|
this.withOutput(() => {
|
|
697
|
-
this.writeLine(
|
|
698
|
-
if (details) {
|
|
699
|
-
this.writeLine(` ${details}`, this.errorStream);
|
|
700
|
-
}
|
|
661
|
+
this.writeLine(this.wrapWithPrefix(text, `${icon} `));
|
|
701
662
|
});
|
|
702
663
|
}
|
|
703
|
-
|
|
664
|
+
showSubAction(text, status = 'info') {
|
|
665
|
+
if (!text.trim()) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
704
668
|
this.clearSpinnerIfActive();
|
|
669
|
+
const prefersRich = text.includes('```');
|
|
670
|
+
let rendered = prefersRich ? this.buildRichSubActionLines(text, status) : this.buildWrappedSubActionLines(text, status);
|
|
671
|
+
if (!rendered.length && prefersRich) {
|
|
672
|
+
rendered = this.buildWrappedSubActionLines(text, status);
|
|
673
|
+
}
|
|
674
|
+
if (!rendered.length) {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
705
677
|
this.withOutput(() => {
|
|
706
|
-
this.writeLine(
|
|
678
|
+
this.writeLine(rendered.join('\n'));
|
|
679
|
+
this.writeLine();
|
|
707
680
|
});
|
|
708
681
|
}
|
|
682
|
+
buildWrappedSubActionLines(text, status) {
|
|
683
|
+
const lines = text.split('\n').map((line) => line.trimEnd());
|
|
684
|
+
while (lines.length && !lines[lines.length - 1]?.trim()) {
|
|
685
|
+
lines.pop();
|
|
686
|
+
}
|
|
687
|
+
if (!lines.length) {
|
|
688
|
+
return [];
|
|
689
|
+
}
|
|
690
|
+
const rendered = [];
|
|
691
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
692
|
+
const segment = lines[index] ?? '';
|
|
693
|
+
const isLast = index === lines.length - 1;
|
|
694
|
+
const { prefix, continuation } = this.buildSubActionPrefixes(status, isLast);
|
|
695
|
+
rendered.push(this.wrapWithPrefix(segment, prefix, { continuationPrefix: continuation }));
|
|
696
|
+
}
|
|
697
|
+
return rendered;
|
|
698
|
+
}
|
|
699
|
+
buildRichSubActionLines(text, status) {
|
|
700
|
+
const normalized = text.trim();
|
|
701
|
+
if (!normalized) {
|
|
702
|
+
return [];
|
|
703
|
+
}
|
|
704
|
+
const width = Math.max(DISPLAY_CONSTANTS.MIN_ACTION_WIDTH, Math.min(this.getColumnWidth(), DISPLAY_CONSTANTS.MAX_ACTION_WIDTH));
|
|
705
|
+
const samplePrefix = this.buildSubActionPrefixes(status, true).prefix;
|
|
706
|
+
const contentWidth = Math.max(DISPLAY_CONSTANTS.MIN_CONTENT_WIDTH, width - this.visibleLength(samplePrefix));
|
|
707
|
+
const blocks = formatRichContent(normalized, contentWidth);
|
|
708
|
+
if (!blocks.length) {
|
|
709
|
+
return [];
|
|
710
|
+
}
|
|
711
|
+
return blocks.map((line, index) => {
|
|
712
|
+
const isLast = index === blocks.length - 1;
|
|
713
|
+
const { prefix } = this.buildSubActionPrefixes(status, isLast);
|
|
714
|
+
if (!line.trim()) {
|
|
715
|
+
return prefix.trimEnd();
|
|
716
|
+
}
|
|
717
|
+
return `${prefix}${line}`;
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
showMessage(content, role = 'assistant') {
|
|
721
|
+
if (role === 'system') {
|
|
722
|
+
this.showSystemMessage(content);
|
|
723
|
+
}
|
|
724
|
+
else {
|
|
725
|
+
this.showAssistantMessage(content);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
showSystemMessage(content) {
|
|
729
|
+
this.clearSpinnerIfActive();
|
|
730
|
+
const normalized = content.trim();
|
|
731
|
+
if (!normalized) {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
this.stream(`${normalized}\n\n`);
|
|
735
|
+
}
|
|
736
|
+
showError(message, error) {
|
|
737
|
+
this.clearSpinnerIfActive();
|
|
738
|
+
const details = this.formatErrorDetails(error);
|
|
739
|
+
const parts = [`${theme.error('✗')} ${message}`];
|
|
740
|
+
if (details) {
|
|
741
|
+
parts.push(` ${details}`);
|
|
742
|
+
}
|
|
743
|
+
this.stream(`${parts.join('\n')}\n`);
|
|
744
|
+
}
|
|
745
|
+
showWarning(message) {
|
|
746
|
+
this.clearSpinnerIfActive();
|
|
747
|
+
this.stream(`${theme.warning('!')} ${message}\n`);
|
|
748
|
+
}
|
|
709
749
|
showInfo(message) {
|
|
710
750
|
this.clearSpinnerIfActive();
|
|
711
|
-
this.
|
|
712
|
-
this.writeLine(`${theme.info('ℹ')} ${message}`);
|
|
713
|
-
});
|
|
751
|
+
this.stream(`${theme.info('ℹ')} ${message}\n`);
|
|
714
752
|
}
|
|
715
753
|
/**
|
|
716
754
|
* Show a success message with simple styling
|
|
717
755
|
*/
|
|
718
756
|
showSuccess(message) {
|
|
719
757
|
this.clearSpinnerIfActive();
|
|
720
|
-
this.
|
|
721
|
-
this.writeLine(`${theme.success('✓')} ${message}`);
|
|
722
|
-
});
|
|
758
|
+
this.stream(`${theme.success('✓')} ${message}\n`);
|
|
723
759
|
}
|
|
724
760
|
/**
|
|
725
761
|
* Show a stylish progress indicator for long operations
|
|
@@ -793,6 +829,13 @@ export class Display {
|
|
|
793
829
|
}
|
|
794
830
|
// Claude Code style: don't show providers on startup, keep it minimal
|
|
795
831
|
}
|
|
832
|
+
/**
|
|
833
|
+
* Show unified status bar - Claude Code style (minimal)
|
|
834
|
+
* Note: No-op - status is shown in mode controls line
|
|
835
|
+
*/
|
|
836
|
+
showUnifiedStatusBar(_providers) {
|
|
837
|
+
// No-op - banner is streamed as content, status shown in control bar
|
|
838
|
+
}
|
|
796
839
|
/**
|
|
797
840
|
* Show streaming header - no-op, banner is streamed as content
|
|
798
841
|
*/
|
|
@@ -864,6 +907,11 @@ export class Display {
|
|
|
864
907
|
this.stdoutTracker.reset();
|
|
865
908
|
// Banner is streamed content - no re-render on clear
|
|
866
909
|
}
|
|
910
|
+
newLine() {
|
|
911
|
+
this.withOutput(() => {
|
|
912
|
+
this.writeLine();
|
|
913
|
+
});
|
|
914
|
+
}
|
|
867
915
|
// Legacy banner methods removed - banner is streamed as content by the shell
|
|
868
916
|
formatModelLabel(model) {
|
|
869
917
|
if (/gpt-5\.1-?codex/i.test(model)) {
|
|
@@ -905,6 +953,51 @@ export class Display {
|
|
|
905
953
|
}
|
|
906
954
|
return `${parts[0]}/.../${parts[parts.length - 1]}`;
|
|
907
955
|
}
|
|
956
|
+
buildChatBox(content, metadata) {
|
|
957
|
+
const normalized = content.trim();
|
|
958
|
+
if (!normalized) {
|
|
959
|
+
return '';
|
|
960
|
+
}
|
|
961
|
+
if (isPlainOutputMode()) {
|
|
962
|
+
const body = renderMessageBody(normalized, this.resolveMessageWidth());
|
|
963
|
+
const telemetry = this.formatTelemetryLine(metadata);
|
|
964
|
+
return telemetry ? `${body}\n${telemetry}` : body;
|
|
965
|
+
}
|
|
966
|
+
const width = this.resolveMessageWidth();
|
|
967
|
+
const panel = renderMessagePanel(normalized, {
|
|
968
|
+
width,
|
|
969
|
+
title: 'Assistant',
|
|
970
|
+
icon: icons.assistant,
|
|
971
|
+
accentColor: theme.assistant ?? theme.primary,
|
|
972
|
+
borderColor: theme.ui.border,
|
|
973
|
+
});
|
|
974
|
+
const telemetry = this.formatTelemetryLine(metadata);
|
|
975
|
+
if (!telemetry) {
|
|
976
|
+
return panel;
|
|
977
|
+
}
|
|
978
|
+
return `${panel}\n${telemetry}`;
|
|
979
|
+
}
|
|
980
|
+
resolveMessageWidth() {
|
|
981
|
+
const columns = this.getColumnWidth();
|
|
982
|
+
return Math.max(DISPLAY_CONSTANTS.MIN_MESSAGE_WIDTH, Math.min(columns - DISPLAY_CONSTANTS.MESSAGE_PADDING, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH));
|
|
983
|
+
}
|
|
984
|
+
formatTelemetryLine(metadata) {
|
|
985
|
+
if (!metadata) {
|
|
986
|
+
return '';
|
|
987
|
+
}
|
|
988
|
+
const parts = [];
|
|
989
|
+
const elapsed = this.formatElapsed(metadata.elapsedMs);
|
|
990
|
+
if (elapsed) {
|
|
991
|
+
const elapsedLabel = theme.metrics?.elapsedLabel ?? theme.accent;
|
|
992
|
+
const elapsedValue = theme.metrics?.elapsedValue ?? theme.secondary;
|
|
993
|
+
parts.push(`${elapsedLabel('elapsed')} ${elapsedValue(elapsed)}`);
|
|
994
|
+
}
|
|
995
|
+
if (!parts.length) {
|
|
996
|
+
return '';
|
|
997
|
+
}
|
|
998
|
+
const separator = theme.ui.muted(' • ');
|
|
999
|
+
return ` ${parts.join(separator)}`;
|
|
1000
|
+
}
|
|
908
1001
|
formatElapsed(elapsedMs) {
|
|
909
1002
|
if (typeof elapsedMs !== 'number' || !Number.isFinite(elapsedMs) || elapsedMs < 0) {
|
|
910
1003
|
return null;
|
|
@@ -1008,6 +1101,128 @@ export class Display {
|
|
|
1008
1101
|
return theme.ui.muted(text);
|
|
1009
1102
|
}
|
|
1010
1103
|
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Wraps text with a prefix on the first line and optional continuation prefix.
|
|
1106
|
+
* Handles multi-line text and word wrapping intelligently.
|
|
1107
|
+
*/
|
|
1108
|
+
wrapWithPrefix(text, prefix, options) {
|
|
1109
|
+
if (!text) {
|
|
1110
|
+
return prefix.trimEnd();
|
|
1111
|
+
}
|
|
1112
|
+
const width = Math.max(DISPLAY_CONSTANTS.MIN_ACTION_WIDTH, Math.min(this.getColumnWidth(), DISPLAY_CONSTANTS.MAX_ACTION_WIDTH));
|
|
1113
|
+
const prefixWidth = this.visibleLength(prefix);
|
|
1114
|
+
const available = Math.max(DISPLAY_CONSTANTS.MIN_CONTENT_WIDTH, width - prefixWidth);
|
|
1115
|
+
const indent = typeof options?.continuationPrefix === 'string'
|
|
1116
|
+
? options.continuationPrefix
|
|
1117
|
+
: ' '.repeat(Math.max(0, prefixWidth));
|
|
1118
|
+
const segments = text.split('\n');
|
|
1119
|
+
const lines = [];
|
|
1120
|
+
let usedPrefix = false;
|
|
1121
|
+
for (const segment of segments) {
|
|
1122
|
+
if (!segment.trim()) {
|
|
1123
|
+
if (usedPrefix) {
|
|
1124
|
+
lines.push(indent);
|
|
1125
|
+
}
|
|
1126
|
+
else {
|
|
1127
|
+
lines.push(prefix.trimEnd());
|
|
1128
|
+
usedPrefix = true;
|
|
1129
|
+
}
|
|
1130
|
+
continue;
|
|
1131
|
+
}
|
|
1132
|
+
const wrapped = this.wrapLine(segment.trim(), available);
|
|
1133
|
+
for (const line of wrapped) {
|
|
1134
|
+
lines.push(!usedPrefix ? `${prefix}${line}` : `${indent}${line}`);
|
|
1135
|
+
usedPrefix = true;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
return lines.join('\n');
|
|
1139
|
+
}
|
|
1140
|
+
resolveStatusColor(status) {
|
|
1141
|
+
switch (status) {
|
|
1142
|
+
case 'success':
|
|
1143
|
+
return theme.success;
|
|
1144
|
+
case 'error':
|
|
1145
|
+
return theme.error;
|
|
1146
|
+
case 'warning':
|
|
1147
|
+
return theme.warning;
|
|
1148
|
+
case 'pending':
|
|
1149
|
+
return theme.info;
|
|
1150
|
+
default:
|
|
1151
|
+
return theme.secondary;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
formatActionIcon(status) {
|
|
1155
|
+
const colorize = this.resolveStatusColor(status);
|
|
1156
|
+
return colorize(`${icons.action}`);
|
|
1157
|
+
}
|
|
1158
|
+
buildClaudeStyleThought(content, durationMs) {
|
|
1159
|
+
// Claude Code style: ∴ Thought for Xs or ✻ Thinking…
|
|
1160
|
+
const thinkingStyle = theme.thinking || {
|
|
1161
|
+
icon: theme.info,
|
|
1162
|
+
text: theme.ui.muted,
|
|
1163
|
+
border: theme.ui.border,
|
|
1164
|
+
label: theme.info,
|
|
1165
|
+
};
|
|
1166
|
+
const width = Math.min(this.getColumnWidth() - 4, 70);
|
|
1167
|
+
const lines = [];
|
|
1168
|
+
// Header: "∴ Thought for Xs (ctrl+o to show thinking)" for completed, "✻ Thinking…" for active
|
|
1169
|
+
if (durationMs !== undefined) {
|
|
1170
|
+
const elapsed = this.formatElapsedTime(Math.floor(durationMs / 1000));
|
|
1171
|
+
const expandHint = theme.ui.muted('(ctrl+o to show thinking)');
|
|
1172
|
+
lines.push(`${theme.info('∴')} Thought for ${elapsed} ${expandHint}`);
|
|
1173
|
+
}
|
|
1174
|
+
else {
|
|
1175
|
+
lines.push(`${theme.info('✻')} ${thinkingStyle.label('Thinking…')}`);
|
|
1176
|
+
}
|
|
1177
|
+
// Parse and format the thinking content with simple indentation
|
|
1178
|
+
const contentLines = content.split('\n');
|
|
1179
|
+
const hasContent = contentLines.some(line => line.trim().length > 0);
|
|
1180
|
+
if (hasContent) {
|
|
1181
|
+
lines.push(''); // Visual gap between header and content
|
|
1182
|
+
}
|
|
1183
|
+
for (const line of contentLines) {
|
|
1184
|
+
const trimmed = line.replace(/\s+$/, '');
|
|
1185
|
+
if (!trimmed.trim()) {
|
|
1186
|
+
lines.push(''); // Preserve intentional blank lines inside the block
|
|
1187
|
+
continue;
|
|
1188
|
+
}
|
|
1189
|
+
const wrapped = this.wrapLine(trimmed, width - 4);
|
|
1190
|
+
for (const wrappedLine of wrapped) {
|
|
1191
|
+
lines.push(` ${thinkingStyle.text(wrappedLine)}`);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
return lines.join('\n');
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Show a thinking block with rich formatting (public method for external use)
|
|
1198
|
+
* @param content The thinking content to display
|
|
1199
|
+
* @param durationMs Optional duration in milliseconds to show "Thought for Xs"
|
|
1200
|
+
*/
|
|
1201
|
+
showThinkingBlock(content, durationMs) {
|
|
1202
|
+
this.clearSpinnerIfActive();
|
|
1203
|
+
const block = this.buildClaudeStyleThought(content, durationMs);
|
|
1204
|
+
this.withOutput(() => {
|
|
1205
|
+
this.writeLine();
|
|
1206
|
+
this.writeLine(block);
|
|
1207
|
+
this.writeLine();
|
|
1208
|
+
this.writeLine(); // Extra newline for better visual separation
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
buildSubActionPrefixes(status, isLast) {
|
|
1212
|
+
if (isLast) {
|
|
1213
|
+
const colorize = this.resolveStatusColor(status);
|
|
1214
|
+
// Claude Code style: use ⎿ for sub-action result/detail prefix
|
|
1215
|
+
return {
|
|
1216
|
+
prefix: ` ${colorize(icons.subaction)} `,
|
|
1217
|
+
continuation: ' ',
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
const branch = theme.ui.muted('│');
|
|
1221
|
+
return {
|
|
1222
|
+
prefix: ` ${branch} `,
|
|
1223
|
+
continuation: ` ${branch} `,
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1011
1226
|
/**
|
|
1012
1227
|
* Wraps a single line of text to fit within the specified width.
|
|
1013
1228
|
* Intelligently handles word breaking and preserves spaces.
|