wave-code 0.8.1 → 0.8.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.
@@ -1,284 +1,401 @@
1
- import { useEffect, useRef, useState, useCallback } from "react";
1
+ import { useEffect, useReducer, useCallback, useRef } from "react";
2
2
  import { Key } from "ink";
3
3
  import {
4
- InputManager,
4
+ inputReducer,
5
+ initialState,
5
6
  InputManagerCallbacks,
6
- AttachedImage,
7
- } from "../managers/InputManager.js";
8
- import { FileItem } from "../components/FileSelector.js";
9
- import { PermissionMode } from "wave-agent-sdk";
10
- import { logger } from "../utils/logger.js";
7
+ } from "../managers/inputReducer.js";
8
+ import { searchFiles as searchFilesUtil, PermissionMode } from "wave-agent-sdk";
9
+ import * as handlers from "../managers/inputHandlers.js";
11
10
 
12
11
  export const useInputManager = (
13
12
  callbacks: Partial<InputManagerCallbacks> = {},
14
13
  ) => {
15
- const managerRef = useRef<InputManager | null>(null);
16
- const [isManagerReady, setIsManagerReady] = useState(false);
17
-
18
- // React state that mirrors InputManager state
19
- const [inputText, setInputText] = useState("");
20
- const [cursorPosition, setCursorPosition] = useState(0);
21
- const [fileSelectorState, setFileSelectorState] = useState({
22
- show: false,
23
- files: [] as FileItem[],
24
- query: "",
25
- position: -1,
26
- });
27
- const [commandSelectorState, setCommandSelectorState] = useState({
28
- show: false,
29
- query: "",
30
- position: -1,
31
- });
32
- const [historySearchState, setHistorySearchState] = useState({
33
- show: false,
34
- query: "",
35
- });
36
- const [showBackgroundTaskManager, setShowBackgroundTaskManager] =
37
- useState(false);
38
- const [showMcpManager, setShowMcpManager] = useState(false);
39
- const [showRewindManager, setShowRewindManager] = useState(false);
40
- const [showHelp, setShowHelp] = useState(false);
41
- const [showStatusCommand, setShowStatusCommand] = useState(false);
42
- const [permissionMode, setPermissionModeState] =
43
- useState<PermissionMode>("default");
44
- const [attachedImages, setAttachedImages] = useState<AttachedImage[]>([]);
45
-
46
- // Create InputManager on mount and update callbacks when they change
14
+ const [state, dispatch] = useReducer(inputReducer, initialState);
15
+ const callbacksRef = useRef(callbacks);
16
+ const stateRef = useRef(state);
17
+
18
+ // Update refs when they change
47
19
  useEffect(() => {
48
- if (!managerRef.current) {
49
- // Create InputManager on first mount
50
- const manager = new InputManager({
51
- logger,
52
- onInputTextChange: setInputText,
53
- onCursorPositionChange: setCursorPosition,
54
- onFileSelectorStateChange: (show, files, query, position) => {
55
- setFileSelectorState({ show, files, query, position });
56
- },
57
- onCommandSelectorStateChange: (show, query, position) => {
58
- setCommandSelectorState({ show, query, position });
59
- },
60
- onHistorySearchStateChange: (show, query) => {
61
- setHistorySearchState({ show, query });
62
- },
63
- onBackgroundTaskManagerStateChange: (show) => {
64
- setShowBackgroundTaskManager(show);
65
- },
66
- onMcpManagerStateChange: (show) => {
67
- setShowMcpManager(show);
68
- },
69
- onRewindManagerStateChange: (show) => {
70
- setShowRewindManager(show);
71
- },
72
- onHelpStateChange: (show) => {
73
- setShowHelp(show);
74
- },
75
- onStatusCommandStateChange: (show) => {
76
- setShowStatusCommand(show);
77
- },
78
- onPermissionModeChange: (mode) => {
79
- setPermissionModeState(mode);
80
- callbacks.onPermissionModeChange?.(mode);
81
- },
82
- onImagesStateChange: setAttachedImages,
83
- ...callbacks,
84
- });
85
-
86
- managerRef.current = manager;
87
- setIsManagerReady(true);
88
- } else {
89
- // Update callbacks on existing manager
90
- managerRef.current.updateCallbacks({
91
- logger,
92
- onInputTextChange: setInputText,
93
- onCursorPositionChange: setCursorPosition,
94
- onFileSelectorStateChange: (show, files, query, position) => {
95
- setFileSelectorState({ show, files, query, position });
96
- },
97
- onCommandSelectorStateChange: (show, query, position) => {
98
- setCommandSelectorState({ show, query, position });
99
- },
100
- onHistorySearchStateChange: (show, query) => {
101
- setHistorySearchState({ show, query });
102
- },
103
- onBackgroundTaskManagerStateChange: (show) => {
104
- setShowBackgroundTaskManager(show);
105
- },
106
- onMcpManagerStateChange: (show) => {
107
- setShowMcpManager(show);
108
- },
109
- onRewindManagerStateChange: (show) => {
110
- setShowRewindManager(show);
111
- },
112
- onHelpStateChange: (show) => {
113
- setShowHelp(show);
114
- },
115
- onStatusCommandStateChange: (show) => {
116
- setShowStatusCommand(show);
117
- },
118
- onPermissionModeChange: (mode) => {
119
- setPermissionModeState(mode);
120
- callbacks.onPermissionModeChange?.(mode);
121
- },
122
- onImagesStateChange: setAttachedImages,
123
- ...callbacks,
124
- });
125
- }
20
+ callbacksRef.current = callbacks;
126
21
  }, [callbacks]);
127
22
 
128
- // Cleanup on unmount
129
23
  useEffect(() => {
130
- return () => {
131
- if (managerRef.current) {
132
- managerRef.current.destroy();
133
- }
134
- };
135
- }, []);
24
+ stateRef.current = state;
25
+ }, [state]);
136
26
 
137
- // Expose manager methods
138
- const insertTextAtCursor = useCallback(
139
- (
140
- text: string,
141
- callback?: (newText: string, newCursorPosition: number) => void,
142
- ) => {
143
- managerRef.current?.insertTextAtCursor(text, callback);
144
- },
145
- [],
146
- );
27
+ // Handle selectorJustUsed reset
28
+ useEffect(() => {
29
+ if (state.selectorJustUsed) {
30
+ const timer = setTimeout(() => {
31
+ dispatch({ type: "SET_SELECTOR_JUST_USED", payload: false });
32
+ }, 0);
33
+ return () => clearTimeout(timer);
34
+ }
35
+ }, [state.selectorJustUsed]);
147
36
 
148
- const deleteCharAtCursor = useCallback(
149
- (callback?: (newText: string, newCursorPosition: number) => void) => {
150
- managerRef.current?.deleteCharAtCursor(callback);
151
- },
152
- [],
153
- );
37
+ // Handle debounced file search
38
+ useEffect(() => {
39
+ if (state.showFileSelector) {
40
+ const debounceDelay = parseInt(
41
+ process.env.FILE_SELECTOR_DEBOUNCE_MS || "300",
42
+ 10,
43
+ );
44
+ const timer = setTimeout(async () => {
45
+ try {
46
+ const fileItems = await searchFilesUtil(state.fileSearchQuery);
47
+ dispatch({ type: "SET_FILTERED_FILES", payload: fileItems });
48
+ } catch (error) {
49
+ console.error("File search error:", error);
50
+ dispatch({ type: "SET_FILTERED_FILES", payload: [] });
51
+ }
52
+ }, debounceDelay);
53
+ return () => clearTimeout(timer);
54
+ }
55
+ }, [state.showFileSelector, state.fileSearchQuery]);
56
+
57
+ // Handle paste debouncing
58
+ useEffect(() => {
59
+ if (state.isPasting) {
60
+ const pasteDebounceDelay = parseInt(
61
+ process.env.PASTE_DEBOUNCE_MS || "30",
62
+ 10,
63
+ );
64
+ const timer = setTimeout(() => {
65
+ const processedInput = stateRef.current.pasteBuffer.replace(
66
+ /\r/g,
67
+ "\n",
68
+ );
69
+ dispatch({ type: "COMPRESS_AND_INSERT_TEXT", payload: processedInput });
70
+ dispatch({ type: "END_PASTE" });
71
+ callbacksRef.current.onResetHistoryNavigation?.();
72
+ }, pasteDebounceDelay);
73
+ return () => clearTimeout(timer);
74
+ }
75
+ }, [state.isPasting, state.pasteBuffer]);
76
+
77
+ // Sync state changes with callbacks
78
+ useEffect(() => {
79
+ callbacksRef.current.onInputTextChange?.(state.inputText);
80
+ }, [state.inputText]);
81
+
82
+ useEffect(() => {
83
+ callbacksRef.current.onCursorPositionChange?.(state.cursorPosition);
84
+ }, [state.cursorPosition]);
85
+
86
+ useEffect(() => {
87
+ callbacksRef.current.onFileSelectorStateChange?.(
88
+ state.showFileSelector,
89
+ state.filteredFiles,
90
+ state.fileSearchQuery,
91
+ state.atPosition,
92
+ );
93
+ }, [
94
+ state.showFileSelector,
95
+ state.filteredFiles,
96
+ state.fileSearchQuery,
97
+ state.atPosition,
98
+ ]);
99
+
100
+ useEffect(() => {
101
+ callbacksRef.current.onCommandSelectorStateChange?.(
102
+ state.showCommandSelector,
103
+ state.commandSearchQuery,
104
+ state.slashPosition,
105
+ );
106
+ }, [
107
+ state.showCommandSelector,
108
+ state.commandSearchQuery,
109
+ state.slashPosition,
110
+ ]);
111
+
112
+ useEffect(() => {
113
+ callbacksRef.current.onHistorySearchStateChange?.(
114
+ state.showHistorySearch,
115
+ state.historySearchQuery,
116
+ );
117
+ }, [state.showHistorySearch, state.historySearchQuery]);
118
+
119
+ useEffect(() => {
120
+ callbacksRef.current.onBackgroundTaskManagerStateChange?.(
121
+ state.showBackgroundTaskManager,
122
+ );
123
+ }, [state.showBackgroundTaskManager]);
124
+
125
+ useEffect(() => {
126
+ callbacksRef.current.onMcpManagerStateChange?.(state.showMcpManager);
127
+ }, [state.showMcpManager]);
128
+
129
+ useEffect(() => {
130
+ callbacksRef.current.onRewindManagerStateChange?.(state.showRewindManager);
131
+ }, [state.showRewindManager]);
132
+
133
+ useEffect(() => {
134
+ callbacksRef.current.onHelpStateChange?.(state.showHelp);
135
+ }, [state.showHelp]);
136
+
137
+ useEffect(() => {
138
+ callbacksRef.current.onStatusCommandStateChange?.(state.showStatusCommand);
139
+ }, [state.showStatusCommand]);
140
+
141
+ useEffect(() => {
142
+ callbacksRef.current.onImagesStateChange?.(state.attachedImages);
143
+ }, [state.attachedImages]);
144
+
145
+ // Methods
146
+ const insertTextAtCursor = useCallback((text: string) => {
147
+ dispatch({ type: "INSERT_TEXT", payload: text });
148
+ }, []);
149
+
150
+ const deleteCharAtCursor = useCallback(() => {
151
+ dispatch({ type: "DELETE_CHAR" });
152
+ }, []);
154
153
 
155
154
  const clearInput = useCallback(() => {
156
- managerRef.current?.clearInput();
155
+ dispatch({ type: "CLEAR_INPUT" });
157
156
  }, []);
158
157
 
159
158
  const moveCursorLeft = useCallback(() => {
160
- managerRef.current?.moveCursorLeft();
159
+ dispatch({ type: "MOVE_CURSOR", payload: -1 });
161
160
  }, []);
162
161
 
163
162
  const moveCursorRight = useCallback(() => {
164
- managerRef.current?.moveCursorRight();
163
+ dispatch({ type: "MOVE_CURSOR", payload: 1 });
165
164
  }, []);
166
165
 
167
- // File selector methods
168
166
  const activateFileSelector = useCallback((position: number) => {
169
- managerRef.current?.activateFileSelector(position);
167
+ dispatch({ type: "ACTIVATE_FILE_SELECTOR", payload: position });
170
168
  }, []);
171
169
 
172
- const handleFileSelect = useCallback(
173
- (filePath: string) => {
174
- return (
175
- managerRef.current?.handleFileSelect(filePath) || {
176
- newInput: inputText,
177
- newCursorPosition: cursorPosition,
178
- }
179
- );
180
- },
181
- [inputText, cursorPosition],
182
- );
170
+ const handleFileSelect = useCallback((filePath: string) => {
171
+ return handlers.handleFileSelect(
172
+ stateRef.current,
173
+ dispatch,
174
+ callbacksRef.current,
175
+ filePath,
176
+ );
177
+ }, []);
183
178
 
184
179
  const handleCancelFileSelect = useCallback(() => {
185
- managerRef.current?.handleCancelFileSelect();
180
+ dispatch({ type: "CANCEL_FILE_SELECTOR" });
186
181
  }, []);
187
182
 
188
183
  const updateFileSearchQuery = useCallback((query: string) => {
189
- managerRef.current?.updateFileSearchQuery(query);
184
+ dispatch({ type: "SET_FILE_SEARCH_QUERY", payload: query });
190
185
  }, []);
191
186
 
192
187
  const checkForAtDeletion = useCallback((cursorPos: number) => {
193
- return managerRef.current?.checkForAtDeletion(cursorPos) || false;
188
+ return handlers.checkForAtDeletion(stateRef.current, dispatch, cursorPos);
194
189
  }, []);
195
190
 
196
- // Command selector methods
197
191
  const activateCommandSelector = useCallback((position: number) => {
198
- managerRef.current?.activateCommandSelector(position);
192
+ dispatch({ type: "ACTIVATE_COMMAND_SELECTOR", payload: position });
199
193
  }, []);
200
194
 
201
- const handleCommandSelect = useCallback(
202
- (command: string) => {
203
- return (
204
- managerRef.current?.handleCommandSelect(command) || {
205
- newInput: inputText,
206
- newCursorPosition: cursorPosition,
207
- }
208
- );
209
- },
210
- [inputText, cursorPosition],
211
- );
195
+ const handleCommandSelect = useCallback((command: string) => {
196
+ return handlers.handleCommandSelect(
197
+ stateRef.current,
198
+ dispatch,
199
+ callbacksRef.current,
200
+ command,
201
+ );
202
+ }, []);
212
203
 
213
- const handleCommandInsert = useCallback(
214
- (command: string) => {
215
- return (
216
- managerRef.current?.handleCommandInsert(command) || {
217
- newInput: inputText,
218
- newCursorPosition: cursorPosition,
219
- }
204
+ const handleCommandInsert = useCallback((command: string) => {
205
+ const currentState = stateRef.current;
206
+ if (currentState.slashPosition >= 0) {
207
+ const beforeSlash = currentState.inputText.substring(
208
+ 0,
209
+ currentState.slashPosition,
220
210
  );
221
- },
222
- [inputText, cursorPosition],
223
- );
211
+ const afterQuery = currentState.inputText.substring(
212
+ currentState.cursorPosition,
213
+ );
214
+ const newInput = beforeSlash + `/${command} ` + afterQuery;
215
+ const newCursorPosition = beforeSlash.length + command.length + 2;
216
+
217
+ dispatch({ type: "SET_INPUT_TEXT", payload: newInput });
218
+ dispatch({ type: "SET_CURSOR_POSITION", payload: newCursorPosition });
219
+ dispatch({ type: "CANCEL_COMMAND_SELECTOR" });
220
+
221
+ callbacksRef.current.onInputTextChange?.(newInput);
222
+ callbacksRef.current.onCursorPositionChange?.(newCursorPosition);
223
+
224
+ return { newInput, newCursorPosition };
225
+ }
226
+ return {
227
+ newInput: currentState.inputText,
228
+ newCursorPosition: currentState.cursorPosition,
229
+ };
230
+ }, []);
224
231
 
225
232
  const handleCancelCommandSelect = useCallback(() => {
226
- managerRef.current?.handleCancelCommandSelect();
233
+ dispatch({ type: "CANCEL_COMMAND_SELECTOR" });
227
234
  }, []);
228
235
 
229
236
  const updateCommandSearchQuery = useCallback((query: string) => {
230
- managerRef.current?.updateCommandSearchQuery(query);
237
+ dispatch({ type: "SET_COMMAND_SEARCH_QUERY", payload: query });
231
238
  }, []);
232
239
 
233
240
  const checkForSlashDeletion = useCallback((cursorPos: number) => {
234
- return managerRef.current?.checkForSlashDeletion(cursorPos) || false;
241
+ return handlers.checkForSlashDeletion(
242
+ stateRef.current,
243
+ dispatch,
244
+ cursorPos,
245
+ );
235
246
  }, []);
236
247
 
237
- // History search methods
238
248
  const handleHistorySearchSelect = useCallback((prompt: string) => {
239
- managerRef.current?.handleHistorySearchSelect(prompt);
249
+ dispatch({ type: "SET_INPUT_TEXT", payload: prompt });
250
+ dispatch({ type: "SET_CURSOR_POSITION", payload: prompt.length });
251
+ dispatch({ type: "CANCEL_HISTORY_SEARCH" });
240
252
  }, []);
241
253
 
242
254
  const handleCancelHistorySearch = useCallback(() => {
243
- managerRef.current?.handleCancelHistorySearch();
255
+ dispatch({ type: "CANCEL_HISTORY_SEARCH" });
244
256
  }, []);
245
257
 
246
- // Special character handling
247
258
  const handleSpecialCharInput = useCallback((char: string) => {
248
- managerRef.current?.handleSpecialCharInput(char);
259
+ handlers.handleSpecialCharInput(
260
+ stateRef.current,
261
+ dispatch,
262
+ char,
263
+ stateRef.current.cursorPosition,
264
+ stateRef.current.inputText,
265
+ );
266
+ }, []);
267
+
268
+ const setInputText = useCallback((text: string) => {
269
+ dispatch({ type: "SET_INPUT_TEXT", payload: text });
270
+ }, []);
271
+
272
+ const setCursorPosition = useCallback((position: number) => {
273
+ dispatch({ type: "SET_CURSOR_POSITION", payload: position });
274
+ }, []);
275
+
276
+ const setShowBackgroundTaskManager = useCallback((show: boolean) => {
277
+ dispatch({ type: "SET_SHOW_BACKGROUND_TASK_MANAGER", payload: show });
278
+ }, []);
279
+
280
+ const setShowMcpManager = useCallback((show: boolean) => {
281
+ dispatch({ type: "SET_SHOW_MCP_MANAGER", payload: show });
282
+ }, []);
283
+
284
+ const setShowRewindManager = useCallback((show: boolean) => {
285
+ dispatch({ type: "SET_SHOW_REWIND_MANAGER", payload: show });
286
+ }, []);
287
+
288
+ const setShowHelp = useCallback((show: boolean) => {
289
+ dispatch({ type: "SET_SHOW_HELP", payload: show });
290
+ }, []);
291
+
292
+ const setShowStatusCommand = useCallback((show: boolean) => {
293
+ dispatch({ type: "SET_SHOW_STATUS_COMMAND", payload: show });
294
+ }, []);
295
+
296
+ const setPermissionMode = useCallback((mode: PermissionMode) => {
297
+ dispatch({ type: "SET_PERMISSION_MODE", payload: mode });
298
+ callbacksRef.current.onPermissionModeChange?.(mode);
299
+ }, []);
300
+
301
+ const addImage = useCallback((imagePath: string, mimeType: string) => {
302
+ dispatch({ type: "ADD_IMAGE", payload: { path: imagePath, mimeType } });
303
+ }, []);
304
+
305
+ const removeImage = useCallback((imageId: number) => {
306
+ dispatch({ type: "REMOVE_IMAGE", payload: imageId });
249
307
  }, []);
250
308
 
251
- // Direct state access methods (for compatibility with existing code)
252
- const setInputTextDirect = useCallback((text: string) => {
253
- managerRef.current?.setInputText(text);
309
+ const clearImages = useCallback(() => {
310
+ dispatch({ type: "CLEAR_IMAGES" });
254
311
  }, []);
255
312
 
256
- const setCursorPositionDirect = useCallback((position: number) => {
257
- managerRef.current?.setCursorPosition(position);
313
+ const handlePasteImage = useCallback(async () => {
314
+ return await handlers.handlePasteImage(dispatch);
258
315
  }, []);
259
316
 
260
- // Complex handlers that combine multiple operations
317
+ const handlePasteInput = useCallback((input: string) => {
318
+ handlers.handlePasteInput(
319
+ stateRef.current,
320
+ dispatch,
321
+ callbacksRef.current,
322
+ input,
323
+ );
324
+ }, []);
325
+
326
+ const handleSubmit = useCallback(
327
+ async (
328
+ attachedImages: Array<{ id: number; path: string; mimeType: string }>,
329
+ isLoading: boolean = false,
330
+ isCommandRunning: boolean = false,
331
+ ) => {
332
+ await handlers.handleSubmit(
333
+ stateRef.current,
334
+ dispatch,
335
+ callbacksRef.current,
336
+ isLoading,
337
+ isCommandRunning,
338
+ attachedImages,
339
+ );
340
+ },
341
+ [],
342
+ );
343
+
344
+ const expandLongTextPlaceholders = useCallback((text: string) => {
345
+ return handlers.expandLongTextPlaceholders(
346
+ text,
347
+ stateRef.current.longTextMap,
348
+ );
349
+ }, []);
350
+
351
+ const clearLongTextMap = useCallback(() => {
352
+ dispatch({ type: "CLEAR_LONG_TEXT_MAP" });
353
+ }, []);
354
+
355
+ const handleInput = useCallback(
356
+ async (
357
+ input: string,
358
+ key: Key,
359
+ attachedImages: Array<{ id: number; path: string; mimeType: string }>,
360
+ isLoading: boolean = false,
361
+ isCommandRunning: boolean = false,
362
+ clearImages?: () => void,
363
+ ) => {
364
+ return await handlers.handleInput(
365
+ stateRef.current,
366
+ dispatch,
367
+ callbacksRef.current,
368
+ input,
369
+ key,
370
+ isLoading,
371
+ isCommandRunning,
372
+ clearImages,
373
+ );
374
+ },
375
+ [],
376
+ );
377
+
261
378
  return {
262
379
  // State
263
- inputText,
264
- cursorPosition,
265
- showFileSelector: fileSelectorState.show,
266
- filteredFiles: fileSelectorState.files,
267
- fileSearchQuery: fileSelectorState.query,
268
- atPosition: fileSelectorState.position,
269
- showCommandSelector: commandSelectorState.show,
270
- commandSearchQuery: commandSelectorState.query,
271
- slashPosition: commandSelectorState.position,
272
- showHistorySearch: historySearchState.show,
273
- historySearchQuery: historySearchState.query,
274
- showBackgroundTaskManager,
275
- showMcpManager,
276
- showRewindManager,
277
- showHelp,
278
- showStatusCommand,
279
- permissionMode,
280
- attachedImages,
281
- isManagerReady,
380
+ inputText: state.inputText,
381
+ cursorPosition: state.cursorPosition,
382
+ showFileSelector: state.showFileSelector,
383
+ filteredFiles: state.filteredFiles,
384
+ fileSearchQuery: state.fileSearchQuery,
385
+ atPosition: state.atPosition,
386
+ showCommandSelector: state.showCommandSelector,
387
+ commandSearchQuery: state.commandSearchQuery,
388
+ slashPosition: state.slashPosition,
389
+ showHistorySearch: state.showHistorySearch,
390
+ historySearchQuery: state.historySearchQuery,
391
+ showBackgroundTaskManager: state.showBackgroundTaskManager,
392
+ showMcpManager: state.showMcpManager,
393
+ showRewindManager: state.showRewindManager,
394
+ showHelp: state.showHelp,
395
+ showStatusCommand: state.showStatusCommand,
396
+ permissionMode: state.permissionMode,
397
+ attachedImages: state.attachedImages,
398
+ isManagerReady: true,
282
399
 
283
400
  // Methods
284
401
  insertTextAtCursor,
@@ -310,97 +427,33 @@ export const useInputManager = (
310
427
  handleSpecialCharInput,
311
428
 
312
429
  // Bash/MCP Manager
313
- setShowBackgroundTaskManager: useCallback((show: boolean) => {
314
- managerRef.current?.setShowBackgroundTaskManager(show);
315
- }, []),
316
- setShowMcpManager: useCallback((show: boolean) => {
317
- managerRef.current?.setShowMcpManager(show);
318
- }, []),
319
- setShowRewindManager: useCallback((show: boolean) => {
320
- managerRef.current?.setShowRewindManager(show);
321
- setShowRewindManager(show);
322
- }, []),
323
- setShowHelp: useCallback((show: boolean) => {
324
- managerRef.current?.setShowHelp(show);
325
- setShowHelp(show);
326
- }, []),
327
- setShowStatusCommand: useCallback((show: boolean) => {
328
- managerRef.current?.setShowStatusCommand(show);
329
- setShowStatusCommand(show);
330
- }, []),
331
- setPermissionMode: useCallback((mode: PermissionMode) => {
332
- setPermissionModeState(mode);
333
- managerRef.current?.setPermissionMode(mode);
334
- }, []),
430
+ setShowBackgroundTaskManager,
431
+ setShowMcpManager,
432
+ setShowRewindManager,
433
+ setShowHelp,
434
+ setShowStatusCommand,
435
+ setPermissionMode,
335
436
 
336
437
  // Image management
337
- addImage: useCallback((imagePath: string, mimeType: string) => {
338
- return managerRef.current?.addImage(imagePath, mimeType);
339
- }, []),
340
- removeImage: useCallback((imageId: number) => {
341
- managerRef.current?.removeImage(imageId);
342
- }, []),
343
- clearImages: useCallback(() => {
344
- managerRef.current?.clearImages();
345
- }, []),
346
- handlePasteImage: useCallback(async () => {
347
- return (await managerRef.current?.handlePasteImage()) || false;
348
- }, []),
438
+ addImage,
439
+ removeImage,
440
+ clearImages,
441
+ handlePasteImage,
349
442
 
350
443
  // Paste and text handling
351
- handlePasteInput: useCallback((input: string) => {
352
- managerRef.current?.handlePasteInput(input);
353
- }, []),
354
- handleSubmit: useCallback(
355
- async (
356
- attachedImages: Array<{ id: number; path: string; mimeType: string }>,
357
- isLoading: boolean = false,
358
- isCommandRunning: boolean = false,
359
- ) => {
360
- await managerRef.current?.handleSubmit(
361
- attachedImages,
362
- isLoading,
363
- isCommandRunning,
364
- );
365
- },
366
- [],
367
- ),
368
- expandLongTextPlaceholders: useCallback((text: string) => {
369
- return managerRef.current?.expandLongTextPlaceholders(text) || text;
370
- }, []),
371
- clearLongTextMap: useCallback(() => {
372
- managerRef.current?.clearLongTextMap();
373
- }, []),
444
+ handlePasteInput,
445
+ handleSubmit,
446
+ expandLongTextPlaceholders,
447
+ clearLongTextMap,
374
448
 
375
449
  // Main input handler
376
- handleInput: useCallback(
377
- async (
378
- input: string,
379
- key: Key,
380
- attachedImages: Array<{ id: number; path: string; mimeType: string }>,
381
- isLoading: boolean = false,
382
- isCommandRunning: boolean = false,
383
- clearImages?: () => void,
384
- ) => {
385
- return (
386
- (await managerRef.current?.handleInput(
387
- input,
388
- key,
389
- attachedImages,
390
- isLoading,
391
- isCommandRunning,
392
- clearImages,
393
- )) || false
394
- );
395
- },
396
- [],
397
- ),
450
+ handleInput,
398
451
 
399
- // Direct state setters (for React compatibility)
400
- setInputText: setInputTextDirect,
401
- setCursorPosition: setCursorPositionDirect,
452
+ // Direct state setters
453
+ setInputText,
454
+ setCursorPosition,
402
455
 
403
- // Manager reference for advanced usage
404
- manager: managerRef.current,
456
+ // Manager reference (for compatibility, though it's null now)
457
+ manager: null,
405
458
  };
406
459
  };