wave-code 0.17.5 → 0.17.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 +3 -0
- package/dist/acp/agent.d.ts.map +1 -1
- package/dist/acp/agent.js +307 -172
- package/dist/components/BtwDisplay.d.ts.map +1 -1
- package/dist/components/BtwDisplay.js +2 -2
- package/dist/components/InputBox.js +14 -9
- package/dist/components/StatusLine.d.ts +0 -1
- package/dist/components/StatusLine.d.ts.map +1 -1
- package/dist/components/StatusLine.js +2 -2
- package/dist/constants/commands.d.ts.map +1 -1
- package/dist/constants/commands.js +18 -0
- package/dist/contexts/useChat.d.ts +3 -0
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +21 -0
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +13 -38
- package/dist/managers/inputHandlers.d.ts.map +1 -1
- package/dist/managers/inputHandlers.js +22 -40
- package/dist/managers/inputReducer.d.ts +4 -1
- package/dist/managers/inputReducer.d.ts.map +1 -1
- package/dist/managers/inputReducer.js +21 -34
- package/package.json +2 -2
- package/src/acp/agent.ts +418 -201
- package/src/components/BtwDisplay.tsx +4 -1
- package/src/components/InputBox.tsx +46 -46
- package/src/components/StatusLine.tsx +1 -7
- package/src/constants/commands.ts +18 -0
- package/src/contexts/useChat.tsx +27 -0
- package/src/hooks/useInputManager.ts +13 -38
- package/src/managers/inputHandlers.ts +20 -49
- package/src/managers/inputReducer.ts +27 -40
|
@@ -8,7 +8,7 @@ interface BtwDisplayProps {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export const BtwDisplay: React.FC<BtwDisplayProps> = ({ btwState }) => {
|
|
11
|
-
if (!btwState.
|
|
11
|
+
if (!btwState.question) {
|
|
12
12
|
return null;
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -26,6 +26,9 @@ export const BtwDisplay: React.FC<BtwDisplayProps> = ({ btwState }) => {
|
|
|
26
26
|
{btwState.answer && (
|
|
27
27
|
<Box flexDirection="column">
|
|
28
28
|
<Markdown>{btwState.answer}</Markdown>
|
|
29
|
+
<Text color="gray" dimColor>
|
|
30
|
+
ESC to dismiss
|
|
31
|
+
</Text>
|
|
29
32
|
</Box>
|
|
30
33
|
)}
|
|
31
34
|
</Box>
|
|
@@ -76,6 +76,9 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
76
76
|
sessionId,
|
|
77
77
|
workingDirectory,
|
|
78
78
|
askBtw,
|
|
79
|
+
clearMessages,
|
|
80
|
+
compact,
|
|
81
|
+
goalCommand,
|
|
79
82
|
currentModel,
|
|
80
83
|
configuredModels,
|
|
81
84
|
setModel,
|
|
@@ -155,6 +158,9 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
155
158
|
} = useInputManager({
|
|
156
159
|
onSendMessage: sendMessage,
|
|
157
160
|
onAskBtw: askBtw,
|
|
161
|
+
onClearMessages: clearMessages,
|
|
162
|
+
onCompact: compact,
|
|
163
|
+
onGoalCommand: goalCommand,
|
|
158
164
|
onHasSlashCommand: hasSlashCommand,
|
|
159
165
|
onAbortMessage: abortMessage,
|
|
160
166
|
onBackgroundCurrentTask: backgroundCurrentTask,
|
|
@@ -328,53 +334,47 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
328
334
|
<WorkflowManager onCancel={() => setShowWorkflowManager(false)} />
|
|
329
335
|
)}
|
|
330
336
|
|
|
331
|
-
{
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
337
|
+
{btwState.question
|
|
338
|
+
? null
|
|
339
|
+
: showBackgroundTaskManager ||
|
|
340
|
+
showMcpManager ||
|
|
341
|
+
showRewindManager ||
|
|
342
|
+
showHelp ||
|
|
343
|
+
showStatusCommand ||
|
|
344
|
+
showLoginCommand ||
|
|
345
|
+
showPluginManager ||
|
|
346
|
+
showWorkflowManager || (
|
|
347
|
+
<Box flexDirection="column">
|
|
348
|
+
<Box
|
|
349
|
+
borderStyle="single"
|
|
350
|
+
borderColor="gray"
|
|
351
|
+
borderLeft={false}
|
|
352
|
+
borderRight={false}
|
|
353
|
+
>
|
|
354
|
+
<Text color={isPlaceholder ? "gray" : "white"}>
|
|
355
|
+
{shouldShowCursor ? (
|
|
356
|
+
<>
|
|
357
|
+
{beforeCursor}
|
|
358
|
+
<Text backgroundColor="white" color="black">
|
|
359
|
+
{atCursor}
|
|
360
|
+
</Text>
|
|
361
|
+
{afterCursor}
|
|
362
|
+
</>
|
|
363
|
+
) : (
|
|
364
|
+
displayText
|
|
365
|
+
)}
|
|
366
|
+
</Text>
|
|
367
|
+
</Box>
|
|
368
|
+
<StatusLine
|
|
369
|
+
permissionMode={permissionMode}
|
|
370
|
+
isShellCommand={isShellCommand}
|
|
371
|
+
isGoalActive={isGoalActive}
|
|
372
|
+
goalElapsed={goalElapsed}
|
|
373
|
+
latestTotalTokens={latestTotalTokens}
|
|
374
|
+
maxInputTokens={maxInputTokens}
|
|
375
|
+
/>
|
|
366
376
|
</Box>
|
|
367
|
-
|
|
368
|
-
permissionMode={permissionMode}
|
|
369
|
-
isShellCommand={isShellCommand}
|
|
370
|
-
isBtwActive={btwState.isActive}
|
|
371
|
-
isGoalActive={isGoalActive}
|
|
372
|
-
goalElapsed={goalElapsed}
|
|
373
|
-
latestTotalTokens={latestTotalTokens}
|
|
374
|
-
maxInputTokens={maxInputTokens}
|
|
375
|
-
/>
|
|
376
|
-
</Box>
|
|
377
|
-
)}
|
|
377
|
+
)}
|
|
378
378
|
</Box>
|
|
379
379
|
);
|
|
380
380
|
};
|
|
@@ -4,7 +4,6 @@ import { Box, Text } from "ink";
|
|
|
4
4
|
export interface StatusLineProps {
|
|
5
5
|
permissionMode: string;
|
|
6
6
|
isShellCommand: boolean;
|
|
7
|
-
isBtwActive: boolean;
|
|
8
7
|
isGoalActive?: boolean;
|
|
9
8
|
goalElapsed?: string;
|
|
10
9
|
latestTotalTokens?: number;
|
|
@@ -14,7 +13,6 @@ export interface StatusLineProps {
|
|
|
14
13
|
export const StatusLine: React.FC<StatusLineProps> = ({
|
|
15
14
|
permissionMode,
|
|
16
15
|
isShellCommand,
|
|
17
|
-
isBtwActive,
|
|
18
16
|
isGoalActive,
|
|
19
17
|
goalElapsed,
|
|
20
18
|
latestTotalTokens = 0,
|
|
@@ -30,11 +28,7 @@ export const StatusLine: React.FC<StatusLineProps> = ({
|
|
|
30
28
|
|
|
31
29
|
return (
|
|
32
30
|
<Box paddingRight={1} justifyContent="space-between" width="100%">
|
|
33
|
-
{
|
|
34
|
-
<Text color="gray">
|
|
35
|
-
Mode: <Text color="cyan">BTW</Text> (ESC to dismiss)
|
|
36
|
-
</Text>
|
|
37
|
-
) : isShellCommand ? (
|
|
31
|
+
{isShellCommand ? (
|
|
38
32
|
<Text color="gray">
|
|
39
33
|
Shell: <Text color="yellow">Run shell command</Text>
|
|
40
34
|
</Text>
|
|
@@ -68,4 +68,22 @@ export const AVAILABLE_COMMANDS: SlashCommand[] = [
|
|
|
68
68
|
description: "View and manage workflow runs",
|
|
69
69
|
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
70
70
|
},
|
|
71
|
+
{
|
|
72
|
+
id: "clear",
|
|
73
|
+
name: "clear",
|
|
74
|
+
description: "Clear conversation history and reset session",
|
|
75
|
+
handler: () => {},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: "compact",
|
|
79
|
+
name: "compact",
|
|
80
|
+
description: "Compact conversation history to reduce context usage",
|
|
81
|
+
handler: () => {},
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: "goal",
|
|
85
|
+
name: "goal",
|
|
86
|
+
description: "Set, check, or clear an autonomous goal for the session",
|
|
87
|
+
handler: () => {},
|
|
88
|
+
},
|
|
71
89
|
];
|
package/src/contexts/useChat.tsx
CHANGED
|
@@ -53,6 +53,9 @@ export interface ChatContextType {
|
|
|
53
53
|
longTextMap?: Record<string, string>,
|
|
54
54
|
) => Promise<void>;
|
|
55
55
|
askBtw: (question: string) => Promise<string>;
|
|
56
|
+
clearMessages: () => Promise<void>;
|
|
57
|
+
compact: (instructions?: string) => Promise<void>;
|
|
58
|
+
goalCommand: (args?: string) => Promise<void>;
|
|
56
59
|
abortMessage: () => void;
|
|
57
60
|
recallQueuedMessage: () => QueuedMessage | null;
|
|
58
61
|
removeQueuedMessageById: (id: string) => boolean;
|
|
@@ -623,6 +626,27 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
623
626
|
return await agentRef.current.askBtw(question);
|
|
624
627
|
}, []);
|
|
625
628
|
|
|
629
|
+
const clearMessages = useCallback(async () => {
|
|
630
|
+
await agentRef.current?.clearMessages();
|
|
631
|
+
}, []);
|
|
632
|
+
|
|
633
|
+
const compact = useCallback(async (instructions?: string) => {
|
|
634
|
+
await agentRef.current?.compact(instructions);
|
|
635
|
+
}, []);
|
|
636
|
+
|
|
637
|
+
const goalCommand = useCallback(async (args?: string) => {
|
|
638
|
+
const trimmed = args?.trim() ?? "";
|
|
639
|
+
if (!trimmed) {
|
|
640
|
+
await agentRef.current?.showGoalStatus();
|
|
641
|
+
} else if (
|
|
642
|
+
["clear", "stop", "off", "reset", "none", "cancel"].includes(trimmed)
|
|
643
|
+
) {
|
|
644
|
+
await agentRef.current?.clearGoal();
|
|
645
|
+
} else {
|
|
646
|
+
await agentRef.current?.setGoal(trimmed);
|
|
647
|
+
}
|
|
648
|
+
}, []);
|
|
649
|
+
|
|
626
650
|
// Unified interrupt method, interrupt both AI messages and command execution
|
|
627
651
|
const abortMessage = useCallback(() => {
|
|
628
652
|
agentRef.current?.abortMessage();
|
|
@@ -824,6 +848,9 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
824
848
|
sessionId,
|
|
825
849
|
sendMessage,
|
|
826
850
|
askBtw,
|
|
851
|
+
clearMessages,
|
|
852
|
+
compact,
|
|
853
|
+
goalCommand,
|
|
827
854
|
abortMessage,
|
|
828
855
|
recallQueuedMessage,
|
|
829
856
|
removeQueuedMessageById,
|
|
@@ -45,6 +45,9 @@ export const useInputManager = (
|
|
|
45
45
|
logger,
|
|
46
46
|
hasQueuedMessages: hasQueuedMessagesProp,
|
|
47
47
|
onRecallQueuedMessage,
|
|
48
|
+
onClearMessages,
|
|
49
|
+
onCompact,
|
|
50
|
+
onGoalCommand,
|
|
48
51
|
} = callbacks;
|
|
49
52
|
|
|
50
53
|
// Handle debounced file search
|
|
@@ -212,11 +215,12 @@ export const useInputManager = (
|
|
|
212
215
|
dispatch({ type: "SET_SHOW_MODEL_SELECTOR", payload: true });
|
|
213
216
|
} else if (command === "workflows") {
|
|
214
217
|
dispatch({ type: "SET_SHOW_WORKFLOW_MANAGER", payload: true });
|
|
215
|
-
} else if (command === "
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
218
|
+
} else if (command === "clear") {
|
|
219
|
+
await onClearMessages?.();
|
|
220
|
+
} else if (command === "compact") {
|
|
221
|
+
await onCompact?.(effect.args);
|
|
222
|
+
} else if (command === "goal") {
|
|
223
|
+
await onGoalCommand?.(effect.args);
|
|
220
224
|
}
|
|
221
225
|
}
|
|
222
226
|
break;
|
|
@@ -243,6 +247,9 @@ export const useInputManager = (
|
|
|
243
247
|
logger,
|
|
244
248
|
onHasSlashCommand,
|
|
245
249
|
onRecallQueuedMessage,
|
|
250
|
+
onClearMessages,
|
|
251
|
+
onCompact,
|
|
252
|
+
onGoalCommand,
|
|
246
253
|
]);
|
|
247
254
|
|
|
248
255
|
useEffect(() => {
|
|
@@ -320,39 +327,7 @@ export const useInputManager = (
|
|
|
320
327
|
onImagesStateChange?.(state.attachedImages);
|
|
321
328
|
}, [state.attachedImages, onImagesStateChange]);
|
|
322
329
|
|
|
323
|
-
//
|
|
324
|
-
useEffect(() => {
|
|
325
|
-
if (
|
|
326
|
-
state.btwState.isActive &&
|
|
327
|
-
state.btwState.isLoading &&
|
|
328
|
-
state.btwState.question
|
|
329
|
-
) {
|
|
330
|
-
const askBtw = async () => {
|
|
331
|
-
try {
|
|
332
|
-
const answer = await onAskBtw?.(state.btwState.question);
|
|
333
|
-
dispatch({
|
|
334
|
-
type: "SET_BTW_STATE",
|
|
335
|
-
payload: { answer, isLoading: false },
|
|
336
|
-
});
|
|
337
|
-
} catch (error) {
|
|
338
|
-
console.error("Failed to ask side question:", error);
|
|
339
|
-
dispatch({
|
|
340
|
-
type: "SET_BTW_STATE",
|
|
341
|
-
payload: {
|
|
342
|
-
answer: "Error: Failed to get an answer for your side question.",
|
|
343
|
-
isLoading: false,
|
|
344
|
-
},
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
};
|
|
348
|
-
askBtw();
|
|
349
|
-
}
|
|
350
|
-
}, [
|
|
351
|
-
state.btwState.isActive,
|
|
352
|
-
state.btwState.isLoading,
|
|
353
|
-
state.btwState.question,
|
|
354
|
-
onAskBtw,
|
|
355
|
-
]);
|
|
330
|
+
// /btw side question is handled via pendingEffect "ASK_BTW" above
|
|
356
331
|
|
|
357
332
|
// Methods
|
|
358
333
|
const insertTextAtCursor = useCallback((text: string) => {
|
|
@@ -373,11 +373,12 @@ export const handleCommandSelect = (
|
|
|
373
373
|
dispatch({ type: "SET_SHOW_MODEL_SELECTOR", payload: true });
|
|
374
374
|
} else if (command === "workflows") {
|
|
375
375
|
dispatch({ type: "SET_SHOW_WORKFLOW_MANAGER", payload: true });
|
|
376
|
-
} else if (command === "
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
376
|
+
} else if (command === "clear") {
|
|
377
|
+
await callbacks.onClearMessages?.();
|
|
378
|
+
} else if (command === "compact") {
|
|
379
|
+
await callbacks.onCompact?.();
|
|
380
|
+
} else if (command === "goal") {
|
|
381
|
+
await callbacks.onGoalCommand?.();
|
|
381
382
|
}
|
|
382
383
|
}
|
|
383
384
|
})();
|
|
@@ -701,44 +702,17 @@ export const handleInput = async (
|
|
|
701
702
|
key: Key,
|
|
702
703
|
clearImages?: () => void,
|
|
703
704
|
): Promise<boolean> => {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
return true;
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
if (key.return) {
|
|
719
|
-
if (state.inputText.trim() && !state.btwState.isLoading) {
|
|
720
|
-
dispatch({
|
|
721
|
-
type: "SET_BTW_STATE",
|
|
722
|
-
payload: {
|
|
723
|
-
question: state.inputText.trim(),
|
|
724
|
-
isLoading: true,
|
|
725
|
-
answer: undefined,
|
|
726
|
-
},
|
|
727
|
-
});
|
|
728
|
-
dispatch({ type: "CLEAR_INPUT" });
|
|
729
|
-
}
|
|
730
|
-
return true;
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
// Handle normal input for the question
|
|
734
|
-
return await handleNormalInput(
|
|
735
|
-
state,
|
|
736
|
-
dispatch,
|
|
737
|
-
callbacks,
|
|
738
|
-
input,
|
|
739
|
-
key,
|
|
740
|
-
clearImages,
|
|
741
|
-
);
|
|
705
|
+
// Handle ESC to dismiss btw answer
|
|
706
|
+
if (key.escape && state.btwState.question && !state.btwState.isLoading) {
|
|
707
|
+
dispatch({
|
|
708
|
+
type: "SET_BTW_STATE",
|
|
709
|
+
payload: {
|
|
710
|
+
question: "",
|
|
711
|
+
answer: undefined,
|
|
712
|
+
isLoading: false,
|
|
713
|
+
},
|
|
714
|
+
});
|
|
715
|
+
return true;
|
|
742
716
|
}
|
|
743
717
|
|
|
744
718
|
if (key.escape) {
|
|
@@ -754,8 +728,7 @@ export const handleInput = async (
|
|
|
754
728
|
state.showStatusCommand ||
|
|
755
729
|
state.showPluginManager ||
|
|
756
730
|
state.showModelSelector ||
|
|
757
|
-
state.showWorkflowManager
|
|
758
|
-
state.btwState.isActive
|
|
731
|
+
state.showWorkflowManager
|
|
759
732
|
)
|
|
760
733
|
) {
|
|
761
734
|
callbacks.onAbortMessage?.();
|
|
@@ -779,8 +752,7 @@ export const handleInput = async (
|
|
|
779
752
|
state.showStatusCommand ||
|
|
780
753
|
state.showPluginManager ||
|
|
781
754
|
state.showModelSelector ||
|
|
782
|
-
state.showWorkflowManager
|
|
783
|
-
state.btwState.isActive
|
|
755
|
+
state.showWorkflowManager
|
|
784
756
|
) {
|
|
785
757
|
if (
|
|
786
758
|
state.showBackgroundTaskManager ||
|
|
@@ -790,8 +762,7 @@ export const handleInput = async (
|
|
|
790
762
|
state.showStatusCommand ||
|
|
791
763
|
state.showPluginManager ||
|
|
792
764
|
state.showModelSelector ||
|
|
793
|
-
state.showWorkflowManager
|
|
794
|
-
state.btwState.isActive
|
|
765
|
+
state.showWorkflowManager
|
|
795
766
|
) {
|
|
796
767
|
return true;
|
|
797
768
|
}
|
|
@@ -22,7 +22,6 @@ export interface AttachedImage {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export interface BtwState {
|
|
25
|
-
isActive: boolean;
|
|
26
25
|
question: string;
|
|
27
26
|
answer?: string;
|
|
28
27
|
isLoading: boolean;
|
|
@@ -41,7 +40,7 @@ export type PendingEffect =
|
|
|
41
40
|
| { type: "PERMISSION_MODE_CHANGE"; mode: PermissionMode }
|
|
42
41
|
| { type: "FETCH_HISTORY" }
|
|
43
42
|
| { type: "PASTE_IMAGE" }
|
|
44
|
-
| { type: "EXECUTE_COMMAND"; command: string }
|
|
43
|
+
| { type: "EXECUTE_COMMAND"; command: string; args?: string }
|
|
45
44
|
| { type: "RECALL_QUEUED_MESSAGE" };
|
|
46
45
|
|
|
47
46
|
export interface InputManagerCallbacks {
|
|
@@ -78,6 +77,9 @@ export interface InputManagerCallbacks {
|
|
|
78
77
|
onBackgroundCurrentTask?: () => void;
|
|
79
78
|
onPermissionModeChange?: (mode: PermissionMode) => void;
|
|
80
79
|
onAskBtw?: (question: string) => Promise<string>;
|
|
80
|
+
onClearMessages?: () => Promise<void>;
|
|
81
|
+
onCompact?: (instructions?: string) => Promise<void>;
|
|
82
|
+
onGoalCommand?: (args?: string) => Promise<void>;
|
|
81
83
|
sessionId?: string;
|
|
82
84
|
workdir?: string;
|
|
83
85
|
getFullMessageThread?: () => Promise<{
|
|
@@ -164,7 +166,6 @@ export const initialState: InputState = {
|
|
|
164
166
|
originalLongTextMap: {},
|
|
165
167
|
isFileSearching: false,
|
|
166
168
|
btwState: {
|
|
167
|
-
isActive: false,
|
|
168
169
|
question: "",
|
|
169
170
|
isLoading: false,
|
|
170
171
|
},
|
|
@@ -688,42 +689,19 @@ export function inputReducer(
|
|
|
688
689
|
const { input, key } = action.payload;
|
|
689
690
|
const hasQueuedMessages = action.payload.hasQueuedMessages ?? false;
|
|
690
691
|
|
|
691
|
-
// 1.
|
|
692
|
-
if (
|
|
693
|
-
|
|
692
|
+
// 1. Escape Handling
|
|
693
|
+
if (key.escape) {
|
|
694
|
+
// Dismiss btw answer
|
|
695
|
+
if (state.btwState.question && !state.btwState.isLoading) {
|
|
694
696
|
return {
|
|
695
697
|
...state,
|
|
696
698
|
btwState: {
|
|
697
|
-
isActive: false,
|
|
698
699
|
question: "",
|
|
699
700
|
answer: undefined,
|
|
700
701
|
isLoading: false,
|
|
701
702
|
},
|
|
702
703
|
};
|
|
703
704
|
}
|
|
704
|
-
|
|
705
|
-
if (key.return) {
|
|
706
|
-
const question = state.inputText.trim();
|
|
707
|
-
if (question && !state.btwState.isLoading) {
|
|
708
|
-
return {
|
|
709
|
-
...state,
|
|
710
|
-
inputText: "",
|
|
711
|
-
cursorPosition: 0,
|
|
712
|
-
btwState: {
|
|
713
|
-
...state.btwState,
|
|
714
|
-
question,
|
|
715
|
-
isLoading: true,
|
|
716
|
-
answer: undefined,
|
|
717
|
-
},
|
|
718
|
-
pendingEffect: { type: "ASK_BTW", question },
|
|
719
|
-
};
|
|
720
|
-
}
|
|
721
|
-
return state;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
// 2. Escape Handling
|
|
726
|
-
if (key.escape) {
|
|
727
705
|
if (state.showFileSelector) {
|
|
728
706
|
return {
|
|
729
707
|
...state,
|
|
@@ -1017,13 +995,12 @@ export function inputReducer(
|
|
|
1017
995
|
.replace(imageRegex, "")
|
|
1018
996
|
.trim();
|
|
1019
997
|
|
|
1020
|
-
if (
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
: "";
|
|
998
|
+
if (contentWithPlaceholders.startsWith("/btw ")) {
|
|
999
|
+
const question = contentWithPlaceholders.substring(5).trim();
|
|
1000
|
+
if (!question) {
|
|
1001
|
+
// Bare /btw with no question text — ignore
|
|
1002
|
+
return state;
|
|
1003
|
+
}
|
|
1027
1004
|
|
|
1028
1005
|
return {
|
|
1029
1006
|
...state,
|
|
@@ -1032,15 +1009,19 @@ export function inputReducer(
|
|
|
1032
1009
|
historyIndex: -1,
|
|
1033
1010
|
longTextMap: {},
|
|
1034
1011
|
btwState: {
|
|
1035
|
-
isActive: true,
|
|
1036
1012
|
question,
|
|
1037
|
-
isLoading:
|
|
1013
|
+
isLoading: true,
|
|
1038
1014
|
answer: undefined,
|
|
1039
1015
|
},
|
|
1040
|
-
pendingEffect:
|
|
1016
|
+
pendingEffect: { type: "ASK_BTW", question },
|
|
1041
1017
|
};
|
|
1042
1018
|
}
|
|
1043
1019
|
|
|
1020
|
+
if (contentWithPlaceholders === "/btw") {
|
|
1021
|
+
// Bare /btw — ignore
|
|
1022
|
+
return state;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1044
1025
|
// Check if the content is a CLI-internal slash command (help, tasks,
|
|
1045
1026
|
// etc.) that should be executed locally rather than sent as a message.
|
|
1046
1027
|
// Agent slash commands and unknown /commands always go to SEND_MESSAGE.
|
|
@@ -1055,6 +1036,11 @@ export function inputReducer(
|
|
|
1055
1036
|
(cmd) => cmd.id === commandName,
|
|
1056
1037
|
);
|
|
1057
1038
|
if (isInternalCommand) {
|
|
1039
|
+
const argsText =
|
|
1040
|
+
spaceIndex === -1
|
|
1041
|
+
? undefined
|
|
1042
|
+
: contentWithPlaceholders.substring(spaceIndex + 1).trim() ||
|
|
1043
|
+
undefined;
|
|
1058
1044
|
return {
|
|
1059
1045
|
...state,
|
|
1060
1046
|
inputText: "",
|
|
@@ -1064,6 +1050,7 @@ export function inputReducer(
|
|
|
1064
1050
|
pendingEffect: {
|
|
1065
1051
|
type: "EXECUTE_COMMAND",
|
|
1066
1052
|
command: commandName,
|
|
1053
|
+
args: argsText,
|
|
1067
1054
|
},
|
|
1068
1055
|
};
|
|
1069
1056
|
}
|