wave-code 0.0.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.
- package/README.md +120 -0
- package/bin/wave-code.js +16 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +62 -0
- package/dist/components/App.d.ts +8 -0
- package/dist/components/App.d.ts.map +1 -0
- package/dist/components/App.js +10 -0
- package/dist/components/BashHistorySelector.d.ts +10 -0
- package/dist/components/BashHistorySelector.d.ts.map +1 -0
- package/dist/components/BashHistorySelector.js +83 -0
- package/dist/components/BashShellManager.d.ts +6 -0
- package/dist/components/BashShellManager.d.ts.map +1 -0
- package/dist/components/BashShellManager.js +116 -0
- package/dist/components/ChatInterface.d.ts +3 -0
- package/dist/components/ChatInterface.d.ts.map +1 -0
- package/dist/components/ChatInterface.js +31 -0
- package/dist/components/CommandOutputDisplay.d.ts +9 -0
- package/dist/components/CommandOutputDisplay.d.ts.map +1 -0
- package/dist/components/CommandOutputDisplay.js +40 -0
- package/dist/components/CommandSelector.d.ts +11 -0
- package/dist/components/CommandSelector.d.ts.map +1 -0
- package/dist/components/CommandSelector.js +60 -0
- package/dist/components/CompressDisplay.d.ts +9 -0
- package/dist/components/CompressDisplay.d.ts.map +1 -0
- package/dist/components/CompressDisplay.js +17 -0
- package/dist/components/DiffViewer.d.ts +9 -0
- package/dist/components/DiffViewer.d.ts.map +1 -0
- package/dist/components/DiffViewer.js +221 -0
- package/dist/components/FileSelector.d.ts +13 -0
- package/dist/components/FileSelector.d.ts.map +1 -0
- package/dist/components/FileSelector.js +48 -0
- package/dist/components/InputBox.d.ts +23 -0
- package/dist/components/InputBox.d.ts.map +1 -0
- package/dist/components/InputBox.js +124 -0
- package/dist/components/McpManager.d.ts +10 -0
- package/dist/components/McpManager.d.ts.map +1 -0
- package/dist/components/McpManager.js +123 -0
- package/dist/components/MemoryDisplay.d.ts +8 -0
- package/dist/components/MemoryDisplay.d.ts.map +1 -0
- package/dist/components/MemoryDisplay.js +25 -0
- package/dist/components/MemoryTypeSelector.d.ts +8 -0
- package/dist/components/MemoryTypeSelector.d.ts.map +1 -0
- package/dist/components/MemoryTypeSelector.js +38 -0
- package/dist/components/MessageList.d.ts +12 -0
- package/dist/components/MessageList.d.ts.map +1 -0
- package/dist/components/MessageList.js +36 -0
- package/dist/components/ToolResultDisplay.d.ts +9 -0
- package/dist/components/ToolResultDisplay.d.ts.map +1 -0
- package/dist/components/ToolResultDisplay.js +52 -0
- package/dist/contexts/useAppConfig.d.ts +11 -0
- package/dist/contexts/useAppConfig.d.ts.map +1 -0
- package/dist/contexts/useAppConfig.js +13 -0
- package/dist/contexts/useChat.d.ts +36 -0
- package/dist/contexts/useChat.d.ts.map +1 -0
- package/dist/contexts/useChat.js +208 -0
- package/dist/hooks/useBashHistorySelector.d.ts +15 -0
- package/dist/hooks/useBashHistorySelector.d.ts.map +1 -0
- package/dist/hooks/useBashHistorySelector.js +61 -0
- package/dist/hooks/useCommandSelector.d.ts +24 -0
- package/dist/hooks/useCommandSelector.d.ts.map +1 -0
- package/dist/hooks/useCommandSelector.js +98 -0
- package/dist/hooks/useFileSelector.d.ts +16 -0
- package/dist/hooks/useFileSelector.d.ts.map +1 -0
- package/dist/hooks/useFileSelector.js +174 -0
- package/dist/hooks/useImageManager.d.ts +13 -0
- package/dist/hooks/useImageManager.d.ts.map +1 -0
- package/dist/hooks/useImageManager.js +46 -0
- package/dist/hooks/useInputHistory.d.ts +11 -0
- package/dist/hooks/useInputHistory.d.ts.map +1 -0
- package/dist/hooks/useInputHistory.js +64 -0
- package/dist/hooks/useInputKeyboardHandler.d.ts +83 -0
- package/dist/hooks/useInputKeyboardHandler.d.ts.map +1 -0
- package/dist/hooks/useInputKeyboardHandler.js +507 -0
- package/dist/hooks/useInputState.d.ts +14 -0
- package/dist/hooks/useInputState.d.ts.map +1 -0
- package/dist/hooks/useInputState.js +57 -0
- package/dist/hooks/useMemoryTypeSelector.d.ts +9 -0
- package/dist/hooks/useMemoryTypeSelector.d.ts.map +1 -0
- package/dist/hooks/useMemoryTypeSelector.js +27 -0
- package/dist/hooks/usePagination.d.ts +20 -0
- package/dist/hooks/usePagination.d.ts.map +1 -0
- package/dist/hooks/usePagination.js +168 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +91 -0
- package/dist/plain-cli.d.ts +7 -0
- package/dist/plain-cli.d.ts.map +1 -0
- package/dist/plain-cli.js +49 -0
- package/dist/utils/clipboard.d.ts +22 -0
- package/dist/utils/clipboard.d.ts.map +1 -0
- package/dist/utils/clipboard.js +347 -0
- package/dist/utils/constants.d.ts +17 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +18 -0
- package/dist/utils/logger.d.ts +72 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +245 -0
- package/package.json +60 -0
- package/src/cli.tsx +82 -0
- package/src/components/App.tsx +31 -0
- package/src/components/BashHistorySelector.tsx +163 -0
- package/src/components/BashShellManager.tsx +306 -0
- package/src/components/ChatInterface.tsx +88 -0
- package/src/components/CommandOutputDisplay.tsx +81 -0
- package/src/components/CommandSelector.tsx +144 -0
- package/src/components/CompressDisplay.tsx +58 -0
- package/src/components/DiffViewer.tsx +321 -0
- package/src/components/FileSelector.tsx +137 -0
- package/src/components/InputBox.tsx +310 -0
- package/src/components/McpManager.tsx +328 -0
- package/src/components/MemoryDisplay.tsx +62 -0
- package/src/components/MemoryTypeSelector.tsx +96 -0
- package/src/components/MessageList.tsx +215 -0
- package/src/components/ToolResultDisplay.tsx +138 -0
- package/src/contexts/useAppConfig.tsx +32 -0
- package/src/contexts/useChat.tsx +300 -0
- package/src/hooks/useBashHistorySelector.ts +77 -0
- package/src/hooks/useCommandSelector.ts +131 -0
- package/src/hooks/useFileSelector.ts +227 -0
- package/src/hooks/useImageManager.ts +64 -0
- package/src/hooks/useInputHistory.ts +74 -0
- package/src/hooks/useInputKeyboardHandler.ts +778 -0
- package/src/hooks/useInputState.ts +66 -0
- package/src/hooks/useMemoryTypeSelector.ts +40 -0
- package/src/hooks/usePagination.ts +203 -0
- package/src/index.ts +108 -0
- package/src/plain-cli.ts +66 -0
- package/src/utils/clipboard.ts +384 -0
- package/src/utils/constants.ts +22 -0
- package/src/utils/logger.ts +301 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
export const MemoryDisplay = ({ block }) => {
|
|
4
|
+
const { content, isSuccess, memoryType, storagePath } = block;
|
|
5
|
+
const getStatusIcon = () => {
|
|
6
|
+
return isSuccess ? "💾" : "⚠️";
|
|
7
|
+
};
|
|
8
|
+
const getStatusColor = () => {
|
|
9
|
+
return isSuccess ? "green" : "red";
|
|
10
|
+
};
|
|
11
|
+
const getStatusText = () => {
|
|
12
|
+
return isSuccess ? "Added to memory" : "Failed to add memory";
|
|
13
|
+
};
|
|
14
|
+
const getStorageText = () => {
|
|
15
|
+
if (!isSuccess)
|
|
16
|
+
return null;
|
|
17
|
+
if (memoryType === "user") {
|
|
18
|
+
return `Memory saved to ${storagePath || "user-memory.md"}`;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
return `Memory saved to ${storagePath || "WAVE.md"}`;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Text, { color: getStatusColor(), children: [getStatusIcon(), " "] }), _jsx(Text, { color: getStatusColor(), children: getStatusText() })] }), content && (_jsx(Box, { marginTop: 1, paddingLeft: 2, children: _jsx(Box, { borderLeft: true, borderColor: isSuccess ? "green" : "red", paddingLeft: 1, children: _jsx(Text, { color: "gray", children: content }) }) })), isSuccess && (_jsx(Box, { paddingLeft: 2, marginTop: 1, children: _jsx(Text, { color: "yellow", dimColor: true, children: getStorageText() }) }))] }));
|
|
25
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface MemoryTypeSelectorProps {
|
|
3
|
+
message: string;
|
|
4
|
+
onSelect: (type: "project" | "user") => void;
|
|
5
|
+
onCancel: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare const MemoryTypeSelector: React.FC<MemoryTypeSelectorProps>;
|
|
8
|
+
//# sourceMappingURL=MemoryTypeSelector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MemoryTypeSelector.d.ts","sourceRoot":"","sources":["../../src/components/MemoryTypeSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,KAAK,IAAI,CAAC;IAC7C,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAsFhE,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Box, Text, useInput } from "ink";
|
|
4
|
+
export const MemoryTypeSelector = ({ message, onSelect, onCancel, }) => {
|
|
5
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
6
|
+
const options = [
|
|
7
|
+
{
|
|
8
|
+
type: "project",
|
|
9
|
+
label: "Project Memory",
|
|
10
|
+
description: "Save to current project (WAVE.md)",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
type: "user",
|
|
14
|
+
label: "User Memory",
|
|
15
|
+
description: "Save to user global memory",
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
useInput((input, key) => {
|
|
19
|
+
if (key.return) {
|
|
20
|
+
const selectedOption = options[selectedIndex];
|
|
21
|
+
onSelect(selectedOption.type);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (key.escape) {
|
|
25
|
+
onCancel();
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (key.upArrow) {
|
|
29
|
+
setSelectedIndex(Math.max(0, selectedIndex - 1));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (key.downArrow) {
|
|
33
|
+
setSelectedIndex(Math.min(options.length - 1, selectedIndex + 1));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "green", padding: 1, gap: 1, marginBottom: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "green", bold: true, children: ["Save Memory: \"", message.substring(1).trim(), "\""] }) }), _jsx(Text, { color: "gray", children: "Choose where to save this memory:" }), options.map((option, index) => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: index === selectedIndex ? "black" : "white", backgroundColor: index === selectedIndex ? "green" : undefined, bold: index === selectedIndex, children: option.label }), index === selectedIndex && (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "gray", dimColor: true, children: option.description }) }))] }, option.type))), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 to navigate, Enter to select, Escape to cancel" }) })] }));
|
|
38
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Message } from "wave-agent-sdk";
|
|
3
|
+
export interface MessageListProps {
|
|
4
|
+
messages: Message[];
|
|
5
|
+
isLoading?: boolean;
|
|
6
|
+
isCommandRunning?: boolean;
|
|
7
|
+
isCompressing?: boolean;
|
|
8
|
+
latestTotalTokens?: number;
|
|
9
|
+
isExpanded?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare const MessageList: React.FC<MessageListProps>;
|
|
12
|
+
//# sourceMappingURL=MessageList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAkG9C,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,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAyGlD,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
|
+
import { DiffViewer } from "./DiffViewer.js";
|
|
5
|
+
import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
|
|
6
|
+
import { ToolResultDisplay } from "./ToolResultDisplay.js";
|
|
7
|
+
import { MemoryDisplay } from "./MemoryDisplay.js";
|
|
8
|
+
import { CompressDisplay } from "./CompressDisplay.js";
|
|
9
|
+
import { usePagination } from "../hooks/usePagination.js";
|
|
10
|
+
// Function to render a single message
|
|
11
|
+
const renderMessageItem = (message, originalIndex, isExpanded, previousMessage) => {
|
|
12
|
+
const shouldShowHeader = previousMessage?.role !== message.role;
|
|
13
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [shouldShowHeader && (_jsx(Box, { children: _jsxs(Text, { color: message.role === "user" ? "cyan" : "green", bold: true, children: [message.role === "user" ? "👤 You" : "🤖 Assistant", _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "#", originalIndex + 1] })] }) })), _jsx(Box, { marginLeft: 2, flexDirection: "column", gap: 1, marginTop: shouldShowHeader ? 1 : 0, children: message.blocks.map((block, blockIndex) => (_jsxs(Box, { children: [block.type === "text" && block.content.trim() && (_jsx(Box, { children: _jsx(Text, { children: block.content }) })), block.type === "error" && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["\u274C Error: ", block.content] }) })), block.type === "diff" && (_jsx(DiffViewer, { block: block, isExpanded: isExpanded })), 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 === "custom_command" && (_jsxs(Box, { children: [_jsx(Text, { color: "cyan", bold: true, children: "\u26A1" }), _jsx(Text, { children: block.originalInput || `/${block.commandName}` })] }))] }, blockIndex))) })] }, `message-${originalIndex}`));
|
|
14
|
+
};
|
|
15
|
+
export const MessageList = ({ messages, isLoading = false, isCommandRunning = false, isCompressing = false, latestTotalTokens = 0, isExpanded = false, }) => {
|
|
16
|
+
// Use original messages for pagination calculation
|
|
17
|
+
const { displayInfo } = usePagination(messages);
|
|
18
|
+
// Get current page messages while preserving original index information
|
|
19
|
+
const currentMessagesWithIndex = useMemo(() => {
|
|
20
|
+
return messages
|
|
21
|
+
.slice(displayInfo.startIndex, displayInfo.endIndex)
|
|
22
|
+
.map((message, index) => ({
|
|
23
|
+
message,
|
|
24
|
+
originalIndex: displayInfo.startIndex + index,
|
|
25
|
+
}));
|
|
26
|
+
}, [messages, displayInfo.startIndex, displayInfo.endIndex]);
|
|
27
|
+
// Empty message state
|
|
28
|
+
if (messages.length === 0) {
|
|
29
|
+
return (_jsx(Box, { flexDirection: "column", paddingY: 1, children: _jsx(Text, { color: "gray", children: "Welcome to WAVE Code Assistant!" }) }));
|
|
30
|
+
}
|
|
31
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { flexDirection: "column", children: currentMessagesWithIndex.map(({ message, originalIndex }) => {
|
|
32
|
+
// Get previous message
|
|
33
|
+
const previousMessage = originalIndex > 0 ? messages[originalIndex - 1] : undefined;
|
|
34
|
+
return renderMessageItem(message, originalIndex, isExpanded, previousMessage);
|
|
35
|
+
}) }), !isExpanded && (isLoading || isCommandRunning || isCompressing) && (_jsxs(Box, { marginTop: 1, 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: "blue", bold: true, children: latestTotalTokens.toLocaleString() }), _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "tokens |", " "] }), _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, { marginTop: 1, children: _jsxs(Box, { justifyContent: "space-between", width: "100%", children: [_jsxs(Box, { children: [_jsxs(Text, { color: "gray", children: ["Messages ", messages.length, " Page ", displayInfo.currentPage, "/", displayInfo.totalPages] }), _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "\u2190 ", _jsx(Text, { color: "cyan", children: "Ctrl+U/D" }), " Navigate"] })] }), _jsxs(Text, { color: "gray", dimColor: true, children: [_jsx(Text, { color: "cyan", children: "Ctrl+O" }), " Toggle", " ", isExpanded ? "Collapse" : "Expand"] })] }) }))] }));
|
|
36
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { ToolBlock } from "wave-agent-sdk";
|
|
3
|
+
interface ToolResultDisplayProps {
|
|
4
|
+
block: ToolBlock;
|
|
5
|
+
isExpanded?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const ToolResultDisplay: React.FC<ToolResultDisplayProps>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=ToolResultDisplay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolResultDisplay.d.ts","sourceRoot":"","sources":["../../src/components/ToolResultDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,UAAU,sBAAsB;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAgI9D,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
export const ToolResultDisplay = ({ block, isExpanded = false, }) => {
|
|
4
|
+
const { parameters, result, compactParams, isRunning, success, error, name } = block;
|
|
5
|
+
// Directly use compactParams
|
|
6
|
+
// (no change needed as we destructured it above)
|
|
7
|
+
const getStatusColor = () => {
|
|
8
|
+
if (isRunning)
|
|
9
|
+
return "yellow";
|
|
10
|
+
if (success)
|
|
11
|
+
return "green";
|
|
12
|
+
if (error || success === false)
|
|
13
|
+
return "red";
|
|
14
|
+
return "gray"; // Unknown state or no state information
|
|
15
|
+
};
|
|
16
|
+
const getStatusText = () => {
|
|
17
|
+
if (isRunning)
|
|
18
|
+
return "🔄";
|
|
19
|
+
if (success)
|
|
20
|
+
return "";
|
|
21
|
+
if (error || success === false)
|
|
22
|
+
return "❌ Failed";
|
|
23
|
+
return ""; // Don't display text for unknown state
|
|
24
|
+
};
|
|
25
|
+
const hasImages = () => {
|
|
26
|
+
return block.images && block.images.length > 0;
|
|
27
|
+
};
|
|
28
|
+
const getImageIndicator = () => {
|
|
29
|
+
if (!hasImages())
|
|
30
|
+
return "";
|
|
31
|
+
const imageCount = block.images.length;
|
|
32
|
+
return imageCount === 1 ? "🖼️" : `🖼️×${imageCount}`;
|
|
33
|
+
};
|
|
34
|
+
const toolName = name ? String(name) : "Tool";
|
|
35
|
+
// Get shortResult, if not available show last 5 lines of result
|
|
36
|
+
const getShortResult = () => {
|
|
37
|
+
if (block.shortResult) {
|
|
38
|
+
return block.shortResult;
|
|
39
|
+
}
|
|
40
|
+
// If no shortResult but has result, return last 5 lines
|
|
41
|
+
if (block.result) {
|
|
42
|
+
const lines = block.result.split("\n");
|
|
43
|
+
if (lines.length > 5) {
|
|
44
|
+
return lines.slice(-5).join("\n");
|
|
45
|
+
}
|
|
46
|
+
return block.result;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
};
|
|
50
|
+
const shortResult = getShortResult();
|
|
51
|
+
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: "magenta", children: "\uD83D\uDD27 " }), _jsx(Text, { color: "white", children: toolName }), !isExpanded && compactParams && (_jsxs(Text, { color: "gray", children: [" (", compactParams, ")"] })), _jsxs(Text, { color: getStatusColor(), children: [" ", getStatusText()] }), hasImages() && _jsxs(Text, { color: "blue", children: [" ", getImageIndicator()] })] }), !isExpanded && shortResult && (_jsx(Box, { paddingLeft: 2, borderLeft: true, borderColor: "gray", flexDirection: "column", children: shortResult.split("\n").map((line, index) => (_jsx(Text, { color: "white", 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)] }) }))] }));
|
|
52
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface AppConfig {
|
|
3
|
+
restoreSessionId?: string;
|
|
4
|
+
continueLastSession?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare const useAppConfig: () => AppConfig;
|
|
7
|
+
export interface AppProviderProps extends AppConfig {
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export declare const AppProvider: React.FC<AppProviderProps>;
|
|
11
|
+
//# sourceMappingURL=useAppConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAppConfig.d.ts","sourceRoot":"","sources":["../../src/contexts/useAppConfig.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAEzD,MAAM,WAAW,SAAS;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAID,eAAO,MAAM,YAAY,iBAMxB,CAAC;AAEF,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAUlD,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext } from "react";
|
|
3
|
+
const AppContext = createContext(null);
|
|
4
|
+
export const useAppConfig = () => {
|
|
5
|
+
const context = useContext(AppContext);
|
|
6
|
+
if (!context) {
|
|
7
|
+
throw new Error("useAppConfig must be used within AppProvider");
|
|
8
|
+
}
|
|
9
|
+
return context;
|
|
10
|
+
};
|
|
11
|
+
export const AppProvider = ({ restoreSessionId, continueLastSession, children, }) => {
|
|
12
|
+
return (_jsx(AppContext.Provider, { value: { restoreSessionId, continueLastSession }, children: children }));
|
|
13
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Message, McpServerStatus, BackgroundShell, SlashCommand } from "wave-agent-sdk";
|
|
3
|
+
export interface ChatContextType {
|
|
4
|
+
messages: Message[];
|
|
5
|
+
isLoading: boolean;
|
|
6
|
+
isCommandRunning: boolean;
|
|
7
|
+
isCompressing: boolean;
|
|
8
|
+
userInputHistory: string[];
|
|
9
|
+
isExpanded: boolean;
|
|
10
|
+
sessionId: string;
|
|
11
|
+
sendMessage: (content: string, images?: Array<{
|
|
12
|
+
path: string;
|
|
13
|
+
mimeType: string;
|
|
14
|
+
}>) => Promise<void>;
|
|
15
|
+
abortMessage: () => void;
|
|
16
|
+
latestTotalTokens: number;
|
|
17
|
+
saveMemory: (message: string, type: "project" | "user") => Promise<void>;
|
|
18
|
+
mcpServers: McpServerStatus[];
|
|
19
|
+
connectMcpServer: (serverName: string) => Promise<boolean>;
|
|
20
|
+
disconnectMcpServer: (serverName: string) => Promise<boolean>;
|
|
21
|
+
backgroundShells: BackgroundShell[];
|
|
22
|
+
getBackgroundShellOutput: (shellId: string) => {
|
|
23
|
+
stdout: string;
|
|
24
|
+
stderr: string;
|
|
25
|
+
status: string;
|
|
26
|
+
} | null;
|
|
27
|
+
killBackgroundShell: (shellId: string) => boolean;
|
|
28
|
+
slashCommands: SlashCommand[];
|
|
29
|
+
hasSlashCommand: (commandId: string) => boolean;
|
|
30
|
+
}
|
|
31
|
+
export declare const useChat: () => ChatContextType;
|
|
32
|
+
export interface ChatProviderProps {
|
|
33
|
+
children: React.ReactNode;
|
|
34
|
+
}
|
|
35
|
+
export declare const ChatProvider: React.FC<ChatProviderProps>;
|
|
36
|
+
//# sourceMappingURL=useChat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/contexts/useChat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAON,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EACV,OAAO,EACP,eAAe,EACf,eAAe,EACf,YAAY,EACb,MAAM,gBAAgB,CAAC;AAKxB,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAE3B,UAAU,EAAE,OAAO,CAAC;IAEpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,CACX,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,KAC/C,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAE1B,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzE,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,mBAAmB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE9D,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,wBAAwB,EAAE,CACxB,OAAO,EAAE,MAAM,KACZ;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/D,mBAAmB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAElD,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CACjD;AAID,eAAO,MAAM,OAAO,uBAMnB,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAwOpD,CAAC"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useCallback, useRef, useEffect, useState, } from "react";
|
|
3
|
+
import { useInput } from "ink";
|
|
4
|
+
import { useAppConfig } from "./useAppConfig.js";
|
|
5
|
+
import { Agent } from "wave-agent-sdk";
|
|
6
|
+
import { logger } from "../utils/logger.js";
|
|
7
|
+
const ChatContext = createContext(null);
|
|
8
|
+
export const useChat = () => {
|
|
9
|
+
const context = useContext(ChatContext);
|
|
10
|
+
if (!context) {
|
|
11
|
+
throw new Error("useChat must be used within ChatProvider");
|
|
12
|
+
}
|
|
13
|
+
return context;
|
|
14
|
+
};
|
|
15
|
+
export const ChatProvider = ({ children }) => {
|
|
16
|
+
const { restoreSessionId, continueLastSession } = useAppConfig();
|
|
17
|
+
// Message Display State
|
|
18
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
19
|
+
// AI State
|
|
20
|
+
const [messages, setMessages] = useState([]);
|
|
21
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
22
|
+
const [latestTotalTokens, setlatestTotalTokens] = useState(0);
|
|
23
|
+
const [sessionId, setSessionId] = useState("");
|
|
24
|
+
const [isCommandRunning, setIsCommandRunning] = useState(false);
|
|
25
|
+
const [isCompressing, setIsCompressing] = useState(false);
|
|
26
|
+
const [userInputHistory, setUserInputHistory] = useState([]);
|
|
27
|
+
// MCP State
|
|
28
|
+
const [mcpServers, setMcpServers] = useState([]);
|
|
29
|
+
// Background bash shells state
|
|
30
|
+
const [backgroundShells, setBackgroundShells] = useState([]);
|
|
31
|
+
// Command state
|
|
32
|
+
const [slashCommands, setSlashCommands] = useState([]);
|
|
33
|
+
const agentRef = useRef(null);
|
|
34
|
+
// Listen for Ctrl+O hotkey to toggle collapse/expand state
|
|
35
|
+
useInput((input, key) => {
|
|
36
|
+
if (key.ctrl && input === "o") {
|
|
37
|
+
setIsExpanded((prev) => !prev);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
// Initialize AI manager
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
const initializeAgent = async () => {
|
|
43
|
+
const callbacks = {
|
|
44
|
+
onMessagesChange: (newMessages) => {
|
|
45
|
+
setMessages([...newMessages]);
|
|
46
|
+
},
|
|
47
|
+
onServersChange: (servers) => {
|
|
48
|
+
setMcpServers([...servers]);
|
|
49
|
+
},
|
|
50
|
+
onSessionIdChange: (sessionId) => {
|
|
51
|
+
setSessionId(sessionId);
|
|
52
|
+
},
|
|
53
|
+
onLatestTotalTokensChange: (tokens) => {
|
|
54
|
+
setlatestTotalTokens(tokens);
|
|
55
|
+
},
|
|
56
|
+
onUserInputHistoryChange: (history) => {
|
|
57
|
+
setUserInputHistory([...history]);
|
|
58
|
+
},
|
|
59
|
+
onCompressionStateChange: (isCompressingState) => {
|
|
60
|
+
setIsCompressing(isCompressingState);
|
|
61
|
+
},
|
|
62
|
+
onShellsChange: (shells) => {
|
|
63
|
+
setBackgroundShells([...shells]);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
try {
|
|
67
|
+
const agent = await Agent.create({
|
|
68
|
+
callbacks,
|
|
69
|
+
restoreSessionId,
|
|
70
|
+
continueLastSession,
|
|
71
|
+
logger,
|
|
72
|
+
});
|
|
73
|
+
agentRef.current = agent;
|
|
74
|
+
// Get initial state
|
|
75
|
+
setSessionId(agent.sessionId);
|
|
76
|
+
setMessages(agent.messages);
|
|
77
|
+
setIsLoading(agent.isLoading);
|
|
78
|
+
setlatestTotalTokens(agent.latestTotalTokens);
|
|
79
|
+
setIsCommandRunning(agent.isCommandRunning);
|
|
80
|
+
setIsCompressing(agent.isCompressing);
|
|
81
|
+
setUserInputHistory(agent.userInputHistory);
|
|
82
|
+
// Get initial MCP servers state
|
|
83
|
+
const mcpServers = agent.getMcpServers?.() || [];
|
|
84
|
+
setMcpServers(mcpServers);
|
|
85
|
+
// Get initial commands
|
|
86
|
+
const agentSlashCommands = agent.getSlashCommands?.() || [];
|
|
87
|
+
setSlashCommands(agentSlashCommands);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
console.error("Failed to initialize AI manager:", error);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
initializeAgent();
|
|
94
|
+
}, [restoreSessionId, continueLastSession]);
|
|
95
|
+
// Cleanup on unmount
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
return () => {
|
|
98
|
+
if (agentRef.current) {
|
|
99
|
+
agentRef.current.destroy();
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}, []);
|
|
103
|
+
// Send message function (including judgment logic)
|
|
104
|
+
const sendMessage = useCallback(async (content, images) => {
|
|
105
|
+
// Check if there's content to send (text content or image attachments)
|
|
106
|
+
const hasTextContent = content.trim();
|
|
107
|
+
const hasImageAttachments = images && images.length > 0;
|
|
108
|
+
if (!hasTextContent && !hasImageAttachments)
|
|
109
|
+
return;
|
|
110
|
+
try {
|
|
111
|
+
// Handle memory mode - check if it's a memory message (starts with # and only one line)
|
|
112
|
+
if (content.startsWith("#") && !content.includes("\n")) {
|
|
113
|
+
const memoryText = content.substring(1).trim();
|
|
114
|
+
if (!memoryText)
|
|
115
|
+
return;
|
|
116
|
+
// In memory mode, don't add user message, only wait for user to choose memory type then add assistant message
|
|
117
|
+
// Don't auto-save, wait for user to choose memory type
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
// Handle bash mode - check if it's a bash command (starts with ! and only one line)
|
|
121
|
+
if (content.startsWith("!") && !content.includes("\n")) {
|
|
122
|
+
const command = content.substring(1).trim();
|
|
123
|
+
if (!command)
|
|
124
|
+
return;
|
|
125
|
+
// In bash mode, don't add user message to UI, directly execute command
|
|
126
|
+
// Executing bash command will automatically add assistant message
|
|
127
|
+
// Set command running state
|
|
128
|
+
setIsCommandRunning(true);
|
|
129
|
+
try {
|
|
130
|
+
await agentRef.current?.executeBashCommand(command);
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
// Clear command running state
|
|
134
|
+
setIsCommandRunning(false);
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// Handle normal AI message and slash commands
|
|
139
|
+
// Slash commands are now handled internally in agent.sendMessage
|
|
140
|
+
// Set loading state
|
|
141
|
+
setIsLoading(true);
|
|
142
|
+
try {
|
|
143
|
+
await agentRef.current?.sendMessage(content, images);
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
// Clear loading state
|
|
147
|
+
setIsLoading(false);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
console.error("Failed to send message:", error);
|
|
152
|
+
// Loading state will be automatically updated by the useEffect that watches messages
|
|
153
|
+
}
|
|
154
|
+
}, []);
|
|
155
|
+
// Unified interrupt method, interrupt both AI messages and command execution
|
|
156
|
+
const abortMessage = useCallback(() => {
|
|
157
|
+
agentRef.current?.abortMessage();
|
|
158
|
+
}, []);
|
|
159
|
+
// Memory save function - delegate to Agent
|
|
160
|
+
const saveMemory = useCallback(async (message, type) => {
|
|
161
|
+
await agentRef.current?.saveMemory(message, type);
|
|
162
|
+
}, []);
|
|
163
|
+
// MCP management methods - delegate to Agent
|
|
164
|
+
const connectMcpServer = useCallback(async (serverName) => {
|
|
165
|
+
return (await agentRef.current?.connectMcpServer(serverName)) ?? false;
|
|
166
|
+
}, []);
|
|
167
|
+
const disconnectMcpServer = useCallback(async (serverName) => {
|
|
168
|
+
return (await agentRef.current?.disconnectMcpServer(serverName)) ?? false;
|
|
169
|
+
}, []);
|
|
170
|
+
// Background bash management methods - delegate to Agent
|
|
171
|
+
const getBackgroundShellOutput = useCallback((shellId) => {
|
|
172
|
+
if (!agentRef.current)
|
|
173
|
+
return null;
|
|
174
|
+
return agentRef.current.getBackgroundShellOutput(shellId);
|
|
175
|
+
}, []);
|
|
176
|
+
const killBackgroundShell = useCallback((shellId) => {
|
|
177
|
+
if (!agentRef.current)
|
|
178
|
+
return false;
|
|
179
|
+
return agentRef.current.killBackgroundShell(shellId);
|
|
180
|
+
}, []);
|
|
181
|
+
const hasSlashCommand = useCallback((commandId) => {
|
|
182
|
+
if (!agentRef.current)
|
|
183
|
+
return false;
|
|
184
|
+
return agentRef.current.hasSlashCommand(commandId);
|
|
185
|
+
}, []);
|
|
186
|
+
const contextValue = {
|
|
187
|
+
messages,
|
|
188
|
+
isLoading,
|
|
189
|
+
isCommandRunning,
|
|
190
|
+
userInputHistory,
|
|
191
|
+
isExpanded,
|
|
192
|
+
sessionId,
|
|
193
|
+
sendMessage,
|
|
194
|
+
abortMessage,
|
|
195
|
+
latestTotalTokens,
|
|
196
|
+
isCompressing,
|
|
197
|
+
saveMemory,
|
|
198
|
+
mcpServers,
|
|
199
|
+
connectMcpServer,
|
|
200
|
+
disconnectMcpServer,
|
|
201
|
+
backgroundShells,
|
|
202
|
+
getBackgroundShellOutput,
|
|
203
|
+
killBackgroundShell,
|
|
204
|
+
slashCommands,
|
|
205
|
+
hasSlashCommand,
|
|
206
|
+
};
|
|
207
|
+
return (_jsx(ChatContext.Provider, { value: contextValue, children: children }));
|
|
208
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const useBashHistorySelector: () => {
|
|
2
|
+
showBashHistorySelector: boolean;
|
|
3
|
+
bashHistorySearchQuery: string;
|
|
4
|
+
activateBashHistorySelector: (position: number) => void;
|
|
5
|
+
handleBashHistorySelect: (command: string, inputText: string, cursorPosition: number) => {
|
|
6
|
+
newInput: string;
|
|
7
|
+
newCursorPosition: number;
|
|
8
|
+
};
|
|
9
|
+
handleBashHistoryExecute: (command: string) => string;
|
|
10
|
+
handleCancelBashHistorySelect: () => void;
|
|
11
|
+
updateBashHistorySearchQuery: (query: string) => void;
|
|
12
|
+
checkForExclamationDeletion: (cursorPosition: number) => boolean;
|
|
13
|
+
exclamationPosition: number;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=useBashHistorySelector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBashHistorySelector.d.ts","sourceRoot":"","sources":["../../src/hooks/useBashHistorySelector.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,sBAAsB;;;4CAK0B,MAAM;uCAOrD,MAAM,aAAa,MAAM,kBAAkB,MAAM;;;;wCAyBN,MAAM;;0CAOJ,MAAM;kDAK5C,MAAM;;CAyB1B,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useState, useCallback } from "react";
|
|
2
|
+
export const useBashHistorySelector = () => {
|
|
3
|
+
const [showBashHistorySelector, setShowBashHistorySelector] = useState(false);
|
|
4
|
+
const [exclamationPosition, setExclamationPosition] = useState(-1);
|
|
5
|
+
const [bashHistorySearchQuery, setBashHistorySearchQuery] = useState("");
|
|
6
|
+
const activateBashHistorySelector = useCallback((position) => {
|
|
7
|
+
setShowBashHistorySelector(true);
|
|
8
|
+
setExclamationPosition(position);
|
|
9
|
+
setBashHistorySearchQuery("");
|
|
10
|
+
}, []);
|
|
11
|
+
const handleBashHistorySelect = useCallback((command, inputText, cursorPosition) => {
|
|
12
|
+
if (exclamationPosition >= 0) {
|
|
13
|
+
// Replace ! and search query with selected command
|
|
14
|
+
const beforeExclamation = inputText.substring(0, exclamationPosition);
|
|
15
|
+
const afterQuery = inputText.substring(cursorPosition);
|
|
16
|
+
const newInput = beforeExclamation + `!${command}` + afterQuery;
|
|
17
|
+
const newCursorPosition = beforeExclamation.length + command.length + 1;
|
|
18
|
+
setShowBashHistorySelector(false);
|
|
19
|
+
setExclamationPosition(-1);
|
|
20
|
+
setBashHistorySearchQuery("");
|
|
21
|
+
return { newInput, newCursorPosition };
|
|
22
|
+
}
|
|
23
|
+
return { newInput: inputText, newCursorPosition: cursorPosition };
|
|
24
|
+
}, [exclamationPosition]);
|
|
25
|
+
const handleCancelBashHistorySelect = useCallback(() => {
|
|
26
|
+
setShowBashHistorySelector(false);
|
|
27
|
+
setExclamationPosition(-1);
|
|
28
|
+
setBashHistorySearchQuery("");
|
|
29
|
+
}, []);
|
|
30
|
+
const handleBashHistoryExecute = useCallback((command) => {
|
|
31
|
+
setShowBashHistorySelector(false);
|
|
32
|
+
setExclamationPosition(-1);
|
|
33
|
+
setBashHistorySearchQuery("");
|
|
34
|
+
return command; // Return command to execute
|
|
35
|
+
}, []);
|
|
36
|
+
const updateBashHistorySearchQuery = useCallback((query) => {
|
|
37
|
+
setBashHistorySearchQuery(query);
|
|
38
|
+
}, []);
|
|
39
|
+
const checkForExclamationDeletion = useCallback((cursorPosition) => {
|
|
40
|
+
if (showBashHistorySelector && cursorPosition <= exclamationPosition) {
|
|
41
|
+
handleCancelBashHistorySelect();
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}, [
|
|
46
|
+
showBashHistorySelector,
|
|
47
|
+
exclamationPosition,
|
|
48
|
+
handleCancelBashHistorySelect,
|
|
49
|
+
]);
|
|
50
|
+
return {
|
|
51
|
+
showBashHistorySelector,
|
|
52
|
+
bashHistorySearchQuery,
|
|
53
|
+
activateBashHistorySelector,
|
|
54
|
+
handleBashHistorySelect,
|
|
55
|
+
handleBashHistoryExecute,
|
|
56
|
+
handleCancelBashHistorySelect,
|
|
57
|
+
updateBashHistorySearchQuery,
|
|
58
|
+
checkForExclamationDeletion,
|
|
59
|
+
exclamationPosition,
|
|
60
|
+
};
|
|
61
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface UseCommandSelectorParams {
|
|
2
|
+
onShowBashManager?: () => void;
|
|
3
|
+
onShowMcpManager?: () => void;
|
|
4
|
+
sendMessage?: (content: string) => Promise<void>;
|
|
5
|
+
hasSlashCommand?: (commandId: string) => boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const useCommandSelector: ({ onShowBashManager, onShowMcpManager, sendMessage, hasSlashCommand, }: UseCommandSelectorParams) => {
|
|
8
|
+
showCommandSelector: boolean;
|
|
9
|
+
commandSearchQuery: string;
|
|
10
|
+
activateCommandSelector: (position: number) => void;
|
|
11
|
+
handleCommandSelect: (command: string, inputText: string, cursorPosition: number) => {
|
|
12
|
+
newInput: string;
|
|
13
|
+
newCursorPosition: number;
|
|
14
|
+
};
|
|
15
|
+
handleCommandInsert: (command: string, inputText: string, cursorPosition: number) => {
|
|
16
|
+
newInput: string;
|
|
17
|
+
newCursorPosition: number;
|
|
18
|
+
};
|
|
19
|
+
handleCancelCommandSelect: () => void;
|
|
20
|
+
updateCommandSearchQuery: (query: string) => void;
|
|
21
|
+
checkForSlashDeletion: (cursorPosition: number) => boolean;
|
|
22
|
+
slashPosition: number;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=useCommandSelector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCommandSelector.d.ts","sourceRoot":"","sources":["../../src/hooks/useCommandSelector.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,wBAAwB;IACvC,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAClD;AAED,eAAO,MAAM,kBAAkB,GAAI,wEAKhC,wBAAwB;;;wCAK8B,MAAM;mCA2BjD,MAAM,aAAa,MAAM,kBAAkB,MAAM;;;;mCApBjD,MAAM,aAAa,MAAM,kBAAkB,MAAM;;;;;sCA8ER,MAAM;4CAKxC,MAAM;;CAqB1B,CAAC"}
|