wave-code 0.5.0 → 0.6.2
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/components/App.d.ts.map +1 -1
- package/dist/components/App.js +40 -2
- package/dist/components/BackgroundTaskManager.d.ts +6 -0
- package/dist/components/BackgroundTaskManager.d.ts.map +1 -0
- package/dist/components/{TaskManager.js → BackgroundTaskManager.js} +1 -1
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +40 -5
- package/dist/components/CommandOutputDisplay.d.ts.map +1 -1
- package/dist/components/CommandOutputDisplay.js +6 -17
- package/dist/components/CommandSelector.d.ts.map +1 -1
- package/dist/components/CommandSelector.js +16 -2
- package/dist/components/CompressDisplay.d.ts.map +1 -1
- package/dist/components/CompressDisplay.js +6 -10
- package/dist/components/ConfirmationDetails.d.ts +9 -0
- package/dist/components/ConfirmationDetails.d.ts.map +1 -0
- package/dist/components/ConfirmationDetails.js +53 -0
- package/dist/components/{Confirmation.d.ts → ConfirmationSelector.d.ts} +3 -3
- package/dist/components/ConfirmationSelector.d.ts.map +1 -0
- package/dist/components/{Confirmation.js → ConfirmationSelector.js} +34 -96
- package/dist/components/DiffDisplay.d.ts.map +1 -1
- package/dist/components/DiffDisplay.js +48 -1
- package/dist/components/FileSelector.d.ts.map +1 -1
- package/dist/components/FileSelector.js +2 -2
- package/dist/components/HelpView.d.ts +6 -0
- package/dist/components/HelpView.d.ts.map +1 -0
- package/dist/components/HelpView.js +24 -0
- package/dist/components/HistorySearch.d.ts.map +1 -1
- package/dist/components/HistorySearch.js +12 -4
- package/dist/components/InputBox.d.ts +1 -3
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +14 -17
- package/dist/components/LoadingIndicator.d.ts +11 -0
- package/dist/components/LoadingIndicator.d.ts.map +1 -0
- package/dist/components/LoadingIndicator.js +6 -0
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/Markdown.js +114 -121
- package/dist/components/MessageItem.d.ts +1 -1
- package/dist/components/MessageItem.d.ts.map +1 -1
- package/dist/components/MessageItem.js +3 -5
- package/dist/components/MessageList.d.ts +2 -3
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +29 -12
- package/dist/components/PlanDisplay.d.ts.map +1 -1
- package/dist/components/PlanDisplay.js +4 -12
- package/dist/components/RewindCommand.d.ts +4 -0
- package/dist/components/RewindCommand.d.ts.map +1 -1
- package/dist/components/RewindCommand.js +20 -3
- package/dist/components/TaskList.d.ts +3 -0
- package/dist/components/TaskList.d.ts.map +1 -0
- package/dist/components/TaskList.js +40 -0
- package/dist/components/ToolDisplay.d.ts +9 -0
- package/dist/components/ToolDisplay.d.ts.map +1 -0
- package/dist/components/ToolDisplay.js +44 -0
- package/dist/contexts/useChat.d.ts +11 -3
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +51 -32
- package/dist/hooks/useInputManager.d.ts +4 -15
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +20 -65
- package/dist/hooks/useTasks.d.ts +2 -0
- package/dist/hooks/useTasks.d.ts.map +1 -0
- package/dist/hooks/useTasks.js +5 -0
- package/dist/managers/InputManager.d.ts +8 -30
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +38 -144
- package/dist/print-cli.d.ts.map +1 -1
- package/dist/print-cli.js +11 -30
- package/package.json +5 -6
- package/src/components/App.tsx +51 -3
- package/src/components/{TaskManager.tsx → BackgroundTaskManager.tsx} +4 -2
- package/src/components/ChatInterface.tsx +80 -23
- package/src/components/CommandOutputDisplay.tsx +16 -38
- package/src/components/CommandSelector.tsx +41 -17
- package/src/components/CompressDisplay.tsx +5 -22
- package/src/components/ConfirmationDetails.tsx +108 -0
- package/src/components/{Confirmation.tsx → ConfirmationSelector.tsx} +74 -193
- package/src/components/DiffDisplay.tsx +71 -1
- package/src/components/FileSelector.tsx +0 -2
- package/src/components/HelpView.tsx +59 -0
- package/src/components/HistorySearch.tsx +45 -21
- package/src/components/InputBox.tsx +51 -63
- package/src/components/LoadingIndicator.tsx +56 -0
- package/src/components/Markdown.tsx +126 -323
- package/src/components/MessageItem.tsx +13 -24
- package/src/components/MessageList.tsx +48 -82
- package/src/components/PlanDisplay.tsx +4 -27
- package/src/components/RewindCommand.tsx +39 -2
- package/src/components/TaskList.tsx +58 -0
- package/src/components/{ToolResultDisplay.tsx → ToolDisplay.tsx} +8 -18
- package/src/contexts/useChat.tsx +73 -41
- package/src/hooks/useInputManager.ts +21 -83
- package/src/hooks/useTasks.ts +6 -0
- package/src/managers/InputManager.ts +43 -179
- package/src/print-cli.ts +17 -35
- package/dist/components/Confirmation.d.ts.map +0 -1
- package/dist/components/MemoryDisplay.d.ts +0 -8
- package/dist/components/MemoryDisplay.d.ts.map +0 -1
- package/dist/components/MemoryDisplay.js +0 -25
- package/dist/components/MemoryTypeSelector.d.ts +0 -8
- package/dist/components/MemoryTypeSelector.d.ts.map +0 -1
- package/dist/components/MemoryTypeSelector.js +0 -38
- package/dist/components/SubagentBlock.d.ts +0 -8
- package/dist/components/SubagentBlock.d.ts.map +0 -1
- package/dist/components/SubagentBlock.js +0 -70
- package/dist/components/TaskManager.d.ts +0 -6
- package/dist/components/TaskManager.d.ts.map +0 -1
- package/dist/components/ToolResultDisplay.d.ts +0 -9
- package/dist/components/ToolResultDisplay.d.ts.map +0 -1
- package/dist/components/ToolResultDisplay.js +0 -54
- package/src/components/MemoryDisplay.tsx +0 -62
- package/src/components/MemoryTypeSelector.tsx +0 -98
- package/src/components/SubagentBlock.tsx +0 -143
|
@@ -18,13 +18,6 @@ export class InputManager {
|
|
|
18
18
|
// History search state
|
|
19
19
|
this.showHistorySearch = false;
|
|
20
20
|
this.historySearchQuery = "";
|
|
21
|
-
// Memory type selector state
|
|
22
|
-
this.showMemoryTypeSelector = false;
|
|
23
|
-
this.memoryMessage = "";
|
|
24
|
-
// Input history state
|
|
25
|
-
this.userInputHistory = [];
|
|
26
|
-
this.historyIndex = -1;
|
|
27
|
-
this.historyBuffer = "";
|
|
28
21
|
// Paste debounce state
|
|
29
22
|
this.pasteDebounceTimer = null;
|
|
30
23
|
this.pasteBuffer = "";
|
|
@@ -37,9 +30,10 @@ export class InputManager {
|
|
|
37
30
|
this.attachedImages = [];
|
|
38
31
|
this.imageIdCounter = 1;
|
|
39
32
|
// Additional UI state
|
|
40
|
-
this.
|
|
33
|
+
this.showBackgroundTaskManager = false;
|
|
41
34
|
this.showMcpManager = false;
|
|
42
35
|
this.showRewindManager = false;
|
|
36
|
+
this.showHelp = false;
|
|
43
37
|
// Permission mode state
|
|
44
38
|
this.permissionMode = "default";
|
|
45
39
|
// Flag to prevent handleInput conflicts when selector selection occurs
|
|
@@ -105,12 +99,6 @@ export class InputManager {
|
|
|
105
99
|
moveCursorRight() {
|
|
106
100
|
this.setCursorPosition(this.cursorPosition + 1);
|
|
107
101
|
}
|
|
108
|
-
moveCursorToStart() {
|
|
109
|
-
this.setCursorPosition(0);
|
|
110
|
-
}
|
|
111
|
-
moveCursorToEnd() {
|
|
112
|
-
this.setCursorPosition(this.inputText.length);
|
|
113
|
-
}
|
|
114
102
|
// File selector methods
|
|
115
103
|
async searchFiles(query) {
|
|
116
104
|
try {
|
|
@@ -220,17 +208,20 @@ export class InputManager {
|
|
|
220
208
|
}
|
|
221
209
|
// If not an agent command or execution failed, check local commands
|
|
222
210
|
if (!commandExecuted) {
|
|
223
|
-
if (command === "tasks"
|
|
224
|
-
this.
|
|
211
|
+
if (command === "tasks") {
|
|
212
|
+
this.setShowBackgroundTaskManager(true);
|
|
225
213
|
commandExecuted = true;
|
|
226
214
|
}
|
|
227
|
-
else if (command === "mcp"
|
|
228
|
-
this.
|
|
215
|
+
else if (command === "mcp") {
|
|
216
|
+
this.setShowMcpManager(true);
|
|
229
217
|
commandExecuted = true;
|
|
230
218
|
}
|
|
231
|
-
else if (command === "rewind"
|
|
232
|
-
this.
|
|
233
|
-
|
|
219
|
+
else if (command === "rewind") {
|
|
220
|
+
this.setShowRewindManager(true);
|
|
221
|
+
commandExecuted = true;
|
|
222
|
+
}
|
|
223
|
+
else if (command === "help") {
|
|
224
|
+
this.setShowHelp(true);
|
|
234
225
|
commandExecuted = true;
|
|
235
226
|
}
|
|
236
227
|
}
|
|
@@ -280,79 +271,6 @@ export class InputManager {
|
|
|
280
271
|
}
|
|
281
272
|
return false;
|
|
282
273
|
}
|
|
283
|
-
// Memory type selector methods
|
|
284
|
-
activateMemoryTypeSelector(message) {
|
|
285
|
-
this.showMemoryTypeSelector = true;
|
|
286
|
-
this.memoryMessage = message;
|
|
287
|
-
this.callbacks.onMemoryTypeSelectorStateChange?.(true, message);
|
|
288
|
-
}
|
|
289
|
-
async handleMemoryTypeSelect(type) {
|
|
290
|
-
const currentMessage = this.inputText.trim();
|
|
291
|
-
if (currentMessage.startsWith("#")) {
|
|
292
|
-
await this.callbacks.onSaveMemory?.(currentMessage, type);
|
|
293
|
-
}
|
|
294
|
-
// Close the selector
|
|
295
|
-
this.showMemoryTypeSelector = false;
|
|
296
|
-
this.memoryMessage = "";
|
|
297
|
-
this.callbacks.onMemoryTypeSelectorStateChange?.(false, "");
|
|
298
|
-
// Clear input box
|
|
299
|
-
this.clearInput();
|
|
300
|
-
}
|
|
301
|
-
handleCancelMemoryTypeSelect() {
|
|
302
|
-
this.showMemoryTypeSelector = false;
|
|
303
|
-
this.memoryMessage = "";
|
|
304
|
-
this.callbacks.onMemoryTypeSelectorStateChange?.(false, "");
|
|
305
|
-
}
|
|
306
|
-
// Input history methods
|
|
307
|
-
setUserInputHistory(history) {
|
|
308
|
-
this.userInputHistory = history;
|
|
309
|
-
}
|
|
310
|
-
navigateHistory(direction, currentInput) {
|
|
311
|
-
if (this.historyIndex === -1) {
|
|
312
|
-
this.historyBuffer = currentInput;
|
|
313
|
-
}
|
|
314
|
-
if (direction === "up") {
|
|
315
|
-
if (this.historyIndex < this.userInputHistory.length - 1) {
|
|
316
|
-
this.historyIndex++;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
else {
|
|
320
|
-
// Down direction
|
|
321
|
-
if (this.historyIndex > 0) {
|
|
322
|
-
this.historyIndex--;
|
|
323
|
-
}
|
|
324
|
-
else if (this.historyIndex === 0) {
|
|
325
|
-
// Go from first history item to draft
|
|
326
|
-
this.historyIndex = -1;
|
|
327
|
-
}
|
|
328
|
-
else if (this.historyIndex === -1) {
|
|
329
|
-
// Go from draft to empty (beyond history bottom)
|
|
330
|
-
this.historyIndex = -2;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
let newInput;
|
|
334
|
-
if (this.historyIndex === -1) {
|
|
335
|
-
newInput = this.historyBuffer;
|
|
336
|
-
}
|
|
337
|
-
else if (this.historyIndex === -2) {
|
|
338
|
-
// Beyond history bottom, clear input
|
|
339
|
-
newInput = "";
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
342
|
-
const historyItem = this.userInputHistory[this.userInputHistory.length - 1 - this.historyIndex];
|
|
343
|
-
newInput = historyItem || "";
|
|
344
|
-
}
|
|
345
|
-
const newCursorPosition = newInput.length;
|
|
346
|
-
this.inputText = newInput;
|
|
347
|
-
this.cursorPosition = newCursorPosition;
|
|
348
|
-
this.callbacks.onInputTextChange?.(newInput);
|
|
349
|
-
this.callbacks.onCursorPositionChange?.(newCursorPosition);
|
|
350
|
-
return { newInput, newCursorPosition };
|
|
351
|
-
}
|
|
352
|
-
resetHistoryNavigation() {
|
|
353
|
-
this.historyIndex = -1;
|
|
354
|
-
this.historyBuffer = "";
|
|
355
|
-
}
|
|
356
274
|
// Getter methods for state
|
|
357
275
|
isFileSelectorActive() {
|
|
358
276
|
return this.showFileSelector;
|
|
@@ -360,9 +278,6 @@ export class InputManager {
|
|
|
360
278
|
isCommandSelectorActive() {
|
|
361
279
|
return this.showCommandSelector;
|
|
362
280
|
}
|
|
363
|
-
isMemoryTypeSelectorActive() {
|
|
364
|
-
return this.showMemoryTypeSelector;
|
|
365
|
-
}
|
|
366
281
|
getFileSelectorState() {
|
|
367
282
|
return {
|
|
368
283
|
show: this.showFileSelector,
|
|
@@ -378,12 +293,6 @@ export class InputManager {
|
|
|
378
293
|
position: this.slashPosition,
|
|
379
294
|
};
|
|
380
295
|
}
|
|
381
|
-
getMemoryTypeSelectorState() {
|
|
382
|
-
return {
|
|
383
|
-
show: this.showMemoryTypeSelector,
|
|
384
|
-
message: this.memoryMessage,
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
296
|
// Update search queries for active selectors
|
|
388
297
|
updateSearchQueriesForActiveSelectors(inputText, cursorPosition) {
|
|
389
298
|
if (this.showFileSelector && this.atPosition >= 0) {
|
|
@@ -411,9 +320,6 @@ export class InputManager {
|
|
|
411
320
|
// Only activate command selector if '/' is at the start of input
|
|
412
321
|
this.activateCommandSelector(this.cursorPosition - 1);
|
|
413
322
|
}
|
|
414
|
-
else if (char === "#" && this.cursorPosition === 1) {
|
|
415
|
-
// Memory message detection will be handled in submit
|
|
416
|
-
}
|
|
417
323
|
else {
|
|
418
324
|
// Update search queries for active selectors
|
|
419
325
|
this.updateSearchQueriesForActiveSelectors(this.inputText, this.cursorPosition);
|
|
@@ -539,12 +445,12 @@ export class InputManager {
|
|
|
539
445
|
}
|
|
540
446
|
}
|
|
541
447
|
// Task manager state methods
|
|
542
|
-
|
|
543
|
-
return this.
|
|
448
|
+
getShowBackgroundTaskManager() {
|
|
449
|
+
return this.showBackgroundTaskManager;
|
|
544
450
|
}
|
|
545
|
-
|
|
546
|
-
this.
|
|
547
|
-
this.callbacks.
|
|
451
|
+
setShowBackgroundTaskManager(show) {
|
|
452
|
+
this.showBackgroundTaskManager = show;
|
|
453
|
+
this.callbacks.onBackgroundTaskManagerStateChange?.(show);
|
|
548
454
|
}
|
|
549
455
|
getShowMcpManager() {
|
|
550
456
|
return this.showMcpManager;
|
|
@@ -560,6 +466,13 @@ export class InputManager {
|
|
|
560
466
|
this.showRewindManager = show;
|
|
561
467
|
this.callbacks.onRewindManagerStateChange?.(show);
|
|
562
468
|
}
|
|
469
|
+
getShowHelp() {
|
|
470
|
+
return this.showHelp;
|
|
471
|
+
}
|
|
472
|
+
setShowHelp(show) {
|
|
473
|
+
this.showHelp = show;
|
|
474
|
+
this.callbacks.onHelpStateChange?.(show);
|
|
475
|
+
}
|
|
563
476
|
// Permission mode methods
|
|
564
477
|
getPermissionMode() {
|
|
565
478
|
return this.permissionMode;
|
|
@@ -586,13 +499,6 @@ export class InputManager {
|
|
|
586
499
|
return;
|
|
587
500
|
}
|
|
588
501
|
if (this.inputText.trim()) {
|
|
589
|
-
const trimmedInput = this.inputText.trim();
|
|
590
|
-
// Check if it's a memory message (starts with # and only one line)
|
|
591
|
-
if (trimmedInput.startsWith("#") && !trimmedInput.includes("\n")) {
|
|
592
|
-
// Activate memory type selector
|
|
593
|
-
this.activateMemoryTypeSelector(trimmedInput);
|
|
594
|
-
return;
|
|
595
|
-
}
|
|
596
502
|
// Extract image information
|
|
597
503
|
const imageRegex = /\[Image #(\d+)\]/g;
|
|
598
504
|
const matches = [...this.inputText.matchAll(imageRegex)];
|
|
@@ -714,14 +620,6 @@ export class InputManager {
|
|
|
714
620
|
this.moveCursorRight();
|
|
715
621
|
return true;
|
|
716
622
|
}
|
|
717
|
-
if (("home" in key && key.home) || (key.ctrl && input === "a")) {
|
|
718
|
-
this.moveCursorToStart();
|
|
719
|
-
return true;
|
|
720
|
-
}
|
|
721
|
-
if (("end" in key && key.end) || (key.ctrl && input === "e")) {
|
|
722
|
-
this.moveCursorToEnd();
|
|
723
|
-
return true;
|
|
724
|
-
}
|
|
725
623
|
// Handle Ctrl+V for pasting images
|
|
726
624
|
if (key.ctrl && input === "v") {
|
|
727
625
|
this.handlePasteImage().catch((error) => {
|
|
@@ -739,15 +637,6 @@ export class InputManager {
|
|
|
739
637
|
this.callbacks.onBackgroundCurrentTask?.();
|
|
740
638
|
return true;
|
|
741
639
|
}
|
|
742
|
-
// Handle up/down keys for history navigation (only when no selector is active)
|
|
743
|
-
if (key.upArrow && !this.showFileSelector && !this.showCommandSelector) {
|
|
744
|
-
this.navigateHistory("up", this.inputText);
|
|
745
|
-
return true;
|
|
746
|
-
}
|
|
747
|
-
if (key.downArrow && !this.showFileSelector && !this.showCommandSelector) {
|
|
748
|
-
this.navigateHistory("down", this.inputText);
|
|
749
|
-
return true;
|
|
750
|
-
}
|
|
751
640
|
// Handle typing input
|
|
752
641
|
if (input &&
|
|
753
642
|
!key.ctrl &&
|
|
@@ -773,7 +662,11 @@ export class InputManager {
|
|
|
773
662
|
return true;
|
|
774
663
|
}
|
|
775
664
|
// Handle interrupt request - use Esc key to interrupt AI request or command
|
|
776
|
-
if (key.escape &&
|
|
665
|
+
if (key.escape &&
|
|
666
|
+
(isLoading || isCommandRunning) &&
|
|
667
|
+
!this.showBackgroundTaskManager &&
|
|
668
|
+
!this.showMcpManager &&
|
|
669
|
+
!this.showRewindManager) {
|
|
777
670
|
// Unified interrupt for AI message generation and command execution
|
|
778
671
|
this.callbacks.onAbortMessage?.();
|
|
779
672
|
return true;
|
|
@@ -788,16 +681,17 @@ export class InputManager {
|
|
|
788
681
|
if (this.showFileSelector ||
|
|
789
682
|
this.showCommandSelector ||
|
|
790
683
|
this.showHistorySearch ||
|
|
791
|
-
this.
|
|
792
|
-
this.showTaskManager ||
|
|
684
|
+
this.showBackgroundTaskManager ||
|
|
793
685
|
this.showMcpManager ||
|
|
794
|
-
this.showRewindManager
|
|
795
|
-
|
|
796
|
-
|
|
686
|
+
this.showRewindManager ||
|
|
687
|
+
this.showHelp) {
|
|
688
|
+
if (this.showBackgroundTaskManager ||
|
|
797
689
|
this.showMcpManager ||
|
|
798
|
-
this.showRewindManager
|
|
799
|
-
|
|
800
|
-
|
|
690
|
+
this.showRewindManager ||
|
|
691
|
+
this.showHelp) {
|
|
692
|
+
// Task manager, MCP manager, Rewind and Help don't need to handle input, handled by component itself
|
|
693
|
+
// Return true to indicate we've "handled" it (by ignoring it) so it doesn't leak to normal input
|
|
694
|
+
return true;
|
|
801
695
|
}
|
|
802
696
|
if (this.showHistorySearch) {
|
|
803
697
|
if (key.escape) {
|
package/dist/print-cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print-cli.d.ts","sourceRoot":"","sources":["../src/print-cli.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAgBD,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"print-cli.d.ts","sourceRoot":"","sources":["../src/print-cli.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAgBD,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA8J3E"}
|
package/dist/print-cli.js
CHANGED
|
@@ -48,38 +48,10 @@ export async function startPrintCli(options) {
|
|
|
48
48
|
// FR-001: Stream content updates for real-time display - output only the new chunk
|
|
49
49
|
process.stdout.write(chunk);
|
|
50
50
|
},
|
|
51
|
-
// Tool block callback - display tool name when tool starts
|
|
52
|
-
onToolBlockUpdated: (params) => {
|
|
53
|
-
// Print tool name only during 'running' stage (happens once per tool call)
|
|
54
|
-
if (params.stage === "running" && params.name) {
|
|
55
|
-
process.stdout.write(`\n🔧 ${params.name}`);
|
|
56
|
-
if (params.compactParams) {
|
|
57
|
-
process.stdout.write(` ${params.compactParams}`);
|
|
58
|
-
}
|
|
59
|
-
process.stdout.write(`\n`);
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
// Subagent block callbacks
|
|
63
|
-
onSubAgentBlockAdded: (subagentId, parameters) => {
|
|
64
|
-
// Display subagent creation with indentation
|
|
65
|
-
process.stdout.write(`\n🤖 Subagent [${parameters.subagent_type}]: ${parameters.description}\n`);
|
|
66
|
-
},
|
|
67
|
-
onSubAgentBlockUpdated: (subagentId, status) => {
|
|
68
|
-
// Display subagent status updates
|
|
69
|
-
const statusIconMap = {
|
|
70
|
-
active: "🔄",
|
|
71
|
-
completed: "✅",
|
|
72
|
-
error: "❌",
|
|
73
|
-
aborted: "⚠️",
|
|
74
|
-
};
|
|
75
|
-
const statusIcon = statusIconMap[status] ?? "🔄";
|
|
76
|
-
process.stdout.write(` ${statusIcon} Subagent status: ${status}\n`);
|
|
77
|
-
},
|
|
78
51
|
// Subagent message callbacks
|
|
79
52
|
onSubagentAssistantMessageAdded: (subagentId) => {
|
|
80
53
|
subagentReasoningStates.set(subagentId, false);
|
|
81
54
|
subagentContentStates.set(subagentId, false);
|
|
82
|
-
// Subagent assistant message started - add indentation
|
|
83
55
|
process.stdout.write("\n ");
|
|
84
56
|
},
|
|
85
57
|
onSubagentAssistantReasoningUpdated: (subagentId, chunk) => {
|
|
@@ -95,13 +67,22 @@ export async function startPrintCli(options) {
|
|
|
95
67
|
process.stdout.write("\n 📝 Response: ");
|
|
96
68
|
subagentContentStates.set(subagentId, true);
|
|
97
69
|
}
|
|
98
|
-
// Stream subagent content with indentation - output only the new chunk
|
|
99
70
|
process.stdout.write(chunk);
|
|
100
71
|
},
|
|
101
72
|
onSubagentUserMessageAdded: (_subagentId, params) => {
|
|
102
|
-
// Display subagent user messages with indentation
|
|
103
73
|
process.stdout.write(`\n 👤 User: ${params.content}\n`);
|
|
104
74
|
},
|
|
75
|
+
// Tool block callback - display tool name when tool starts
|
|
76
|
+
onToolBlockUpdated: (params) => {
|
|
77
|
+
// Print tool name only during 'running' stage (happens once per tool call)
|
|
78
|
+
if (params.stage === "running" && params.name) {
|
|
79
|
+
process.stdout.write(`\n🔧 ${params.name}`);
|
|
80
|
+
if (params.compactParams) {
|
|
81
|
+
process.stdout.write(` ${params.compactParams}`);
|
|
82
|
+
}
|
|
83
|
+
process.stdout.write(`\n`);
|
|
84
|
+
}
|
|
85
|
+
},
|
|
105
86
|
// Error block callback
|
|
106
87
|
onErrorBlockAdded: (error) => {
|
|
107
88
|
// Display error blocks with distinct formatting
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wave-code",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "CLI-based code assistant powered by AI, built with React and Ink",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,15 +30,14 @@
|
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"chalk": "^5.6.2",
|
|
33
|
-
"cli-highlight": "^2.1.11",
|
|
34
33
|
"diff": "^8.0.2",
|
|
35
34
|
"glob": "^13.0.0",
|
|
36
|
-
"ink": "^6.
|
|
37
|
-
"marked": "^
|
|
35
|
+
"ink": "^6.7.0",
|
|
36
|
+
"marked": "^17.0.2",
|
|
38
37
|
"react": "^19.2.4",
|
|
39
38
|
"react-dom": "19.2.4",
|
|
40
39
|
"yargs": "^17.7.2",
|
|
41
|
-
"wave-agent-sdk": "0.
|
|
40
|
+
"wave-agent-sdk": "0.6.2"
|
|
42
41
|
},
|
|
43
42
|
"devDependencies": {
|
|
44
43
|
"@types/react": "^19.1.8",
|
|
@@ -60,7 +59,7 @@
|
|
|
60
59
|
},
|
|
61
60
|
"license": "MIT",
|
|
62
61
|
"scripts": {
|
|
63
|
-
"wave": "tsx src/index.ts",
|
|
62
|
+
"wave": "tsx --tsconfig tsconfig.dev.json src/index.ts",
|
|
64
63
|
"build": "rimraf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
65
64
|
"type-check": "tsc --noEmit --incremental",
|
|
66
65
|
"watch": "tsc -p tsconfig.build.json --watch & tsc-alias -p tsconfig.build.json --watch",
|
package/src/components/App.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useState, useEffect, useRef } from "react";
|
|
2
|
+
import { useStdout } from "ink";
|
|
2
3
|
import { ChatInterface } from "./ChatInterface.js";
|
|
3
|
-
import { ChatProvider } from "../contexts/useChat.js";
|
|
4
|
+
import { ChatProvider, useChat } from "../contexts/useChat.js";
|
|
4
5
|
import { AppProvider } from "../contexts/useAppConfig.js";
|
|
5
6
|
|
|
6
7
|
interface AppProps {
|
|
@@ -16,11 +17,58 @@ const AppWithProviders: React.FC<{
|
|
|
16
17
|
}> = ({ bypassPermissions, pluginDirs }) => {
|
|
17
18
|
return (
|
|
18
19
|
<ChatProvider bypassPermissions={bypassPermissions} pluginDirs={pluginDirs}>
|
|
19
|
-
<
|
|
20
|
+
<ChatInterfaceWithRemount />
|
|
20
21
|
</ChatProvider>
|
|
21
22
|
);
|
|
22
23
|
};
|
|
23
24
|
|
|
25
|
+
const ChatInterfaceWithRemount: React.FC = () => {
|
|
26
|
+
const { stdout } = useStdout();
|
|
27
|
+
const { isExpanded, rewindId, wasLastDetailsTooTall, sessionId } = useChat();
|
|
28
|
+
|
|
29
|
+
const [remountKey, setRemountKey] = useState(
|
|
30
|
+
String(isExpanded) + rewindId + wasLastDetailsTooTall,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const prevSessionId = useRef(sessionId);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const newKey =
|
|
37
|
+
String(isExpanded) +
|
|
38
|
+
rewindId +
|
|
39
|
+
wasLastDetailsTooTall +
|
|
40
|
+
(prevSessionId.current && sessionId && prevSessionId.current !== sessionId
|
|
41
|
+
? sessionId
|
|
42
|
+
: "");
|
|
43
|
+
|
|
44
|
+
if (newKey !== remountKey) {
|
|
45
|
+
const timeout = setTimeout(() => {
|
|
46
|
+
stdout?.write("\u001b[2J\u001b[0;0H", (err?: Error | null) => {
|
|
47
|
+
if (err) {
|
|
48
|
+
console.error("Failed to clear terminal:", err);
|
|
49
|
+
}
|
|
50
|
+
setRemountKey(newKey);
|
|
51
|
+
});
|
|
52
|
+
}, 100);
|
|
53
|
+
|
|
54
|
+
return () => clearTimeout(timeout);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (sessionId) {
|
|
58
|
+
prevSessionId.current = sessionId;
|
|
59
|
+
}
|
|
60
|
+
}, [
|
|
61
|
+
isExpanded,
|
|
62
|
+
rewindId,
|
|
63
|
+
wasLastDetailsTooTall,
|
|
64
|
+
sessionId,
|
|
65
|
+
remountKey,
|
|
66
|
+
stdout,
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
return <ChatInterface key={remountKey} />;
|
|
70
|
+
};
|
|
71
|
+
|
|
24
72
|
export const App: React.FC<AppProps> = ({
|
|
25
73
|
restoreSessionId,
|
|
26
74
|
continueLastSession,
|
|
@@ -12,11 +12,13 @@ interface Task {
|
|
|
12
12
|
runtime?: number;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export interface
|
|
15
|
+
export interface BackgroundTaskManagerProps {
|
|
16
16
|
onCancel: () => void;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export const
|
|
19
|
+
export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
|
|
20
|
+
onCancel,
|
|
21
|
+
}) => {
|
|
20
22
|
const { backgroundTasks, getBackgroundTaskOutput, stopBackgroundTask } =
|
|
21
23
|
useChat();
|
|
22
24
|
const [tasks, setTasks] = useState<Task[]>([]);
|
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Box } from "ink";
|
|
1
|
+
import React, { useState, useCallback } from "react";
|
|
2
|
+
import { Box, useStdout } from "ink";
|
|
3
3
|
import { MessageList } from "./MessageList.js";
|
|
4
4
|
import { InputBox } from "./InputBox.js";
|
|
5
|
-
import {
|
|
5
|
+
import { LoadingIndicator } from "./LoadingIndicator.js";
|
|
6
|
+
import { TaskList } from "./TaskList.js";
|
|
7
|
+
import { ConfirmationDetails } from "./ConfirmationDetails.js";
|
|
8
|
+
import { ConfirmationSelector } from "./ConfirmationSelector.js";
|
|
9
|
+
|
|
6
10
|
import { useChat } from "../contexts/useChat.js";
|
|
11
|
+
import type { PermissionDecision } from "wave-agent-sdk";
|
|
7
12
|
|
|
8
13
|
export const ChatInterface: React.FC = () => {
|
|
14
|
+
const { stdout } = useStdout();
|
|
15
|
+
const [isDetailsTooTall, setIsDetailsTooTall] = useState(false);
|
|
16
|
+
|
|
9
17
|
const {
|
|
10
18
|
messages,
|
|
11
19
|
isLoading,
|
|
12
20
|
isCommandRunning,
|
|
13
|
-
userInputHistory,
|
|
14
21
|
isCompressing,
|
|
15
22
|
sendMessage,
|
|
16
23
|
abortMessage,
|
|
17
|
-
saveMemory,
|
|
18
24
|
mcpServers,
|
|
19
25
|
connectMcpServer,
|
|
20
26
|
disconnectMcpServer,
|
|
@@ -26,45 +32,96 @@ export const ChatInterface: React.FC = () => {
|
|
|
26
32
|
isConfirmationVisible,
|
|
27
33
|
confirmingTool,
|
|
28
34
|
handleConfirmationDecision,
|
|
29
|
-
handleConfirmationCancel,
|
|
30
|
-
|
|
35
|
+
handleConfirmationCancel: originalHandleConfirmationCancel,
|
|
36
|
+
setWasLastDetailsTooTall,
|
|
31
37
|
} = useChat();
|
|
32
38
|
|
|
39
|
+
const handleHeightMeasured = useCallback(
|
|
40
|
+
(height: number) => {
|
|
41
|
+
const terminalHeight = stdout?.rows || 24;
|
|
42
|
+
if (height > terminalHeight - 10) {
|
|
43
|
+
setIsDetailsTooTall(true);
|
|
44
|
+
} else {
|
|
45
|
+
setIsDetailsTooTall(false);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
[stdout?.rows],
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const handleConfirmationCancel = useCallback(() => {
|
|
52
|
+
if (isDetailsTooTall) {
|
|
53
|
+
setWasLastDetailsTooTall((prev) => prev + 1);
|
|
54
|
+
setIsDetailsTooTall(false);
|
|
55
|
+
}
|
|
56
|
+
originalHandleConfirmationCancel();
|
|
57
|
+
}, [
|
|
58
|
+
isDetailsTooTall,
|
|
59
|
+
originalHandleConfirmationCancel,
|
|
60
|
+
setWasLastDetailsTooTall,
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
const wrappedHandleConfirmationDecision = useCallback(
|
|
64
|
+
(decision: PermissionDecision) => {
|
|
65
|
+
if (isDetailsTooTall) {
|
|
66
|
+
setWasLastDetailsTooTall((prev) => prev + 1);
|
|
67
|
+
setIsDetailsTooTall(false);
|
|
68
|
+
}
|
|
69
|
+
handleConfirmationDecision(decision);
|
|
70
|
+
},
|
|
71
|
+
[isDetailsTooTall, handleConfirmationDecision, setWasLastDetailsTooTall],
|
|
72
|
+
);
|
|
73
|
+
|
|
33
74
|
if (!sessionId) return null;
|
|
34
75
|
|
|
35
76
|
return (
|
|
36
|
-
<Box flexDirection="column"
|
|
77
|
+
<Box flexDirection="column">
|
|
37
78
|
<MessageList
|
|
38
79
|
messages={messages}
|
|
39
80
|
isLoading={isLoading}
|
|
40
81
|
isCommandRunning={isCommandRunning}
|
|
41
|
-
isCompressing={isCompressing}
|
|
42
|
-
latestTotalTokens={latestTotalTokens}
|
|
43
82
|
isExpanded={isExpanded}
|
|
44
|
-
|
|
83
|
+
forceStaticLastMessage={isDetailsTooTall}
|
|
45
84
|
/>
|
|
46
85
|
|
|
86
|
+
{(isLoading || isCommandRunning || isCompressing) &&
|
|
87
|
+
!isConfirmationVisible &&
|
|
88
|
+
!isExpanded && (
|
|
89
|
+
<LoadingIndicator
|
|
90
|
+
isLoading={isLoading}
|
|
91
|
+
isCommandRunning={isCommandRunning}
|
|
92
|
+
isCompressing={isCompressing}
|
|
93
|
+
latestTotalTokens={latestTotalTokens}
|
|
94
|
+
/>
|
|
95
|
+
)}
|
|
96
|
+
{!isConfirmationVisible && !isExpanded && <TaskList />}
|
|
97
|
+
|
|
47
98
|
{isConfirmationVisible && (
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
99
|
+
<>
|
|
100
|
+
<ConfirmationDetails
|
|
101
|
+
toolName={confirmingTool!.name}
|
|
102
|
+
toolInput={confirmingTool!.input}
|
|
103
|
+
isExpanded={isExpanded}
|
|
104
|
+
onHeightMeasured={handleHeightMeasured}
|
|
105
|
+
/>
|
|
106
|
+
<ConfirmationSelector
|
|
107
|
+
toolName={confirmingTool!.name}
|
|
108
|
+
toolInput={confirmingTool!.input}
|
|
109
|
+
suggestedPrefix={confirmingTool!.suggestedPrefix}
|
|
110
|
+
hidePersistentOption={confirmingTool!.hidePersistentOption}
|
|
111
|
+
isExpanded={isExpanded}
|
|
112
|
+
onDecision={wrappedHandleConfirmationDecision}
|
|
113
|
+
onCancel={handleConfirmationCancel}
|
|
114
|
+
onAbort={abortMessage}
|
|
115
|
+
/>
|
|
116
|
+
</>
|
|
58
117
|
)}
|
|
59
118
|
|
|
60
119
|
{!isConfirmationVisible && !isExpanded && (
|
|
61
120
|
<InputBox
|
|
62
121
|
isLoading={isLoading}
|
|
63
122
|
isCommandRunning={isCommandRunning}
|
|
64
|
-
userInputHistory={userInputHistory}
|
|
65
123
|
sendMessage={sendMessage}
|
|
66
124
|
abortMessage={abortMessage}
|
|
67
|
-
saveMemory={saveMemory}
|
|
68
125
|
mcpServers={mcpServers}
|
|
69
126
|
connectMcpServer={connectMcpServer}
|
|
70
127
|
disconnectMcpServer={disconnectMcpServer}
|