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
@@ -1,8 +1,8 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React, { useMemo } from "react";
3
- import { Box, Text, useStdout } from "ink";
4
- import { marked } from "marked";
5
- import { highlight } from "cli-highlight";
3
+ import { Box, Text } from "ink";
4
+ import { Renderer, marked } from "marked";
5
+ import chalk from "chalk";
6
6
  const unescapeHtml = (html) => {
7
7
  return html
8
8
  .replace(/&/g, "&")
@@ -12,124 +12,117 @@ const unescapeHtml = (html) => {
12
12
  .replace(/'/g, "'")
13
13
  .replace(/'/g, "'");
14
14
  };
15
- const InlineRenderer = ({ tokens }) => {
16
- return (_jsx(_Fragment, { children: tokens.map((token, index) => {
17
- switch (token.type) {
18
- case "text": {
19
- const t = token;
20
- if (t.tokens) {
21
- return _jsx(InlineRenderer, { tokens: t.tokens }, index);
22
- }
23
- return _jsx(Text, { children: unescapeHtml(t.text) }, index);
24
- }
25
- case "strong":
26
- return (_jsx(Text, { bold: true, children: token.tokens ? (_jsx(InlineRenderer, { tokens: token.tokens })) : (unescapeHtml(token.text)) }, index));
27
- case "em":
28
- return (_jsx(Text, { italic: true, children: token.tokens ? (_jsx(InlineRenderer, { tokens: token.tokens })) : (unescapeHtml(token.text)) }, index));
29
- case "codespan":
30
- return (_jsx(Text, { color: "yellow", children: unescapeHtml(token.text) }, index));
31
- case "link": {
32
- const t = token;
33
- return (_jsxs(Text, { children: [_jsx(Text, { color: "blue", underline: true, children: t.tokens ? (_jsx(InlineRenderer, { tokens: t.tokens })) : (unescapeHtml(t.text)) }), _jsxs(Text, { color: "gray", children: [" (", t.href, ")"] })] }, index));
34
- }
35
- case "br":
36
- return _jsx(Text, { children: "\n" }, index);
37
- case "del":
38
- return (_jsx(Text, { strikethrough: true, children: token.tokens ? (_jsx(InlineRenderer, { tokens: token.tokens })) : (unescapeHtml(token.text)) }, index));
39
- default:
40
- return _jsx(Text, { children: token.raw }, index);
41
- }
42
- }) }));
43
- };
44
- const TableRenderer = ({ token }) => {
45
- const { stdout } = useStdout();
46
- const terminalWidth = (stdout?.columns || 80) - 2;
47
- const columnWidths = useMemo(() => {
48
- const numCols = token.header.length;
49
- const minWidth = 5;
50
- const maxColWidth = 40;
51
- const widths = token.header.map((h) => Math.min(maxColWidth, Math.max(minWidth, h.text.length)));
52
- token.rows.forEach((row) => {
53
- row.forEach((cell, i) => {
54
- widths[i] = Math.min(maxColWidth, Math.max(widths[i] || minWidth, cell.text.length));
55
- });
56
- });
57
- const paddedWidths = widths.map((w) => w + 2);
58
- const totalWidth = paddedWidths.reduce((a, b) => a + b, 0) + numCols + 1;
59
- if (totalWidth <= terminalWidth) {
60
- return paddedWidths;
61
- }
62
- // If table is too wide, scale down columns proportionally
63
- const availableWidth = terminalWidth - numCols - 1;
64
- const scaleFactor = availableWidth / (totalWidth - numCols - 1);
65
- return paddedWidths.map((w) => Math.max(minWidth, Math.floor(w * scaleFactor)));
66
- }, [token, terminalWidth]);
67
- return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: "gray", width: columnWidths.reduce((a, b) => a + b, 0) + token.header.length + 1, children: [_jsx(Box, { flexDirection: "row", borderStyle: "single", borderBottom: true, borderTop: false, borderLeft: false, borderRight: false, borderColor: "gray", children: token.header.map((cell, i) => (_jsx(Box, { width: columnWidths[i], paddingX: 1, borderStyle: "single", borderLeft: i > 0, borderRight: false, borderTop: false, borderBottom: false, borderColor: "gray", children: _jsx(Text, { bold: true, wrap: "wrap", children: _jsx(InlineRenderer, { tokens: cell.tokens }) }) }, i))) }), token.rows.map((row, rowIndex) => (_jsx(Box, { flexDirection: "row", children: row.map((cell, i) => (_jsx(Box, { width: columnWidths[i], paddingX: 1, borderStyle: "single", borderLeft: i > 0, borderRight: false, borderTop: false, borderBottom: false, borderColor: "gray", children: _jsx(Text, { wrap: "wrap", children: _jsx(InlineRenderer, { tokens: cell.tokens }) }) }, i))) }, rowIndex)))] }));
68
- };
69
- const BlockRenderer = ({ tokens }) => {
70
- return (_jsx(_Fragment, { children: tokens.map((token, index) => {
71
- switch (token.type) {
72
- case "heading": {
73
- const t = token;
74
- return (_jsx(Box, { marginBottom: 1, flexDirection: "column", children: _jsxs(Text, { bold: true, color: "cyan", children: ["#".repeat(t.depth), " ", _jsx(InlineRenderer, { tokens: t.tokens })] }) }, index));
75
- }
76
- case "paragraph": {
77
- const t = token;
78
- return (_jsx(Box, { marginBottom: 1, flexDirection: "row", children: _jsx(Text, { children: _jsx(InlineRenderer, { tokens: t.tokens }) }) }, index));
79
- }
80
- case "code": {
81
- const t = token;
82
- if (t.lang !== undefined) {
83
- const raw = token.raw.endsWith("\n")
84
- ? token.raw.slice(0, -1)
85
- : token.raw;
86
- const lines = raw.split("\n");
87
- const opening = lines[0];
88
- const closing = lines[lines.length - 1];
89
- const content = lines.slice(1, -1).join("\n");
90
- const highlighted = content
91
- ? highlight(unescapeHtml(content), {
92
- language: t.lang,
93
- ignoreIllegals: true,
94
- })
95
- : "";
96
- return (_jsxs(Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [_jsx(Text, { color: "gray", children: opening }), highlighted && _jsx(Text, { children: highlighted }), _jsx(Text, { color: "gray", children: closing })] }, index));
97
- }
98
- return (_jsx(Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: _jsx(Text, { children: unescapeHtml(t.text) }) }, index));
99
- }
100
- case "list": {
101
- const t = token;
102
- return (_jsx(Box, { flexDirection: "column", marginBottom: 1, paddingLeft: 2, children: t.items.map((item, i) => {
103
- const start = t.start || 1;
104
- return (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "gray", children: t.ordered ? `${start + i}. ` : "• " }), _jsx(Box, { flexDirection: "column", flexGrow: 1, children: item.tokens.map((itemToken, itemIndex) => {
105
- if (itemToken.type === "text" ||
106
- itemToken.type === "paragraph") {
107
- const it = itemToken;
108
- return (_jsx(Box, { flexDirection: "row", children: _jsx(Text, { children: _jsx(InlineRenderer, { tokens: it.tokens || [itemToken] }) }) }, itemIndex));
109
- }
110
- return (_jsx(BlockRenderer, { tokens: [itemToken] }, itemIndex));
111
- }) })] }, i));
112
- }) }, index));
113
- }
114
- case "blockquote": {
115
- const t = token;
116
- return (_jsx(Box, { flexDirection: "column", paddingLeft: 2, borderStyle: "single", borderLeft: true, borderRight: false, borderTop: false, borderBottom: false, borderColor: "gray", marginBottom: 1, children: _jsx(BlockRenderer, { tokens: t.tokens }) }, index));
117
- }
118
- case "hr":
119
- return (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "gray", children: "─".repeat(20) }) }, index));
120
- case "table":
121
- return _jsx(TableRenderer, { token: token }, index);
122
- case "space":
123
- return null;
124
- default:
125
- return (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: token.raw }) }, index));
126
- }
127
- }) }));
128
- };
129
- // Markdown component using custom Ink-based renderer
15
+ class AnsiRenderer extends Renderer {
16
+ code({ text, lang }) {
17
+ const prefix = lang ? `\`\`\`${lang}` : "```";
18
+ const suffix = "```";
19
+ return `\n${chalk.gray(prefix)}\n${text}\n${chalk.gray(suffix)}\n`;
20
+ }
21
+ blockquote({ tokens }) {
22
+ const body = this.parser.parse(tokens);
23
+ return ("\n" +
24
+ body
25
+ .trim()
26
+ .split("\n")
27
+ .map((line) => chalk.gray("> ") + line)
28
+ .join("\n") +
29
+ "\n");
30
+ }
31
+ heading({ tokens, depth }) {
32
+ const text = this.parser.parseInline(tokens);
33
+ const hashes = "#".repeat(depth);
34
+ return `\n${chalk.cyan(`${hashes} ${text}`)}\n`;
35
+ }
36
+ hr() {
37
+ return `\n${chalk.gray("".repeat(20))}\n`;
38
+ }
39
+ list(token) {
40
+ const body = token.items
41
+ .map((item, i) => {
42
+ const text = this.listitem(item);
43
+ const prefix = token.ordered
44
+ ? chalk.gray(`${(token.start || 1) + i}. `)
45
+ : chalk.gray("• ");
46
+ const lines = text.split("\n");
47
+ const firstLine = prefix + lines[0];
48
+ const restLines = lines
49
+ .slice(1)
50
+ .filter((line) => line.length > 0)
51
+ .map((line) => " " + line);
52
+ return [firstLine, ...restLines].join("\n") + "\n";
53
+ })
54
+ .join("");
55
+ return `\n${body}`;
56
+ }
57
+ listitem(item) {
58
+ return `${this.parser.parse(item.tokens).trim()}\n`;
59
+ }
60
+ checkbox({ checked }) {
61
+ return checked ? chalk.green("[x] ") : chalk.gray("[ ] ");
62
+ }
63
+ paragraph({ tokens }) {
64
+ const text = this.parser.parseInline(tokens);
65
+ return `\n${text}\n`;
66
+ }
67
+ table(token) {
68
+ const header = token.header.map((cell) => this.tablecell(cell)).join("");
69
+ const body = token.rows
70
+ .map((row) => row.map((cell) => this.tablecell(cell)).join("") + "\n")
71
+ .join("");
72
+ return `\n${header}\n${body}\n`;
73
+ }
74
+ tablerow({ text }) {
75
+ return text + "\n";
76
+ }
77
+ tablecell(token) {
78
+ const text = token.header ? chalk.bold(token.text) : token.text;
79
+ return text + " | ";
80
+ }
81
+ strong({ tokens }) {
82
+ const text = this.parser.parseInline(tokens);
83
+ return chalk.bold(text);
84
+ }
85
+ em({ tokens }) {
86
+ const text = this.parser.parseInline(tokens);
87
+ return chalk.italic(text);
88
+ }
89
+ codespan({ text }) {
90
+ return chalk.yellow(text);
91
+ }
92
+ br() {
93
+ return "\n";
94
+ }
95
+ del({ tokens }) {
96
+ const text = this.parser.parseInline(tokens);
97
+ return chalk.strikethrough(text);
98
+ }
99
+ link({ href, tokens }) {
100
+ const text = this.parser.parseInline(tokens);
101
+ const linkText = chalk.blue.underline(text);
102
+ const hrefText = chalk.gray(`(${href})`);
103
+ return `${linkText} ${hrefText}`;
104
+ }
105
+ image({ href, tokens, text }) {
106
+ const alt = this.parser.parseInline(tokens) || text;
107
+ return chalk.gray(`![${alt}](${href})`);
108
+ }
109
+ text(token) {
110
+ return "tokens" in token && token.tokens
111
+ ? this.parser.parseInline(token.tokens)
112
+ : unescapeHtml(token.text);
113
+ }
114
+ }
115
+ const renderer = new AnsiRenderer();
116
+ // Markdown component using custom ANSI renderer
130
117
  export const Markdown = React.memo(({ children }) => {
131
- const tokens = useMemo(() => marked.lexer(children), [children]);
132
- return (_jsx(Box, { flexDirection: "column", children: _jsx(BlockRenderer, { tokens: tokens }) }));
118
+ const ansiContent = useMemo(() => {
119
+ return marked.parse(children, {
120
+ renderer,
121
+ gfm: true,
122
+ breaks: true,
123
+ });
124
+ }, [children]);
125
+ return (_jsx(Box, { flexDirection: "column", children: _jsx(Text, { children: ansiContent.trim() }) }));
133
126
  });
134
127
  // Add display name for debugging
135
128
  Markdown.displayName = "Markdown";
@@ -4,5 +4,5 @@ export interface MessageItemProps {
4
4
  isExpanded: boolean;
5
5
  shouldShowHeader: boolean;
6
6
  }
7
- export declare const MessageItem: ({ message, isExpanded, shouldShowHeader, }: MessageItemProps) => import("react/jsx-runtime").JSX.Element | null;
7
+ export declare const MessageItem: ({ message, isExpanded }: MessageItemProps) => import("react/jsx-runtime").JSX.Element | null;
8
8
  //# sourceMappingURL=MessageItem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../src/components/MessageItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAU9C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,eAAO,MAAM,WAAW,GAAI,4CAIzB,gBAAgB,mDAyElB,CAAC"}
1
+ {"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../src/components/MessageItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAQ9C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,eAAO,MAAM,WAAW,GAAI,yBAAyB,gBAAgB,mDAoEpE,CAAC"}
@@ -2,14 +2,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text } from "ink";
3
3
  import { MessageSource } from "wave-agent-sdk";
4
4
  import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
5
- import { ToolResultDisplay } from "./ToolResultDisplay.js";
6
- import { MemoryDisplay } from "./MemoryDisplay.js";
5
+ import { ToolDisplay } from "./ToolDisplay.js";
7
6
  import { CompressDisplay } from "./CompressDisplay.js";
8
- import { SubagentBlock } from "./SubagentBlock.js";
9
7
  import { ReasoningDisplay } from "./ReasoningDisplay.js";
10
8
  import { Markdown } from "./Markdown.js";
11
- export const MessageItem = ({ message, isExpanded, shouldShowHeader, }) => {
9
+ export const MessageItem = ({ message, isExpanded }) => {
12
10
  if (message.blocks.length === 0)
13
11
  return null;
14
- return (_jsxs(Box, { flexDirection: "column", gap: 1, marginTop: 1, children: [shouldShowHeader && (_jsx(Box, { children: _jsx(Text, { color: message.role === "user" ? "cyan" : "green", bold: true, children: message.role === "user" ? "👤 You" : "🤖 Assistant" }) })), _jsx(Box, { flexDirection: "column", gap: 1, children: message.blocks.map((block, blockIndex) => (_jsxs(Box, { children: [block.type === "text" && block.content.trim() && (_jsxs(Box, { children: [block.customCommandContent && (_jsxs(Text, { color: "cyan", bold: true, children: ["\u26A1", " "] })), block.source === MessageSource.HOOK && (_jsxs(Text, { color: "magenta", bold: true, children: ["\uD83D\uDD17", " "] })), _jsx(Markdown, { children: block.content })] })), block.type === "error" && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["\u274C Error: ", block.content] }) })), block.type === "command_output" && (_jsx(CommandOutputDisplay, { block: block, isExpanded: isExpanded })), block.type === "tool" && (_jsx(ToolResultDisplay, { block: block, isExpanded: isExpanded })), block.type === "image" && (_jsxs(Box, { children: [_jsx(Text, { color: "magenta", bold: true, children: "\uD83D\uDCF7 Image" }), block.imageUrls && block.imageUrls.length > 0 && (_jsxs(Text, { color: "gray", dimColor: true, children: [" ", "(", block.imageUrls.length, ")"] }))] })), block.type === "memory" && _jsx(MemoryDisplay, { block: block }), block.type === "compress" && (_jsx(CompressDisplay, { block: block, isExpanded: isExpanded })), block.type === "subagent" && _jsx(SubagentBlock, { block: block }), block.type === "reasoning" && _jsx(ReasoningDisplay, { block: block })] }, blockIndex))) })] }));
12
+ return (_jsx(Box, { flexDirection: "column", gap: 1, marginTop: 1, children: _jsx(Box, { flexDirection: "column", gap: 1, children: message.blocks.map((block, blockIndex) => (_jsxs(Box, { children: [block.type === "text" && block.content.trim() && (_jsxs(Box, { children: [block.customCommandContent && (_jsx(Text, { color: "cyan", bold: true, children: "\u26A1" })), block.source === MessageSource.HOOK && (_jsx(Text, { color: "magenta", bold: true, children: "\uD83D\uDD17" })), message.role === "user" ? (_jsx(Text, { backgroundColor: "gray", color: "white", children: block.content })) : (_jsx(Markdown, { children: block.content }))] })), block.type === "error" && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["\u274C Error: ", block.content] }) })), block.type === "command_output" && (_jsx(CommandOutputDisplay, { block: block, isExpanded: isExpanded })), block.type === "tool" && (_jsx(ToolDisplay, { block: block, isExpanded: isExpanded })), block.type === "image" && (_jsxs(Box, { children: [_jsx(Text, { color: "magenta", bold: true, children: "\uD83D\uDCF7 Image" }), block.imageUrls && block.imageUrls.length > 0 && (_jsxs(Text, { color: "gray", dimColor: true, children: [" ", "(", block.imageUrls.length, ")"] }))] })), block.type === "compress" && (_jsx(CompressDisplay, { block: block, isExpanded: isExpanded })), block.type === "reasoning" && _jsx(ReasoningDisplay, { block: block })] }, blockIndex))) }) }));
15
13
  };
@@ -4,9 +4,8 @@ export interface MessageListProps {
4
4
  messages: Message[];
5
5
  isLoading?: boolean;
6
6
  isCommandRunning?: boolean;
7
- isCompressing?: boolean;
8
- latestTotalTokens?: number;
9
7
  isExpanded?: boolean;
8
+ forceStaticLastMessage?: boolean;
10
9
  }
11
- export declare const MessageList: React.MemoExoticComponent<({ messages, isLoading, isCommandRunning, isCompressing, latestTotalTokens, isExpanded, }: MessageListProps) => import("react/jsx-runtime").JSX.Element>;
10
+ export declare const MessageList: React.MemoExoticComponent<({ messages, isLoading, isCommandRunning, isExpanded, forceStaticLastMessage, }: 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,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAG9C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,uHAQnB,gBAAgB,6CAwIpB,CAAC"}
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAS9C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,eAAO,MAAM,WAAW,6GAOnB,gBAAgB,6CAkGpB,CAAC"}
@@ -1,38 +1,55 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from "react";
3
3
  import { Box, Text, Static } from "ink";
4
+ import { TASK_CREATE_TOOL_NAME, TASK_GET_TOOL_NAME, TASK_UPDATE_TOOL_NAME, TASK_LIST_TOOL_NAME, } from "wave-agent-sdk";
4
5
  import { MessageItem } from "./MessageItem.js";
5
- export const MessageList = React.memo(({ messages, isLoading = false, isCommandRunning = false, isCompressing = false, latestTotalTokens = 0, isExpanded = false, }) => {
6
+ export const MessageList = React.memo(({ messages, isLoading = false, isCommandRunning = false, isExpanded = false, forceStaticLastMessage = false, }) => {
6
7
  // Empty message state
7
8
  if (messages.length === 0) {
8
- return (_jsx(Box, { flexDirection: "column", paddingY: 1, children: _jsx(Text, { color: "gray", children: "Welcome to WAVE Code Assistant!" }) }));
9
+ return (_jsx(Box, { flexDirection: "column", gap: 1, children: _jsx(Box, { flexDirection: "column", paddingY: 1, children: _jsx(Text, { color: "gray", children: "Welcome to WAVE Code Assistant!" }) }) }));
9
10
  }
10
11
  // Limit messages when expanded to prevent long rendering times
11
12
  const maxExpandedMessages = 20;
12
13
  const shouldLimitMessages = isExpanded && messages.length > maxExpandedMessages;
14
+ // Filter out task management tools and empty messages
15
+ const taskMgmtTools = [
16
+ TASK_CREATE_TOOL_NAME,
17
+ TASK_GET_TOOL_NAME,
18
+ TASK_UPDATE_TOOL_NAME,
19
+ TASK_LIST_TOOL_NAME,
20
+ ];
21
+ const filteredMessages = messages
22
+ .map((message) => ({
23
+ ...message,
24
+ blocks: message.blocks.filter((block) => !(block.type === "tool" &&
25
+ typeof block.name === "string" &&
26
+ taskMgmtTools.includes(block.name))),
27
+ }))
28
+ .filter((message) => message.blocks.length > 0);
13
29
  const displayMessages = shouldLimitMessages
14
- ? messages.slice(-maxExpandedMessages)
15
- : messages;
16
- const omittedCount = shouldLimitMessages
17
- ? messages.length - maxExpandedMessages
18
- : 0;
30
+ ? filteredMessages.slice(-maxExpandedMessages)
31
+ : filteredMessages;
19
32
  // Compute which messages to render statically vs dynamically
20
- const shouldRenderLastDynamic = isLoading || isCommandRunning;
33
+ const lastMessage = displayMessages[displayMessages.length - 1];
34
+ const hasNonEndTool = lastMessage?.blocks.some((block) => block.type === "tool" && block.stage !== "end");
35
+ const hasRunningCommand = lastMessage?.blocks.some((block) => block.type === "command_output" && block.isRunning);
36
+ const shouldRenderLastDynamic = !forceStaticLastMessage &&
37
+ (isLoading || isCommandRunning || hasNonEndTool || hasRunningCommand);
21
38
  const staticMessages = shouldRenderLastDynamic
22
39
  ? displayMessages.slice(0, -1)
23
40
  : displayMessages;
24
41
  const dynamicMessages = shouldRenderLastDynamic && displayMessages.length > 0
25
42
  ? [displayMessages[displayMessages.length - 1]]
26
43
  : [];
27
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [omittedCount > 0 && (_jsx(Box, { children: _jsxs(Text, { color: "gray", dimColor: true, children: ["... ", omittedCount, " earlier message", omittedCount !== 1 ? "s" : "", " ", "omitted (showing latest ", maxExpandedMessages, ")"] }) })), _jsx(Static, { items: staticMessages, children: (message, key) => {
44
+ return (_jsxs(Box, { flexDirection: "column", paddingBottom: 1, children: [_jsx(Static, { items: staticMessages, children: (message, key) => {
28
45
  // Get previous message
29
46
  const previousMessage = key > 0 ? staticMessages[key - 1] : undefined;
30
47
  return (_jsx(MessageItem, { message: message, shouldShowHeader: previousMessage?.role !== message.role, isExpanded: isExpanded }, key));
31
48
  } }), dynamicMessages.map((message, index) => {
32
49
  const messageIndex = staticMessages.length + index;
33
50
  const previousMessage = messageIndex > 0 ? displayMessages[messageIndex - 1] : undefined;
34
- return (_jsx(Box, { marginTop: -1, children: _jsx(MessageItem, { message: message, shouldShowHeader: previousMessage?.role !== message.role, isExpanded: isExpanded }) }, `dynamic-${index}`));
35
- }), (isLoading || isCommandRunning || isCompressing) && (_jsxs(Box, { flexDirection: "column", gap: 1, children: [isLoading && (_jsxs(Box, { children: [_jsx(Text, { color: "yellow", children: "\uD83D\uDCAD AI is thinking... " }), _jsxs(Text, { color: "gray", dimColor: true, children: ["|", " "] }), _jsx(Text, { color: "red", bold: true, children: "Esc" }), _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "to abort"] })] })), isCommandRunning && (_jsx(Text, { color: "blue", children: "\uD83D\uDE80 Command is running..." })), isCompressing && (_jsx(Text, { color: "magenta", children: "\uD83D\uDDDC\uFE0F Compressing message history..." }))] })), messages.length > 0 && (_jsx(Box, { children: _jsxs(Box, { justifyContent: "space-between", width: "100%", children: [_jsx(Box, { children: _jsxs(Text, { color: "gray", children: ["Messages ", messages.length, latestTotalTokens > 0 && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "gray", dimColor: true, children: [" ", "|", " "] }), _jsx(Text, { color: "blue", bold: true, children: latestTotalTokens.toLocaleString() }), _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "tokens"] })] }))] }) }), _jsxs(Text, { color: "gray", dimColor: true, children: [_jsx(Text, { color: "cyan", children: "Ctrl+O" }), " Toggle", " ", isExpanded ? "Collapse" : "Expand"] })] }) }))] }));
51
+ return (_jsx(Box, { children: _jsx(MessageItem, { message: message, shouldShowHeader: previousMessage?.role !== message.role, isExpanded: isExpanded }) }, `dynamic-${index}`));
52
+ })] }));
36
53
  });
37
54
  // Add display name for debugging
38
55
  MessageList.displayName = "MessageList";
@@ -1 +1 @@
1
- {"version":3,"file":"PlanDisplay.d.ts","sourceRoot":"","sources":["../../src/components/PlanDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAIvC,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA+BlD,CAAC"}
1
+ {"version":3,"file":"PlanDisplay.d.ts","sourceRoot":"","sources":["../../src/components/PlanDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAQlD,CAAC"}
@@ -1,14 +1,6 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useMemo } from "react";
3
- import { Box, Text, useStdout } from "ink";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box } from "ink";
4
3
  import { Markdown } from "./Markdown.js";
5
- export const PlanDisplay = ({ plan, isExpanded = false, }) => {
6
- const { stdout } = useStdout();
7
- const maxHeight = useMemo(() => {
8
- // Similar to DiffDisplay.tsx maxHeight calculation
9
- return Math.max(5, (stdout?.rows || 24) - 25);
10
- }, [stdout?.rows]);
11
- const lines = useMemo(() => plan.split("\n"), [plan]);
12
- const isOverflowing = !isExpanded && lines.length > maxHeight;
13
- return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Box, { flexDirection: "column", height: isOverflowing ? maxHeight : undefined, overflow: "hidden", children: _jsx(Markdown, { children: plan }) }), isOverflowing && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", dimColor: true, children: ["... (plan truncated, ", lines.length, " lines total)"] }) }))] }));
4
+ export const PlanDisplay = ({ plan }) => {
5
+ return (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(Box, { flexDirection: "column", children: _jsx(Markdown, { children: plan }) }) }));
14
6
  };
@@ -4,6 +4,10 @@ export interface RewindCommandProps {
4
4
  messages: Message[];
5
5
  onSelect: (index: number) => void;
6
6
  onCancel: () => void;
7
+ getFullMessageThread?: () => Promise<{
8
+ messages: Message[];
9
+ sessionIds: string[];
10
+ }>;
7
11
  }
8
12
  export declare const RewindCommand: React.FC<RewindCommandProps>;
9
13
  //# sourceMappingURL=RewindCommand.d.ts.map
@@ -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;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAuGtD,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,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,CAwItD,CAAC"}
@@ -1,12 +1,26 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from "react";
2
+ import React, { useState } from "react";
3
3
  import { Box, Text, useInput } from "ink";
4
- export const RewindCommand = ({ messages, onSelect, onCancel, }) => {
4
+ export const RewindCommand = ({ messages: initialMessages, onSelect, onCancel, getFullMessageThread, }) => {
5
+ const [messages, setMessages] = useState(initialMessages);
6
+ const [isLoading, setIsLoading] = useState(!!getFullMessageThread);
7
+ React.useEffect(() => {
8
+ if (getFullMessageThread) {
9
+ getFullMessageThread().then(({ messages: fullMessages }) => {
10
+ setMessages(fullMessages);
11
+ setIsLoading(false);
12
+ });
13
+ }
14
+ }, [getFullMessageThread]);
5
15
  // Filter user messages as checkpoints
6
16
  const checkpoints = messages
7
17
  .map((msg, index) => ({ msg, index }))
8
18
  .filter(({ msg }) => msg.role === "user");
9
19
  const [selectedIndex, setSelectedIndex] = useState(checkpoints.length - 1);
20
+ // Update selectedIndex when checkpoints change (after loading full thread)
21
+ React.useEffect(() => {
22
+ setSelectedIndex(checkpoints.length - 1);
23
+ }, [checkpoints.length]);
10
24
  useInput((input, key) => {
11
25
  if (key.return) {
12
26
  if (checkpoints.length > 0 && selectedIndex >= 0) {
@@ -27,6 +41,9 @@ export const RewindCommand = ({ messages, onSelect, onCancel, }) => {
27
41
  return;
28
42
  }
29
43
  });
44
+ if (isLoading) {
45
+ return (_jsx(Box, { flexDirection: "column", paddingX: 1, borderStyle: "single", borderColor: "cyan", borderLeft: false, borderRight: false, children: _jsx(Text, { color: "cyan", children: "Loading full message thread..." }) }));
46
+ }
30
47
  if (checkpoints.length === 0) {
31
48
  return (_jsxs(Box, { flexDirection: "column", paddingX: 1, borderStyle: "single", borderColor: "yellow", borderLeft: false, borderRight: false, children: [_jsx(Text, { color: "yellow", children: "No user messages found to rewind to." }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
32
49
  }
@@ -38,5 +55,5 @@ export const RewindCommand = ({ messages, onSelect, onCancel, }) => {
38
55
  .join(" ")
39
56
  .substring(0, 60);
40
57
  return (_jsx(Box, { children: _jsxs(Text, { color: isSelected ? "black" : "white", backgroundColor: isSelected ? "cyan" : undefined, children: [isSelected ? "▶ " : " ", "[", checkpoint.index, "]", " ", content || "(No text content)", index === checkpoints.length - 1 ? " (Latest)" : ""] }) }, checkpoint.index));
41
- }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter to rewind \u2022 Esc to cancel" }) }), _jsx(Box, { children: _jsx(Text, { color: "red", dimColor: true, children: "\u26A0\uFE0F Warning: This will delete all subsequent messages and revert file changes." }) })] }));
58
+ }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter to rewind \u2022 Esc to cancel" }) }), _jsx(Box, { children: _jsx(Text, { color: "red", dimColor: true, children: "\u26A0\uFE0F Warning: This will delete all subsequent messages and revert file and task list changes." }) })] }));
42
59
  };
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ export declare const TaskList: React.FC;
3
+ //# sourceMappingURL=TaskList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskList.d.ts","sourceRoot":"","sources":["../../src/components/TaskList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAoD5B,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useChat } from "../contexts/useChat.js";
3
+ import { Box, Text } from "ink";
4
+ import { useTasks } from "../hooks/useTasks.js";
5
+ export const TaskList = () => {
6
+ const tasks = useTasks();
7
+ const { isTaskListVisible } = useChat();
8
+ if (tasks.length === 0 || !isTaskListVisible) {
9
+ return null;
10
+ }
11
+ const getStatusIcon = (status, isBlocked) => {
12
+ if (isBlocked) {
13
+ return _jsx(Text, { color: "red", children: "\uD83D\uDD12" });
14
+ }
15
+ switch (status) {
16
+ case "pending":
17
+ return _jsx(Text, { color: "gray", children: "\u25A1" });
18
+ case "in_progress":
19
+ return _jsx(Text, { color: "yellow", children: "\u25A0" });
20
+ case "completed":
21
+ return _jsx(Text, { color: "green", children: "\u2713" });
22
+ case "deleted":
23
+ return _jsx(Text, { color: "red", children: "\u2715" });
24
+ default:
25
+ return _jsx(Text, { color: "gray", children: "?" });
26
+ }
27
+ };
28
+ return (_jsx(Box, { flexDirection: "column", children: tasks.map((task) => {
29
+ const isDimmed = task.status === "completed" || task.status === "deleted";
30
+ const isBlocked = task.blockedBy && task.blockedBy.length > 0;
31
+ const blockingTaskIds = isBlocked
32
+ ? task.blockedBy.map((id) => `#${id}`)
33
+ : [];
34
+ const blockedByText = isBlocked && blockingTaskIds.length > 0
35
+ ? ` (Blocked by: ${blockingTaskIds.join(", ")})`
36
+ : "";
37
+ const fullText = `${task.subject}${blockedByText}`;
38
+ return (_jsxs(Box, { gap: 1, children: [getStatusIcon(task.status, isBlocked), _jsx(Text, { dimColor: isDimmed, children: fullText })] }, task.id));
39
+ }) }));
40
+ };
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ import type { ToolBlock } from "wave-agent-sdk";
3
+ interface ToolDisplayProps {
4
+ block: ToolBlock;
5
+ isExpanded?: boolean;
6
+ }
7
+ export declare const ToolDisplay: React.FC<ToolDisplayProps>;
8
+ export {};
9
+ //# sourceMappingURL=ToolDisplay.d.ts.map
@@ -0,0 +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,CA+HlD,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { DiffDisplay } from "./DiffDisplay.js";
4
+ export const ToolDisplay = ({ block, isExpanded = false, }) => {
5
+ const { parameters, result, compactParams, stage, success, error, name } = block;
6
+ // Directly use compactParams
7
+ // (no change needed as we destructured it above)
8
+ const getStatusColor = () => {
9
+ if (stage === "running")
10
+ return "yellow";
11
+ if (success)
12
+ return "green";
13
+ if (error || success === false)
14
+ return "red";
15
+ return "gray"; // Unknown state or no state information
16
+ };
17
+ const hasImages = () => {
18
+ return block.images && block.images.length > 0;
19
+ };
20
+ const getImageIndicator = () => {
21
+ if (!hasImages())
22
+ return "";
23
+ const imageCount = block.images.length;
24
+ return imageCount === 1 ? "🖼️" : `🖼️×${imageCount}`;
25
+ };
26
+ const toolName = name ? String(name) : "Tool";
27
+ // Get shortResult, if not available show last 5 lines of result
28
+ const getShortResult = () => {
29
+ if (block.shortResult) {
30
+ return block.shortResult;
31
+ }
32
+ // If no shortResult but has result, return last 5 lines
33
+ 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;
39
+ }
40
+ return null;
41
+ };
42
+ const shortResult = getShortResult();
43
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Box, { flexShrink: 0, children: [_jsx(Text, { color: getStatusColor(), children: "\u25CF " }), _jsx(Text, { color: "white", children: toolName })] }), !isExpanded && compactParams && (_jsxs(Text, { color: "gray", children: [" ", compactParams] })), hasImages() && _jsxs(Text, { color: "blue", children: [" ", getImageIndicator()] })] }), !isExpanded && shortResult && !error && (_jsx(Box, { paddingLeft: 2, borderLeft: true, borderColor: "gray", flexDirection: "column", children: shortResult.split("\n").map((line, index) => (_jsx(Text, { color: "gray", children: line }, index))) })), isExpanded && parameters && (_jsxs(Box, { paddingLeft: 2, borderLeft: true, borderColor: "gray", flexDirection: "column", children: [_jsx(Text, { color: "cyan", bold: true, children: "Parameters:" }), _jsx(Text, { color: "gray", children: parameters })] })), isExpanded && result && (_jsx(Box, { flexDirection: "column", children: _jsxs(Box, { paddingLeft: 2, borderLeft: true, borderColor: "green", flexDirection: "column", children: [_jsx(Text, { color: "cyan", bold: true, children: "Result:" }), _jsx(Text, { color: "white", children: result })] }) })), error && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["Error: ", typeof error === "string" ? error : String(error)] }) })), stage === "end" && success && (_jsx(DiffDisplay, { toolName: name, parameters: parameters }))] }));
44
+ };