wave-code 0.5.0 → 0.6.1

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 (95) hide show
  1. package/dist/components/App.d.ts.map +1 -1
  2. package/dist/components/App.js +38 -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 +39 -5
  8. package/dist/components/CommandSelector.d.ts.map +1 -1
  9. package/dist/components/CommandSelector.js +10 -2
  10. package/dist/components/CompressDisplay.d.ts.map +1 -1
  11. package/dist/components/CompressDisplay.js +6 -10
  12. package/dist/components/ConfirmationDetails.d.ts +9 -0
  13. package/dist/components/ConfirmationDetails.d.ts.map +1 -0
  14. package/dist/components/ConfirmationDetails.js +53 -0
  15. package/dist/components/{Confirmation.d.ts → ConfirmationSelector.d.ts} +3 -3
  16. package/dist/components/ConfirmationSelector.d.ts.map +1 -0
  17. package/dist/components/{Confirmation.js → ConfirmationSelector.js} +34 -96
  18. package/dist/components/DiffDisplay.d.ts.map +1 -1
  19. package/dist/components/DiffDisplay.js +44 -1
  20. package/dist/components/FileSelector.d.ts.map +1 -1
  21. package/dist/components/FileSelector.js +2 -2
  22. package/dist/components/HistorySearch.d.ts.map +1 -1
  23. package/dist/components/HistorySearch.js +12 -4
  24. package/dist/components/InputBox.d.ts +1 -3
  25. package/dist/components/InputBox.d.ts.map +1 -1
  26. package/dist/components/InputBox.js +7 -17
  27. package/dist/components/LoadingIndicator.d.ts +11 -0
  28. package/dist/components/LoadingIndicator.d.ts.map +1 -0
  29. package/dist/components/LoadingIndicator.js +6 -0
  30. package/dist/components/Markdown.d.ts.map +1 -1
  31. package/dist/components/Markdown.js +114 -121
  32. package/dist/components/MessageItem.d.ts.map +1 -1
  33. package/dist/components/MessageItem.js +1 -2
  34. package/dist/components/MessageList.d.ts +2 -3
  35. package/dist/components/MessageList.d.ts.map +1 -1
  36. package/dist/components/MessageList.js +7 -7
  37. package/dist/components/PlanDisplay.d.ts.map +1 -1
  38. package/dist/components/PlanDisplay.js +4 -12
  39. package/dist/components/RewindCommand.d.ts +4 -0
  40. package/dist/components/RewindCommand.d.ts.map +1 -1
  41. package/dist/components/RewindCommand.js +19 -2
  42. package/dist/components/SubagentBlock.d.ts.map +1 -1
  43. package/dist/components/SubagentBlock.js +9 -6
  44. package/dist/components/TaskList.d.ts +3 -0
  45. package/dist/components/TaskList.d.ts.map +1 -0
  46. package/dist/components/TaskList.js +49 -0
  47. package/dist/components/ToolResultDisplay.js +1 -1
  48. package/dist/contexts/useChat.d.ts +11 -3
  49. package/dist/contexts/useChat.d.ts.map +1 -1
  50. package/dist/contexts/useChat.js +36 -31
  51. package/dist/hooks/useInputManager.d.ts +2 -13
  52. package/dist/hooks/useInputManager.d.ts.map +1 -1
  53. package/dist/hooks/useInputManager.js +8 -57
  54. package/dist/hooks/useTasks.d.ts +2 -0
  55. package/dist/hooks/useTasks.d.ts.map +1 -0
  56. package/dist/hooks/useTasks.js +5 -0
  57. package/dist/managers/InputManager.d.ts +4 -28
  58. package/dist/managers/InputManager.d.ts.map +1 -1
  59. package/dist/managers/InputManager.js +22 -128
  60. package/package.json +5 -6
  61. package/src/components/App.tsx +50 -3
  62. package/src/components/{TaskManager.tsx → BackgroundTaskManager.tsx} +4 -2
  63. package/src/components/ChatInterface.tsx +79 -23
  64. package/src/components/CommandSelector.tsx +35 -17
  65. package/src/components/CompressDisplay.tsx +5 -22
  66. package/src/components/ConfirmationDetails.tsx +108 -0
  67. package/src/components/{Confirmation.tsx → ConfirmationSelector.tsx} +69 -184
  68. package/src/components/DiffDisplay.tsx +62 -1
  69. package/src/components/FileSelector.tsx +0 -2
  70. package/src/components/HistorySearch.tsx +45 -21
  71. package/src/components/InputBox.tsx +11 -33
  72. package/src/components/LoadingIndicator.tsx +56 -0
  73. package/src/components/Markdown.tsx +126 -323
  74. package/src/components/MessageItem.tsx +1 -3
  75. package/src/components/MessageList.tsx +10 -67
  76. package/src/components/PlanDisplay.tsx +4 -27
  77. package/src/components/RewindCommand.tsx +38 -1
  78. package/src/components/SubagentBlock.tsx +25 -16
  79. package/src/components/TaskList.tsx +70 -0
  80. package/src/components/ToolResultDisplay.tsx +2 -2
  81. package/src/contexts/useChat.tsx +57 -40
  82. package/src/hooks/useInputManager.ts +9 -73
  83. package/src/hooks/useTasks.ts +6 -0
  84. package/src/managers/InputManager.ts +25 -159
  85. package/dist/components/Confirmation.d.ts.map +0 -1
  86. package/dist/components/MemoryDisplay.d.ts +0 -8
  87. package/dist/components/MemoryDisplay.d.ts.map +0 -1
  88. package/dist/components/MemoryDisplay.js +0 -25
  89. package/dist/components/MemoryTypeSelector.d.ts +0 -8
  90. package/dist/components/MemoryTypeSelector.d.ts.map +0 -1
  91. package/dist/components/MemoryTypeSelector.js +0 -38
  92. package/dist/components/TaskManager.d.ts +0 -6
  93. package/dist/components/TaskManager.d.ts.map +0 -1
  94. package/src/components/MemoryDisplay.tsx +0 -62
  95. package/src/components/MemoryTypeSelector.tsx +0 -98
@@ -88,9 +88,52 @@ export const DiffDisplay = ({ toolName, parameters, }) => {
88
88
  const lines = part.value
89
89
  .split("\n")
90
90
  .filter((line) => line !== "");
91
- lines.forEach((line, lineIndex) => {
91
+ const isFirstBlock = partIndex === 0;
92
+ const isLastBlock = partIndex === lineDiffs.length - 1;
93
+ let linesToDisplay = lines;
94
+ let showEllipsisTop = false;
95
+ let showEllipsisBottom = false;
96
+ if (isFirstBlock && !isLastBlock) {
97
+ // First block: keep last 3
98
+ if (lines.length > 3) {
99
+ linesToDisplay = lines.slice(-3);
100
+ showEllipsisTop = true;
101
+ }
102
+ }
103
+ else if (isLastBlock && !isFirstBlock) {
104
+ // Last block: keep first 3
105
+ if (lines.length > 3) {
106
+ linesToDisplay = lines.slice(0, 3);
107
+ showEllipsisBottom = true;
108
+ }
109
+ }
110
+ else if (!isFirstBlock && !isLastBlock) {
111
+ // Middle block: keep first 3 and last 3
112
+ if (lines.length > 6) {
113
+ linesToDisplay = [...lines.slice(0, 3), ...lines.slice(-3)];
114
+ showEllipsisTop = false; // We'll put ellipsis in the middle
115
+ }
116
+ }
117
+ else if (isFirstBlock && isLastBlock) {
118
+ // Only one block (no changes?) - keep all or apply a general limit
119
+ // For now, let's keep all if it's the only block
120
+ }
121
+ if (showEllipsisTop) {
122
+ diffElements.push(_jsx(Box, { children: _jsx(Text, { color: "gray", children: " ..." }) }, `ellipsis-top-${changeIndex}-${partIndex}`));
123
+ }
124
+ linesToDisplay.forEach((line, lineIndex) => {
125
+ // If it's a middle block and we are at the split point
126
+ if (!isFirstBlock &&
127
+ !isLastBlock &&
128
+ lines.length > 6 &&
129
+ lineIndex === 3) {
130
+ diffElements.push(_jsx(Box, { children: _jsx(Text, { color: "gray", children: " ..." }) }, `ellipsis-mid-${changeIndex}-${partIndex}`));
131
+ }
92
132
  diffElements.push(_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "white", children: " " }), _jsx(Text, { color: "white", children: line })] }, `context-${changeIndex}-${partIndex}-${lineIndex}`));
93
133
  });
134
+ if (showEllipsisBottom) {
135
+ diffElements.push(_jsx(Box, { children: _jsx(Text, { color: "gray", children: " ..." }) }, `ellipsis-bottom-${changeIndex}-${partIndex}`));
136
+ }
94
137
  }
95
138
  });
96
139
  // If it's a single line change (one removed, one added), use word-level diff
@@ -1 +1 @@
1
- {"version":3,"file":"FileSelector.d.ts","sourceRoot":"","sources":["../../src/components/FileSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA6HpD,CAAC"}
1
+ {"version":3,"file":"FileSelector.d.ts","sourceRoot":"","sources":["../../src/components/FileSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA2HpD,CAAC"}
@@ -24,7 +24,7 @@ export const FileSelector = ({ files, searchQuery, onSelect, onCancel, }) => {
24
24
  }
25
25
  });
26
26
  if (files.length === 0) {
27
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, children: [_jsxs(Text, { color: "yellow", children: ["\uD83D\uDCC1 No files found for \"", searchQuery, "\""] }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
27
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", borderBottom: false, borderLeft: false, borderRight: false, children: [_jsxs(Text, { color: "yellow", children: ["\uD83D\uDCC1 No files found for \"", searchQuery, "\""] }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
28
28
  }
29
29
  const maxDisplay = 10;
30
30
  // Calculate display window start and end positions
@@ -39,7 +39,7 @@ export const FileSelector = ({ files, searchQuery, onSelect, onCancel, }) => {
39
39
  };
40
40
  };
41
41
  const { startIndex, endIndex, displayFiles } = getDisplayWindow();
42
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, children: [_jsxs(Text, { color: "cyan", bold: true, children: ["\uD83D\uDCC1 Select File/Directory", " ", searchQuery && `(filtering: "${searchQuery}")`] }), startIndex > 0 && (_jsxs(Text, { dimColor: true, children: ["... ", startIndex, " more files above"] })), displayFiles.map((fileItem, displayIndex) => {
42
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, children: [_jsxs(Text, { color: "cyan", bold: true, children: ["\uD83D\uDCC1 Select File/Directory", " ", searchQuery && `(filtering: "${searchQuery}")`] }), startIndex > 0 && (_jsxs(Text, { dimColor: true, children: ["... ", startIndex, " more files above"] })), displayFiles.map((fileItem, displayIndex) => {
43
43
  const actualIndex = startIndex + displayIndex;
44
44
  const isSelected = actualIndex === selectedIndex;
45
45
  const icon = fileItem.type === "directory" ? "📁" : "📄";
@@ -1 +1 @@
1
- {"version":3,"file":"HistorySearch.d.ts","sourceRoot":"","sources":["../../src/components/HistorySearch.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAyItD,CAAC"}
1
+ {"version":3,"file":"HistorySearch.d.ts","sourceRoot":"","sources":["../../src/components/HistorySearch.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAiKtD,CAAC"}
@@ -3,6 +3,7 @@ import React, { useState, useEffect } from "react";
3
3
  import { Box, Text, useInput } from "ink";
4
4
  import { PromptHistoryManager } from "wave-agent-sdk";
5
5
  export const HistorySearch = ({ searchQuery, onSelect, onCancel, }) => {
6
+ const MAX_VISIBLE_ITEMS = 5;
6
7
  const [selectedIndex, setSelectedIndex] = useState(0);
7
8
  const [entries, setEntries] = useState([]);
8
9
  const entriesRef = React.useRef([]);
@@ -16,8 +17,8 @@ export const HistorySearch = ({ searchQuery, onSelect, onCancel, }) => {
16
17
  useEffect(() => {
17
18
  const fetchHistory = async () => {
18
19
  const results = await PromptHistoryManager.searchHistory(searchQuery);
19
- const limitedResults = results.slice(0, 10);
20
- setEntries(limitedResults); // Limit to 10 results
20
+ const limitedResults = results.slice(0, 20);
21
+ setEntries(limitedResults); // Limit to 20 results
21
22
  setSelectedIndex(0);
22
23
  };
23
24
  fetchHistory();
@@ -44,7 +45,7 @@ export const HistorySearch = ({ searchQuery, onSelect, onCancel, }) => {
44
45
  }
45
46
  });
46
47
  if (entries.length === 0) {
47
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, children: [_jsxs(Text, { color: "yellow", children: ["No history found ", searchQuery && `for "${searchQuery}"`] }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
48
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", borderBottom: false, borderLeft: false, borderRight: false, children: [_jsxs(Text, { color: "yellow", children: ["No history found ", searchQuery && `for "${searchQuery}"`] }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
48
49
  }
49
50
  const formatTimestamp = (timestamp) => {
50
51
  const date = new Date(timestamp);
@@ -63,5 +64,12 @@ export const HistorySearch = ({ searchQuery, onSelect, onCancel, }) => {
63
64
  return diffMinutes > 0 ? `${diffMinutes}m ago` : "just now";
64
65
  }
65
66
  };
66
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "blue", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "blue", bold: true, children: ["Prompt History ", searchQuery && `(filtering: "${searchQuery}")`] }) }), entries.map((entry, index) => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: index === selectedIndex ? "black" : "white", backgroundColor: index === selectedIndex ? "blue" : undefined, wrap: "truncate-end", children: entry.prompt.replace(/\n/g, " ") }), index === selectedIndex && (_jsx(Box, { marginLeft: 4, children: _jsx(Text, { color: "gray", dimColor: true, children: formatTimestamp(entry.timestamp) }) }))] }, index))), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 to navigate, Enter to select, Escape to cancel" }) })] }));
67
+ // Calculate visible window
68
+ const startIndex = Math.max(0, Math.min(selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2), Math.max(0, entries.length - MAX_VISIBLE_ITEMS)));
69
+ const visibleEntries = entries.slice(startIndex, startIndex + MAX_VISIBLE_ITEMS);
70
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "blue", borderBottom: false, borderLeft: false, borderRight: false, gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "blue", bold: true, children: ["Prompt History ", searchQuery && `(filtering: "${searchQuery}")`] }) }), _jsx(Box, { flexDirection: "column", children: visibleEntries.map((entry, index) => {
71
+ const actualIndex = startIndex + index;
72
+ const isSelected = actualIndex === selectedIndex;
73
+ return (_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", children: [_jsx(Box, { flexShrink: 1, children: _jsx(Text, { color: isSelected ? "black" : "white", backgroundColor: isSelected ? "blue" : undefined, wrap: "truncate-end", children: entry.prompt.replace(/\n/g, " ") }) }), isSelected && (_jsx(Box, { marginLeft: 2, flexShrink: 0, children: _jsx(Text, { color: "gray", dimColor: true, children: formatTimestamp(entry.timestamp) }) }))] }, actualIndex));
74
+ }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 to navigate, Enter to select, Escape to cancel" }) })] }));
67
75
  };
@@ -1,18 +1,16 @@
1
1
  import React from "react";
2
2
  import type { McpServerStatus, SlashCommand } from "wave-agent-sdk";
3
- export declare const INPUT_PLACEHOLDER_TEXT = "Type your message (use @ to reference files, / for commands, # to add memory, Ctrl+R to search history)...";
3
+ export declare const INPUT_PLACEHOLDER_TEXT = "Type your message (use @ to reference files, / for commands, Ctrl+R to search history, Ctrl+O to expand messages, Ctrl+T to toggle tasks)...";
4
4
  export declare const INPUT_PLACEHOLDER_TEXT_PREFIX: string;
5
5
  export interface InputBoxProps {
6
6
  isLoading?: boolean;
7
7
  isCommandRunning?: boolean;
8
8
  workdir?: string;
9
- userInputHistory?: string[];
10
9
  sendMessage?: (message: string, images?: Array<{
11
10
  path: string;
12
11
  mimeType: string;
13
12
  }>) => void;
14
13
  abortMessage?: () => void;
15
- saveMemory?: (message: string, type: "project" | "user") => Promise<void>;
16
14
  mcpServers?: McpServerStatus[];
17
15
  connectMcpServer?: (serverName: string) => Promise<boolean>;
18
16
  disconnectMcpServer?: (serverName: string) => Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAazC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,+GAC2E,CAAC;AAE/G,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,KAC/C,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1E,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAClD;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAiO5C,CAAC"}
1
+ {"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAYzC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,iJAC6G,CAAC;AAEjJ,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,KAC/C,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAE1B,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAClD;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA8M5C,CAAC"}
@@ -5,16 +5,15 @@ import { useInput } from "ink";
5
5
  import { FileSelector } from "./FileSelector.js";
6
6
  import { CommandSelector } from "./CommandSelector.js";
7
7
  import { HistorySearch } from "./HistorySearch.js";
8
- import { MemoryTypeSelector } from "./MemoryTypeSelector.js";
9
- import { TaskManager } from "./TaskManager.js";
8
+ import { BackgroundTaskManager } from "./BackgroundTaskManager.js";
10
9
  import { McpManager } from "./McpManager.js";
11
10
  import { RewindCommand } from "./RewindCommand.js";
12
11
  import { useInputManager } from "../hooks/useInputManager.js";
13
12
  import { useChat } from "../contexts/useChat.js";
14
- export const INPUT_PLACEHOLDER_TEXT = "Type your message (use @ to reference files, / for commands, # to add memory, Ctrl+R to search history)...";
13
+ export const INPUT_PLACEHOLDER_TEXT = "Type your message (use @ to reference files, / for commands, Ctrl+R to search history, Ctrl+O to expand messages, Ctrl+T to toggle tasks)...";
15
14
  export const INPUT_PLACEHOLDER_TEXT_PREFIX = INPUT_PLACEHOLDER_TEXT.substring(0, 10);
16
- export const InputBox = ({ isLoading = false, isCommandRunning = false, userInputHistory = [], sendMessage = () => { }, abortMessage = () => { }, saveMemory = async () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, }) => {
17
- const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, handleRewindSelect, backgroundCurrentTask, messages, } = useChat();
15
+ export const InputBox = ({ isLoading = false, isCommandRunning = false, sendMessage = () => { }, abortMessage = () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, }) => {
16
+ const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, } = useChat();
18
17
  // Input manager with all input state and functionality (including images)
19
18
  const { inputText, cursorPosition,
20
19
  // Image management
@@ -23,23 +22,18 @@ export const InputBox = ({ isLoading = false, isCommandRunning = false, userInpu
23
22
  showFileSelector, filteredFiles, fileSearchQuery: searchQuery, handleFileSelect, handleCancelFileSelect,
24
23
  // Command selector
25
24
  showCommandSelector, commandSearchQuery, handleCommandSelect, handleCommandInsert, handleCancelCommandSelect, handleHistorySearchSelect, handleCancelHistorySearch,
26
- // Memory type selector
27
- showMemoryTypeSelector, memoryMessage, handleMemoryTypeSelect, handleCancelMemoryTypeSelect,
28
25
  // History search
29
26
  showHistorySearch, historySearchQuery,
30
27
  // Task/MCP Manager
31
- showTaskManager, showMcpManager, showRewindManager, setShowTaskManager, setShowMcpManager, setShowRewindManager,
28
+ showBackgroundTaskManager, showMcpManager, showRewindManager, setShowBackgroundTaskManager, setShowMcpManager, setShowRewindManager,
32
29
  // Permission mode
33
30
  permissionMode, setPermissionMode,
34
- // Input history
35
- setUserInputHistory,
36
31
  // Main handler
37
32
  handleInput,
38
33
  // Manager ready state
39
34
  isManagerReady, } = useInputManager({
40
35
  onSendMessage: sendMessage,
41
36
  onHasSlashCommand: hasSlashCommand,
42
- onSaveMemory: saveMemory,
43
37
  onAbortMessage: abortMessage,
44
38
  onBackgroundCurrentTask: backgroundCurrentTask,
45
39
  onPermissionModeChange: setChatPermissionMode,
@@ -48,10 +42,6 @@ export const InputBox = ({ isLoading = false, isCommandRunning = false, userInpu
48
42
  useEffect(() => {
49
43
  setPermissionMode(chatPermissionMode);
50
44
  }, [chatPermissionMode, setPermissionMode]);
51
- // Set user input history when it changes
52
- useEffect(() => {
53
- setUserInputHistory(userInputHistory);
54
- }, [userInputHistory, setUserInputHistory]);
55
45
  // Use the InputManager's unified input handler
56
46
  useInput(async (input, key) => {
57
47
  await handleInput(input, key, attachedImages, isLoading, isCommandRunning, clearImages);
@@ -82,7 +72,7 @@ export const InputBox = ({ isLoading = false, isCommandRunning = false, userInpu
82
72
  await handleRewindSelect(index);
83
73
  };
84
74
  if (showRewindManager) {
85
- return (_jsx(RewindCommand, { messages: messages, onSelect: handleRewindSelectWithClose, onCancel: handleRewindCancel }));
75
+ return (_jsx(RewindCommand, { messages: messages, onSelect: handleRewindSelectWithClose, onCancel: handleRewindCancel, getFullMessageThread: getFullMessageThread }));
86
76
  }
87
- return (_jsxs(Box, { flexDirection: "column", children: [showFileSelector && (_jsx(FileSelector, { files: filteredFiles, searchQuery: searchQuery, onSelect: handleFileSelect, onCancel: handleCancelFileSelect })), showCommandSelector && (_jsx(CommandSelector, { searchQuery: commandSearchQuery, onSelect: handleCommandSelect, onInsert: handleCommandInsert, onCancel: handleCancelCommandSelect, commands: slashCommands })), showHistorySearch && (_jsx(HistorySearch, { searchQuery: historySearchQuery, onSelect: handleHistorySearchSelect, onCancel: handleCancelHistorySearch })), showMemoryTypeSelector && (_jsx(MemoryTypeSelector, { message: memoryMessage, onSelect: handleMemoryTypeSelect, onCancel: handleCancelMemoryTypeSelect })), showTaskManager && (_jsx(TaskManager, { onCancel: () => setShowTaskManager(false) })), showMcpManager && (_jsx(McpManager, { onCancel: () => setShowMcpManager(false), servers: mcpServers, onConnectServer: connectMcpServer, onDisconnectServer: disconnectMcpServer })), showTaskManager || showMcpManager || showRewindManager || (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { borderStyle: "single", borderColor: "gray", borderLeft: false, borderRight: false, children: _jsx(Text, { color: isPlaceholder ? "gray" : "white", children: shouldShowCursor ? (_jsxs(_Fragment, { children: [beforeCursor, _jsx(Text, { backgroundColor: "white", color: "black", children: atCursor }), afterCursor] })) : (displayText) }) }), _jsx(Box, { paddingRight: 1, children: _jsxs(Text, { color: "gray", children: ["Mode:", " ", _jsx(Text, { color: permissionMode === "plan" ? "yellow" : "cyan", children: permissionMode }), " ", "(Shift+Tab to cycle)"] }) })] }))] }));
77
+ return (_jsxs(Box, { flexDirection: "column", children: [showFileSelector && (_jsx(FileSelector, { files: filteredFiles, searchQuery: searchQuery, onSelect: handleFileSelect, onCancel: handleCancelFileSelect })), showCommandSelector && (_jsx(CommandSelector, { searchQuery: commandSearchQuery, onSelect: handleCommandSelect, onInsert: handleCommandInsert, onCancel: handleCancelCommandSelect, commands: slashCommands })), showHistorySearch && (_jsx(HistorySearch, { searchQuery: historySearchQuery, onSelect: handleHistorySearchSelect, onCancel: handleCancelHistorySearch })), showBackgroundTaskManager && (_jsx(BackgroundTaskManager, { onCancel: () => setShowBackgroundTaskManager(false) })), showMcpManager && (_jsx(McpManager, { onCancel: () => setShowMcpManager(false), servers: mcpServers, onConnectServer: connectMcpServer, onDisconnectServer: disconnectMcpServer })), showBackgroundTaskManager || showMcpManager || showRewindManager || (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { borderStyle: "single", borderColor: "gray", borderLeft: false, borderRight: false, children: _jsx(Text, { color: isPlaceholder ? "gray" : "white", children: shouldShowCursor ? (_jsxs(_Fragment, { children: [beforeCursor, _jsx(Text, { backgroundColor: "white", color: "black", children: atCursor }), afterCursor] })) : (displayText) }) }), _jsx(Box, { paddingRight: 1, justifyContent: "space-between", width: "100%", children: _jsxs(Text, { color: "gray", children: ["Mode:", " ", _jsx(Text, { color: permissionMode === "plan" ? "yellow" : "cyan", children: permissionMode }), " ", "(Shift+Tab to cycle)"] }) })] }))] }));
88
78
  };
@@ -0,0 +1,11 @@
1
+ export interface LoadingIndicatorProps {
2
+ isLoading?: boolean;
3
+ isCommandRunning?: boolean;
4
+ isCompressing?: boolean;
5
+ latestTotalTokens?: number;
6
+ }
7
+ export declare const LoadingIndicator: {
8
+ ({ isLoading, isCommandRunning, isCompressing, latestTotalTokens, }: LoadingIndicatorProps): import("react/jsx-runtime").JSX.Element;
9
+ displayName: string;
10
+ };
11
+ //# sourceMappingURL=LoadingIndicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoadingIndicator.d.ts","sourceRoot":"","sources":["../../src/components/LoadingIndicator.tsx"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,gBAAgB;yEAK1B,qBAAqB;;CAsCvB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ export const LoadingIndicator = ({ isLoading = false, isCommandRunning = false, isCompressing = false, latestTotalTokens = 0, }) => {
4
+ return (_jsxs(Box, { flexDirection: "column", children: [isLoading && (_jsxs(Box, { children: [_jsx(Text, { color: "yellow", children: "\uD83D\uDCAD AI is thinking... " }), 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: "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..." }))] }));
5
+ };
6
+ LoadingIndicator.displayName = "LoadingIndicator";
@@ -1 +1 @@
1
- {"version":3,"file":"Markdown.d.ts","sourceRoot":"","sources":["../../src/components/Markdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAKvC,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAmVD,eAAO,MAAM,QAAQ,2CAA6B,aAAa,6CAQ7D,CAAC"}
1
+ {"version":3,"file":"Markdown.d.ts","sourceRoot":"","sources":["../../src/components/Markdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAKvC,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAwID,eAAO,MAAM,QAAQ,2CAA6B,aAAa,6CAc7D,CAAC"}
@@ -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(/&amp;/g, "&")
@@ -12,124 +12,117 @@ const unescapeHtml = (html) => {
12
12
  .replace(/&#39;/g, "'")
13
13
  .replace(/&apos;/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";
@@ -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;AAS9C,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,mDAwElB,CAAC"}
@@ -3,7 +3,6 @@ import { Box, Text } from "ink";
3
3
  import { MessageSource } from "wave-agent-sdk";
4
4
  import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
5
5
  import { ToolResultDisplay } from "./ToolResultDisplay.js";
6
- import { MemoryDisplay } from "./MemoryDisplay.js";
7
6
  import { CompressDisplay } from "./CompressDisplay.js";
8
7
  import { SubagentBlock } from "./SubagentBlock.js";
9
8
  import { ReasoningDisplay } from "./ReasoningDisplay.js";
@@ -11,5 +10,5 @@ import { Markdown } from "./Markdown.js";
11
10
  export const MessageItem = ({ message, isExpanded, shouldShowHeader, }) => {
12
11
  if (message.blocks.length === 0)
13
12
  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))) })] }));
13
+ 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 === "compress" && (_jsx(CompressDisplay, { block: block, isExpanded: isExpanded })), block.type === "subagent" && _jsx(SubagentBlock, { block: block }), block.type === "reasoning" && _jsx(ReasoningDisplay, { block: block })] }, blockIndex))) })] }));
15
14
  };
@@ -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;AAG9C,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,6CAiFpB,CAAC"}