wave-code 0.2.1 → 0.5.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.
Files changed (156) hide show
  1. package/dist/commands/plugin/disable.d.ts +2 -1
  2. package/dist/commands/plugin/disable.d.ts.map +1 -1
  3. package/dist/commands/plugin/disable.js +3 -2
  4. package/dist/commands/plugin/enable.d.ts +2 -1
  5. package/dist/commands/plugin/enable.d.ts.map +1 -1
  6. package/dist/commands/plugin/enable.js +3 -2
  7. package/dist/commands/plugin/install.d.ts +2 -1
  8. package/dist/commands/plugin/install.d.ts.map +1 -1
  9. package/dist/commands/plugin/list.d.ts.map +1 -1
  10. package/dist/commands/plugin/list.js +15 -3
  11. package/dist/commands/plugin/marketplace.d.ts +3 -0
  12. package/dist/commands/plugin/marketplace.d.ts.map +1 -1
  13. package/dist/commands/plugin/marketplace.js +15 -1
  14. package/dist/commands/plugin/uninstall.d.ts +4 -0
  15. package/dist/commands/plugin/uninstall.d.ts.map +1 -0
  16. package/dist/commands/plugin/uninstall.js +29 -0
  17. package/dist/commands/plugin/update.d.ts +4 -0
  18. package/dist/commands/plugin/update.d.ts.map +1 -0
  19. package/dist/commands/plugin/update.js +15 -0
  20. package/dist/components/ChatInterface.d.ts.map +1 -1
  21. package/dist/components/ChatInterface.js +2 -2
  22. package/dist/components/CommandSelector.d.ts.map +1 -1
  23. package/dist/components/CommandSelector.js +9 -3
  24. package/dist/components/Confirmation.d.ts.map +1 -1
  25. package/dist/components/Confirmation.js +73 -20
  26. package/dist/components/DiffDisplay.d.ts +0 -1
  27. package/dist/components/DiffDisplay.d.ts.map +1 -1
  28. package/dist/components/DiffDisplay.js +38 -59
  29. package/dist/components/DiscoverView.d.ts +3 -0
  30. package/dist/components/DiscoverView.d.ts.map +1 -0
  31. package/dist/components/DiscoverView.js +25 -0
  32. package/dist/components/FileSelector.js +1 -1
  33. package/dist/components/HistorySearch.d.ts +8 -0
  34. package/dist/components/HistorySearch.d.ts.map +1 -0
  35. package/dist/components/HistorySearch.js +67 -0
  36. package/dist/components/InputBox.d.ts +1 -1
  37. package/dist/components/InputBox.d.ts.map +1 -1
  38. package/dist/components/InputBox.js +29 -19
  39. package/dist/components/InstalledView.d.ts +3 -0
  40. package/dist/components/InstalledView.d.ts.map +1 -0
  41. package/dist/components/InstalledView.js +30 -0
  42. package/dist/components/Markdown.d.ts.map +1 -1
  43. package/dist/components/Markdown.js +24 -10
  44. package/dist/components/MarketplaceAddForm.d.ts +3 -0
  45. package/dist/components/MarketplaceAddForm.d.ts.map +1 -0
  46. package/dist/components/MarketplaceAddForm.js +26 -0
  47. package/dist/components/MarketplaceDetail.d.ts +3 -0
  48. package/dist/components/MarketplaceDetail.d.ts.map +1 -0
  49. package/dist/components/MarketplaceDetail.js +38 -0
  50. package/dist/components/MarketplaceList.d.ts +9 -0
  51. package/dist/components/MarketplaceList.d.ts.map +1 -0
  52. package/dist/components/MarketplaceList.js +16 -0
  53. package/dist/components/MarketplaceView.d.ts +3 -0
  54. package/dist/components/MarketplaceView.d.ts.map +1 -0
  55. package/dist/components/MarketplaceView.js +28 -0
  56. package/dist/components/PlanDisplay.d.ts.map +1 -1
  57. package/dist/components/PlanDisplay.js +2 -2
  58. package/dist/components/PluginDetail.d.ts +3 -0
  59. package/dist/components/PluginDetail.d.ts.map +1 -0
  60. package/dist/components/PluginDetail.js +63 -0
  61. package/dist/components/PluginList.d.ts +14 -0
  62. package/dist/components/PluginList.d.ts.map +1 -0
  63. package/dist/components/PluginList.js +12 -0
  64. package/dist/components/PluginManagerShell.d.ts +5 -0
  65. package/dist/components/PluginManagerShell.d.ts.map +1 -0
  66. package/dist/components/PluginManagerShell.js +89 -0
  67. package/dist/components/PluginManagerTypes.d.ts +33 -0
  68. package/dist/components/PluginManagerTypes.d.ts.map +1 -0
  69. package/dist/components/PluginManagerTypes.js +1 -0
  70. package/dist/components/RewindCommand.d.ts +9 -0
  71. package/dist/components/RewindCommand.d.ts.map +1 -0
  72. package/dist/components/RewindCommand.js +42 -0
  73. package/dist/components/SessionSelector.d.ts +11 -0
  74. package/dist/components/SessionSelector.d.ts.map +1 -0
  75. package/dist/components/SessionSelector.js +38 -0
  76. package/dist/components/SubagentBlock.d.ts.map +1 -1
  77. package/dist/components/SubagentBlock.js +24 -1
  78. package/dist/components/TaskManager.d.ts +6 -0
  79. package/dist/components/TaskManager.d.ts.map +1 -0
  80. package/dist/components/TaskManager.js +114 -0
  81. package/dist/components/ToolResultDisplay.d.ts.map +1 -1
  82. package/dist/components/ToolResultDisplay.js +2 -1
  83. package/dist/contexts/PluginManagerContext.d.ts +4 -0
  84. package/dist/contexts/PluginManagerContext.d.ts.map +1 -0
  85. package/dist/contexts/PluginManagerContext.js +9 -0
  86. package/dist/contexts/useChat.d.ts +7 -4
  87. package/dist/contexts/useChat.d.ts.map +1 -1
  88. package/dist/contexts/useChat.js +37 -12
  89. package/dist/hooks/useInputManager.d.ts +8 -16
  90. package/dist/hooks/useInputManager.d.ts.map +1 -1
  91. package/dist/hooks/useInputManager.js +39 -55
  92. package/dist/hooks/usePluginManager.d.ts +3 -0
  93. package/dist/hooks/usePluginManager.d.ts.map +1 -0
  94. package/dist/hooks/usePluginManager.js +227 -0
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +150 -177
  97. package/dist/managers/InputManager.d.ts +18 -26
  98. package/dist/managers/InputManager.d.ts.map +1 -1
  99. package/dist/managers/InputManager.js +93 -119
  100. package/dist/plugin-manager-cli.d.ts +6 -0
  101. package/dist/plugin-manager-cli.d.ts.map +1 -0
  102. package/dist/plugin-manager-cli.js +12 -0
  103. package/dist/session-selector-cli.d.ts +2 -0
  104. package/dist/session-selector-cli.d.ts.map +1 -0
  105. package/dist/session-selector-cli.js +25 -0
  106. package/package.json +9 -5
  107. package/src/commands/plugin/disable.ts +7 -3
  108. package/src/commands/plugin/enable.ts +7 -3
  109. package/src/commands/plugin/install.ts +2 -1
  110. package/src/commands/plugin/list.ts +21 -3
  111. package/src/commands/plugin/marketplace.ts +17 -1
  112. package/src/commands/plugin/uninstall.ts +39 -0
  113. package/src/commands/plugin/update.ts +19 -0
  114. package/src/components/ChatInterface.tsx +2 -1
  115. package/src/components/CommandSelector.tsx +10 -3
  116. package/src/components/Confirmation.tsx +115 -25
  117. package/src/components/DiffDisplay.tsx +60 -106
  118. package/src/components/DiscoverView.tsx +31 -0
  119. package/src/components/FileSelector.tsx +1 -1
  120. package/src/components/HistorySearch.tsx +148 -0
  121. package/src/components/InputBox.tsx +51 -34
  122. package/src/components/InstalledView.tsx +61 -0
  123. package/src/components/Markdown.tsx +44 -28
  124. package/src/components/MarketplaceAddForm.tsx +39 -0
  125. package/src/components/MarketplaceDetail.tsx +79 -0
  126. package/src/components/MarketplaceList.tsx +52 -0
  127. package/src/components/MarketplaceView.tsx +43 -0
  128. package/src/components/PlanDisplay.tsx +14 -19
  129. package/src/components/PluginDetail.tsx +147 -0
  130. package/src/components/PluginList.tsx +51 -0
  131. package/src/components/PluginManagerShell.tsx +189 -0
  132. package/src/components/PluginManagerTypes.ts +47 -0
  133. package/src/components/RewindCommand.tsx +114 -0
  134. package/src/components/SessionSelector.tsx +127 -0
  135. package/src/components/SubagentBlock.tsx +34 -1
  136. package/src/components/{BashShellManager.tsx → TaskManager.tsx} +79 -75
  137. package/src/components/ToolResultDisplay.tsx +6 -2
  138. package/src/contexts/PluginManagerContext.ts +15 -0
  139. package/src/contexts/useChat.tsx +51 -20
  140. package/src/hooks/useInputManager.ts +39 -71
  141. package/src/hooks/usePluginManager.ts +302 -0
  142. package/src/index.ts +241 -280
  143. package/src/managers/InputManager.ts +113 -162
  144. package/src/plugin-manager-cli.tsx +13 -0
  145. package/src/session-selector-cli.tsx +37 -0
  146. package/dist/components/BashHistorySelector.d.ts +0 -11
  147. package/dist/components/BashHistorySelector.d.ts.map +0 -1
  148. package/dist/components/BashHistorySelector.js +0 -93
  149. package/dist/components/BashShellManager.d.ts +0 -6
  150. package/dist/components/BashShellManager.d.ts.map +0 -1
  151. package/dist/components/BashShellManager.js +0 -116
  152. package/dist/hooks/usePagination.d.ts +0 -20
  153. package/dist/hooks/usePagination.d.ts.map +0 -1
  154. package/dist/hooks/usePagination.js +0 -168
  155. package/src/components/BashHistorySelector.tsx +0 -181
  156. package/src/hooks/usePagination.ts +0 -203
@@ -1,9 +1,9 @@
1
1
  import { FileItem } from "../components/FileSelector.js";
2
2
  import {
3
3
  searchFiles as searchFilesUtil,
4
- deleteBashCommandFromHistory,
5
4
  PermissionMode,
6
5
  Logger,
6
+ PromptHistoryManager,
7
7
  } from "wave-agent-sdk";
8
8
  import { readClipboardImage } from "../utils/clipboard.js";
9
9
  import type { Key } from "ink";
@@ -28,16 +28,14 @@ export interface InputManagerCallbacks {
28
28
  query: string,
29
29
  position: number,
30
30
  ) => void;
31
- onBashHistorySelectorStateChange?: (
32
- show: boolean,
33
- query: string,
34
- position: number,
35
- ) => void;
31
+ onHistorySearchStateChange?: (show: boolean, query: string) => void;
36
32
  onMemoryTypeSelectorStateChange?: (show: boolean, message: string) => void;
37
- onShowBashManager?: () => void;
33
+ onShowTaskManager?: () => void;
34
+ onTaskManagerStateChange?: (show: boolean) => void;
38
35
  onShowMcpManager?: () => void;
39
- onBashManagerStateChange?: (show: boolean) => void;
40
36
  onMcpManagerStateChange?: (show: boolean) => void;
37
+ onShowRewindManager?: () => void;
38
+ onRewindManagerStateChange?: (show: boolean) => void;
41
39
  onImagesStateChange?: (images: AttachedImage[]) => void;
42
40
  onSendMessage?: (
43
41
  content: string,
@@ -46,6 +44,7 @@ export interface InputManagerCallbacks {
46
44
  onHasSlashCommand?: (commandId: string) => boolean;
47
45
  onSaveMemory?: (message: string, type: "project" | "user") => Promise<void>;
48
46
  onAbortMessage?: () => void;
47
+ onBackgroundCurrentTask?: () => void;
49
48
  onResetHistoryNavigation?: () => void;
50
49
  onPermissionModeChange?: (mode: PermissionMode) => void;
51
50
  logger?: Logger;
@@ -68,10 +67,9 @@ export class InputManager {
68
67
  private slashPosition: number = -1;
69
68
  private commandSearchQuery: string = "";
70
69
 
71
- // Bash history selector state
72
- private showBashHistorySelector: boolean = false;
73
- private exclamationPosition: number = -1;
74
- private bashHistorySearchQuery: string = "";
70
+ // History search state
71
+ private showHistorySearch: boolean = false;
72
+ private historySearchQuery: string = "";
75
73
 
76
74
  // Memory type selector state
77
75
  private showMemoryTypeSelector: boolean = false;
@@ -97,8 +95,9 @@ export class InputManager {
97
95
  private imageIdCounter: number = 1;
98
96
 
99
97
  // Additional UI state
100
- private showBashManager: boolean = false;
98
+ private showTaskManager: boolean = false;
101
99
  private showMcpManager: boolean = false;
100
+ private showRewindManager: boolean = false;
102
101
 
103
102
  // Permission mode state
104
103
  private permissionMode: PermissionMode = "default";
@@ -363,12 +362,18 @@ export class InputManager {
363
362
 
364
363
  // If not an agent command or execution failed, check local commands
365
364
  if (!commandExecuted) {
366
- if (command === "bashes" && this.callbacks.onShowBashManager) {
367
- this.callbacks.onShowBashManager();
365
+ if (command === "tasks" && this.callbacks.onShowTaskManager) {
366
+ this.callbacks.onShowTaskManager();
368
367
  commandExecuted = true;
369
368
  } else if (command === "mcp" && this.callbacks.onShowMcpManager) {
370
369
  this.callbacks.onShowMcpManager();
371
370
  commandExecuted = true;
371
+ } else if (
372
+ command === "rewind" &&
373
+ this.callbacks.onShowRewindManager
374
+ ) {
375
+ this.callbacks.onShowRewindManager();
376
+ commandExecuted = true;
372
377
  }
373
378
  }
374
379
  })();
@@ -434,105 +439,6 @@ export class InputManager {
434
439
  return false;
435
440
  }
436
441
 
437
- // Bash history selector methods
438
- activateBashHistorySelector(position: number): void {
439
- this.showBashHistorySelector = true;
440
- this.exclamationPosition = position;
441
- this.bashHistorySearchQuery = "";
442
-
443
- this.callbacks.onBashHistorySelectorStateChange?.(true, "", position);
444
- }
445
-
446
- updateBashHistorySearchQuery(query: string): void {
447
- this.bashHistorySearchQuery = query;
448
- this.callbacks.onBashHistorySelectorStateChange?.(
449
- this.showBashHistorySelector,
450
- query,
451
- this.exclamationPosition,
452
- );
453
- }
454
-
455
- handleBashHistorySelect(command: string): {
456
- newInput: string;
457
- newCursorPosition: number;
458
- } {
459
- if (this.exclamationPosition >= 0) {
460
- const beforeExclamation = this.inputText.substring(
461
- 0,
462
- this.exclamationPosition,
463
- );
464
- const afterQuery = this.inputText.substring(this.cursorPosition);
465
- const newInput = beforeExclamation + `!${command}` + afterQuery;
466
- const newCursorPosition = beforeExclamation.length + command.length + 1;
467
-
468
- this.inputText = newInput;
469
- this.cursorPosition = newCursorPosition;
470
-
471
- this.handleCancelBashHistorySelect();
472
-
473
- // Set flag to prevent handleInput from processing the same Enter key
474
- this.selectorJustUsed = true;
475
- setTimeout(() => {
476
- this.selectorJustUsed = false;
477
- }, 0);
478
-
479
- this.callbacks.onInputTextChange?.(newInput);
480
- this.callbacks.onCursorPositionChange?.(newCursorPosition);
481
-
482
- return { newInput, newCursorPosition };
483
- }
484
- return { newInput: this.inputText, newCursorPosition: this.cursorPosition };
485
- }
486
-
487
- handleCancelBashHistorySelect(): void {
488
- this.showBashHistorySelector = false;
489
- this.exclamationPosition = -1;
490
- this.bashHistorySearchQuery = "";
491
-
492
- this.callbacks.onBashHistorySelectorStateChange?.(false, "", -1);
493
- }
494
-
495
- handleBashHistoryExecute(command: string): string {
496
- this.showBashHistorySelector = false;
497
- this.exclamationPosition = -1;
498
- this.bashHistorySearchQuery = "";
499
-
500
- this.callbacks.onBashHistorySelectorStateChange?.(false, "", -1);
501
-
502
- return command; // Return command to execute
503
- }
504
-
505
- handleBashHistoryExecuteAndSend(command: string): void {
506
- const commandToExecute = this.handleBashHistoryExecute(command);
507
- // Clear input box and execute command, ensure command starts with !
508
- const bashCommand = commandToExecute.startsWith("!")
509
- ? commandToExecute
510
- : `!${commandToExecute}`;
511
- this.clearInput();
512
- this.callbacks.onSendMessage?.(bashCommand);
513
- }
514
-
515
- handleBashHistoryDelete(command: string, workdir?: string): void {
516
- deleteBashCommandFromHistory(command, workdir);
517
- // Trigger a refresh of the selector state to force re-render of BashHistorySelector
518
- this.callbacks.onBashHistorySelectorStateChange?.(
519
- this.showBashHistorySelector,
520
- this.bashHistorySearchQuery,
521
- this.exclamationPosition,
522
- );
523
- }
524
-
525
- checkForExclamationDeletion(cursorPosition: number): boolean {
526
- if (
527
- this.showBashHistorySelector &&
528
- cursorPosition <= this.exclamationPosition
529
- ) {
530
- this.handleCancelBashHistorySelect();
531
- return true;
532
- }
533
- return false;
534
- }
535
-
536
442
  // Memory type selector methods
537
443
  activateMemoryTypeSelector(message: string): void {
538
444
  this.showMemoryTypeSelector = true;
@@ -631,10 +537,6 @@ export class InputManager {
631
537
  return this.showCommandSelector;
632
538
  }
633
539
 
634
- isBashHistorySelectorActive(): boolean {
635
- return this.showBashHistorySelector;
636
- }
637
-
638
540
  isMemoryTypeSelectorActive(): boolean {
639
541
  return this.showMemoryTypeSelector;
640
542
  }
@@ -656,14 +558,6 @@ export class InputManager {
656
558
  };
657
559
  }
658
560
 
659
- getBashHistorySelectorState() {
660
- return {
661
- show: this.showBashHistorySelector,
662
- query: this.bashHistorySearchQuery,
663
- position: this.exclamationPosition,
664
- };
665
- }
666
-
667
561
  getMemoryTypeSelectorState() {
668
562
  return {
669
563
  show: this.showMemoryTypeSelector,
@@ -686,11 +580,6 @@ export class InputManager {
686
580
  const queryEnd = cursorPosition;
687
581
  const newQuery = inputText.substring(queryStart, queryEnd);
688
582
  this.updateCommandSearchQuery(newQuery);
689
- } else if (this.showBashHistorySelector && this.exclamationPosition >= 0) {
690
- const queryStart = this.exclamationPosition + 1;
691
- const queryEnd = cursorPosition;
692
- const newQuery = inputText.substring(queryStart, queryEnd);
693
- this.updateBashHistorySearchQuery(newQuery);
694
583
  }
695
584
  }
696
585
 
@@ -698,11 +587,14 @@ export class InputManager {
698
587
  handleSpecialCharInput(char: string): void {
699
588
  if (char === "@") {
700
589
  this.activateFileSelector(this.cursorPosition - 1);
701
- } else if (char === "/" && !this.showFileSelector) {
590
+ } else if (
591
+ char === "/" &&
592
+ !this.showFileSelector &&
593
+ this.cursorPosition === 1
594
+ ) {
702
595
  // Don't activate command selector when file selector is active
596
+ // Only activate command selector if '/' is at the start of input
703
597
  this.activateCommandSelector(this.cursorPosition - 1);
704
- } else if (char === "!" && this.cursorPosition === 1) {
705
- this.activateBashHistorySelector(0);
706
598
  } else if (char === "#" && this.cursorPosition === 1) {
707
599
  // Memory message detection will be handled in submit
708
600
  } else {
@@ -860,14 +752,14 @@ export class InputManager {
860
752
  }
861
753
  }
862
754
 
863
- // Bash/MCP manager state methods
864
- getShowBashManager(): boolean {
865
- return this.showBashManager;
755
+ // Task manager state methods
756
+ getShowTaskManager(): boolean {
757
+ return this.showTaskManager;
866
758
  }
867
759
 
868
- setShowBashManager(show: boolean): void {
869
- this.showBashManager = show;
870
- this.callbacks.onBashManagerStateChange?.(show);
760
+ setShowTaskManager(show: boolean): void {
761
+ this.showTaskManager = show;
762
+ this.callbacks.onTaskManagerStateChange?.(show);
871
763
  }
872
764
 
873
765
  getShowMcpManager(): boolean {
@@ -879,6 +771,15 @@ export class InputManager {
879
771
  this.callbacks.onMcpManagerStateChange?.(show);
880
772
  }
881
773
 
774
+ getShowRewindManager(): boolean {
775
+ return this.showRewindManager;
776
+ }
777
+
778
+ setShowRewindManager(show: boolean): void {
779
+ this.showRewindManager = show;
780
+ this.callbacks.onRewindManagerStateChange?.(show);
781
+ }
782
+
882
783
  // Permission mode methods
883
784
  getPermissionMode(): PermissionMode {
884
785
  return this.permissionMode;
@@ -941,6 +842,11 @@ export class InputManager {
941
842
  let cleanContent = this.inputText.replace(imageRegex, "").trim();
942
843
  cleanContent = this.expandLongTextPlaceholders(cleanContent);
943
844
 
845
+ // Save to prompt history
846
+ PromptHistoryManager.addEntry(cleanContent).catch((err: unknown) => {
847
+ this.logger?.error("Failed to save prompt history", err);
848
+ });
849
+
944
850
  this.callbacks.onSendMessage?.(
945
851
  cleanContent,
946
852
  referencedImages.length > 0 ? referencedImages : undefined,
@@ -961,7 +867,6 @@ export class InputManager {
961
867
  // Check for special character deletion
962
868
  this.checkForAtDeletion(newCursorPosition);
963
869
  this.checkForSlashDeletion(newCursorPosition);
964
- this.checkForExclamationDeletion(newCursorPosition);
965
870
 
966
871
  // Update search queries using the same logic as character input
967
872
  this.updateSearchQueriesForActiveSelectors(
@@ -1004,6 +909,32 @@ export class InputManager {
1004
909
  return false;
1005
910
  }
1006
911
 
912
+ // History search methods
913
+ activateHistorySearch(): void {
914
+ this.showHistorySearch = true;
915
+ this.historySearchQuery = "";
916
+ this.callbacks.onHistorySearchStateChange?.(true, "");
917
+ }
918
+
919
+ updateHistorySearchQuery(query: string): void {
920
+ this.historySearchQuery = query;
921
+ this.callbacks.onHistorySearchStateChange?.(true, query);
922
+ }
923
+
924
+ handleHistorySearchSelect(prompt: string): void {
925
+ this.inputText = prompt;
926
+ this.cursorPosition = prompt.length;
927
+ this.callbacks.onInputTextChange?.(prompt);
928
+ this.callbacks.onCursorPositionChange?.(prompt.length);
929
+ this.handleCancelHistorySearch();
930
+ }
931
+
932
+ handleCancelHistorySearch(): void {
933
+ this.showHistorySearch = false;
934
+ this.historySearchQuery = "";
935
+ this.callbacks.onHistorySearchStateChange?.(false, "");
936
+ }
937
+
1007
938
  // Handle normal input (when no selector is active)
1008
939
  async handleNormalInput(
1009
940
  input: string,
@@ -1024,8 +955,6 @@ export class InputManager {
1024
955
  this.handleCancelFileSelect();
1025
956
  } else if (this.showCommandSelector) {
1026
957
  this.handleCancelCommandSelect();
1027
- } else if (this.showBashHistorySelector) {
1028
- this.handleCancelBashHistorySelect();
1029
958
  }
1030
959
  return true;
1031
960
  }
@@ -1039,7 +968,6 @@ export class InputManager {
1039
968
  const newCursorPosition = this.cursorPosition - 1;
1040
969
  this.checkForAtDeletion(newCursorPosition);
1041
970
  this.checkForSlashDeletion(newCursorPosition);
1042
- this.checkForExclamationDeletion(newCursorPosition);
1043
971
  }
1044
972
  return true;
1045
973
  }
@@ -1072,23 +1000,25 @@ export class InputManager {
1072
1000
  return true;
1073
1001
  }
1074
1002
 
1003
+ // Handle Ctrl+R for history search
1004
+ if (key.ctrl && input === "r") {
1005
+ this.activateHistorySearch();
1006
+ return true;
1007
+ }
1008
+
1009
+ // Handle Ctrl+B for backgrounding current task
1010
+ if (key.ctrl && input === "b") {
1011
+ this.callbacks.onBackgroundCurrentTask?.();
1012
+ return true;
1013
+ }
1014
+
1075
1015
  // Handle up/down keys for history navigation (only when no selector is active)
1076
- if (
1077
- key.upArrow &&
1078
- !this.showFileSelector &&
1079
- !this.showCommandSelector &&
1080
- !this.showBashHistorySelector
1081
- ) {
1016
+ if (key.upArrow && !this.showFileSelector && !this.showCommandSelector) {
1082
1017
  this.navigateHistory("up", this.inputText);
1083
1018
  return true;
1084
1019
  }
1085
1020
 
1086
- if (
1087
- key.downArrow &&
1088
- !this.showFileSelector &&
1089
- !this.showCommandSelector &&
1090
- !this.showBashHistorySelector
1091
- ) {
1021
+ if (key.downArrow && !this.showFileSelector && !this.showCommandSelector) {
1092
1022
  this.navigateHistory("down", this.inputText);
1093
1023
  return true;
1094
1024
  }
@@ -1147,19 +1077,40 @@ export class InputManager {
1147
1077
  if (
1148
1078
  this.showFileSelector ||
1149
1079
  this.showCommandSelector ||
1150
- this.showBashHistorySelector ||
1080
+ this.showHistorySearch ||
1151
1081
  this.showMemoryTypeSelector ||
1152
- this.showBashManager ||
1153
- this.showMcpManager
1082
+ this.showTaskManager ||
1083
+ this.showMcpManager ||
1084
+ this.showRewindManager
1154
1085
  ) {
1155
1086
  if (
1156
1087
  this.showMemoryTypeSelector ||
1157
- this.showBashManager ||
1158
- this.showMcpManager
1088
+ this.showTaskManager ||
1089
+ this.showMcpManager ||
1090
+ this.showRewindManager
1159
1091
  ) {
1160
- // Memory type selector, bash manager and MCP manager don't need to handle input, handled by component itself
1092
+ // Memory type selector, task manager, MCP manager and Rewind don't need to handle input, handled by component itself
1161
1093
  return false;
1162
1094
  }
1095
+
1096
+ if (this.showHistorySearch) {
1097
+ if (key.escape) {
1098
+ this.handleCancelHistorySearch();
1099
+ return true;
1100
+ }
1101
+ if (key.backspace || key.delete) {
1102
+ if (this.historySearchQuery.length > 0) {
1103
+ this.updateHistorySearchQuery(this.historySearchQuery.slice(0, -1));
1104
+ }
1105
+ return true;
1106
+ }
1107
+ if (input && !key.ctrl && !key.meta && !key.return && !key.tab) {
1108
+ this.updateHistorySearchQuery(this.historySearchQuery + input);
1109
+ return true;
1110
+ }
1111
+ return true; // Let HistorySearch component handle arrows and Enter
1112
+ }
1113
+
1163
1114
  return this.handleSelectorInput(input, key);
1164
1115
  } else {
1165
1116
  return await this.handleNormalInput(
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import { render } from "ink";
3
+ import { PluginManagerShell } from "./components/PluginManagerShell.js";
4
+
5
+ /**
6
+ * Entry point for the Plugin Manager CLI.
7
+ * Renders the Ink component and handles the lifecycle.
8
+ */
9
+ export async function startPluginManagerCli(): Promise<boolean> {
10
+ const { waitUntilExit } = render(<PluginManagerShell />);
11
+ await waitUntilExit();
12
+ return true;
13
+ }
@@ -0,0 +1,37 @@
1
+ import React from "react";
2
+ import { render, Box } from "ink";
3
+ import { listSessions, truncateContent } from "wave-agent-sdk";
4
+ import { SessionSelector } from "./components/SessionSelector.js";
5
+
6
+ export async function startSessionSelectorCli(): Promise<string | null> {
7
+ const currentWorkdir = process.cwd();
8
+ const sessions = await listSessions(currentWorkdir);
9
+
10
+ if (sessions.length === 0) {
11
+ console.log(`No sessions found for workdir: ${currentWorkdir}`);
12
+ return null;
13
+ }
14
+
15
+ const sessionsWithContent = sessions.map((s) => ({
16
+ ...s,
17
+ firstMessage: truncateContent(s.firstMessage || "No content", 80),
18
+ }));
19
+
20
+ return new Promise((resolve) => {
21
+ const { unmount } = render(
22
+ <Box padding={1}>
23
+ <SessionSelector
24
+ sessions={sessionsWithContent}
25
+ onSelect={(sessionId) => {
26
+ unmount();
27
+ resolve(sessionId);
28
+ }}
29
+ onCancel={() => {
30
+ unmount();
31
+ resolve(null);
32
+ }}
33
+ />
34
+ </Box>,
35
+ );
36
+ });
37
+ }
@@ -1,11 +0,0 @@
1
- import React from "react";
2
- export interface BashHistorySelectorProps {
3
- searchQuery: string;
4
- workdir: string;
5
- onSelect: (command: string) => void;
6
- onExecute: (command: string) => void;
7
- onDelete: (command: string, workdir?: string) => void;
8
- onCancel: () => void;
9
- }
10
- export declare const BashHistorySelector: React.FC<BashHistorySelectorProps>;
11
- //# sourceMappingURL=BashHistorySelector.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BashHistorySelector.d.ts","sourceRoot":"","sources":["../../src/components/BashHistorySelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAKnD,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAsKlE,CAAC"}
@@ -1,93 +0,0 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useState, useEffect } from "react";
3
- import { Box, Text, useInput } from "ink";
4
- import { searchBashHistory } from "wave-agent-sdk";
5
- import { logger } from "../utils/logger.js";
6
- export const BashHistorySelector = ({ searchQuery, workdir, onSelect, onExecute, onDelete, onCancel, }) => {
7
- const [selectedIndex, setSelectedIndex] = useState(0);
8
- const [commands, setCommands] = useState([]);
9
- const [refreshCounter, setRefreshCounter] = useState(0);
10
- // Search bash history
11
- useEffect(() => {
12
- const results = searchBashHistory(searchQuery, 10);
13
- setCommands(results);
14
- setSelectedIndex(0);
15
- logger.debug("Bash history search:", {
16
- searchQuery,
17
- workdir,
18
- resultCount: results.length,
19
- refreshCounter,
20
- });
21
- }, [searchQuery, workdir, refreshCounter]);
22
- useInput((input, key) => {
23
- logger.debug("BashHistorySelector useInput:", {
24
- input,
25
- key,
26
- commandsLength: commands.length,
27
- selectedIndex,
28
- });
29
- if (key.return) {
30
- if (commands.length > 0 && selectedIndex < commands.length) {
31
- const selectedCommand = commands[selectedIndex];
32
- onExecute(selectedCommand.command);
33
- }
34
- else if (commands.length === 0 && searchQuery.trim()) {
35
- // When no history records match, execute the search query as a new command
36
- onExecute(searchQuery.trim());
37
- }
38
- return;
39
- }
40
- if (key.tab) {
41
- if (commands.length > 0 && selectedIndex < commands.length) {
42
- const selectedCommand = commands[selectedIndex];
43
- onSelect(selectedCommand.command);
44
- }
45
- else if (commands.length === 0 && searchQuery.trim()) {
46
- // When no history records match, insert the search query
47
- onSelect(searchQuery.trim());
48
- }
49
- return;
50
- }
51
- if (key.escape) {
52
- onCancel();
53
- return;
54
- }
55
- if (key.ctrl && input === "d") {
56
- if (commands.length > 0 && selectedIndex < commands.length) {
57
- const selectedCommand = commands[selectedIndex];
58
- onDelete(selectedCommand.command, selectedCommand.workdir);
59
- setRefreshCounter((prev) => prev + 1);
60
- }
61
- return;
62
- }
63
- if (key.upArrow) {
64
- setSelectedIndex(Math.max(0, selectedIndex - 1));
65
- return;
66
- }
67
- if (key.downArrow) {
68
- setSelectedIndex(Math.min(commands.length - 1, selectedIndex + 1));
69
- return;
70
- }
71
- });
72
- if (commands.length === 0) {
73
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, children: [_jsxs(Text, { color: "yellow", children: ["No bash history found ", searchQuery && `for "${searchQuery}"`] }), searchQuery.trim() && (_jsxs(Text, { color: "green", children: ["Press Enter to execute: ", searchQuery] })), searchQuery.trim() && (_jsxs(Text, { color: "blue", children: ["Press Tab to insert: ", searchQuery] })), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
74
- }
75
- const formatTimestamp = (timestamp) => {
76
- const date = new Date(timestamp);
77
- const now = new Date();
78
- const diffMs = now.getTime() - date.getTime();
79
- const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
80
- const diffDays = Math.floor(diffHours / 24);
81
- if (diffDays > 0) {
82
- return `${diffDays}d ago`;
83
- }
84
- else if (diffHours > 0) {
85
- return `${diffHours}h ago`;
86
- }
87
- else {
88
- const diffMinutes = Math.floor(diffMs / (1000 * 60));
89
- return diffMinutes > 0 ? `${diffMinutes}m ago` : "just now";
90
- }
91
- };
92
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "blue", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "blue", bold: true, children: ["Bash History ", searchQuery && `(filtering: "${searchQuery}")`] }) }), commands.map((cmd, index) => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: index === selectedIndex ? "black" : "white", backgroundColor: index === selectedIndex ? "blue" : undefined, children: cmd.command }), index === selectedIndex && (_jsx(Box, { marginLeft: 4, flexDirection: "column", children: _jsxs(Text, { color: "gray", dimColor: true, children: [formatTimestamp(cmd.timestamp), cmd.workdir !== workdir && ` • in ${cmd.workdir}`] }) }))] }, index))), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 to navigate, Enter to execute, Tab to insert, Ctrl+d to remove, Escape to cancel" }) })] }));
93
- };
@@ -1,6 +0,0 @@
1
- import React from "react";
2
- export interface BashShellManagerProps {
3
- onCancel: () => void;
4
- }
5
- export declare const BashShellManager: React.FC<BashShellManagerProps>;
6
- //# sourceMappingURL=BashShellManager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BashShellManager.d.ts","sourceRoot":"","sources":["../../src/components/BashShellManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAanD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAwS5D,CAAC"}