wave-code 0.0.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.
Files changed (131) hide show
  1. package/README.md +120 -0
  2. package/bin/wave-code.js +16 -0
  3. package/dist/cli.d.ts +6 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +62 -0
  6. package/dist/components/App.d.ts +8 -0
  7. package/dist/components/App.d.ts.map +1 -0
  8. package/dist/components/App.js +10 -0
  9. package/dist/components/BashHistorySelector.d.ts +10 -0
  10. package/dist/components/BashHistorySelector.d.ts.map +1 -0
  11. package/dist/components/BashHistorySelector.js +83 -0
  12. package/dist/components/BashShellManager.d.ts +6 -0
  13. package/dist/components/BashShellManager.d.ts.map +1 -0
  14. package/dist/components/BashShellManager.js +116 -0
  15. package/dist/components/ChatInterface.d.ts +3 -0
  16. package/dist/components/ChatInterface.d.ts.map +1 -0
  17. package/dist/components/ChatInterface.js +31 -0
  18. package/dist/components/CommandOutputDisplay.d.ts +9 -0
  19. package/dist/components/CommandOutputDisplay.d.ts.map +1 -0
  20. package/dist/components/CommandOutputDisplay.js +40 -0
  21. package/dist/components/CommandSelector.d.ts +11 -0
  22. package/dist/components/CommandSelector.d.ts.map +1 -0
  23. package/dist/components/CommandSelector.js +60 -0
  24. package/dist/components/CompressDisplay.d.ts +9 -0
  25. package/dist/components/CompressDisplay.d.ts.map +1 -0
  26. package/dist/components/CompressDisplay.js +17 -0
  27. package/dist/components/DiffViewer.d.ts +9 -0
  28. package/dist/components/DiffViewer.d.ts.map +1 -0
  29. package/dist/components/DiffViewer.js +221 -0
  30. package/dist/components/FileSelector.d.ts +13 -0
  31. package/dist/components/FileSelector.d.ts.map +1 -0
  32. package/dist/components/FileSelector.js +48 -0
  33. package/dist/components/InputBox.d.ts +23 -0
  34. package/dist/components/InputBox.d.ts.map +1 -0
  35. package/dist/components/InputBox.js +124 -0
  36. package/dist/components/McpManager.d.ts +10 -0
  37. package/dist/components/McpManager.d.ts.map +1 -0
  38. package/dist/components/McpManager.js +123 -0
  39. package/dist/components/MemoryDisplay.d.ts +8 -0
  40. package/dist/components/MemoryDisplay.d.ts.map +1 -0
  41. package/dist/components/MemoryDisplay.js +25 -0
  42. package/dist/components/MemoryTypeSelector.d.ts +8 -0
  43. package/dist/components/MemoryTypeSelector.d.ts.map +1 -0
  44. package/dist/components/MemoryTypeSelector.js +38 -0
  45. package/dist/components/MessageList.d.ts +12 -0
  46. package/dist/components/MessageList.d.ts.map +1 -0
  47. package/dist/components/MessageList.js +36 -0
  48. package/dist/components/ToolResultDisplay.d.ts +9 -0
  49. package/dist/components/ToolResultDisplay.d.ts.map +1 -0
  50. package/dist/components/ToolResultDisplay.js +52 -0
  51. package/dist/contexts/useAppConfig.d.ts +11 -0
  52. package/dist/contexts/useAppConfig.d.ts.map +1 -0
  53. package/dist/contexts/useAppConfig.js +13 -0
  54. package/dist/contexts/useChat.d.ts +36 -0
  55. package/dist/contexts/useChat.d.ts.map +1 -0
  56. package/dist/contexts/useChat.js +208 -0
  57. package/dist/hooks/useBashHistorySelector.d.ts +15 -0
  58. package/dist/hooks/useBashHistorySelector.d.ts.map +1 -0
  59. package/dist/hooks/useBashHistorySelector.js +61 -0
  60. package/dist/hooks/useCommandSelector.d.ts +24 -0
  61. package/dist/hooks/useCommandSelector.d.ts.map +1 -0
  62. package/dist/hooks/useCommandSelector.js +98 -0
  63. package/dist/hooks/useFileSelector.d.ts +16 -0
  64. package/dist/hooks/useFileSelector.d.ts.map +1 -0
  65. package/dist/hooks/useFileSelector.js +174 -0
  66. package/dist/hooks/useImageManager.d.ts +13 -0
  67. package/dist/hooks/useImageManager.d.ts.map +1 -0
  68. package/dist/hooks/useImageManager.js +46 -0
  69. package/dist/hooks/useInputHistory.d.ts +11 -0
  70. package/dist/hooks/useInputHistory.d.ts.map +1 -0
  71. package/dist/hooks/useInputHistory.js +64 -0
  72. package/dist/hooks/useInputKeyboardHandler.d.ts +83 -0
  73. package/dist/hooks/useInputKeyboardHandler.d.ts.map +1 -0
  74. package/dist/hooks/useInputKeyboardHandler.js +507 -0
  75. package/dist/hooks/useInputState.d.ts +14 -0
  76. package/dist/hooks/useInputState.d.ts.map +1 -0
  77. package/dist/hooks/useInputState.js +57 -0
  78. package/dist/hooks/useMemoryTypeSelector.d.ts +9 -0
  79. package/dist/hooks/useMemoryTypeSelector.d.ts.map +1 -0
  80. package/dist/hooks/useMemoryTypeSelector.js +27 -0
  81. package/dist/hooks/usePagination.d.ts +20 -0
  82. package/dist/hooks/usePagination.d.ts.map +1 -0
  83. package/dist/hooks/usePagination.js +168 -0
  84. package/dist/index.d.ts +5 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +91 -0
  87. package/dist/plain-cli.d.ts +7 -0
  88. package/dist/plain-cli.d.ts.map +1 -0
  89. package/dist/plain-cli.js +49 -0
  90. package/dist/utils/clipboard.d.ts +22 -0
  91. package/dist/utils/clipboard.d.ts.map +1 -0
  92. package/dist/utils/clipboard.js +347 -0
  93. package/dist/utils/constants.d.ts +17 -0
  94. package/dist/utils/constants.d.ts.map +1 -0
  95. package/dist/utils/constants.js +18 -0
  96. package/dist/utils/logger.d.ts +72 -0
  97. package/dist/utils/logger.d.ts.map +1 -0
  98. package/dist/utils/logger.js +245 -0
  99. package/package.json +60 -0
  100. package/src/cli.tsx +82 -0
  101. package/src/components/App.tsx +31 -0
  102. package/src/components/BashHistorySelector.tsx +163 -0
  103. package/src/components/BashShellManager.tsx +306 -0
  104. package/src/components/ChatInterface.tsx +88 -0
  105. package/src/components/CommandOutputDisplay.tsx +81 -0
  106. package/src/components/CommandSelector.tsx +144 -0
  107. package/src/components/CompressDisplay.tsx +58 -0
  108. package/src/components/DiffViewer.tsx +321 -0
  109. package/src/components/FileSelector.tsx +137 -0
  110. package/src/components/InputBox.tsx +310 -0
  111. package/src/components/McpManager.tsx +328 -0
  112. package/src/components/MemoryDisplay.tsx +62 -0
  113. package/src/components/MemoryTypeSelector.tsx +96 -0
  114. package/src/components/MessageList.tsx +215 -0
  115. package/src/components/ToolResultDisplay.tsx +138 -0
  116. package/src/contexts/useAppConfig.tsx +32 -0
  117. package/src/contexts/useChat.tsx +300 -0
  118. package/src/hooks/useBashHistorySelector.ts +77 -0
  119. package/src/hooks/useCommandSelector.ts +131 -0
  120. package/src/hooks/useFileSelector.ts +227 -0
  121. package/src/hooks/useImageManager.ts +64 -0
  122. package/src/hooks/useInputHistory.ts +74 -0
  123. package/src/hooks/useInputKeyboardHandler.ts +778 -0
  124. package/src/hooks/useInputState.ts +66 -0
  125. package/src/hooks/useMemoryTypeSelector.ts +40 -0
  126. package/src/hooks/usePagination.ts +203 -0
  127. package/src/index.ts +108 -0
  128. package/src/plain-cli.ts +66 -0
  129. package/src/utils/clipboard.ts +384 -0
  130. package/src/utils/constants.ts +22 -0
  131. package/src/utils/logger.ts +301 -0
@@ -0,0 +1,98 @@
1
+ import { useState, useCallback } from "react";
2
+ export const useCommandSelector = ({ onShowBashManager, onShowMcpManager, sendMessage, hasSlashCommand, }) => {
3
+ const [showCommandSelector, setShowCommandSelector] = useState(false);
4
+ const [slashPosition, setSlashPosition] = useState(-1);
5
+ const [commandSearchQuery, setCommandSearchQuery] = useState("");
6
+ const activateCommandSelector = useCallback((position) => {
7
+ setShowCommandSelector(true);
8
+ setSlashPosition(position);
9
+ setCommandSearchQuery("");
10
+ }, []);
11
+ const handleCommandInsert = useCallback((command, inputText, cursorPosition) => {
12
+ if (slashPosition >= 0) {
13
+ // Replace content from / to current cursor position with /command_name + space
14
+ const beforeSlash = inputText.substring(0, slashPosition);
15
+ const afterQuery = inputText.substring(cursorPosition);
16
+ const newInput = beforeSlash + `/${command} ` + afterQuery;
17
+ const newCursorPosition = beforeSlash.length + command.length + 2; // +2 for "/" and " "
18
+ setShowCommandSelector(false);
19
+ setSlashPosition(-1);
20
+ setCommandSearchQuery("");
21
+ return { newInput, newCursorPosition };
22
+ }
23
+ return { newInput: inputText, newCursorPosition: cursorPosition };
24
+ }, [slashPosition]);
25
+ const handleCommandSelect = useCallback((command, inputText, cursorPosition) => {
26
+ if (slashPosition >= 0) {
27
+ // Replace command part, keep other content
28
+ const beforeSlash = inputText.substring(0, slashPosition);
29
+ const afterQuery = inputText.substring(cursorPosition);
30
+ const newInput = beforeSlash + afterQuery;
31
+ const newCursorPosition = beforeSlash.length;
32
+ // Execute command asynchronously
33
+ (async () => {
34
+ // First check if it's an agent command
35
+ let commandExecuted = false;
36
+ if (sendMessage && hasSlashCommand && hasSlashCommand(command)) {
37
+ // Execute complete command (replace partial input with complete command name)
38
+ const fullCommand = `/${command}`;
39
+ try {
40
+ await sendMessage(fullCommand);
41
+ commandExecuted = true;
42
+ }
43
+ catch (error) {
44
+ console.error("Failed to execute slash command:", error);
45
+ }
46
+ }
47
+ // If not an agent command or execution failed, check local commands
48
+ if (!commandExecuted) {
49
+ if (command === "bashes" && onShowBashManager) {
50
+ onShowBashManager();
51
+ commandExecuted = true;
52
+ }
53
+ else if (command === "mcp" && onShowMcpManager) {
54
+ onShowMcpManager();
55
+ commandExecuted = true;
56
+ }
57
+ }
58
+ })();
59
+ setShowCommandSelector(false);
60
+ setSlashPosition(-1);
61
+ setCommandSearchQuery("");
62
+ return { newInput, newCursorPosition };
63
+ }
64
+ return { newInput: inputText, newCursorPosition: cursorPosition };
65
+ }, [
66
+ slashPosition,
67
+ onShowBashManager,
68
+ onShowMcpManager,
69
+ sendMessage,
70
+ hasSlashCommand,
71
+ ]);
72
+ const handleCancelCommandSelect = useCallback(() => {
73
+ setShowCommandSelector(false);
74
+ setSlashPosition(-1);
75
+ setCommandSearchQuery("");
76
+ }, []);
77
+ const updateCommandSearchQuery = useCallback((query) => {
78
+ setCommandSearchQuery(query);
79
+ }, []);
80
+ const checkForSlashDeletion = useCallback((cursorPosition) => {
81
+ if (showCommandSelector && cursorPosition <= slashPosition) {
82
+ handleCancelCommandSelect();
83
+ return true;
84
+ }
85
+ return false;
86
+ }, [showCommandSelector, slashPosition, handleCancelCommandSelect]);
87
+ return {
88
+ showCommandSelector,
89
+ commandSearchQuery,
90
+ activateCommandSelector,
91
+ handleCommandSelect,
92
+ handleCommandInsert,
93
+ handleCancelCommandSelect,
94
+ updateCommandSearchQuery,
95
+ checkForSlashDeletion,
96
+ slashPosition,
97
+ };
98
+ };
@@ -0,0 +1,16 @@
1
+ import { FileItem } from "../components/FileSelector.js";
2
+ export declare const useFileSelector: () => {
3
+ showFileSelector: boolean;
4
+ filteredFiles: FileItem[];
5
+ searchQuery: string;
6
+ activateFileSelector: (position: number) => void;
7
+ handleFileSelect: (filePath: string, inputText: string, cursorPosition: number) => {
8
+ newInput: string;
9
+ newCursorPosition: number;
10
+ };
11
+ handleCancelFileSelect: () => void;
12
+ updateSearchQuery: (query: string) => void;
13
+ checkForAtDeletion: (cursorPosition: number) => boolean;
14
+ atPosition: number;
15
+ };
16
+ //# sourceMappingURL=useFileSelector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFileSelector.d.ts","sourceRoot":"","sources":["../../src/hooks/useFileSelector.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAEzD,eAAO,MAAM,eAAe;;;;qCA2Jb,MAAM;iCAWN,MAAM,aAAa,MAAM,kBAAkB,MAAM;;;;;+BA2BhB,MAAM;yCAKjC,MAAM;;CAqB1B,CAAC"}
@@ -0,0 +1,174 @@
1
+ import { useState, useCallback, useEffect, useRef } from "react";
2
+ import { glob } from "glob";
3
+ import { getGlobIgnorePatterns } from "wave-agent-sdk";
4
+ import * as fs from "fs";
5
+ import * as path from "path";
6
+ export const useFileSelector = () => {
7
+ const [showFileSelector, setShowFileSelector] = useState(false);
8
+ const [atPosition, setAtPosition] = useState(-1);
9
+ const [searchQuery, setSearchQuery] = useState("");
10
+ const [filteredFiles, setFilteredFiles] = useState([]);
11
+ const debounceTimerRef = useRef(null);
12
+ // Check if path is a directory
13
+ const isDirectory = useCallback((filePath) => {
14
+ try {
15
+ const fullPath = path.isAbsolute(filePath)
16
+ ? filePath
17
+ : path.join(process.cwd(), filePath);
18
+ return fs.statSync(fullPath).isDirectory();
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ }, []);
24
+ // Convert string paths to FileItem objects
25
+ const convertToFileItems = useCallback((paths) => {
26
+ return paths.map((filePath) => ({
27
+ path: filePath,
28
+ type: isDirectory(filePath) ? "directory" : "file",
29
+ }));
30
+ }, [isDirectory]);
31
+ // Use glob to search files and directories
32
+ const searchFiles = useCallback(async (query) => {
33
+ try {
34
+ let files = [];
35
+ let directories = [];
36
+ const globOptions = {
37
+ ignore: getGlobIgnorePatterns(process.cwd()),
38
+ maxDepth: 10,
39
+ nocase: true, // Case insensitive
40
+ dot: true, // Include hidden files and directories
41
+ cwd: process.cwd(), // Specify search root directory
42
+ };
43
+ if (!query.trim()) {
44
+ // When query is empty, show some common file types and directories
45
+ const commonPatterns = [
46
+ "**/*.ts",
47
+ "**/*.tsx",
48
+ "**/*.js",
49
+ "**/*.jsx",
50
+ "**/*.json",
51
+ ];
52
+ // Search files
53
+ const filePromises = commonPatterns.map((pattern) => glob(pattern, { ...globOptions, nodir: true }));
54
+ // Search directories (only search first level to avoid too many results)
55
+ const dirPromises = [glob("*/", { ...globOptions, maxDepth: 1 })];
56
+ const fileResults = await Promise.all(filePromises);
57
+ const dirResults = await Promise.all(dirPromises);
58
+ files = fileResults.flat();
59
+ directories = dirResults.flat().map((dir) => {
60
+ // glob returns string type paths, remove trailing slash
61
+ return String(dir).replace(/\/$/, "");
62
+ });
63
+ }
64
+ else {
65
+ // Build multiple glob patterns to support more flexible search
66
+ const filePatterns = [
67
+ // Match files with filenames containing query
68
+ `**/*${query}*`,
69
+ // Match files with query in path (match directory names)
70
+ `**/${query}*/**/*`,
71
+ ];
72
+ const dirPatterns = [
73
+ // Match directory names containing query
74
+ `**/*${query}*/`,
75
+ // Match directories containing query in path
76
+ `**/${query}*/`,
77
+ ];
78
+ // Search files
79
+ const filePromises = filePatterns.map((pattern) => glob(pattern, { ...globOptions, nodir: true }));
80
+ // Search directories
81
+ const dirPromises = dirPatterns.map((pattern) => glob(pattern, { ...globOptions, nodir: false }));
82
+ const fileResults = await Promise.all(filePromises);
83
+ const dirResults = await Promise.all(dirPromises);
84
+ files = fileResults.flat();
85
+ directories = dirResults.flat().map((dir) => {
86
+ // glob returns string type paths, remove trailing slash
87
+ return String(dir).replace(/\/$/, "");
88
+ });
89
+ }
90
+ // Deduplicate and merge files and directories
91
+ const uniqueFiles = Array.from(new Set(files));
92
+ const uniqueDirectories = Array.from(new Set(directories));
93
+ const allPaths = [...uniqueDirectories, ...uniqueFiles]; // Directories first
94
+ // Limit to maximum 10 results and convert to FileItem
95
+ const fileItems = convertToFileItems(allPaths.slice(0, 10));
96
+ setFilteredFiles(fileItems);
97
+ }
98
+ catch (error) {
99
+ console.error("Glob search error:", error);
100
+ setFilteredFiles([]);
101
+ }
102
+ }, [convertToFileItems]);
103
+ // Debounced search
104
+ const debouncedSearchFiles = useCallback((query) => {
105
+ // Clear previous timer
106
+ if (debounceTimerRef.current) {
107
+ clearTimeout(debounceTimerRef.current);
108
+ }
109
+ // Set new timer, support environment variable configuration
110
+ const debounceDelay = parseInt(process.env.FILE_SELECTOR_DEBOUNCE_MS || "300", 10);
111
+ debounceTimerRef.current = setTimeout(() => {
112
+ searchFiles(query);
113
+ }, debounceDelay);
114
+ }, [searchFiles]);
115
+ // Trigger debounced search when search query changes
116
+ useEffect(() => {
117
+ debouncedSearchFiles(searchQuery);
118
+ // Cleanup function: clear timer when component unmounts
119
+ return () => {
120
+ if (debounceTimerRef.current) {
121
+ clearTimeout(debounceTimerRef.current);
122
+ }
123
+ };
124
+ }, [searchQuery, debouncedSearchFiles]);
125
+ const activateFileSelector = useCallback((position) => {
126
+ setShowFileSelector(true);
127
+ setAtPosition(position);
128
+ setSearchQuery("");
129
+ // Immediately trigger search to display initial file list, without waiting for debounce
130
+ searchFiles("");
131
+ }, [searchFiles]);
132
+ const handleFileSelect = useCallback((filePath, inputText, cursorPosition) => {
133
+ if (atPosition >= 0) {
134
+ // Replace @ and search query with selected file path, remove @ symbol
135
+ const beforeAt = inputText.substring(0, atPosition);
136
+ const afterQuery = inputText.substring(cursorPosition);
137
+ const newInput = beforeAt + `${filePath} ` + afterQuery;
138
+ const newCursorPosition = beforeAt.length + filePath.length + 1;
139
+ setShowFileSelector(false);
140
+ setAtPosition(-1);
141
+ setSearchQuery("");
142
+ setFilteredFiles([]);
143
+ return { newInput, newCursorPosition };
144
+ }
145
+ return { newInput: inputText, newCursorPosition: cursorPosition };
146
+ }, [atPosition]);
147
+ const handleCancelFileSelect = useCallback(() => {
148
+ setShowFileSelector(false);
149
+ setAtPosition(-1);
150
+ setSearchQuery("");
151
+ setFilteredFiles([]);
152
+ }, []);
153
+ const updateSearchQuery = useCallback((query) => {
154
+ setSearchQuery(query);
155
+ }, []);
156
+ const checkForAtDeletion = useCallback((cursorPosition) => {
157
+ if (showFileSelector && cursorPosition <= atPosition) {
158
+ handleCancelFileSelect();
159
+ return true;
160
+ }
161
+ return false;
162
+ }, [showFileSelector, atPosition, handleCancelFileSelect]);
163
+ return {
164
+ showFileSelector,
165
+ filteredFiles,
166
+ searchQuery,
167
+ activateFileSelector,
168
+ handleFileSelect,
169
+ handleCancelFileSelect,
170
+ updateSearchQuery,
171
+ checkForAtDeletion,
172
+ atPosition,
173
+ };
174
+ };
@@ -0,0 +1,13 @@
1
+ export interface AttachedImage {
2
+ id: number;
3
+ path: string;
4
+ mimeType: string;
5
+ }
6
+ export declare const useImageManager: (insertTextAtCursor: (text: string) => void) => {
7
+ attachedImages: AttachedImage[];
8
+ addImage: (imagePath: string, mimeType: string) => AttachedImage;
9
+ removeImage: (imageId: number) => void;
10
+ clearImages: () => void;
11
+ handlePasteImage: () => Promise<boolean>;
12
+ };
13
+ //# sourceMappingURL=useImageManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useImageManager.d.ts","sourceRoot":"","sources":["../../src/hooks/useImageManager.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,GAAI,oBAAoB,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI;;0BAK1D,MAAM,YAAY,MAAM;2BAaI,MAAM;;;CAoCjD,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { useState, useCallback } from "react";
2
+ import { readClipboardImage } from "../utils/clipboard.js";
3
+ export const useImageManager = (insertTextAtCursor) => {
4
+ const [attachedImages, setAttachedImages] = useState([]);
5
+ const [imageIdCounter, setImageIdCounter] = useState(1);
6
+ const addImage = useCallback((imagePath, mimeType) => {
7
+ const newImage = {
8
+ id: imageIdCounter,
9
+ path: imagePath,
10
+ mimeType,
11
+ };
12
+ setAttachedImages((prev) => [...prev, newImage]);
13
+ setImageIdCounter((prev) => prev + 1);
14
+ return newImage;
15
+ }, [imageIdCounter]);
16
+ const removeImage = useCallback((imageId) => {
17
+ setAttachedImages((prev) => prev.filter((img) => img.id !== imageId));
18
+ }, []);
19
+ const clearImages = useCallback(() => {
20
+ setAttachedImages([]);
21
+ }, []);
22
+ const handlePasteImage = useCallback(async () => {
23
+ try {
24
+ const result = await readClipboardImage();
25
+ if (result.success && result.imagePath && result.mimeType) {
26
+ // Add image to manager
27
+ const attachedImage = addImage(result.imagePath, result.mimeType);
28
+ // Insert image placeholder at cursor position
29
+ insertTextAtCursor(`[Image #${attachedImage.id}]`);
30
+ return true;
31
+ }
32
+ return false;
33
+ }
34
+ catch (error) {
35
+ console.warn("Failed to paste image from clipboard:", error);
36
+ return false;
37
+ }
38
+ }, [addImage, insertTextAtCursor]);
39
+ return {
40
+ attachedImages,
41
+ addImage,
42
+ removeImage,
43
+ clearImages,
44
+ handlePasteImage,
45
+ };
46
+ };
@@ -0,0 +1,11 @@
1
+ export interface UseInputHistoryParams {
2
+ userInputHistory: string[];
3
+ }
4
+ export declare const useInputHistory: ({ userInputHistory, }: UseInputHistoryParams) => {
5
+ resetHistoryNavigation: () => void;
6
+ navigateHistory: (direction: "up" | "down", inputText: string) => {
7
+ newInput: string;
8
+ newCursorPosition: number;
9
+ };
10
+ };
11
+ //# sourceMappingURL=useInputHistory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInputHistory.d.ts","sourceRoot":"","sources":["../../src/hooks/useInputHistory.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,eAAO,MAAM,eAAe,GAAI,uBAE7B,qBAAqB;;iCAYR,IAAI,GAAG,MAAM,aAAa,MAAM;;;;CAqD/C,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { useState, useCallback } from "react";
2
+ export const useInputHistory = ({ userInputHistory, }) => {
3
+ const [historyIndex, setHistoryIndex] = useState(-1);
4
+ const [currentDraftText, setCurrentDraftText] = useState("");
5
+ // Reset history navigation state
6
+ const resetHistoryNavigation = useCallback(() => {
7
+ setHistoryIndex(-1);
8
+ setCurrentDraftText("");
9
+ }, []);
10
+ // Handle history navigation
11
+ const navigateHistory = useCallback((direction, inputText) => {
12
+ if (userInputHistory.length === 0)
13
+ return { newInput: inputText, newCursorPosition: inputText.length };
14
+ let newInput;
15
+ if (direction === "up") {
16
+ // Navigate up to earlier history records
17
+ if (historyIndex === -1) {
18
+ // First time pressing up key, save current input as draft
19
+ setCurrentDraftText(inputText);
20
+ const newIndex = userInputHistory.length - 1;
21
+ setHistoryIndex(newIndex);
22
+ newInput = userInputHistory[newIndex];
23
+ }
24
+ else if (historyIndex > 0) {
25
+ const newIndex = historyIndex - 1;
26
+ setHistoryIndex(newIndex);
27
+ newInput = userInputHistory[newIndex];
28
+ }
29
+ else {
30
+ newInput = inputText;
31
+ }
32
+ }
33
+ else {
34
+ // Navigate down to newer history records
35
+ if (historyIndex >= 0) {
36
+ if (historyIndex < userInputHistory.length - 1) {
37
+ const newIndex = historyIndex + 1;
38
+ setHistoryIndex(newIndex);
39
+ newInput = userInputHistory[newIndex];
40
+ }
41
+ else {
42
+ // Return to draft text
43
+ setHistoryIndex(-1);
44
+ newInput = currentDraftText;
45
+ }
46
+ }
47
+ else {
48
+ // Already in draft state, pressing down key again clears input box
49
+ if (inputText.trim() !== "") {
50
+ setCurrentDraftText("");
51
+ newInput = "";
52
+ }
53
+ else {
54
+ newInput = inputText;
55
+ }
56
+ }
57
+ }
58
+ return { newInput, newCursorPosition: newInput.length };
59
+ }, [userInputHistory, historyIndex, currentDraftText]);
60
+ return {
61
+ resetHistoryNavigation,
62
+ navigateHistory,
63
+ };
64
+ };
@@ -0,0 +1,83 @@
1
+ interface KeyboardHandlerProps {
2
+ inputText: string;
3
+ setInputText: (text: string) => void;
4
+ cursorPosition: number;
5
+ setCursorPosition: (position: number) => void;
6
+ moveCursorLeft: () => void;
7
+ moveCursorRight: () => void;
8
+ moveCursorToStart: () => void;
9
+ moveCursorToEnd: () => void;
10
+ deleteCharAtCursor: () => void;
11
+ insertTextAtCursor: (text: string) => void;
12
+ clearInput: () => void;
13
+ resetHistoryNavigation: () => void;
14
+ navigateHistory: (direction: "up" | "down", inputText: string, activateBashMode?: () => void) => {
15
+ newInput: string;
16
+ newCursorPosition: number;
17
+ };
18
+ handlePasteImage: () => Promise<boolean>;
19
+ attachedImages: Array<{
20
+ id: number;
21
+ path: string;
22
+ mimeType: string;
23
+ }>;
24
+ clearImages: () => void;
25
+ showFileSelector: boolean;
26
+ activateFileSelector: (position: number) => void;
27
+ handleFileSelect: (filePath: string, inputText: string, cursorPosition: number) => {
28
+ newInput: string;
29
+ newCursorPosition: number;
30
+ };
31
+ handleCancelFileSelect: () => void;
32
+ updateSearchQuery: (query: string) => void;
33
+ checkForAtDeletion: (cursorPosition: number) => boolean;
34
+ atPosition: number;
35
+ showCommandSelector: boolean;
36
+ activateCommandSelector: (position: number) => void;
37
+ handleCommandSelect: (command: string, inputText: string, cursorPosition: number) => {
38
+ newInput: string;
39
+ newCursorPosition: number;
40
+ };
41
+ handleCommandInsert: (command: string, inputText: string, cursorPosition: number) => {
42
+ newInput: string;
43
+ newCursorPosition: number;
44
+ };
45
+ handleCancelCommandSelect: () => void;
46
+ updateCommandSearchQuery: (query: string) => void;
47
+ checkForSlashDeletion: (cursorPosition: number) => boolean;
48
+ slashPosition: number;
49
+ showBashHistorySelector: boolean;
50
+ activateBashHistorySelector: (position: number) => void;
51
+ handleBashHistorySelect: (command: string, inputText: string, cursorPosition: number) => {
52
+ newInput: string;
53
+ newCursorPosition: number;
54
+ };
55
+ handleBashHistoryExecute: (command: string) => string;
56
+ handleCancelBashHistorySelect: () => void;
57
+ updateBashHistorySearchQuery: (query: string) => void;
58
+ checkForExclamationDeletion: (cursorPosition: number) => boolean;
59
+ exclamationPosition: number;
60
+ showMemoryTypeSelector: boolean;
61
+ activateMemoryTypeSelector: (message: string) => void;
62
+ handleMemoryTypeSelect: (type: "project" | "user") => void;
63
+ showBashManager: boolean;
64
+ showMcpManager: boolean;
65
+ isCommandRunning: boolean;
66
+ isLoading: boolean;
67
+ sendMessage: (message: string, images?: Array<{
68
+ path: string;
69
+ mimeType: string;
70
+ }>) => void;
71
+ abortMessage: () => void;
72
+ saveMemory: (message: string, type: "project" | "user") => Promise<void>;
73
+ }
74
+ export declare const useInputKeyboardHandler: (props: KeyboardHandlerProps) => {
75
+ handleFileSelect: (filePath: string) => void;
76
+ handleCommandSelect: (command: string) => void;
77
+ handleCommandInsert: (command: string) => void;
78
+ handleBashHistorySelect: (command: string) => void;
79
+ handleBashHistoryExecute: (command: string) => void;
80
+ handleMemoryTypeSelect: (type: "project" | "user") => Promise<void>;
81
+ };
82
+ export {};
83
+ //# sourceMappingURL=useInputKeyboardHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInputKeyboardHandler.d.ts","sourceRoot":"","sources":["../../src/hooks/useInputKeyboardHandler.ts"],"names":[],"mappings":"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"}