wave-code 0.11.5 → 0.11.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/acp/agent.d.ts.map +1 -1
- package/dist/acp/agent.js +9 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +97 -0
- package/dist/components/App.js +1 -1
- package/dist/components/BtwDisplay.d.ts +8 -0
- package/dist/components/BtwDisplay.d.ts.map +1 -0
- package/dist/components/BtwDisplay.js +9 -0
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +3 -4
- package/dist/components/ConfirmationDetails.d.ts.map +1 -1
- package/dist/components/ConfirmationDetails.js +7 -1
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +13 -3
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +5 -3
- package/dist/components/RewindCommand.js +2 -2
- package/dist/components/StatusLine.d.ts +8 -0
- package/dist/components/StatusLine.d.ts.map +1 -0
- package/dist/components/StatusLine.js +5 -0
- package/dist/constants/commands.d.ts.map +1 -1
- package/dist/constants/commands.js +6 -0
- package/dist/contexts/useChat.d.ts +4 -0
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +35 -1
- package/dist/hooks/useInputManager.d.ts +3 -0
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +50 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/managers/inputHandlers.d.ts +1 -1
- package/dist/managers/inputHandlers.d.ts.map +1 -1
- package/dist/managers/inputHandlers.js +68 -5
- package/dist/managers/inputReducer.d.ts +17 -0
- package/dist/managers/inputReducer.d.ts.map +1 -1
- package/dist/managers/inputReducer.js +16 -0
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +4 -0
- package/package.json +4 -2
- package/src/acp/agent.ts +10 -0
- package/src/commands/update.ts +116 -0
- package/src/components/App.tsx +1 -1
- package/src/components/BtwDisplay.tsx +33 -0
- package/src/components/ChatInterface.tsx +25 -25
- package/src/components/ConfirmationDetails.tsx +14 -0
- package/src/components/InputBox.tsx +30 -17
- package/src/components/MessageList.tsx +6 -3
- package/src/components/RewindCommand.tsx +2 -2
- package/src/components/StatusLine.tsx +36 -0
- package/src/constants/commands.ts +6 -0
- package/src/contexts/useChat.tsx +49 -1
- package/src/hooks/useInputManager.ts +59 -0
- package/src/index.ts +9 -0
- package/src/managers/inputHandlers.ts +87 -4
- package/src/managers/inputReducer.ts +31 -1
- package/src/utils/version.ts +8 -0
|
@@ -10,6 +10,7 @@ import { RewindCommand } from "./RewindCommand.js";
|
|
|
10
10
|
import { HelpView } from "./HelpView.js";
|
|
11
11
|
import { StatusCommand } from "./StatusCommand.js";
|
|
12
12
|
import { PluginManagerShell } from "./PluginManagerShell.js";
|
|
13
|
+
import { StatusLine } from "./StatusLine.js";
|
|
13
14
|
import { useInputManager } from "../hooks/useInputManager.js";
|
|
14
15
|
import { useChat } from "../contexts/useChat.js";
|
|
15
16
|
|
|
@@ -54,12 +55,16 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
54
55
|
const {
|
|
55
56
|
permissionMode: chatPermissionMode,
|
|
56
57
|
setPermissionMode: setChatPermissionMode,
|
|
58
|
+
allowBypassInCycle: chatAllowBypassInCycle,
|
|
57
59
|
handleRewindSelect,
|
|
58
60
|
backgroundCurrentTask,
|
|
59
61
|
messages,
|
|
60
62
|
getFullMessageThread,
|
|
61
63
|
sessionId,
|
|
62
64
|
workingDirectory,
|
|
65
|
+
askBtw,
|
|
66
|
+
btwState: chatBtwState,
|
|
67
|
+
setBtwState: setChatBtwState,
|
|
63
68
|
} = useChat();
|
|
64
69
|
|
|
65
70
|
// Input manager with all input state and functionality (including images)
|
|
@@ -103,12 +108,18 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
103
108
|
// Permission mode
|
|
104
109
|
permissionMode,
|
|
105
110
|
setPermissionMode,
|
|
111
|
+
setAllowBypassInCycle,
|
|
112
|
+
// BTW state
|
|
113
|
+
btwState,
|
|
106
114
|
// Main handler
|
|
107
115
|
handleInput,
|
|
108
116
|
// Manager ready state
|
|
109
117
|
isManagerReady,
|
|
110
118
|
} = useInputManager({
|
|
111
119
|
onSendMessage: sendMessage,
|
|
120
|
+
onAskBtw: askBtw,
|
|
121
|
+
btwState: chatBtwState,
|
|
122
|
+
onBtwStateChange: setChatBtwState,
|
|
112
123
|
onHasSlashCommand: hasSlashCommand,
|
|
113
124
|
onAbortMessage: abortMessage,
|
|
114
125
|
onBackgroundCurrentTask: backgroundCurrentTask,
|
|
@@ -123,6 +134,11 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
123
134
|
setPermissionMode(chatPermissionMode);
|
|
124
135
|
}, [chatPermissionMode, setPermissionMode]);
|
|
125
136
|
|
|
137
|
+
// Sync allowBypassInCycle from useChat to InputManager
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
setAllowBypassInCycle(chatAllowBypassInCycle);
|
|
140
|
+
}, [chatAllowBypassInCycle, setAllowBypassInCycle]);
|
|
141
|
+
|
|
126
142
|
// Use the InputManager's unified input handler
|
|
127
143
|
useInput(async (input, key) => {
|
|
128
144
|
await handleInput(input, key, attachedImages, clearImages);
|
|
@@ -243,12 +259,19 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
243
259
|
<Box flexDirection="column">
|
|
244
260
|
<Box
|
|
245
261
|
borderStyle="single"
|
|
246
|
-
borderColor="gray"
|
|
262
|
+
borderColor={btwState.isActive ? "cyan" : "gray"}
|
|
247
263
|
borderLeft={false}
|
|
248
264
|
borderRight={false}
|
|
249
265
|
>
|
|
250
266
|
<Text color={isPlaceholder ? "gray" : "white"}>
|
|
251
|
-
{
|
|
267
|
+
{btwState.isActive && isPlaceholder ? (
|
|
268
|
+
<>
|
|
269
|
+
<Text backgroundColor="white" color="black">
|
|
270
|
+
{" "}
|
|
271
|
+
</Text>
|
|
272
|
+
<Text color="cyan">Type your side question...</Text>
|
|
273
|
+
</>
|
|
274
|
+
) : shouldShowCursor ? (
|
|
252
275
|
<>
|
|
253
276
|
{beforeCursor}
|
|
254
277
|
<Text backgroundColor="white" color="black">
|
|
@@ -261,21 +284,11 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
261
284
|
)}
|
|
262
285
|
</Text>
|
|
263
286
|
</Box>
|
|
264
|
-
<
|
|
265
|
-
{
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
) : (
|
|
270
|
-
<Text color="gray">
|
|
271
|
-
Mode:{" "}
|
|
272
|
-
<Text color={permissionMode === "plan" ? "yellow" : "cyan"}>
|
|
273
|
-
{permissionMode}
|
|
274
|
-
</Text>{" "}
|
|
275
|
-
(Shift+Tab to cycle)
|
|
276
|
-
</Text>
|
|
277
|
-
)}
|
|
278
|
-
</Box>
|
|
287
|
+
<StatusLine
|
|
288
|
+
permissionMode={permissionMode}
|
|
289
|
+
isShellCommand={isShellCommand}
|
|
290
|
+
isBtwActive={btwState.isActive}
|
|
291
|
+
/>
|
|
279
292
|
</Box>
|
|
280
293
|
)}
|
|
281
294
|
</Box>
|
|
@@ -41,8 +41,11 @@ export const MessageList = React.memo(
|
|
|
41
41
|
// Limit messages to prevent long rendering times
|
|
42
42
|
const maxMessages = 10;
|
|
43
43
|
|
|
44
|
+
// Filter out meta messages
|
|
45
|
+
const visibleMessages = messages.filter((m) => !m.isMeta);
|
|
46
|
+
|
|
44
47
|
// Flatten messages into blocks with metadata
|
|
45
|
-
const allBlocks =
|
|
48
|
+
const allBlocks = visibleMessages.flatMap((message, messageIndex) => {
|
|
46
49
|
return message.blocks.map((block, blockIndex) => ({
|
|
47
50
|
block,
|
|
48
51
|
message,
|
|
@@ -101,8 +104,8 @@ export const MessageList = React.memo(
|
|
|
101
104
|
);
|
|
102
105
|
}
|
|
103
106
|
if (
|
|
104
|
-
|
|
105
|
-
item.messageIndex <
|
|
107
|
+
visibleMessages.length > maxMessages &&
|
|
108
|
+
item.messageIndex < visibleMessages.length - maxMessages
|
|
106
109
|
) {
|
|
107
110
|
return null;
|
|
108
111
|
}
|
|
@@ -30,10 +30,10 @@ export const RewindCommand: React.FC<RewindCommandProps> = ({
|
|
|
30
30
|
}
|
|
31
31
|
}, [getFullMessageThread]);
|
|
32
32
|
|
|
33
|
-
// Filter user messages as checkpoints
|
|
33
|
+
// Filter user messages as checkpoints, excluding meta messages
|
|
34
34
|
const checkpoints = messages
|
|
35
35
|
.map((msg, index) => ({ msg, index }))
|
|
36
|
-
.filter(({ msg }) => msg.role === "user");
|
|
36
|
+
.filter(({ msg }) => msg.role === "user" && !msg.isMeta);
|
|
37
37
|
|
|
38
38
|
const MAX_VISIBLE_ITEMS = 3;
|
|
39
39
|
const [selectedIndex, setSelectedIndex] = useState(checkpoints.length - 1);
|
|
@@ -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,10 @@ 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
|
+
},
|
|
41
47
|
];
|
package/src/contexts/useChat.tsx
CHANGED
|
@@ -51,6 +51,7 @@ 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;
|
|
56
57
|
// MCP functionality
|
|
@@ -77,6 +78,7 @@ export interface ChatContextType {
|
|
|
77
78
|
// Permission functionality
|
|
78
79
|
permissionMode: PermissionMode;
|
|
79
80
|
setPermissionMode: (mode: PermissionMode) => void;
|
|
81
|
+
allowBypassInCycle: boolean;
|
|
80
82
|
// Permission confirmation state
|
|
81
83
|
isConfirmationVisible: boolean;
|
|
82
84
|
confirmingTool?: {
|
|
@@ -113,6 +115,10 @@ export interface ChatContextType {
|
|
|
113
115
|
workingDirectory: string;
|
|
114
116
|
version?: string;
|
|
115
117
|
workdir?: string;
|
|
118
|
+
btwState: import("../managers/inputReducer.js").BtwState;
|
|
119
|
+
setBtwState: (
|
|
120
|
+
payload: Partial<import("../managers/inputReducer.js").BtwState>,
|
|
121
|
+
) => void;
|
|
116
122
|
}
|
|
117
123
|
|
|
118
124
|
const ChatContext = createContext<ChatContextType | null>(null);
|
|
@@ -235,8 +241,32 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
235
241
|
// Status metadata state
|
|
236
242
|
const [workingDirectory, setWorkingDirectory] = useState("");
|
|
237
243
|
|
|
244
|
+
// /btw state
|
|
245
|
+
const [btwState, setBtwStateInternal] = useState<
|
|
246
|
+
import("../managers/inputReducer.js").BtwState
|
|
247
|
+
>({
|
|
248
|
+
isActive: false,
|
|
249
|
+
question: "",
|
|
250
|
+
isLoading: false,
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const setBtwState = useCallback(
|
|
254
|
+
(payload: Partial<import("../managers/inputReducer.js").BtwState>) => {
|
|
255
|
+
setBtwStateInternal((prev) => {
|
|
256
|
+
const newState = { ...prev, ...payload };
|
|
257
|
+
if (process.env.NODE_ENV === "test") {
|
|
258
|
+
// console.log("setBtwState", newState);
|
|
259
|
+
}
|
|
260
|
+
return newState;
|
|
261
|
+
});
|
|
262
|
+
},
|
|
263
|
+
[],
|
|
264
|
+
);
|
|
265
|
+
|
|
238
266
|
// Confirmation too tall state
|
|
239
267
|
const [wasLastDetailsTooTall, setWasLastDetailsTooTall] = useState(0);
|
|
268
|
+
const allowBypassInCycle =
|
|
269
|
+
!!bypassPermissions || initialPermissionMode === "bypassPermissions";
|
|
240
270
|
|
|
241
271
|
const agentRef = useRef<Agent | null>(null);
|
|
242
272
|
const taskUpdateTimerRef = useRef<NodeJS.Timeout | null>(null);
|
|
@@ -497,6 +527,13 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
497
527
|
[isLoading, isCommandRunning],
|
|
498
528
|
);
|
|
499
529
|
|
|
530
|
+
const askBtw = useCallback(async (question: string) => {
|
|
531
|
+
if (!agentRef.current) {
|
|
532
|
+
throw new Error("Agent not initialized");
|
|
533
|
+
}
|
|
534
|
+
return await agentRef.current.askBtw(question);
|
|
535
|
+
}, []);
|
|
536
|
+
|
|
500
537
|
// Process queued messages when idle
|
|
501
538
|
useEffect(() => {
|
|
502
539
|
if (!isLoading && !isCommandRunning && queuedMessages.length > 0) {
|
|
@@ -664,10 +701,17 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
664
701
|
setIsTaskListVisible((prev) => !prev);
|
|
665
702
|
}
|
|
666
703
|
|
|
667
|
-
// Handle ESC key to cancel confirmation
|
|
704
|
+
// Handle ESC key to cancel confirmation or dismiss BTW
|
|
668
705
|
if (key.escape) {
|
|
669
706
|
if (isConfirmationVisible) {
|
|
670
707
|
handleConfirmationCancel();
|
|
708
|
+
} else if (btwState.isActive) {
|
|
709
|
+
setBtwState({
|
|
710
|
+
isActive: false,
|
|
711
|
+
question: "",
|
|
712
|
+
answer: undefined,
|
|
713
|
+
isLoading: false,
|
|
714
|
+
});
|
|
671
715
|
}
|
|
672
716
|
}
|
|
673
717
|
});
|
|
@@ -682,6 +726,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
682
726
|
queuedMessages,
|
|
683
727
|
sessionId,
|
|
684
728
|
sendMessage,
|
|
729
|
+
askBtw,
|
|
685
730
|
abortMessage,
|
|
686
731
|
latestTotalTokens,
|
|
687
732
|
isCompressing,
|
|
@@ -698,6 +743,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
698
743
|
subagentLatestTokens,
|
|
699
744
|
permissionMode,
|
|
700
745
|
setPermissionMode,
|
|
746
|
+
allowBypassInCycle,
|
|
701
747
|
isConfirmationVisible,
|
|
702
748
|
confirmingTool,
|
|
703
749
|
showConfirmation,
|
|
@@ -715,6 +761,8 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
715
761
|
workingDirectory,
|
|
716
762
|
version,
|
|
717
763
|
workdir,
|
|
764
|
+
btwState,
|
|
765
|
+
setBtwState,
|
|
718
766
|
};
|
|
719
767
|
|
|
720
768
|
return (
|
|
@@ -153,6 +153,47 @@ export const useInputManager = (
|
|
|
153
153
|
callbacksRef.current.onImagesStateChange?.(state.attachedImages);
|
|
154
154
|
}, [state.attachedImages]);
|
|
155
155
|
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
if (callbacksRef.current.onBtwStateChange) {
|
|
158
|
+
callbacksRef.current.onBtwStateChange(state.btwState);
|
|
159
|
+
}
|
|
160
|
+
}, [state.btwState]);
|
|
161
|
+
|
|
162
|
+
// Handle /btw side question
|
|
163
|
+
useEffect(() => {
|
|
164
|
+
if (
|
|
165
|
+
state.btwState.isActive &&
|
|
166
|
+
state.btwState.isLoading &&
|
|
167
|
+
state.btwState.question
|
|
168
|
+
) {
|
|
169
|
+
const askBtw = async () => {
|
|
170
|
+
try {
|
|
171
|
+
const answer = await callbacksRef.current.onAskBtw?.(
|
|
172
|
+
state.btwState.question,
|
|
173
|
+
);
|
|
174
|
+
dispatch({
|
|
175
|
+
type: "SET_BTW_STATE",
|
|
176
|
+
payload: { answer, isLoading: false },
|
|
177
|
+
});
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.error("Failed to ask side question:", error);
|
|
180
|
+
dispatch({
|
|
181
|
+
type: "SET_BTW_STATE",
|
|
182
|
+
payload: {
|
|
183
|
+
answer: "Error: Failed to get an answer for your side question.",
|
|
184
|
+
isLoading: false,
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
askBtw();
|
|
190
|
+
}
|
|
191
|
+
}, [
|
|
192
|
+
state.btwState.isActive,
|
|
193
|
+
state.btwState.isLoading,
|
|
194
|
+
state.btwState.question,
|
|
195
|
+
]);
|
|
196
|
+
|
|
156
197
|
// Methods
|
|
157
198
|
const insertTextAtCursor = useCallback((text: string) => {
|
|
158
199
|
dispatch({ type: "INSERT_TEXT", payload: text });
|
|
@@ -307,6 +348,21 @@ export const useInputManager = (
|
|
|
307
348
|
callbacksRef.current.onPermissionModeChange?.(mode);
|
|
308
349
|
}, []);
|
|
309
350
|
|
|
351
|
+
const setAllowBypassInCycle = useCallback((allow: boolean) => {
|
|
352
|
+
dispatch({ type: "SET_ALLOW_BYPASS_IN_CYCLE", payload: allow });
|
|
353
|
+
}, []);
|
|
354
|
+
|
|
355
|
+
const setBtwState = useCallback(
|
|
356
|
+
(payload: Partial<import("../managers/inputReducer.js").BtwState>) => {
|
|
357
|
+
if (callbacksRef.current.onBtwStateChange) {
|
|
358
|
+
callbacksRef.current.onBtwStateChange(payload);
|
|
359
|
+
} else {
|
|
360
|
+
dispatch({ type: "SET_BTW_STATE", payload });
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
[],
|
|
364
|
+
);
|
|
365
|
+
|
|
310
366
|
const addImage = useCallback((imagePath: string, mimeType: string) => {
|
|
311
367
|
dispatch({ type: "ADD_IMAGE", payload: { path: imagePath, mimeType } });
|
|
312
368
|
}, []);
|
|
@@ -398,6 +454,7 @@ export const useInputManager = (
|
|
|
398
454
|
showPluginManager: state.showPluginManager,
|
|
399
455
|
permissionMode: state.permissionMode,
|
|
400
456
|
attachedImages: state.attachedImages,
|
|
457
|
+
btwState: state.btwState,
|
|
401
458
|
isManagerReady: true,
|
|
402
459
|
|
|
403
460
|
// Methods
|
|
@@ -437,6 +494,8 @@ export const useInputManager = (
|
|
|
437
494
|
setShowStatusCommand,
|
|
438
495
|
setShowPluginManager,
|
|
439
496
|
setPermissionMode,
|
|
497
|
+
setAllowBypassInCycle,
|
|
498
|
+
setBtwState,
|
|
440
499
|
|
|
441
500
|
// Image management
|
|
442
501
|
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,11 @@ 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 === "btw") {
|
|
374
|
+
dispatch({
|
|
375
|
+
type: "SET_BTW_STATE",
|
|
376
|
+
payload: { isActive: true, question: "", isLoading: false },
|
|
377
|
+
});
|
|
345
378
|
}
|
|
346
379
|
}
|
|
347
380
|
})();
|
|
@@ -461,8 +494,10 @@ export const handleSelectorInput = (
|
|
|
461
494
|
if (input === " ") {
|
|
462
495
|
if (state.showFileSelector) {
|
|
463
496
|
dispatch({ type: "CANCEL_FILE_SELECTOR" });
|
|
497
|
+
return false;
|
|
464
498
|
} else if (state.showCommandSelector) {
|
|
465
499
|
dispatch({ type: "CANCEL_COMMAND_SELECTOR" });
|
|
500
|
+
return false;
|
|
466
501
|
}
|
|
467
502
|
}
|
|
468
503
|
|
|
@@ -667,6 +702,46 @@ export const handleInput = async (
|
|
|
667
702
|
return true;
|
|
668
703
|
}
|
|
669
704
|
|
|
705
|
+
if (state.btwState.isActive) {
|
|
706
|
+
if (key.escape) {
|
|
707
|
+
dispatch({
|
|
708
|
+
type: "SET_BTW_STATE",
|
|
709
|
+
payload: {
|
|
710
|
+
isActive: false,
|
|
711
|
+
question: "",
|
|
712
|
+
answer: undefined,
|
|
713
|
+
isLoading: false,
|
|
714
|
+
},
|
|
715
|
+
});
|
|
716
|
+
return true;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (key.return) {
|
|
720
|
+
if (state.inputText.trim() && !state.btwState.isLoading) {
|
|
721
|
+
dispatch({
|
|
722
|
+
type: "SET_BTW_STATE",
|
|
723
|
+
payload: {
|
|
724
|
+
question: state.inputText.trim(),
|
|
725
|
+
isLoading: true,
|
|
726
|
+
answer: undefined,
|
|
727
|
+
},
|
|
728
|
+
});
|
|
729
|
+
dispatch({ type: "CLEAR_INPUT" });
|
|
730
|
+
}
|
|
731
|
+
return true;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// Handle normal input for the question
|
|
735
|
+
return await handleNormalInput(
|
|
736
|
+
state,
|
|
737
|
+
dispatch,
|
|
738
|
+
callbacks,
|
|
739
|
+
input,
|
|
740
|
+
key,
|
|
741
|
+
clearImages,
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
|
|
670
745
|
if (key.escape) {
|
|
671
746
|
if (
|
|
672
747
|
!(
|
|
@@ -678,7 +753,8 @@ export const handleInput = async (
|
|
|
678
753
|
state.showRewindManager ||
|
|
679
754
|
state.showHelp ||
|
|
680
755
|
state.showStatusCommand ||
|
|
681
|
-
state.showPluginManager
|
|
756
|
+
state.showPluginManager ||
|
|
757
|
+
state.btwState.isActive
|
|
682
758
|
)
|
|
683
759
|
) {
|
|
684
760
|
callbacks.onAbortMessage?.();
|
|
@@ -687,7 +763,12 @@ export const handleInput = async (
|
|
|
687
763
|
}
|
|
688
764
|
|
|
689
765
|
if (key.tab && key.shift) {
|
|
690
|
-
cyclePermissionMode(
|
|
766
|
+
cyclePermissionMode(
|
|
767
|
+
state.permissionMode,
|
|
768
|
+
dispatch,
|
|
769
|
+
callbacks,
|
|
770
|
+
state.allowBypassInCycle,
|
|
771
|
+
);
|
|
691
772
|
return true;
|
|
692
773
|
}
|
|
693
774
|
|
|
@@ -700,7 +781,8 @@ export const handleInput = async (
|
|
|
700
781
|
state.showRewindManager ||
|
|
701
782
|
state.showHelp ||
|
|
702
783
|
state.showStatusCommand ||
|
|
703
|
-
state.showPluginManager
|
|
784
|
+
state.showPluginManager ||
|
|
785
|
+
state.btwState.isActive
|
|
704
786
|
) {
|
|
705
787
|
if (
|
|
706
788
|
state.showBackgroundTaskManager ||
|
|
@@ -708,7 +790,8 @@ export const handleInput = async (
|
|
|
708
790
|
state.showRewindManager ||
|
|
709
791
|
state.showHelp ||
|
|
710
792
|
state.showStatusCommand ||
|
|
711
|
-
state.showPluginManager
|
|
793
|
+
state.showPluginManager ||
|
|
794
|
+
state.btwState.isActive
|
|
712
795
|
) {
|
|
713
796
|
return true;
|
|
714
797
|
}
|
|
@@ -12,6 +12,13 @@ export interface AttachedImage {
|
|
|
12
12
|
mimeType: string;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
export interface BtwState {
|
|
16
|
+
isActive: boolean;
|
|
17
|
+
question: string;
|
|
18
|
+
answer?: string;
|
|
19
|
+
isLoading: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
export interface InputManagerCallbacks {
|
|
16
23
|
onInputTextChange?: (text: string) => void;
|
|
17
24
|
onCursorPositionChange?: (position: number) => void;
|
|
@@ -43,6 +50,9 @@ export interface InputManagerCallbacks {
|
|
|
43
50
|
onAbortMessage?: () => void;
|
|
44
51
|
onBackgroundCurrentTask?: () => void;
|
|
45
52
|
onPermissionModeChange?: (mode: PermissionMode) => void;
|
|
53
|
+
onAskBtw?: (question: string) => Promise<string>;
|
|
54
|
+
btwState?: BtwState;
|
|
55
|
+
onBtwStateChange?: (payload: Partial<BtwState>) => void;
|
|
46
56
|
sessionId?: string;
|
|
47
57
|
workdir?: string;
|
|
48
58
|
getFullMessageThread?: () => Promise<{
|
|
@@ -75,6 +85,7 @@ export interface InputState {
|
|
|
75
85
|
showStatusCommand: boolean;
|
|
76
86
|
showPluginManager: boolean;
|
|
77
87
|
permissionMode: PermissionMode;
|
|
88
|
+
allowBypassInCycle: boolean;
|
|
78
89
|
selectorJustUsed: boolean;
|
|
79
90
|
isPasting: boolean;
|
|
80
91
|
pasteBuffer: string;
|
|
@@ -84,6 +95,7 @@ export interface InputState {
|
|
|
84
95
|
originalInputText: string;
|
|
85
96
|
originalLongTextMap: Record<string, string>;
|
|
86
97
|
isFileSearching: boolean;
|
|
98
|
+
btwState: BtwState;
|
|
87
99
|
}
|
|
88
100
|
|
|
89
101
|
export const initialState: InputState = {
|
|
@@ -109,6 +121,7 @@ export const initialState: InputState = {
|
|
|
109
121
|
showStatusCommand: false,
|
|
110
122
|
showPluginManager: false,
|
|
111
123
|
permissionMode: "default",
|
|
124
|
+
allowBypassInCycle: false,
|
|
112
125
|
selectorJustUsed: false,
|
|
113
126
|
isPasting: false,
|
|
114
127
|
pasteBuffer: "",
|
|
@@ -118,6 +131,11 @@ export const initialState: InputState = {
|
|
|
118
131
|
originalInputText: "",
|
|
119
132
|
originalLongTextMap: {},
|
|
120
133
|
isFileSearching: false,
|
|
134
|
+
btwState: {
|
|
135
|
+
isActive: false,
|
|
136
|
+
question: "",
|
|
137
|
+
isLoading: false,
|
|
138
|
+
},
|
|
121
139
|
};
|
|
122
140
|
|
|
123
141
|
export type InputAction =
|
|
@@ -146,6 +164,7 @@ export type InputAction =
|
|
|
146
164
|
| { type: "SET_SHOW_STATUS_COMMAND"; payload: boolean }
|
|
147
165
|
| { type: "SET_SHOW_PLUGIN_MANAGER"; payload: boolean }
|
|
148
166
|
| { type: "SET_PERMISSION_MODE"; payload: PermissionMode }
|
|
167
|
+
| { type: "SET_ALLOW_BYPASS_IN_CYCLE"; payload: boolean }
|
|
149
168
|
| { type: "SET_SELECTOR_JUST_USED"; payload: boolean }
|
|
150
169
|
| { type: "INSERT_TEXT_WITH_PLACEHOLDER"; payload: string }
|
|
151
170
|
| { type: "CLEAR_LONG_TEXT_MAP" }
|
|
@@ -160,7 +179,8 @@ export type InputAction =
|
|
|
160
179
|
| { type: "SET_HISTORY_ENTRIES"; payload: PromptEntry[] }
|
|
161
180
|
| { type: "NAVIGATE_HISTORY"; payload: "up" | "down" }
|
|
162
181
|
| { type: "RESET_HISTORY_NAVIGATION" }
|
|
163
|
-
| { type: "SELECT_HISTORY_ENTRY"; payload: PromptEntry }
|
|
182
|
+
| { type: "SELECT_HISTORY_ENTRY"; payload: PromptEntry }
|
|
183
|
+
| { type: "SET_BTW_STATE"; payload: Partial<BtwState> };
|
|
164
184
|
|
|
165
185
|
export function inputReducer(
|
|
166
186
|
state: InputState,
|
|
@@ -340,6 +360,8 @@ export function inputReducer(
|
|
|
340
360
|
};
|
|
341
361
|
case "SET_PERMISSION_MODE":
|
|
342
362
|
return { ...state, permissionMode: action.payload };
|
|
363
|
+
case "SET_ALLOW_BYPASS_IN_CYCLE":
|
|
364
|
+
return { ...state, allowBypassInCycle: action.payload };
|
|
343
365
|
case "SET_SELECTOR_JUST_USED":
|
|
344
366
|
return { ...state, selectorJustUsed: action.payload };
|
|
345
367
|
case "INSERT_TEXT_WITH_PLACEHOLDER": {
|
|
@@ -483,6 +505,14 @@ export function inputReducer(
|
|
|
483
505
|
originalInputText: "",
|
|
484
506
|
originalLongTextMap: {},
|
|
485
507
|
};
|
|
508
|
+
case "SET_BTW_STATE":
|
|
509
|
+
return {
|
|
510
|
+
...state,
|
|
511
|
+
btwState: {
|
|
512
|
+
...state.btwState,
|
|
513
|
+
...action.payload,
|
|
514
|
+
},
|
|
515
|
+
};
|
|
486
516
|
default:
|
|
487
517
|
return state;
|
|
488
518
|
}
|