erosolar-cli 2.1.92 → 2.1.94

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.
@@ -14,7 +14,7 @@ export interface CommandSuggestion {
14
14
  description: string;
15
15
  category?: string;
16
16
  }
17
- type CanonicalEventType = 'prompt' | 'thought' | 'stream' | 'tool' | 'build' | 'test' | 'response';
17
+ type CanonicalEventType = 'prompt' | 'thought' | 'stream' | 'tool' | 'tool-result' | 'build' | 'test' | 'response';
18
18
  export type RendererEventType = CanonicalEventType | 'raw' | 'banner' | 'error' | 'streaming' | 'tool-call' | 'tool-result';
19
19
  export interface UnifiedUIRendererOptions {
20
20
  debug?: boolean;
@@ -50,6 +50,7 @@ export declare class UnifiedUIRenderer extends EventEmitter {
50
50
  private hotkeysInToggleLine;
51
51
  private collapsedPaste;
52
52
  private mode;
53
+ private streamingStartTime;
53
54
  private statusMessage;
54
55
  private statusOverride;
55
56
  private statusStreaming;
@@ -129,6 +130,53 @@ export declare class UnifiedUIRenderer extends EventEmitter {
129
130
  private renderEvent;
130
131
  private normalizeEventType;
131
132
  private formatContent;
133
+ /**
134
+ * Format text in Claude Code style: ⏺ prefix with wrapped continuation lines
135
+ * Example:
136
+ * ⏺ The AI ran tools but gave no response. Need to fix
137
+ * the response handling. Let me check where the AI's
138
+ * text response should be displayed:
139
+ */
140
+ private formatClaudeCodeBlock;
141
+ /**
142
+ * Format a tool call in Claude Code style:
143
+ * ⏺ Search(pattern: "foo", path: "src",
144
+ * output_mode: "content", head_limit: 30)
145
+ */
146
+ private formatToolCall;
147
+ /**
148
+ * Parse tool arguments from string like: key: "value", key2: value2
149
+ */
150
+ private parseToolArgs;
151
+ /**
152
+ * Format an argument value (truncate long strings)
153
+ */
154
+ private formatArgValue;
155
+ /**
156
+ * Format a tool result in Claude Code style:
157
+ * ⎿ Found 12 lines (ctrl+o to expand)
158
+ */
159
+ private formatToolResult;
160
+ /**
161
+ * Format a compact tool call: ⏺ Read → file.ts
162
+ */
163
+ private formatCompactToolCall;
164
+ /**
165
+ * Extract a short summary from tool args
166
+ */
167
+ private extractToolSummary;
168
+ /**
169
+ * Format a compact tool result: └─ 42 lines
170
+ */
171
+ private formatCompactToolResult;
172
+ /**
173
+ * Format a compact response with bullet on first line
174
+ */
175
+ private formatCompactResponse;
176
+ /**
177
+ * Format streaming elapsed time in Claude Code style: 3m 30s
178
+ */
179
+ private formatStreamingElapsed;
132
180
  /**
133
181
  * Format a compact conversation block (Claude Code style)
134
182
  * Shows a visual separator with "history" label and ctrl+o hint
@@ -1 +1 @@
1
- {"version":3,"file":"UnifiedUIRenderer.d.ts","sourceRoot":"","sources":["../../src/ui/UnifiedUIRenderer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"UnifiedUIRenderer.d.ts","sourceRoot":"","sources":["../../src/ui/UnifiedUIRenderer.ts"],"names":[],"mappings":"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"}
@@ -56,6 +56,7 @@ export class UnifiedUIRenderer extends EventEmitter {
56
56
  hotkeysInToggleLine = new Set();
57
57
  collapsedPaste = null;
58
58
  mode = 'idle';
59
+ streamingStartTime = null;
59
60
  statusMessage = null;
60
61
  statusOverride = null;
61
62
  statusStreaming = null;
@@ -712,6 +713,7 @@ export class UnifiedUIRenderer extends EventEmitter {
712
713
  normalized === 'thought' ||
713
714
  normalized === 'stream' ||
714
715
  normalized === 'tool' ||
716
+ normalized === 'tool-result' ||
715
717
  normalized === 'build' ||
716
718
  normalized === 'test') {
717
719
  this.hasConversationContent = true;
@@ -862,8 +864,9 @@ export class UnifiedUIRenderer extends EventEmitter {
862
864
  return 'stream';
863
865
  case 'tool':
864
866
  case 'tool-call':
865
- case 'tool-result':
866
867
  return 'tool';
868
+ case 'tool-result':
869
+ return 'tool-result';
867
870
  case 'build':
868
871
  return 'build';
869
872
  case 'test':
@@ -889,62 +892,291 @@ export class UnifiedUIRenderer extends EventEmitter {
889
892
  const lines = event.content.split('\n').map(line => line.trimEnd());
890
893
  return `${lines.join('\n')}\n`;
891
894
  }
892
- // Tighter spacing: single newline after each event (not \n before AND after)
895
+ // Compact, user-friendly formatting
893
896
  switch (event.type) {
894
897
  case 'prompt':
895
- // User prompt with highlighted prefix
898
+ // User prompt - just the text (prompt box handles styling)
896
899
  return `${theme.primary('>')} ${event.content}\n`;
897
900
  case 'thought': {
898
901
  // Filter out generic/useless thought messages
899
902
  const contentLower = event.content.toLowerCase();
900
903
  const uselessPatterns = [
901
- 'ready to assist',
902
- 'no files read',
903
- 'no task specified',
904
- 'waiting for',
905
- 'standing by',
906
- 'here to help',
907
- 'how can i help',
908
- 'what would you like',
904
+ 'ready to assist', 'no files read', 'no task specified',
905
+ 'waiting for', 'standing by', 'here to help',
906
+ 'how can i help', 'what would you like', 'thinking',
907
+ 'set_status', 'completed',
909
908
  ];
910
909
  if (uselessPatterns.some(p => contentLower.includes(p))) {
911
910
  return ''; // Don't display useless thoughts
912
911
  }
913
- // Thinking indicator with subtle cyan styling
914
- const thinkIcon = theme.thinking?.icon ? theme.thinking.icon('') : theme.info('◐');
915
- return `${thinkIcon} ${theme.ui.muted(event.content)}\n`;
912
+ // Compact thought: just the text, no extra spacing
913
+ return `${theme.ui.muted('')} ${theme.ui.muted(event.content)}\n`;
916
914
  }
917
915
  case 'tool': {
918
- // Tool calls with distinct icon and highlighted name
919
- const toolIcon = theme.tool('');
920
- // Parse tool name if present in format "ToolName(...)" or "ToolName"
921
- const content = event.content.replace(/^[⏺⚙]\s*/, ''); // Remove existing icons
922
- const toolMatch = content.match(/^(\w+)(\(.*)?$/);
923
- if (toolMatch) {
924
- const toolName = theme.success(toolMatch[1]);
925
- const toolArgs = toolMatch[2] ? theme.ui.muted(toolMatch[2]) : '';
926
- return `${toolIcon} ${toolName}${toolArgs}\n`;
927
- }
928
- return `${bullet} ${content}\n`;
916
+ // Compact tool display: ⚡ToolName result
917
+ const content = event.content.replace(/^[⏺⚙○]\s*/, '');
918
+ return this.formatCompactToolCall(content);
919
+ }
920
+ case 'tool-result': {
921
+ // Inline result: └─ summary
922
+ return this.formatCompactToolResult(event.content);
929
923
  }
930
924
  case 'build':
931
- // Build output with wrench icon
932
- return `${theme.warning('🔨')} ${event.content}\n`;
925
+ return `${bullet} ${theme.warning('Build')} ${theme.ui.muted('→')} ${event.content}\n`;
933
926
  case 'test':
934
- // Test output with check icon
935
- return `${theme.info('🧪')} ${event.content}\n`;
927
+ return `${bullet} ${theme.info('Test')} ${theme.ui.muted('→')} ${event.content}\n`;
936
928
  case 'stream':
937
929
  return event.content;
938
930
  case 'response':
939
931
  default: {
940
- // Claude Code style: for first line, indent rest
941
- const lines = event.content.split('\n');
942
- return (lines
943
- .map((line, i) => (i === 0 ? `${bullet} ${line}` : ` ${line}`))
944
- .join('\n') + '\n');
932
+ // Clean response without excessive bullets
933
+ return this.formatCompactResponse(event.content);
945
934
  }
946
935
  }
947
936
  }
937
+ /**
938
+ * Format text in Claude Code style: ⏺ prefix with wrapped continuation lines
939
+ * Example:
940
+ * ⏺ The AI ran tools but gave no response. Need to fix
941
+ * the response handling. Let me check where the AI's
942
+ * text response should be displayed:
943
+ */
944
+ formatClaudeCodeBlock(content) {
945
+ const bullet = '⏺';
946
+ const maxWidth = Math.min(this.cols - 4, 56); // Leave room for prefix and margins
947
+ const lines = content.split('\n');
948
+ const result = [];
949
+ for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
950
+ const line = lines[lineIdx];
951
+ if (!line.trim()) {
952
+ result.push('');
953
+ continue;
954
+ }
955
+ // Word-wrap each line
956
+ const words = line.split(/(\s+)/);
957
+ let currentLine = '';
958
+ for (const word of words) {
959
+ if ((currentLine + word).length > maxWidth && currentLine.trim()) {
960
+ // First line of this paragraph gets ⏺, rest get indent
961
+ const prefix = result.length === 0 && lineIdx === 0 ? `${bullet} ` : ' ';
962
+ result.push(`${prefix}${currentLine.trimEnd()}`);
963
+ currentLine = word.trimStart();
964
+ }
965
+ else {
966
+ currentLine += word;
967
+ }
968
+ }
969
+ if (currentLine.trim()) {
970
+ const prefix = result.length === 0 && lineIdx === 0 ? `${bullet} ` : ' ';
971
+ result.push(`${prefix}${currentLine.trimEnd()}`);
972
+ }
973
+ }
974
+ return result.join('\n') + '\n';
975
+ }
976
+ /**
977
+ * Format a tool call in Claude Code style:
978
+ * ⏺ Search(pattern: "foo", path: "src",
979
+ * output_mode: "content", head_limit: 30)
980
+ */
981
+ formatToolCall(content) {
982
+ const bullet = '⏺';
983
+ // Parse tool name and arguments
984
+ const match = content.match(/^(\w+)\((.*)\)$/s);
985
+ if (!match) {
986
+ // Simple format without args
987
+ const nameMatch = content.match(/^(\w+)/);
988
+ if (nameMatch) {
989
+ return `${bullet} ${theme.info(nameMatch[1])}\n`;
990
+ }
991
+ return `${bullet} ${content}\n`;
992
+ }
993
+ const toolName = match[1];
994
+ const argsStr = match[2];
995
+ const maxWidth = Math.min(this.cols - 4, 56);
996
+ // Format: ⏺ ToolName(args...)
997
+ const prefix = `${bullet} ${theme.info(toolName)}(`;
998
+ const prefixLen = toolName.length + 3; // "⏺ ToolName(" visible length
999
+ const indent = ' '.repeat(prefixLen + 4); // Extra indent for wrapped args
1000
+ // Parse and format arguments
1001
+ const args = this.parseToolArgs(argsStr);
1002
+ if (args.length === 0) {
1003
+ return `${prefix})\n`;
1004
+ }
1005
+ const lines = [];
1006
+ let currentLine = prefix;
1007
+ for (let i = 0; i < args.length; i++) {
1008
+ const arg = args[i];
1009
+ const argText = `${theme.ui.muted(arg.key + ':')} ${this.formatArgValue(arg.value)}`;
1010
+ const separator = i < args.length - 1 ? ', ' : ')';
1011
+ // Check if this arg fits on current line
1012
+ const testLine = currentLine + argText + separator;
1013
+ if (this.stripAnsi(testLine).length > maxWidth && currentLine !== prefix) {
1014
+ lines.push(currentLine.trimEnd());
1015
+ currentLine = indent + argText + separator;
1016
+ }
1017
+ else {
1018
+ currentLine += argText + separator;
1019
+ }
1020
+ }
1021
+ if (currentLine.trim()) {
1022
+ lines.push(currentLine.trimEnd());
1023
+ }
1024
+ return lines.join('\n') + '\n';
1025
+ }
1026
+ /**
1027
+ * Parse tool arguments from string like: key: "value", key2: value2
1028
+ */
1029
+ parseToolArgs(argsStr) {
1030
+ const args = [];
1031
+ // Simple regex to extract key: value pairs
1032
+ const regex = /(\w+):\s*("(?:[^"\\]|\\.)*"|[^,\)]+)/g;
1033
+ let match;
1034
+ while ((match = regex.exec(argsStr)) !== null) {
1035
+ args.push({ key: match[1], value: match[2].trim() });
1036
+ }
1037
+ return args;
1038
+ }
1039
+ /**
1040
+ * Format an argument value (truncate long strings)
1041
+ */
1042
+ formatArgValue(value) {
1043
+ // Remove surrounding quotes if present
1044
+ const isQuoted = value.startsWith('"') && value.endsWith('"');
1045
+ const inner = isQuoted ? value.slice(1, -1) : value;
1046
+ // Truncate long values
1047
+ const maxLen = 40;
1048
+ const truncated = inner.length > maxLen ? inner.slice(0, maxLen - 3) + '...' : inner;
1049
+ return isQuoted ? `"${truncated}"` : truncated;
1050
+ }
1051
+ /**
1052
+ * Format a tool result in Claude Code style:
1053
+ * ⎿ Found 12 lines (ctrl+o to expand)
1054
+ */
1055
+ formatToolResult(content) {
1056
+ // Check if this is a summary line (e.g., "Found X lines")
1057
+ const summaryMatch = content.match(/^(Found \d+ (?:lines?|files?|matches?)|Read \d+ lines?|Wrote \d+ lines?|Edited|Created|Deleted)/i);
1058
+ if (summaryMatch) {
1059
+ return ` ${theme.ui.muted('⎿')} ${content} ${theme.ui.muted('(ctrl+o to expand)')}\n`;
1060
+ }
1061
+ // For other results, show truncated preview
1062
+ const lines = content.split('\n');
1063
+ if (lines.length > 3) {
1064
+ const preview = lines.slice(0, 2).join('\n');
1065
+ return ` ${theme.ui.muted('⎿')} ${preview}\n ${theme.ui.muted(`... ${lines.length - 2} more lines (ctrl+o to expand)`)}\n`;
1066
+ }
1067
+ return ` ${theme.ui.muted('⎿')} ${content}\n`;
1068
+ }
1069
+ /**
1070
+ * Format a compact tool call: ⏺ Read → file.ts
1071
+ */
1072
+ formatCompactToolCall(content) {
1073
+ const bullet = '⏺';
1074
+ // Parse tool name and args
1075
+ const match = content.match(/^(\w+)\s*(?:\((.*)\))?$/s);
1076
+ if (!match) {
1077
+ return `${bullet} ${content}\n`;
1078
+ }
1079
+ const toolName = match[1];
1080
+ const argsStr = match[2] || '';
1081
+ // Extract the most important arg for summary
1082
+ const summary = this.extractToolSummary(toolName, argsStr);
1083
+ if (summary) {
1084
+ return `${bullet} ${theme.info(toolName)} ${theme.ui.muted('→')} ${summary}\n`;
1085
+ }
1086
+ return `${bullet} ${theme.info(toolName)}\n`;
1087
+ }
1088
+ /**
1089
+ * Extract a short summary from tool args
1090
+ */
1091
+ extractToolSummary(toolName, argsStr) {
1092
+ const tool = toolName.toLowerCase();
1093
+ // Extract path/file for file operations
1094
+ if (['read', 'write', 'edit', 'glob', 'grep', 'search'].includes(tool)) {
1095
+ const pathMatch = argsStr.match(/(?:path|file_path|pattern):\s*"([^"]+)"/);
1096
+ if (pathMatch) {
1097
+ const path = pathMatch[1];
1098
+ // Shorten long paths
1099
+ const short = path.length > 30 ? '…' + path.slice(-28) : path;
1100
+ return theme.ui.muted(short);
1101
+ }
1102
+ }
1103
+ // Extract command for bash
1104
+ if (tool === 'bash') {
1105
+ const cmdMatch = argsStr.match(/command:\s*"([^"]+)"/);
1106
+ if (cmdMatch) {
1107
+ const cmd = cmdMatch[1];
1108
+ const short = cmd.length > 40 ? cmd.slice(0, 37) + '…' : cmd;
1109
+ return theme.ui.muted(short);
1110
+ }
1111
+ }
1112
+ return null;
1113
+ }
1114
+ /**
1115
+ * Format a compact tool result: └─ 42 lines
1116
+ */
1117
+ formatCompactToolResult(content) {
1118
+ // Parse common result patterns
1119
+ const lineMatch = content.match(/(\d+)\s*lines?/i);
1120
+ const fileMatch = content.match(/(\d+)\s*(?:files?|matches?)/i);
1121
+ const successMatch = content.match(/^(success|ok|done|completed|written|edited|created)/i);
1122
+ if (lineMatch) {
1123
+ return ` ${theme.ui.muted('└─')} ${theme.success(lineMatch[1])} ${theme.ui.muted('lines')}\n`;
1124
+ }
1125
+ if (fileMatch) {
1126
+ return ` ${theme.ui.muted('└─')} ${theme.success(fileMatch[1])} ${theme.ui.muted('files')}\n`;
1127
+ }
1128
+ if (successMatch) {
1129
+ return ` ${theme.ui.muted('└─')} ${theme.success('✓')}\n`;
1130
+ }
1131
+ // Truncate long results
1132
+ const short = content.length > 50 ? content.slice(0, 47) + '…' : content;
1133
+ return ` ${theme.ui.muted('└─')} ${theme.ui.muted(short)}\n`;
1134
+ }
1135
+ /**
1136
+ * Format a compact response with bullet on first line
1137
+ */
1138
+ formatCompactResponse(content) {
1139
+ const bullet = '⏺';
1140
+ const trimmed = content.trim();
1141
+ if (!trimmed)
1142
+ return '';
1143
+ // Single line responses - bullet prefix
1144
+ if (!trimmed.includes('\n') && trimmed.length < 80) {
1145
+ return `${bullet} ${trimmed}\n`;
1146
+ }
1147
+ // Multi-line: bullet on first, indent continuation
1148
+ const lines = trimmed.split('\n');
1149
+ const result = [];
1150
+ for (let i = 0; i < lines.length; i++) {
1151
+ const line = lines[i].trimEnd();
1152
+ if (!line) {
1153
+ result.push('');
1154
+ }
1155
+ else if (i === 0) {
1156
+ result.push(`${bullet} ${line}`);
1157
+ }
1158
+ else {
1159
+ result.push(` ${line}`);
1160
+ }
1161
+ }
1162
+ return result.join('\n') + '\n';
1163
+ }
1164
+ /**
1165
+ * Format streaming elapsed time in Claude Code style: 3m 30s
1166
+ */
1167
+ formatStreamingElapsed() {
1168
+ if (!this.streamingStartTime)
1169
+ return null;
1170
+ const elapsed = Math.floor((Date.now() - this.streamingStartTime) / 1000);
1171
+ if (elapsed < 5)
1172
+ return null; // Don't show for very short durations
1173
+ const mins = Math.floor(elapsed / 60);
1174
+ const secs = elapsed % 60;
1175
+ if (mins > 0) {
1176
+ return `${mins}m ${secs}s`;
1177
+ }
1178
+ return `${secs}s`;
1179
+ }
948
1180
  /**
949
1181
  * Format a compact conversation block (Claude Code style)
950
1182
  * Shows a visual separator with "history" label and ctrl+o hint
@@ -980,11 +1212,13 @@ export class UnifiedUIRenderer extends EventEmitter {
980
1212
  setMode(mode) {
981
1213
  const wasStreaming = this.mode === 'streaming';
982
1214
  this.mode = mode;
983
- // Start/stop spinner animation based on streaming state
1215
+ // Track streaming start time for elapsed display
984
1216
  if (mode === 'streaming' && !wasStreaming) {
1217
+ this.streamingStartTime = Date.now();
985
1218
  this.startSpinnerAnimation();
986
1219
  }
987
1220
  else if (mode === 'idle' && wasStreaming) {
1221
+ this.streamingStartTime = null;
988
1222
  this.stopSpinnerAnimation();
989
1223
  }
990
1224
  if (wasStreaming && mode === 'idle' && !this.lastOutputEndedWithNewline) {
@@ -1204,11 +1438,14 @@ export class UnifiedUIRenderer extends EventEmitter {
1204
1438
  const maxWidth = this.safeWidth();
1205
1439
  // Simple horizontal divider - clean and reliable
1206
1440
  const divider = theme.ui.muted('─'.repeat(Math.min(maxWidth, 56)));
1207
- // Activity line (only when streaming) - friendly animated indicator
1441
+ // Activity line (only when streaming) - Claude Code style: ✻ Determining…
1208
1442
  if (this.mode === 'streaming' && this.activityMessage) {
1209
- const spinnerChars = ['○', '◔', '◑', '◕', '●', '◕', '◑', '◔'];
1210
- const spinnerChar = spinnerChars[this.spinnerFrame % spinnerChars.length] ?? '';
1211
- const activityLine = `${theme.info(spinnerChar)} ${this.activityMessage}… ${theme.ui.muted('(esc to pause)')}`;
1443
+ // Animated sparkle like Claude Code
1444
+ const spinnerChars = ['✱', '✲', '✳', '✴', '', '✶', '✷', '✸'];
1445
+ const spinnerChar = spinnerChars[this.spinnerFrame % spinnerChars.length] ?? '✻';
1446
+ const elapsed = this.formatStreamingElapsed();
1447
+ const elapsedStr = elapsed ? ` ${theme.ui.muted(`· ${elapsed}`)}` : '';
1448
+ const activityLine = `${theme.info(spinnerChar)} ${this.activityMessage}…${elapsedStr} ${theme.ui.muted('(esc to interrupt)')}`;
1212
1449
  lines.push(this.truncateLine(activityLine, maxWidth));
1213
1450
  }
1214
1451
  // Top divider