wave-code 0.12.0 → 0.12.2

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 (66) hide show
  1. package/README.md +9 -51
  2. package/dist/acp/agent.js +1 -1
  3. package/dist/components/App.d.ts +1 -0
  4. package/dist/components/App.d.ts.map +1 -1
  5. package/dist/components/App.js +5 -2
  6. package/dist/components/BackgroundTaskManager.d.ts.map +1 -1
  7. package/dist/components/BackgroundTaskManager.js +2 -1
  8. package/dist/components/BangDisplay.d.ts.map +1 -1
  9. package/dist/components/BangDisplay.js +2 -14
  10. package/dist/components/ChatInterface.d.ts.map +1 -1
  11. package/dist/components/ChatInterface.js +17 -27
  12. package/dist/components/ConfirmationDetails.d.ts +0 -1
  13. package/dist/components/ConfirmationDetails.d.ts.map +1 -1
  14. package/dist/components/ConfirmationDetails.js +4 -12
  15. package/dist/components/ConfirmationSelector.d.ts +0 -1
  16. package/dist/components/ConfirmationSelector.d.ts.map +1 -1
  17. package/dist/components/ConfirmationSelector.js +4 -12
  18. package/dist/components/DiffDisplay.d.ts.map +1 -1
  19. package/dist/components/DiffDisplay.js +2 -23
  20. package/dist/components/MessageList.d.ts +1 -2
  21. package/dist/components/MessageList.d.ts.map +1 -1
  22. package/dist/components/MessageList.js +12 -17
  23. package/dist/components/RewindCommand.d.ts.map +1 -1
  24. package/dist/components/RewindCommand.js +2 -4
  25. package/dist/components/StatusCommand.d.ts.map +1 -1
  26. package/dist/components/StatusCommand.js +1 -1
  27. package/dist/components/ToolDisplay.d.ts.map +1 -1
  28. package/dist/components/ToolDisplay.js +3 -6
  29. package/dist/contexts/useChat.d.ts +0 -2
  30. package/dist/contexts/useChat.d.ts.map +1 -1
  31. package/dist/contexts/useChat.js +27 -44
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +10 -0
  34. package/dist/utils/highlightUtils.d.ts.map +1 -1
  35. package/dist/utils/highlightUtils.js +0 -8
  36. package/dist/utils/logger.d.ts.map +1 -1
  37. package/dist/utils/logger.js +13 -11
  38. package/dist/utils/throttle.d.ts +15 -0
  39. package/dist/utils/throttle.d.ts.map +1 -0
  40. package/dist/utils/throttle.js +55 -0
  41. package/dist/utils/toolParameterTransforms.d.ts +5 -1
  42. package/dist/utils/toolParameterTransforms.d.ts.map +1 -1
  43. package/dist/utils/toolParameterTransforms.js +14 -0
  44. package/dist/utils/worktree.d.ts +0 -1
  45. package/dist/utils/worktree.d.ts.map +1 -1
  46. package/dist/utils/worktree.js +2 -2
  47. package/package.json +3 -3
  48. package/src/acp/agent.ts +1 -1
  49. package/src/components/App.tsx +6 -2
  50. package/src/components/BackgroundTaskManager.tsx +3 -6
  51. package/src/components/BangDisplay.tsx +4 -22
  52. package/src/components/ChatInterface.tsx +18 -33
  53. package/src/components/ConfirmationDetails.tsx +2 -15
  54. package/src/components/ConfirmationSelector.tsx +3 -15
  55. package/src/components/DiffDisplay.tsx +2 -27
  56. package/src/components/MessageList.tsx +17 -20
  57. package/src/components/RewindCommand.tsx +3 -5
  58. package/src/components/StatusCommand.tsx +7 -0
  59. package/src/components/ToolDisplay.tsx +3 -6
  60. package/src/contexts/useChat.tsx +34 -59
  61. package/src/index.ts +13 -0
  62. package/src/utils/highlightUtils.ts +0 -8
  63. package/src/utils/logger.ts +12 -14
  64. package/src/utils/throttle.ts +75 -0
  65. package/src/utils/toolParameterTransforms.ts +23 -1
  66. package/src/utils/worktree.ts +7 -3
package/README.md CHANGED
@@ -31,38 +31,26 @@ export WAVE_API_KEY="your_token_here"
31
31
 
32
32
  # AI Gateway API URL (required)
33
33
  export WAVE_BASE_URL="https://your-api-gateway-url.com"
34
+
35
+ # AI model (required)
36
+ export WAVE_MODEL="MiniMax-M2.7"
37
+
38
+ # Fast AI model (required)
39
+ export WAVE_FAST_MODEL="MiniMax-M2.7-highspeed"
34
40
  ```
35
41
 
36
42
  ### Optional Environment Variables
37
43
 
38
44
  ```bash
39
- # Specify AI model (optional, defaults to gemini-3-flash)
40
- export WAVE_MODEL="gemini-3-flash"
41
-
42
- # Specify fast AI model (optional, defaults to gemini-2.5-flash)
43
- export WAVE_FAST_MODEL="gemini-2.5-flash"
44
-
45
45
  # Token limit (optional, defaults to 96000)
46
46
  export WAVE_MAX_INPUT_TOKENS="96000"
47
-
48
47
  ```
49
48
 
50
49
  ## Usage
51
50
 
52
- ### Full Command
53
-
54
51
  ```bash
55
52
  # Start the CLI
56
- wave-code
57
-
58
- # Continue from last session
59
- wave-code --continue
60
-
61
- # Restore specific session
62
- wave-code --restore session_id
63
-
64
- # List available sessions
65
- wave-code --list-sessions
53
+ wave-code -h
66
54
  ```
67
55
 
68
56
  ### Short Command (wave)
@@ -70,42 +58,12 @@ wave-code --list-sessions
70
58
  For convenience, you can also use the shorter `wave` command:
71
59
 
72
60
  ```bash
73
- # Start the CLI (equivalent to wave-code)
74
- wave
75
-
76
- # Continue from last session
77
- wave --continue
78
-
79
- # Restore specific session
80
- wave --restore session_id
81
-
82
- # List available sessions
83
- wave --list-sessions
84
-
85
- # Show help
86
- wave --help
61
+ # Start the CLI
62
+ wave -h
87
63
  ```
88
64
 
89
65
  The `wave` command is an alias for `wave-code` and supports all the same options and functionality.
90
66
 
91
- ## Development
92
-
93
- This package depends on `wave-agent-sdk` for core functionality including AI services, tools, and utilities.
94
-
95
- ```bash
96
- # Install dependencies
97
- pnpm install
98
-
99
- # Start development
100
- pnpm dev
101
-
102
- # Build
103
- pnpm build
104
-
105
- # Test
106
- pnpm test
107
- ```
108
-
109
67
  ## License
110
68
 
111
69
  MIT
package/dist/acp/agent.js CHANGED
@@ -508,7 +508,7 @@ export class WaveAcpAgent {
508
508
  },
509
509
  });
510
510
  }
511
- if (contents.length === 0) {
511
+ if (name.startsWith("mcp__")) {
512
512
  contents.push({
513
513
  type: "content",
514
514
  content: {
@@ -5,6 +5,7 @@ interface AppProps extends BaseAppProps {
5
5
  continueLastSession?: boolean;
6
6
  onExit: (shouldRemove: boolean) => void;
7
7
  }
8
+ export declare const ChatInterfaceWithRemount: React.FC;
8
9
  export declare const App: React.FC<AppProps>;
9
10
  export {};
10
11
  //# 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;AAgJD,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,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,EAiD5C,CAAC;AAEF,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAmClC,CAAC"}
@@ -50,11 +50,12 @@ const AppWithProviders = ({ bypassPermissions, permissionMode, pluginDirs, tools
50
50
  }
51
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
52
  };
53
- const ChatInterfaceWithRemount = () => {
53
+ export const ChatInterfaceWithRemount = () => {
54
54
  const { stdout } = useStdout();
55
55
  const { isExpanded, rewindId, wasLastDetailsTooTall, sessionId } = useChat();
56
56
  const [remountKey, setRemountKey] = useState(String(isExpanded) + rewindId + wasLastDetailsTooTall);
57
57
  const prevSessionId = useRef(sessionId);
58
+ const isRemountScheduled = useRef(false);
58
59
  useEffect(() => {
59
60
  const newKey = String(isExpanded) +
60
61
  rewindId +
@@ -62,13 +63,15 @@ const ChatInterfaceWithRemount = () => {
62
63
  (prevSessionId.current && sessionId && prevSessionId.current !== sessionId
63
64
  ? sessionId
64
65
  : "");
65
- if (newKey !== remountKey) {
66
+ if (newKey !== remountKey && !isRemountScheduled.current) {
67
+ isRemountScheduled.current = true;
66
68
  const timeout = setTimeout(() => {
67
69
  stdout?.write("\u001b[2J\u001b[3J\u001b[0;0H", (err) => {
68
70
  if (err) {
69
71
  console.error("Failed to clear terminal:", err);
70
72
  }
71
73
  setRemountKey(newKey);
74
+ isRemountScheduled.current = false;
72
75
  });
73
76
  }, 100);
74
77
  return () => clearTimeout(timeout);
@@ -1 +1 @@
1
- {"version":3,"file":"BackgroundTaskManager.d.ts","sourceRoot":"","sources":["../../src/components/BackgroundTaskManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAenD,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CA6UtE,CAAC"}
1
+ {"version":3,"file":"BackgroundTaskManager.d.ts","sourceRoot":"","sources":["../../src/components/BackgroundTaskManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAgBnD,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAyUtE,CAAC"}
@@ -2,6 +2,7 @@ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useState, useEffect } from "react";
3
3
  import { Box, Text, useInput } from "ink";
4
4
  import { useChat } from "../contexts/useChat.js";
5
+ import { getLastLines } from "wave-agent-sdk";
5
6
  export const BackgroundTaskManager = ({ onCancel, }) => {
6
7
  const { backgroundTasks, getBackgroundTaskOutput, stopBackgroundTask } = useChat();
7
8
  const [tasks, setTasks] = useState([]);
@@ -102,7 +103,7 @@ export const BackgroundTaskManager = ({ onCancel, }) => {
102
103
  setViewMode("list");
103
104
  return null;
104
105
  }
105
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "cyan", bold: true, children: ["Background Task Details: ", task.id] }) }), _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Type:" }), " ", task.type] }) }), task.description && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Description:" }), " ", task.description] }) })), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Status:" }), " ", task.status, task.exitCode !== undefined && ` (exit code: ${task.exitCode})`] }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Started:" }), " ", formatTime(task.startTime), task.runtime !== undefined && (_jsxs(Text, { children: [" ", "| ", _jsx(Text, { color: "blue", children: "Runtime:" }), " ", formatDuration(task.runtime)] }))] }) }), task.outputPath && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Log File:" }), " ", task.outputPath] }) }))] }), detailOutput.stdout && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "green", bold: true, children: "OUTPUT (last 10 lines):" }), _jsx(Box, { borderStyle: "single", borderColor: "green", padding: 1, children: _jsx(Text, { children: detailOutput.stdout.split("\n").slice(-10).join("\n") }) })] })), detailOutput.stderr && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "red", bold: true, children: "ERRORS:" }), _jsx(Box, { borderStyle: "single", borderColor: "red", padding: 1, children: _jsx(Text, { color: "red", children: detailOutput.stderr.split("\n").slice(-10).join("\n") }) })] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: [task.status === "running" ? "k to stop · " : "", "Esc to go back"] }) })] }));
106
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "cyan", bold: true, children: ["Background Task Details: ", task.id] }) }), _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Type:" }), " ", task.type] }) }), task.description && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Description:" }), " ", task.description] }) })), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Status:" }), " ", task.status, task.exitCode !== undefined && ` (exit code: ${task.exitCode})`] }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Started:" }), " ", formatTime(task.startTime), task.runtime !== undefined && (_jsxs(Text, { children: [" ", "| ", _jsx(Text, { color: "blue", children: "Runtime:" }), " ", formatDuration(task.runtime)] }))] }) }), task.outputPath && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Log File:" }), " ", task.outputPath] }) }))] }), detailOutput.stdout && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "green", bold: true, children: "OUTPUT (last 10 lines):" }), _jsx(Box, { borderStyle: "single", borderColor: "green", padding: 1, children: _jsx(Text, { children: getLastLines(detailOutput.stdout, 10) }) })] })), detailOutput.stderr && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "red", bold: true, children: "ERRORS:" }), _jsx(Box, { borderStyle: "single", borderColor: "red", padding: 1, children: _jsx(Text, { color: "red", children: getLastLines(detailOutput.stderr, 10) }) })] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: [task.status === "running" ? "k to stop · " : "", "Esc to go back"] }) })] }));
106
107
  }
107
108
  if (!backgroundTasks) {
108
109
  return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "Background Tasks" }), _jsx(Text, { children: "Background tasks not available" }), _jsx(Text, { dimColor: true, children: "Press Escape to close" })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"BangDisplay.d.ts","sourceRoot":"","sources":["../../src/components/BangDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,UAAU,gBAAgB;IACxB,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAiDlD,CAAC"}
1
+ {"version":3,"file":"BangDisplay.d.ts","sourceRoot":"","sources":["../../src/components/BangDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,UAAU,gBAAgB;IACxB,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA8BlD,CAAC"}
@@ -1,17 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect } from "react";
3
2
  import { Box, Text } from "ink";
3
+ import { getLastLines } from "wave-agent-sdk";
4
4
  export const BangDisplay = ({ block, isExpanded = false, }) => {
5
5
  const { command, output, isRunning, exitCode } = block;
6
- const [isOverflowing, setIsOverflowing] = useState(false);
7
6
  const MAX_LINES = 3; // Set maximum display lines
8
- // Detect if content is overflowing
9
- useEffect(() => {
10
- if (output) {
11
- const lines = output.split("\n");
12
- setIsOverflowing(!isExpanded && lines.length > MAX_LINES);
13
- }
14
- }, [output, isExpanded]);
15
7
  const getStatusColor = () => {
16
8
  if (isRunning)
17
9
  return "yellow";
@@ -21,9 +13,5 @@ export const BangDisplay = ({ block, isExpanded = false, }) => {
21
13
  return "red";
22
14
  return "gray"; // Unknown state
23
15
  };
24
- return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: getStatusColor(), children: "! " }), _jsx(Text, { color: "white", children: command })] }), output && (_jsx(Box, { paddingLeft: 2, height: isExpanded
25
- ? undefined
26
- : Math.min(output.split("\n").length, MAX_LINES), overflow: "hidden", children: _jsx(Text, { color: "gray", children: isOverflowing
27
- ? output.split("\n").slice(-MAX_LINES).join("\n")
28
- : output }) }))] }));
16
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: getStatusColor(), children: "! " }), _jsx(Text, { color: "white", children: command })] }), output && (_jsx(Box, { paddingLeft: 2, overflow: "hidden", children: _jsx(Text, { color: "gray", children: isExpanded ? output : getLastLines(output, MAX_LINES) }) }))] }));
29
17
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AActE,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAqKjC,CAAC"}
1
+ {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyD,MAAM,OAAO,CAAC;AAc9E,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAsJjC,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useCallback, useLayoutEffect } from "react";
3
- import { Box, useStdout } from "ink";
2
+ import { useState, useCallback, useLayoutEffect, useRef } from "react";
3
+ import { Box, useStdout, measureElement } from "ink";
4
4
  import { MessageList } from "./MessageList.js";
5
5
  import { BtwDisplay } from "./BtwDisplay.js";
6
6
  import { InputBox } from "./InputBox.js";
@@ -12,45 +12,35 @@ import { ConfirmationSelector } from "./ConfirmationSelector.js";
12
12
  import { useChat } from "../contexts/useChat.js";
13
13
  export const ChatInterface = () => {
14
14
  const { stdout } = useStdout();
15
- const [detailsHeight, setDetailsHeight] = useState(0);
16
- const [selectorHeight, setSelectorHeight] = useState(0);
17
- const [dynamicBlocksHeight, setDynamicBlocksHeight] = useState(0);
18
15
  const [isConfirmationTooTall, setIsConfirmationTooTall] = useState(false);
19
16
  const { messages, isLoading, isCommandRunning, isCompressing, sendMessage, abortMessage, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, slashCommands, hasSlashCommand, isConfirmationVisible, confirmingTool, handleConfirmationDecision, handleConfirmationCancel: originalHandleConfirmationCancel, setWasLastDetailsTooTall, version, workdir, btwState, } = useChat();
20
- const displayMessages = messages;
21
- const handleDetailsHeightMeasured = useCallback((height) => {
22
- setDetailsHeight(height);
23
- }, []);
24
- const handleSelectorHeightMeasured = useCallback((height) => {
25
- setSelectorHeight(height);
26
- }, []);
27
- const handleDynamicBlocksHeightMeasured = useCallback((height) => {
28
- setDynamicBlocksHeight(height);
29
- }, []);
17
+ const interfaceRef = useRef(null);
30
18
  useLayoutEffect(() => {
31
19
  if (!isConfirmationVisible) {
32
20
  setIsConfirmationTooTall(false);
33
- setDetailsHeight(0);
34
- setSelectorHeight(0);
35
- setDynamicBlocksHeight(0);
36
21
  return;
37
22
  }
38
23
  if (isConfirmationTooTall) {
39
24
  return;
40
25
  }
41
- const terminalHeight = stdout?.rows || 24;
42
- const totalHeight = detailsHeight + selectorHeight + dynamicBlocksHeight;
43
- if (totalHeight > terminalHeight - 3) {
44
- setIsConfirmationTooTall(true);
26
+ if (interfaceRef.current) {
27
+ const { height } = measureElement(interfaceRef.current);
28
+ const terminalHeight = stdout?.rows || 24;
29
+ if (height > terminalHeight - 3) {
30
+ setIsConfirmationTooTall(true);
31
+ }
45
32
  }
46
33
  }, [
47
- detailsHeight,
48
- selectorHeight,
49
- dynamicBlocksHeight,
50
- stdout?.rows,
34
+ messages,
35
+ isLoading,
36
+ isCommandRunning,
37
+ isCompressing,
38
+ isExpanded,
51
39
  isConfirmationVisible,
52
40
  isConfirmationTooTall,
41
+ stdout?.rows,
53
42
  ]);
43
+ const displayMessages = messages;
54
44
  const handleConfirmationCancel = useCallback(() => {
55
45
  if (isConfirmationTooTall) {
56
46
  setWasLastDetailsTooTall((prev) => prev + 1);
@@ -75,5 +65,5 @@ export const ChatInterface = () => {
75
65
  ]);
76
66
  if (!sessionId)
77
67
  return null;
78
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(MessageList, { messages: displayMessages, isExpanded: isExpanded, forceStatic: isConfirmationVisible && isConfirmationTooTall, version: version, workdir: workdir, onDynamicBlocksHeightMeasured: handleDynamicBlocksHeightMeasured }), !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, 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 })] }))] }));
68
+ return (_jsxs(Box, { ref: interfaceRef, flexDirection: "column", children: [_jsx(MessageList, { messages: displayMessages, isExpanded: isExpanded, forceStatic: isConfirmationVisible && isConfirmationTooTall, version: version, workdir: workdir }), !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, isStatic: isConfirmationTooTall }), _jsx(ConfirmationSelector, { toolName: confirmingTool.name, toolInput: confirmingTool.input, suggestedPrefix: confirmingTool.suggestedPrefix, hidePersistentOption: confirmingTool.hidePersistentOption, isExpanded: isExpanded, onDecision: wrappedHandleConfirmationDecision, onCancel: handleConfirmationCancel, onAbort: abortMessage })] }))] }));
79
69
  };
@@ -4,7 +4,6 @@ export interface ConfirmationDetailsProps {
4
4
  toolInput?: Record<string, unknown>;
5
5
  planContent?: string;
6
6
  isExpanded?: boolean;
7
- onHeightMeasured?: (height: number) => void;
8
7
  isStatic?: boolean;
9
8
  }
10
9
  export declare const ConfirmationDetails: React.FC<ConfirmationDetailsProps>;
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmationDetails.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationDetails.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkC,MAAM,OAAO,CAAC;AAsCvD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAyElE,CAAC"}
1
+ {"version":3,"file":"ConfirmationDetails.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationDetails.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAsC1B,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA6DlE,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import React, { useLayoutEffect, useRef } from "react";
3
- import { Box, Text, useStdout, measureElement, Static } from "ink";
2
+ import React from "react";
3
+ import { Box, Text, Static } from "ink";
4
4
  import { BASH_TOOL_NAME, EDIT_TOOL_NAME, WRITE_TOOL_NAME, EXIT_PLAN_MODE_TOOL_NAME, ASK_USER_QUESTION_TOOL_NAME, } from "wave-agent-sdk";
5
5
  import { DiffDisplay } from "./DiffDisplay.js";
6
6
  import { PlanDisplay } from "./PlanDisplay.js";
@@ -25,18 +25,10 @@ const getActionDescription = (toolName, toolInput) => {
25
25
  return "Execute operation";
26
26
  }
27
27
  };
28
- export const ConfirmationDetails = ({ toolName, toolInput, planContent, isExpanded = false, onHeightMeasured, isStatic = false, }) => {
29
- const { stdout } = useStdout();
30
- const boxRef = useRef(null);
28
+ export const ConfirmationDetails = ({ toolName, toolInput, planContent, isExpanded = false, isStatic = false, }) => {
31
29
  const startLineNumber = toolInput?.startLineNumber ??
32
30
  (toolName === WRITE_TOOL_NAME ? 1 : undefined);
33
- useLayoutEffect(() => {
34
- if (boxRef.current) {
35
- const { height } = measureElement(boxRef.current);
36
- onHeightMeasured?.(height);
37
- }
38
- }, [stdout?.rows, onHeightMeasured, toolInput, isExpanded]);
39
- const content = (_jsxs(Box, { ref: boxRef, flexDirection: "column", borderStyle: "single", borderColor: "yellow", borderBottom: false, borderLeft: false, borderRight: false, children: [_jsxs(Text, { color: "yellow", bold: true, children: ["Tool: ", toolName] }), _jsx(Text, { color: "yellow", children: getActionDescription(toolName, toolInput) }), _jsx(DiffDisplay, { toolName: toolName, parameters: JSON.stringify(toolInput), startLineNumber: startLineNumber }), toolName !== WRITE_TOOL_NAME &&
31
+ const content = (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", borderBottom: false, borderLeft: false, borderRight: false, children: [_jsxs(Text, { color: "yellow", bold: true, children: ["Tool: ", toolName] }), _jsx(Text, { color: "yellow", children: getActionDescription(toolName, toolInput) }), _jsx(DiffDisplay, { toolName: toolName, parameters: JSON.stringify(toolInput), startLineNumber: startLineNumber }), toolName !== WRITE_TOOL_NAME &&
40
32
  toolName !== EDIT_TOOL_NAME &&
41
33
  toolName !== EXIT_PLAN_MODE_TOOL_NAME &&
42
34
  toolName !== ASK_USER_QUESTION_TOOL_NAME &&
@@ -9,7 +9,6 @@ export interface ConfirmationSelectorProps {
9
9
  onDecision: (decision: PermissionDecision) => void;
10
10
  onCancel: () => void;
11
11
  onAbort: () => void;
12
- onHeightMeasured?: (height: number) => void;
13
12
  }
14
13
  export declare const ConfirmationSelector: React.FC<ConfirmationSelectorProps>;
15
14
  //# sourceMappingURL=ConfirmationSelector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmationSelector.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuD,MAAM,OAAO,CAAC;AAE5E,OAAO,KAAK,EAAE,kBAAkB,EAAwB,MAAM,gBAAgB,CAAC;AAgB/E,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACnD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AASD,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA2nBpE,CAAC"}
1
+ {"version":3,"file":"ConfirmationSelector.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAE3D,OAAO,KAAK,EAAE,kBAAkB,EAAwB,MAAM,gBAAgB,CAAC;AAgB/E,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACnD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AASD,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAgnBpE,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useLayoutEffect, useRef, useState } from "react";
3
- import { Box, Text, useInput, useStdout, measureElement } from "ink";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { Box, Text, useInput } from "ink";
4
4
  import { BASH_TOOL_NAME, EXIT_PLAN_MODE_TOOL_NAME, ASK_USER_QUESTION_TOOL_NAME, } from "wave-agent-sdk";
5
5
  const getHeaderColor = (header) => {
6
6
  const colors = ["red", "green", "blue", "magenta", "cyan"];
@@ -10,15 +10,7 @@ const getHeaderColor = (header) => {
10
10
  }
11
11
  return colors[Math.abs(hash) % colors.length];
12
12
  };
13
- export const ConfirmationSelector = ({ toolName, toolInput, suggestedPrefix, hidePersistentOption, isExpanded = false, onDecision, onCancel, onAbort, onHeightMeasured, }) => {
14
- const { stdout } = useStdout();
15
- const boxRef = useRef(null);
16
- useLayoutEffect(() => {
17
- if (boxRef.current) {
18
- const { height } = measureElement(boxRef.current);
19
- onHeightMeasured?.(height);
20
- }
21
- }, [stdout?.rows, onHeightMeasured, toolName, toolInput, isExpanded]);
13
+ export const ConfirmationSelector = ({ toolName, toolInput, suggestedPrefix, hidePersistentOption, isExpanded = false, onDecision, onCancel, onAbort, }) => {
22
14
  const [state, setState] = useState({
23
15
  selectedOption: toolName === EXIT_PLAN_MODE_TOOL_NAME ? "clear" : "allow",
24
16
  alternativeText: "",
@@ -414,7 +406,7 @@ export const ConfirmationSelector = ({ toolName, toolInput, suggestedPrefix, hid
414
406
  });
415
407
  const placeholderText = "Type here to tell Wave what to change";
416
408
  const showPlaceholder = state.selectedOption === "alternative" && !state.hasUserInput;
417
- return (_jsxs(Box, { ref: boxRef, flexDirection: "column", children: [toolName === ASK_USER_QUESTION_TOOL_NAME &&
409
+ return (_jsxs(Box, { flexDirection: "column", children: [toolName === ASK_USER_QUESTION_TOOL_NAME &&
418
410
  currentQuestion &&
419
411
  !isExpanded && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: getHeaderColor(currentQuestion.header), bold: true, children: currentQuestion.header.slice(0, 12).toUpperCase() }), _jsx(Box, { marginLeft: 1, children: _jsx(Text, { bold: true, children: currentQuestion.question }) })] }), _jsx(Box, { flexDirection: "column", children: [...currentQuestion.options, { label: "Other" }].map((option, index) => {
420
412
  const isSelected = questionState.selectedOptionIndex === index;
@@ -1 +1 @@
1
- {"version":3,"file":"DiffDisplay.d.ts","sourceRoot":"","sources":["../../src/components/DiffDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAYvC,UAAU,gBAAgB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA6WlD,CAAC"}
1
+ {"version":3,"file":"DiffDisplay.d.ts","sourceRoot":"","sources":["../../src/components/DiffDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAMvC,UAAU,gBAAgB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA0VlD,CAAC"}
@@ -1,11 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMemo } from "react";
3
3
  import { Box, Text } from "ink";
4
- import { WRITE_TOOL_NAME, EDIT_TOOL_NAME, } from "wave-agent-sdk";
4
+ import { WRITE_TOOL_NAME, EDIT_TOOL_NAME } from "wave-agent-sdk";
5
5
  import { transformToolBlockToChanges } from "../utils/toolParameterTransforms.js";
6
6
  import { diffLines, diffWords } from "diff";
7
- import path from "path";
8
- import { Markdown } from "./Markdown.js";
9
7
  export const DiffDisplay = ({ toolName, parameters, startLineNumber, }) => {
10
8
  const showDiff = toolName && [WRITE_TOOL_NAME, EDIT_TOOL_NAME].includes(toolName);
11
9
  // Diff detection and transformation using typed parameters
@@ -55,23 +53,6 @@ export const DiffDisplay = ({ toolName, parameters, startLineNumber, }) => {
55
53
  };
56
54
  }
57
55
  };
58
- // Render highlighted code for Write tool
59
- const renderWriteContent = () => {
60
- if (!parameters)
61
- return null;
62
- try {
63
- const parsed = JSON.parse(parameters);
64
- const content = parsed.content || "";
65
- const filePath = parsed.file_path || "";
66
- const ext = path.extname(filePath).slice(1);
67
- const markdown = `\`\`\`${ext}\n${content}\n\`\`\``;
68
- return _jsx(Markdown, { children: markdown });
69
- }
70
- catch (error) {
71
- console.warn("Error rendering write content:", error);
72
- return null;
73
- }
74
- };
75
56
  // Render expanded diff display
76
57
  const renderExpandedDiff = () => {
77
58
  try {
@@ -216,7 +197,5 @@ export const DiffDisplay = ({ toolName, parameters, startLineNumber, }) => {
216
197
  if (!showDiff) {
217
198
  return null;
218
199
  }
219
- return (_jsx(Box, { flexDirection: "column", children: _jsx(Box, { paddingLeft: 2, borderLeft: true, borderColor: "cyan", flexDirection: "column", children: toolName === WRITE_TOOL_NAME
220
- ? renderWriteContent()
221
- : renderExpandedDiff() }) }));
200
+ return (_jsx(Box, { flexDirection: "column", children: _jsx(Box, { paddingLeft: 2, borderLeft: true, borderColor: "cyan", flexDirection: "column", children: renderExpandedDiff() }) }));
222
201
  };
@@ -6,7 +6,6 @@ export interface MessageListProps {
6
6
  forceStatic?: boolean;
7
7
  version?: string;
8
8
  workdir?: string;
9
- onDynamicBlocksHeightMeasured?: (height: number) => void;
10
9
  }
11
- export declare const MessageList: React.MemoExoticComponent<({ messages, isExpanded, forceStatic, version, workdir, onDynamicBlocksHeightMeasured, }: 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>;
12
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,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,6BAA6B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1D;AAED,eAAO,MAAM,WAAW,sHAQnB,gBAAgB,6CAkHpB,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"}
@@ -1,14 +1,21 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import React, { useLayoutEffect, useRef } from "react";
2
+ import React from "react";
3
3
  import os from "os";
4
- import { Box, Text, Static, measureElement } from "ink";
4
+ import { Box, Text, Static } from "ink";
5
5
  import { MessageBlockItem } from "./MessageBlockItem.js";
6
- export const MessageList = React.memo(({ messages, isExpanded = false, forceStatic = false, version, workdir, onDynamicBlocksHeightMeasured, }) => {
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;
10
10
  // Filter out meta messages
11
11
  const visibleMessages = messages.filter((m) => !m.isMeta);
12
+ const isRunning = (b) => (b.type === "tool" && b.stage === "running") ||
13
+ (b.type === "bang" && b.isRunning) ||
14
+ (b.type === "slash" && b.stage === "running");
15
+ const messagesWithRunningBlocks = new Set(visibleMessages
16
+ .map((m, i) => ({ m, i }))
17
+ .filter(({ m }) => m.blocks.some(isRunning))
18
+ .map(({ i }) => i));
12
19
  // Flatten messages into blocks with metadata
13
20
  const allBlocks = visibleMessages.flatMap((message, messageIndex) => {
14
21
  return message.blocks.map((block, blockIndex) => ({
@@ -23,23 +30,11 @@ export const MessageList = React.memo(({ messages, isExpanded = false, forceStat
23
30
  const blocksWithStatus = allBlocks.map((item) => {
24
31
  const { block } = item;
25
32
  const isDynamic = !forceStatic &&
26
- ((block.type === "tool" && block.stage === "running") ||
27
- (block.type === "bang" && block.isRunning) ||
28
- (block.type === "slash" && block.stage === "running"));
33
+ (messagesWithRunningBlocks.has(item.messageIndex) || isRunning(block));
29
34
  return { ...item, isDynamic };
30
35
  });
31
36
  const staticBlocks = blocksWithStatus.filter((b) => !b.isDynamic);
32
37
  const dynamicBlocks = blocksWithStatus.filter((b) => b.isDynamic);
33
- const dynamicBlocksRef = useRef(null);
34
- useLayoutEffect(() => {
35
- if (dynamicBlocksRef.current) {
36
- const { height } = measureElement(dynamicBlocksRef.current);
37
- onDynamicBlocksHeightMeasured?.(height);
38
- }
39
- else {
40
- onDynamicBlocksHeightMeasured?.(0);
41
- }
42
- }, [dynamicBlocks, isExpanded, onDynamicBlocksHeightMeasured]);
43
38
  const staticItems = [
44
39
  {
45
40
  isWelcome: true,
@@ -59,7 +54,7 @@ export const MessageList = React.memo(({ messages, isExpanded = false, forceStat
59
54
  return null;
60
55
  }
61
56
  return (_jsx(MessageBlockItem, { block: item.block, message: item.message, isExpanded: isExpanded, paddingTop: 1 }, item.key));
62
- } })), 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))) }))] }));
57
+ } })), 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))) }))] }));
63
58
  });
64
59
  // Add display name for debugging
65
60
  MessageList.displayName = "MessageList";
@@ -1 +1 @@
1
- {"version":3,"file":"RewindCommand.d.ts","sourceRoot":"","sources":["../../src/components/RewindCommand.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,OAAO,EAAa,MAAM,gBAAgB,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,OAAO,CAAC;QACnC,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC,CAAC;CACJ;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAwJtD,CAAC"}
1
+ {"version":3,"file":"RewindCommand.d.ts","sourceRoot":"","sources":["../../src/components/RewindCommand.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAG9C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,OAAO,CAAC;QACnC,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC,CAAC;CACJ;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAqJtD,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useState } from "react";
3
3
  import { Box, Text, useInput } from "ink";
4
+ import { getMessageContent } from "wave-agent-sdk";
4
5
  export const RewindCommand = ({ messages: initialMessages, onSelect, onCancel, getFullMessageThread, }) => {
5
6
  const [messages, setMessages] = useState(initialMessages);
6
7
  const [isLoading, setIsLoading] = useState(!!getFullMessageThread);
@@ -54,10 +55,7 @@ export const RewindCommand = ({ messages: initialMessages, onSelect, onCancel, g
54
55
  return (_jsxs(Box, { flexDirection: "column", paddingX: 1, gap: 1, borderStyle: "single", borderColor: "cyan", borderLeft: false, borderRight: false, children: [_jsx(Box, { children: _jsx(Text, { color: "cyan", bold: true, children: "Rewind: Select a message to revert to" }) }), _jsx(Box, { flexDirection: "column", children: visibleCheckpoints.map((checkpoint, index) => {
55
56
  const actualIndex = startIndex + index;
56
57
  const isSelected = actualIndex === selectedIndex;
57
- const content = checkpoint.msg.blocks
58
- .filter((b) => b.type === "text")
59
- .map((b) => b.content)
60
- .join(" ")
58
+ const content = getMessageContent(checkpoint.msg)
61
59
  .replace(/\n/g, "\\n")
62
60
  .substring(0, 60);
63
61
  return (_jsx(Box, { children: _jsxs(Text, { color: isSelected ? "black" : "white", backgroundColor: isSelected ? "cyan" : undefined, children: [isSelected ? "▶ " : " ", "[", checkpoint.index, "]", " ", content || "(No text content)", actualIndex === checkpoints.length - 1 ? " (Latest)" : ""] }) }, checkpoint.index));
@@ -1 +1 @@
1
- {"version":3,"file":"StatusCommand.d.ts","sourceRoot":"","sources":["../../src/components/StatusCommand.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA+EtD,CAAC"}
1
+ {"version":3,"file":"StatusCommand.d.ts","sourceRoot":"","sources":["../../src/components/StatusCommand.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAsFtD,CAAC"}
@@ -24,5 +24,5 @@ export const StatusCommand = ({ onCancel }) => {
24
24
  catch {
25
25
  // Fallback if package.json cannot be read
26
26
  }
27
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", borderLeft: false, borderRight: false, paddingX: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "cyan", bold: true, underline: true, children: "Agent Status" }) }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Version:" }) }), _jsx(Text, { color: "white", children: version })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Session ID:" }) }), _jsx(Text, { color: "white", children: sessionId })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "cwd:" }) }), _jsx(Text, { color: "white", wrap: "wrap", children: workingDirectory })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Wave base URL:" }) }), _jsx(Text, { color: "white", children: gatewayConfig.baseURL })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Model:" }) }), _jsx(Text, { color: "white", children: modelConfig.model })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Esc to cancel" }) })] }));
27
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", borderLeft: false, borderRight: false, paddingX: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "cyan", bold: true, underline: true, children: "Agent Status" }) }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Version:" }) }), _jsx(Text, { color: "white", children: version })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Session ID:" }) }), _jsx(Text, { color: "white", children: sessionId })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "cwd:" }) }), _jsx(Text, { color: "white", wrap: "wrap", children: workingDirectory })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Wave base URL:" }) }), _jsx(Text, { color: "white", children: gatewayConfig.baseURL })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Model:" }) }), _jsx(Text, { color: "white", children: modelConfig.model })] }), _jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: "Fast model:" }) }), _jsx(Text, { color: "white", children: modelConfig.fastModel })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Esc to cancel" }) })] }));
28
28
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ToolDisplay.d.ts","sourceRoot":"","sources":["../../src/components/ToolDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,UAAU,gBAAgB;IACxB,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAmIlD,CAAC"}
1
+ {"version":3,"file":"ToolDisplay.d.ts","sourceRoot":"","sources":["../../src/components/ToolDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAIhD,UAAU,gBAAgB;IACxB,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA+HlD,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text } from "ink";
3
+ import { getLastLines } from "wave-agent-sdk";
3
4
  import { DiffDisplay } from "./DiffDisplay.js";
4
5
  export const ToolDisplay = ({ block, isExpanded = false, }) => {
5
6
  const { parameters, result, compactParams, stage, success, error, name } = block;
@@ -31,14 +32,10 @@ export const ToolDisplay = ({ block, isExpanded = false, }) => {
31
32
  }
32
33
  // If no shortResult but has result, return last 5 lines
33
34
  if (block.result) {
34
- const lines = block.result.split("\n");
35
- if (lines.length > 5) {
36
- return lines.slice(-5).join("\n");
37
- }
38
- return block.result;
35
+ return getLastLines(block.result, 5);
39
36
  }
40
37
  return null;
41
38
  };
42
39
  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)] }) })), !isExpanded && stage === "end" && success && (_jsx(DiffDisplay, { toolName: name, parameters: parameters, startLineNumber: block.startLineNumber }))] }));
40
+ 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", wrap: "truncate-end", 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
41
  };
@@ -43,8 +43,6 @@ export interface ChatContextType {
43
43
  stopBackgroundTask: (taskId: string) => boolean;
44
44
  slashCommands: SlashCommand[];
45
45
  hasSlashCommand: (commandId: string) => boolean;
46
- subagentMessages: Record<string, Message[]>;
47
- subagentLatestTokens: Record<string, number>;
48
46
  permissionMode: PermissionMode;
49
47
  setPermissionMode: (mode: PermissionMode) => void;
50
48
  allowBypassInCycle: boolean;