wave-code 0.5.0 → 0.6.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 (112) hide show
  1. package/dist/components/App.d.ts.map +1 -1
  2. package/dist/components/App.js +40 -2
  3. package/dist/components/BackgroundTaskManager.d.ts +6 -0
  4. package/dist/components/BackgroundTaskManager.d.ts.map +1 -0
  5. package/dist/components/{TaskManager.js → BackgroundTaskManager.js} +1 -1
  6. package/dist/components/ChatInterface.d.ts.map +1 -1
  7. package/dist/components/ChatInterface.js +40 -5
  8. package/dist/components/CommandOutputDisplay.d.ts.map +1 -1
  9. package/dist/components/CommandOutputDisplay.js +6 -17
  10. package/dist/components/CommandSelector.d.ts.map +1 -1
  11. package/dist/components/CommandSelector.js +16 -2
  12. package/dist/components/CompressDisplay.d.ts.map +1 -1
  13. package/dist/components/CompressDisplay.js +6 -10
  14. package/dist/components/ConfirmationDetails.d.ts +9 -0
  15. package/dist/components/ConfirmationDetails.d.ts.map +1 -0
  16. package/dist/components/ConfirmationDetails.js +53 -0
  17. package/dist/components/{Confirmation.d.ts → ConfirmationSelector.d.ts} +3 -3
  18. package/dist/components/ConfirmationSelector.d.ts.map +1 -0
  19. package/dist/components/{Confirmation.js → ConfirmationSelector.js} +34 -96
  20. package/dist/components/DiffDisplay.d.ts.map +1 -1
  21. package/dist/components/DiffDisplay.js +48 -1
  22. package/dist/components/FileSelector.d.ts.map +1 -1
  23. package/dist/components/FileSelector.js +2 -2
  24. package/dist/components/HelpView.d.ts +6 -0
  25. package/dist/components/HelpView.d.ts.map +1 -0
  26. package/dist/components/HelpView.js +24 -0
  27. package/dist/components/HistorySearch.d.ts.map +1 -1
  28. package/dist/components/HistorySearch.js +12 -4
  29. package/dist/components/InputBox.d.ts +1 -3
  30. package/dist/components/InputBox.d.ts.map +1 -1
  31. package/dist/components/InputBox.js +14 -17
  32. package/dist/components/LoadingIndicator.d.ts +11 -0
  33. package/dist/components/LoadingIndicator.d.ts.map +1 -0
  34. package/dist/components/LoadingIndicator.js +6 -0
  35. package/dist/components/Markdown.d.ts.map +1 -1
  36. package/dist/components/Markdown.js +114 -121
  37. package/dist/components/MessageItem.d.ts +1 -1
  38. package/dist/components/MessageItem.d.ts.map +1 -1
  39. package/dist/components/MessageItem.js +3 -5
  40. package/dist/components/MessageList.d.ts +2 -3
  41. package/dist/components/MessageList.d.ts.map +1 -1
  42. package/dist/components/MessageList.js +29 -12
  43. package/dist/components/PlanDisplay.d.ts.map +1 -1
  44. package/dist/components/PlanDisplay.js +4 -12
  45. package/dist/components/RewindCommand.d.ts +4 -0
  46. package/dist/components/RewindCommand.d.ts.map +1 -1
  47. package/dist/components/RewindCommand.js +20 -3
  48. package/dist/components/TaskList.d.ts +3 -0
  49. package/dist/components/TaskList.d.ts.map +1 -0
  50. package/dist/components/TaskList.js +40 -0
  51. package/dist/components/ToolDisplay.d.ts +9 -0
  52. package/dist/components/ToolDisplay.d.ts.map +1 -0
  53. package/dist/components/ToolDisplay.js +44 -0
  54. package/dist/contexts/useChat.d.ts +11 -3
  55. package/dist/contexts/useChat.d.ts.map +1 -1
  56. package/dist/contexts/useChat.js +51 -32
  57. package/dist/hooks/useInputManager.d.ts +4 -15
  58. package/dist/hooks/useInputManager.d.ts.map +1 -1
  59. package/dist/hooks/useInputManager.js +20 -65
  60. package/dist/hooks/useTasks.d.ts +2 -0
  61. package/dist/hooks/useTasks.d.ts.map +1 -0
  62. package/dist/hooks/useTasks.js +5 -0
  63. package/dist/managers/InputManager.d.ts +8 -30
  64. package/dist/managers/InputManager.d.ts.map +1 -1
  65. package/dist/managers/InputManager.js +38 -144
  66. package/dist/print-cli.d.ts.map +1 -1
  67. package/dist/print-cli.js +11 -30
  68. package/package.json +5 -6
  69. package/src/components/App.tsx +51 -3
  70. package/src/components/{TaskManager.tsx → BackgroundTaskManager.tsx} +4 -2
  71. package/src/components/ChatInterface.tsx +80 -23
  72. package/src/components/CommandOutputDisplay.tsx +16 -38
  73. package/src/components/CommandSelector.tsx +41 -17
  74. package/src/components/CompressDisplay.tsx +5 -22
  75. package/src/components/ConfirmationDetails.tsx +108 -0
  76. package/src/components/{Confirmation.tsx → ConfirmationSelector.tsx} +74 -193
  77. package/src/components/DiffDisplay.tsx +71 -1
  78. package/src/components/FileSelector.tsx +0 -2
  79. package/src/components/HelpView.tsx +59 -0
  80. package/src/components/HistorySearch.tsx +45 -21
  81. package/src/components/InputBox.tsx +51 -63
  82. package/src/components/LoadingIndicator.tsx +56 -0
  83. package/src/components/Markdown.tsx +126 -323
  84. package/src/components/MessageItem.tsx +13 -24
  85. package/src/components/MessageList.tsx +48 -82
  86. package/src/components/PlanDisplay.tsx +4 -27
  87. package/src/components/RewindCommand.tsx +39 -2
  88. package/src/components/TaskList.tsx +58 -0
  89. package/src/components/{ToolResultDisplay.tsx → ToolDisplay.tsx} +8 -18
  90. package/src/contexts/useChat.tsx +73 -41
  91. package/src/hooks/useInputManager.ts +21 -83
  92. package/src/hooks/useTasks.ts +6 -0
  93. package/src/managers/InputManager.ts +43 -179
  94. package/src/print-cli.ts +17 -35
  95. package/dist/components/Confirmation.d.ts.map +0 -1
  96. package/dist/components/MemoryDisplay.d.ts +0 -8
  97. package/dist/components/MemoryDisplay.d.ts.map +0 -1
  98. package/dist/components/MemoryDisplay.js +0 -25
  99. package/dist/components/MemoryTypeSelector.d.ts +0 -8
  100. package/dist/components/MemoryTypeSelector.d.ts.map +0 -1
  101. package/dist/components/MemoryTypeSelector.js +0 -38
  102. package/dist/components/SubagentBlock.d.ts +0 -8
  103. package/dist/components/SubagentBlock.d.ts.map +0 -1
  104. package/dist/components/SubagentBlock.js +0 -70
  105. package/dist/components/TaskManager.d.ts +0 -6
  106. package/dist/components/TaskManager.d.ts.map +0 -1
  107. package/dist/components/ToolResultDisplay.d.ts +0 -9
  108. package/dist/components/ToolResultDisplay.d.ts.map +0 -1
  109. package/dist/components/ToolResultDisplay.js +0 -54
  110. package/src/components/MemoryDisplay.tsx +0 -62
  111. package/src/components/MemoryTypeSelector.tsx +0 -98
  112. package/src/components/SubagentBlock.tsx +0 -143
@@ -13,7 +13,7 @@ export const CommandOutputDisplay: React.FC<CommandOutputDisplayProps> = ({
13
13
  }) => {
14
14
  const { command, output, isRunning, exitCode } = block;
15
15
  const [isOverflowing, setIsOverflowing] = useState(false);
16
- const MAX_LINES = 10; // Set maximum display lines
16
+ const MAX_LINES = 3; // Set maximum display lines
17
17
 
18
18
  // Detect if content is overflowing
19
19
  useEffect(() => {
@@ -30,50 +30,28 @@ export const CommandOutputDisplay: React.FC<CommandOutputDisplayProps> = ({
30
30
  return "gray"; // Unknown state
31
31
  };
32
32
 
33
- const getStatusText = () => {
34
- if (isRunning) return "🔄";
35
- if (exitCode === 0) return "✅";
36
- if (exitCode === 130) return "⚠️"; // SIGINT (Ctrl+C)
37
- if (exitCode !== null && exitCode !== 0) return "❌";
38
- return ""; // Don't display text for unknown state
39
- };
40
-
41
33
  return (
42
34
  <Box flexDirection="column">
43
35
  <Box>
44
- <Text color="cyan">$ </Text>
36
+ <Text color={getStatusColor()}>$ </Text>
45
37
  <Text color="white">{command}</Text>
46
- <Text color={getStatusColor()}> {getStatusText()}</Text>
47
38
  </Box>
48
39
 
49
40
  {output && (
50
- <Box marginTop={1} flexDirection="column">
51
- <Box
52
- paddingLeft={2}
53
- borderLeft
54
- borderColor="gray"
55
- flexDirection="column"
56
- height={
57
- isExpanded
58
- ? undefined
59
- : Math.min(output.split("\n").length, MAX_LINES)
60
- }
61
- overflow="hidden"
62
- >
63
- <Text color="gray">
64
- {isOverflowing
65
- ? output.split("\n").slice(-MAX_LINES).join("\n")
66
- : output}
67
- </Text>
68
- </Box>
69
- {isOverflowing && (
70
- <Box paddingLeft={2} marginTop={1}>
71
- <Text color="yellow" dimColor>
72
- Content truncated ({output.split("\n").length} lines total,
73
- showing last {MAX_LINES} lines)
74
- </Text>
75
- </Box>
76
- )}
41
+ <Box
42
+ paddingLeft={2}
43
+ height={
44
+ isExpanded
45
+ ? undefined
46
+ : Math.min(output.split("\n").length, MAX_LINES)
47
+ }
48
+ overflow="hidden"
49
+ >
50
+ <Text color="gray">
51
+ {isOverflowing
52
+ ? output.split("\n").slice(-MAX_LINES).join("\n")
53
+ : output}
54
+ </Text>
77
55
  </Box>
78
56
  )}
79
57
  </Box>
@@ -22,6 +22,12 @@ const AVAILABLE_COMMANDS: SlashCommand[] = [
22
22
  "Revert conversation and file changes to a previous checkpoint",
23
23
  handler: () => {}, // Handler here won't be used, actual processing is in the hook
24
24
  },
25
+ {
26
+ id: "help",
27
+ name: "help",
28
+ description: "Show help and key bindings",
29
+ handler: () => {}, // Handler here won't be used, actual processing is in the hook
30
+ },
25
31
  ];
26
32
 
27
33
  export interface CommandSelectorProps {
@@ -39,6 +45,7 @@ export const CommandSelector: React.FC<CommandSelectorProps> = ({
39
45
  onCancel,
40
46
  commands = [], // Default to empty array
41
47
  }) => {
48
+ const MAX_VISIBLE_ITEMS = 3;
42
49
  const [selectedIndex, setSelectedIndex] = useState(0);
43
50
 
44
51
  // Merge agent commands and local commands
@@ -51,6 +58,19 @@ export const CommandSelector: React.FC<CommandSelectorProps> = ({
51
58
  command.id.toLowerCase().includes(searchQuery.toLowerCase()),
52
59
  );
53
60
 
61
+ // Calculate visible window
62
+ const startIndex = Math.max(
63
+ 0,
64
+ Math.min(
65
+ selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2),
66
+ Math.max(0, filteredCommands.length - MAX_VISIBLE_ITEMS),
67
+ ),
68
+ );
69
+ const visibleCommands = filteredCommands.slice(
70
+ startIndex,
71
+ startIndex + MAX_VISIBLE_ITEMS,
72
+ );
73
+
54
74
  useInput((input, key) => {
55
75
  if (key.return) {
56
76
  if (
@@ -101,7 +121,6 @@ export const CommandSelector: React.FC<CommandSelectorProps> = ({
101
121
  borderBottom={false}
102
122
  borderLeft={false}
103
123
  borderRight={false}
104
- paddingTop={1}
105
124
  >
106
125
  <Text color="yellow">No commands found for "{searchQuery}"</Text>
107
126
  <Text dimColor>Press Escape to cancel</Text>
@@ -117,7 +136,6 @@ export const CommandSelector: React.FC<CommandSelectorProps> = ({
117
136
  borderBottom={false}
118
137
  borderLeft={false}
119
138
  borderRight={false}
120
- paddingTop={1}
121
139
  gap={1}
122
140
  >
123
141
  <Box>
@@ -126,23 +144,29 @@ export const CommandSelector: React.FC<CommandSelectorProps> = ({
126
144
  </Text>
127
145
  </Box>
128
146
 
129
- {filteredCommands.map((command, index) => (
130
- <Box key={command.id} flexDirection="column">
131
- <Text
132
- color={index === selectedIndex ? "black" : "white"}
133
- backgroundColor={index === selectedIndex ? "magenta" : undefined}
134
- >
135
- {index === selectedIndex ? "▶ " : " "}/{command.id}
136
- </Text>
137
- {index === selectedIndex && (
138
- <Box marginLeft={4}>
139
- <Text color="gray" dimColor>
140
- {command.description}
147
+ <Box flexDirection="column">
148
+ {visibleCommands.map((command, index) => {
149
+ const actualIndex = startIndex + index;
150
+ const isSelected = actualIndex === selectedIndex;
151
+ return (
152
+ <Box key={command.id} flexDirection="column">
153
+ <Text
154
+ color={isSelected ? "black" : "white"}
155
+ backgroundColor={isSelected ? "magenta" : undefined}
156
+ >
157
+ {isSelected ? "" : " "}/{command.id}
141
158
  </Text>
159
+ {isSelected && (
160
+ <Box marginLeft={4}>
161
+ <Text color="gray" dimColor>
162
+ {command.description}
163
+ </Text>
164
+ </Box>
165
+ )}
142
166
  </Box>
143
- )}
144
- </Box>
145
- ))}
167
+ );
168
+ })}
169
+ </Box>
146
170
 
147
171
  <Box>
148
172
  <Text dimColor>
@@ -7,25 +7,16 @@ interface CompressDisplayProps {
7
7
  isExpanded?: boolean;
8
8
  }
9
9
 
10
- export const CompressDisplay: React.FC<CompressDisplayProps> = ({
11
- block,
12
- isExpanded = false,
13
- }) => {
10
+ export const CompressDisplay: React.FC<CompressDisplayProps> = ({ block }) => {
14
11
  const { content } = block;
15
- const MAX_LINES = 3; // Set maximum display lines for compressed content
16
12
 
17
- const { displayContent, isOverflowing } = useMemo(() => {
13
+ const { displayContent } = useMemo(() => {
18
14
  if (!content) {
19
- return { displayContent: "", isOverflowing: false };
15
+ return { displayContent: "" };
20
16
  }
21
17
 
22
- const lines = content.split("\n");
23
- const overflow = !isExpanded && lines.length > MAX_LINES;
24
-
25
- const display = overflow ? lines.slice(0, MAX_LINES).join("\n") : content;
26
-
27
- return { displayContent: display, isOverflowing: overflow };
28
- }, [content, isExpanded]);
18
+ return { displayContent: content };
19
+ }, [content]);
29
20
 
30
21
  return (
31
22
  <Box flexDirection="column">
@@ -43,14 +34,6 @@ export const CompressDisplay: React.FC<CompressDisplayProps> = ({
43
34
  >
44
35
  <Text color="white">{displayContent}</Text>
45
36
  </Box>
46
- {isOverflowing && (
47
- <Box paddingLeft={2} marginTop={1}>
48
- <Text color="yellow" dimColor>
49
- Content truncated ({content.split("\n").length} lines total,
50
- showing first {MAX_LINES} lines. Press Ctrl+O to expand.
51
- </Text>
52
- </Box>
53
- )}
54
37
  </Box>
55
38
  )}
56
39
  </Box>
@@ -0,0 +1,108 @@
1
+ import React, { useLayoutEffect, useRef, useState } from "react";
2
+ import { Box, Text, useStdout, measureElement, Static } from "ink";
3
+ import {
4
+ BASH_TOOL_NAME,
5
+ EDIT_TOOL_NAME,
6
+ MULTI_EDIT_TOOL_NAME,
7
+ DELETE_FILE_TOOL_NAME,
8
+ WRITE_TOOL_NAME,
9
+ EXIT_PLAN_MODE_TOOL_NAME,
10
+ ASK_USER_QUESTION_TOOL_NAME,
11
+ } from "wave-agent-sdk";
12
+ import { DiffDisplay } from "./DiffDisplay.js";
13
+ import { PlanDisplay } from "./PlanDisplay.js";
14
+
15
+ // Helper function to generate descriptive action text
16
+ const getActionDescription = (
17
+ toolName: string,
18
+ toolInput?: Record<string, unknown>,
19
+ ): string => {
20
+ if (!toolInput) {
21
+ return "Execute operation";
22
+ }
23
+
24
+ switch (toolName) {
25
+ case BASH_TOOL_NAME:
26
+ return `Execute command: ${toolInput.command || "unknown command"}`;
27
+ case EDIT_TOOL_NAME:
28
+ return `Edit file: ${toolInput.file_path || "unknown file"}`;
29
+ case MULTI_EDIT_TOOL_NAME:
30
+ return `Edit multiple sections in: ${toolInput.file_path || "unknown file"}`;
31
+ case DELETE_FILE_TOOL_NAME:
32
+ return `Delete file: ${toolInput.target_file || "unknown file"}`;
33
+ case WRITE_TOOL_NAME:
34
+ return `Write to file: ${toolInput.file_path || "unknown file"}`;
35
+ case EXIT_PLAN_MODE_TOOL_NAME:
36
+ return "Review and approve the plan";
37
+ case ASK_USER_QUESTION_TOOL_NAME:
38
+ return "Answer questions to clarify intent";
39
+ default:
40
+ return "Execute operation";
41
+ }
42
+ };
43
+
44
+ export interface ConfirmationDetailsProps {
45
+ toolName: string;
46
+ toolInput?: Record<string, unknown>;
47
+ isExpanded?: boolean;
48
+ onHeightMeasured?: (height: number) => void;
49
+ }
50
+
51
+ export const ConfirmationDetails: React.FC<ConfirmationDetailsProps> = ({
52
+ toolName,
53
+ toolInput,
54
+ isExpanded = false,
55
+ onHeightMeasured,
56
+ }) => {
57
+ const { stdout } = useStdout();
58
+ const [isStatic, setIsStatic] = useState(false);
59
+ const boxRef = useRef(null);
60
+
61
+ useLayoutEffect(() => {
62
+ if (boxRef.current) {
63
+ const { height } = measureElement(boxRef.current);
64
+ const terminalHeight = stdout?.rows || 24;
65
+ if (height > terminalHeight - 10) {
66
+ setIsStatic(true);
67
+ }
68
+ onHeightMeasured?.(height);
69
+ }
70
+ }, [stdout?.rows, onHeightMeasured]);
71
+
72
+ const content = (
73
+ <Box
74
+ ref={boxRef}
75
+ flexDirection="column"
76
+ borderStyle="single"
77
+ borderColor="yellow"
78
+ borderBottom={false}
79
+ borderLeft={false}
80
+ borderRight={false}
81
+ paddingTop={1}
82
+ >
83
+ <Text color="yellow" bold>
84
+ Tool: {toolName}
85
+ </Text>
86
+ <Text color="yellow">{getActionDescription(toolName, toolInput)}</Text>
87
+
88
+ <DiffDisplay toolName={toolName} parameters={JSON.stringify(toolInput)} />
89
+
90
+ {toolName !== ASK_USER_QUESTION_TOOL_NAME &&
91
+ toolName === EXIT_PLAN_MODE_TOOL_NAME &&
92
+ !!toolInput?.plan_content && (
93
+ <PlanDisplay
94
+ plan={toolInput.plan_content as string}
95
+ isExpanded={isExpanded}
96
+ />
97
+ )}
98
+ </Box>
99
+ );
100
+
101
+ if (isStatic) {
102
+ return <Static items={[1]}>{() => content}</Static>;
103
+ }
104
+
105
+ return content;
106
+ };
107
+
108
+ ConfirmationDetails.displayName = "ConfirmationDetails";