wave-code 0.11.6 → 0.12.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 (70) hide show
  1. package/dist/acp/agent.d.ts.map +1 -1
  2. package/dist/acp/agent.js +9 -0
  3. package/dist/commands/update.d.ts +2 -0
  4. package/dist/commands/update.d.ts.map +1 -0
  5. package/dist/commands/update.js +97 -0
  6. package/dist/components/App.js +1 -1
  7. package/dist/components/BtwDisplay.d.ts +8 -0
  8. package/dist/components/BtwDisplay.d.ts.map +1 -0
  9. package/dist/components/BtwDisplay.js +9 -0
  10. package/dist/components/ChatInterface.d.ts.map +1 -1
  11. package/dist/components/ChatInterface.js +3 -5
  12. package/dist/components/ConfirmationDetails.d.ts.map +1 -1
  13. package/dist/components/ConfirmationDetails.js +7 -1
  14. package/dist/components/InputBox.d.ts.map +1 -1
  15. package/dist/components/InputBox.js +18 -4
  16. package/dist/components/MessageBlockItem.d.ts.map +1 -1
  17. package/dist/components/MessageBlockItem.js +2 -1
  18. package/dist/components/MessageList.d.ts +1 -2
  19. package/dist/components/MessageList.d.ts.map +1 -1
  20. package/dist/components/MessageList.js +9 -6
  21. package/dist/components/ModelSelector.d.ts +9 -0
  22. package/dist/components/ModelSelector.d.ts.map +1 -0
  23. package/dist/components/ModelSelector.js +34 -0
  24. package/dist/components/RewindCommand.js +2 -2
  25. package/dist/components/SlashDisplay.d.ts +9 -0
  26. package/dist/components/SlashDisplay.d.ts.map +1 -0
  27. package/dist/components/SlashDisplay.js +20 -0
  28. package/dist/components/StatusLine.d.ts +8 -0
  29. package/dist/components/StatusLine.d.ts.map +1 -0
  30. package/dist/components/StatusLine.js +5 -0
  31. package/dist/constants/commands.d.ts.map +1 -1
  32. package/dist/constants/commands.js +12 -0
  33. package/dist/contexts/useChat.d.ts +8 -0
  34. package/dist/contexts/useChat.d.ts.map +1 -1
  35. package/dist/contexts/useChat.js +61 -1
  36. package/dist/hooks/useInputManager.d.ts +5 -0
  37. package/dist/hooks/useInputManager.d.ts.map +1 -1
  38. package/dist/hooks/useInputManager.js +58 -0
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +4 -0
  41. package/dist/managers/inputHandlers.d.ts +1 -1
  42. package/dist/managers/inputHandlers.d.ts.map +1 -1
  43. package/dist/managers/inputHandlers.js +74 -5
  44. package/dist/managers/inputReducer.d.ts +22 -0
  45. package/dist/managers/inputReducer.d.ts.map +1 -1
  46. package/dist/managers/inputReducer.js +23 -0
  47. package/dist/utils/version.d.ts +2 -0
  48. package/dist/utils/version.d.ts.map +1 -0
  49. package/dist/utils/version.js +4 -0
  50. package/package.json +4 -2
  51. package/src/acp/agent.ts +10 -0
  52. package/src/commands/update.ts +116 -0
  53. package/src/components/App.tsx +1 -1
  54. package/src/components/BtwDisplay.tsx +33 -0
  55. package/src/components/ChatInterface.tsx +25 -29
  56. package/src/components/ConfirmationDetails.tsx +14 -0
  57. package/src/components/InputBox.tsx +47 -17
  58. package/src/components/MessageBlockItem.tsx +5 -5
  59. package/src/components/MessageList.tsx +9 -10
  60. package/src/components/ModelSelector.tsx +109 -0
  61. package/src/components/RewindCommand.tsx +2 -2
  62. package/src/components/SlashDisplay.tsx +70 -0
  63. package/src/components/StatusLine.tsx +36 -0
  64. package/src/constants/commands.ts +12 -0
  65. package/src/contexts/useChat.tsx +82 -1
  66. package/src/hooks/useInputManager.ts +69 -0
  67. package/src/index.ts +9 -0
  68. package/src/managers/inputHandlers.ts +92 -4
  69. package/src/managers/inputReducer.ts +41 -1
  70. package/src/utils/version.ts +8 -0
@@ -0,0 +1,70 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+ import type { SlashBlock } from "wave-agent-sdk";
4
+
5
+ interface SlashDisplayProps {
6
+ block: SlashBlock;
7
+ isExpanded?: boolean;
8
+ }
9
+
10
+ export const SlashDisplay: React.FC<SlashDisplayProps> = ({
11
+ block,
12
+ isExpanded = false,
13
+ }) => {
14
+ const { command, args, stage, shortResult, error, result } = block;
15
+
16
+ const getStatusColor = () => {
17
+ switch (stage) {
18
+ case "running":
19
+ return "yellow";
20
+ case "success":
21
+ return "green";
22
+ case "error":
23
+ return "red";
24
+ case "aborted":
25
+ return "gray";
26
+ default:
27
+ return "white";
28
+ }
29
+ };
30
+
31
+ return (
32
+ <Box flexDirection="column">
33
+ <Box>
34
+ <Text color={getStatusColor()}>/ </Text>
35
+ <Text color="white">{command}</Text>
36
+ {args && <Text color="gray"> {args}</Text>}
37
+ </Box>
38
+
39
+ {/* Display shortResult in collapsed state */}
40
+ {!isExpanded && shortResult && !error && (
41
+ <Box paddingLeft={2} flexDirection="column">
42
+ {shortResult.split("\n").map((line, index) => (
43
+ <Text key={index} color="gray">
44
+ {line}
45
+ </Text>
46
+ ))}
47
+ </Box>
48
+ )}
49
+
50
+ {/* Display complete result in expanded state */}
51
+ {isExpanded && result && (
52
+ <Box paddingLeft={2} flexDirection="column">
53
+ <Text color="cyan" bold>
54
+ Result:
55
+ </Text>
56
+ <Text color="white">{result}</Text>
57
+ </Box>
58
+ )}
59
+
60
+ {/* Error information always displayed */}
61
+ {error && (
62
+ <Box paddingLeft={2}>
63
+ <Text color="red">
64
+ Error: {typeof error === "string" ? error : String(error)}
65
+ </Text>
66
+ </Box>
67
+ )}
68
+ </Box>
69
+ );
70
+ };
@@ -0,0 +1,36 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+
4
+ export interface StatusLineProps {
5
+ permissionMode: string;
6
+ isShellCommand: boolean;
7
+ isBtwActive: boolean;
8
+ }
9
+
10
+ export const StatusLine: React.FC<StatusLineProps> = ({
11
+ permissionMode,
12
+ isShellCommand,
13
+ isBtwActive,
14
+ }) => {
15
+ return (
16
+ <Box paddingRight={1} justifyContent="space-between" width="100%">
17
+ {isBtwActive ? (
18
+ <Text color="gray">
19
+ Mode: <Text color="cyan">BTW</Text> (ESC to dismiss)
20
+ </Text>
21
+ ) : isShellCommand ? (
22
+ <Text color="gray">
23
+ Shell: <Text color="yellow">Run shell command</Text>
24
+ </Text>
25
+ ) : (
26
+ <Text color="gray">
27
+ Mode:{" "}
28
+ <Text color={permissionMode === "plan" ? "yellow" : "cyan"}>
29
+ {permissionMode}
30
+ </Text>{" "}
31
+ (Shift+Tab to cycle)
32
+ </Text>
33
+ )}
34
+ </Box>
35
+ );
36
+ };
@@ -38,4 +38,16 @@ export const AVAILABLE_COMMANDS: SlashCommand[] = [
38
38
  description: "View and manage plugins",
39
39
  handler: () => {}, // Handler here won't be used, actual processing is in the hook
40
40
  },
41
+ {
42
+ id: "btw",
43
+ name: "btw",
44
+ description: "Ask a side question without tool use",
45
+ handler: () => {}, // Handler here won't be used, actual processing is in the hook
46
+ },
47
+ {
48
+ id: "model",
49
+ name: "model",
50
+ description: "Switch between configured AI models",
51
+ handler: () => {}, // Handler here won't be used, actual processing is in the hook
52
+ },
41
53
  ];
@@ -51,8 +51,14 @@ export interface ChatContextType {
51
51
  images?: Array<{ path: string; mimeType: string }>,
52
52
  longTextMap?: Record<string, string>,
53
53
  ) => Promise<void>;
54
+ askBtw: (question: string) => Promise<string>;
54
55
  abortMessage: () => void;
55
56
  latestTotalTokens: number;
57
+ // Model functionality
58
+ currentModel: string;
59
+ configuredModels: string[];
60
+ getConfiguredModels: () => string[];
61
+ setModel: (model: string) => void;
56
62
  // MCP functionality
57
63
  mcpServers: McpServerStatus[];
58
64
  connectMcpServer: (serverName: string) => Promise<boolean>;
@@ -77,6 +83,7 @@ export interface ChatContextType {
77
83
  // Permission functionality
78
84
  permissionMode: PermissionMode;
79
85
  setPermissionMode: (mode: PermissionMode) => void;
86
+ allowBypassInCycle: boolean;
80
87
  // Permission confirmation state
81
88
  isConfirmationVisible: boolean;
82
89
  confirmingTool?: {
@@ -113,6 +120,10 @@ export interface ChatContextType {
113
120
  workingDirectory: string;
114
121
  version?: string;
115
122
  workdir?: string;
123
+ btwState: import("../managers/inputReducer.js").BtwState;
124
+ setBtwState: (
125
+ payload: Partial<import("../managers/inputReducer.js").BtwState>,
126
+ ) => void;
116
127
  }
117
128
 
118
129
  const ChatContext = createContext<ChatContextType | null>(null);
@@ -170,6 +181,8 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
170
181
  const [sessionId, setSessionId] = useState("");
171
182
  const [isCommandRunning, setIsCommandRunning] = useState(false);
172
183
  const [isCompressing, setIsCompressing] = useState(false);
184
+ const [currentModel, setCurrentModelState] = useState("");
185
+ const [configuredModels, setConfiguredModels] = useState<string[]>([]);
173
186
 
174
187
  // MCP State
175
188
  const [mcpServers, setMcpServers] = useState<McpServerStatus[]>([]);
@@ -235,8 +248,32 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
235
248
  // Status metadata state
236
249
  const [workingDirectory, setWorkingDirectory] = useState("");
237
250
 
251
+ // /btw state
252
+ const [btwState, setBtwStateInternal] = useState<
253
+ import("../managers/inputReducer.js").BtwState
254
+ >({
255
+ isActive: false,
256
+ question: "",
257
+ isLoading: false,
258
+ });
259
+
260
+ const setBtwState = useCallback(
261
+ (payload: Partial<import("../managers/inputReducer.js").BtwState>) => {
262
+ setBtwStateInternal((prev) => {
263
+ const newState = { ...prev, ...payload };
264
+ if (process.env.NODE_ENV === "test") {
265
+ // console.log("setBtwState", newState);
266
+ }
267
+ return newState;
268
+ });
269
+ },
270
+ [],
271
+ );
272
+
238
273
  // Confirmation too tall state
239
274
  const [wasLastDetailsTooTall, setWasLastDetailsTooTall] = useState(0);
275
+ const allowBypassInCycle =
276
+ !!bypassPermissions || initialPermissionMode === "bypassPermissions";
240
277
 
241
278
  const agentRef = useRef<Agent | null>(null);
242
279
  const taskUpdateTimerRef = useRef<NodeJS.Timeout | null>(null);
@@ -327,6 +364,12 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
327
364
  onPermissionModeChange: (mode) => {
328
365
  setPermissionModeState(mode);
329
366
  },
367
+ onModelChange: (model) => {
368
+ setCurrentModelState(model);
369
+ },
370
+ onConfiguredModelsChange: (models) => {
371
+ setConfiguredModels(models);
372
+ },
330
373
  };
331
374
 
332
375
  try {
@@ -384,6 +427,8 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
384
427
  setIsCompressing(agent.isCompressing);
385
428
  setPermissionModeState(agent.getPermissionMode());
386
429
  setWorkingDirectory(agent.workingDirectory);
430
+ setCurrentModelState(agent.getModelConfig().model);
431
+ setConfiguredModels(agent.getConfiguredModels());
387
432
 
388
433
  // Get initial MCP servers state
389
434
  const mcpServers = agent.getMcpServers?.() || [];
@@ -497,6 +542,13 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
497
542
  [isLoading, isCommandRunning],
498
543
  );
499
544
 
545
+ const askBtw = useCallback(async (question: string) => {
546
+ if (!agentRef.current) {
547
+ throw new Error("Agent not initialized");
548
+ }
549
+ return await agentRef.current.askBtw(question);
550
+ }, []);
551
+
500
552
  // Process queued messages when idle
501
553
  useEffect(() => {
502
554
  if (!isLoading && !isCommandRunning && queuedMessages.length > 0) {
@@ -635,6 +687,20 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
635
687
  return agentRef.current.getModelConfig();
636
688
  }, []);
637
689
 
690
+ const getConfiguredModels = useCallback(() => {
691
+ if (!agentRef.current) {
692
+ return [];
693
+ }
694
+ return agentRef.current.getConfiguredModels();
695
+ }, []);
696
+
697
+ const setModel = useCallback((model: string) => {
698
+ if (agentRef.current) {
699
+ agentRef.current.setModel(model);
700
+ setCurrentModelState(model);
701
+ }
702
+ }, []);
703
+
638
704
  // Listen for Ctrl+O hotkey to toggle collapse/expand state and ESC to cancel confirmation
639
705
  useInput((input, key) => {
640
706
  if (key.ctrl && input === "o") {
@@ -664,10 +730,17 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
664
730
  setIsTaskListVisible((prev) => !prev);
665
731
  }
666
732
 
667
- // Handle ESC key to cancel confirmation
733
+ // Handle ESC key to cancel confirmation or dismiss BTW
668
734
  if (key.escape) {
669
735
  if (isConfirmationVisible) {
670
736
  handleConfirmationCancel();
737
+ } else if (btwState.isActive) {
738
+ setBtwState({
739
+ isActive: false,
740
+ question: "",
741
+ answer: undefined,
742
+ isLoading: false,
743
+ });
671
744
  }
672
745
  }
673
746
  });
@@ -682,8 +755,13 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
682
755
  queuedMessages,
683
756
  sessionId,
684
757
  sendMessage,
758
+ askBtw,
685
759
  abortMessage,
686
760
  latestTotalTokens,
761
+ currentModel,
762
+ configuredModels,
763
+ getConfiguredModels,
764
+ setModel,
687
765
  isCompressing,
688
766
  mcpServers,
689
767
  connectMcpServer,
@@ -698,6 +776,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
698
776
  subagentLatestTokens,
699
777
  permissionMode,
700
778
  setPermissionMode,
779
+ allowBypassInCycle,
701
780
  isConfirmationVisible,
702
781
  confirmingTool,
703
782
  showConfirmation,
@@ -715,6 +794,8 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
715
794
  workingDirectory,
716
795
  version,
717
796
  workdir,
797
+ btwState,
798
+ setBtwState,
718
799
  };
719
800
 
720
801
  return (
@@ -149,10 +149,55 @@ export const useInputManager = (
149
149
  callbacksRef.current.onPluginManagerStateChange?.(state.showPluginManager);
150
150
  }, [state.showPluginManager]);
151
151
 
152
+ useEffect(() => {
153
+ callbacksRef.current.onModelSelectorStateChange?.(state.showModelSelector);
154
+ }, [state.showModelSelector]);
155
+
152
156
  useEffect(() => {
153
157
  callbacksRef.current.onImagesStateChange?.(state.attachedImages);
154
158
  }, [state.attachedImages]);
155
159
 
160
+ useEffect(() => {
161
+ if (callbacksRef.current.onBtwStateChange) {
162
+ callbacksRef.current.onBtwStateChange(state.btwState);
163
+ }
164
+ }, [state.btwState]);
165
+
166
+ // Handle /btw side question
167
+ useEffect(() => {
168
+ if (
169
+ state.btwState.isActive &&
170
+ state.btwState.isLoading &&
171
+ state.btwState.question
172
+ ) {
173
+ const askBtw = async () => {
174
+ try {
175
+ const answer = await callbacksRef.current.onAskBtw?.(
176
+ state.btwState.question,
177
+ );
178
+ dispatch({
179
+ type: "SET_BTW_STATE",
180
+ payload: { answer, isLoading: false },
181
+ });
182
+ } catch (error) {
183
+ console.error("Failed to ask side question:", error);
184
+ dispatch({
185
+ type: "SET_BTW_STATE",
186
+ payload: {
187
+ answer: "Error: Failed to get an answer for your side question.",
188
+ isLoading: false,
189
+ },
190
+ });
191
+ }
192
+ };
193
+ askBtw();
194
+ }
195
+ }, [
196
+ state.btwState.isActive,
197
+ state.btwState.isLoading,
198
+ state.btwState.question,
199
+ ]);
200
+
156
201
  // Methods
157
202
  const insertTextAtCursor = useCallback((text: string) => {
158
203
  dispatch({ type: "INSERT_TEXT", payload: text });
@@ -302,11 +347,30 @@ export const useInputManager = (
302
347
  dispatch({ type: "SET_SHOW_PLUGIN_MANAGER", payload: show });
303
348
  }, []);
304
349
 
350
+ const setShowModelSelector = useCallback((show: boolean) => {
351
+ dispatch({ type: "SET_SHOW_MODEL_SELECTOR", payload: show });
352
+ }, []);
353
+
305
354
  const setPermissionMode = useCallback((mode: PermissionMode) => {
306
355
  dispatch({ type: "SET_PERMISSION_MODE", payload: mode });
307
356
  callbacksRef.current.onPermissionModeChange?.(mode);
308
357
  }, []);
309
358
 
359
+ const setAllowBypassInCycle = useCallback((allow: boolean) => {
360
+ dispatch({ type: "SET_ALLOW_BYPASS_IN_CYCLE", payload: allow });
361
+ }, []);
362
+
363
+ const setBtwState = useCallback(
364
+ (payload: Partial<import("../managers/inputReducer.js").BtwState>) => {
365
+ if (callbacksRef.current.onBtwStateChange) {
366
+ callbacksRef.current.onBtwStateChange(payload);
367
+ } else {
368
+ dispatch({ type: "SET_BTW_STATE", payload });
369
+ }
370
+ },
371
+ [],
372
+ );
373
+
310
374
  const addImage = useCallback((imagePath: string, mimeType: string) => {
311
375
  dispatch({ type: "ADD_IMAGE", payload: { path: imagePath, mimeType } });
312
376
  }, []);
@@ -396,8 +460,10 @@ export const useInputManager = (
396
460
  showHelp: state.showHelp,
397
461
  showStatusCommand: state.showStatusCommand,
398
462
  showPluginManager: state.showPluginManager,
463
+ showModelSelector: state.showModelSelector,
399
464
  permissionMode: state.permissionMode,
400
465
  attachedImages: state.attachedImages,
466
+ btwState: state.btwState,
401
467
  isManagerReady: true,
402
468
 
403
469
  // Methods
@@ -436,7 +502,10 @@ export const useInputManager = (
436
502
  setShowHelp,
437
503
  setShowStatusCommand,
438
504
  setShowPluginManager,
505
+ setShowModelSelector,
439
506
  setPermissionMode,
507
+ setAllowBypassInCycle,
508
+ setBtwState,
440
509
 
441
510
  // Image management
442
511
  addImage,
package/src/index.ts CHANGED
@@ -228,6 +228,15 @@ export async function main() {
228
228
  },
229
229
  );
230
230
  })
231
+ .command(
232
+ "update",
233
+ "Update WAVE Code to the latest version",
234
+ {},
235
+ async () => {
236
+ const { updateCommand } = await import("./commands/update.js");
237
+ await updateCommand();
238
+ },
239
+ )
231
240
  .version()
232
241
  .alias("v", "version")
233
242
  .example("$0", "Start CLI with default settings")
@@ -55,6 +55,30 @@ export const handleSubmit = async (
55
55
  .replace(imageRegex, "")
56
56
  .trim();
57
57
 
58
+ if (
59
+ contentWithPlaceholders === "/btw" ||
60
+ contentWithPlaceholders.startsWith("/btw ")
61
+ ) {
62
+ const question = contentWithPlaceholders.startsWith("/btw ")
63
+ ? contentWithPlaceholders.substring(5).trim()
64
+ : "";
65
+
66
+ const payload = {
67
+ isActive: true,
68
+ question,
69
+ isLoading: question !== "",
70
+ };
71
+
72
+ dispatch({
73
+ type: "SET_BTW_STATE",
74
+ payload,
75
+ });
76
+ dispatch({ type: "CLEAR_INPUT" });
77
+ dispatch({ type: "RESET_HISTORY_NAVIGATION" });
78
+ dispatch({ type: "CLEAR_LONG_TEXT_MAP" });
79
+ return;
80
+ }
81
+
58
82
  PromptHistoryManager.addEntry(
59
83
  contentWithPlaceholders,
60
84
  callbacks.sessionId,
@@ -100,8 +124,12 @@ export const cyclePermissionMode = (
100
124
  currentMode: PermissionMode,
101
125
  dispatch: React.Dispatch<InputAction>,
102
126
  callbacks: Partial<InputManagerCallbacks>,
127
+ allowBypassInCycle: boolean = false,
103
128
  ) => {
104
129
  const modes: PermissionMode[] = ["default", "acceptEdits", "plan"];
130
+ if (allowBypassInCycle) {
131
+ modes.push("bypassPermissions");
132
+ }
105
133
  const currentIndex = modes.indexOf(currentMode);
106
134
  const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % modes.length;
107
135
  const nextMode = modes[nextIndex];
@@ -342,6 +370,13 @@ export const handleCommandSelect = (
342
370
  dispatch({ type: "SET_SHOW_STATUS_COMMAND", payload: true });
343
371
  } else if (command === "plugin") {
344
372
  dispatch({ type: "SET_SHOW_PLUGIN_MANAGER", payload: true });
373
+ } else if (command === "model") {
374
+ dispatch({ type: "SET_SHOW_MODEL_SELECTOR", payload: true });
375
+ } else if (command === "btw") {
376
+ dispatch({
377
+ type: "SET_BTW_STATE",
378
+ payload: { isActive: true, question: "", isLoading: false },
379
+ });
345
380
  }
346
381
  }
347
382
  })();
@@ -461,8 +496,10 @@ export const handleSelectorInput = (
461
496
  if (input === " ") {
462
497
  if (state.showFileSelector) {
463
498
  dispatch({ type: "CANCEL_FILE_SELECTOR" });
499
+ return false;
464
500
  } else if (state.showCommandSelector) {
465
501
  dispatch({ type: "CANCEL_COMMAND_SELECTOR" });
502
+ return false;
466
503
  }
467
504
  }
468
505
 
@@ -667,6 +704,46 @@ export const handleInput = async (
667
704
  return true;
668
705
  }
669
706
 
707
+ if (state.btwState.isActive) {
708
+ if (key.escape) {
709
+ dispatch({
710
+ type: "SET_BTW_STATE",
711
+ payload: {
712
+ isActive: false,
713
+ question: "",
714
+ answer: undefined,
715
+ isLoading: false,
716
+ },
717
+ });
718
+ return true;
719
+ }
720
+
721
+ if (key.return) {
722
+ if (state.inputText.trim() && !state.btwState.isLoading) {
723
+ dispatch({
724
+ type: "SET_BTW_STATE",
725
+ payload: {
726
+ question: state.inputText.trim(),
727
+ isLoading: true,
728
+ answer: undefined,
729
+ },
730
+ });
731
+ dispatch({ type: "CLEAR_INPUT" });
732
+ }
733
+ return true;
734
+ }
735
+
736
+ // Handle normal input for the question
737
+ return await handleNormalInput(
738
+ state,
739
+ dispatch,
740
+ callbacks,
741
+ input,
742
+ key,
743
+ clearImages,
744
+ );
745
+ }
746
+
670
747
  if (key.escape) {
671
748
  if (
672
749
  !(
@@ -678,7 +755,9 @@ export const handleInput = async (
678
755
  state.showRewindManager ||
679
756
  state.showHelp ||
680
757
  state.showStatusCommand ||
681
- state.showPluginManager
758
+ state.showPluginManager ||
759
+ state.showModelSelector ||
760
+ state.btwState.isActive
682
761
  )
683
762
  ) {
684
763
  callbacks.onAbortMessage?.();
@@ -687,7 +766,12 @@ export const handleInput = async (
687
766
  }
688
767
 
689
768
  if (key.tab && key.shift) {
690
- cyclePermissionMode(state.permissionMode, dispatch, callbacks);
769
+ cyclePermissionMode(
770
+ state.permissionMode,
771
+ dispatch,
772
+ callbacks,
773
+ state.allowBypassInCycle,
774
+ );
691
775
  return true;
692
776
  }
693
777
 
@@ -700,7 +784,9 @@ export const handleInput = async (
700
784
  state.showRewindManager ||
701
785
  state.showHelp ||
702
786
  state.showStatusCommand ||
703
- state.showPluginManager
787
+ state.showPluginManager ||
788
+ state.showModelSelector ||
789
+ state.btwState.isActive
704
790
  ) {
705
791
  if (
706
792
  state.showBackgroundTaskManager ||
@@ -708,7 +794,9 @@ export const handleInput = async (
708
794
  state.showRewindManager ||
709
795
  state.showHelp ||
710
796
  state.showStatusCommand ||
711
- state.showPluginManager
797
+ state.showPluginManager ||
798
+ state.showModelSelector ||
799
+ state.btwState.isActive
712
800
  ) {
713
801
  return true;
714
802
  }