wave-code 0.0.6 → 0.0.10
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 +1 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/components/App.d.ts +1 -0
- package/dist/components/App.d.ts.map +1 -1
- package/dist/components/App.js +4 -4
- package/dist/components/BashHistorySelector.d.ts.map +1 -1
- package/dist/components/BashHistorySelector.js +17 -3
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +4 -2
- package/dist/components/Confirmation.d.ts +13 -0
- package/dist/components/Confirmation.d.ts.map +1 -0
- package/dist/components/Confirmation.js +172 -0
- package/dist/components/DiffDisplay.d.ts +8 -0
- package/dist/components/DiffDisplay.d.ts.map +1 -0
- package/dist/components/DiffDisplay.js +168 -0
- package/dist/components/FileSelector.d.ts +2 -4
- package/dist/components/FileSelector.d.ts.map +1 -1
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +10 -1
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/Markdown.js +115 -16
- package/dist/components/MemoryDisplay.js +1 -1
- package/dist/components/MessageItem.d.ts +1 -2
- package/dist/components/MessageItem.d.ts.map +1 -1
- package/dist/components/MessageItem.js +3 -3
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +2 -2
- package/dist/components/ReasoningDisplay.d.ts +8 -0
- package/dist/components/ReasoningDisplay.d.ts.map +1 -0
- package/dist/components/ReasoningDisplay.js +10 -0
- package/dist/components/ToolResultDisplay.d.ts.map +1 -1
- package/dist/components/ToolResultDisplay.js +2 -1
- package/dist/contexts/useChat.d.ts +15 -1
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +124 -15
- package/dist/hooks/useInputManager.d.ts +3 -0
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -4
- package/dist/managers/InputManager.d.ts +8 -0
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +33 -2
- package/dist/print-cli.d.ts +1 -0
- package/dist/print-cli.d.ts.map +1 -1
- package/dist/print-cli.js +36 -3
- package/dist/utils/toolParameterTransforms.d.ts +23 -0
- package/dist/utils/toolParameterTransforms.d.ts.map +1 -0
- package/dist/utils/toolParameterTransforms.js +77 -0
- package/package.json +10 -8
- package/src/cli.tsx +3 -1
- package/src/components/App.tsx +7 -3
- package/src/components/BashHistorySelector.tsx +26 -3
- package/src/components/ChatInterface.tsx +31 -15
- package/src/components/Confirmation.tsx +286 -0
- package/src/components/DiffDisplay.tsx +300 -0
- package/src/components/FileSelector.tsx +2 -4
- package/src/components/InputBox.tsx +37 -14
- package/src/components/Markdown.tsx +329 -16
- package/src/components/MemoryDisplay.tsx +1 -1
- package/src/components/MessageItem.tsx +4 -12
- package/src/components/MessageList.tsx +0 -2
- package/src/components/ReasoningDisplay.tsx +33 -0
- package/src/components/ToolResultDisplay.tsx +4 -0
- package/src/contexts/useChat.tsx +206 -14
- package/src/hooks/useInputManager.ts +19 -0
- package/src/index.ts +34 -4
- package/src/managers/InputManager.ts +46 -2
- package/src/print-cli.ts +42 -2
- package/src/utils/toolParameterTransforms.ts +104 -0
- package/dist/components/DiffViewer.d.ts +0 -9
- package/dist/components/DiffViewer.d.ts.map +0 -1
- package/dist/components/DiffViewer.js +0 -221
- package/dist/utils/fileSearch.d.ts +0 -20
- package/dist/utils/fileSearch.d.ts.map +0 -1
- package/dist/utils/fileSearch.js +0 -102
- package/src/components/DiffViewer.tsx +0 -323
- package/src/utils/fileSearch.ts +0 -133
|
@@ -1,22 +1,121 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React, { useMemo } from "react";
|
|
3
|
-
import { Text } from "ink";
|
|
3
|
+
import { Box, Text, useStdout } from "ink";
|
|
4
4
|
import { marked } from "marked";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
const unescapeHtml = (html) => {
|
|
6
|
+
return html
|
|
7
|
+
.replace(/&/g, "&")
|
|
8
|
+
.replace(/</g, "<")
|
|
9
|
+
.replace(/>/g, ">")
|
|
10
|
+
.replace(/"/g, '"')
|
|
11
|
+
.replace(/'/g, "'");
|
|
12
|
+
};
|
|
13
|
+
const InlineRenderer = ({ tokens }) => {
|
|
14
|
+
return (_jsx(_Fragment, { children: tokens.map((token, index) => {
|
|
15
|
+
switch (token.type) {
|
|
16
|
+
case "text": {
|
|
17
|
+
const t = token;
|
|
18
|
+
if (t.tokens) {
|
|
19
|
+
return _jsx(InlineRenderer, { tokens: t.tokens }, index);
|
|
20
|
+
}
|
|
21
|
+
return _jsx(Text, { children: unescapeHtml(t.text) }, index);
|
|
22
|
+
}
|
|
23
|
+
case "strong":
|
|
24
|
+
return (_jsx(Text, { bold: true, children: token.tokens ? (_jsx(InlineRenderer, { tokens: token.tokens })) : (unescapeHtml(token.text)) }, index));
|
|
25
|
+
case "em":
|
|
26
|
+
return (_jsx(Text, { italic: true, children: token.tokens ? (_jsx(InlineRenderer, { tokens: token.tokens })) : (unescapeHtml(token.text)) }, index));
|
|
27
|
+
case "codespan":
|
|
28
|
+
return (_jsx(Text, { color: "yellow", children: unescapeHtml(token.text) }, index));
|
|
29
|
+
case "link":
|
|
30
|
+
return (_jsx(Text, { color: "blue", underline: true, children: token.tokens ? (_jsx(InlineRenderer, { tokens: token.tokens })) : (unescapeHtml(token.text)) }, index));
|
|
31
|
+
case "br":
|
|
32
|
+
return _jsx(Text, { children: "\n" }, index);
|
|
33
|
+
case "del":
|
|
34
|
+
return (_jsx(Text, { strikethrough: true, children: token.tokens ? (_jsx(InlineRenderer, { tokens: token.tokens })) : (unescapeHtml(token.text)) }, index));
|
|
35
|
+
default:
|
|
36
|
+
return _jsx(Text, { children: token.raw }, index);
|
|
37
|
+
}
|
|
38
|
+
}) }));
|
|
39
|
+
};
|
|
40
|
+
const TableRenderer = ({ token }) => {
|
|
41
|
+
const { stdout } = useStdout();
|
|
42
|
+
const terminalWidth = (stdout?.columns || 80) - 2;
|
|
43
|
+
const columnWidths = useMemo(() => {
|
|
44
|
+
const numCols = token.header.length;
|
|
45
|
+
const minWidth = 5;
|
|
46
|
+
const maxColWidth = 40;
|
|
47
|
+
const widths = token.header.map((h) => Math.min(maxColWidth, Math.max(minWidth, h.text.length)));
|
|
48
|
+
token.rows.forEach((row) => {
|
|
49
|
+
row.forEach((cell, i) => {
|
|
50
|
+
widths[i] = Math.min(maxColWidth, Math.max(widths[i] || minWidth, cell.text.length));
|
|
51
|
+
});
|
|
15
52
|
});
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
53
|
+
const paddedWidths = widths.map((w) => w + 2);
|
|
54
|
+
const totalWidth = paddedWidths.reduce((a, b) => a + b, 0) + numCols + 1;
|
|
55
|
+
if (totalWidth <= terminalWidth) {
|
|
56
|
+
return paddedWidths;
|
|
57
|
+
}
|
|
58
|
+
// If table is too wide, scale down columns proportionally
|
|
59
|
+
const availableWidth = terminalWidth - numCols - 1;
|
|
60
|
+
const scaleFactor = availableWidth / (totalWidth - numCols - 1);
|
|
61
|
+
return paddedWidths.map((w) => Math.max(minWidth, Math.floor(w * scaleFactor)));
|
|
62
|
+
}, [token, terminalWidth]);
|
|
63
|
+
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)))] }));
|
|
64
|
+
};
|
|
65
|
+
const BlockRenderer = ({ tokens }) => {
|
|
66
|
+
return (_jsx(_Fragment, { children: tokens.map((token, index) => {
|
|
67
|
+
switch (token.type) {
|
|
68
|
+
case "heading": {
|
|
69
|
+
const t = token;
|
|
70
|
+
return (_jsx(Box, { marginBottom: 1, flexDirection: "column", children: _jsxs(Text, { bold: true, color: "cyan", children: ["#".repeat(t.depth), " ", _jsx(InlineRenderer, { tokens: t.tokens })] }) }, index));
|
|
71
|
+
}
|
|
72
|
+
case "paragraph": {
|
|
73
|
+
const t = token;
|
|
74
|
+
return (_jsx(Box, { marginBottom: 1, flexDirection: "row", flexWrap: "wrap", children: _jsx(InlineRenderer, { tokens: t.tokens }) }, index));
|
|
75
|
+
}
|
|
76
|
+
case "code": {
|
|
77
|
+
const t = token;
|
|
78
|
+
if (t.lang !== undefined) {
|
|
79
|
+
const lines = token.raw.replace(/\n$/, "").split("\n");
|
|
80
|
+
const opening = lines[0];
|
|
81
|
+
const closing = lines[lines.length - 1];
|
|
82
|
+
const content = lines.slice(1, -1).join("\n");
|
|
83
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [_jsx(Text, { color: "gray", children: opening }), content && _jsx(Text, { children: content }), _jsx(Text, { color: "gray", children: closing })] }, index));
|
|
84
|
+
}
|
|
85
|
+
return (_jsx(Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: _jsx(Text, { children: t.text }) }, index));
|
|
86
|
+
}
|
|
87
|
+
case "list": {
|
|
88
|
+
const t = token;
|
|
89
|
+
return (_jsx(Box, { flexDirection: "column", marginBottom: 1, paddingLeft: 2, children: t.items.map((item, i) => {
|
|
90
|
+
const start = t.start || 1;
|
|
91
|
+
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) => {
|
|
92
|
+
if (itemToken.type === "text") {
|
|
93
|
+
const it = itemToken;
|
|
94
|
+
return (_jsx(Box, { flexDirection: "row", flexWrap: "wrap", children: _jsx(InlineRenderer, { tokens: it.tokens || [itemToken] }) }, itemIndex));
|
|
95
|
+
}
|
|
96
|
+
return (_jsx(BlockRenderer, { tokens: [itemToken] }, itemIndex));
|
|
97
|
+
}) })] }, i));
|
|
98
|
+
}) }, index));
|
|
99
|
+
}
|
|
100
|
+
case "blockquote": {
|
|
101
|
+
const t = token;
|
|
102
|
+
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));
|
|
103
|
+
}
|
|
104
|
+
case "hr":
|
|
105
|
+
return (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "gray", children: "─".repeat(20) }) }, index));
|
|
106
|
+
case "table":
|
|
107
|
+
return _jsx(TableRenderer, { token: token }, index);
|
|
108
|
+
case "space":
|
|
109
|
+
return null;
|
|
110
|
+
default:
|
|
111
|
+
return (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: token.raw }) }, index));
|
|
112
|
+
}
|
|
113
|
+
}) }));
|
|
114
|
+
};
|
|
115
|
+
// Markdown component using custom Ink-based renderer
|
|
116
|
+
export const Markdown = React.memo(({ children }) => {
|
|
117
|
+
const tokens = useMemo(() => marked.lexer(children), [children]);
|
|
118
|
+
return (_jsx(Box, { flexDirection: "column", children: _jsx(BlockRenderer, { tokens: tokens }) }));
|
|
20
119
|
});
|
|
21
120
|
// Add display name for debugging
|
|
22
121
|
Markdown.displayName = "Markdown";
|
|
@@ -15,7 +15,7 @@ export const MemoryDisplay = ({ block }) => {
|
|
|
15
15
|
if (!isSuccess)
|
|
16
16
|
return null;
|
|
17
17
|
if (memoryType === "user") {
|
|
18
|
-
return `Memory saved to ${storagePath || "
|
|
18
|
+
return `Memory saved to ${storagePath || "AGENTS.md"}`;
|
|
19
19
|
}
|
|
20
20
|
else {
|
|
21
21
|
return `Memory saved to ${storagePath || "AGENTS.md"}`;
|
|
@@ -3,7 +3,6 @@ export interface MessageItemProps {
|
|
|
3
3
|
message: Message;
|
|
4
4
|
isExpanded: boolean;
|
|
5
5
|
shouldShowHeader: boolean;
|
|
6
|
-
isStatic?: boolean;
|
|
7
6
|
}
|
|
8
|
-
export declare const MessageItem: ({ message, isExpanded, shouldShowHeader,
|
|
7
|
+
export declare const MessageItem: ({ message, isExpanded, shouldShowHeader, }: MessageItemProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
9
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;
|
|
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,15 +1,15 @@
|
|
|
1
1
|
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
|
-
import { DiffViewer } from "./DiffViewer.js";
|
|
5
4
|
import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
|
|
6
5
|
import { ToolResultDisplay } from "./ToolResultDisplay.js";
|
|
7
6
|
import { MemoryDisplay } from "./MemoryDisplay.js";
|
|
8
7
|
import { CompressDisplay } from "./CompressDisplay.js";
|
|
9
8
|
import { SubagentBlock } from "./SubagentBlock.js";
|
|
9
|
+
import { ReasoningDisplay } from "./ReasoningDisplay.js";
|
|
10
10
|
import { Markdown } from "./Markdown.js";
|
|
11
|
-
export const MessageItem = ({ message, isExpanded, shouldShowHeader,
|
|
11
|
+
export const MessageItem = ({ message, isExpanded, shouldShowHeader, }) => {
|
|
12
12
|
if (message.blocks.length === 0)
|
|
13
13
|
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", " "] })),
|
|
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))) })] }));
|
|
15
15
|
};
|
|
@@ -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,
|
|
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"}
|
|
@@ -27,11 +27,11 @@ export const MessageList = React.memo(({ messages, isLoading = false, isCommandR
|
|
|
27
27
|
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, 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) => {
|
|
28
28
|
// Get previous message
|
|
29
29
|
const previousMessage = key > 0 ? staticMessages[key - 1] : undefined;
|
|
30
|
-
return (_jsx(MessageItem, { message: message, shouldShowHeader: previousMessage?.role !== message.role, isExpanded: isExpanded
|
|
30
|
+
return (_jsx(MessageItem, { message: message, shouldShowHeader: previousMessage?.role !== message.role, isExpanded: isExpanded }, key));
|
|
31
31
|
} }), dynamicMessages.map((message, index) => {
|
|
32
32
|
const messageIndex = staticMessages.length + index;
|
|
33
33
|
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
|
|
34
|
+
return (_jsx(Box, { marginTop: -1, children: _jsx(MessageItem, { message: message, shouldShowHeader: previousMessage?.role !== message.role, isExpanded: isExpanded }) }, `dynamic-${index}`));
|
|
35
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"] })] }) }))] }));
|
|
36
36
|
});
|
|
37
37
|
// Add display name for debugging
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { ReasoningBlock } from "wave-agent-sdk";
|
|
3
|
+
interface ReasoningDisplayProps {
|
|
4
|
+
block: ReasoningBlock;
|
|
5
|
+
}
|
|
6
|
+
export declare const ReasoningDisplay: React.FC<ReasoningDisplayProps>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=ReasoningDisplay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReasoningDisplay.d.ts","sourceRoot":"","sources":["../../src/components/ReasoningDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD,UAAU,qBAAqB;IAC7B,KAAK,EAAE,cAAc,CAAC;CACvB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAuB5D,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box } from "ink";
|
|
3
|
+
import { Markdown } from "./Markdown.js";
|
|
4
|
+
export const ReasoningDisplay = ({ block, }) => {
|
|
5
|
+
const { content } = block;
|
|
6
|
+
if (!content || !content.trim()) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
return (_jsx(Box, { borderRight: false, borderTop: false, borderBottom: false, borderStyle: "classic", borderColor: "blue", paddingLeft: 1, children: _jsx(Box, { flexDirection: "column", children: _jsx(Markdown, { children: content }) }) }));
|
|
10
|
+
};
|
|
@@ -1 +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;
|
|
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;AAGhD,UAAU,sBAAsB;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAmI9D,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
+
import { DiffDisplay } from "./DiffDisplay.js";
|
|
3
4
|
export const ToolResultDisplay = ({ block, isExpanded = false, }) => {
|
|
4
5
|
const { parameters, result, compactParams, stage, success, error, name } = block;
|
|
5
6
|
// Directly use compactParams
|
|
@@ -48,5 +49,5 @@ export const ToolResultDisplay = ({ block, isExpanded = false, }) => {
|
|
|
48
49
|
return null;
|
|
49
50
|
};
|
|
50
51
|
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 && !error && (_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
|
+
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 && !error && (_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)] }) })), _jsx(DiffDisplay, { toolBlock: block })] }));
|
|
52
53
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import type { Message, McpServerStatus, BackgroundShell, SlashCommand } from "wave-agent-sdk";
|
|
2
|
+
import type { Message, McpServerStatus, BackgroundShell, SlashCommand, PermissionDecision, PermissionMode } from "wave-agent-sdk";
|
|
3
3
|
export interface ChatContextType {
|
|
4
4
|
messages: Message[];
|
|
5
5
|
isLoading: boolean;
|
|
@@ -28,10 +28,24 @@ export interface ChatContextType {
|
|
|
28
28
|
slashCommands: SlashCommand[];
|
|
29
29
|
hasSlashCommand: (commandId: string) => boolean;
|
|
30
30
|
subagentMessages: Record<string, Message[]>;
|
|
31
|
+
permissionMode: PermissionMode;
|
|
32
|
+
setPermissionMode: (mode: PermissionMode) => void;
|
|
33
|
+
isConfirmationVisible: boolean;
|
|
34
|
+
confirmingTool?: {
|
|
35
|
+
name: string;
|
|
36
|
+
input?: Record<string, unknown>;
|
|
37
|
+
suggestedPrefix?: string;
|
|
38
|
+
hidePersistentOption?: boolean;
|
|
39
|
+
};
|
|
40
|
+
showConfirmation: (toolName: string, toolInput?: Record<string, unknown>, suggestedPrefix?: string, hidePersistentOption?: boolean) => Promise<PermissionDecision>;
|
|
41
|
+
hideConfirmation: () => void;
|
|
42
|
+
handleConfirmationDecision: (decision: PermissionDecision) => void;
|
|
43
|
+
handleConfirmationCancel: () => void;
|
|
31
44
|
}
|
|
32
45
|
export declare const useChat: () => ChatContextType;
|
|
33
46
|
export interface ChatProviderProps {
|
|
34
47
|
children: React.ReactNode;
|
|
48
|
+
bypassPermissions?: boolean;
|
|
35
49
|
}
|
|
36
50
|
export declare const ChatProvider: React.FC<ChatProviderProps>;
|
|
37
51
|
//# sourceMappingURL=useChat.d.ts.map
|
|
@@ -1 +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,
|
|
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,EACZ,kBAAkB,EAClB,cAAc,EACf,MAAM,gBAAgB,CAAC;AAUxB,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;IAEhD,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAE5C,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAElD,qBAAqB,EAAE,OAAO,CAAC;IAC/B,cAAc,CAAC,EAAE;QACf,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC,CAAC;IACF,gBAAgB,EAAE,CAChB,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,eAAe,CAAC,EAAE,MAAM,EACxB,oBAAoB,CAAC,EAAE,OAAO,KAC3B,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjC,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,0BAA0B,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACnE,wBAAwB,EAAE,MAAM,IAAI,CAAC;CACtC;AAID,eAAO,MAAM,OAAO,uBAMnB,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA0apD,CAAC"}
|
package/dist/contexts/useChat.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { createContext, useContext, useCallback, useRef, useEffect, useState, } from "react";
|
|
3
3
|
import { useInput } from "ink";
|
|
4
4
|
import { useAppConfig } from "./useAppConfig.js";
|
|
5
|
-
import { Agent } from "wave-agent-sdk";
|
|
5
|
+
import { Agent, } from "wave-agent-sdk";
|
|
6
6
|
import { logger } from "../utils/logger.js";
|
|
7
7
|
import { displayUsageSummary } from "../utils/usageSummary.js";
|
|
8
8
|
const ChatContext = createContext(null);
|
|
@@ -13,7 +13,7 @@ export const useChat = () => {
|
|
|
13
13
|
}
|
|
14
14
|
return context;
|
|
15
15
|
};
|
|
16
|
-
export const ChatProvider = ({ children }) => {
|
|
16
|
+
export const ChatProvider = ({ children, bypassPermissions, }) => {
|
|
17
17
|
const { restoreSessionId, continueLastSession } = useAppConfig();
|
|
18
18
|
// Message Display State
|
|
19
19
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
@@ -33,19 +33,29 @@ export const ChatProvider = ({ children }) => {
|
|
|
33
33
|
const [slashCommands, setSlashCommands] = useState([]);
|
|
34
34
|
// Subagent messages state
|
|
35
35
|
const [subagentMessages, setSubagentMessages] = useState({});
|
|
36
|
+
// Permission state
|
|
37
|
+
const [permissionMode, setPermissionModeState] = useState("default");
|
|
38
|
+
// Confirmation state with queue-based architecture
|
|
39
|
+
const [isConfirmationVisible, setIsConfirmationVisible] = useState(false);
|
|
40
|
+
const [confirmingTool, setConfirmingTool] = useState();
|
|
41
|
+
const [confirmationQueue, setConfirmationQueue] = useState([]);
|
|
42
|
+
const [currentConfirmation, setCurrentConfirmation] = useState(null);
|
|
36
43
|
const agentRef = useRef(null);
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
// Permission confirmation methods with queue support
|
|
45
|
+
const showConfirmation = useCallback(async (toolName, toolInput, suggestedPrefix, hidePersistentOption) => {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
const queueItem = {
|
|
48
|
+
toolName,
|
|
49
|
+
toolInput,
|
|
50
|
+
suggestedPrefix,
|
|
51
|
+
hidePersistentOption,
|
|
52
|
+
resolver: resolve,
|
|
53
|
+
reject,
|
|
54
|
+
};
|
|
55
|
+
setConfirmationQueue((prev) => [...prev, queueItem]);
|
|
56
|
+
// processNextConfirmation will be called via useEffect
|
|
57
|
+
});
|
|
58
|
+
}, []);
|
|
49
59
|
// Initialize AI manager
|
|
50
60
|
useEffect(() => {
|
|
51
61
|
const initializeAgent = async () => {
|
|
@@ -74,18 +84,40 @@ export const ChatProvider = ({ children }) => {
|
|
|
74
84
|
setBackgroundShells([...shells]);
|
|
75
85
|
},
|
|
76
86
|
onSubagentMessagesChange: (subagentId, messages) => {
|
|
87
|
+
logger.debug("onSubagentMessagesChange", subagentId, messages.length);
|
|
77
88
|
setSubagentMessages((prev) => ({
|
|
78
89
|
...prev,
|
|
79
90
|
[subagentId]: [...messages],
|
|
80
91
|
}));
|
|
81
92
|
},
|
|
93
|
+
onPermissionModeChange: (mode) => {
|
|
94
|
+
setPermissionModeState(mode);
|
|
95
|
+
},
|
|
82
96
|
};
|
|
83
97
|
try {
|
|
98
|
+
// Create the permission callback inside the try block to access showConfirmation
|
|
99
|
+
const permissionCallback = bypassPermissions
|
|
100
|
+
? undefined
|
|
101
|
+
: async (context) => {
|
|
102
|
+
try {
|
|
103
|
+
return await showConfirmation(context.toolName, context.toolInput, context.suggestedPrefix, context.hidePersistentOption);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// If confirmation was cancelled or failed, deny the operation
|
|
107
|
+
return {
|
|
108
|
+
behavior: "deny",
|
|
109
|
+
message: "Operation cancelled by user",
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
};
|
|
84
113
|
const agent = await Agent.create({
|
|
85
114
|
callbacks,
|
|
86
115
|
restoreSessionId,
|
|
87
116
|
continueLastSession,
|
|
88
117
|
logger,
|
|
118
|
+
permissionMode: bypassPermissions ? "bypassPermissions" : undefined,
|
|
119
|
+
canUseTool: permissionCallback,
|
|
120
|
+
stream: false, // 关闭流式模式
|
|
89
121
|
});
|
|
90
122
|
agentRef.current = agent;
|
|
91
123
|
// Get initial state
|
|
@@ -96,6 +128,7 @@ export const ChatProvider = ({ children }) => {
|
|
|
96
128
|
setIsCommandRunning(agent.isCommandRunning);
|
|
97
129
|
setIsCompressing(agent.isCompressing);
|
|
98
130
|
setUserInputHistory(agent.userInputHistory);
|
|
131
|
+
setPermissionModeState(agent.getPermissionMode());
|
|
99
132
|
// Get initial MCP servers state
|
|
100
133
|
const mcpServers = agent.getMcpServers?.() || [];
|
|
101
134
|
setMcpServers(mcpServers);
|
|
@@ -108,7 +141,12 @@ export const ChatProvider = ({ children }) => {
|
|
|
108
141
|
}
|
|
109
142
|
};
|
|
110
143
|
initializeAgent();
|
|
111
|
-
}, [
|
|
144
|
+
}, [
|
|
145
|
+
restoreSessionId,
|
|
146
|
+
continueLastSession,
|
|
147
|
+
bypassPermissions,
|
|
148
|
+
showConfirmation,
|
|
149
|
+
]);
|
|
112
150
|
// Cleanup on unmount
|
|
113
151
|
useEffect(() => {
|
|
114
152
|
return () => {
|
|
@@ -186,6 +224,17 @@ export const ChatProvider = ({ children }) => {
|
|
|
186
224
|
const saveMemory = useCallback(async (message, type) => {
|
|
187
225
|
await agentRef.current?.saveMemory(message, type);
|
|
188
226
|
}, []);
|
|
227
|
+
// Permission management methods
|
|
228
|
+
const setPermissionMode = useCallback((mode) => {
|
|
229
|
+
setPermissionModeState((prev) => {
|
|
230
|
+
if (prev === mode)
|
|
231
|
+
return prev;
|
|
232
|
+
if (agentRef.current && agentRef.current.getPermissionMode() !== mode) {
|
|
233
|
+
agentRef.current.setPermissionMode(mode);
|
|
234
|
+
}
|
|
235
|
+
return mode;
|
|
236
|
+
});
|
|
237
|
+
}, []);
|
|
189
238
|
// MCP management methods - delegate to Agent
|
|
190
239
|
const connectMcpServer = useCallback(async (serverName) => {
|
|
191
240
|
return (await agentRef.current?.connectMcpServer(serverName)) ?? false;
|
|
@@ -209,6 +258,58 @@ export const ChatProvider = ({ children }) => {
|
|
|
209
258
|
return false;
|
|
210
259
|
return agentRef.current.hasSlashCommand(commandId);
|
|
211
260
|
}, []);
|
|
261
|
+
// Queue processing helper
|
|
262
|
+
const processNextConfirmation = useCallback(() => {
|
|
263
|
+
if (confirmationQueue.length > 0 && !isConfirmationVisible) {
|
|
264
|
+
const next = confirmationQueue[0];
|
|
265
|
+
setCurrentConfirmation(next);
|
|
266
|
+
setConfirmingTool({
|
|
267
|
+
name: next.toolName,
|
|
268
|
+
input: next.toolInput,
|
|
269
|
+
suggestedPrefix: next.suggestedPrefix,
|
|
270
|
+
hidePersistentOption: next.hidePersistentOption,
|
|
271
|
+
});
|
|
272
|
+
setIsConfirmationVisible(true);
|
|
273
|
+
setConfirmationQueue((prev) => prev.slice(1));
|
|
274
|
+
}
|
|
275
|
+
}, [confirmationQueue, isConfirmationVisible]);
|
|
276
|
+
// Process queue when queue changes or confirmation is hidden
|
|
277
|
+
useEffect(() => {
|
|
278
|
+
processNextConfirmation();
|
|
279
|
+
}, [processNextConfirmation]);
|
|
280
|
+
const hideConfirmation = useCallback(() => {
|
|
281
|
+
setIsConfirmationVisible(false);
|
|
282
|
+
setConfirmingTool(undefined);
|
|
283
|
+
setCurrentConfirmation(null);
|
|
284
|
+
}, []);
|
|
285
|
+
const handleConfirmationDecision = useCallback((decision) => {
|
|
286
|
+
if (currentConfirmation) {
|
|
287
|
+
currentConfirmation.resolver(decision);
|
|
288
|
+
}
|
|
289
|
+
hideConfirmation();
|
|
290
|
+
}, [currentConfirmation, hideConfirmation]);
|
|
291
|
+
const handleConfirmationCancel = useCallback(() => {
|
|
292
|
+
if (currentConfirmation) {
|
|
293
|
+
currentConfirmation.reject();
|
|
294
|
+
}
|
|
295
|
+
hideConfirmation();
|
|
296
|
+
}, [currentConfirmation, hideConfirmation]);
|
|
297
|
+
// Listen for Ctrl+O hotkey to toggle collapse/expand state and ESC to cancel confirmation
|
|
298
|
+
useInput((input, key) => {
|
|
299
|
+
if (key.ctrl && input === "o") {
|
|
300
|
+
// Clear terminal screen when expanded state changes
|
|
301
|
+
process.stdout.write("\x1Bc", () => {
|
|
302
|
+
setIsExpanded((prev) => {
|
|
303
|
+
const newExpanded = !prev;
|
|
304
|
+
return newExpanded;
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
// Handle ESC key to cancel confirmation
|
|
309
|
+
if (key.escape && isConfirmationVisible) {
|
|
310
|
+
handleConfirmationCancel();
|
|
311
|
+
}
|
|
312
|
+
});
|
|
212
313
|
const contextValue = {
|
|
213
314
|
messages,
|
|
214
315
|
isLoading,
|
|
@@ -230,6 +331,14 @@ export const ChatProvider = ({ children }) => {
|
|
|
230
331
|
slashCommands,
|
|
231
332
|
hasSlashCommand,
|
|
232
333
|
subagentMessages,
|
|
334
|
+
permissionMode,
|
|
335
|
+
setPermissionMode,
|
|
336
|
+
isConfirmationVisible,
|
|
337
|
+
confirmingTool,
|
|
338
|
+
showConfirmation,
|
|
339
|
+
hideConfirmation,
|
|
340
|
+
handleConfirmationDecision,
|
|
341
|
+
handleConfirmationCancel,
|
|
233
342
|
};
|
|
234
343
|
return (_jsx(ChatContext.Provider, { value: contextValue, children: children }));
|
|
235
344
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Key } from "ink";
|
|
2
2
|
import { InputManager, InputManagerCallbacks, AttachedImage } from "../managers/InputManager.js";
|
|
3
3
|
import { FileItem } from "../components/FileSelector.js";
|
|
4
|
+
import { PermissionMode } from "wave-agent-sdk";
|
|
4
5
|
export declare const useInputManager: (callbacks?: Partial<InputManagerCallbacks>) => {
|
|
5
6
|
inputText: string;
|
|
6
7
|
cursorPosition: number;
|
|
@@ -18,6 +19,7 @@ export declare const useInputManager: (callbacks?: Partial<InputManagerCallbacks
|
|
|
18
19
|
memoryMessage: string;
|
|
19
20
|
showBashManager: boolean;
|
|
20
21
|
showMcpManager: boolean;
|
|
22
|
+
permissionMode: PermissionMode;
|
|
21
23
|
attachedImages: AttachedImage[];
|
|
22
24
|
isManagerReady: boolean;
|
|
23
25
|
insertTextAtCursor: (text: string, callback?: (newText: string, newCursorPosition: number) => void) => void;
|
|
@@ -68,6 +70,7 @@ export declare const useInputManager: (callbacks?: Partial<InputManagerCallbacks
|
|
|
68
70
|
handleSpecialCharInput: (char: string) => void;
|
|
69
71
|
setShowBashManager: (show: boolean) => void;
|
|
70
72
|
setShowMcpManager: (show: boolean) => void;
|
|
73
|
+
setPermissionMode: (mode: PermissionMode) => void;
|
|
71
74
|
addImage: (imagePath: string, mimeType: string) => AttachedImage | undefined;
|
|
72
75
|
removeImage: (imageId: number) => void;
|
|
73
76
|
clearImages: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useInputManager.d.ts","sourceRoot":"","sources":["../../src/hooks/useInputManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,aAAa,EACd,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"useInputManager.d.ts","sourceRoot":"","sources":["../../src/hooks/useInputManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,aAAa,EACd,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhD,eAAO,MAAM,eAAe,GAC1B,YAAW,OAAO,CAAC,qBAAqB,CAAM;;;;;;;;;;;;;;;;;;;;+BAwHpC,MAAM,aACD,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,KAAK,IAAI;oCAQrD,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,KAAK,IAAI;;;;;;qCA2Bd,MAAM;iCAK7C,MAAM;;;;;mCAe+B,MAAM;oCAIL,MAAM;wCAKF,MAAM;mCAKjD,MAAM;;;;mCAYN,MAAM;;;;;sCAemC,MAAM;uCAIL,MAAM;4CAKD,MAAM;uCAKrD,MAAM;;;;;0CAeuC,MAAM;wCAIR,MAAM;6CAID,MAAM;0CAKT,MAAM;mCAKhD,SAAS,GAAG,MAAM;;mCAWiB,MAAM,EAAE;iCAK5C,IAAI,GAAG,MAAM,gBAAgB,MAAM;;;;;mCAgBC,MAAM;+BAuFf,OAAO;8BAGR,OAAO;8BAGP,cAAc;0BAMlB,MAAM,YAAY,MAAM;2BAGvB,MAAM;;;8BAWH,MAAM;mCAKxB,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,cAC1D,OAAO,qBACA,OAAO;uCAUkB,MAAM;;+CApHO,MAAM;yBAiIvD,MAAM,OACR,GAAG,kBACQ,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,cAC1D,OAAO,qBACA,OAAO,gBACX,MAAM,IAAI;yBA/IgB,MAAM;kCAIG,MAAM;;CAkK9D,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEffect, useRef, useState, useCallback } from "react";
|
|
2
2
|
import { InputManager, } from "../managers/InputManager.js";
|
|
3
|
+
import { logger } from "../utils/logger.js";
|
|
3
4
|
export const useInputManager = (callbacks = {}) => {
|
|
4
5
|
const managerRef = useRef(null);
|
|
5
6
|
const [isManagerReady, setIsManagerReady] = useState(false);
|
|
@@ -28,12 +29,14 @@ export const useInputManager = (callbacks = {}) => {
|
|
|
28
29
|
});
|
|
29
30
|
const [showBashManager, setShowBashManager] = useState(false);
|
|
30
31
|
const [showMcpManager, setShowMcpManager] = useState(false);
|
|
32
|
+
const [permissionMode, setPermissionModeState] = useState("default");
|
|
31
33
|
const [attachedImages, setAttachedImages] = useState([]);
|
|
32
34
|
// Create InputManager on mount and update callbacks when they change
|
|
33
35
|
useEffect(() => {
|
|
34
36
|
if (!managerRef.current) {
|
|
35
37
|
// Create InputManager on first mount
|
|
36
38
|
const manager = new InputManager({
|
|
39
|
+
logger,
|
|
37
40
|
onInputTextChange: setInputText,
|
|
38
41
|
onCursorPositionChange: setCursorPosition,
|
|
39
42
|
onFileSelectorStateChange: (show, files, query, position) => {
|
|
@@ -54,6 +57,10 @@ export const useInputManager = (callbacks = {}) => {
|
|
|
54
57
|
onMcpManagerStateChange: (show) => {
|
|
55
58
|
setShowMcpManager(show);
|
|
56
59
|
},
|
|
60
|
+
onPermissionModeChange: (mode) => {
|
|
61
|
+
setPermissionModeState(mode);
|
|
62
|
+
callbacks.onPermissionModeChange?.(mode);
|
|
63
|
+
},
|
|
57
64
|
onImagesStateChange: setAttachedImages,
|
|
58
65
|
onShowBashManager: () => setShowBashManager(true),
|
|
59
66
|
onShowMcpManager: () => setShowMcpManager(true),
|
|
@@ -65,6 +72,7 @@ export const useInputManager = (callbacks = {}) => {
|
|
|
65
72
|
else {
|
|
66
73
|
// Update callbacks on existing manager
|
|
67
74
|
managerRef.current.updateCallbacks({
|
|
75
|
+
logger,
|
|
68
76
|
onInputTextChange: setInputText,
|
|
69
77
|
onCursorPositionChange: setCursorPosition,
|
|
70
78
|
onFileSelectorStateChange: (show, files, query, position) => {
|
|
@@ -85,6 +93,10 @@ export const useInputManager = (callbacks = {}) => {
|
|
|
85
93
|
onMcpManagerStateChange: (show) => {
|
|
86
94
|
setShowMcpManager(show);
|
|
87
95
|
},
|
|
96
|
+
onPermissionModeChange: (mode) => {
|
|
97
|
+
setPermissionModeState(mode);
|
|
98
|
+
callbacks.onPermissionModeChange?.(mode);
|
|
99
|
+
},
|
|
88
100
|
onImagesStateChange: setAttachedImages,
|
|
89
101
|
onShowBashManager: () => setShowBashManager(true),
|
|
90
102
|
onShowMcpManager: () => setShowMcpManager(true),
|
|
@@ -244,6 +256,7 @@ export const useInputManager = (callbacks = {}) => {
|
|
|
244
256
|
memoryMessage: memoryTypeSelectorState.message,
|
|
245
257
|
showBashManager,
|
|
246
258
|
showMcpManager,
|
|
259
|
+
permissionMode,
|
|
247
260
|
attachedImages,
|
|
248
261
|
isManagerReady,
|
|
249
262
|
// Methods
|
|
@@ -291,6 +304,10 @@ export const useInputManager = (callbacks = {}) => {
|
|
|
291
304
|
setShowMcpManager: useCallback((show) => {
|
|
292
305
|
managerRef.current?.setShowMcpManager(show);
|
|
293
306
|
}, []),
|
|
307
|
+
setPermissionMode: useCallback((mode) => {
|
|
308
|
+
setPermissionModeState(mode);
|
|
309
|
+
managerRef.current?.setPermissionMode(mode);
|
|
310
|
+
}, []),
|
|
294
311
|
// Image management
|
|
295
312
|
addImage: useCallback((imagePath, mimeType) => {
|
|
296
313
|
return managerRef.current?.addImage(imagePath, mimeType);
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,wBAAsB,IAAI,kBAmHzB;AAGD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGpC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC"}
|