wave-code 0.12.6 → 0.12.8

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.
@@ -5,5 +5,5 @@ export const BtwDisplay = ({ btwState }) => {
5
5
  if (!btwState.isActive) {
6
6
  return null;
7
7
  }
8
- return (_jsxs(Box, { flexDirection: "column", marginTop: 0, marginBottom: 1, children: [btwState.question && (_jsxs(Box, { children: [_jsx(Text, { color: btwState.isLoading ? "yellow" : "green", children: "\u25CF " }), _jsxs(Text, { italic: true, color: "gray", children: ["/btw ", btwState.question] })] })), btwState.answer && (_jsx(Box, { flexDirection: "column", children: _jsx(Markdown, { children: btwState.answer }) }))] }));
8
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 0, marginBottom: 0, children: [btwState.question && (_jsxs(Box, { children: [_jsx(Text, { color: btwState.isLoading ? "yellow" : "green", children: "/ " }), _jsxs(Text, { italic: true, color: "gray", children: ["btw ", btwState.question] })] })), btwState.answer && (_jsx(Box, { flexDirection: "column", children: _jsx(Markdown, { children: btwState.answer }) }))] }));
9
9
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAc3D,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAiIjC,CAAC"}
1
+ {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAa3D,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EA+HjC,CAAC"}
@@ -2,7 +2,6 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
2
2
  import { useState, useRef, useEffect } from "react";
3
3
  import { Box, useStdout, measureElement, Static } from "ink";
4
4
  import { MessageList } from "./MessageList.js";
5
- import { BtwDisplay } from "./BtwDisplay.js";
6
5
  import { InputBox } from "./InputBox.js";
7
6
  import { LoadingIndicator } from "./LoadingIndicator.js";
8
7
  import { TaskList } from "./TaskList.js";
@@ -11,7 +10,7 @@ import { ConfirmationDetails } from "./ConfirmationDetails.js";
11
10
  import { ConfirmationSelector } from "./ConfirmationSelector.js";
12
11
  import { useChat } from "../contexts/useChat.js";
13
12
  export const ChatInterface = () => {
14
- const { messages, isLoading, isCommandRunning, isCompressing, sendMessage, abortMessage, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, slashCommands, hasSlashCommand, isConfirmationVisible, hasPendingConfirmations, confirmingTool, handleConfirmationDecision, handleConfirmationCancel, version, workdir, btwState, remountKey, requestRemount, } = useChat();
13
+ const { messages, isLoading, isCommandRunning, isCompressing, sendMessage, abortMessage, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, slashCommands, hasSlashCommand, isConfirmationVisible, hasPendingConfirmations, confirmingTool, handleConfirmationDecision, handleConfirmationCancel, version, workdir, remountKey, requestRemount, } = useChat();
15
14
  const displayMessages = messages;
16
15
  const [forceStatic, setForceStatic] = useState(false);
17
16
  const { stdout } = useStdout();
@@ -38,5 +37,5 @@ export const ChatInterface = () => {
38
37
  ]);
39
38
  if (!sessionId)
40
39
  return null;
41
- return (_jsxs(Box, { ref: chatInterfaceRef, flexDirection: "column", children: [_jsx(MessageList, { messages: displayMessages, isExpanded: isExpanded, version: version, workdir: workdir, forceStatic: forceStatic }, remountKey), !isConfirmationVisible && !isExpanded && (_jsxs(_Fragment, { children: [_jsx(BtwDisplay, { btwState: btwState }), (isLoading || isCommandRunning || isCompressing) && (_jsx(LoadingIndicator, { isLoading: isLoading, isCommandRunning: isCommandRunning, isCompressing: isCompressing, latestTotalTokens: latestTotalTokens })), _jsx(TaskList, {}), _jsx(QueuedMessageList, {}), _jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, sendMessage: sendMessage, abortMessage: abortMessage, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand })] })), isConfirmationVisible && (_jsxs(_Fragment, { children: [forceStatic ? (_jsx(Static, { items: [{ key: "confirmation-details" }], children: () => (_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded })) })) : (_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded })), _jsx(ConfirmationSelector, { toolName: confirmingTool.name, toolInput: confirmingTool.input, suggestedPrefix: confirmingTool.suggestedPrefix, hidePersistentOption: confirmingTool.hidePersistentOption, isExpanded: isExpanded, onDecision: handleConfirmationDecision, onCancel: handleConfirmationCancel, onAbort: abortMessage })] }))] }));
40
+ return (_jsxs(Box, { ref: chatInterfaceRef, flexDirection: "column", children: [_jsx(MessageList, { messages: displayMessages, isExpanded: isExpanded, version: version, workdir: workdir, forceStatic: forceStatic }, remountKey), !isConfirmationVisible && !isExpanded && (_jsxs(_Fragment, { children: [(isLoading || isCommandRunning || isCompressing) && (_jsx(LoadingIndicator, { isLoading: isLoading, isCommandRunning: isCommandRunning, isCompressing: isCompressing, latestTotalTokens: latestTotalTokens })), _jsx(TaskList, {}), _jsx(QueuedMessageList, {}), _jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, sendMessage: sendMessage, abortMessage: abortMessage, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand })] })), isConfirmationVisible && (_jsxs(_Fragment, { children: [forceStatic ? (_jsx(Static, { items: [{ key: "confirmation-details" }], children: () => (_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded })) })) : (_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded })), _jsx(ConfirmationSelector, { toolName: confirmingTool.name, toolInput: confirmingTool.input, suggestedPrefix: confirmingTool.suggestedPrefix, hidePersistentOption: confirmingTool.hidePersistentOption, isExpanded: isExpanded, onDecision: handleConfirmationDecision, onCancel: handleConfirmationCancel, onAbort: abortMessage })] }))] }));
42
41
  };
@@ -1 +1 @@
1
- {"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAiBzC,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,EAClD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACjC,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,CA0Q5C,CAAC"}
1
+ {"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAkBzC,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,EAClD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACjC,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,CAuQ5C,CAAC"}
@@ -13,12 +13,13 @@ import { StatusCommand } from "./StatusCommand.js";
13
13
  import { PluginManagerShell } from "./PluginManagerShell.js";
14
14
  import { ModelSelector } from "./ModelSelector.js";
15
15
  import { StatusLine } from "./StatusLine.js";
16
+ import { BtwDisplay } from "./BtwDisplay.js";
16
17
  import { useInputManager } from "../hooks/useInputManager.js";
17
18
  import { useChat } from "../contexts/useChat.js";
18
19
  export const INPUT_PLACEHOLDER_TEXT = "Type your message (use /help for more info)...";
19
20
  export const INPUT_PLACEHOLDER_TEXT_PREFIX = INPUT_PLACEHOLDER_TEXT.substring(0, 10);
20
21
  export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, }) => {
21
- const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, allowBypassInCycle: chatAllowBypassInCycle, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, sessionId, workingDirectory, askBtw, btwState: chatBtwState, setBtwState: setChatBtwState, currentModel, configuredModels, setModel, } = useChat();
22
+ const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, allowBypassInCycle: chatAllowBypassInCycle, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, sessionId, workingDirectory, askBtw, currentModel, configuredModels, setModel, } = useChat();
22
23
  // Input manager with all input state and functionality (including images)
23
24
  const { inputText, cursorPosition,
24
25
  // Image management
@@ -41,8 +42,6 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
41
42
  isManagerReady, } = useInputManager({
42
43
  onSendMessage: sendMessage,
43
44
  onAskBtw: askBtw,
44
- btwState: chatBtwState,
45
- onBtwStateChange: setChatBtwState,
46
45
  onHasSlashCommand: hasSlashCommand,
47
46
  onAbortMessage: abortMessage,
48
47
  onBackgroundCurrentTask: backgroundCurrentTask,
@@ -104,7 +103,7 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
104
103
  if (showModelSelector) {
105
104
  return (_jsx(ModelSelector, { onCancel: () => setShowModelSelector(false), currentModel: currentModel, configuredModels: configuredModels, onSelectModel: setModel }));
106
105
  }
107
- 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 ||
106
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(BtwDisplay, { btwState: btwState }), 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 ||
108
107
  showMcpManager ||
109
108
  showRewindManager ||
110
109
  showHelp ||
@@ -1 +1 @@
1
- {"version":3,"file":"MarketplaceAddForm.d.ts","sourceRoot":"","sources":["../../src/components/MarketplaceAddForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAIxC,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EA+CtC,CAAC"}
1
+ {"version":3,"file":"MarketplaceAddForm.d.ts","sourceRoot":"","sources":["../../src/components/MarketplaceAddForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAI3D,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAkDtC,CAAC"}
@@ -1,10 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from "react";
2
+ import { useState, useRef, useEffect } from "react";
3
3
  import { Box, Text, useInput } from "ink";
4
4
  import { usePluginManagerContext } from "../contexts/PluginManagerContext.js";
5
5
  export const MarketplaceAddForm = () => {
6
6
  const { state, actions } = usePluginManagerContext();
7
7
  const [source, setSource] = useState("");
8
+ const sourceRef = useRef(source);
9
+ // Keep ref in sync with state
10
+ useEffect(() => {
11
+ sourceRef.current = source;
12
+ }, [source]);
8
13
  useInput((input, key) => {
9
14
  if (key.escape) {
10
15
  actions.setView("MARKETPLACES");
@@ -13,12 +18,9 @@ export const MarketplaceAddForm = () => {
13
18
  return;
14
19
  }
15
20
  else if (key.return) {
16
- setSource((prev) => {
17
- if (prev.trim()) {
18
- actions.addMarketplace(prev.trim());
19
- }
20
- return prev;
21
- });
21
+ if (sourceRef.current.trim()) {
22
+ actions.addMarketplace(sourceRef.current.trim());
23
+ }
22
24
  }
23
25
  else if (key.backspace || key.delete) {
24
26
  setSource((prev) => prev.slice(0, -1));
@@ -1 +1 @@
1
- {"version":3,"file":"McpManager.d.ts","sourceRoot":"","sources":["../../src/components/McpManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA0ThD,CAAC"}
1
+ {"version":3,"file":"McpManager.d.ts","sourceRoot":"","sources":["../../src/components/McpManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAoThD,CAAC"}
@@ -1,9 +1,18 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useState } from "react";
2
+ import { useState, useRef, useEffect } from "react";
3
3
  import { Box, Text, useInput } from "ink";
4
4
  export const McpManager = ({ onCancel, servers, onConnectServer, onDisconnectServer, }) => {
5
5
  const [selectedIndex, setSelectedIndex] = useState(0);
6
6
  const [viewMode, setViewMode] = useState("list");
7
+ // Keep ref in sync with state to avoid stale closures in useInput
8
+ const selectedIndexRef = useRef(selectedIndex);
9
+ const viewModeRef = useRef(viewMode);
10
+ useEffect(() => {
11
+ selectedIndexRef.current = selectedIndex;
12
+ }, [selectedIndex]);
13
+ useEffect(() => {
14
+ viewModeRef.current = viewMode;
15
+ }, [viewMode]);
7
16
  // Dynamically calculate selectedServer based on selectedIndex and servers
8
17
  const selectedServer = viewMode === "detail" &&
9
18
  servers.length > 0 &&
@@ -45,29 +54,18 @@ export const McpManager = ({ onCancel, servers, onConnectServer, onDisconnectSer
45
54
  };
46
55
  useInput((input, key) => {
47
56
  if (key.return) {
48
- setViewMode((prevMode) => {
49
- if (prevMode === "list") {
50
- setSelectedIndex((prevIndex) => {
51
- if (servers.length > 0 && prevIndex < servers.length) {
52
- // We can't call setViewMode here because we're already in a setViewMode call
53
- // But we can return the new mode from the outer setViewMode
54
- }
55
- return prevIndex;
56
- });
57
- return "detail";
58
- }
59
- return prevMode;
60
- });
57
+ if (viewModeRef.current === "list") {
58
+ setViewMode("detail");
59
+ }
61
60
  return;
62
61
  }
63
62
  if (key.escape) {
64
- setViewMode((prev) => {
65
- if (prev === "detail") {
66
- return "list";
67
- }
63
+ if (viewModeRef.current === "detail") {
64
+ setViewMode("list");
65
+ }
66
+ else {
68
67
  onCancel();
69
- return prev;
70
- });
68
+ }
71
69
  return;
72
70
  }
73
71
  if (key.upArrow) {
@@ -80,24 +78,18 @@ export const McpManager = ({ onCancel, servers, onConnectServer, onDisconnectSer
80
78
  }
81
79
  // Hotkeys for server actions
82
80
  if (input === "c") {
83
- setSelectedIndex((prev) => {
84
- const server = servers[prev];
85
- if (server &&
86
- (server.status === "disconnected" || server.status === "error")) {
87
- handleConnect(server.name);
88
- }
89
- return prev;
90
- });
81
+ const server = servers[selectedIndexRef.current];
82
+ if (server &&
83
+ (server.status === "disconnected" || server.status === "error")) {
84
+ handleConnect(server.name);
85
+ }
91
86
  return;
92
87
  }
93
88
  if (input === "d") {
94
- setSelectedIndex((prev) => {
95
- const server = servers[prev];
96
- if (server && server.status === "connected") {
97
- handleDisconnect(server.name);
98
- }
99
- return prev;
100
- });
89
+ const server = servers[selectedIndexRef.current];
90
+ if (server && server.status === "connected") {
91
+ handleDisconnect(server.name);
92
+ }
101
93
  return;
102
94
  }
103
95
  });
@@ -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,EAAgB,MAAM,gBAAgB,CAAC;AAG5D,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;CAClB;AAED,eAAO,MAAM,WAAW,uFAOnB,gBAAgB,6CAiHpB,CAAC"}
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,EAAgB,MAAM,gBAAgB,CAAC;AAG5D,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;CAClB;AAED,eAAO,MAAM,WAAW,uFAOnB,gBAAgB,6CAkHpB,CAAC"}
@@ -30,6 +30,7 @@ export const MessageList = React.memo(({ messages, isExpanded = false, forceStat
30
30
  const blocksWithStatus = allBlocks.map((item) => {
31
31
  const { block } = item;
32
32
  const isDynamic = !forceStatic &&
33
+ !isExpanded &&
33
34
  (messagesWithRunningBlocks.has(item.messageIndex) || isRunning(block));
34
35
  return { ...item, isDynamic };
35
36
  });
@@ -1 +1 @@
1
- {"version":3,"file":"PluginDetail.d.ts","sourceRoot":"","sources":["../../src/components/PluginDetail.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAUxC,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EA+JhC,CAAC"}
1
+ {"version":3,"file":"PluginDetail.d.ts","sourceRoot":"","sources":["../../src/components/PluginDetail.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAU3D,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAqKhC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from "react";
2
+ import { useState, useRef, useEffect } from "react";
3
3
  import { Box, Text, useInput } from "ink";
4
4
  import { usePluginManagerContext } from "../contexts/PluginManagerContext.js";
5
5
  const SCOPES = [
@@ -11,6 +11,15 @@ export const PluginDetail = () => {
11
11
  const { state, discoverablePlugins, installedPlugins, actions } = usePluginManagerContext();
12
12
  const [selectedScopeIndex, setSelectedScopeIndex] = useState(0);
13
13
  const [selectedActionIndex, setSelectedActionIndex] = useState(0);
14
+ // Keep refs in sync with state to avoid stale closures in useInput
15
+ const selectedScopeIndexRef = useRef(selectedScopeIndex);
16
+ const selectedActionIndexRef = useRef(selectedActionIndex);
17
+ useEffect(() => {
18
+ selectedScopeIndexRef.current = selectedScopeIndex;
19
+ }, [selectedScopeIndex]);
20
+ useEffect(() => {
21
+ selectedActionIndexRef.current = selectedActionIndex;
22
+ }, [selectedActionIndex]);
14
23
  const plugin = discoverablePlugins.find((p) => `${p.name}@${p.marketplace}` === state.selectedId) ||
15
24
  installedPlugins.find((p) => `${p.name}@${p.marketplace}` === state.selectedId);
16
25
  const INSTALLED_ACTIONS = [
@@ -33,22 +42,16 @@ export const PluginDetail = () => {
33
42
  }
34
43
  else if (key.return && plugin && !state.isLoading) {
35
44
  if (isInstalledAndEnabled) {
36
- setSelectedActionIndex((prev) => {
37
- const action = INSTALLED_ACTIONS[prev].id;
38
- if (action === "uninstall") {
39
- actions.uninstallPlugin(plugin.name, plugin.marketplace);
40
- }
41
- else {
42
- actions.updatePlugin(plugin.name, plugin.marketplace);
43
- }
44
- return prev;
45
- });
45
+ const action = INSTALLED_ACTIONS[selectedActionIndexRef.current].id;
46
+ if (action === "uninstall") {
47
+ actions.uninstallPlugin(plugin.name, plugin.marketplace);
48
+ }
49
+ else {
50
+ actions.updatePlugin(plugin.name, plugin.marketplace);
51
+ }
46
52
  }
47
53
  else {
48
- setSelectedScopeIndex((prev) => {
49
- actions.installPlugin(plugin.name, plugin.marketplace, SCOPES[prev].id);
50
- return prev;
51
- });
54
+ actions.installPlugin(plugin.name, plugin.marketplace, SCOPES[selectedScopeIndexRef.current].id);
52
55
  }
53
56
  }
54
57
  });
@@ -72,8 +72,6 @@ export interface ChatContextType {
72
72
  workingDirectory: string;
73
73
  version?: string;
74
74
  workdir?: string;
75
- btwState: import("../managers/inputReducer.js").BtwState;
76
- setBtwState: (payload: Partial<import("../managers/inputReducer.js").BtwState>) => void;
77
75
  }
78
76
  export declare const useChat: () => ChatContextType;
79
77
  export interface ChatProviderProps extends BaseAppProps {
@@ -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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"}
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createContext, useContext, useCallback, useRef, useEffect, useState, useMemo, } from "react";
3
3
  import { useInput, useStdout } from "ink";
4
4
  import { useAppConfig } from "./useAppConfig.js";
5
- import { Agent, OPERATION_CANCELLED_BY_USER, cloneMessage, } from "wave-agent-sdk";
5
+ import { Agent, OPERATION_CANCELLED_BY_USER, } from "wave-agent-sdk";
6
6
  import { logger } from "../utils/logger.js";
7
7
  import { throttle } from "../utils/throttle.js";
8
8
  import { displayUsageSummary } from "../utils/usageSummary.js";
@@ -66,12 +66,17 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
66
66
  // Remount state
67
67
  const [remountKey, setRemountKey] = useState(0);
68
68
  const prevSessionId = useRef(null);
69
- const requestRemount = useCallback(() => {
69
+ const requestRemount = useMemo(() => throttle(() => {
70
70
  logger.info("requesting remount");
71
71
  stdout?.write("\u001b[2J\u001b[3J\u001b[0;0H", () => {
72
72
  setRemountKey((prev) => prev + 1);
73
73
  });
74
- }, [stdout]);
74
+ }, 1000, { leading: true, trailing: false }), [stdout]);
75
+ useEffect(() => {
76
+ return () => {
77
+ requestRemount.cancel();
78
+ };
79
+ }, [requestRemount]);
75
80
  // Track sessionId changes to trigger remount
76
81
  useEffect(() => {
77
82
  if (prevSessionId.current &&
@@ -85,21 +90,6 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
85
90
  }, [sessionId, requestRemount]);
86
91
  // Status metadata state
87
92
  const [workingDirectory, setWorkingDirectory] = useState("");
88
- // /btw state
89
- const [btwState, setBtwStateInternal] = useState({
90
- isActive: false,
91
- question: "",
92
- isLoading: false,
93
- });
94
- const setBtwState = useCallback((payload) => {
95
- setBtwStateInternal((prev) => {
96
- const newState = { ...prev, ...payload };
97
- if (process.env.NODE_ENV === "test") {
98
- // console.log("setBtwState", newState);
99
- }
100
- return newState;
101
- });
102
- }, []);
103
93
  const allowBypassInCycle = !!bypassPermissions || initialPermissionMode === "bypassPermissions";
104
94
  const agentRef = useRef(null);
105
95
  // Permission confirmation methods with queue support
@@ -430,49 +420,32 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
430
420
  useInput((input, key) => {
431
421
  if (key.ctrl && input === "o") {
432
422
  // Clear terminal screen when expanded state changes
433
- setIsExpanded((prev) => {
434
- const newExpanded = !prev;
435
- isExpandedRef.current = newExpanded;
436
- if (newExpanded) {
437
- // Transitioning to EXPANDED: Freeze the current view
438
- // Cancel any pending throttled updates to avoid overwriting the frozen state
439
- throttledSetMessages.cancel();
440
- // Deep copy the last message to ensure it doesn't update if the agent is still writing to it
441
- setMessages((currentMessages) => {
442
- if (currentMessages.length === 0)
443
- return currentMessages;
444
- const lastMessage = currentMessages[currentMessages.length - 1];
445
- const frozenLastMessage = cloneMessage(lastMessage);
446
- return [...currentMessages.slice(0, -1), frozenLastMessage];
447
- });
448
- }
449
- else {
450
- // Transitioning to COLLAPSED: Restore from agent's actual state
451
- if (agentRef.current) {
452
- setMessages([...agentRef.current.messages]);
453
- }
423
+ // Use ref to get the current value to avoid stale closure
424
+ const nextExpanded = !isExpandedRef.current;
425
+ setIsExpanded(nextExpanded);
426
+ isExpandedRef.current = nextExpanded;
427
+ if (nextExpanded) {
428
+ // Transitioning to EXPANDED: Freeze the current view
429
+ // Cancel any pending throttled updates to avoid overwriting the frozen state
430
+ throttledSetMessages.cancel();
431
+ }
432
+ else {
433
+ // Transitioning to COLLAPSED: Restore from agent's actual state
434
+ if (agentRef.current) {
435
+ setMessages([...agentRef.current.messages]);
454
436
  }
455
- return newExpanded;
456
- });
437
+ }
457
438
  // Force remount to re-render Static items with new isExpanded state
458
439
  requestRemount();
459
440
  }
460
441
  if (key.ctrl && input === "t") {
461
442
  setIsTaskListVisible((prev) => !prev);
462
443
  }
463
- // Handle ESC key to cancel confirmation or dismiss BTW
444
+ // Handle ESC key to cancel confirmation
464
445
  if (key.escape) {
465
446
  if (isConfirmationVisible) {
466
447
  handleConfirmationCancel();
467
448
  }
468
- else if (btwState.isActive) {
469
- setBtwState({
470
- isActive: false,
471
- question: "",
472
- answer: undefined,
473
- isLoading: false,
474
- });
475
- }
476
449
  }
477
450
  });
478
451
  const contextValue = {
@@ -514,7 +487,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
514
487
  handleConfirmationCancel,
515
488
  backgroundCurrentTask,
516
489
  remountKey,
517
- requestRemount,
490
+ requestRemount: requestRemount,
518
491
  handleRewindSelect,
519
492
  getFullMessageThread,
520
493
  getGatewayConfig,
@@ -522,8 +495,6 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
522
495
  workingDirectory,
523
496
  version,
524
497
  workdir,
525
- btwState,
526
- setBtwState,
527
498
  };
528
499
  return (_jsx(ChatContext.Provider, { value: contextValue, children: children }));
529
500
  };
@@ -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,EAEL,cAAc,EACd,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAGxB,eAAO,MAAM,eAAe,GAC1B,YAAW,OAAO,CAAC,qBAAqB,CAAM;;;;;;;;;;;;;;;;;;;;;;;;+BA0LA,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;iCAIP,OAAO;iCAIP,OAAO;8BAIV,cAAc;mCAKT,OAAO;2BAK7C,OAAO,CAAC,OAAO,6BAA6B,EAAE,QAAQ,CAAC;0BAU1B,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;yBA/GY,MAAM;kCAIG,MAAM;;CAkNxD,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;;;;;;;;;;;;;;;;;;;;;;;;+BAoLA,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;iCAIP,OAAO;iCAIP,OAAO;8BAIV,cAAc;mCAKT,OAAO;2BAK7C,OAAO,CAAC,OAAO,6BAA6B,EAAE,QAAQ,CAAC;0BAM1B,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;yBA3GY,MAAM;kCAIG,MAAM;;CA8MxD,CAAC"}
@@ -106,11 +106,6 @@ export const useInputManager = (callbacks = {}) => {
106
106
  useEffect(() => {
107
107
  callbacksRef.current.onImagesStateChange?.(state.attachedImages);
108
108
  }, [state.attachedImages]);
109
- useEffect(() => {
110
- if (callbacksRef.current.onBtwStateChange) {
111
- callbacksRef.current.onBtwStateChange(state.btwState);
112
- }
113
- }, [state.btwState]);
114
109
  // Handle /btw side question
115
110
  useEffect(() => {
116
111
  if (state.btwState.isActive &&
@@ -252,12 +247,7 @@ export const useInputManager = (callbacks = {}) => {
252
247
  dispatch({ type: "SET_ALLOW_BYPASS_IN_CYCLE", payload: allow });
253
248
  }, []);
254
249
  const setBtwState = useCallback((payload) => {
255
- if (callbacksRef.current.onBtwStateChange) {
256
- callbacksRef.current.onBtwStateChange(payload);
257
- }
258
- else {
259
- dispatch({ type: "SET_BTW_STATE", payload });
260
- }
250
+ dispatch({ type: "SET_BTW_STATE", payload });
261
251
  }, []);
262
252
  const addImage = useCallback((imagePath, mimeType) => {
263
253
  dispatch({ type: "ADD_IMAGE", payload: { path: imagePath, mimeType } });
@@ -33,8 +33,6 @@ export interface InputManagerCallbacks {
33
33
  onBackgroundCurrentTask?: () => void;
34
34
  onPermissionModeChange?: (mode: PermissionMode) => void;
35
35
  onAskBtw?: (question: string) => Promise<string>;
36
- btwState?: BtwState;
37
- onBtwStateChange?: (payload: Partial<BtwState>) => void;
38
36
  sessionId?: string;
39
37
  workdir?: string;
40
38
  getFullMessageThread?: () => Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"inputReducer.d.ts","sourceRoot":"","sources":["../../src/managers/inputReducer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,cAAc,EACd,MAAM,EACN,WAAW,EACX,OAAO,EACR,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,yBAAyB,CAAC,EAAE,CAC1B,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,QAAQ,EAAE,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,KACb,IAAI,CAAC;IACV,4BAA4B,CAAC,EAAE,CAC7B,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,KACb,IAAI,CAAC;IACV,0BAA0B,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpE,kCAAkC,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7D,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,0BAA0B,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,0BAA0B,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,0BAA0B,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,0BAA0B,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IACxD,aAAa,CAAC,EAAE,CACd,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,EAClD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACjC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;IACnD,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,uBAAuB,CAAC,EAAE,MAAM,IAAI,CAAC;IACrC,sBAAsB,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IACxD,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,MAAM,OAAO,CAAC;QACnC,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,QAAQ,EAAE,CAAC;IAC1B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,yBAAyB,EAAE,OAAO,CAAC;IACnC,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,cAAc,EAAE,cAAc,CAAC;IAC/B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B,EAAE,MAAM,CAAC;IACnC,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,eAAO,MAAM,YAAY,EAAE,UAuC1B,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,wBAAwB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,uBAAuB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,OAAO,EAAE,QAAQ,EAAE,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,sBAAsB,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,2BAA2B,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,0BAA0B,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,yBAAyB,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,yBAAyB,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,0BAA0B,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,kCAAkC,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,yBAAyB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,yBAAyB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,yBAAyB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,yBAAyB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,2BAA2B,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,wBAAwB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,8BAA8B,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,qBAAqB,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC5E;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IACE,IAAI,EAAE,kCAAkC,CAAC;IACzC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C,GACD;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,WAAW,EAAE,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,0BAA0B,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;CAAE,CAAC;AAE1D,wBAAgB,YAAY,CAC1B,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,WAAW,GAClB,UAAU,CAiVZ"}
1
+ {"version":3,"file":"inputReducer.d.ts","sourceRoot":"","sources":["../../src/managers/inputReducer.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-code",
3
- "version": "0.12.6",
3
+ "version": "0.12.8",
4
4
  "description": "CLI-based code assistant powered by AI, built with React and Ink",
5
5
  "repository": {
6
6
  "type": "git",
@@ -42,7 +42,7 @@
42
42
  "semver": "^7.7.4",
43
43
  "yargs": "^17.7.2",
44
44
  "zod": "^3.23.8",
45
- "wave-agent-sdk": "0.12.6"
45
+ "wave-agent-sdk": "0.12.8"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/react": "^19.1.8",
@@ -13,12 +13,12 @@ export const BtwDisplay: React.FC<BtwDisplayProps> = ({ btwState }) => {
13
13
  }
14
14
 
15
15
  return (
16
- <Box flexDirection="column" marginTop={0} marginBottom={1}>
16
+ <Box flexDirection="column" marginTop={0} marginBottom={0}>
17
17
  {btwState.question && (
18
18
  <Box>
19
- <Text color={btwState.isLoading ? "yellow" : "green"}>● </Text>
19
+ <Text color={btwState.isLoading ? "yellow" : "green"}>/ </Text>
20
20
  <Text italic color="gray">
21
- /btw {btwState.question}
21
+ btw {btwState.question}
22
22
  </Text>
23
23
  </Box>
24
24
  )}
@@ -2,7 +2,6 @@ import React, { useState, useRef, useEffect } from "react";
2
2
  import { Box, useStdout, measureElement, Static } from "ink";
3
3
  import type { DOMElement } from "ink";
4
4
  import { MessageList } from "./MessageList.js";
5
- import { BtwDisplay } from "./BtwDisplay.js";
6
5
  import { InputBox } from "./InputBox.js";
7
6
  import { LoadingIndicator } from "./LoadingIndicator.js";
8
7
  import { TaskList } from "./TaskList.js";
@@ -35,7 +34,6 @@ export const ChatInterface: React.FC = () => {
35
34
  handleConfirmationCancel,
36
35
  version,
37
36
  workdir,
38
- btwState,
39
37
  remountKey,
40
38
  requestRemount,
41
39
  } = useChat();
@@ -81,7 +79,6 @@ export const ChatInterface: React.FC = () => {
81
79
 
82
80
  {!isConfirmationVisible && !isExpanded && (
83
81
  <>
84
- <BtwDisplay btwState={btwState} />
85
82
  {(isLoading || isCommandRunning || isCompressing) && (
86
83
  <LoadingIndicator
87
84
  isLoading={isLoading}
@@ -12,6 +12,7 @@ import { StatusCommand } from "./StatusCommand.js";
12
12
  import { PluginManagerShell } from "./PluginManagerShell.js";
13
13
  import { ModelSelector } from "./ModelSelector.js";
14
14
  import { StatusLine } from "./StatusLine.js";
15
+ import { BtwDisplay } from "./BtwDisplay.js";
15
16
  import { useInputManager } from "../hooks/useInputManager.js";
16
17
  import { useChat } from "../contexts/useChat.js";
17
18
 
@@ -64,8 +65,6 @@ export const InputBox: React.FC<InputBoxProps> = ({
64
65
  sessionId,
65
66
  workingDirectory,
66
67
  askBtw,
67
- btwState: chatBtwState,
68
- setBtwState: setChatBtwState,
69
68
  currentModel,
70
69
  configuredModels,
71
70
  setModel,
@@ -124,8 +123,6 @@ export const InputBox: React.FC<InputBoxProps> = ({
124
123
  } = useInputManager({
125
124
  onSendMessage: sendMessage,
126
125
  onAskBtw: askBtw,
127
- btwState: chatBtwState,
128
- onBtwStateChange: setChatBtwState,
129
126
  onHasSlashCommand: hasSlashCommand,
130
127
  onAbortMessage: abortMessage,
131
128
  onBackgroundCurrentTask: backgroundCurrentTask,
@@ -224,6 +221,7 @@ export const InputBox: React.FC<InputBoxProps> = ({
224
221
 
225
222
  return (
226
223
  <Box flexDirection="column">
224
+ <BtwDisplay btwState={btwState} />
227
225
  {showFileSelector && (
228
226
  <FileSelector
229
227
  files={filteredFiles}
@@ -1,10 +1,16 @@
1
- import React, { useState } from "react";
1
+ import React, { useState, useRef, useEffect } from "react";
2
2
  import { Box, Text, useInput } from "ink";
3
3
  import { usePluginManagerContext } from "../contexts/PluginManagerContext.js";
4
4
 
5
5
  export const MarketplaceAddForm: React.FC = () => {
6
6
  const { state, actions } = usePluginManagerContext();
7
7
  const [source, setSource] = useState("");
8
+ const sourceRef = useRef(source);
9
+
10
+ // Keep ref in sync with state
11
+ useEffect(() => {
12
+ sourceRef.current = source;
13
+ }, [source]);
8
14
 
9
15
  useInput((input, key) => {
10
16
  if (key.escape) {
@@ -12,12 +18,9 @@ export const MarketplaceAddForm: React.FC = () => {
12
18
  } else if (state.isLoading) {
13
19
  return;
14
20
  } else if (key.return) {
15
- setSource((prev) => {
16
- if (prev.trim()) {
17
- actions.addMarketplace(prev.trim());
18
- }
19
- return prev;
20
- });
21
+ if (sourceRef.current.trim()) {
22
+ actions.addMarketplace(sourceRef.current.trim());
23
+ }
21
24
  } else if (key.backspace || key.delete) {
22
25
  setSource((prev) => prev.slice(0, -1));
23
26
  } else if (input.length === 1) {
@@ -1,4 +1,4 @@
1
- import React, { useState } from "react";
1
+ import React, { useState, useRef, useEffect } from "react";
2
2
  import { Box, Text, useInput } from "ink";
3
3
  import { McpServerStatus } from "wave-agent-sdk";
4
4
 
@@ -18,6 +18,18 @@ export const McpManager: React.FC<McpManagerProps> = ({
18
18
  const [selectedIndex, setSelectedIndex] = useState(0);
19
19
  const [viewMode, setViewMode] = useState<"list" | "detail">("list");
20
20
 
21
+ // Keep ref in sync with state to avoid stale closures in useInput
22
+ const selectedIndexRef = useRef(selectedIndex);
23
+ const viewModeRef = useRef(viewMode);
24
+
25
+ useEffect(() => {
26
+ selectedIndexRef.current = selectedIndex;
27
+ }, [selectedIndex]);
28
+
29
+ useEffect(() => {
30
+ viewModeRef.current = viewMode;
31
+ }, [viewMode]);
32
+
21
33
  // Dynamically calculate selectedServer based on selectedIndex and servers
22
34
  const selectedServer =
23
35
  viewMode === "detail" &&
@@ -66,30 +78,18 @@ export const McpManager: React.FC<McpManagerProps> = ({
66
78
 
67
79
  useInput((input, key) => {
68
80
  if (key.return) {
69
- setViewMode((prevMode) => {
70
- if (prevMode === "list") {
71
- setSelectedIndex((prevIndex) => {
72
- if (servers.length > 0 && prevIndex < servers.length) {
73
- // We can't call setViewMode here because we're already in a setViewMode call
74
- // But we can return the new mode from the outer setViewMode
75
- }
76
- return prevIndex;
77
- });
78
- return "detail";
79
- }
80
- return prevMode;
81
- });
81
+ if (viewModeRef.current === "list") {
82
+ setViewMode("detail");
83
+ }
82
84
  return;
83
85
  }
84
86
 
85
87
  if (key.escape) {
86
- setViewMode((prev) => {
87
- if (prev === "detail") {
88
- return "list";
89
- }
88
+ if (viewModeRef.current === "detail") {
89
+ setViewMode("list");
90
+ } else {
90
91
  onCancel();
91
- return prev;
92
- });
92
+ }
93
93
  return;
94
94
  }
95
95
 
@@ -105,27 +105,21 @@ export const McpManager: React.FC<McpManagerProps> = ({
105
105
 
106
106
  // Hotkeys for server actions
107
107
  if (input === "c") {
108
- setSelectedIndex((prev) => {
109
- const server = servers[prev];
110
- if (
111
- server &&
112
- (server.status === "disconnected" || server.status === "error")
113
- ) {
114
- handleConnect(server.name);
115
- }
116
- return prev;
117
- });
108
+ const server = servers[selectedIndexRef.current];
109
+ if (
110
+ server &&
111
+ (server.status === "disconnected" || server.status === "error")
112
+ ) {
113
+ handleConnect(server.name);
114
+ }
118
115
  return;
119
116
  }
120
117
 
121
118
  if (input === "d") {
122
- setSelectedIndex((prev) => {
123
- const server = servers[prev];
124
- if (server && server.status === "connected") {
125
- handleDisconnect(server.name);
126
- }
127
- return prev;
128
- });
119
+ const server = servers[selectedIndexRef.current];
120
+ if (server && server.status === "connected") {
121
+ handleDisconnect(server.name);
122
+ }
129
123
  return;
130
124
  }
131
125
  });
@@ -65,6 +65,7 @@ export const MessageList = React.memo(
65
65
  const { block } = item;
66
66
  const isDynamic =
67
67
  !forceStatic &&
68
+ !isExpanded &&
68
69
  (messagesWithRunningBlocks.has(item.messageIndex) || isRunning(block));
69
70
  return { ...item, isDynamic };
70
71
  });
@@ -1,4 +1,4 @@
1
- import React, { useState } from "react";
1
+ import React, { useState, useRef, useEffect } from "react";
2
2
  import { Box, Text, useInput } from "ink";
3
3
  import { usePluginManagerContext } from "../contexts/PluginManagerContext.js";
4
4
 
@@ -14,6 +14,18 @@ export const PluginDetail: React.FC = () => {
14
14
  const [selectedScopeIndex, setSelectedScopeIndex] = useState(0);
15
15
  const [selectedActionIndex, setSelectedActionIndex] = useState(0);
16
16
 
17
+ // Keep refs in sync with state to avoid stale closures in useInput
18
+ const selectedScopeIndexRef = useRef(selectedScopeIndex);
19
+ const selectedActionIndexRef = useRef(selectedActionIndex);
20
+
21
+ useEffect(() => {
22
+ selectedScopeIndexRef.current = selectedScopeIndex;
23
+ }, [selectedScopeIndex]);
24
+
25
+ useEffect(() => {
26
+ selectedActionIndexRef.current = selectedActionIndex;
27
+ }, [selectedActionIndex]);
28
+
17
29
  const plugin =
18
30
  discoverablePlugins.find(
19
31
  (p) => `${p.name}@${p.marketplace}` === state.selectedId,
@@ -51,24 +63,18 @@ export const PluginDetail: React.FC = () => {
51
63
  );
52
64
  } else if (key.return && plugin && !state.isLoading) {
53
65
  if (isInstalledAndEnabled) {
54
- setSelectedActionIndex((prev) => {
55
- const action = INSTALLED_ACTIONS[prev].id;
56
- if (action === "uninstall") {
57
- actions.uninstallPlugin(plugin.name, plugin.marketplace);
58
- } else {
59
- actions.updatePlugin(plugin.name, plugin.marketplace);
60
- }
61
- return prev;
62
- });
66
+ const action = INSTALLED_ACTIONS[selectedActionIndexRef.current].id;
67
+ if (action === "uninstall") {
68
+ actions.uninstallPlugin(plugin.name, plugin.marketplace);
69
+ } else {
70
+ actions.updatePlugin(plugin.name, plugin.marketplace);
71
+ }
63
72
  } else {
64
- setSelectedScopeIndex((prev) => {
65
- actions.installPlugin(
66
- plugin.name,
67
- plugin.marketplace,
68
- SCOPES[prev].id,
69
- );
70
- return prev;
71
- });
73
+ actions.installPlugin(
74
+ plugin.name,
75
+ plugin.marketplace,
76
+ SCOPES[selectedScopeIndexRef.current].id,
77
+ );
72
78
  }
73
79
  }
74
80
  });
@@ -23,7 +23,6 @@ import {
23
23
  AgentCallbacks,
24
24
  type ToolPermissionContext,
25
25
  OPERATION_CANCELLED_BY_USER,
26
- cloneMessage,
27
26
  } from "wave-agent-sdk";
28
27
  import { logger } from "../utils/logger.js";
29
28
  import { throttle } from "../utils/throttle.js";
@@ -121,10 +120,6 @@ export interface ChatContextType {
121
120
  workingDirectory: string;
122
121
  version?: string;
123
122
  workdir?: string;
124
- btwState: import("../managers/inputReducer.js").BtwState;
125
- setBtwState: (
126
- payload: Partial<import("../managers/inputReducer.js").BtwState>,
127
- ) => void;
128
123
  }
129
124
 
130
125
  const ChatContext = createContext<ChatContextType | null>(null);
@@ -258,12 +253,26 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
258
253
  const [remountKey, setRemountKey] = useState(0);
259
254
  const prevSessionId = useRef<string | null>(null);
260
255
 
261
- const requestRemount = useCallback(() => {
262
- logger.info("requesting remount");
263
- stdout?.write("\u001b[2J\u001b[3J\u001b[0;0H", () => {
264
- setRemountKey((prev) => prev + 1);
265
- });
266
- }, [stdout]);
256
+ const requestRemount = useMemo(
257
+ () =>
258
+ throttle(
259
+ () => {
260
+ logger.info("requesting remount");
261
+ stdout?.write("\u001b[2J\u001b[3J\u001b[0;0H", () => {
262
+ setRemountKey((prev) => prev + 1);
263
+ });
264
+ },
265
+ 1000,
266
+ { leading: true, trailing: false },
267
+ ),
268
+ [stdout],
269
+ );
270
+
271
+ useEffect(() => {
272
+ return () => {
273
+ requestRemount.cancel();
274
+ };
275
+ }, [requestRemount]);
267
276
 
268
277
  // Track sessionId changes to trigger remount
269
278
  useEffect(() => {
@@ -282,28 +291,6 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
282
291
  // Status metadata state
283
292
  const [workingDirectory, setWorkingDirectory] = useState("");
284
293
 
285
- // /btw state
286
- const [btwState, setBtwStateInternal] = useState<
287
- import("../managers/inputReducer.js").BtwState
288
- >({
289
- isActive: false,
290
- question: "",
291
- isLoading: false,
292
- });
293
-
294
- const setBtwState = useCallback(
295
- (payload: Partial<import("../managers/inputReducer.js").BtwState>) => {
296
- setBtwStateInternal((prev) => {
297
- const newState = { ...prev, ...payload };
298
- if (process.env.NODE_ENV === "test") {
299
- // console.log("setBtwState", newState);
300
- }
301
- return newState;
302
- });
303
- },
304
- [],
305
- );
306
-
307
294
  const allowBypassInCycle =
308
295
  !!bypassPermissions || initialPermissionMode === "bypassPermissions";
309
296
 
@@ -702,28 +689,21 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
702
689
  useInput((input, key) => {
703
690
  if (key.ctrl && input === "o") {
704
691
  // Clear terminal screen when expanded state changes
705
- setIsExpanded((prev) => {
706
- const newExpanded = !prev;
707
- isExpandedRef.current = newExpanded;
708
- if (newExpanded) {
709
- // Transitioning to EXPANDED: Freeze the current view
710
- // Cancel any pending throttled updates to avoid overwriting the frozen state
711
- throttledSetMessages.cancel();
712
- // Deep copy the last message to ensure it doesn't update if the agent is still writing to it
713
- setMessages((currentMessages) => {
714
- if (currentMessages.length === 0) return currentMessages;
715
- const lastMessage = currentMessages[currentMessages.length - 1];
716
- const frozenLastMessage = cloneMessage(lastMessage);
717
- return [...currentMessages.slice(0, -1), frozenLastMessage];
718
- });
719
- } else {
720
- // Transitioning to COLLAPSED: Restore from agent's actual state
721
- if (agentRef.current) {
722
- setMessages([...agentRef.current.messages]);
723
- }
692
+ // Use ref to get the current value to avoid stale closure
693
+ const nextExpanded = !isExpandedRef.current;
694
+ setIsExpanded(nextExpanded);
695
+ isExpandedRef.current = nextExpanded;
696
+
697
+ if (nextExpanded) {
698
+ // Transitioning to EXPANDED: Freeze the current view
699
+ // Cancel any pending throttled updates to avoid overwriting the frozen state
700
+ throttledSetMessages.cancel();
701
+ } else {
702
+ // Transitioning to COLLAPSED: Restore from agent's actual state
703
+ if (agentRef.current) {
704
+ setMessages([...agentRef.current.messages]);
724
705
  }
725
- return newExpanded;
726
- });
706
+ }
727
707
  // Force remount to re-render Static items with new isExpanded state
728
708
  requestRemount();
729
709
  }
@@ -732,17 +712,10 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
732
712
  setIsTaskListVisible((prev) => !prev);
733
713
  }
734
714
 
735
- // Handle ESC key to cancel confirmation or dismiss BTW
715
+ // Handle ESC key to cancel confirmation
736
716
  if (key.escape) {
737
717
  if (isConfirmationVisible) {
738
718
  handleConfirmationCancel();
739
- } else if (btwState.isActive) {
740
- setBtwState({
741
- isActive: false,
742
- question: "",
743
- answer: undefined,
744
- isLoading: false,
745
- });
746
719
  }
747
720
  }
748
721
  });
@@ -786,7 +759,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
786
759
  handleConfirmationCancel,
787
760
  backgroundCurrentTask,
788
761
  remountKey,
789
- requestRemount,
762
+ requestRemount: requestRemount as () => void,
790
763
  handleRewindSelect,
791
764
  getFullMessageThread,
792
765
 
@@ -795,8 +768,6 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
795
768
  workingDirectory,
796
769
  version,
797
770
  workdir,
798
- btwState,
799
- setBtwState,
800
771
  };
801
772
 
802
773
  return (
@@ -157,12 +157,6 @@ export const useInputManager = (
157
157
  callbacksRef.current.onImagesStateChange?.(state.attachedImages);
158
158
  }, [state.attachedImages]);
159
159
 
160
- useEffect(() => {
161
- if (callbacksRef.current.onBtwStateChange) {
162
- callbacksRef.current.onBtwStateChange(state.btwState);
163
- }
164
- }, [state.btwState]);
165
-
166
160
  // Handle /btw side question
167
161
  useEffect(() => {
168
162
  if (
@@ -362,11 +356,7 @@ export const useInputManager = (
362
356
 
363
357
  const setBtwState = useCallback(
364
358
  (payload: Partial<import("../managers/inputReducer.js").BtwState>) => {
365
- if (callbacksRef.current.onBtwStateChange) {
366
- callbacksRef.current.onBtwStateChange(payload);
367
- } else {
368
- dispatch({ type: "SET_BTW_STATE", payload });
369
- }
359
+ dispatch({ type: "SET_BTW_STATE", payload });
370
360
  },
371
361
  [],
372
362
  );
@@ -52,8 +52,6 @@ export interface InputManagerCallbacks {
52
52
  onBackgroundCurrentTask?: () => void;
53
53
  onPermissionModeChange?: (mode: PermissionMode) => void;
54
54
  onAskBtw?: (question: string) => Promise<string>;
55
- btwState?: BtwState;
56
- onBtwStateChange?: (payload: Partial<BtwState>) => void;
57
55
  sessionId?: string;
58
56
  workdir?: string;
59
57
  getFullMessageThread?: () => Promise<{