erosolar-cli 2.1.172 → 2.1.173
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 +1 -1
- package/agents/erosolar-code.rules.json +2 -2
- package/agents/general.rules.json +21 -3
- package/dist/capabilities/askUserCapability.js +1 -1
- package/dist/capabilities/askUserCapability.js.map +1 -1
- package/dist/capabilities/statusCapability.js +2 -2
- package/dist/capabilities/statusCapability.js.map +1 -1
- package/dist/codex/capabilities/codexCoreCapability.d.ts +6 -0
- package/dist/codex/capabilities/codexCoreCapability.d.ts.map +1 -0
- package/dist/codex/capabilities/codexCoreCapability.js +516 -0
- package/dist/codex/capabilities/codexCoreCapability.js.map +1 -0
- package/dist/codex/fs.d.ts +4 -0
- package/dist/codex/fs.d.ts.map +1 -0
- package/dist/codex/fs.js +25 -0
- package/dist/codex/fs.js.map +1 -0
- package/dist/codex/persistence/planStore.d.ts +4 -0
- package/dist/codex/persistence/planStore.d.ts.map +1 -0
- package/dist/codex/persistence/planStore.js +59 -0
- package/dist/codex/persistence/planStore.js.map +1 -0
- package/dist/codex/pluginAllowlist.d.ts +4 -0
- package/dist/codex/pluginAllowlist.d.ts.map +1 -0
- package/dist/codex/pluginAllowlist.js +14 -0
- package/dist/codex/pluginAllowlist.js.map +1 -0
- package/dist/codex/types.d.ts +21 -0
- package/dist/codex/types.d.ts.map +1 -0
- package/dist/codex/types.js +62 -0
- package/dist/codex/types.js.map +1 -0
- package/dist/contracts/agent-schemas.json +5 -5
- package/dist/core/agent.d.ts +83 -24
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +499 -248
- package/dist/core/agent.js.map +1 -1
- package/dist/core/preferences.d.ts +1 -0
- package/dist/core/preferences.d.ts.map +1 -1
- package/dist/core/preferences.js +8 -1
- package/dist/core/preferences.js.map +1 -1
- package/dist/core/reliabilityPrompt.d.ts +9 -0
- package/dist/core/reliabilityPrompt.d.ts.map +1 -0
- package/dist/core/reliabilityPrompt.js +31 -0
- package/dist/core/reliabilityPrompt.js.map +1 -0
- package/dist/core/schemaValidator.js +3 -3
- package/dist/core/schemaValidator.js.map +1 -1
- package/dist/core/toolPreconditions.d.ts +0 -11
- package/dist/core/toolPreconditions.d.ts.map +1 -1
- package/dist/core/toolPreconditions.js +33 -164
- package/dist/core/toolPreconditions.js.map +1 -1
- package/dist/core/toolRuntime.d.ts.map +1 -1
- package/dist/core/toolRuntime.js +9 -114
- package/dist/core/toolRuntime.js.map +1 -1
- package/dist/core/updateChecker.d.ts +61 -1
- package/dist/core/updateChecker.d.ts.map +1 -1
- package/dist/core/updateChecker.js +147 -3
- package/dist/core/updateChecker.js.map +1 -1
- package/dist/headless/evalMode.d.ts.map +1 -1
- package/dist/headless/evalMode.js +6 -0
- package/dist/headless/evalMode.js.map +1 -1
- package/dist/headless/headlessApp.d.ts.map +1 -1
- package/dist/headless/headlessApp.js +6 -39
- package/dist/headless/headlessApp.js.map +1 -1
- package/dist/mcp/sseClient.d.ts +4 -1
- package/dist/mcp/sseClient.d.ts.map +1 -1
- package/dist/mcp/sseClient.js +36 -2
- package/dist/mcp/sseClient.js.map +1 -1
- package/dist/mcp/stdioClient.d.ts +4 -1
- package/dist/mcp/stdioClient.d.ts.map +1 -1
- package/dist/mcp/stdioClient.js +41 -1
- package/dist/mcp/stdioClient.js.map +1 -1
- package/dist/mcp/toolBridge.d.ts +3 -0
- package/dist/mcp/toolBridge.d.ts.map +1 -1
- package/dist/mcp/toolBridge.js +2 -2
- package/dist/mcp/toolBridge.js.map +1 -1
- package/dist/mcp/types.d.ts +18 -0
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -1
- package/dist/plugins/tools/nodeDefaults.js +0 -2
- package/dist/plugins/tools/nodeDefaults.js.map +1 -1
- package/dist/providers/openaiResponsesProvider.d.ts.map +1 -1
- package/dist/providers/openaiResponsesProvider.js +79 -74
- package/dist/providers/openaiResponsesProvider.js.map +1 -1
- package/dist/runtime/agentController.d.ts.map +1 -1
- package/dist/runtime/agentController.js +6 -3
- package/dist/runtime/agentController.js.map +1 -1
- package/dist/runtime/agentSession.d.ts +0 -2
- package/dist/runtime/agentSession.d.ts.map +1 -1
- package/dist/runtime/agentSession.js +2 -2
- package/dist/runtime/agentSession.js.map +1 -1
- package/dist/shell/interactiveShell.d.ts +25 -18
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +345 -291
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/shellApp.d.ts.map +1 -1
- package/dist/shell/shellApp.js +15 -8
- package/dist/shell/shellApp.js.map +1 -1
- package/dist/shell/systemPrompt.d.ts.map +1 -1
- package/dist/shell/systemPrompt.js +4 -15
- package/dist/shell/systemPrompt.js.map +1 -1
- package/dist/subagents/taskRunner.js +2 -1
- package/dist/subagents/taskRunner.js.map +1 -1
- package/dist/tools/bashTools.d.ts.map +1 -1
- package/dist/tools/bashTools.js +101 -8
- package/dist/tools/bashTools.js.map +1 -1
- package/dist/tools/diffUtils.d.ts +8 -2
- package/dist/tools/diffUtils.d.ts.map +1 -1
- package/dist/tools/diffUtils.js +72 -13
- package/dist/tools/diffUtils.js.map +1 -1
- package/dist/tools/grepTools.d.ts.map +1 -1
- package/dist/tools/grepTools.js +10 -2
- package/dist/tools/grepTools.js.map +1 -1
- package/dist/tools/planningTools.d.ts +0 -10
- package/dist/tools/planningTools.d.ts.map +1 -1
- package/dist/tools/planningTools.js +0 -16
- package/dist/tools/planningTools.js.map +1 -1
- package/dist/tools/searchTools.d.ts.map +1 -1
- package/dist/tools/searchTools.js +4 -2
- package/dist/tools/searchTools.js.map +1 -1
- package/dist/ui/PromptController.d.ts +7 -4
- package/dist/ui/PromptController.d.ts.map +1 -1
- package/dist/ui/PromptController.js +4 -7
- package/dist/ui/PromptController.js.map +1 -1
- package/dist/ui/ShellUIAdapter.d.ts +286 -28
- package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
- package/dist/ui/ShellUIAdapter.js +1485 -121
- package/dist/ui/ShellUIAdapter.js.map +1 -1
- package/dist/ui/UnifiedUIController.d.ts +80 -0
- package/dist/ui/UnifiedUIController.d.ts.map +1 -0
- package/dist/ui/UnifiedUIController.js +211 -0
- package/dist/ui/UnifiedUIController.js.map +1 -0
- package/dist/ui/UnifiedUIRenderer.d.ts +102 -46
- package/dist/ui/UnifiedUIRenderer.d.ts.map +1 -1
- package/dist/ui/UnifiedUIRenderer.js +680 -610
- package/dist/ui/UnifiedUIRenderer.js.map +1 -1
- package/dist/ui/animatedStatus.d.ts +128 -6
- package/dist/ui/animatedStatus.d.ts.map +1 -1
- package/dist/ui/animatedStatus.js +383 -50
- package/dist/ui/animatedStatus.js.map +1 -1
- package/dist/ui/animation/AnimationScheduler.d.ts +192 -0
- package/dist/ui/animation/AnimationScheduler.d.ts.map +1 -0
- package/dist/ui/animation/AnimationScheduler.js +432 -0
- package/dist/ui/animation/AnimationScheduler.js.map +1 -0
- package/dist/ui/display.d.ts +179 -25
- package/dist/ui/display.d.ts.map +1 -1
- package/dist/ui/display.js +678 -96
- package/dist/ui/display.js.map +1 -1
- package/dist/ui/inPlaceUpdater.d.ts +181 -0
- package/dist/ui/inPlaceUpdater.d.ts.map +1 -0
- package/dist/ui/inPlaceUpdater.js +515 -0
- package/dist/ui/inPlaceUpdater.js.map +1 -0
- package/dist/ui/interrupts/InterruptManager.d.ts +142 -0
- package/dist/ui/interrupts/InterruptManager.d.ts.map +1 -0
- package/dist/ui/interrupts/InterruptManager.js +439 -0
- package/dist/ui/interrupts/InterruptManager.js.map +1 -0
- package/dist/ui/layout.d.ts +0 -1
- package/dist/ui/layout.d.ts.map +1 -1
- package/dist/ui/layout.js +0 -12
- package/dist/ui/layout.js.map +1 -1
- package/dist/ui/orchestration/StatusOrchestrator.d.ts +1 -1
- package/dist/ui/orchestration/StatusOrchestrator.js +1 -1
- package/dist/ui/orchestration/UIUpdateCoordinator.d.ts +61 -7
- package/dist/ui/orchestration/UIUpdateCoordinator.d.ts.map +1 -1
- package/dist/ui/orchestration/UIUpdateCoordinator.js +232 -20
- package/dist/ui/orchestration/UIUpdateCoordinator.js.map +1 -1
- package/dist/ui/shortcutsHelp.d.ts.map +1 -1
- package/dist/ui/shortcutsHelp.js +0 -1
- package/dist/ui/shortcutsHelp.js.map +1 -1
- package/dist/ui/telemetry/ResponseTracker.d.ts +22 -0
- package/dist/ui/telemetry/ResponseTracker.d.ts.map +1 -0
- package/dist/ui/telemetry/ResponseTracker.js +60 -0
- package/dist/ui/telemetry/ResponseTracker.js.map +1 -0
- package/dist/ui/telemetry/UITelemetry.d.ts +181 -0
- package/dist/ui/telemetry/UITelemetry.d.ts.map +1 -0
- package/dist/ui/telemetry/UITelemetry.js +446 -0
- package/dist/ui/telemetry/UITelemetry.js.map +1 -0
- package/dist/ui/unified/index.d.ts +28 -1
- package/dist/ui/unified/index.d.ts.map +1 -1
- package/dist/ui/unified/index.js +41 -2
- package/dist/ui/unified/index.js.map +1 -1
- package/dist/ui/unified/layout.d.ts +12 -0
- package/dist/ui/unified/layout.d.ts.map +1 -0
- package/dist/ui/unified/layout.js +96 -0
- package/dist/ui/unified/layout.js.map +1 -0
- package/package.json +1 -2
- package/dist/StringUtils.d.ts +0 -8
- package/dist/StringUtils.d.ts.map +0 -1
- package/dist/StringUtils.js +0 -11
- package/dist/StringUtils.js.map +0 -1
- package/dist/core/aiFlowSupervisor.d.ts +0 -44
- package/dist/core/aiFlowSupervisor.d.ts.map +0 -1
- package/dist/core/aiFlowSupervisor.js +0 -299
- package/dist/core/aiFlowSupervisor.js.map +0 -1
- package/dist/core/cliTestHarness.d.ts +0 -200
- package/dist/core/cliTestHarness.d.ts.map +0 -1
- package/dist/core/cliTestHarness.js +0 -549
- package/dist/core/cliTestHarness.js.map +0 -1
- package/dist/core/testUtils.d.ts +0 -121
- package/dist/core/testUtils.d.ts.map +0 -1
- package/dist/core/testUtils.js +0 -235
- package/dist/core/testUtils.js.map +0 -1
- package/dist/core/toolValidation.d.ts +0 -116
- package/dist/core/toolValidation.d.ts.map +0 -1
- package/dist/core/toolValidation.js +0 -282
- package/dist/core/toolValidation.js.map +0 -1
- package/dist/ui/planOverlay.d.ts +0 -28
- package/dist/ui/planOverlay.d.ts.map +0 -1
- package/dist/ui/planOverlay.js +0 -156
- package/dist/ui/planOverlay.js.map +0 -1
- package/dist/ui/streamingFormatter.d.ts +0 -30
- package/dist/ui/streamingFormatter.d.ts.map +0 -1
- package/dist/ui/streamingFormatter.js +0 -91
- package/dist/ui/streamingFormatter.js.map +0 -1
- package/dist/utils/errorUtils.d.ts +0 -16
- package/dist/utils/errorUtils.d.ts.map +0 -1
- package/dist/utils/errorUtils.js +0 -66
- package/dist/utils/errorUtils.js.map +0 -1
package/dist/ui/display.js
CHANGED
|
@@ -1,123 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Display - Simplified UI facade that routes all output through UnifiedUIRenderer
|
|
3
|
+
*
|
|
4
|
+
* This class now serves as a compatibility layer, providing the same API
|
|
5
|
+
* but delegating all actual rendering to UnifiedUIRenderer.
|
|
6
|
+
*/
|
|
1
7
|
import readline from 'node:readline';
|
|
2
|
-
import { theme } from './theme.js';
|
|
8
|
+
import { theme, icons } from './theme.js';
|
|
9
|
+
import { renderMessagePanel, renderMessageBody } from './richText.js';
|
|
10
|
+
import { getTerminalColumns } from './layout.js';
|
|
11
|
+
import { highlightError } from './textHighlighter.js';
|
|
12
|
+
import { renderSectionHeading } from './designSystem.js';
|
|
13
|
+
import { isPlainOutputMode } from './outputMode.js';
|
|
14
|
+
// Display configuration constants
|
|
15
|
+
const DISPLAY_CONSTANTS = {
|
|
16
|
+
MIN_BANNER_WIDTH: 32,
|
|
17
|
+
MAX_BANNER_WIDTH: 120,
|
|
18
|
+
BANNER_PADDING: 4,
|
|
19
|
+
MIN_MESSAGE_WIDTH: 42,
|
|
20
|
+
MAX_MESSAGE_WIDTH: 110,
|
|
21
|
+
MESSAGE_PADDING: 4,
|
|
22
|
+
MIN_ACTION_WIDTH: 40,
|
|
23
|
+
MAX_ACTION_WIDTH: 90,
|
|
24
|
+
MIN_THOUGHT_WIDTH: 48,
|
|
25
|
+
MAX_THOUGHT_WIDTH: 96,
|
|
26
|
+
MIN_CONTENT_WIDTH: 10,
|
|
27
|
+
MIN_WRAP_WIDTH: 12,
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Display class - now a thin wrapper around UnifiedUIRenderer
|
|
31
|
+
*
|
|
32
|
+
* Provides backward-compatible API while routing all output through the renderer.
|
|
33
|
+
*/
|
|
3
34
|
export class Display {
|
|
4
|
-
renderer = null;
|
|
5
35
|
outputStream;
|
|
36
|
+
errorStream;
|
|
37
|
+
renderer = null;
|
|
38
|
+
outputInterceptors = new Set();
|
|
6
39
|
inlinePanelHandler = null;
|
|
7
|
-
|
|
8
|
-
lastToolResult = null;
|
|
9
|
-
activeSpinner = null;
|
|
10
|
-
constructor(stream = process.stdout, _errorStream) {
|
|
40
|
+
constructor(stream = process.stdout, errorStream) {
|
|
11
41
|
this.outputStream = stream;
|
|
42
|
+
this.errorStream = errorStream ?? stream;
|
|
12
43
|
}
|
|
13
44
|
setRenderer(renderer) {
|
|
14
45
|
this.renderer = renderer;
|
|
15
46
|
}
|
|
47
|
+
hasRenderer() {
|
|
48
|
+
return Boolean(this.renderer);
|
|
49
|
+
}
|
|
16
50
|
setInlinePanelHandler(handler) {
|
|
17
51
|
this.inlinePanelHandler = handler;
|
|
18
52
|
}
|
|
19
|
-
|
|
53
|
+
maybeHandleInlinePanel(content) {
|
|
54
|
+
if (!this.inlinePanelHandler) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
return this.inlinePanelHandler(content) === true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
enqueueEvent(type, content) {
|
|
65
|
+
if (!this.renderer || !content) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
this.renderer.addEvent(type, content);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
registerOutputInterceptor(interceptor) {
|
|
72
|
+
if (!interceptor) {
|
|
73
|
+
return () => { };
|
|
74
|
+
}
|
|
75
|
+
this.outputInterceptors.add(interceptor);
|
|
76
|
+
return () => {
|
|
77
|
+
this.outputInterceptors.delete(interceptor);
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
notifyBeforeOutput() {
|
|
81
|
+
for (const interceptor of this.outputInterceptors) {
|
|
82
|
+
interceptor.beforeWrite?.();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
notifyAfterOutput(content) {
|
|
86
|
+
const interceptors = Array.from(this.outputInterceptors);
|
|
87
|
+
for (let index = interceptors.length - 1; index >= 0; index -= 1) {
|
|
88
|
+
interceptors[index]?.afterWrite?.(content);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Write raw content directly
|
|
93
|
+
*/
|
|
94
|
+
writeRaw(content) {
|
|
20
95
|
if (!content)
|
|
21
96
|
return;
|
|
22
|
-
|
|
23
|
-
|
|
97
|
+
this.notifyBeforeOutput();
|
|
98
|
+
if (this.enqueueEvent('raw', content)) {
|
|
99
|
+
this.notifyAfterOutput(content);
|
|
24
100
|
return;
|
|
25
101
|
}
|
|
102
|
+
// Fallback if no renderer
|
|
26
103
|
this.outputStream.write(content);
|
|
104
|
+
this.notifyAfterOutput(content);
|
|
27
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Stream chunk (for streaming responses)
|
|
108
|
+
*/
|
|
28
109
|
stream(chunk) {
|
|
29
110
|
if (!chunk)
|
|
30
111
|
return;
|
|
31
|
-
this.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (!content)
|
|
112
|
+
this.notifyBeforeOutput();
|
|
113
|
+
if (this.enqueueEvent('streaming', chunk)) {
|
|
114
|
+
this.notifyAfterOutput(chunk);
|
|
35
115
|
return;
|
|
36
|
-
|
|
37
|
-
|
|
116
|
+
}
|
|
117
|
+
// Fallback
|
|
118
|
+
this.outputStream.write(chunk);
|
|
119
|
+
this.notifyAfterOutput(chunk);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Backward-compatible alias
|
|
123
|
+
*/
|
|
124
|
+
writeStreamChunk(chunk) {
|
|
125
|
+
this.stream(chunk);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get the output stream for direct access
|
|
129
|
+
*/
|
|
130
|
+
getOutputStream() {
|
|
131
|
+
return this.outputStream;
|
|
38
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Show thinking indicator
|
|
135
|
+
* NO-OP: Don't emit events during SSE streaming.
|
|
136
|
+
* The animated spinner in the status line shows thinking state.
|
|
137
|
+
*/
|
|
138
|
+
showThinking(_message = 'Thinking…') {
|
|
139
|
+
// NO-OP: Spinner animation handles thinking state visually.
|
|
140
|
+
// No events emitted - final message handler renders complete content.
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Update thinking indicator (status line only, not scrollback)
|
|
144
|
+
* This is called frequently during streaming to show progress snippets.
|
|
145
|
+
* The actual content will be rendered as a complete block later.
|
|
146
|
+
*/
|
|
147
|
+
updateThinking(_message) {
|
|
148
|
+
// NO-OP: Don't emit events for transient thinking updates.
|
|
149
|
+
// Thinking snippets are shown only in the status indicator (animated spinner).
|
|
150
|
+
// The complete thought/response will be rendered as a block when ready.
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Stop thinking (no-op - renderer handles state)
|
|
154
|
+
*/
|
|
155
|
+
stopThinking(_addNewLine = true) {
|
|
156
|
+
// No-op - renderer handles thinking state
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Show assistant message
|
|
160
|
+
*/
|
|
39
161
|
showAssistantMessage(content, metadata) {
|
|
40
162
|
const normalized = content.trim();
|
|
41
163
|
if (!normalized)
|
|
42
164
|
return;
|
|
43
|
-
this.clearActiveSpinner();
|
|
44
165
|
const isThought = metadata?.isFinal === false;
|
|
45
|
-
const
|
|
46
|
-
this.
|
|
166
|
+
const useRichBlock = !isThought && metadata?.wasStreamed !== true;
|
|
167
|
+
const wrapped = useRichBlock ? this.buildChatBox(normalized, metadata) : this.wrapForRenderer(normalized);
|
|
168
|
+
const telemetry = !useRichBlock && metadata?.isFinal !== false ? this.formatTelemetryLine(metadata) : '';
|
|
169
|
+
const payload = telemetry ? `${wrapped}\n${telemetry}` : wrapped;
|
|
170
|
+
const eventType = isThought ? 'thought' : useRichBlock ? 'banner' : 'response';
|
|
171
|
+
this.notifyBeforeOutput();
|
|
172
|
+
if (!this.enqueueEvent(eventType, payload)) {
|
|
173
|
+
this.outputStream.write(`${payload}\n`);
|
|
174
|
+
}
|
|
175
|
+
this.notifyAfterOutput(payload);
|
|
47
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Show narrative (thought)
|
|
179
|
+
*/
|
|
48
180
|
showNarrative(content) {
|
|
49
|
-
this.showAssistantMessage(content, { isFinal: false });
|
|
50
|
-
}
|
|
51
|
-
showSystemMessage(content) {
|
|
52
181
|
const normalized = content.trim();
|
|
53
182
|
if (!normalized)
|
|
54
183
|
return;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
this.emit('response', normalized);
|
|
184
|
+
// Render narrative as a thought so it appears before tool actions
|
|
185
|
+
this.showAssistantMessage(normalized, { isFinal: false });
|
|
59
186
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.emit('response', `${theme.warning('!')} ${message}`);
|
|
187
|
+
/**
|
|
188
|
+
* Show action
|
|
189
|
+
*/
|
|
190
|
+
showAction(text, status = 'info') {
|
|
191
|
+
if (!text.trim())
|
|
192
|
+
return;
|
|
193
|
+
const icon = this.formatActionIcon(status);
|
|
194
|
+
const rendered = this.wrapWithPrefix(text, `${icon} `);
|
|
195
|
+
this.enqueueEvent('raw', `${rendered}\n`);
|
|
70
196
|
}
|
|
71
|
-
|
|
72
|
-
|
|
197
|
+
/**
|
|
198
|
+
* Show sub-action
|
|
199
|
+
*/
|
|
200
|
+
showSubAction(text, status = 'info') {
|
|
201
|
+
if (!text.trim())
|
|
202
|
+
return;
|
|
203
|
+
const lines = this.buildWrappedSubActionLines(text, status);
|
|
204
|
+
if (!lines.length)
|
|
205
|
+
return;
|
|
206
|
+
this.enqueueEvent('raw', `${lines.join('\n')}\n\n`);
|
|
73
207
|
}
|
|
74
|
-
|
|
75
|
-
|
|
208
|
+
/**
|
|
209
|
+
* Show message
|
|
210
|
+
*/
|
|
211
|
+
showMessage(content, role = 'assistant') {
|
|
212
|
+
if (role === 'system') {
|
|
213
|
+
this.showSystemMessage(content);
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
this.showAssistantMessage(content);
|
|
217
|
+
}
|
|
76
218
|
}
|
|
77
|
-
|
|
219
|
+
/**
|
|
220
|
+
* Show system message
|
|
221
|
+
*/
|
|
222
|
+
showSystemMessage(content) {
|
|
78
223
|
const normalized = content.trim();
|
|
79
224
|
if (!normalized)
|
|
80
225
|
return;
|
|
81
|
-
this.
|
|
82
|
-
}
|
|
83
|
-
showThinking(message = 'Thinking…') {
|
|
84
|
-
this.thinkingStart = Date.now();
|
|
85
|
-
this.emit('thought', message);
|
|
86
|
-
}
|
|
87
|
-
updateThinking(message) {
|
|
88
|
-
this.emit('thought', message);
|
|
89
|
-
}
|
|
90
|
-
stopThinking(addNewline = true) {
|
|
91
|
-
this.clearActiveSpinner(!addNewline);
|
|
92
|
-
this.thinkingStart = null;
|
|
93
|
-
}
|
|
94
|
-
clearActiveSpinner(useStop = false) {
|
|
95
|
-
if (!this.activeSpinner) {
|
|
226
|
+
if (this.maybeHandleInlinePanel(normalized)) {
|
|
96
227
|
return;
|
|
97
228
|
}
|
|
98
|
-
const
|
|
99
|
-
this.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
spinner.clear();
|
|
103
|
-
}
|
|
104
|
-
else if (typeof spinner.stop === 'function') {
|
|
105
|
-
spinner.stop();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
// ignore spinner errors
|
|
229
|
+
const output = `${normalized}\n\n`;
|
|
230
|
+
this.notifyBeforeOutput();
|
|
231
|
+
if (!this.enqueueEvent('response', output)) {
|
|
232
|
+
this.outputStream.write(output);
|
|
110
233
|
}
|
|
234
|
+
this.notifyAfterOutput(output);
|
|
111
235
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
236
|
+
/**
|
|
237
|
+
* Show test event (renders in unified UI "test" lane)
|
|
238
|
+
*/
|
|
239
|
+
showTestEvent(content) {
|
|
240
|
+
const normalized = content.trim();
|
|
241
|
+
if (!normalized)
|
|
242
|
+
return;
|
|
243
|
+
this.notifyBeforeOutput();
|
|
244
|
+
if (!this.enqueueEvent('test', normalized)) {
|
|
245
|
+
this.outputStream.write(`${normalized}\n\n`);
|
|
118
246
|
}
|
|
119
|
-
|
|
247
|
+
this.notifyAfterOutput(normalized);
|
|
120
248
|
}
|
|
249
|
+
/**
|
|
250
|
+
* Show an inline panel; in non-overlay mode this simply writes to output.
|
|
251
|
+
*/
|
|
121
252
|
showInlinePanel(content) {
|
|
122
253
|
const lines = Array.isArray(content) ? content : content.split('\n');
|
|
123
254
|
const normalized = lines.map(line => line.trimEnd()).filter(line => line.trim().length > 0);
|
|
@@ -129,15 +260,22 @@ export class Display {
|
|
|
129
260
|
this.renderer.setInlinePanel(normalized);
|
|
130
261
|
return;
|
|
131
262
|
}
|
|
263
|
+
// Fallback for plain mode: emit directly without routing through the inline handler
|
|
132
264
|
const output = `${normalized.join('\n')}\n`;
|
|
265
|
+
this.notifyBeforeOutput();
|
|
133
266
|
this.outputStream.write(output);
|
|
267
|
+
this.notifyAfterOutput(output);
|
|
134
268
|
}
|
|
135
269
|
clearInlinePanel() {
|
|
136
270
|
if (this.renderer && typeof this.renderer.clearInlinePanel === 'function') {
|
|
137
271
|
this.renderer.clearInlinePanel();
|
|
138
272
|
}
|
|
139
273
|
}
|
|
140
|
-
|
|
274
|
+
/**
|
|
275
|
+
* Capture a single line of user input without logging it to scrollback.
|
|
276
|
+
* Uses the unified renderer when available, with a readline fallback.
|
|
277
|
+
*/
|
|
278
|
+
async captureUserInput(options = {}) {
|
|
141
279
|
if (this.renderer && typeof this.renderer.captureInput === 'function') {
|
|
142
280
|
return this.renderer.captureInput(options);
|
|
143
281
|
}
|
|
@@ -158,46 +296,180 @@ export class Display {
|
|
|
158
296
|
});
|
|
159
297
|
});
|
|
160
298
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
299
|
+
/**
|
|
300
|
+
* Show error
|
|
301
|
+
*/
|
|
302
|
+
showError(message, error) {
|
|
303
|
+
const details = this.formatErrorDetails(error);
|
|
304
|
+
const parts = [`${theme.error('✗')} ${message}`];
|
|
305
|
+
if (details) {
|
|
306
|
+
parts.push(` ${details}`);
|
|
307
|
+
}
|
|
308
|
+
const output = `${parts.join('\n')}\n`;
|
|
309
|
+
this.notifyBeforeOutput();
|
|
310
|
+
if (!this.enqueueEvent('response', output)) {
|
|
311
|
+
this.outputStream.write(output);
|
|
312
|
+
}
|
|
313
|
+
this.notifyAfterOutput(output);
|
|
167
314
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
315
|
+
/**
|
|
316
|
+
* Show warning
|
|
317
|
+
*/
|
|
318
|
+
showWarning(message) {
|
|
319
|
+
const output = `${theme.warning('!')} ${message}\n`;
|
|
320
|
+
this.notifyBeforeOutput();
|
|
321
|
+
if (!this.enqueueEvent('response', output)) {
|
|
322
|
+
this.outputStream.write(output);
|
|
171
323
|
}
|
|
172
|
-
|
|
173
|
-
|
|
324
|
+
this.notifyAfterOutput(output);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Show info
|
|
328
|
+
*/
|
|
329
|
+
showInfo(message) {
|
|
330
|
+
const output = `${theme.info('ℹ')} ${message}\n`;
|
|
331
|
+
this.notifyBeforeOutput();
|
|
332
|
+
if (!this.enqueueEvent('response', output)) {
|
|
333
|
+
this.outputStream.write(output);
|
|
334
|
+
}
|
|
335
|
+
this.notifyAfterOutput(output);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Show success
|
|
339
|
+
*/
|
|
340
|
+
showSuccess(message) {
|
|
341
|
+
const output = `${theme.success('✓')} ${message}\n`;
|
|
342
|
+
this.notifyBeforeOutput();
|
|
343
|
+
if (!this.enqueueEvent('response', output)) {
|
|
344
|
+
this.outputStream.write(output);
|
|
345
|
+
}
|
|
346
|
+
this.notifyAfterOutput(output);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Show progress badge
|
|
350
|
+
*/
|
|
351
|
+
showProgressBadge(label, current, total) {
|
|
352
|
+
const percentage = Math.round((current / total) * 100);
|
|
353
|
+
const barWidth = 20;
|
|
354
|
+
const filled = Math.round((current / total) * barWidth);
|
|
355
|
+
const empty = barWidth - filled;
|
|
356
|
+
const progressBar = `${'█'.repeat(filled)}${'░'.repeat(empty)}`;
|
|
357
|
+
const badge = `[${label}] ${progressBar} ${percentage}%`;
|
|
358
|
+
this.stream(`\r${theme.info(badge)}`);
|
|
359
|
+
if (current >= total) {
|
|
360
|
+
this.stream('\n');
|
|
174
361
|
}
|
|
175
362
|
}
|
|
176
|
-
|
|
363
|
+
/**
|
|
364
|
+
* Show status line
|
|
365
|
+
*/
|
|
366
|
+
showStatusLine(status, elapsedMs, _context) {
|
|
177
367
|
const normalized = status?.trim();
|
|
178
368
|
if (!normalized)
|
|
179
369
|
return;
|
|
180
370
|
const elapsed = this.formatElapsed(elapsedMs);
|
|
181
|
-
const parts = [normalized];
|
|
371
|
+
const parts = [`• ${normalized}`];
|
|
182
372
|
if (elapsed) {
|
|
183
373
|
parts.push(elapsed);
|
|
184
374
|
}
|
|
375
|
+
if (process.stdout.isTTY) {
|
|
376
|
+
parts.push('esc to interrupt');
|
|
377
|
+
}
|
|
378
|
+
// Status is kept internal; avoid forcing unnecessary prompt re-renders.
|
|
185
379
|
this.renderer?.updateStatusBundle({ main: parts.join(' • ') }, { render: false });
|
|
186
380
|
}
|
|
381
|
+
/**
|
|
382
|
+
* Show command palette
|
|
383
|
+
*/
|
|
384
|
+
showCommandPalette(commands, options) {
|
|
385
|
+
if (!commands || commands.length === 0)
|
|
386
|
+
return;
|
|
387
|
+
const panel = this.buildCommandPalette(commands, options);
|
|
388
|
+
if (!panel.trim())
|
|
389
|
+
return;
|
|
390
|
+
const output = `\n${panel}\n\n`;
|
|
391
|
+
this.notifyBeforeOutput();
|
|
392
|
+
if (!this.enqueueEvent('response', output)) {
|
|
393
|
+
this.outputStream.write(output);
|
|
394
|
+
}
|
|
395
|
+
this.notifyAfterOutput(output);
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Show planning step
|
|
399
|
+
*/
|
|
400
|
+
showPlanningStep(step, index, total) {
|
|
401
|
+
if (!step?.trim() || index < 1 || total < 1 || index > total)
|
|
402
|
+
return;
|
|
403
|
+
const width = Math.max(DISPLAY_CONSTANTS.MIN_THOUGHT_WIDTH, Math.min(this.getColumnWidth(), DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH));
|
|
404
|
+
const heading = renderSectionHeading(`Plan ${index}/${total}`, {
|
|
405
|
+
subtitle: step,
|
|
406
|
+
icon: icons.arrow,
|
|
407
|
+
tone: 'info',
|
|
408
|
+
width,
|
|
409
|
+
});
|
|
410
|
+
this.enqueueEvent('raw', `${heading}\n`);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Show thinking block
|
|
414
|
+
*/
|
|
415
|
+
showThinkingBlock(content, durationMs) {
|
|
416
|
+
const block = this.buildClaudeStyleThought(content, durationMs);
|
|
417
|
+
this.enqueueEvent('raw', `\n${block}\n\n`);
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Clear screen
|
|
421
|
+
*/
|
|
187
422
|
clear() {
|
|
188
|
-
// Renderer
|
|
423
|
+
// Renderer handles this
|
|
189
424
|
}
|
|
190
|
-
|
|
191
|
-
|
|
425
|
+
/**
|
|
426
|
+
* Update streaming status (routes to renderer)
|
|
427
|
+
*/
|
|
428
|
+
updateStreamingStatus(status) {
|
|
429
|
+
this.renderer?.updateStatus(status);
|
|
192
430
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
431
|
+
/**
|
|
432
|
+
* Clear streaming status
|
|
433
|
+
*/
|
|
434
|
+
clearStreamingStatus() {
|
|
435
|
+
this.renderer?.updateStatus(null);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Check if streaming status is visible
|
|
439
|
+
*/
|
|
440
|
+
isStreamingStatusVisible() {
|
|
441
|
+
return false; // Renderer manages this
|
|
442
|
+
}
|
|
443
|
+
parallelAgentStatus(content) {
|
|
444
|
+
if (!content)
|
|
445
|
+
return;
|
|
446
|
+
this.enqueueEvent('streaming', `${content}\n`);
|
|
447
|
+
}
|
|
448
|
+
// ==================== Private Helper Methods ====================
|
|
449
|
+
getColumnWidth() {
|
|
450
|
+
if (typeof this.outputStream.columns === 'number' &&
|
|
451
|
+
Number.isFinite(this.outputStream.columns) &&
|
|
452
|
+
this.outputStream.columns > 0) {
|
|
453
|
+
return this.outputStream.columns;
|
|
454
|
+
}
|
|
455
|
+
return getTerminalColumns();
|
|
456
|
+
}
|
|
457
|
+
formatErrorDetails(error) {
|
|
458
|
+
if (!error)
|
|
459
|
+
return null;
|
|
460
|
+
if (error instanceof Error) {
|
|
461
|
+
if (error.stack)
|
|
462
|
+
return highlightError(error.stack);
|
|
463
|
+
return highlightError(error.message);
|
|
464
|
+
}
|
|
465
|
+
if (typeof error === 'string') {
|
|
466
|
+
return highlightError(error);
|
|
467
|
+
}
|
|
196
468
|
try {
|
|
197
|
-
return
|
|
469
|
+
return highlightError(JSON.stringify(error, null, 2));
|
|
198
470
|
}
|
|
199
471
|
catch {
|
|
200
|
-
return
|
|
472
|
+
return null;
|
|
201
473
|
}
|
|
202
474
|
}
|
|
203
475
|
formatElapsed(elapsedMs) {
|
|
@@ -212,6 +484,316 @@ export class Display {
|
|
|
212
484
|
}
|
|
213
485
|
return `${seconds}s`;
|
|
214
486
|
}
|
|
487
|
+
buildChatBox(content, metadata) {
|
|
488
|
+
const normalized = content.trim();
|
|
489
|
+
if (!normalized)
|
|
490
|
+
return '';
|
|
491
|
+
if (isPlainOutputMode()) {
|
|
492
|
+
const body = renderMessageBody(normalized, this.resolveMessageWidth());
|
|
493
|
+
const telemetry = this.formatTelemetryLine(metadata);
|
|
494
|
+
return telemetry ? `${body}\n${telemetry}` : body;
|
|
495
|
+
}
|
|
496
|
+
const width = this.resolveMessageWidth();
|
|
497
|
+
const panel = renderMessagePanel(normalized, {
|
|
498
|
+
width,
|
|
499
|
+
title: 'Assistant',
|
|
500
|
+
icon: icons.assistant,
|
|
501
|
+
accentColor: theme.assistant ?? theme.primary,
|
|
502
|
+
borderColor: theme.ui.border,
|
|
503
|
+
});
|
|
504
|
+
const telemetry = this.formatTelemetryLine(metadata);
|
|
505
|
+
return telemetry ? `${panel}\n${telemetry}` : panel;
|
|
506
|
+
}
|
|
507
|
+
resolveMessageWidth() {
|
|
508
|
+
const columns = this.getColumnWidth();
|
|
509
|
+
return Math.max(DISPLAY_CONSTANTS.MIN_MESSAGE_WIDTH, Math.min(columns - DISPLAY_CONSTANTS.MESSAGE_PADDING, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH));
|
|
510
|
+
}
|
|
511
|
+
formatTelemetryLine(metadata) {
|
|
512
|
+
if (!metadata)
|
|
513
|
+
return '';
|
|
514
|
+
const parts = [];
|
|
515
|
+
const elapsed = this.formatElapsed(metadata.elapsedMs);
|
|
516
|
+
if (elapsed) {
|
|
517
|
+
const elapsedLabel = theme.metrics?.elapsedLabel ?? theme.accent;
|
|
518
|
+
const elapsedValue = theme.metrics?.elapsedValue ?? theme.secondary;
|
|
519
|
+
parts.push(`${elapsedLabel('elapsed')} ${elapsedValue(elapsed)}`);
|
|
520
|
+
}
|
|
521
|
+
if (!parts.length)
|
|
522
|
+
return '';
|
|
523
|
+
const separator = theme.ui.muted(' • ');
|
|
524
|
+
return ` ${parts.join(separator)}`;
|
|
525
|
+
}
|
|
526
|
+
buildClaudeStyleThought(content, durationMs) {
|
|
527
|
+
const thinkingStyle = theme.thinking || {
|
|
528
|
+
icon: theme.info,
|
|
529
|
+
text: theme.ui.muted,
|
|
530
|
+
border: theme.ui.border,
|
|
531
|
+
label: theme.info,
|
|
532
|
+
};
|
|
533
|
+
const width = Math.min(this.getColumnWidth() - 4, 70);
|
|
534
|
+
const lines = [];
|
|
535
|
+
// Header
|
|
536
|
+
if (durationMs !== undefined) {
|
|
537
|
+
const elapsed = this.formatElapsedTime(Math.floor(durationMs / 1000));
|
|
538
|
+
lines.push(`${theme.info('∴')} Thought for ${elapsed}`);
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
lines.push(`${theme.info('✻')} ${thinkingStyle.label('Thinking…')}`);
|
|
542
|
+
}
|
|
543
|
+
// Content
|
|
544
|
+
const contentLines = content.split('\n');
|
|
545
|
+
const hasContent = contentLines.some(line => line.trim().length > 0);
|
|
546
|
+
if (hasContent) {
|
|
547
|
+
lines.push('');
|
|
548
|
+
}
|
|
549
|
+
for (const line of contentLines) {
|
|
550
|
+
const trimmed = line.replace(/\s+$/, '');
|
|
551
|
+
if (!trimmed.trim()) {
|
|
552
|
+
lines.push('');
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
const wrapped = this.wrapLine(trimmed, width - 4);
|
|
556
|
+
for (const wrappedLine of wrapped) {
|
|
557
|
+
lines.push(` ${thinkingStyle.text(wrappedLine)}`);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
return lines.join('\n');
|
|
561
|
+
}
|
|
562
|
+
formatElapsedTime(seconds) {
|
|
563
|
+
if (seconds < 60) {
|
|
564
|
+
return `${seconds}s`;
|
|
565
|
+
}
|
|
566
|
+
const mins = Math.floor(seconds / 60);
|
|
567
|
+
const secs = seconds % 60;
|
|
568
|
+
return secs > 0 ? `${mins}m ${secs}s` : `${mins}m`;
|
|
569
|
+
}
|
|
570
|
+
buildCommandPalette(commands, options) {
|
|
571
|
+
if (!commands.length)
|
|
572
|
+
return '';
|
|
573
|
+
const width = Math.max(DISPLAY_CONSTANTS.MIN_MESSAGE_WIDTH, Math.min(this.getColumnWidth() - 2, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH));
|
|
574
|
+
const indent = ' ';
|
|
575
|
+
const grouped = this.groupPaletteCommands(commands);
|
|
576
|
+
const commandWidth = this.computeCommandColumnWidth(commands, width, indent.length);
|
|
577
|
+
const descWidth = Math.max(DISPLAY_CONSTANTS.MIN_WRAP_WIDTH, width - indent.length - commandWidth - 1);
|
|
578
|
+
const title = options?.title ?? 'Slash commands';
|
|
579
|
+
const intro = options?.intro ?? 'Describe a task or pick a command below:';
|
|
580
|
+
const lines = [];
|
|
581
|
+
lines.push(theme.gradient.primary(title));
|
|
582
|
+
const introLines = this.wrapLine(intro, width);
|
|
583
|
+
for (const line of introLines) {
|
|
584
|
+
lines.push(theme.ui.muted(line));
|
|
585
|
+
}
|
|
586
|
+
lines.push('');
|
|
587
|
+
grouped.forEach(({ category, items }, index) => {
|
|
588
|
+
const label = this.formatPaletteCategory(category);
|
|
589
|
+
if (label) {
|
|
590
|
+
lines.push(theme.bold(label));
|
|
591
|
+
}
|
|
592
|
+
for (const item of items) {
|
|
593
|
+
const wrappedDesc = this.wrapLine(item.description, descWidth);
|
|
594
|
+
const paddedCommand = item.command.padEnd(commandWidth);
|
|
595
|
+
const commandLabel = theme.primary(paddedCommand);
|
|
596
|
+
const firstLine = wrappedDesc[0] ?? '';
|
|
597
|
+
lines.push(`${indent}${commandLabel} ${this.colorizePaletteText(firstLine, item.tone)}`);
|
|
598
|
+
for (const extra of wrappedDesc.slice(1)) {
|
|
599
|
+
lines.push(`${indent}${' '.repeat(commandWidth)} ${this.colorizePaletteText(extra, item.tone)}`);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (index < grouped.length - 1) {
|
|
603
|
+
lines.push('');
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
return lines.join('\n').trimEnd();
|
|
607
|
+
}
|
|
608
|
+
groupPaletteCommands(commands) {
|
|
609
|
+
const FALLBACK = 'other';
|
|
610
|
+
const groups = new Map();
|
|
611
|
+
for (const item of commands) {
|
|
612
|
+
const key = (item.category ?? FALLBACK).toLowerCase();
|
|
613
|
+
const bucket = groups.get(key) ?? [];
|
|
614
|
+
bucket.push(item);
|
|
615
|
+
groups.set(key, bucket);
|
|
616
|
+
}
|
|
617
|
+
const order = ['configuration', 'workspace', 'diagnostics', 'other'];
|
|
618
|
+
const orderedKeys = [
|
|
619
|
+
...order.filter((key) => groups.has(key)),
|
|
620
|
+
...Array.from(groups.keys()).filter((key) => !order.includes(key)),
|
|
621
|
+
];
|
|
622
|
+
return orderedKeys.map((category) => ({ category, items: groups.get(category) ?? [] }));
|
|
623
|
+
}
|
|
624
|
+
computeCommandColumnWidth(commands, totalWidth, indentWidth) {
|
|
625
|
+
const longest = commands.reduce((max, item) => Math.max(max, this.visibleLength(item.command)), 0);
|
|
626
|
+
const maxAllowed = Math.max(12, Math.min(longest + 2, Math.floor(totalWidth * 0.35)));
|
|
627
|
+
const budget = Math.max(10, totalWidth - indentWidth - DISPLAY_CONSTANTS.MIN_WRAP_WIDTH);
|
|
628
|
+
return Math.min(maxAllowed, budget);
|
|
629
|
+
}
|
|
630
|
+
formatPaletteCategory(category) {
|
|
631
|
+
if (!category)
|
|
632
|
+
return 'Other';
|
|
633
|
+
switch (category.toLowerCase()) {
|
|
634
|
+
case 'configuration': return 'Configuration';
|
|
635
|
+
case 'workspace': return 'Workspace';
|
|
636
|
+
case 'diagnostics': return 'Diagnostics';
|
|
637
|
+
case 'other': return 'Other';
|
|
638
|
+
default: return category[0]?.toUpperCase() + category.slice(1);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
colorizePaletteText(text, tone) {
|
|
642
|
+
switch (tone) {
|
|
643
|
+
case 'warn': return theme.warning(text);
|
|
644
|
+
case 'success': return theme.success(text);
|
|
645
|
+
case 'info': return theme.info(text);
|
|
646
|
+
case 'muted':
|
|
647
|
+
default: return theme.ui.muted(text);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
wrapWithPrefix(text, prefix, options) {
|
|
651
|
+
if (!text) {
|
|
652
|
+
return prefix.trimEnd();
|
|
653
|
+
}
|
|
654
|
+
const width = Math.max(DISPLAY_CONSTANTS.MIN_ACTION_WIDTH, Math.min(this.getColumnWidth(), DISPLAY_CONSTANTS.MAX_ACTION_WIDTH));
|
|
655
|
+
const prefixWidth = this.visibleLength(prefix);
|
|
656
|
+
const available = Math.max(DISPLAY_CONSTANTS.MIN_CONTENT_WIDTH, width - prefixWidth);
|
|
657
|
+
const indent = typeof options?.continuationPrefix === 'string'
|
|
658
|
+
? options.continuationPrefix
|
|
659
|
+
: ' '.repeat(Math.max(0, prefixWidth));
|
|
660
|
+
const segments = text.split('\n');
|
|
661
|
+
const lines = [];
|
|
662
|
+
let usedPrefix = false;
|
|
663
|
+
for (const segment of segments) {
|
|
664
|
+
if (!segment.trim()) {
|
|
665
|
+
if (usedPrefix) {
|
|
666
|
+
lines.push(indent);
|
|
667
|
+
}
|
|
668
|
+
else {
|
|
669
|
+
lines.push(prefix.trimEnd());
|
|
670
|
+
usedPrefix = true;
|
|
671
|
+
}
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
const wrapped = this.wrapLine(segment.trim(), available);
|
|
675
|
+
for (const line of wrapped) {
|
|
676
|
+
lines.push(!usedPrefix ? `${prefix}${line}` : `${indent}${line}`);
|
|
677
|
+
usedPrefix = true;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return lines.join('\n');
|
|
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
|
+
const rendered = [];
|
|
690
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
691
|
+
const segment = lines[index] ?? '';
|
|
692
|
+
const isLast = index === lines.length - 1;
|
|
693
|
+
const { prefix, continuation } = this.buildSubActionPrefixes(status, isLast);
|
|
694
|
+
rendered.push(this.wrapWithPrefix(segment, prefix, { continuationPrefix: continuation }));
|
|
695
|
+
}
|
|
696
|
+
return rendered;
|
|
697
|
+
}
|
|
698
|
+
buildSubActionPrefixes(status, isLast) {
|
|
699
|
+
if (isLast) {
|
|
700
|
+
const colorize = this.resolveStatusColor(status);
|
|
701
|
+
return {
|
|
702
|
+
prefix: ` ${colorize(icons.subaction)} `,
|
|
703
|
+
continuation: ' ',
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
const branch = theme.ui.muted('│');
|
|
707
|
+
return {
|
|
708
|
+
prefix: ` ${branch} `,
|
|
709
|
+
continuation: ` ${branch} `,
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
resolveStatusColor(status) {
|
|
713
|
+
switch (status) {
|
|
714
|
+
case 'success': return theme.success;
|
|
715
|
+
case 'error': return theme.error;
|
|
716
|
+
case 'warning': return theme.warning;
|
|
717
|
+
case 'pending': return theme.info;
|
|
718
|
+
default: return theme.secondary;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
formatActionIcon(status) {
|
|
722
|
+
const colorize = this.resolveStatusColor(status);
|
|
723
|
+
return colorize(`${icons.action}`);
|
|
724
|
+
}
|
|
725
|
+
wrapForRenderer(text) {
|
|
726
|
+
const width = Math.max(DISPLAY_CONSTANTS.MIN_WRAP_WIDTH, Math.min(this.getColumnWidth() - 4, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH));
|
|
727
|
+
const lines = [];
|
|
728
|
+
for (const line of text.split('\n')) {
|
|
729
|
+
const trimmed = line.trimEnd();
|
|
730
|
+
const wrapped = this.wrapLine(trimmed, width);
|
|
731
|
+
lines.push(...wrapped);
|
|
732
|
+
}
|
|
733
|
+
return lines.join('\n').trimEnd();
|
|
734
|
+
}
|
|
735
|
+
wrapLine(text, width) {
|
|
736
|
+
if (width <= 0)
|
|
737
|
+
return [text];
|
|
738
|
+
if (!text)
|
|
739
|
+
return [''];
|
|
740
|
+
if (text.length <= width)
|
|
741
|
+
return [text];
|
|
742
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
743
|
+
if (!words.length)
|
|
744
|
+
return this.chunkWord(text, width);
|
|
745
|
+
const lines = [];
|
|
746
|
+
let current = '';
|
|
747
|
+
for (const word of words) {
|
|
748
|
+
if (!current) {
|
|
749
|
+
if (word.length <= width) {
|
|
750
|
+
current = word;
|
|
751
|
+
}
|
|
752
|
+
else {
|
|
753
|
+
const chunks = this.chunkWord(word, width);
|
|
754
|
+
lines.push(...chunks.slice(0, -1));
|
|
755
|
+
current = chunks[chunks.length - 1] ?? '';
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
else if (current.length + 1 + word.length <= width) {
|
|
759
|
+
current = `${current} ${word}`;
|
|
760
|
+
}
|
|
761
|
+
else {
|
|
762
|
+
lines.push(current);
|
|
763
|
+
if (word.length <= width) {
|
|
764
|
+
current = word;
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
const chunks = this.chunkWord(word, width);
|
|
768
|
+
lines.push(...chunks.slice(0, -1));
|
|
769
|
+
current = chunks[chunks.length - 1] ?? '';
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
if (current) {
|
|
774
|
+
lines.push(current);
|
|
775
|
+
}
|
|
776
|
+
return lines.length ? lines : [''];
|
|
777
|
+
}
|
|
778
|
+
chunkWord(word, width) {
|
|
779
|
+
if (width <= 0 || !word)
|
|
780
|
+
return word ? [word] : [''];
|
|
781
|
+
const chunks = [];
|
|
782
|
+
for (let i = 0; i < word.length; i += width) {
|
|
783
|
+
chunks.push(word.slice(i, i + width));
|
|
784
|
+
}
|
|
785
|
+
return chunks.length > 0 ? chunks : [''];
|
|
786
|
+
}
|
|
787
|
+
visibleLength(value) {
|
|
788
|
+
if (!value)
|
|
789
|
+
return 0;
|
|
790
|
+
return this.stripAnsi(value).length;
|
|
791
|
+
}
|
|
792
|
+
stripAnsi(value) {
|
|
793
|
+
if (!value)
|
|
794
|
+
return '';
|
|
795
|
+
return value.replace(/\u001B\[[0-?]*[ -/]*[@-~]/g, '');
|
|
796
|
+
}
|
|
215
797
|
}
|
|
216
798
|
export const display = new Display();
|
|
217
799
|
//# sourceMappingURL=display.js.map
|