erosolar-cli 1.7.162 → 1.7.165
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/dist/contracts/unified-schema.json +6 -6
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/unified/tools.d.ts.map +1 -1
- package/dist/core/unified/tools.js +15 -37
- package/dist/core/unified/tools.js.map +1 -1
- package/dist/shell/interactiveShell.d.ts +25 -0
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +104 -50
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/shellApp.d.ts.map +1 -1
- package/dist/shell/shellApp.js +6 -2
- package/dist/shell/shellApp.js.map +1 -1
- package/dist/shell/unifiedChatBox.d.ts +178 -0
- package/dist/shell/unifiedChatBox.d.ts.map +1 -0
- package/dist/shell/unifiedChatBox.js +539 -0
- package/dist/shell/unifiedChatBox.js.map +1 -0
- package/dist/tools/codeQualityTools.d.ts.map +1 -1
- package/dist/tools/codeQualityTools.js +112 -0
- package/dist/tools/codeQualityTools.js.map +1 -1
- package/dist/tools/diffUtils.d.ts +1 -1
- package/dist/tools/diffUtils.d.ts.map +1 -1
- package/dist/tools/diffUtils.js +19 -3
- package/dist/tools/diffUtils.js.map +1 -1
- package/dist/tools/editTools.d.ts +11 -0
- package/dist/tools/editTools.d.ts.map +1 -1
- package/dist/tools/editTools.js +191 -119
- package/dist/tools/editTools.js.map +1 -1
- package/dist/tools/fileTools.js +1 -1
- package/dist/tools/fileTools.js.map +1 -1
- package/dist/tools/softwareEngineeringTools.d.ts +7 -0
- package/dist/tools/softwareEngineeringTools.d.ts.map +1 -0
- package/dist/tools/softwareEngineeringTools.js +338 -0
- package/dist/tools/softwareEngineeringTools.js.map +1 -0
- package/dist/ui/display.d.ts +17 -0
- package/dist/ui/display.d.ts.map +1 -1
- package/dist/ui/display.js +34 -0
- package/dist/ui/display.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UnifiedChatBox - Claude Code style unified input at bottom of terminal
|
|
3
|
+
*
|
|
4
|
+
* This implements Claude Code's exact approach:
|
|
5
|
+
*
|
|
6
|
+
* 1. Natural Output Flow
|
|
7
|
+
* - Streaming output just writes to stdout normally
|
|
8
|
+
* - The cursor stays where it is after each write
|
|
9
|
+
* - Lines scroll up naturally as new content appears
|
|
10
|
+
* - NO scroll regions, NO save/restore cursor during streaming
|
|
11
|
+
*
|
|
12
|
+
* 2. Readline Handles Input
|
|
13
|
+
* - Uses Node.js readline module for input
|
|
14
|
+
* - The input prompt naturally moves up as output streams above it
|
|
15
|
+
* - User can type while streaming - input is queued in memory, not rendered
|
|
16
|
+
*
|
|
17
|
+
* 3. Queue-Based Approach
|
|
18
|
+
* User types during streaming → Input stored in queue → Processed after streaming ends
|
|
19
|
+
*
|
|
20
|
+
* 4. The Key Insight
|
|
21
|
+
* The cursor is NEVER moved during streaming. Output just appends at current position.
|
|
22
|
+
* The "input at bottom" effect comes from:
|
|
23
|
+
* - New output pushes older content (including the prompt) upward
|
|
24
|
+
* - After streaming ends, a new prompt is shown at the bottom
|
|
25
|
+
*/
|
|
26
|
+
import * as readline from 'node:readline';
|
|
27
|
+
import { EventEmitter } from 'node:events';
|
|
28
|
+
import { theme } from '../ui/theme.js';
|
|
29
|
+
/**
|
|
30
|
+
* UnifiedChatBox - Exactly like Claude Code
|
|
31
|
+
*
|
|
32
|
+
* During idle: readline shows prompt at current cursor position (naturally at bottom)
|
|
33
|
+
* During streaming: output flows naturally, typed input goes to invisible queue
|
|
34
|
+
* After streaming: new prompt appears at bottom naturally
|
|
35
|
+
*/
|
|
36
|
+
export class UnifiedChatBox extends EventEmitter {
|
|
37
|
+
rl = null;
|
|
38
|
+
writeStream;
|
|
39
|
+
readStream;
|
|
40
|
+
state = {
|
|
41
|
+
isStreaming: false,
|
|
42
|
+
inputBuffer: '',
|
|
43
|
+
cursorPosition: 0,
|
|
44
|
+
queuedInputs: [],
|
|
45
|
+
};
|
|
46
|
+
inputIdCounter = 0;
|
|
47
|
+
keypressHandler = null;
|
|
48
|
+
originalStdoutWrite = null;
|
|
49
|
+
outputSuppressed = false;
|
|
50
|
+
// Configuration
|
|
51
|
+
maxQueueSize = 100;
|
|
52
|
+
maxInputLength = 10000;
|
|
53
|
+
promptText = '> ';
|
|
54
|
+
constructor(writeStream = process.stdout, readStream = process.stdin) {
|
|
55
|
+
super();
|
|
56
|
+
this.writeStream = writeStream;
|
|
57
|
+
this.readStream = readStream;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Initialize with an existing readline interface
|
|
61
|
+
*/
|
|
62
|
+
attachToReadline(rl) {
|
|
63
|
+
this.rl = rl;
|
|
64
|
+
this.setupKeypressCapture();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Set the prompt text
|
|
68
|
+
*/
|
|
69
|
+
setPrompt(text) {
|
|
70
|
+
this.promptText = text;
|
|
71
|
+
if (this.rl) {
|
|
72
|
+
this.rl.setPrompt(text);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get current prompt text
|
|
77
|
+
*/
|
|
78
|
+
getPrompt() {
|
|
79
|
+
return this.promptText;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Start streaming mode - Claude Code style
|
|
83
|
+
*
|
|
84
|
+
* What happens:
|
|
85
|
+
* - Output continues to flow naturally to stdout
|
|
86
|
+
* - User keystrokes are captured but NOT echoed
|
|
87
|
+
* - Captured keystrokes go into an invisible queue
|
|
88
|
+
* - NO cursor manipulation at all
|
|
89
|
+
*/
|
|
90
|
+
startStreaming() {
|
|
91
|
+
if (this.state.isStreaming) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
this.state.isStreaming = true;
|
|
95
|
+
this.state.inputBuffer = '';
|
|
96
|
+
this.state.cursorPosition = 0;
|
|
97
|
+
// Suppress readline echo - characters typed go to queue, not screen
|
|
98
|
+
this.suppressReadlineEcho();
|
|
99
|
+
this.emit('streaming-start');
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* End streaming mode - Claude Code style
|
|
103
|
+
*
|
|
104
|
+
* What happens:
|
|
105
|
+
* - Restore readline echo
|
|
106
|
+
* - Return queue summary for caller to process
|
|
107
|
+
* - Caller should then show a fresh prompt (naturally at bottom)
|
|
108
|
+
*/
|
|
109
|
+
endStreaming() {
|
|
110
|
+
// Restore readline echo first
|
|
111
|
+
this.restoreReadlineEcho();
|
|
112
|
+
const summary = {
|
|
113
|
+
queuedCount: this.state.queuedInputs.length,
|
|
114
|
+
queueSummary: this.getQueueSummary(),
|
|
115
|
+
};
|
|
116
|
+
this.state.isStreaming = false;
|
|
117
|
+
this.emit('streaming-end', summary);
|
|
118
|
+
return summary;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Check if currently streaming
|
|
122
|
+
*/
|
|
123
|
+
isStreaming() {
|
|
124
|
+
return this.state.isStreaming;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Set up keypress capture for invisible input during streaming
|
|
128
|
+
*/
|
|
129
|
+
setupKeypressCapture() {
|
|
130
|
+
if (!this.readStream || !this.readStream.isTTY) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// Enable keypress events if not already enabled
|
|
134
|
+
if (this.readStream.listenerCount('keypress') === 0 && this.rl) {
|
|
135
|
+
readline.emitKeypressEvents(this.readStream, this.rl);
|
|
136
|
+
}
|
|
137
|
+
// Ensure raw mode for keypress events
|
|
138
|
+
if (this.readStream.setRawMode && !this.readStream.isRaw) {
|
|
139
|
+
this.readStream.setRawMode(true);
|
|
140
|
+
}
|
|
141
|
+
this.keypressHandler = (str, key) => {
|
|
142
|
+
// Only capture when streaming
|
|
143
|
+
if (!this.state.isStreaming) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
this.handleKeypress(str, key);
|
|
147
|
+
};
|
|
148
|
+
this.readStream.prependListener('keypress', this.keypressHandler);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Handle keypress during streaming - queue input invisibly
|
|
152
|
+
*/
|
|
153
|
+
handleKeypress(str, key) {
|
|
154
|
+
if (!key) {
|
|
155
|
+
// Regular character
|
|
156
|
+
if (str && str.length > 0) {
|
|
157
|
+
this.appendToBuffer(str);
|
|
158
|
+
}
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// Ctrl+C - queue interrupt
|
|
162
|
+
if (key.ctrl && key.name === 'c') {
|
|
163
|
+
this.queueInterrupt();
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// Enter - queue the current buffer
|
|
167
|
+
if (key.name === 'return' || key.name === 'enter') {
|
|
168
|
+
this.submitBuffer();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
// Backspace
|
|
172
|
+
if (key.name === 'backspace') {
|
|
173
|
+
this.handleBackspace();
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
// Delete
|
|
177
|
+
if (key.name === 'delete') {
|
|
178
|
+
this.handleDelete();
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// Arrow keys for cursor movement
|
|
182
|
+
if (key.name === 'left') {
|
|
183
|
+
this.state.cursorPosition = Math.max(0, this.state.cursorPosition - 1);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (key.name === 'right') {
|
|
187
|
+
this.state.cursorPosition = Math.min(this.state.inputBuffer.length, this.state.cursorPosition + 1);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
// Home/End
|
|
191
|
+
if (key.name === 'home' || (key.ctrl && key.name === 'a')) {
|
|
192
|
+
this.state.cursorPosition = 0;
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (key.name === 'end' || (key.ctrl && key.name === 'e')) {
|
|
196
|
+
this.state.cursorPosition = this.state.inputBuffer.length;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
// Ctrl+U - clear line
|
|
200
|
+
if (key.ctrl && key.name === 'u') {
|
|
201
|
+
this.state.inputBuffer = this.state.inputBuffer.slice(this.state.cursorPosition);
|
|
202
|
+
this.state.cursorPosition = 0;
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
// Ctrl+K - delete to end
|
|
206
|
+
if (key.ctrl && key.name === 'k') {
|
|
207
|
+
this.state.inputBuffer = this.state.inputBuffer.slice(0, this.state.cursorPosition);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
// Ctrl+W - delete word
|
|
211
|
+
if (key.ctrl && key.name === 'w') {
|
|
212
|
+
this.handleDeleteWord();
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
// Ignore other control sequences
|
|
216
|
+
if (key.ctrl || key.meta) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
// Regular character with key info
|
|
220
|
+
if (str && str.length > 0) {
|
|
221
|
+
this.appendToBuffer(str);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Append character(s) to the invisible buffer
|
|
226
|
+
*/
|
|
227
|
+
appendToBuffer(chars) {
|
|
228
|
+
if (this.state.inputBuffer.length >= this.maxInputLength) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const available = this.maxInputLength - this.state.inputBuffer.length;
|
|
232
|
+
const toAdd = chars.slice(0, available);
|
|
233
|
+
this.state.inputBuffer =
|
|
234
|
+
this.state.inputBuffer.slice(0, this.state.cursorPosition) +
|
|
235
|
+
toAdd +
|
|
236
|
+
this.state.inputBuffer.slice(this.state.cursorPosition);
|
|
237
|
+
this.state.cursorPosition += toAdd.length;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Handle backspace in buffer
|
|
241
|
+
*/
|
|
242
|
+
handleBackspace() {
|
|
243
|
+
if (this.state.cursorPosition === 0) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
this.state.inputBuffer =
|
|
247
|
+
this.state.inputBuffer.slice(0, this.state.cursorPosition - 1) +
|
|
248
|
+
this.state.inputBuffer.slice(this.state.cursorPosition);
|
|
249
|
+
this.state.cursorPosition = Math.max(0, this.state.cursorPosition - 1);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Handle delete key in buffer
|
|
253
|
+
*/
|
|
254
|
+
handleDelete() {
|
|
255
|
+
if (this.state.cursorPosition >= this.state.inputBuffer.length) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
this.state.inputBuffer =
|
|
259
|
+
this.state.inputBuffer.slice(0, this.state.cursorPosition) +
|
|
260
|
+
this.state.inputBuffer.slice(this.state.cursorPosition + 1);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Handle Ctrl+W - delete word before cursor
|
|
264
|
+
*/
|
|
265
|
+
handleDeleteWord() {
|
|
266
|
+
if (this.state.cursorPosition === 0) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
let pos = this.state.cursorPosition;
|
|
270
|
+
// Skip spaces
|
|
271
|
+
while (pos > 0 && this.state.inputBuffer[pos - 1] === ' ') {
|
|
272
|
+
pos--;
|
|
273
|
+
}
|
|
274
|
+
// Skip word
|
|
275
|
+
while (pos > 0 && this.state.inputBuffer[pos - 1] !== ' ') {
|
|
276
|
+
pos--;
|
|
277
|
+
}
|
|
278
|
+
this.state.inputBuffer =
|
|
279
|
+
this.state.inputBuffer.slice(0, pos) +
|
|
280
|
+
this.state.inputBuffer.slice(this.state.cursorPosition);
|
|
281
|
+
this.state.cursorPosition = pos;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Submit current buffer to queue
|
|
285
|
+
*/
|
|
286
|
+
submitBuffer() {
|
|
287
|
+
const text = this.state.inputBuffer.trim();
|
|
288
|
+
if (!text) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
// Check queue limit
|
|
292
|
+
if (this.state.queuedInputs.length >= this.maxQueueSize) {
|
|
293
|
+
// Remove oldest non-command to make room
|
|
294
|
+
const idx = this.state.queuedInputs.findIndex(q => q.type !== 'command');
|
|
295
|
+
if (idx >= 0) {
|
|
296
|
+
this.state.queuedInputs.splice(idx, 1);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
return; // Queue full
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
const input = {
|
|
303
|
+
id: `input-${++this.inputIdCounter}`,
|
|
304
|
+
text,
|
|
305
|
+
timestamp: Date.now(),
|
|
306
|
+
type: text.startsWith('/') ? 'command' : 'message',
|
|
307
|
+
};
|
|
308
|
+
this.state.queuedInputs.push(input);
|
|
309
|
+
this.state.inputBuffer = '';
|
|
310
|
+
this.state.cursorPosition = 0;
|
|
311
|
+
this.emit('input-queued', input);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Queue an interrupt
|
|
315
|
+
*/
|
|
316
|
+
queueInterrupt() {
|
|
317
|
+
const input = {
|
|
318
|
+
id: `input-${++this.inputIdCounter}`,
|
|
319
|
+
text: '',
|
|
320
|
+
timestamp: Date.now(),
|
|
321
|
+
type: 'interrupt',
|
|
322
|
+
};
|
|
323
|
+
// Interrupt goes to front of queue
|
|
324
|
+
this.state.queuedInputs.unshift(input);
|
|
325
|
+
this.state.inputBuffer = '';
|
|
326
|
+
this.state.cursorPosition = 0;
|
|
327
|
+
this.emit('input-queued', input);
|
|
328
|
+
this.emit('interrupt');
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Suppress readline echo during streaming
|
|
332
|
+
* Characters typed will be captured but not displayed
|
|
333
|
+
*/
|
|
334
|
+
suppressReadlineEcho() {
|
|
335
|
+
if (this.outputSuppressed || !this.writeStream.isTTY) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
this.originalStdoutWrite = this.writeStream.write.bind(this.writeStream);
|
|
339
|
+
const self = this;
|
|
340
|
+
// Replace stdout.write to filter readline echo
|
|
341
|
+
this.writeStream.write = function (chunk, encodingOrCallback, callback) {
|
|
342
|
+
if (!self.originalStdoutWrite) {
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
const str = typeof chunk === 'string' ? chunk : chunk.toString();
|
|
346
|
+
// During streaming, filter out readline echo patterns:
|
|
347
|
+
// - Single printable characters (user typing)
|
|
348
|
+
// - Backspace sequences
|
|
349
|
+
// - Cursor movement sequences
|
|
350
|
+
// - Short control sequences
|
|
351
|
+
// But allow through:
|
|
352
|
+
// - Multi-character content (actual AI output)
|
|
353
|
+
// - Newlines and formatting
|
|
354
|
+
// Single printable char - likely user typing, suppress
|
|
355
|
+
if (str.length === 1 && str.charCodeAt(0) >= 32 && str.charCodeAt(0) < 127) {
|
|
356
|
+
if (typeof encodingOrCallback === 'function') {
|
|
357
|
+
encodingOrCallback(null);
|
|
358
|
+
}
|
|
359
|
+
else if (callback) {
|
|
360
|
+
callback(null);
|
|
361
|
+
}
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
// Backspace sequences
|
|
365
|
+
if (str === '\b \b' || str === '\x1b[D \x1b[D' || str === '\b' || str === '\x7f') {
|
|
366
|
+
if (typeof encodingOrCallback === 'function') {
|
|
367
|
+
encodingOrCallback(null);
|
|
368
|
+
}
|
|
369
|
+
else if (callback) {
|
|
370
|
+
callback(null);
|
|
371
|
+
}
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
// Cursor movement sequences
|
|
375
|
+
if (/^\x1b\[\d*[ABCD]$/.test(str)) {
|
|
376
|
+
if (typeof encodingOrCallback === 'function') {
|
|
377
|
+
encodingOrCallback(null);
|
|
378
|
+
}
|
|
379
|
+
else if (callback) {
|
|
380
|
+
callback(null);
|
|
381
|
+
}
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
// Short control sequences from readline
|
|
385
|
+
if (str.length <= 3 && /^[\x1b\[\]\d;GKJ]+$/.test(str)) {
|
|
386
|
+
if (typeof encodingOrCallback === 'function') {
|
|
387
|
+
encodingOrCallback(null);
|
|
388
|
+
}
|
|
389
|
+
else if (callback) {
|
|
390
|
+
callback(null);
|
|
391
|
+
}
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
// Prompt redraw patterns
|
|
395
|
+
if (/^\r/.test(str) && str.length < 20 && /^[\r\x1b\[\dGK> ]+$/.test(str)) {
|
|
396
|
+
if (typeof encodingOrCallback === 'function') {
|
|
397
|
+
encodingOrCallback(null);
|
|
398
|
+
}
|
|
399
|
+
else if (callback) {
|
|
400
|
+
callback(null);
|
|
401
|
+
}
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
// Clear line + prompt patterns
|
|
405
|
+
if (/^\x1b\[\d*[GK]/.test(str) && str.length < 15) {
|
|
406
|
+
if (typeof encodingOrCallback === 'function') {
|
|
407
|
+
encodingOrCallback(null);
|
|
408
|
+
}
|
|
409
|
+
else if (callback) {
|
|
410
|
+
callback(null);
|
|
411
|
+
}
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
// Allow everything else through (actual AI output)
|
|
415
|
+
if (typeof encodingOrCallback === 'function') {
|
|
416
|
+
return self.originalStdoutWrite(chunk, encodingOrCallback);
|
|
417
|
+
}
|
|
418
|
+
return self.originalStdoutWrite(chunk, encodingOrCallback, callback);
|
|
419
|
+
};
|
|
420
|
+
this.outputSuppressed = true;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Restore readline echo
|
|
424
|
+
*/
|
|
425
|
+
restoreReadlineEcho() {
|
|
426
|
+
if (!this.outputSuppressed || !this.originalStdoutWrite) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
this.writeStream.write = this.originalStdoutWrite;
|
|
430
|
+
this.originalStdoutWrite = null;
|
|
431
|
+
this.outputSuppressed = false;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Check if there are queued inputs
|
|
435
|
+
*/
|
|
436
|
+
hasQueuedInput() {
|
|
437
|
+
return this.state.queuedInputs.length > 0;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Get next queued input
|
|
441
|
+
*/
|
|
442
|
+
dequeue() {
|
|
443
|
+
return this.state.queuedInputs.shift();
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Get all queued inputs
|
|
447
|
+
*/
|
|
448
|
+
getQueue() {
|
|
449
|
+
return [...this.state.queuedInputs];
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Clear queue
|
|
453
|
+
*/
|
|
454
|
+
clearQueue() {
|
|
455
|
+
this.state.queuedInputs = [];
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Get queue summary for display
|
|
459
|
+
*/
|
|
460
|
+
getQueueSummary() {
|
|
461
|
+
const count = this.state.queuedInputs.length;
|
|
462
|
+
if (count === 0) {
|
|
463
|
+
return '';
|
|
464
|
+
}
|
|
465
|
+
const commands = this.state.queuedInputs.filter(q => q.type === 'command').length;
|
|
466
|
+
const messages = this.state.queuedInputs.filter(q => q.type === 'message').length;
|
|
467
|
+
const interrupts = this.state.queuedInputs.filter(q => q.type === 'interrupt').length;
|
|
468
|
+
const parts = [];
|
|
469
|
+
if (interrupts > 0) {
|
|
470
|
+
parts.push(`${interrupts} interrupt${interrupts === 1 ? '' : 's'}`);
|
|
471
|
+
}
|
|
472
|
+
if (commands > 0) {
|
|
473
|
+
parts.push(`${commands} command${commands === 1 ? '' : 's'}`);
|
|
474
|
+
}
|
|
475
|
+
if (messages > 0) {
|
|
476
|
+
parts.push(`${messages} message${messages === 1 ? '' : 's'}`);
|
|
477
|
+
}
|
|
478
|
+
return parts.join(', ') + ' queued';
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Get current input buffer (for display if needed)
|
|
482
|
+
*/
|
|
483
|
+
getInputBuffer() {
|
|
484
|
+
return this.state.inputBuffer;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Get current state
|
|
488
|
+
*/
|
|
489
|
+
getState() {
|
|
490
|
+
return {
|
|
491
|
+
...this.state,
|
|
492
|
+
queuedInputs: [...this.state.queuedInputs],
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Show queue indicator if there are queued items
|
|
497
|
+
*/
|
|
498
|
+
showQueueIndicator() {
|
|
499
|
+
const count = this.state.queuedInputs.length;
|
|
500
|
+
if (count === 0) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const summary = this.getQueueSummary();
|
|
504
|
+
this.writeStream.write(theme.ui.muted(`\n📝 ${summary}\n`));
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Dispose and cleanup
|
|
508
|
+
*/
|
|
509
|
+
dispose() {
|
|
510
|
+
// Restore echo if suppressed
|
|
511
|
+
this.restoreReadlineEcho();
|
|
512
|
+
// Remove keypress handler
|
|
513
|
+
if (this.keypressHandler && this.readStream) {
|
|
514
|
+
this.readStream.off('keypress', this.keypressHandler);
|
|
515
|
+
this.keypressHandler = null;
|
|
516
|
+
}
|
|
517
|
+
// Clear state
|
|
518
|
+
this.state.queuedInputs = [];
|
|
519
|
+
this.state.inputBuffer = '';
|
|
520
|
+
this.rl = null;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Singleton instance
|
|
525
|
+
*/
|
|
526
|
+
let globalInstance = null;
|
|
527
|
+
export function getUnifiedChatBox() {
|
|
528
|
+
if (!globalInstance) {
|
|
529
|
+
globalInstance = new UnifiedChatBox();
|
|
530
|
+
}
|
|
531
|
+
return globalInstance;
|
|
532
|
+
}
|
|
533
|
+
export function resetUnifiedChatBox() {
|
|
534
|
+
if (globalInstance) {
|
|
535
|
+
globalInstance.dispose();
|
|
536
|
+
}
|
|
537
|
+
globalInstance = null;
|
|
538
|
+
}
|
|
539
|
+
//# sourceMappingURL=unifiedChatBox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unifiedChatBox.js","sourceRoot":"","sources":["../../src/shell/unifiedChatBox.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codeQualityTools.d.ts","sourceRoot":"","sources":["../../src/tools/codeQualityTools.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAuB7D,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"codeQualityTools.d.ts","sourceRoot":"","sources":["../../src/tools/codeQualityTools.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAuB7D,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,EAAE,CA0L3E"}
|
|
@@ -96,6 +96,52 @@ export function createCodeQualityTools(workingDir) {
|
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
},
|
|
99
|
+
{
|
|
100
|
+
name: 'scan_dependency_health',
|
|
101
|
+
description: 'Run npm audit to surface known vulnerabilities (requires npm registry access).',
|
|
102
|
+
parameters: {
|
|
103
|
+
type: 'object',
|
|
104
|
+
properties: {
|
|
105
|
+
timeout: {
|
|
106
|
+
type: 'number',
|
|
107
|
+
description: 'Timeout in milliseconds (default: 180000).',
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
additionalProperties: false,
|
|
111
|
+
},
|
|
112
|
+
handler: async (args) => {
|
|
113
|
+
const timeout = typeof args['timeout'] === 'number' && Number.isFinite(args['timeout']) && args['timeout'] > 0
|
|
114
|
+
? args['timeout']
|
|
115
|
+
: 180000;
|
|
116
|
+
try {
|
|
117
|
+
const packageJsonPath = join(workingDir, 'package.json');
|
|
118
|
+
if (!existsSync(packageJsonPath)) {
|
|
119
|
+
return 'Error: package.json not found. Cannot run dependency audit.';
|
|
120
|
+
}
|
|
121
|
+
const { stdout, stderr } = await execAsync('npm audit --json', {
|
|
122
|
+
cwd: workingDir,
|
|
123
|
+
timeout,
|
|
124
|
+
maxBuffer: 1024 * 1024 * 10,
|
|
125
|
+
});
|
|
126
|
+
try {
|
|
127
|
+
const auditResult = JSON.parse(stdout || stderr);
|
|
128
|
+
return formatAuditReport(auditResult);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// If JSON parsing fails, return raw output
|
|
132
|
+
return stdout || stderr || 'No output from npm audit';
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const stdout = error.stdout ?? '';
|
|
137
|
+
const stderr = error.stderr ?? '';
|
|
138
|
+
if (error.killed) {
|
|
139
|
+
return `Error: npm audit command timed out after ${timeout}ms`;
|
|
140
|
+
}
|
|
141
|
+
return `Error running dependency audit: ${error.message}\nstdout: ${stdout}\nstderr: ${stderr}`;
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
},
|
|
99
145
|
{
|
|
100
146
|
name: 'inspect_code_quality',
|
|
101
147
|
description: 'Generate a maintainability report (function complexity, TODO density, comment coverage) for a file.',
|
|
@@ -292,4 +338,70 @@ function formatQualityReport(content, structural, ast) {
|
|
|
292
338
|
}
|
|
293
339
|
return output.join('\n');
|
|
294
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* Format npm audit JSON output into a concise, human-readable report.
|
|
343
|
+
* Handles both modern (vulnerabilities/actions) and legacy (advisories) formats.
|
|
344
|
+
*/
|
|
345
|
+
function formatAuditReport(audit) {
|
|
346
|
+
if (!audit || typeof audit !== 'object') {
|
|
347
|
+
return 'No audit data available.';
|
|
348
|
+
}
|
|
349
|
+
const lines = [];
|
|
350
|
+
lines.push('# Dependency audit summary');
|
|
351
|
+
lines.push('');
|
|
352
|
+
const vulnSummary = audit.metadata?.vulnerabilities ?? audit.vulnerabilities ?? {};
|
|
353
|
+
const entries = Object.entries(vulnSummary).filter(([, value]) => typeof value === 'number' && value > 0);
|
|
354
|
+
const total = typeof audit.metadata?.vulnerabilities?.total === 'number'
|
|
355
|
+
? audit.metadata.vulnerabilities.total
|
|
356
|
+
: entries.reduce((acc, [, value]) => acc + value, 0);
|
|
357
|
+
if (entries.length === 0) {
|
|
358
|
+
lines.push('No vulnerabilities reported.');
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
lines.push(`Total vulnerabilities: ${total}`);
|
|
362
|
+
for (const [severity, count] of entries) {
|
|
363
|
+
lines.push(`- ${severity}: ${count}`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const advisories = audit.advisories && typeof audit.advisories === 'object'
|
|
367
|
+
? Object.values(audit.advisories)
|
|
368
|
+
: [];
|
|
369
|
+
if (Array.isArray(advisories) && advisories.length > 0) {
|
|
370
|
+
lines.push('');
|
|
371
|
+
lines.push('Top advisories:');
|
|
372
|
+
for (const advisory of advisories.slice(0, 5)) {
|
|
373
|
+
const id = advisory.id ?? advisory.advisoryId ?? 'unknown';
|
|
374
|
+
const module = advisory.module_name ?? advisory.module ?? 'unknown';
|
|
375
|
+
const severity = advisory.severity ?? advisory.overall_severity ?? 'unknown';
|
|
376
|
+
lines.push(`- ${module} (id: ${id}) — severity: ${severity}`);
|
|
377
|
+
}
|
|
378
|
+
if (advisories.length > 5) {
|
|
379
|
+
lines.push(`…and ${advisories.length - 5} more advisories`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const actions = Array.isArray(audit.actions) ? audit.actions : [];
|
|
383
|
+
if (actions.length > 0) {
|
|
384
|
+
lines.push('');
|
|
385
|
+
lines.push('Recommended actions:');
|
|
386
|
+
for (const action of actions.slice(0, 5)) {
|
|
387
|
+
const resolved = Array.isArray(action.resolves) ? action.resolves : [];
|
|
388
|
+
const paths = resolved
|
|
389
|
+
.map((item) => item.path || item.id || '')
|
|
390
|
+
.filter((item) => Boolean(item));
|
|
391
|
+
const pathSummary = paths.length ? ` (paths: ${paths.slice(0, 3).join(', ')}${paths.length > 3 ? ', …' : ''})` : '';
|
|
392
|
+
lines.push(`- ${action.action || 'upgrade/dependency change'}${pathSummary}`);
|
|
393
|
+
}
|
|
394
|
+
if (actions.length > 5) {
|
|
395
|
+
lines.push(`…and ${actions.length - 5} more actions`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
// Fallback to raw JSON when no useful info was extracted
|
|
399
|
+
const meaningful = entries.length > 0 || advisories.length > 0 || actions.length > 0;
|
|
400
|
+
if (!meaningful) {
|
|
401
|
+
lines.push('');
|
|
402
|
+
lines.push('Raw audit output:');
|
|
403
|
+
lines.push(JSON.stringify(audit, null, 2));
|
|
404
|
+
}
|
|
405
|
+
return lines.join('\n');
|
|
406
|
+
}
|
|
295
407
|
//# sourceMappingURL=codeQualityTools.js.map
|