wave-code 0.2.0 → 0.4.0
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/commands/plugin/disable.d.ts +2 -1
- package/dist/commands/plugin/disable.d.ts.map +1 -1
- package/dist/commands/plugin/disable.js +3 -2
- package/dist/commands/plugin/enable.d.ts +2 -1
- package/dist/commands/plugin/enable.d.ts.map +1 -1
- package/dist/commands/plugin/enable.js +3 -2
- package/dist/commands/plugin/install.d.ts +2 -1
- package/dist/commands/plugin/install.d.ts.map +1 -1
- package/dist/commands/plugin/list.d.ts.map +1 -1
- package/dist/commands/plugin/list.js +15 -3
- package/dist/commands/plugin/marketplace.d.ts +3 -0
- package/dist/commands/plugin/marketplace.d.ts.map +1 -1
- package/dist/commands/plugin/marketplace.js +15 -1
- package/dist/commands/plugin/uninstall.d.ts +4 -0
- package/dist/commands/plugin/uninstall.d.ts.map +1 -0
- package/dist/commands/plugin/uninstall.js +29 -0
- package/dist/commands/plugin/update.d.ts +4 -0
- package/dist/commands/plugin/update.d.ts.map +1 -0
- package/dist/commands/plugin/update.js +15 -0
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +2 -2
- package/dist/components/CommandSelector.d.ts.map +1 -1
- package/dist/components/CommandSelector.js +6 -0
- package/dist/components/Confirmation.js +1 -1
- package/dist/components/DiscoverView.d.ts +3 -0
- package/dist/components/DiscoverView.d.ts.map +1 -0
- package/dist/components/DiscoverView.js +25 -0
- package/dist/components/FileSelector.js +1 -1
- package/dist/components/HistorySearch.d.ts +8 -0
- package/dist/components/HistorySearch.d.ts.map +1 -0
- package/dist/components/HistorySearch.js +67 -0
- package/dist/components/InputBox.d.ts +1 -1
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +26 -17
- package/dist/components/InstalledView.d.ts +3 -0
- package/dist/components/InstalledView.d.ts.map +1 -0
- package/dist/components/InstalledView.js +30 -0
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/Markdown.js +22 -9
- package/dist/components/MarketplaceAddForm.d.ts +3 -0
- package/dist/components/MarketplaceAddForm.d.ts.map +1 -0
- package/dist/components/MarketplaceAddForm.js +26 -0
- package/dist/components/MarketplaceDetail.d.ts +3 -0
- package/dist/components/MarketplaceDetail.d.ts.map +1 -0
- package/dist/components/MarketplaceDetail.js +38 -0
- package/dist/components/MarketplaceList.d.ts +9 -0
- package/dist/components/MarketplaceList.d.ts.map +1 -0
- package/dist/components/MarketplaceList.js +16 -0
- package/dist/components/MarketplaceView.d.ts +3 -0
- package/dist/components/MarketplaceView.d.ts.map +1 -0
- package/dist/components/MarketplaceView.js +28 -0
- package/dist/components/PluginDetail.d.ts +3 -0
- package/dist/components/PluginDetail.d.ts.map +1 -0
- package/dist/components/PluginDetail.js +63 -0
- package/dist/components/PluginList.d.ts +14 -0
- package/dist/components/PluginList.d.ts.map +1 -0
- package/dist/components/PluginList.js +12 -0
- package/dist/components/PluginManagerShell.d.ts +5 -0
- package/dist/components/PluginManagerShell.d.ts.map +1 -0
- package/dist/components/PluginManagerShell.js +89 -0
- package/dist/components/PluginManagerTypes.d.ts +33 -0
- package/dist/components/PluginManagerTypes.d.ts.map +1 -0
- package/dist/components/PluginManagerTypes.js +1 -0
- package/dist/components/RewindCommand.d.ts +9 -0
- package/dist/components/RewindCommand.d.ts.map +1 -0
- package/dist/components/RewindCommand.js +42 -0
- package/dist/components/SessionSelector.d.ts +11 -0
- package/dist/components/SessionSelector.d.ts.map +1 -0
- package/dist/components/SessionSelector.js +38 -0
- package/dist/components/SubagentBlock.d.ts.map +1 -1
- package/dist/components/SubagentBlock.js +20 -1
- package/dist/components/ToolResultDisplay.js +1 -1
- package/dist/contexts/PluginManagerContext.d.ts +4 -0
- package/dist/contexts/PluginManagerContext.d.ts.map +1 -0
- package/dist/contexts/PluginManagerContext.js +9 -0
- package/dist/contexts/useChat.d.ts +2 -0
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +21 -0
- package/dist/hooks/useInputManager.d.ts +6 -14
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +29 -45
- package/dist/hooks/usePluginManager.d.ts +3 -0
- package/dist/hooks/usePluginManager.d.ts.map +1 -0
- package/dist/hooks/usePluginManager.js +223 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +150 -177
- package/dist/managers/InputManager.d.ts +12 -21
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +77 -108
- package/dist/plugin-manager-cli.d.ts +6 -0
- package/dist/plugin-manager-cli.d.ts.map +1 -0
- package/dist/plugin-manager-cli.js +12 -0
- package/dist/session-selector-cli.d.ts +2 -0
- package/dist/session-selector-cli.d.ts.map +1 -0
- package/dist/session-selector-cli.js +25 -0
- package/package.json +7 -3
- package/src/commands/plugin/disable.ts +7 -3
- package/src/commands/plugin/enable.ts +7 -3
- package/src/commands/plugin/install.ts +2 -1
- package/src/commands/plugin/list.ts +21 -3
- package/src/commands/plugin/marketplace.ts +17 -1
- package/src/commands/plugin/uninstall.ts +39 -0
- package/src/commands/plugin/update.ts +19 -0
- package/src/components/ChatInterface.tsx +2 -1
- package/src/components/CommandSelector.tsx +7 -0
- package/src/components/Confirmation.tsx +1 -1
- package/src/components/DiscoverView.tsx +31 -0
- package/src/components/FileSelector.tsx +1 -1
- package/src/components/HistorySearch.tsx +148 -0
- package/src/components/InputBox.tsx +43 -28
- package/src/components/InstalledView.tsx +61 -0
- package/src/components/Markdown.tsx +37 -26
- package/src/components/MarketplaceAddForm.tsx +39 -0
- package/src/components/MarketplaceDetail.tsx +79 -0
- package/src/components/MarketplaceList.tsx +52 -0
- package/src/components/MarketplaceView.tsx +43 -0
- package/src/components/PluginDetail.tsx +147 -0
- package/src/components/PluginList.tsx +51 -0
- package/src/components/PluginManagerShell.tsx +189 -0
- package/src/components/PluginManagerTypes.ts +47 -0
- package/src/components/RewindCommand.tsx +114 -0
- package/src/components/SessionSelector.tsx +127 -0
- package/src/components/SubagentBlock.tsx +29 -1
- package/src/components/ToolResultDisplay.tsx +2 -2
- package/src/contexts/PluginManagerContext.ts +15 -0
- package/src/contexts/useChat.tsx +26 -0
- package/src/hooks/useInputManager.ts +29 -61
- package/src/hooks/usePluginManager.ts +296 -0
- package/src/index.ts +241 -280
- package/src/managers/InputManager.ts +93 -149
- package/src/plugin-manager-cli.tsx +13 -0
- package/src/session-selector-cli.tsx +37 -0
- package/dist/components/BashHistorySelector.d.ts +0 -11
- package/dist/components/BashHistorySelector.d.ts.map +0 -1
- package/dist/components/BashHistorySelector.js +0 -93
- package/dist/hooks/usePagination.d.ts +0 -20
- package/dist/hooks/usePagination.d.ts.map +0 -1
- package/dist/hooks/usePagination.js +0 -168
- package/src/components/BashHistorySelector.tsx +0 -181
- package/src/hooks/usePagination.ts +0 -203
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { searchFiles as searchFilesUtil,
|
|
1
|
+
import { searchFiles as searchFilesUtil, PromptHistoryManager, } from "wave-agent-sdk";
|
|
2
2
|
import { readClipboardImage } from "../utils/clipboard.js";
|
|
3
3
|
export class InputManager {
|
|
4
4
|
constructor(callbacks = {}) {
|
|
@@ -15,10 +15,9 @@ export class InputManager {
|
|
|
15
15
|
this.showCommandSelector = false;
|
|
16
16
|
this.slashPosition = -1;
|
|
17
17
|
this.commandSearchQuery = "";
|
|
18
|
-
//
|
|
19
|
-
this.
|
|
20
|
-
this.
|
|
21
|
-
this.bashHistorySearchQuery = "";
|
|
18
|
+
// History search state
|
|
19
|
+
this.showHistorySearch = false;
|
|
20
|
+
this.historySearchQuery = "";
|
|
22
21
|
// Memory type selector state
|
|
23
22
|
this.showMemoryTypeSelector = false;
|
|
24
23
|
this.memoryMessage = "";
|
|
@@ -40,6 +39,7 @@ export class InputManager {
|
|
|
40
39
|
// Additional UI state
|
|
41
40
|
this.showBashManager = false;
|
|
42
41
|
this.showMcpManager = false;
|
|
42
|
+
this.showRewindManager = false;
|
|
43
43
|
// Permission mode state
|
|
44
44
|
this.permissionMode = "default";
|
|
45
45
|
// Flag to prevent handleInput conflicts when selector selection occurs
|
|
@@ -228,6 +228,11 @@ export class InputManager {
|
|
|
228
228
|
this.callbacks.onShowMcpManager();
|
|
229
229
|
commandExecuted = true;
|
|
230
230
|
}
|
|
231
|
+
else if (command === "rewind" &&
|
|
232
|
+
this.callbacks.onShowRewindManager) {
|
|
233
|
+
this.callbacks.onShowRewindManager();
|
|
234
|
+
commandExecuted = true;
|
|
235
|
+
}
|
|
231
236
|
}
|
|
232
237
|
})();
|
|
233
238
|
this.handleCancelCommandSelect();
|
|
@@ -275,72 +280,6 @@ export class InputManager {
|
|
|
275
280
|
}
|
|
276
281
|
return false;
|
|
277
282
|
}
|
|
278
|
-
// Bash history selector methods
|
|
279
|
-
activateBashHistorySelector(position) {
|
|
280
|
-
this.showBashHistorySelector = true;
|
|
281
|
-
this.exclamationPosition = position;
|
|
282
|
-
this.bashHistorySearchQuery = "";
|
|
283
|
-
this.callbacks.onBashHistorySelectorStateChange?.(true, "", position);
|
|
284
|
-
}
|
|
285
|
-
updateBashHistorySearchQuery(query) {
|
|
286
|
-
this.bashHistorySearchQuery = query;
|
|
287
|
-
this.callbacks.onBashHistorySelectorStateChange?.(this.showBashHistorySelector, query, this.exclamationPosition);
|
|
288
|
-
}
|
|
289
|
-
handleBashHistorySelect(command) {
|
|
290
|
-
if (this.exclamationPosition >= 0) {
|
|
291
|
-
const beforeExclamation = this.inputText.substring(0, this.exclamationPosition);
|
|
292
|
-
const afterQuery = this.inputText.substring(this.cursorPosition);
|
|
293
|
-
const newInput = beforeExclamation + `!${command}` + afterQuery;
|
|
294
|
-
const newCursorPosition = beforeExclamation.length + command.length + 1;
|
|
295
|
-
this.inputText = newInput;
|
|
296
|
-
this.cursorPosition = newCursorPosition;
|
|
297
|
-
this.handleCancelBashHistorySelect();
|
|
298
|
-
// Set flag to prevent handleInput from processing the same Enter key
|
|
299
|
-
this.selectorJustUsed = true;
|
|
300
|
-
setTimeout(() => {
|
|
301
|
-
this.selectorJustUsed = false;
|
|
302
|
-
}, 0);
|
|
303
|
-
this.callbacks.onInputTextChange?.(newInput);
|
|
304
|
-
this.callbacks.onCursorPositionChange?.(newCursorPosition);
|
|
305
|
-
return { newInput, newCursorPosition };
|
|
306
|
-
}
|
|
307
|
-
return { newInput: this.inputText, newCursorPosition: this.cursorPosition };
|
|
308
|
-
}
|
|
309
|
-
handleCancelBashHistorySelect() {
|
|
310
|
-
this.showBashHistorySelector = false;
|
|
311
|
-
this.exclamationPosition = -1;
|
|
312
|
-
this.bashHistorySearchQuery = "";
|
|
313
|
-
this.callbacks.onBashHistorySelectorStateChange?.(false, "", -1);
|
|
314
|
-
}
|
|
315
|
-
handleBashHistoryExecute(command) {
|
|
316
|
-
this.showBashHistorySelector = false;
|
|
317
|
-
this.exclamationPosition = -1;
|
|
318
|
-
this.bashHistorySearchQuery = "";
|
|
319
|
-
this.callbacks.onBashHistorySelectorStateChange?.(false, "", -1);
|
|
320
|
-
return command; // Return command to execute
|
|
321
|
-
}
|
|
322
|
-
handleBashHistoryExecuteAndSend(command) {
|
|
323
|
-
const commandToExecute = this.handleBashHistoryExecute(command);
|
|
324
|
-
// Clear input box and execute command, ensure command starts with !
|
|
325
|
-
const bashCommand = commandToExecute.startsWith("!")
|
|
326
|
-
? commandToExecute
|
|
327
|
-
: `!${commandToExecute}`;
|
|
328
|
-
this.clearInput();
|
|
329
|
-
this.callbacks.onSendMessage?.(bashCommand);
|
|
330
|
-
}
|
|
331
|
-
handleBashHistoryDelete(command, workdir) {
|
|
332
|
-
deleteBashCommandFromHistory(command, workdir);
|
|
333
|
-
// Trigger a refresh of the selector state to force re-render of BashHistorySelector
|
|
334
|
-
this.callbacks.onBashHistorySelectorStateChange?.(this.showBashHistorySelector, this.bashHistorySearchQuery, this.exclamationPosition);
|
|
335
|
-
}
|
|
336
|
-
checkForExclamationDeletion(cursorPosition) {
|
|
337
|
-
if (this.showBashHistorySelector &&
|
|
338
|
-
cursorPosition <= this.exclamationPosition) {
|
|
339
|
-
this.handleCancelBashHistorySelect();
|
|
340
|
-
return true;
|
|
341
|
-
}
|
|
342
|
-
return false;
|
|
343
|
-
}
|
|
344
283
|
// Memory type selector methods
|
|
345
284
|
activateMemoryTypeSelector(message) {
|
|
346
285
|
this.showMemoryTypeSelector = true;
|
|
@@ -421,9 +360,6 @@ export class InputManager {
|
|
|
421
360
|
isCommandSelectorActive() {
|
|
422
361
|
return this.showCommandSelector;
|
|
423
362
|
}
|
|
424
|
-
isBashHistorySelectorActive() {
|
|
425
|
-
return this.showBashHistorySelector;
|
|
426
|
-
}
|
|
427
363
|
isMemoryTypeSelectorActive() {
|
|
428
364
|
return this.showMemoryTypeSelector;
|
|
429
365
|
}
|
|
@@ -442,13 +378,6 @@ export class InputManager {
|
|
|
442
378
|
position: this.slashPosition,
|
|
443
379
|
};
|
|
444
380
|
}
|
|
445
|
-
getBashHistorySelectorState() {
|
|
446
|
-
return {
|
|
447
|
-
show: this.showBashHistorySelector,
|
|
448
|
-
query: this.bashHistorySearchQuery,
|
|
449
|
-
position: this.exclamationPosition,
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
381
|
getMemoryTypeSelectorState() {
|
|
453
382
|
return {
|
|
454
383
|
show: this.showMemoryTypeSelector,
|
|
@@ -469,25 +398,19 @@ export class InputManager {
|
|
|
469
398
|
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
470
399
|
this.updateCommandSearchQuery(newQuery);
|
|
471
400
|
}
|
|
472
|
-
else if (this.showBashHistorySelector && this.exclamationPosition >= 0) {
|
|
473
|
-
const queryStart = this.exclamationPosition + 1;
|
|
474
|
-
const queryEnd = cursorPosition;
|
|
475
|
-
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
476
|
-
this.updateBashHistorySearchQuery(newQuery);
|
|
477
|
-
}
|
|
478
401
|
}
|
|
479
402
|
// Handle special character input that might trigger selectors
|
|
480
403
|
handleSpecialCharInput(char) {
|
|
481
404
|
if (char === "@") {
|
|
482
405
|
this.activateFileSelector(this.cursorPosition - 1);
|
|
483
406
|
}
|
|
484
|
-
else if (char === "/" &&
|
|
407
|
+
else if (char === "/" &&
|
|
408
|
+
!this.showFileSelector &&
|
|
409
|
+
this.cursorPosition === 1) {
|
|
485
410
|
// Don't activate command selector when file selector is active
|
|
411
|
+
// Only activate command selector if '/' is at the start of input
|
|
486
412
|
this.activateCommandSelector(this.cursorPosition - 1);
|
|
487
413
|
}
|
|
488
|
-
else if (char === "!" && this.cursorPosition === 1) {
|
|
489
|
-
this.activateBashHistorySelector(0);
|
|
490
|
-
}
|
|
491
414
|
else if (char === "#" && this.cursorPosition === 1) {
|
|
492
415
|
// Memory message detection will be handled in submit
|
|
493
416
|
}
|
|
@@ -630,6 +553,13 @@ export class InputManager {
|
|
|
630
553
|
this.showMcpManager = show;
|
|
631
554
|
this.callbacks.onMcpManagerStateChange?.(show);
|
|
632
555
|
}
|
|
556
|
+
getShowRewindManager() {
|
|
557
|
+
return this.showRewindManager;
|
|
558
|
+
}
|
|
559
|
+
setShowRewindManager(show) {
|
|
560
|
+
this.showRewindManager = show;
|
|
561
|
+
this.callbacks.onRewindManagerStateChange?.(show);
|
|
562
|
+
}
|
|
633
563
|
// Permission mode methods
|
|
634
564
|
getPermissionMode() {
|
|
635
565
|
return this.permissionMode;
|
|
@@ -676,6 +606,10 @@ export class InputManager {
|
|
|
676
606
|
// Remove image placeholders, expand long text placeholders, send message
|
|
677
607
|
let cleanContent = this.inputText.replace(imageRegex, "").trim();
|
|
678
608
|
cleanContent = this.expandLongTextPlaceholders(cleanContent);
|
|
609
|
+
// Save to prompt history
|
|
610
|
+
PromptHistoryManager.addEntry(cleanContent).catch((err) => {
|
|
611
|
+
this.logger?.error("Failed to save prompt history", err);
|
|
612
|
+
});
|
|
679
613
|
this.callbacks.onSendMessage?.(cleanContent, referencedImages.length > 0 ? referencedImages : undefined);
|
|
680
614
|
this.clearInput();
|
|
681
615
|
this.callbacks.onResetHistoryNavigation?.();
|
|
@@ -691,7 +625,6 @@ export class InputManager {
|
|
|
691
625
|
// Check for special character deletion
|
|
692
626
|
this.checkForAtDeletion(newCursorPosition);
|
|
693
627
|
this.checkForSlashDeletion(newCursorPosition);
|
|
694
|
-
this.checkForExclamationDeletion(newCursorPosition);
|
|
695
628
|
// Update search queries using the same logic as character input
|
|
696
629
|
this.updateSearchQueriesForActiveSelectors(newInput, newCursorPosition);
|
|
697
630
|
});
|
|
@@ -724,6 +657,28 @@ export class InputManager {
|
|
|
724
657
|
}
|
|
725
658
|
return false;
|
|
726
659
|
}
|
|
660
|
+
// History search methods
|
|
661
|
+
activateHistorySearch() {
|
|
662
|
+
this.showHistorySearch = true;
|
|
663
|
+
this.historySearchQuery = "";
|
|
664
|
+
this.callbacks.onHistorySearchStateChange?.(true, "");
|
|
665
|
+
}
|
|
666
|
+
updateHistorySearchQuery(query) {
|
|
667
|
+
this.historySearchQuery = query;
|
|
668
|
+
this.callbacks.onHistorySearchStateChange?.(true, query);
|
|
669
|
+
}
|
|
670
|
+
handleHistorySearchSelect(prompt) {
|
|
671
|
+
this.inputText = prompt;
|
|
672
|
+
this.cursorPosition = prompt.length;
|
|
673
|
+
this.callbacks.onInputTextChange?.(prompt);
|
|
674
|
+
this.callbacks.onCursorPositionChange?.(prompt.length);
|
|
675
|
+
this.handleCancelHistorySearch();
|
|
676
|
+
}
|
|
677
|
+
handleCancelHistorySearch() {
|
|
678
|
+
this.showHistorySearch = false;
|
|
679
|
+
this.historySearchQuery = "";
|
|
680
|
+
this.callbacks.onHistorySearchStateChange?.(false, "");
|
|
681
|
+
}
|
|
727
682
|
// Handle normal input (when no selector is active)
|
|
728
683
|
async handleNormalInput(input, key, attachedImages, isLoading = false, isCommandRunning = false, clearImages) {
|
|
729
684
|
if (key.return) {
|
|
@@ -738,9 +693,6 @@ export class InputManager {
|
|
|
738
693
|
else if (this.showCommandSelector) {
|
|
739
694
|
this.handleCancelCommandSelect();
|
|
740
695
|
}
|
|
741
|
-
else if (this.showBashHistorySelector) {
|
|
742
|
-
this.handleCancelBashHistorySelect();
|
|
743
|
-
}
|
|
744
696
|
return true;
|
|
745
697
|
}
|
|
746
698
|
if (key.backspace || key.delete) {
|
|
@@ -751,7 +703,6 @@ export class InputManager {
|
|
|
751
703
|
const newCursorPosition = this.cursorPosition - 1;
|
|
752
704
|
this.checkForAtDeletion(newCursorPosition);
|
|
753
705
|
this.checkForSlashDeletion(newCursorPosition);
|
|
754
|
-
this.checkForExclamationDeletion(newCursorPosition);
|
|
755
706
|
}
|
|
756
707
|
return true;
|
|
757
708
|
}
|
|
@@ -778,18 +729,17 @@ export class InputManager {
|
|
|
778
729
|
});
|
|
779
730
|
return true;
|
|
780
731
|
}
|
|
732
|
+
// Handle Ctrl+R for history search
|
|
733
|
+
if (key.ctrl && input === "r") {
|
|
734
|
+
this.activateHistorySearch();
|
|
735
|
+
return true;
|
|
736
|
+
}
|
|
781
737
|
// Handle up/down keys for history navigation (only when no selector is active)
|
|
782
|
-
if (key.upArrow &&
|
|
783
|
-
!this.showFileSelector &&
|
|
784
|
-
!this.showCommandSelector &&
|
|
785
|
-
!this.showBashHistorySelector) {
|
|
738
|
+
if (key.upArrow && !this.showFileSelector && !this.showCommandSelector) {
|
|
786
739
|
this.navigateHistory("up", this.inputText);
|
|
787
740
|
return true;
|
|
788
741
|
}
|
|
789
|
-
if (key.downArrow &&
|
|
790
|
-
!this.showFileSelector &&
|
|
791
|
-
!this.showCommandSelector &&
|
|
792
|
-
!this.showBashHistorySelector) {
|
|
742
|
+
if (key.downArrow && !this.showFileSelector && !this.showCommandSelector) {
|
|
793
743
|
this.navigateHistory("down", this.inputText);
|
|
794
744
|
return true;
|
|
795
745
|
}
|
|
@@ -832,16 +782,35 @@ export class InputManager {
|
|
|
832
782
|
// Check if any selector is active
|
|
833
783
|
if (this.showFileSelector ||
|
|
834
784
|
this.showCommandSelector ||
|
|
835
|
-
this.
|
|
785
|
+
this.showHistorySearch ||
|
|
836
786
|
this.showMemoryTypeSelector ||
|
|
837
787
|
this.showBashManager ||
|
|
838
|
-
this.showMcpManager
|
|
788
|
+
this.showMcpManager ||
|
|
789
|
+
this.showRewindManager) {
|
|
839
790
|
if (this.showMemoryTypeSelector ||
|
|
840
791
|
this.showBashManager ||
|
|
841
|
-
this.showMcpManager
|
|
842
|
-
|
|
792
|
+
this.showMcpManager ||
|
|
793
|
+
this.showRewindManager) {
|
|
794
|
+
// Memory type selector, bash manager, MCP manager and Rewind don't need to handle input, handled by component itself
|
|
843
795
|
return false;
|
|
844
796
|
}
|
|
797
|
+
if (this.showHistorySearch) {
|
|
798
|
+
if (key.escape) {
|
|
799
|
+
this.handleCancelHistorySearch();
|
|
800
|
+
return true;
|
|
801
|
+
}
|
|
802
|
+
if (key.backspace || key.delete) {
|
|
803
|
+
if (this.historySearchQuery.length > 0) {
|
|
804
|
+
this.updateHistorySearchQuery(this.historySearchQuery.slice(0, -1));
|
|
805
|
+
}
|
|
806
|
+
return true;
|
|
807
|
+
}
|
|
808
|
+
if (input && !key.ctrl && !key.meta && !key.return && !key.tab) {
|
|
809
|
+
this.updateHistorySearchQuery(this.historySearchQuery + input);
|
|
810
|
+
return true;
|
|
811
|
+
}
|
|
812
|
+
return true; // Let HistorySearch component handle arrows and Enter
|
|
813
|
+
}
|
|
845
814
|
return this.handleSelectorInput(input, key);
|
|
846
815
|
}
|
|
847
816
|
else {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-manager-cli.d.ts","sourceRoot":"","sources":["../src/plugin-manager-cli.tsx"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAI9D"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { render } from "ink";
|
|
3
|
+
import { PluginManagerShell } from "./components/PluginManagerShell.js";
|
|
4
|
+
/**
|
|
5
|
+
* Entry point for the Plugin Manager CLI.
|
|
6
|
+
* Renders the Ink component and handles the lifecycle.
|
|
7
|
+
*/
|
|
8
|
+
export async function startPluginManagerCli() {
|
|
9
|
+
const { waitUntilExit } = render(_jsx(PluginManagerShell, {}));
|
|
10
|
+
await waitUntilExit();
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-selector-cli.d.ts","sourceRoot":"","sources":["../src/session-selector-cli.tsx"],"names":[],"mappings":"AAKA,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+BtE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { render, Box } from "ink";
|
|
3
|
+
import { listSessions, truncateContent } from "wave-agent-sdk";
|
|
4
|
+
import { SessionSelector } from "./components/SessionSelector.js";
|
|
5
|
+
export async function startSessionSelectorCli() {
|
|
6
|
+
const currentWorkdir = process.cwd();
|
|
7
|
+
const sessions = await listSessions(currentWorkdir);
|
|
8
|
+
if (sessions.length === 0) {
|
|
9
|
+
console.log(`No sessions found for workdir: ${currentWorkdir}`);
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const sessionsWithContent = sessions.map((s) => ({
|
|
13
|
+
...s,
|
|
14
|
+
firstMessage: truncateContent(s.firstMessage || "No content", 80),
|
|
15
|
+
}));
|
|
16
|
+
return new Promise((resolve) => {
|
|
17
|
+
const { unmount } = render(_jsx(Box, { padding: 1, children: _jsx(SessionSelector, { sessions: sessionsWithContent, onSelect: (sessionId) => {
|
|
18
|
+
unmount();
|
|
19
|
+
resolve(sessionId);
|
|
20
|
+
}, onCancel: () => {
|
|
21
|
+
unmount();
|
|
22
|
+
resolve(null);
|
|
23
|
+
} }) }));
|
|
24
|
+
});
|
|
25
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wave-code",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "CLI-based code assistant powered by AI, built with React and Ink",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,17 +30,20 @@
|
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"chalk": "^5.6.2",
|
|
33
|
+
"cli-highlight": "^2.1.11",
|
|
33
34
|
"diff": "^8.0.2",
|
|
34
35
|
"glob": "^13.0.0",
|
|
35
36
|
"ink": "^6.5.1",
|
|
36
37
|
"marked": "^11.2.0",
|
|
37
|
-
"react": "^19.
|
|
38
|
+
"react": "^19.2.4",
|
|
39
|
+
"react-dom": "19.2.4",
|
|
38
40
|
"yargs": "^17.7.2",
|
|
39
|
-
"wave-agent-sdk": "0.
|
|
41
|
+
"wave-agent-sdk": "0.4.0"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
42
44
|
"@types/react": "^19.1.8",
|
|
43
45
|
"@types/yargs": "^17.0.0",
|
|
46
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
44
47
|
"eslint-plugin-react": "^7.37.5",
|
|
45
48
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
46
49
|
"ink-testing-library": "^4.0.0",
|
|
@@ -62,6 +65,7 @@
|
|
|
62
65
|
"type-check": "tsc --noEmit --incremental",
|
|
63
66
|
"watch": "tsc -p tsconfig.build.json --watch & tsc-alias -p tsconfig.build.json --watch",
|
|
64
67
|
"test": "vitest run",
|
|
68
|
+
"test:coverage": "vitest run --coverage",
|
|
65
69
|
"lint": "eslint --cache",
|
|
66
70
|
"format": "prettier --write .",
|
|
67
71
|
"version:patch": "node ../../scripts/version.js patch",
|
|
@@ -2,11 +2,12 @@ import {
|
|
|
2
2
|
ConfigurationService,
|
|
3
3
|
PluginManager,
|
|
4
4
|
PluginScopeManager,
|
|
5
|
+
Scope,
|
|
5
6
|
} from "wave-agent-sdk";
|
|
6
7
|
|
|
7
8
|
export async function disablePluginCommand(argv: {
|
|
8
9
|
plugin: string;
|
|
9
|
-
scope
|
|
10
|
+
scope?: Scope;
|
|
10
11
|
}) {
|
|
11
12
|
const workdir = process.cwd();
|
|
12
13
|
const configurationService = new ConfigurationService();
|
|
@@ -17,10 +18,13 @@ export async function disablePluginCommand(argv: {
|
|
|
17
18
|
pluginManager,
|
|
18
19
|
});
|
|
19
20
|
|
|
21
|
+
const scope =
|
|
22
|
+
argv.scope || scopeManager.findPluginScope(argv.plugin) || "user";
|
|
23
|
+
|
|
20
24
|
try {
|
|
21
|
-
await scopeManager.disablePlugin(
|
|
25
|
+
await scopeManager.disablePlugin(scope, argv.plugin);
|
|
22
26
|
console.log(
|
|
23
|
-
`Successfully disabled plugin: ${argv.plugin} in ${
|
|
27
|
+
`Successfully disabled plugin: ${argv.plugin} in ${scope} scope`,
|
|
24
28
|
);
|
|
25
29
|
process.exit(0);
|
|
26
30
|
} catch (error) {
|
|
@@ -2,11 +2,12 @@ import {
|
|
|
2
2
|
ConfigurationService,
|
|
3
3
|
PluginManager,
|
|
4
4
|
PluginScopeManager,
|
|
5
|
+
Scope,
|
|
5
6
|
} from "wave-agent-sdk";
|
|
6
7
|
|
|
7
8
|
export async function enablePluginCommand(argv: {
|
|
8
9
|
plugin: string;
|
|
9
|
-
scope
|
|
10
|
+
scope?: Scope;
|
|
10
11
|
}) {
|
|
11
12
|
const workdir = process.cwd();
|
|
12
13
|
const configurationService = new ConfigurationService();
|
|
@@ -17,10 +18,13 @@ export async function enablePluginCommand(argv: {
|
|
|
17
18
|
pluginManager,
|
|
18
19
|
});
|
|
19
20
|
|
|
21
|
+
const scope =
|
|
22
|
+
argv.scope || scopeManager.findPluginScope(argv.plugin) || "user";
|
|
23
|
+
|
|
20
24
|
try {
|
|
21
|
-
await scopeManager.enablePlugin(
|
|
25
|
+
await scopeManager.enablePlugin(scope, argv.plugin);
|
|
22
26
|
console.log(
|
|
23
|
-
`Successfully enabled plugin: ${argv.plugin} in ${
|
|
27
|
+
`Successfully enabled plugin: ${argv.plugin} in ${scope} scope`,
|
|
24
28
|
);
|
|
25
29
|
process.exit(0);
|
|
26
30
|
} catch (error) {
|
|
@@ -3,11 +3,12 @@ import {
|
|
|
3
3
|
ConfigurationService,
|
|
4
4
|
PluginManager,
|
|
5
5
|
PluginScopeManager,
|
|
6
|
+
Scope,
|
|
6
7
|
} from "wave-agent-sdk";
|
|
7
8
|
|
|
8
9
|
export async function installPluginCommand(argv: {
|
|
9
10
|
plugin: string;
|
|
10
|
-
scope?:
|
|
11
|
+
scope?: Scope;
|
|
11
12
|
}) {
|
|
12
13
|
const marketplaceService = new MarketplaceService();
|
|
13
14
|
const workdir = process.cwd();
|
|
@@ -1,9 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
MarketplaceService,
|
|
3
|
+
ConfigurationService,
|
|
4
|
+
PluginScopeManager,
|
|
5
|
+
PluginManager,
|
|
6
|
+
} from "wave-agent-sdk";
|
|
2
7
|
|
|
3
8
|
export async function listPluginsCommand() {
|
|
4
|
-
const marketplaceService = new MarketplaceService();
|
|
5
9
|
const configurationService = new ConfigurationService();
|
|
10
|
+
const marketplaceService = new MarketplaceService();
|
|
6
11
|
const workdir = process.cwd();
|
|
12
|
+
const pluginManager = new PluginManager({
|
|
13
|
+
workdir,
|
|
14
|
+
configurationService,
|
|
15
|
+
});
|
|
16
|
+
const pluginScopeManager = new PluginScopeManager({
|
|
17
|
+
workdir,
|
|
18
|
+
configurationService,
|
|
19
|
+
pluginManager,
|
|
20
|
+
});
|
|
7
21
|
|
|
8
22
|
try {
|
|
9
23
|
const installedPlugins = await marketplaceService.getInstalledPlugins();
|
|
@@ -16,6 +30,7 @@ export async function listPluginsCommand() {
|
|
|
16
30
|
marketplace: string;
|
|
17
31
|
installed: boolean;
|
|
18
32
|
version?: string;
|
|
33
|
+
scope?: string;
|
|
19
34
|
}[] = [];
|
|
20
35
|
|
|
21
36
|
for (const m of marketplaces) {
|
|
@@ -24,6 +39,7 @@ export async function listPluginsCommand() {
|
|
|
24
39
|
marketplaceService.getMarketplacePath(m),
|
|
25
40
|
);
|
|
26
41
|
manifest.plugins.forEach((p) => {
|
|
42
|
+
const pluginId = `${p.name}@${m.name}`;
|
|
27
43
|
const installed = installedPlugins.plugins.find(
|
|
28
44
|
(ip) => ip.name === p.name && ip.marketplace === m.name,
|
|
29
45
|
);
|
|
@@ -32,6 +48,7 @@ export async function listPluginsCommand() {
|
|
|
32
48
|
marketplace: m.name,
|
|
33
49
|
installed: !!installed,
|
|
34
50
|
version: installed?.version,
|
|
51
|
+
scope: pluginScopeManager.findPluginScope(pluginId) || undefined,
|
|
35
52
|
});
|
|
36
53
|
});
|
|
37
54
|
} catch {
|
|
@@ -52,7 +69,8 @@ export async function listPluginsCommand() {
|
|
|
52
69
|
: "disabled"
|
|
53
70
|
: "not installed";
|
|
54
71
|
const versionStr = p.version ? ` v${p.version}` : "";
|
|
55
|
-
|
|
72
|
+
const scopeStr = p.scope ? ` (${p.scope})` : "";
|
|
73
|
+
console.log(`- ${pluginId}${versionStr}${scopeStr} [${status}]`);
|
|
56
74
|
});
|
|
57
75
|
}
|
|
58
76
|
process.exit(0);
|
|
@@ -42,7 +42,10 @@ export async function listMarketplacesCommand() {
|
|
|
42
42
|
} else {
|
|
43
43
|
sourceInfo = source.url + (source.ref ? `#${source.ref}` : "");
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
const builtinLabel = m.isBuiltin ? " [builtin]" : "";
|
|
46
|
+
console.log(
|
|
47
|
+
`- ${m.name}${builtinLabel}: ${sourceInfo} (${m.source.source})`,
|
|
48
|
+
);
|
|
46
49
|
});
|
|
47
50
|
}
|
|
48
51
|
process.exit(0);
|
|
@@ -53,6 +56,19 @@ export async function listMarketplacesCommand() {
|
|
|
53
56
|
}
|
|
54
57
|
}
|
|
55
58
|
|
|
59
|
+
export async function removeMarketplaceCommand(argv: { name: string }) {
|
|
60
|
+
const service = new MarketplaceService();
|
|
61
|
+
try {
|
|
62
|
+
await service.removeMarketplace(argv.name);
|
|
63
|
+
console.log(`Successfully removed marketplace: ${argv.name}`);
|
|
64
|
+
process.exit(0);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
67
|
+
console.error(`Failed to remove marketplace: ${message}`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
56
72
|
export async function updateMarketplaceCommand(argv: { name?: string }) {
|
|
57
73
|
const service = new MarketplaceService();
|
|
58
74
|
try {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MarketplaceService,
|
|
3
|
+
ConfigurationService,
|
|
4
|
+
PluginManager,
|
|
5
|
+
PluginScopeManager,
|
|
6
|
+
} from "wave-agent-sdk";
|
|
7
|
+
|
|
8
|
+
export async function uninstallPluginCommand(argv: { plugin: string }) {
|
|
9
|
+
const marketplaceService = new MarketplaceService();
|
|
10
|
+
const workdir = process.cwd();
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
await marketplaceService.uninstallPlugin(argv.plugin);
|
|
14
|
+
console.log(`Successfully uninstalled plugin: ${argv.plugin}`);
|
|
15
|
+
|
|
16
|
+
const configurationService = new ConfigurationService();
|
|
17
|
+
const pluginManager = new PluginManager({ workdir });
|
|
18
|
+
const scopeManager = new PluginScopeManager({
|
|
19
|
+
workdir,
|
|
20
|
+
configurationService,
|
|
21
|
+
pluginManager,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
await scopeManager.removePluginFromAllScopes(argv.plugin);
|
|
26
|
+
console.log(`Cleaned up plugin configuration from all scopes`);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.warn(
|
|
29
|
+
`Warning: Could not clean up all plugin configurations: ${error instanceof Error ? error.message : String(error)}`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
process.exit(0);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
36
|
+
console.error(`Failed to uninstall plugin: ${message}`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { MarketplaceService } from "wave-agent-sdk";
|
|
2
|
+
|
|
3
|
+
export async function updatePluginCommand(argv: { plugin: string }) {
|
|
4
|
+
const marketplaceService = new MarketplaceService();
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
const updated = await marketplaceService.updatePlugin(argv.plugin);
|
|
8
|
+
console.log(
|
|
9
|
+
`Successfully updated plugin: ${updated.name} v${updated.version} from ${updated.marketplace}`,
|
|
10
|
+
);
|
|
11
|
+
console.log(`Cache path: ${updated.cachePath}`);
|
|
12
|
+
|
|
13
|
+
process.exit(0);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16
|
+
console.error(`Failed to update plugin: ${message}`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -27,6 +27,7 @@ export const ChatInterface: React.FC = () => {
|
|
|
27
27
|
confirmingTool,
|
|
28
28
|
handleConfirmationDecision,
|
|
29
29
|
handleConfirmationCancel,
|
|
30
|
+
rewindId,
|
|
30
31
|
} = useChat();
|
|
31
32
|
|
|
32
33
|
if (!sessionId) return null;
|
|
@@ -40,7 +41,7 @@ export const ChatInterface: React.FC = () => {
|
|
|
40
41
|
isCompressing={isCompressing}
|
|
41
42
|
latestTotalTokens={latestTotalTokens}
|
|
42
43
|
isExpanded={isExpanded}
|
|
43
|
-
key={String(isExpanded) + sessionId}
|
|
44
|
+
key={String(isExpanded) + sessionId + rewindId}
|
|
44
45
|
/>
|
|
45
46
|
|
|
46
47
|
{isConfirmationVisible && (
|
|
@@ -15,6 +15,13 @@ const AVAILABLE_COMMANDS: SlashCommand[] = [
|
|
|
15
15
|
description: "View and manage MCP servers",
|
|
16
16
|
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
17
17
|
},
|
|
18
|
+
{
|
|
19
|
+
id: "rewind",
|
|
20
|
+
name: "rewind",
|
|
21
|
+
description:
|
|
22
|
+
"Revert conversation and file changes to a previous checkpoint",
|
|
23
|
+
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
24
|
+
},
|
|
18
25
|
];
|
|
19
26
|
|
|
20
27
|
export interface CommandSelectorProps {
|
|
@@ -229,7 +229,7 @@ export const Confirmation: React.FC<ConfirmationProps> = ({
|
|
|
229
229
|
} else if (state.selectedOption === "auto") {
|
|
230
230
|
if (toolName === BASH_TOOL_NAME) {
|
|
231
231
|
const rule = suggestedPrefix
|
|
232
|
-
? `Bash(${suggestedPrefix}
|
|
232
|
+
? `Bash(${suggestedPrefix}*)`
|
|
233
233
|
: `Bash(${toolInput?.command})`;
|
|
234
234
|
onDecision({
|
|
235
235
|
behavior: "allow",
|