wave-code 0.12.3 → 0.12.4

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,7 +5,6 @@ interface AppProps extends BaseAppProps {
5
5
  continueLastSession?: boolean;
6
6
  onExit: (shouldRemove: boolean) => void;
7
7
  }
8
- export declare const ChatInterfaceWithRemount: React.FC;
9
8
  export declare const App: React.FC<AppProps>;
10
9
  export {};
11
10
  //# sourceMappingURL=App.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAWxE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,UAAU,QAAS,SAAQ,YAAY;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;CACzC;AAiGD,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAuC5C,CAAC;AAEF,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAmClC,CAAC"}
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAWhE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,UAAU,QAAS,SAAQ,YAAY;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;CACzC;AAiGD,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAmClC,CAAC"}
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useState, useEffect, useRef, useCallback } from "react";
3
- import { useStdout, useInput } from "ink";
2
+ import { useState, useEffect, useCallback } from "react";
3
+ import { useInput } from "ink";
4
4
  import { ChatInterface } from "./ChatInterface.js";
5
- import { ChatProvider, useChat } from "../contexts/useChat.js";
5
+ import { ChatProvider } from "../contexts/useChat.js";
6
6
  import { AppProvider } from "../contexts/useAppConfig.js";
7
7
  import { WorktreeExitPrompt } from "./WorktreeExitPrompt.js";
8
8
  import { hasUncommittedChanges, hasNewCommits, getDefaultRemoteBranch, } from "wave-agent-sdk";
@@ -48,38 +48,7 @@ const AppWithProviders = ({ bypassPermissions, permissionMode, pluginDirs, tools
48
48
  if (isExiting && worktreeSession && worktreeStatus) {
49
49
  return (_jsx(WorktreeExitPrompt, { name: worktreeSession.name, path: worktreeSession.path, hasUncommittedChanges: worktreeStatus.hasUncommittedChanges, hasNewCommits: worktreeStatus.hasNewCommits, onKeep: () => onExit(false), onRemove: () => onExit(true), onCancel: () => setIsExiting(false) }));
50
50
  }
51
- return (_jsx(ChatProvider, { bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, workdir: workdir, worktreeSession: worktreeSession, version: version, model: model, children: _jsx(ChatInterfaceWithRemount, {}) }));
52
- };
53
- export const ChatInterfaceWithRemount = () => {
54
- const { stdout } = useStdout();
55
- const { isExpanded, rewindId, sessionId } = useChat();
56
- const [remountKey, setRemountKey] = useState(String(isExpanded) + rewindId);
57
- const prevSessionId = useRef(sessionId);
58
- const isRemountScheduled = useRef(false);
59
- useEffect(() => {
60
- const newKey = String(isExpanded) +
61
- rewindId +
62
- (prevSessionId.current && sessionId && prevSessionId.current !== sessionId
63
- ? sessionId
64
- : "");
65
- if (newKey !== remountKey && !isRemountScheduled.current) {
66
- isRemountScheduled.current = true;
67
- const timeout = setTimeout(() => {
68
- stdout?.write("\u001b[2J\u001b[3J\u001b[0;0H", (err) => {
69
- if (err) {
70
- console.error("Failed to clear terminal:", err);
71
- }
72
- setRemountKey(newKey);
73
- isRemountScheduled.current = false;
74
- });
75
- }, 100);
76
- return () => clearTimeout(timeout);
77
- }
78
- if (sessionId) {
79
- prevSessionId.current = sessionId;
80
- }
81
- }, [isExpanded, rewindId, sessionId, remountKey, stdout]);
82
- return _jsx(ChatInterface, { remountKey: remountKey });
51
+ return (_jsx(ChatProvider, { bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, workdir: workdir, worktreeSession: worktreeSession, version: version, model: model, children: _jsx(ChatInterface, {}) }));
83
52
  };
84
53
  export const App = ({ restoreSessionId, continueLastSession, bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, version, model, onExit, }) => {
85
54
  return (_jsx(AppProvider, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, children: _jsx(AppWithProviders, { bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, worktreeSession: worktreeSession, workdir: workdir, version: version, model: model, onExit: onExit }) }));
@@ -1,5 +1,3 @@
1
1
  import React from "react";
2
- export declare const ChatInterface: React.FC<{
3
- remountKey: string;
4
- }>;
2
+ export declare const ChatInterface: React.FC;
5
3
  //# sourceMappingURL=ChatInterface.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CA0F1D,CAAC"}
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,EAmIjC,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box } from "ink";
2
+ import { useState, useRef, useEffect } from "react";
3
+ import { Box, useStdout, measureElement, Static } from "ink";
3
4
  import { MessageList } from "./MessageList.js";
4
5
  import { BtwDisplay } from "./BtwDisplay.js";
5
6
  import { InputBox } from "./InputBox.js";
@@ -9,10 +10,34 @@ import { QueuedMessageList } from "./QueuedMessageList.js";
9
10
  import { ConfirmationDetails } from "./ConfirmationDetails.js";
10
11
  import { ConfirmationSelector } from "./ConfirmationSelector.js";
11
12
  import { useChat } from "../contexts/useChat.js";
12
- export const ChatInterface = ({ remountKey, }) => {
13
- const { messages, isLoading, isCommandRunning, isCompressing, sendMessage, abortMessage, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, slashCommands, hasSlashCommand, isConfirmationVisible, confirmingTool, handleConfirmationDecision, handleConfirmationCancel, version, workdir, btwState, } = useChat();
13
+ 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();
14
15
  const displayMessages = messages;
16
+ const [forceStatic, setForceStatic] = useState(false);
17
+ const { stdout } = useStdout();
18
+ const terminalHeight = stdout?.rows ?? 24;
19
+ const chatInterfaceRef = useRef(null);
20
+ const prevForceStatic = useRef(forceStatic);
21
+ useEffect(() => {
22
+ if (isConfirmationVisible && chatInterfaceRef.current) {
23
+ const { height } = measureElement(chatInterfaceRef.current);
24
+ if (height > terminalHeight) {
25
+ setForceStatic(true);
26
+ }
27
+ }
28
+ else {
29
+ setForceStatic(false);
30
+ }
31
+ }, [isConfirmationVisible, terminalHeight]);
32
+ // Handle forceStatic transition - request remount when transitioning from true to false
33
+ // AND there are no more pending confirmations in the queue
34
+ useEffect(() => {
35
+ if (prevForceStatic.current && !forceStatic && !hasPendingConfirmations) {
36
+ requestRemount();
37
+ }
38
+ prevForceStatic.current = forceStatic;
39
+ }, [forceStatic, hasPendingConfirmations, requestRemount]);
15
40
  if (!sessionId)
16
41
  return null;
17
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(MessageList, { messages: displayMessages, isExpanded: isExpanded, version: version, workdir: workdir }, 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: [_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
+ 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 })] }))] }));
18
43
  };
@@ -7,5 +7,5 @@ export interface MessageListProps {
7
7
  version?: string;
8
8
  workdir?: string;
9
9
  }
10
- export declare const MessageList: React.MemoExoticComponent<({ messages, isExpanded, version, workdir }: MessageListProps) => import("react/jsx-runtime").JSX.Element>;
10
+ export declare const MessageList: React.MemoExoticComponent<({ messages, isExpanded, forceStatic, version, workdir, }: MessageListProps) => import("react/jsx-runtime").JSX.Element>;
11
11
  //# 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,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,yEAC+B,gBAAgB,6CAgHtE,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,6CAiHpB,CAAC"}
@@ -3,7 +3,7 @@ import React from "react";
3
3
  import os from "os";
4
4
  import { Box, Text, Static } from "ink";
5
5
  import { MessageBlockItem } from "./MessageBlockItem.js";
6
- export const MessageList = React.memo(({ messages, isExpanded = false, version, workdir }) => {
6
+ export const MessageList = React.memo(({ messages, isExpanded = false, forceStatic = false, version, workdir, }) => {
7
7
  const welcomeMessage = (_jsxs(Box, { flexDirection: "column", paddingTop: 1, children: [_jsxs(Text, { color: "gray", children: ["WAVE", version ? ` v${version}` : ""] }), workdir && (_jsx(Text, { color: "gray", wrap: "truncate-middle", children: workdir.replace(os.homedir(), "~") }))] }));
8
8
  // Limit messages to prevent long rendering times
9
9
  const maxMessages = 10;
@@ -29,7 +29,8 @@ export const MessageList = React.memo(({ messages, isExpanded = false, version,
29
29
  // Determine which blocks are static vs dynamic
30
30
  const blocksWithStatus = allBlocks.map((item) => {
31
31
  const { block } = item;
32
- const isDynamic = messagesWithRunningBlocks.has(item.messageIndex) || isRunning(block);
32
+ const isDynamic = !forceStatic &&
33
+ (messagesWithRunningBlocks.has(item.messageIndex) || isRunning(block));
33
34
  return { ...item, isDynamic };
34
35
  });
35
36
  const staticBlocks = blocksWithStatus.filter((b) => !b.isDynamic);
@@ -47,6 +47,7 @@ export interface ChatContextType {
47
47
  setPermissionMode: (mode: PermissionMode) => void;
48
48
  allowBypassInCycle: boolean;
49
49
  isConfirmationVisible: boolean;
50
+ hasPendingConfirmations: boolean;
50
51
  confirmingTool?: {
51
52
  name: string;
52
53
  input?: Record<string, unknown>;
@@ -59,7 +60,8 @@ export interface ChatContextType {
59
60
  handleConfirmationDecision: (decision: PermissionDecision) => void;
60
61
  handleConfirmationCancel: () => void;
61
62
  backgroundCurrentTask: () => void;
62
- rewindId: number;
63
+ remountKey: number;
64
+ requestRemount: () => void;
63
65
  handleRewindSelect: (index: number) => Promise<void>;
64
66
  getFullMessageThread: () => Promise<{
65
67
  messages: Message[];
@@ -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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"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createContext, useContext, useCallback, useRef, useEffect, useState, useMemo, } from "react";
3
- import { useInput } from "ink";
3
+ import { useInput, useStdout } from "ink";
4
4
  import { useAppConfig } from "./useAppConfig.js";
5
5
  import { Agent, OPERATION_CANCELLED_BY_USER, cloneMessage, } from "wave-agent-sdk";
6
6
  import { logger } from "../utils/logger.js";
@@ -17,6 +17,7 @@ export const useChat = () => {
17
17
  };
18
18
  export const ChatProvider = ({ children, bypassPermissions, permissionMode: initialPermissionMode, pluginDirs, tools, allowedTools, disallowedTools, workdir, worktreeSession, version, model, }) => {
19
19
  const { restoreSessionId, continueLastSession } = useAppConfig();
20
+ const { stdout } = useStdout();
20
21
  // Message Display State
21
22
  const [isExpanded, setIsExpanded] = useState(false);
22
23
  const isExpandedRef = useRef(isExpanded);
@@ -62,8 +63,31 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
62
63
  const [confirmingTool, setConfirmingTool] = useState();
63
64
  const [confirmationQueue, setConfirmationQueue] = useState([]);
64
65
  const [currentConfirmation, setCurrentConfirmation] = useState(null);
65
- // Rewind state
66
- const [rewindId, setRewindId] = useState(0);
66
+ // Remount state
67
+ const [remountKey, setRemountKey] = useState(0);
68
+ const prevRemountKey = useRef(remountKey);
69
+ const prevSessionId = useRef(null);
70
+ // Track sessionId changes to trigger remount
71
+ useEffect(() => {
72
+ if (prevSessionId.current &&
73
+ sessionId &&
74
+ prevSessionId.current !== sessionId) {
75
+ setRemountKey((prev) => prev + 1);
76
+ }
77
+ if (sessionId) {
78
+ prevSessionId.current = sessionId;
79
+ }
80
+ }, [sessionId]);
81
+ // Clear terminal when remountKey changes
82
+ useEffect(() => {
83
+ if (remountKey !== prevRemountKey.current && prevRemountKey.current !== 0) {
84
+ stdout?.write("\u001b[2J\u001b[3J\u001b[0;0H");
85
+ }
86
+ prevRemountKey.current = remountKey;
87
+ }, [remountKey, stdout]);
88
+ const requestRemount = useCallback(() => {
89
+ setRemountKey((prev) => prev + 1);
90
+ }, []);
67
91
  // Status metadata state
68
92
  const [workingDirectory, setWorkingDirectory] = useState("");
69
93
  // /btw state
@@ -370,8 +394,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
370
394
  if (agentRef.current) {
371
395
  try {
372
396
  await agentRef.current.truncateHistory(index);
373
- // Clear terminal screen after rewind
374
- setRewindId((prev) => prev + 1);
397
+ setRemountKey((prev) => prev + 1);
375
398
  }
376
399
  catch (error) {
377
400
  logger.error("Failed to rewind:", error);
@@ -486,13 +509,15 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
486
509
  setPermissionMode,
487
510
  allowBypassInCycle,
488
511
  isConfirmationVisible,
512
+ hasPendingConfirmations: confirmationQueue.length > 0,
489
513
  confirmingTool,
490
514
  showConfirmation,
491
515
  hideConfirmation,
492
516
  handleConfirmationDecision,
493
517
  handleConfirmationCancel,
494
518
  backgroundCurrentTask,
495
- rewindId,
519
+ remountKey,
520
+ requestRemount,
496
521
  handleRewindSelect,
497
522
  getFullMessageThread,
498
523
  getGatewayConfig,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-code",
3
- "version": "0.12.3",
3
+ "version": "0.12.4",
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.3"
45
+ "wave-agent-sdk": "0.12.4"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/react": "^19.1.8",
@@ -1,7 +1,7 @@
1
- import React, { useState, useEffect, useRef, useCallback } from "react";
2
- import { useStdout, useInput } from "ink";
1
+ import React, { useState, useEffect, useCallback } from "react";
2
+ import { useInput } from "ink";
3
3
  import { ChatInterface } from "./ChatInterface.js";
4
- import { ChatProvider, useChat } from "../contexts/useChat.js";
4
+ import { ChatProvider } from "../contexts/useChat.js";
5
5
  import { AppProvider } from "../contexts/useAppConfig.js";
6
6
  import { WorktreeExitPrompt } from "./WorktreeExitPrompt.js";
7
7
  import {
@@ -107,52 +107,11 @@ const AppWithProviders: React.FC<AppWithProvidersProps> = ({
107
107
  version={version}
108
108
  model={model}
109
109
  >
110
- <ChatInterfaceWithRemount />
110
+ <ChatInterface />
111
111
  </ChatProvider>
112
112
  );
113
113
  };
114
114
 
115
- export const ChatInterfaceWithRemount: React.FC = () => {
116
- const { stdout } = useStdout();
117
- const { isExpanded, rewindId, sessionId } = useChat();
118
-
119
- const [remountKey, setRemountKey] = useState(String(isExpanded) + rewindId);
120
-
121
- const prevSessionId = useRef(sessionId);
122
- const isRemountScheduled = useRef(false);
123
-
124
- useEffect(() => {
125
- const newKey =
126
- String(isExpanded) +
127
- rewindId +
128
- (prevSessionId.current && sessionId && prevSessionId.current !== sessionId
129
- ? sessionId
130
- : "");
131
-
132
- if (newKey !== remountKey && !isRemountScheduled.current) {
133
- isRemountScheduled.current = true;
134
-
135
- const timeout = setTimeout(() => {
136
- stdout?.write("\u001b[2J\u001b[3J\u001b[0;0H", (err?: Error | null) => {
137
- if (err) {
138
- console.error("Failed to clear terminal:", err);
139
- }
140
- setRemountKey(newKey);
141
- isRemountScheduled.current = false;
142
- });
143
- }, 100);
144
-
145
- return () => clearTimeout(timeout);
146
- }
147
-
148
- if (sessionId) {
149
- prevSessionId.current = sessionId;
150
- }
151
- }, [isExpanded, rewindId, sessionId, remountKey, stdout]);
152
-
153
- return <ChatInterface remountKey={remountKey} />;
154
- };
155
-
156
115
  export const App: React.FC<AppProps> = ({
157
116
  restoreSessionId,
158
117
  continueLastSession,
@@ -1,5 +1,6 @@
1
- import React from "react";
2
- import { Box } from "ink";
1
+ import React, { useState, useRef, useEffect } from "react";
2
+ import { Box, useStdout, measureElement, Static } from "ink";
3
+ import type { DOMElement } from "ink";
3
4
  import { MessageList } from "./MessageList.js";
4
5
  import { BtwDisplay } from "./BtwDisplay.js";
5
6
  import { InputBox } from "./InputBox.js";
@@ -11,9 +12,7 @@ import { ConfirmationSelector } from "./ConfirmationSelector.js";
11
12
 
12
13
  import { useChat } from "../contexts/useChat.js";
13
14
 
14
- export const ChatInterface: React.FC<{ remountKey: string }> = ({
15
- remountKey,
16
- }) => {
15
+ export const ChatInterface: React.FC = () => {
17
16
  const {
18
17
  messages,
19
18
  isLoading,
@@ -30,26 +29,56 @@ export const ChatInterface: React.FC<{ remountKey: string }> = ({
30
29
  slashCommands,
31
30
  hasSlashCommand,
32
31
  isConfirmationVisible,
32
+ hasPendingConfirmations,
33
33
  confirmingTool,
34
34
  handleConfirmationDecision,
35
35
  handleConfirmationCancel,
36
36
  version,
37
37
  workdir,
38
38
  btwState,
39
+ remountKey,
40
+ requestRemount,
39
41
  } = useChat();
40
42
 
41
43
  const displayMessages = messages;
42
44
 
45
+ const [forceStatic, setForceStatic] = useState(false);
46
+ const { stdout } = useStdout();
47
+ const terminalHeight = stdout?.rows ?? 24;
48
+ const chatInterfaceRef = useRef<DOMElement>(null);
49
+ const prevForceStatic = useRef(forceStatic);
50
+
51
+ useEffect(() => {
52
+ if (isConfirmationVisible && chatInterfaceRef.current) {
53
+ const { height } = measureElement(chatInterfaceRef.current);
54
+ if (height > terminalHeight) {
55
+ setForceStatic(true);
56
+ }
57
+ } else {
58
+ setForceStatic(false);
59
+ }
60
+ }, [isConfirmationVisible, terminalHeight]);
61
+
62
+ // Handle forceStatic transition - request remount when transitioning from true to false
63
+ // AND there are no more pending confirmations in the queue
64
+ useEffect(() => {
65
+ if (prevForceStatic.current && !forceStatic && !hasPendingConfirmations) {
66
+ requestRemount();
67
+ }
68
+ prevForceStatic.current = forceStatic;
69
+ }, [forceStatic, hasPendingConfirmations, requestRemount]);
70
+
43
71
  if (!sessionId) return null;
44
72
 
45
73
  return (
46
- <Box flexDirection="column">
74
+ <Box ref={chatInterfaceRef} flexDirection="column">
47
75
  <MessageList
48
76
  key={remountKey}
49
77
  messages={displayMessages}
50
78
  isExpanded={isExpanded}
51
79
  version={version}
52
80
  workdir={workdir}
81
+ forceStatic={forceStatic}
53
82
  />
54
83
 
55
84
  {!isConfirmationVisible && !isExpanded && (
@@ -81,12 +110,25 @@ export const ChatInterface: React.FC<{ remountKey: string }> = ({
81
110
 
82
111
  {isConfirmationVisible && (
83
112
  <>
84
- <ConfirmationDetails
85
- toolName={confirmingTool!.name}
86
- toolInput={confirmingTool!.input}
87
- planContent={confirmingTool!.planContent}
88
- isExpanded={isExpanded}
89
- />
113
+ {forceStatic ? (
114
+ <Static items={[{ key: "confirmation-details" }]}>
115
+ {() => (
116
+ <ConfirmationDetails
117
+ toolName={confirmingTool!.name}
118
+ toolInput={confirmingTool!.input}
119
+ planContent={confirmingTool!.planContent}
120
+ isExpanded={isExpanded}
121
+ />
122
+ )}
123
+ </Static>
124
+ ) : (
125
+ <ConfirmationDetails
126
+ toolName={confirmingTool!.name}
127
+ toolInput={confirmingTool!.input}
128
+ planContent={confirmingTool!.planContent}
129
+ isExpanded={isExpanded}
130
+ />
131
+ )}
90
132
  <ConfirmationSelector
91
133
  toolName={confirmingTool!.name}
92
134
  toolInput={confirmingTool!.input}
@@ -13,7 +13,13 @@ export interface MessageListProps {
13
13
  }
14
14
 
15
15
  export const MessageList = React.memo(
16
- ({ messages, isExpanded = false, version, workdir }: MessageListProps) => {
16
+ ({
17
+ messages,
18
+ isExpanded = false,
19
+ forceStatic = false,
20
+ version,
21
+ workdir,
22
+ }: MessageListProps) => {
17
23
  const welcomeMessage = (
18
24
  <Box flexDirection="column" paddingTop={1}>
19
25
  <Text color="gray">WAVE{version ? ` v${version}` : ""}</Text>
@@ -58,7 +64,8 @@ export const MessageList = React.memo(
58
64
  const blocksWithStatus = allBlocks.map((item) => {
59
65
  const { block } = item;
60
66
  const isDynamic =
61
- messagesWithRunningBlocks.has(item.messageIndex) || isRunning(block);
67
+ !forceStatic &&
68
+ (messagesWithRunningBlocks.has(item.messageIndex) || isRunning(block));
62
69
  return { ...item, isDynamic };
63
70
  });
64
71
 
@@ -7,7 +7,7 @@ import React, {
7
7
  useState,
8
8
  useMemo,
9
9
  } from "react";
10
- import { useInput } from "ink";
10
+ import { useInput, useStdout } from "ink";
11
11
  import { useAppConfig } from "./useAppConfig.js";
12
12
  import type {
13
13
  Message,
@@ -86,6 +86,7 @@ export interface ChatContextType {
86
86
  allowBypassInCycle: boolean;
87
87
  // Permission confirmation state
88
88
  isConfirmationVisible: boolean;
89
+ hasPendingConfirmations: boolean;
89
90
  confirmingTool?: {
90
91
  name: string;
91
92
  input?: Record<string, unknown>;
@@ -105,8 +106,10 @@ export interface ChatContextType {
105
106
  handleConfirmationCancel: () => void;
106
107
  // Background current task
107
108
  backgroundCurrentTask: () => void;
109
+ // Remount functionality
110
+ remountKey: number;
111
+ requestRemount: () => void;
108
112
  // Rewind functionality
109
- rewindId: number;
110
113
  handleRewindSelect: (index: number) => Promise<void>;
111
114
  getFullMessageThread: () => Promise<{
112
115
  messages: Message[];
@@ -152,6 +155,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
152
155
  model,
153
156
  }) => {
154
157
  const { restoreSessionId, continueLastSession } = useAppConfig();
158
+ const { stdout } = useStdout();
155
159
 
156
160
  // Message Display State
157
161
  const [isExpanded, setIsExpanded] = useState(false);
@@ -250,8 +254,36 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
250
254
  reject: () => void;
251
255
  } | null>(null);
252
256
 
253
- // Rewind state
254
- const [rewindId, setRewindId] = useState(0);
257
+ // Remount state
258
+ const [remountKey, setRemountKey] = useState(0);
259
+ const prevRemountKey = useRef(remountKey);
260
+ const prevSessionId = useRef<string | null>(null);
261
+
262
+ // Track sessionId changes to trigger remount
263
+ useEffect(() => {
264
+ if (
265
+ prevSessionId.current &&
266
+ sessionId &&
267
+ prevSessionId.current !== sessionId
268
+ ) {
269
+ setRemountKey((prev) => prev + 1);
270
+ }
271
+ if (sessionId) {
272
+ prevSessionId.current = sessionId;
273
+ }
274
+ }, [sessionId]);
275
+
276
+ // Clear terminal when remountKey changes
277
+ useEffect(() => {
278
+ if (remountKey !== prevRemountKey.current && prevRemountKey.current !== 0) {
279
+ stdout?.write("\u001b[2J\u001b[3J\u001b[0;0H");
280
+ }
281
+ prevRemountKey.current = remountKey;
282
+ }, [remountKey, stdout]);
283
+
284
+ const requestRemount = useCallback(() => {
285
+ setRemountKey((prev) => prev + 1);
286
+ }, []);
255
287
 
256
288
  // Status metadata state
257
289
  const [workingDirectory, setWorkingDirectory] = useState("");
@@ -627,9 +659,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
627
659
  if (agentRef.current) {
628
660
  try {
629
661
  await agentRef.current.truncateHistory(index);
630
-
631
- // Clear terminal screen after rewind
632
- setRewindId((prev) => prev + 1);
662
+ setRemountKey((prev) => prev + 1);
633
663
  } catch (error) {
634
664
  logger.error("Failed to rewind:", error);
635
665
  }
@@ -749,13 +779,15 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
749
779
  setPermissionMode,
750
780
  allowBypassInCycle,
751
781
  isConfirmationVisible,
782
+ hasPendingConfirmations: confirmationQueue.length > 0,
752
783
  confirmingTool,
753
784
  showConfirmation,
754
785
  hideConfirmation,
755
786
  handleConfirmationDecision,
756
787
  handleConfirmationCancel,
757
788
  backgroundCurrentTask,
758
- rewindId,
789
+ remountKey,
790
+ requestRemount,
759
791
  handleRewindSelect,
760
792
  getFullMessageThread,
761
793