wave-code 0.8.4 → 0.9.1

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 (54) hide show
  1. package/dist/components/ChatInterface.d.ts.map +1 -1
  2. package/dist/components/ChatInterface.js +26 -7
  3. package/dist/components/FileSelector.d.ts +1 -0
  4. package/dist/components/FileSelector.d.ts.map +1 -1
  5. package/dist/components/FileSelector.js +3 -3
  6. package/dist/components/HelpView.d.ts.map +1 -1
  7. package/dist/components/HelpView.js +1 -0
  8. package/dist/components/HistorySearch.d.ts +2 -1
  9. package/dist/components/HistorySearch.d.ts.map +1 -1
  10. package/dist/components/HistorySearch.js +1 -1
  11. package/dist/components/InputBox.d.ts.map +1 -1
  12. package/dist/components/InputBox.js +8 -6
  13. package/dist/components/MessageBlockItem.d.ts.map +1 -1
  14. package/dist/components/MessageBlockItem.js +1 -1
  15. package/dist/components/MessageList.d.ts +2 -1
  16. package/dist/components/MessageList.d.ts.map +1 -1
  17. package/dist/components/MessageList.js +14 -4
  18. package/dist/components/QueuedMessageList.d.ts +3 -0
  19. package/dist/components/QueuedMessageList.d.ts.map +1 -0
  20. package/dist/components/QueuedMessageList.js +17 -0
  21. package/dist/components/ReasoningDisplay.d.ts +1 -0
  22. package/dist/components/ReasoningDisplay.d.ts.map +1 -1
  23. package/dist/components/ReasoningDisplay.js +3 -3
  24. package/dist/components/ToolDisplay.js +1 -1
  25. package/dist/contexts/useChat.d.ts +7 -0
  26. package/dist/contexts/useChat.d.ts.map +1 -1
  27. package/dist/contexts/useChat.js +17 -1
  28. package/dist/hooks/useInputManager.d.ts +6 -5
  29. package/dist/hooks/useInputManager.d.ts.map +1 -1
  30. package/dist/hooks/useInputManager.js +18 -16
  31. package/dist/managers/inputHandlers.d.ts +7 -4
  32. package/dist/managers/inputHandlers.d.ts.map +1 -1
  33. package/dist/managers/inputHandlers.js +184 -46
  34. package/dist/managers/inputReducer.d.ts +18 -2
  35. package/dist/managers/inputReducer.d.ts.map +1 -1
  36. package/dist/managers/inputReducer.js +92 -3
  37. package/dist/utils/logger.d.ts.map +1 -1
  38. package/dist/utils/logger.js +13 -1
  39. package/package.json +2 -2
  40. package/src/components/ChatInterface.tsx +42 -15
  41. package/src/components/FileSelector.tsx +13 -3
  42. package/src/components/HelpView.tsx +1 -0
  43. package/src/components/HistorySearch.tsx +2 -2
  44. package/src/components/InputBox.tsx +21 -17
  45. package/src/components/MessageBlockItem.tsx +8 -3
  46. package/src/components/MessageList.tsx +16 -3
  47. package/src/components/QueuedMessageList.tsx +31 -0
  48. package/src/components/ReasoningDisplay.tsx +8 -2
  49. package/src/components/ToolDisplay.tsx +2 -2
  50. package/src/contexts/useChat.tsx +29 -1
  51. package/src/hooks/useInputManager.ts +22 -31
  52. package/src/managers/inputHandlers.ts +223 -60
  53. package/src/managers/inputReducer.ts +104 -6
  54. package/src/utils/logger.ts +15 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAYtE,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EA6IjC,CAAC"}
1
+ {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAatE,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAuKjC,CAAC"}
@@ -5,6 +5,7 @@ import { MessageList } from "./MessageList.js";
5
5
  import { InputBox } from "./InputBox.js";
6
6
  import { LoadingIndicator } from "./LoadingIndicator.js";
7
7
  import { TaskList } from "./TaskList.js";
8
+ import { QueuedMessageList } from "./QueuedMessageList.js";
8
9
  import { ConfirmationDetails } from "./ConfirmationDetails.js";
9
10
  import { ConfirmationSelector } from "./ConfirmationSelector.js";
10
11
  import { useChat } from "../contexts/useChat.js";
@@ -12,6 +13,7 @@ export const ChatInterface = () => {
12
13
  const { stdout } = useStdout();
13
14
  const [detailsHeight, setDetailsHeight] = useState(0);
14
15
  const [selectorHeight, setSelectorHeight] = useState(0);
16
+ const [dynamicBlocksHeight, setDynamicBlocksHeight] = useState(0);
15
17
  const [isConfirmationTooTall, setIsConfirmationTooTall] = useState(false);
16
18
  const { messages, isLoading, isCommandRunning, isCompressing, sendMessage, abortMessage, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, slashCommands, hasSlashCommand, isConfirmationVisible, confirmingTool, handleConfirmationDecision, handleConfirmationCancel: originalHandleConfirmationCancel, setWasLastDetailsTooTall, version, workdir, getModelConfig, } = useChat();
17
19
  const model = getModelConfig().model;
@@ -21,16 +23,33 @@ export const ChatInterface = () => {
21
23
  const handleSelectorHeightMeasured = useCallback((height) => {
22
24
  setSelectorHeight(height);
23
25
  }, []);
26
+ const handleDynamicBlocksHeightMeasured = useCallback((height) => {
27
+ setDynamicBlocksHeight(height);
28
+ }, []);
24
29
  useLayoutEffect(() => {
30
+ if (!isConfirmationVisible) {
31
+ setIsConfirmationTooTall(false);
32
+ setDetailsHeight(0);
33
+ setSelectorHeight(0);
34
+ setDynamicBlocksHeight(0);
35
+ return;
36
+ }
37
+ if (isConfirmationTooTall) {
38
+ return;
39
+ }
25
40
  const terminalHeight = stdout?.rows || 24;
26
- const totalHeight = detailsHeight + selectorHeight;
41
+ const totalHeight = detailsHeight + selectorHeight + dynamicBlocksHeight;
27
42
  if (totalHeight > terminalHeight) {
28
43
  setIsConfirmationTooTall(true);
29
44
  }
30
- else {
31
- setIsConfirmationTooTall(false);
32
- }
33
- }, [detailsHeight, selectorHeight, stdout?.rows]);
45
+ }, [
46
+ detailsHeight,
47
+ selectorHeight,
48
+ dynamicBlocksHeight,
49
+ stdout?.rows,
50
+ isConfirmationVisible,
51
+ isConfirmationTooTall,
52
+ ]);
34
53
  const handleConfirmationCancel = useCallback(() => {
35
54
  if (isConfirmationTooTall) {
36
55
  setWasLastDetailsTooTall((prev) => prev + 1);
@@ -55,7 +74,7 @@ export const ChatInterface = () => {
55
74
  ]);
56
75
  if (!sessionId)
57
76
  return null;
58
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(MessageList, { messages: messages, isExpanded: isExpanded, forceStatic: isConfirmationVisible && isConfirmationTooTall, version: version, workdir: workdir, model: model }), (isLoading || isCommandRunning || isCompressing) &&
77
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(MessageList, { messages: messages, isExpanded: isExpanded, forceStatic: isConfirmationVisible && isConfirmationTooTall, version: version, workdir: workdir, model: model, onDynamicBlocksHeightMeasured: handleDynamicBlocksHeightMeasured }), (isLoading || isCommandRunning || isCompressing) &&
59
78
  !isConfirmationVisible &&
60
- !isExpanded && (_jsx(LoadingIndicator, { isLoading: isLoading, isCommandRunning: isCommandRunning, isCompressing: isCompressing, latestTotalTokens: latestTotalTokens })), !isConfirmationVisible && !isExpanded && _jsx(TaskList, {}), isConfirmationVisible && (_jsxs(_Fragment, { children: [_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, isExpanded: isExpanded, onHeightMeasured: handleDetailsHeightMeasured, isStatic: isConfirmationTooTall }), _jsx(ConfirmationSelector, { toolName: confirmingTool.name, toolInput: confirmingTool.input, suggestedPrefix: confirmingTool.suggestedPrefix, hidePersistentOption: confirmingTool.hidePersistentOption, isExpanded: isExpanded, onDecision: wrappedHandleConfirmationDecision, onCancel: handleConfirmationCancel, onAbort: abortMessage, onHeightMeasured: handleSelectorHeightMeasured })] })), !isConfirmationVisible && !isExpanded && (_jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, sendMessage: sendMessage, abortMessage: abortMessage, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand }))] }));
79
+ !isExpanded && (_jsx(LoadingIndicator, { isLoading: isLoading, isCommandRunning: isCommandRunning, isCompressing: isCompressing, latestTotalTokens: latestTotalTokens })), !isConfirmationVisible && !isExpanded && _jsx(TaskList, {}), isConfirmationVisible && (_jsxs(_Fragment, { children: [_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, isExpanded: isExpanded, onHeightMeasured: handleDetailsHeightMeasured, isStatic: isConfirmationTooTall }), _jsx(ConfirmationSelector, { toolName: confirmingTool.name, toolInput: confirmingTool.input, suggestedPrefix: confirmingTool.suggestedPrefix, hidePersistentOption: confirmingTool.hidePersistentOption, isExpanded: isExpanded, onDecision: wrappedHandleConfirmationDecision, onCancel: handleConfirmationCancel, onAbort: abortMessage, onHeightMeasured: handleSelectorHeightMeasured })] })), !isConfirmationVisible && !isExpanded && (_jsxs(_Fragment, { children: [_jsx(QueuedMessageList, {}), _jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, sendMessage: sendMessage, abortMessage: abortMessage, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand })] }))] }));
61
80
  };
@@ -4,6 +4,7 @@ export { type FileItem } from "wave-agent-sdk";
4
4
  export interface FileSelectorProps {
5
5
  files: FileItem[];
6
6
  searchQuery: string;
7
+ isLoading?: boolean;
7
8
  onSelect: (filePath: string) => void;
8
9
  onCancel: () => void;
9
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FileSelector.d.ts","sourceRoot":"","sources":["../../src/components/FileSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAqHpD,CAAC"}
1
+ {"version":3,"file":"FileSelector.d.ts","sourceRoot":"","sources":["../../src/components/FileSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA8HpD,CAAC"}
@@ -1,7 +1,7 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
3
  import { Box, Text, useInput } from "ink";
4
- export const FileSelector = ({ files, searchQuery, onSelect, onCancel, }) => {
4
+ export const FileSelector = ({ files, searchQuery, isLoading = false, onSelect, onCancel, }) => {
5
5
  const [selectedIndex, setSelectedIndex] = useState(0);
6
6
  useInput((input, key) => {
7
7
  if (key.return || key.tab) {
@@ -24,7 +24,7 @@ export const FileSelector = ({ files, searchQuery, onSelect, onCancel, }) => {
24
24
  }
25
25
  });
26
26
  if (files.length === 0) {
27
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", borderBottom: false, borderLeft: false, borderRight: false, children: [_jsxs(Text, { color: "yellow", children: ["No files found for \"", searchQuery, "\""] }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
27
+ return (_jsx(Box, { flexDirection: "column", borderStyle: "single", borderColor: isLoading ? "cyan" : "yellow", borderBottom: false, borderLeft: false, borderRight: false, children: isLoading ? (_jsx(Text, { color: "cyan", bold: true, children: "Select File/Directory..." })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "yellow", children: ["No files found for \"", searchQuery, "\""] }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] })) }));
28
28
  }
29
29
  const maxDisplay = 10;
30
30
  // Calculate display window start and end positions
@@ -1 +1 @@
1
- {"version":3,"file":"HelpView.d.ts","sourceRoot":"","sources":["../../src/components/HelpView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAoK5C,CAAC"}
1
+ {"version":3,"file":"HelpView.d.ts","sourceRoot":"","sources":["../../src/components/HelpView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAqK5C,CAAC"}
@@ -46,6 +46,7 @@ export const HelpView = ({ onCancel, commands = [], }) => {
46
46
  { key: "Ctrl+T", description: "Toggle task list" },
47
47
  { key: "Ctrl+B", description: "Background current task" },
48
48
  { key: "Ctrl+V", description: "Paste image" },
49
+ { key: "Ctrl+J", description: "Newline" },
49
50
  { key: "Shift+Tab", description: "Cycle permission mode" },
50
51
  {
51
52
  key: "Esc",
@@ -1,7 +1,8 @@
1
1
  import React from "react";
2
+ import { type PromptEntry } from "wave-agent-sdk";
2
3
  export interface HistorySearchProps {
3
4
  searchQuery: string;
4
- onSelect: (prompt: string) => void;
5
+ onSelect: (entry: PromptEntry) => void;
5
6
  onCancel: () => void;
6
7
  }
7
8
  export declare const HistorySearch: React.FC<HistorySearchProps>;
@@ -1 +1 @@
1
- {"version":3,"file":"HistorySearch.d.ts","sourceRoot":"","sources":["../../src/components/HistorySearch.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAkKtD,CAAC"}
1
+ {"version":3,"file":"HistorySearch.d.ts","sourceRoot":"","sources":["../../src/components/HistorySearch.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAExE,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAkKtD,CAAC"}
@@ -27,7 +27,7 @@ export const HistorySearch = ({ searchQuery, onSelect, onCancel, }) => {
27
27
  if (key.return) {
28
28
  if (entriesRef.current.length > 0 &&
29
29
  selectedIndexRef.current < entriesRef.current.length) {
30
- onSelect(entriesRef.current[selectedIndexRef.current].prompt);
30
+ onSelect(entriesRef.current[selectedIndexRef.current]);
31
31
  }
32
32
  return;
33
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAczC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,mDACe,CAAC;AAEnD,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,KAC/C,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAE1B,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAClD;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAkO5C,CAAC"}
1
+ {"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAczC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,mDACe,CAAC;AAEnD,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,KAC/C,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAE1B,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAClD;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAsO5C,CAAC"}
@@ -14,14 +14,14 @@ import { useInputManager } from "../hooks/useInputManager.js";
14
14
  import { useChat } from "../contexts/useChat.js";
15
15
  export const INPUT_PLACEHOLDER_TEXT = "Type your message (use /help for more info)...";
16
16
  export const INPUT_PLACEHOLDER_TEXT_PREFIX = INPUT_PLACEHOLDER_TEXT.substring(0, 10);
17
- export const InputBox = ({ isLoading = false, isCommandRunning = false, sendMessage = () => { }, abortMessage = () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, }) => {
18
- const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, clearMessages, } = useChat();
17
+ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, }) => {
18
+ const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, clearMessages, sessionId, } = useChat();
19
19
  // Input manager with all input state and functionality (including images)
20
20
  const { inputText, cursorPosition,
21
21
  // Image management
22
22
  attachedImages, clearImages,
23
23
  // File selector
24
- showFileSelector, filteredFiles, fileSearchQuery: searchQuery, handleFileSelect, handleCancelFileSelect,
24
+ showFileSelector, filteredFiles, fileSearchQuery: searchQuery, isFileSearching, handleFileSelect, handleCancelFileSelect,
25
25
  // Command selector
26
26
  showCommandSelector, commandSearchQuery, handleCommandSelect, handleCommandInsert, handleCancelCommandSelect, handleHistorySearchSelect, handleCancelHistorySearch,
27
27
  // History search
@@ -40,6 +40,7 @@ export const InputBox = ({ isLoading = false, isCommandRunning = false, sendMess
40
40
  onBackgroundCurrentTask: backgroundCurrentTask,
41
41
  onPermissionModeChange: setChatPermissionMode,
42
42
  onClearMessages: clearMessages,
43
+ sessionId,
43
44
  });
44
45
  // Sync permission mode from useChat to InputManager
45
46
  useEffect(() => {
@@ -47,7 +48,7 @@ export const InputBox = ({ isLoading = false, isCommandRunning = false, sendMess
47
48
  }, [chatPermissionMode, setPermissionMode]);
48
49
  // Use the InputManager's unified input handler
49
50
  useInput(async (input, key) => {
50
- await handleInput(input, key, attachedImages, isLoading, isCommandRunning, clearImages);
51
+ await handleInput(input, key, attachedImages, clearImages);
51
52
  });
52
53
  const handleRewindCancel = () => {
53
54
  if (setShowRewindManager) {
@@ -56,6 +57,7 @@ export const InputBox = ({ isLoading = false, isCommandRunning = false, sendMess
56
57
  };
57
58
  const isPlaceholder = !inputText;
58
59
  const placeholderText = INPUT_PLACEHOLDER_TEXT;
60
+ const isShellCommand = inputText?.startsWith("!") && !inputText.includes("\n");
59
61
  // handleCommandSelectorInsert is already memoized in useInputManager, no need to wrap again
60
62
  // Split text into three parts: before cursor, cursor position, after cursor
61
63
  const displayText = isPlaceholder ? placeholderText : inputText;
@@ -83,9 +85,9 @@ export const InputBox = ({ isLoading = false, isCommandRunning = false, sendMess
83
85
  if (showStatusCommand) {
84
86
  return _jsx(StatusCommand, { onCancel: () => setShowStatusCommand(false) });
85
87
  }
86
- return (_jsxs(Box, { flexDirection: "column", children: [showFileSelector && (_jsx(FileSelector, { files: filteredFiles, searchQuery: searchQuery, onSelect: handleFileSelect, onCancel: handleCancelFileSelect })), showCommandSelector && (_jsx(CommandSelector, { searchQuery: commandSearchQuery, onSelect: handleCommandSelect, onInsert: handleCommandInsert, onCancel: handleCancelCommandSelect, commands: slashCommands })), showHistorySearch && (_jsx(HistorySearch, { searchQuery: historySearchQuery, onSelect: handleHistorySearchSelect, onCancel: handleCancelHistorySearch })), showBackgroundTaskManager && (_jsx(BackgroundTaskManager, { onCancel: () => setShowBackgroundTaskManager(false) })), showMcpManager && (_jsx(McpManager, { onCancel: () => setShowMcpManager(false), servers: mcpServers, onConnectServer: connectMcpServer, onDisconnectServer: disconnectMcpServer })), showBackgroundTaskManager ||
88
+ return (_jsxs(Box, { flexDirection: "column", children: [showFileSelector && (_jsx(FileSelector, { files: filteredFiles, searchQuery: searchQuery, isLoading: isFileSearching, onSelect: handleFileSelect, onCancel: handleCancelFileSelect })), showCommandSelector && (_jsx(CommandSelector, { searchQuery: commandSearchQuery, onSelect: handleCommandSelect, onInsert: handleCommandInsert, onCancel: handleCancelCommandSelect, commands: slashCommands })), showHistorySearch && (_jsx(HistorySearch, { searchQuery: historySearchQuery, onSelect: handleHistorySearchSelect, onCancel: handleCancelHistorySearch })), showBackgroundTaskManager && (_jsx(BackgroundTaskManager, { onCancel: () => setShowBackgroundTaskManager(false) })), showMcpManager && (_jsx(McpManager, { onCancel: () => setShowMcpManager(false), servers: mcpServers, onConnectServer: connectMcpServer, onDisconnectServer: disconnectMcpServer })), showBackgroundTaskManager ||
87
89
  showMcpManager ||
88
90
  showRewindManager ||
89
91
  showHelp ||
90
- showStatusCommand || (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { borderStyle: "single", borderColor: "gray", borderLeft: false, borderRight: false, children: _jsx(Text, { color: isPlaceholder ? "gray" : "white", children: shouldShowCursor ? (_jsxs(_Fragment, { children: [beforeCursor, _jsx(Text, { backgroundColor: "white", color: "black", children: atCursor }), afterCursor] })) : (displayText) }) }), _jsx(Box, { paddingRight: 1, justifyContent: "space-between", width: "100%", children: _jsxs(Text, { color: "gray", children: ["Mode:", " ", _jsx(Text, { color: permissionMode === "plan" ? "yellow" : "cyan", children: permissionMode }), " ", "(Shift+Tab to cycle)"] }) })] }))] }));
92
+ showStatusCommand || (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { borderStyle: "single", borderColor: "gray", borderLeft: false, borderRight: false, children: _jsx(Text, { color: isPlaceholder ? "gray" : "white", children: shouldShowCursor ? (_jsxs(_Fragment, { children: [beforeCursor, _jsx(Text, { backgroundColor: "white", color: "black", children: atCursor }), afterCursor] })) : (displayText) }) }), _jsx(Box, { paddingRight: 1, justifyContent: "space-between", width: "100%", children: isShellCommand ? (_jsxs(Text, { color: "gray", children: ["Shell: ", _jsx(Text, { color: "yellow", children: "Run shell command" })] })) : (_jsxs(Text, { color: "gray", children: ["Mode:", " ", _jsx(Text, { color: permissionMode === "plan" ? "yellow" : "cyan", children: permissionMode }), " ", "(Shift+Tab to cycle)"] })) })] }))] }));
91
93
  };
@@ -1 +1 @@
1
- {"version":3,"file":"MessageBlockItem.d.ts","sourceRoot":"","sources":["../../src/components/MessageBlockItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAQ5D,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,gBAAgB,GAAI,6CAK9B,qBAAqB,4CA4DvB,CAAC"}
1
+ {"version":3,"file":"MessageBlockItem.d.ts","sourceRoot":"","sources":["../../src/components/MessageBlockItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAQ5D,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,gBAAgB,GAAI,6CAK9B,qBAAqB,4CAiEvB,CAAC"}
@@ -7,5 +7,5 @@ import { CompressDisplay } from "./CompressDisplay.js";
7
7
  import { ReasoningDisplay } from "./ReasoningDisplay.js";
8
8
  import { Markdown } from "./Markdown.js";
9
9
  export const MessageBlockItem = ({ block, message, isExpanded, paddingTop = 0, }) => {
10
- return (_jsxs(Box, { flexDirection: "column", paddingTop: paddingTop, children: [block.type === "text" && block.content.trim() && (_jsxs(Box, { children: [block.customCommandContent && (_jsxs(Text, { color: "cyan", bold: true, children: ["$", " "] })), block.source === MessageSource.HOOK && (_jsxs(Text, { color: "magenta", bold: true, children: ["~", " "] })), message.role === "user" ? (_jsx(Text, { backgroundColor: "gray", color: "white", children: block.content })) : (_jsx(Markdown, { children: block.content }))] })), block.type === "error" && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["Error: ", block.content] }) })), block.type === "bang" && (_jsx(BangDisplay, { block: block, isExpanded: isExpanded })), block.type === "tool" && (_jsx(ToolDisplay, { block: block, isExpanded: isExpanded })), block.type === "image" && (_jsxs(Box, { children: [_jsx(Text, { color: "magenta", bold: true, children: "# Image" }), block.imageUrls && block.imageUrls.length > 0 && (_jsxs(Text, { color: "gray", dimColor: true, children: [" ", "(", block.imageUrls.length, ")"] }))] })), block.type === "compress" && (_jsx(CompressDisplay, { block: block, isExpanded: isExpanded })), block.type === "reasoning" && _jsx(ReasoningDisplay, { block: block })] }));
10
+ return (_jsxs(Box, { flexDirection: "column", paddingTop: paddingTop, children: [block.type === "text" && block.content.trim() && (_jsxs(Box, { children: [block.customCommandContent && (_jsxs(Text, { color: "cyan", bold: true, children: ["$", " "] })), block.source === MessageSource.HOOK && (_jsxs(Text, { color: "magenta", bold: true, children: ["~", " "] })), message.role === "user" || isExpanded ? (_jsx(Text, { backgroundColor: message.role === "user" ? "gray" : undefined, color: "white", children: block.content })) : (_jsx(Markdown, { children: block.content }))] })), block.type === "error" && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["Error: ", block.content] }) })), block.type === "bang" && (_jsx(BangDisplay, { block: block, isExpanded: isExpanded })), block.type === "tool" && (_jsx(ToolDisplay, { block: block, isExpanded: isExpanded })), block.type === "image" && (_jsxs(Box, { children: [_jsx(Text, { color: "magenta", bold: true, children: "# Image" }), block.imageUrls && block.imageUrls.length > 0 && (_jsxs(Text, { color: "gray", dimColor: true, children: [" ", "(", block.imageUrls.length, ")"] }))] })), block.type === "compress" && (_jsx(CompressDisplay, { block: block, isExpanded: isExpanded })), block.type === "reasoning" && (_jsx(ReasoningDisplay, { block: block, isExpanded: isExpanded }))] }));
11
11
  };
@@ -7,6 +7,7 @@ export interface MessageListProps {
7
7
  version?: string;
8
8
  workdir?: string;
9
9
  model?: string;
10
+ onDynamicBlocksHeightMeasured?: (height: number) => void;
10
11
  }
11
- export declare const MessageList: React.MemoExoticComponent<({ messages, isExpanded, forceStatic, version, workdir, model, }: MessageListProps) => import("react/jsx-runtime").JSX.Element>;
12
+ export declare const MessageList: React.MemoExoticComponent<({ messages, isExpanded, forceStatic, version, workdir, model, onDynamicBlocksHeightMeasured, }: MessageListProps) => import("react/jsx-runtime").JSX.Element>;
12
13
  //# sourceMappingURL=MessageList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAG9C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,WAAW,8FAQnB,gBAAgB,6CAmGpB,CAAC"}
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkC,MAAM,OAAO,CAAC;AAGvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAG9C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1D;AAED,eAAO,MAAM,WAAW,6HASnB,gBAAgB,6CA8GpB,CAAC"}
@@ -1,9 +1,9 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import React from "react";
2
+ import React, { useLayoutEffect, useRef } from "react";
3
3
  import os from "os";
4
- import { Box, Text, Static } from "ink";
4
+ import { Box, Text, Static, measureElement } from "ink";
5
5
  import { MessageBlockItem } from "./MessageBlockItem.js";
6
- export const MessageList = React.memo(({ messages, isExpanded = false, forceStatic = false, version, workdir, model, }) => {
6
+ export const MessageList = React.memo(({ messages, isExpanded = false, forceStatic = false, version, workdir, model, onDynamicBlocksHeightMeasured, }) => {
7
7
  const welcomeMessage = (_jsxs(Box, { flexDirection: "column", paddingTop: 1, children: [_jsxs(Text, { color: "gray", children: ["WAVE", version ? ` v${version}` : "", model ? ` • ${model}` : ""] }), workdir && (_jsx(Text, { color: "gray", wrap: "truncate-middle", children: workdir.replace(os.homedir(), "~") }))] }));
8
8
  // Limit messages when expanded to prevent long rendering times
9
9
  const maxExpandedMessages = 20;
@@ -35,6 +35,16 @@ export const MessageList = React.memo(({ messages, isExpanded = false, forceStat
35
35
  });
36
36
  const staticBlocks = blocksWithStatus.filter((b) => !b.isDynamic);
37
37
  const dynamicBlocks = blocksWithStatus.filter((b) => b.isDynamic);
38
+ const dynamicBlocksRef = useRef(null);
39
+ useLayoutEffect(() => {
40
+ if (dynamicBlocksRef.current) {
41
+ const { height } = measureElement(dynamicBlocksRef.current);
42
+ onDynamicBlocksHeightMeasured?.(height);
43
+ }
44
+ else {
45
+ onDynamicBlocksHeightMeasured?.(0);
46
+ }
47
+ }, [dynamicBlocks, isExpanded, onDynamicBlocksHeightMeasured]);
38
48
  const staticItems = [
39
49
  { isWelcome: true, key: "welcome", block: undefined, message: undefined },
40
50
  ...staticBlocks.map((b) => ({ ...b, isWelcome: false })),
@@ -44,7 +54,7 @@ export const MessageList = React.memo(({ messages, isExpanded = false, forceStat
44
54
  return (_jsx(React.Fragment, { children: welcomeMessage }, item.key));
45
55
  }
46
56
  return (_jsx(MessageBlockItem, { block: item.block, message: item.message, isExpanded: isExpanded, paddingTop: 1 }, item.key));
47
- } })), dynamicBlocks.length > 0 && (_jsx(Box, { flexDirection: "column", children: dynamicBlocks.map((item) => (_jsx(MessageBlockItem, { block: item.block, message: item.message, isExpanded: isExpanded, paddingTop: 1 }, item.key))) }))] }));
57
+ } })), dynamicBlocks.length > 0 && (_jsx(Box, { ref: dynamicBlocksRef, flexDirection: "column", children: dynamicBlocks.map((item) => (_jsx(MessageBlockItem, { block: item.block, message: item.message, isExpanded: isExpanded, paddingTop: 1 }, item.key))) }))] }));
48
58
  });
49
59
  // Add display name for debugging
50
60
  MessageList.displayName = "MessageList";
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ export declare const QueuedMessageList: React.FC;
3
+ //# sourceMappingURL=QueuedMessageList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueuedMessageList.d.ts","sourceRoot":"","sources":["../../src/components/QueuedMessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EA0BrC,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useChat } from "../contexts/useChat.js";
3
+ import { Box, Text } from "ink";
4
+ export const QueuedMessageList = () => {
5
+ const { queuedMessages = [] } = useChat();
6
+ if (queuedMessages.length === 0) {
7
+ return null;
8
+ }
9
+ return (_jsx(Box, { flexDirection: "column", children: queuedMessages.map((msg, index) => {
10
+ const content = msg.content.trim();
11
+ const hasImages = msg.images && msg.images.length > 0;
12
+ const displayText = content || (hasImages ? "[Images]" : "");
13
+ return (_jsx(Box, { children: _jsx(Text, { color: "gray", italic: true, children: displayText.length > 60
14
+ ? `${displayText.substring(0, 57)}...`
15
+ : displayText }) }, index));
16
+ }) }));
17
+ };
@@ -2,6 +2,7 @@ import React from "react";
2
2
  import type { ReasoningBlock } from "wave-agent-sdk";
3
3
  interface ReasoningDisplayProps {
4
4
  block: ReasoningBlock;
5
+ isExpanded?: boolean;
5
6
  }
6
7
  export declare const ReasoningDisplay: React.FC<ReasoningDisplayProps>;
7
8
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"ReasoningDisplay.d.ts","sourceRoot":"","sources":["../../src/components/ReasoningDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD,UAAU,qBAAqB;IAC7B,KAAK,EAAE,cAAc,CAAC;CACvB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAuB5D,CAAC"}
1
+ {"version":3,"file":"ReasoningDisplay.d.ts","sourceRoot":"","sources":["../../src/components/ReasoningDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD,UAAU,qBAAqB;IAC7B,KAAK,EAAE,cAAc,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA4B5D,CAAC"}
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Box } from "ink";
2
+ import { Box, Text } from "ink";
3
3
  import { Markdown } from "./Markdown.js";
4
- export const ReasoningDisplay = ({ block, }) => {
4
+ export const ReasoningDisplay = ({ block, isExpanded = false, }) => {
5
5
  const { content } = block;
6
6
  if (!content || !content.trim()) {
7
7
  return null;
8
8
  }
9
- return (_jsx(Box, { borderRight: false, borderTop: false, borderBottom: false, borderStyle: "classic", borderColor: "blue", paddingLeft: 1, children: _jsx(Box, { flexDirection: "column", children: _jsx(Markdown, { children: content }) }) }));
9
+ return (_jsx(Box, { borderRight: false, borderTop: false, borderBottom: false, borderStyle: "classic", borderColor: "blue", paddingLeft: 1, children: _jsx(Box, { flexDirection: "column", children: isExpanded ? (_jsx(Text, { color: "white", children: content })) : (_jsx(Markdown, { children: content })) }) }));
10
10
  };
@@ -40,5 +40,5 @@ export const ToolDisplay = ({ block, isExpanded = false, }) => {
40
40
  return null;
41
41
  };
42
42
  const shortResult = getShortResult();
43
- return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Box, { flexShrink: 0, children: [_jsx(Text, { color: getStatusColor(), children: "\u25CF " }), _jsx(Text, { color: "white", children: toolName })] }), !isExpanded && compactParams && (_jsxs(Text, { color: "gray", children: [" ", compactParams] })), hasImages() && _jsxs(Text, { color: "blue", children: [" ", getImageIndicator()] })] }), !isExpanded && shortResult && !error && (_jsx(Box, { paddingLeft: 2, borderLeft: true, borderColor: "gray", flexDirection: "column", children: shortResult.split("\n").map((line, index) => (_jsx(Text, { color: "gray", children: line }, index))) })), isExpanded && parameters && (_jsxs(Box, { paddingLeft: 2, borderLeft: true, borderColor: "gray", flexDirection: "column", children: [_jsx(Text, { color: "cyan", bold: true, children: "Parameters:" }), _jsx(Text, { color: "gray", children: parameters })] })), isExpanded && result && (_jsx(Box, { flexDirection: "column", children: _jsxs(Box, { paddingLeft: 2, borderLeft: true, borderColor: "green", flexDirection: "column", children: [_jsx(Text, { color: "cyan", bold: true, children: "Result:" }), _jsx(Text, { color: "white", children: result })] }) })), error && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["Error: ", typeof error === "string" ? error : String(error)] }) })), stage === "end" && success && (_jsx(DiffDisplay, { toolName: name, parameters: parameters, startLineNumber: block.startLineNumber }))] }));
43
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Box, { flexShrink: 0, children: [_jsx(Text, { color: getStatusColor(), children: "\u25CF " }), _jsx(Text, { color: "white", children: toolName })] }), !isExpanded && compactParams && (_jsxs(Text, { color: "gray", children: [" ", compactParams] })), hasImages() && _jsxs(Text, { color: "blue", children: [" ", getImageIndicator()] })] }), !isExpanded && shortResult && !error && (_jsx(Box, { paddingLeft: 2, borderLeft: true, borderColor: "gray", flexDirection: "column", children: shortResult.split("\n").map((line, index) => (_jsx(Text, { color: "gray", children: line }, index))) })), isExpanded && parameters && (_jsxs(Box, { paddingLeft: 2, borderLeft: true, borderColor: "gray", flexDirection: "column", children: [_jsx(Text, { color: "cyan", bold: true, children: "Parameters:" }), _jsx(Text, { color: "gray", children: parameters })] })), isExpanded && result && (_jsx(Box, { flexDirection: "column", children: _jsxs(Box, { paddingLeft: 2, borderLeft: true, borderColor: "green", flexDirection: "column", children: [_jsx(Text, { color: "cyan", bold: true, children: "Result:" }), _jsx(Text, { color: "white", children: result })] }) })), error && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["Error: ", typeof error === "string" ? error : String(error)] }) })), !isExpanded && stage === "end" && success && (_jsx(DiffDisplay, { toolName: name, parameters: parameters, startLineNumber: block.startLineNumber }))] }));
44
44
  };
@@ -9,6 +9,13 @@ export interface ChatContextType {
9
9
  isExpanded: boolean;
10
10
  isTaskListVisible: boolean;
11
11
  setIsTaskListVisible: (visible: boolean) => void;
12
+ queuedMessages: Array<{
13
+ content: string;
14
+ images?: Array<{
15
+ path: string;
16
+ mimeType: string;
17
+ }>;
18
+ }>;
12
19
  sessionId: string;
13
20
  sendMessage: (content: string, images?: Array<{
14
21
  path: string;
@@ -1 +1 @@
1
- {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/contexts/useChat.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/contexts/useChat.tsx"],"names":[],"mappings":"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"}
@@ -22,6 +22,7 @@ export const ChatProvider = ({ children, bypassPermissions, pluginDirs, tools, w
22
22
  isExpandedRef.current = isExpanded;
23
23
  }, [isExpanded]);
24
24
  const [isTaskListVisible, setIsTaskListVisible] = useState(true);
25
+ const [queuedMessages, setQueuedMessages] = useState([]);
25
26
  // AI State
26
27
  const [messages, setMessages] = useState([]);
27
28
  const [isLoading, setIsLoading] = useState(false);
@@ -203,6 +204,10 @@ export const ChatProvider = ({ children, bypassPermissions, pluginDirs, tools, w
203
204
  const hasImageAttachments = images && images.length > 0;
204
205
  if (!hasTextContent && !hasImageAttachments)
205
206
  return;
207
+ if (isLoading || isCommandRunning) {
208
+ setQueuedMessages((prev) => [...prev, { content, images }]);
209
+ return;
210
+ }
206
211
  try {
207
212
  // Handle bash mode - check if it's a bash command (starts with ! and only one line)
208
213
  if (content.startsWith("!") && !content.includes("\n")) {
@@ -238,12 +243,22 @@ export const ChatProvider = ({ children, bypassPermissions, pluginDirs, tools, w
238
243
  console.error("Failed to send message:", error);
239
244
  // Loading state will be automatically updated by the useEffect that watches messages
240
245
  }
241
- }, []);
246
+ }, [isLoading, isCommandRunning]);
247
+ // Process queued messages when idle
248
+ useEffect(() => {
249
+ if (!isLoading && !isCommandRunning && queuedMessages.length > 0) {
250
+ const nextMessage = queuedMessages[0];
251
+ setQueuedMessages((prev) => prev.slice(1));
252
+ sendMessage(nextMessage.content, nextMessage.images);
253
+ }
254
+ }, [isLoading, isCommandRunning, queuedMessages, sendMessage]);
242
255
  // Unified interrupt method, interrupt both AI messages and command execution
243
256
  const abortMessage = useCallback(() => {
257
+ setQueuedMessages([]);
244
258
  agentRef.current?.abortMessage();
245
259
  }, []);
246
260
  const clearMessages = useCallback(() => {
261
+ setQueuedMessages([]);
247
262
  agentRef.current?.clearMessages();
248
263
  }, []);
249
264
  // Permission management methods
@@ -390,6 +405,7 @@ export const ChatProvider = ({ children, bypassPermissions, pluginDirs, tools, w
390
405
  isExpanded,
391
406
  isTaskListVisible,
392
407
  setIsTaskListVisible,
408
+ queuedMessages,
393
409
  sessionId,
394
410
  sendMessage,
395
411
  abortMessage,
@@ -1,12 +1,13 @@
1
1
  import { Key } from "ink";
2
2
  import { InputManagerCallbacks } from "../managers/inputReducer.js";
3
- import { PermissionMode } from "wave-agent-sdk";
3
+ import { PermissionMode, PromptEntry } from "wave-agent-sdk";
4
4
  export declare const useInputManager: (callbacks?: Partial<InputManagerCallbacks>) => {
5
5
  inputText: string;
6
6
  cursorPosition: number;
7
7
  showFileSelector: boolean;
8
8
  filteredFiles: import("wave-agent-sdk").FileItem[];
9
9
  fileSearchQuery: string;
10
+ isFileSearching: boolean;
10
11
  atPosition: number;
11
12
  showCommandSelector: boolean;
12
13
  commandSearchQuery: string;
@@ -46,9 +47,9 @@ export declare const useInputManager: (callbacks?: Partial<InputManagerCallbacks
46
47
  handleCancelCommandSelect: () => void;
47
48
  updateCommandSearchQuery: (query: string) => void;
48
49
  checkForSlashDeletion: (cursorPos: number) => boolean;
49
- handleHistorySearchSelect: (prompt: string) => void;
50
+ handleHistorySearchSelect: (entry: PromptEntry) => void;
50
51
  handleCancelHistorySearch: () => void;
51
- handleSpecialCharInput: (char: string) => void;
52
+ processSelectorInput: (char: string) => void;
52
53
  setShowBackgroundTaskManager: (show: boolean) => void;
53
54
  setShowMcpManager: (show: boolean) => void;
54
55
  setShowRewindManager: (show: boolean) => void;
@@ -64,14 +65,14 @@ export declare const useInputManager: (callbacks?: Partial<InputManagerCallbacks
64
65
  id: number;
65
66
  path: string;
66
67
  mimeType: string;
67
- }>, isLoading?: boolean, isCommandRunning?: boolean) => Promise<void>;
68
+ }>) => Promise<void>;
68
69
  expandLongTextPlaceholders: (text: string) => string;
69
70
  clearLongTextMap: () => void;
70
71
  handleInput: (input: string, key: Key, attachedImages: Array<{
71
72
  id: number;
72
73
  path: string;
73
74
  mimeType: string;
74
- }>, isLoading?: boolean, isCommandRunning?: boolean, clearImages?: () => void) => Promise<boolean>;
75
+ }>, clearImages?: () => void) => Promise<boolean>;
75
76
  setInputText: (text: string) => void;
76
77
  setCursorPosition: (position: number) => void;
77
78
  manager: null;
@@ -1 +1 @@
1
- {"version":3,"file":"useInputManager.d.ts","sourceRoot":"","sources":["../../src/hooks/useInputManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAGL,qBAAqB,EACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAkC,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhF,eAAO,MAAM,eAAe,GAC1B,YAAW,OAAO,CAAC,qBAAqB,CAAM;;;;;;;;;;;;;;;;;;;;+BAsIA,MAAM;;;;;qCAoBA,MAAM;iCAIV,MAAM;;;;;mCAaJ,MAAM;oCAIL,MAAM;wCAIF,MAAM;mCAIX,MAAM;;;;mCASN,MAAM;;;;;sCAgCH,MAAM;uCAIL,MAAM;wCAQL,MAAM;;mCAUX,MAAM;yCAkBA,OAAO;8BAIlB,OAAO;iCAIJ,OAAO;wBAIhB,OAAO;iCAIE,OAAO;8BAIV,cAAc;0BAKlB,MAAM,YAAY,MAAM;2BAIvB,MAAM;;;8BAYH,MAAM;mCAW/B,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,cAC1D,OAAO,qBACA,OAAO;uCAcyB,MAAM;;yBAajD,MAAM,OACR,GAAG,kBACQ,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,cAC1D,OAAO,qBACA,OAAO,gBACX,MAAM,IAAI;yBA9FY,MAAM;kCAIG,MAAM;;CA2LxD,CAAC"}
1
+ {"version":3,"file":"useInputManager.d.ts","sourceRoot":"","sources":["../../src/hooks/useInputManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAGL,qBAAqB,EACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAEL,cAAc,EACd,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAGxB,eAAO,MAAM,eAAe,GAC1B,YAAW,OAAO,CAAC,qBAAqB,CAAM;;;;;;;;;;;;;;;;;;;;;+BAsIA,MAAM;;;;;qCAoBA,MAAM;iCAIV,MAAM;;;;;mCAaJ,MAAM;oCAIL,MAAM;wCAIF,MAAM;mCAIX,MAAM;;;;mCASN,MAAM;;;;;sCAkCH,MAAM;uCAIL,MAAM;uCAQN,WAAW;;iCAQjB,MAAM;yCAYE,OAAO;8BAIlB,OAAO;iCAIJ,OAAO;wBAIhB,OAAO;iCAIE,OAAO;8BAIV,cAAc;0BAKlB,MAAM,YAAY,MAAM;2BAIvB,MAAM;;;8BAYH,MAAM;mCAW/B,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;uCAYnB,MAAM;;yBAajD,MAAM,OACR,GAAG,kBACQ,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,gBACvD,MAAM,IAAI;yBAxFY,MAAM;kCAIG,MAAM;;CAoLxD,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { useEffect, useReducer, useCallback, useRef } from "react";
2
2
  import { inputReducer, initialState, } from "../managers/inputReducer.js";
3
- import { searchFiles as searchFilesUtil } from "wave-agent-sdk";
3
+ import { searchFiles as searchFilesUtil, } from "wave-agent-sdk";
4
4
  import * as handlers from "../managers/inputHandlers.js";
5
5
  export const useInputManager = (callbacks = {}) => {
6
6
  const [state, dispatch] = useReducer(inputReducer, initialState);
@@ -25,7 +25,9 @@ export const useInputManager = (callbacks = {}) => {
25
25
  // Handle debounced file search
26
26
  useEffect(() => {
27
27
  if (state.showFileSelector) {
28
- const debounceDelay = parseInt(process.env.FILE_SELECTOR_DEBOUNCE_MS || "300", 10);
28
+ const debounceDelay = state.fileSearchQuery === ""
29
+ ? 0
30
+ : parseInt(process.env.FILE_SELECTOR_DEBOUNCE_MS || "300", 10);
29
31
  const timer = setTimeout(async () => {
30
32
  try {
31
33
  const fileItems = await searchFilesUtil(state.fileSearchQuery);
@@ -47,7 +49,7 @@ export const useInputManager = (callbacks = {}) => {
47
49
  const processedInput = stateRef.current.pasteBuffer.replace(/\r/g, "\n");
48
50
  dispatch({ type: "COMPRESS_AND_INSERT_TEXT", payload: processedInput });
49
51
  dispatch({ type: "END_PASTE" });
50
- callbacksRef.current.onResetHistoryNavigation?.();
52
+ dispatch({ type: "RESET_HISTORY_NAVIGATION" });
51
53
  }, pasteDebounceDelay);
52
54
  return () => clearTimeout(timer);
53
55
  }
@@ -135,9 +137,10 @@ export const useInputManager = (callbacks = {}) => {
135
137
  const handleCommandInsert = useCallback((command) => {
136
138
  const currentState = stateRef.current;
137
139
  if (currentState.slashPosition >= 0) {
140
+ const wordEnd = handlers.getWordEnd(currentState.inputText, currentState.slashPosition);
138
141
  const beforeSlash = currentState.inputText.substring(0, currentState.slashPosition);
139
- const afterQuery = currentState.inputText.substring(currentState.cursorPosition);
140
- const newInput = beforeSlash + `/${command} ` + afterQuery;
142
+ const afterWord = currentState.inputText.substring(wordEnd);
143
+ const newInput = beforeSlash + `/${command} ` + afterWord;
141
144
  const newCursorPosition = beforeSlash.length + command.length + 2;
142
145
  dispatch({ type: "SET_INPUT_TEXT", payload: newInput });
143
146
  dispatch({ type: "SET_CURSOR_POSITION", payload: newCursorPosition });
@@ -160,16 +163,14 @@ export const useInputManager = (callbacks = {}) => {
160
163
  const checkForSlashDeletion = useCallback((cursorPos) => {
161
164
  return handlers.checkForSlashDeletion(stateRef.current, dispatch, cursorPos);
162
165
  }, []);
163
- const handleHistorySearchSelect = useCallback((prompt) => {
164
- dispatch({ type: "SET_INPUT_TEXT", payload: prompt });
165
- dispatch({ type: "SET_CURSOR_POSITION", payload: prompt.length });
166
- dispatch({ type: "CANCEL_HISTORY_SEARCH" });
166
+ const handleHistorySearchSelect = useCallback((entry) => {
167
+ dispatch({ type: "SELECT_HISTORY_ENTRY", payload: entry });
167
168
  }, []);
168
169
  const handleCancelHistorySearch = useCallback(() => {
169
170
  dispatch({ type: "CANCEL_HISTORY_SEARCH" });
170
171
  }, []);
171
- const handleSpecialCharInput = useCallback((char) => {
172
- handlers.handleSpecialCharInput(stateRef.current, dispatch, char, stateRef.current.cursorPosition, stateRef.current.inputText);
172
+ const processSelectorInput = useCallback((char) => {
173
+ handlers.processSelectorInput(stateRef.current, dispatch, char);
173
174
  }, []);
174
175
  const setInputText = useCallback((text) => {
175
176
  dispatch({ type: "SET_INPUT_TEXT", payload: text });
@@ -211,8 +212,8 @@ export const useInputManager = (callbacks = {}) => {
211
212
  const handlePasteInput = useCallback((input) => {
212
213
  handlers.handlePasteInput(stateRef.current, dispatch, callbacksRef.current, input);
213
214
  }, []);
214
- const handleSubmit = useCallback(async (attachedImages, isLoading = false, isCommandRunning = false) => {
215
- await handlers.handleSubmit(stateRef.current, dispatch, callbacksRef.current, isLoading, isCommandRunning, attachedImages);
215
+ const handleSubmit = useCallback(async (attachedImages) => {
216
+ await handlers.handleSubmit(stateRef.current, dispatch, callbacksRef.current, attachedImages);
216
217
  }, []);
217
218
  const expandLongTextPlaceholders = useCallback((text) => {
218
219
  return handlers.expandLongTextPlaceholders(text, stateRef.current.longTextMap);
@@ -220,8 +221,8 @@ export const useInputManager = (callbacks = {}) => {
220
221
  const clearLongTextMap = useCallback(() => {
221
222
  dispatch({ type: "CLEAR_LONG_TEXT_MAP" });
222
223
  }, []);
223
- const handleInput = useCallback(async (input, key, attachedImages, isLoading = false, isCommandRunning = false, clearImages) => {
224
- return await handlers.handleInput(stateRef.current, dispatch, callbacksRef.current, input, key, isLoading, isCommandRunning, clearImages);
224
+ const handleInput = useCallback(async (input, key, attachedImages, clearImages) => {
225
+ return await handlers.handleInput(stateRef.current, dispatch, callbacksRef.current, input, key, clearImages);
225
226
  }, []);
226
227
  return {
227
228
  // State
@@ -230,6 +231,7 @@ export const useInputManager = (callbacks = {}) => {
230
231
  showFileSelector: state.showFileSelector,
231
232
  filteredFiles: state.filteredFiles,
232
233
  fileSearchQuery: state.fileSearchQuery,
234
+ isFileSearching: state.isFileSearching,
233
235
  atPosition: state.atPosition,
234
236
  showCommandSelector: state.showCommandSelector,
235
237
  commandSearchQuery: state.commandSearchQuery,
@@ -267,7 +269,7 @@ export const useInputManager = (callbacks = {}) => {
267
269
  handleHistorySearchSelect,
268
270
  handleCancelHistorySearch,
269
271
  // Special handling
270
- handleSpecialCharInput,
272
+ processSelectorInput,
271
273
  // Bash/MCP Manager
272
274
  setShowBackgroundTaskManager,
273
275
  setShowMcpManager,