erosolar-cli 1.7.13 → 1.7.15

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.
Files changed (65) hide show
  1. package/dist/core/responseVerifier.d.ts +79 -0
  2. package/dist/core/responseVerifier.d.ts.map +1 -0
  3. package/dist/core/responseVerifier.js +443 -0
  4. package/dist/core/responseVerifier.js.map +1 -0
  5. package/dist/shell/interactiveShell.d.ts +5 -0
  6. package/dist/shell/interactiveShell.d.ts.map +1 -1
  7. package/dist/shell/interactiveShell.js +45 -14
  8. package/dist/shell/interactiveShell.js.map +1 -1
  9. package/dist/ui/ShellUIAdapter.d.ts +3 -0
  10. package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
  11. package/dist/ui/ShellUIAdapter.js +4 -10
  12. package/dist/ui/ShellUIAdapter.js.map +1 -1
  13. package/dist/ui/display.d.ts +15 -0
  14. package/dist/ui/display.d.ts.map +1 -1
  15. package/dist/ui/display.js +57 -0
  16. package/dist/ui/display.js.map +1 -1
  17. package/dist/ui/persistentPrompt.d.ts +4 -0
  18. package/dist/ui/persistentPrompt.d.ts.map +1 -1
  19. package/dist/ui/persistentPrompt.js +10 -11
  20. package/dist/ui/persistentPrompt.js.map +1 -1
  21. package/package.json +1 -1
  22. package/dist/bin/core/agent.js +0 -362
  23. package/dist/bin/core/agentProfileManifest.js +0 -187
  24. package/dist/bin/core/agentProfiles.js +0 -34
  25. package/dist/bin/core/agentRulebook.js +0 -135
  26. package/dist/bin/core/agentSchemaLoader.js +0 -233
  27. package/dist/bin/core/contextManager.js +0 -412
  28. package/dist/bin/core/contextWindow.js +0 -122
  29. package/dist/bin/core/customCommands.js +0 -80
  30. package/dist/bin/core/errors/apiKeyErrors.js +0 -114
  31. package/dist/bin/core/errors/errorTypes.js +0 -340
  32. package/dist/bin/core/errors/safetyValidator.js +0 -304
  33. package/dist/bin/core/errors.js +0 -32
  34. package/dist/bin/core/modelDiscovery.js +0 -755
  35. package/dist/bin/core/preferences.js +0 -224
  36. package/dist/bin/core/schemaValidator.js +0 -92
  37. package/dist/bin/core/secretStore.js +0 -199
  38. package/dist/bin/core/sessionStore.js +0 -187
  39. package/dist/bin/core/toolRuntime.js +0 -290
  40. package/dist/bin/core/types.js +0 -1
  41. package/dist/bin/shell/bracketedPasteManager.js +0 -350
  42. package/dist/bin/shell/fileChangeTracker.js +0 -65
  43. package/dist/bin/shell/interactiveShell.js +0 -2908
  44. package/dist/bin/shell/liveStatus.js +0 -78
  45. package/dist/bin/shell/shellApp.js +0 -290
  46. package/dist/bin/shell/systemPrompt.js +0 -60
  47. package/dist/bin/shell/updateManager.js +0 -108
  48. package/dist/bin/ui/ShellUIAdapter.js +0 -459
  49. package/dist/bin/ui/UnifiedUIController.js +0 -183
  50. package/dist/bin/ui/animation/AnimationScheduler.js +0 -430
  51. package/dist/bin/ui/codeHighlighter.js +0 -854
  52. package/dist/bin/ui/designSystem.js +0 -121
  53. package/dist/bin/ui/display.js +0 -1222
  54. package/dist/bin/ui/interrupts/InterruptManager.js +0 -437
  55. package/dist/bin/ui/layout.js +0 -139
  56. package/dist/bin/ui/orchestration/StatusOrchestrator.js +0 -403
  57. package/dist/bin/ui/outputMode.js +0 -38
  58. package/dist/bin/ui/persistentPrompt.js +0 -183
  59. package/dist/bin/ui/richText.js +0 -338
  60. package/dist/bin/ui/shortcutsHelp.js +0 -87
  61. package/dist/bin/ui/telemetry/UITelemetry.js +0 -443
  62. package/dist/bin/ui/textHighlighter.js +0 -210
  63. package/dist/bin/ui/theme.js +0 -116
  64. package/dist/bin/ui/toolDisplay.js +0 -423
  65. package/dist/bin/ui/toolDisplayAdapter.js +0 -357
@@ -1,403 +0,0 @@
1
- /**
2
- * StatusOrchestrator - Unified status management system
3
- * Coordinates between tool execution, live status tracking, and overlay display
4
- */
5
- import { EventEmitter } from 'events';
6
- export class StatusOrchestrator extends EventEmitter {
7
- constructor() {
8
- super();
9
- this.statusListeners = new Set();
10
- this.context = {
11
- base: null,
12
- overrides: new Map(),
13
- tools: new Map(),
14
- animations: new Map(),
15
- interrupts: {
16
- pending: [],
17
- active: null,
18
- },
19
- };
20
- // Default priority resolver
21
- this.priorityResolver = (a, b) => {
22
- const tonePriority = {
23
- danger: 4,
24
- warning: 3,
25
- success: 2,
26
- info: 1,
27
- };
28
- const aPriority = tonePriority[a.tone || 'info'];
29
- const bPriority = tonePriority[b.tone || 'info'];
30
- return bPriority - aPriority;
31
- };
32
- }
33
- /**
34
- * Set base status
35
- */
36
- setBaseStatus(status) {
37
- this.context.base = status;
38
- this.emitEvent({
39
- type: 'status.base.changed',
40
- timestamp: Date.now(),
41
- data: { status },
42
- });
43
- }
44
- /**
45
- * Push status override
46
- */
47
- pushOverride(id, status) {
48
- this.context.overrides.set(id, status);
49
- this.emitEvent({
50
- type: 'status.override.pushed',
51
- timestamp: Date.now(),
52
- data: { id, status },
53
- });
54
- }
55
- /**
56
- * Clear status override
57
- */
58
- clearOverride(id) {
59
- const removed = this.context.overrides.delete(id);
60
- if (removed) {
61
- this.emitEvent({
62
- type: 'status.override.cleared',
63
- timestamp: Date.now(),
64
- data: { id },
65
- });
66
- }
67
- }
68
- /**
69
- * Handle tool lifecycle events
70
- */
71
- onToolStart(toolCall) {
72
- const toolStatus = {
73
- toolId: toolCall.id,
74
- tool: toolCall.name,
75
- status: 'starting',
76
- description: this.describeToolOperation(toolCall),
77
- startedAt: Date.now(),
78
- updatedAt: Date.now(),
79
- tone: this.getToolTone(toolCall.name),
80
- };
81
- this.context.tools.set(toolCall.id, toolStatus);
82
- this.emitEvent({
83
- type: 'tool.start',
84
- timestamp: Date.now(),
85
- data: { toolCall, toolStatus },
86
- });
87
- // Update to running status after a brief delay
88
- setTimeout(() => {
89
- const status = this.context.tools.get(toolCall.id);
90
- if (status && status.status === 'starting') {
91
- status.status = 'running';
92
- status.updatedAt = Date.now();
93
- this.emitEvent({
94
- type: 'tool.progress',
95
- timestamp: Date.now(),
96
- data: { toolCall, toolStatus: status },
97
- });
98
- }
99
- }, 100);
100
- }
101
- /**
102
- * Update tool progress
103
- */
104
- onToolProgress(toolId, progress) {
105
- const toolStatus = this.context.tools.get(toolId);
106
- if (!toolStatus)
107
- return;
108
- toolStatus.progress = {
109
- current: progress.current,
110
- total: progress.total,
111
- percentage: Math.round((progress.current / progress.total) * 100),
112
- };
113
- if (progress.message) {
114
- toolStatus.detail = progress.message;
115
- }
116
- toolStatus.updatedAt = Date.now();
117
- this.emitEvent({
118
- type: 'tool.progress',
119
- timestamp: Date.now(),
120
- data: { toolId, toolStatus, progress },
121
- });
122
- }
123
- /**
124
- * Handle tool completion
125
- */
126
- onToolComplete(toolId, result) {
127
- const toolStatus = this.context.tools.get(toolId);
128
- if (!toolStatus)
129
- return;
130
- toolStatus.status = 'completed';
131
- toolStatus.updatedAt = Date.now();
132
- this.emitEvent({
133
- type: 'tool.complete',
134
- timestamp: Date.now(),
135
- data: { toolId, toolStatus, result },
136
- });
137
- // Remove from active tools after animation
138
- setTimeout(() => {
139
- this.context.tools.delete(toolId);
140
- }, 1000);
141
- }
142
- /**
143
- * Handle tool error
144
- */
145
- onToolError(toolId, error) {
146
- const toolStatus = this.context.tools.get(toolId);
147
- if (!toolStatus)
148
- return;
149
- const errorMessage = error instanceof Error ? error.message : String(error);
150
- toolStatus.status = 'error';
151
- toolStatus.tone = 'danger';
152
- toolStatus.detail = errorMessage || 'An error occurred';
153
- toolStatus.updatedAt = Date.now();
154
- this.emitEvent({
155
- type: 'tool.error',
156
- timestamp: Date.now(),
157
- data: { toolId, toolStatus, error },
158
- });
159
- // Remove from active tools after delay
160
- setTimeout(() => {
161
- this.context.tools.delete(toolId);
162
- }, 2000);
163
- }
164
- /**
165
- * Queue an interrupt
166
- */
167
- queueInterrupt(interrupt) {
168
- const id = `interrupt-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
169
- const fullInterrupt = {
170
- ...interrupt,
171
- id,
172
- timestamp: Date.now(),
173
- };
174
- // Insert based on priority
175
- const index = this.context.interrupts.pending.findIndex((i) => i.priority < interrupt.priority);
176
- if (index === -1) {
177
- this.context.interrupts.pending.push(fullInterrupt);
178
- }
179
- else {
180
- this.context.interrupts.pending.splice(index, 0, fullInterrupt);
181
- }
182
- this.emitEvent({
183
- type: 'interrupt.received',
184
- timestamp: Date.now(),
185
- data: { interrupt: fullInterrupt },
186
- });
187
- // Process interrupt queue
188
- this.processInterrupts();
189
- return id;
190
- }
191
- /**
192
- * Process pending interrupts
193
- */
194
- processInterrupts() {
195
- if (this.context.interrupts.active || this.context.interrupts.pending.length === 0) {
196
- return;
197
- }
198
- const interrupt = this.context.interrupts.pending.shift();
199
- if (!interrupt)
200
- return;
201
- this.context.interrupts.active = interrupt;
202
- // Auto-clear interrupt after 3 seconds if not cleared manually
203
- setTimeout(() => {
204
- if (this.context.interrupts.active?.id === interrupt.id) {
205
- this.clearInterrupt(interrupt.id);
206
- }
207
- }, 3000);
208
- }
209
- /**
210
- * Clear an active interrupt
211
- */
212
- clearInterrupt(id) {
213
- if (this.context.interrupts.active?.id === id) {
214
- this.context.interrupts.active = null;
215
- this.processInterrupts(); // Process next in queue
216
- }
217
- }
218
- /**
219
- * Get the current aggregated status
220
- */
221
- getCurrentStatus() {
222
- // Priority order:
223
- // 1. Active interrupt
224
- // 2. Active tools
225
- // 3. Overrides
226
- // 4. Base status
227
- if (this.context.interrupts.active) {
228
- return {
229
- text: this.context.interrupts.active.message,
230
- tone: 'warning',
231
- startedAt: this.context.interrupts.active.timestamp,
232
- };
233
- }
234
- // Get most important tool status
235
- if (this.context.tools.size > 0) {
236
- const toolStatuses = Array.from(this.context.tools.values());
237
- const activeTools = toolStatuses.filter((t) => t.status === 'running');
238
- if (activeTools.length > 0) {
239
- const mostRecent = activeTools.sort((a, b) => b.updatedAt - a.updatedAt)[0];
240
- if (mostRecent) {
241
- return {
242
- text: mostRecent.description,
243
- detail: mostRecent.detail,
244
- tone: mostRecent.tone,
245
- startedAt: mostRecent.startedAt,
246
- };
247
- }
248
- }
249
- }
250
- // Get highest priority override
251
- if (this.context.overrides.size > 0) {
252
- const overrides = Array.from(this.context.overrides.values());
253
- const sorted = overrides.sort(this.priorityResolver);
254
- return sorted[0] || null;
255
- }
256
- return this.context.base;
257
- }
258
- /**
259
- * Register animation
260
- */
261
- registerAnimation(id, type, data) {
262
- this.context.animations.set(id, {
263
- id,
264
- type,
265
- frame: 0,
266
- startedAt: Date.now(),
267
- data,
268
- });
269
- }
270
- /**
271
- * Update animation frame
272
- */
273
- updateAnimationFrame(id) {
274
- const animation = this.context.animations.get(id);
275
- if (animation) {
276
- animation.frame++;
277
- this.emitEvent({
278
- type: 'animation.frame',
279
- timestamp: Date.now(),
280
- data: { animation },
281
- });
282
- }
283
- }
284
- /**
285
- * Clear animation
286
- */
287
- clearAnimation(id) {
288
- this.context.animations.delete(id);
289
- }
290
- /**
291
- * Subscribe to status events
292
- */
293
- subscribe(listener) {
294
- this.statusListeners.add(listener);
295
- return () => this.statusListeners.delete(listener);
296
- }
297
- /**
298
- * Emit status event
299
- */
300
- emitEvent(event) {
301
- this.emit(event.type, event);
302
- this.statusListeners.forEach((listener) => listener(event));
303
- }
304
- /**
305
- * Get tool operation description
306
- */
307
- describeToolOperation(toolCall) {
308
- const params = toolCall.arguments;
309
- switch (toolCall.name) {
310
- case 'read_file':
311
- return `Reading ${this.truncatePath(params.path)}`;
312
- case 'write_file':
313
- return `Writing ${this.truncatePath(params.path)}`;
314
- case 'edit_file':
315
- return `Editing ${this.truncatePath(params.path)}`;
316
- case 'bash':
317
- return `Running: ${this.truncateCommand(params.command)}`;
318
- case 'search_files':
319
- return `Searching for: ${this.truncateQuery(params.query)}`;
320
- case 'list_directory':
321
- return `Listing ${this.truncatePath(params.path || '.')}`;
322
- default:
323
- return `Running ${toolCall.name}`;
324
- }
325
- }
326
- /**
327
- * Get tone for tool type
328
- */
329
- getToolTone(tool) {
330
- const dangerousTools = ['bash', 'write_file', 'edit_file', 'delete_file'];
331
- const warningTools = ['install', 'uninstall', 'update'];
332
- if (dangerousTools.includes(tool)) {
333
- return 'warning';
334
- }
335
- if (warningTools.includes(tool)) {
336
- return 'warning';
337
- }
338
- return 'info';
339
- }
340
- /**
341
- * Helper to truncate paths
342
- */
343
- truncatePath(path, maxLength = 40) {
344
- if (!path)
345
- return '';
346
- if (path.length <= maxLength)
347
- return path;
348
- const parts = path.split('/');
349
- if (parts.length <= 2) {
350
- return '...' + path.slice(-(maxLength - 3));
351
- }
352
- // Keep first and last parts
353
- const first = parts[0] || '';
354
- const last = parts[parts.length - 1] || '';
355
- const middle = '...';
356
- const result = `${first}/${middle}/${last}`;
357
- if (result.length > maxLength) {
358
- return '...' + last.slice(-(maxLength - 3));
359
- }
360
- return result;
361
- }
362
- /**
363
- * Helper to truncate commands
364
- */
365
- truncateCommand(command, maxLength = 40) {
366
- if (!command)
367
- return '';
368
- if (command.length <= maxLength)
369
- return command;
370
- return command.slice(0, maxLength - 3) + '...';
371
- }
372
- /**
373
- * Helper to truncate search queries
374
- */
375
- truncateQuery(query, maxLength = 30) {
376
- if (!query)
377
- return '';
378
- if (query.length <= maxLength)
379
- return query;
380
- return query.slice(0, maxLength - 3) + '...';
381
- }
382
- /**
383
- * Get full context for debugging
384
- */
385
- getContext() {
386
- return { ...this.context };
387
- }
388
- /**
389
- * Reset all status
390
- */
391
- reset() {
392
- this.context = {
393
- base: null,
394
- overrides: new Map(),
395
- tools: new Map(),
396
- animations: new Map(),
397
- interrupts: {
398
- pending: [],
399
- active: null,
400
- },
401
- };
402
- }
403
- }
@@ -1,38 +0,0 @@
1
- /**
2
- * Output mode configuration for terminal UI
3
- *
4
- * Controls whether to use decorative box-drawing characters or plain text.
5
- * Plain mode outputs clipboard-friendly text without Unicode borders.
6
- *
7
- * Environment variable: EROSOLAR_PLAIN_OUTPUT=true
8
- */
9
- let _plainMode = null;
10
- /**
11
- * Check if plain output mode is enabled.
12
- * Plain mode outputs text without box-drawing characters for clean clipboard copying.
13
- */
14
- export function isPlainOutputMode() {
15
- if (_plainMode !== null) {
16
- return _plainMode;
17
- }
18
- const envValue = process.env['EROSOLAR_PLAIN_OUTPUT'];
19
- if (envValue !== undefined) {
20
- _plainMode = ['true', '1', 'yes', 'on'].includes(envValue.toLowerCase());
21
- return _plainMode;
22
- }
23
- // Default to plain output unless explicitly disabled
24
- _plainMode = true;
25
- return _plainMode;
26
- }
27
- /**
28
- * Override the plain output mode setting (useful for testing)
29
- */
30
- export function setPlainOutputMode(enabled) {
31
- _plainMode = enabled;
32
- }
33
- /**
34
- * Reset plain output mode to check environment variable again
35
- */
36
- export function resetPlainOutputMode() {
37
- _plainMode = null;
38
- }
@@ -1,183 +0,0 @@
1
- /**
2
- * PersistentPrompt - Minimal, stable chat input at bottom of terminal
3
- *
4
- * Design principles:
5
- * - Simple: No complex cursor manipulation or multi-line rendering
6
- * - Stable: Uses standard readline without fighting it
7
- * - Reliable: Clear separation between output area and input area
8
- */
9
- import * as readline from 'node:readline';
10
- import { theme } from './theme.js';
11
- /**
12
- * Minimal prompt manager that doesn't fight with readline
13
- */
14
- export class PersistentPrompt {
15
- constructor(writeStream, promptText = '> ') {
16
- this.isEnabled = true;
17
- this.writeStream = writeStream;
18
- this.promptText = promptText;
19
- this.statusBarState = {};
20
- this.promptState = {
21
- userInput: '',
22
- cursorPosition: 0,
23
- isVisible: true,
24
- };
25
- }
26
- /**
27
- * Update the prompt text
28
- */
29
- setPromptText(text) {
30
- this.promptText = text;
31
- }
32
- /**
33
- * Get the formatted prompt string
34
- */
35
- getPrompt() {
36
- return this.promptText;
37
- }
38
- /**
39
- * Update user input state (for tracking only - readline handles display)
40
- */
41
- updateInput(input, cursorPos) {
42
- this.promptState.userInput = input;
43
- this.promptState.cursorPosition = cursorPos;
44
- }
45
- /**
46
- * Update status bar information
47
- */
48
- updateStatusBar(state) {
49
- this.statusBarState = { ...this.statusBarState, ...state };
50
- }
51
- /**
52
- * Show a status line above the prompt (call before readline.prompt())
53
- */
54
- showStatus() {
55
- if (!this.isEnabled)
56
- return;
57
- const status = this.buildStatusLine();
58
- if (status) {
59
- this.writeStream.write('\n' + status + '\n');
60
- }
61
- }
62
- /**
63
- * Show the prompt
64
- */
65
- show() {
66
- this.promptState.isVisible = true;
67
- }
68
- /**
69
- * Hide the prompt
70
- */
71
- hide() {
72
- this.promptState.isVisible = false;
73
- }
74
- /**
75
- * Enable or disable
76
- */
77
- setEnabled(enabled) {
78
- this.isEnabled = enabled;
79
- }
80
- /**
81
- * Clear - no-op for minimal implementation
82
- */
83
- clear() {
84
- // Intentionally minimal - let readline handle clearing
85
- }
86
- /**
87
- * Build status line string
88
- */
89
- buildStatusLine() {
90
- const parts = [];
91
- if (this.statusBarState.fileChanges) {
92
- parts.push(this.statusBarState.fileChanges);
93
- }
94
- if (typeof this.statusBarState.contextUsage === 'number') {
95
- const remaining = Math.max(0, 100 - this.statusBarState.contextUsage);
96
- parts.push(`${remaining}% context`);
97
- }
98
- if (this.statusBarState.message?.trim()) {
99
- parts.push(this.statusBarState.message.trim());
100
- }
101
- if (!parts.length) {
102
- return null;
103
- }
104
- return theme.ui.muted(parts.join(' • '));
105
- }
106
- /**
107
- * Handle terminal resize - no-op for minimal implementation
108
- */
109
- handleResize() {
110
- // Readline handles resize
111
- }
112
- /**
113
- * Dispose
114
- */
115
- dispose() {
116
- // Nothing to clean up in minimal implementation
117
- }
118
- }
119
- /**
120
- * Simple input box that wraps readline with stable behavior
121
- */
122
- export class SimpleInputBox {
123
- constructor(promptText = '> ') {
124
- this.rl = null;
125
- this.statusText = '';
126
- this.promptText = promptText;
127
- }
128
- /**
129
- * Initialize readline interface
130
- */
131
- init(input, output) {
132
- this.rl = readline.createInterface({
133
- input,
134
- output,
135
- prompt: this.promptText,
136
- terminal: true,
137
- });
138
- return this.rl;
139
- }
140
- /**
141
- * Set prompt text
142
- */
143
- setPrompt(text) {
144
- this.promptText = text;
145
- if (this.rl) {
146
- this.rl.setPrompt(text);
147
- }
148
- }
149
- /**
150
- * Set status text (shown above prompt on next prompt())
151
- */
152
- setStatus(text) {
153
- this.statusText = text;
154
- }
155
- /**
156
- * Show prompt with optional status line
157
- */
158
- prompt(preserveCursor) {
159
- if (!this.rl)
160
- return;
161
- // Show status line if set
162
- if (this.statusText) {
163
- process.stdout.write('\n' + theme.ui.muted(this.statusText) + '\n');
164
- this.statusText = '';
165
- }
166
- this.rl.prompt(preserveCursor);
167
- }
168
- /**
169
- * Get readline interface
170
- */
171
- getInterface() {
172
- return this.rl;
173
- }
174
- /**
175
- * Close and cleanup
176
- */
177
- close() {
178
- if (this.rl) {
179
- this.rl.close();
180
- this.rl = null;
181
- }
182
- }
183
- }