wave-code 0.14.4 → 0.15.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.
- package/dist/acp/agent.d.ts.map +1 -1
- package/dist/acp/agent.js +10 -0
- package/dist/components/BackgroundTaskManager.d.ts.map +1 -1
- package/dist/components/BackgroundTaskManager.js +17 -53
- package/dist/components/CommandSelector.d.ts.map +1 -1
- package/dist/components/CommandSelector.js +38 -28
- package/dist/components/ConfirmationSelector.d.ts.map +1 -1
- package/dist/components/ConfirmationSelector.js +18 -196
- package/dist/components/DiscoverView.d.ts.map +1 -1
- package/dist/components/DiscoverView.js +19 -11
- package/dist/components/FileSelector.d.ts.map +1 -1
- package/dist/components/FileSelector.js +29 -25
- package/dist/components/HelpView.d.ts.map +1 -1
- package/dist/components/HelpView.js +24 -28
- package/dist/components/HistorySearch.d.ts.map +1 -1
- package/dist/components/HistorySearch.js +26 -28
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +14 -6
- package/dist/components/InstalledView.d.ts.map +1 -1
- package/dist/components/InstalledView.js +19 -11
- package/dist/components/MarketplaceDetail.d.ts.map +1 -1
- package/dist/components/MarketplaceDetail.js +35 -16
- package/dist/components/MarketplaceView.d.ts.map +1 -1
- package/dist/components/MarketplaceView.js +21 -12
- package/dist/components/McpManager.d.ts.map +1 -1
- package/dist/components/McpManager.js +27 -46
- package/dist/components/ModelSelector.d.ts.map +1 -1
- package/dist/components/ModelSelector.js +27 -17
- package/dist/components/PluginDetail.d.ts.map +1 -1
- package/dist/components/PluginDetail.js +39 -26
- package/dist/components/RewindCommand.d.ts.map +1 -1
- package/dist/components/RewindCommand.js +27 -21
- package/dist/components/SessionSelector.d.ts.map +1 -1
- package/dist/components/SessionSelector.js +21 -16
- package/dist/components/StatusLine.d.ts.map +1 -1
- package/dist/components/StatusLine.js +5 -1
- package/dist/components/WorktreeExitPrompt.d.ts.map +1 -1
- package/dist/components/WorktreeExitPrompt.js +21 -12
- package/dist/contexts/useChat.d.ts +0 -1
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +13 -20
- package/dist/hooks/useInputManager.d.ts +5 -19
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +222 -79
- package/dist/managers/inputHandlers.d.ts +1 -1
- package/dist/managers/inputHandlers.d.ts.map +1 -1
- package/dist/managers/inputHandlers.js +3 -6
- package/dist/managers/inputReducer.d.ts +46 -4
- package/dist/managers/inputReducer.d.ts.map +1 -1
- package/dist/managers/inputReducer.js +519 -4
- package/dist/print-cli.d.ts.map +1 -1
- package/dist/print-cli.js +21 -9
- package/dist/reducers/backgroundTaskManagerReducer.d.ts +20 -0
- package/dist/reducers/backgroundTaskManagerReducer.d.ts.map +1 -1
- package/dist/reducers/backgroundTaskManagerReducer.js +83 -0
- package/dist/reducers/confirmationReducer.d.ts +11 -0
- package/dist/reducers/confirmationReducer.d.ts.map +1 -1
- package/dist/reducers/confirmationReducer.js +146 -0
- package/dist/reducers/helpSelectorReducer.d.ts +26 -0
- package/dist/reducers/helpSelectorReducer.d.ts.map +1 -0
- package/dist/reducers/helpSelectorReducer.js +52 -0
- package/dist/reducers/mcpManagerReducer.d.ts +22 -0
- package/dist/reducers/mcpManagerReducer.d.ts.map +1 -1
- package/dist/reducers/mcpManagerReducer.js +57 -0
- package/dist/reducers/pluginDetailReducer.d.ts +8 -0
- package/dist/reducers/pluginDetailReducer.d.ts.map +1 -1
- package/dist/reducers/pluginDetailReducer.js +32 -0
- package/dist/reducers/questionReducer.d.ts +21 -0
- package/dist/reducers/questionReducer.d.ts.map +1 -1
- package/dist/reducers/questionReducer.js +177 -0
- package/dist/reducers/rewindSelectorReducer.d.ts +22 -0
- package/dist/reducers/rewindSelectorReducer.d.ts.map +1 -0
- package/dist/reducers/rewindSelectorReducer.js +37 -0
- package/dist/reducers/selectorReducer.d.ts +22 -0
- package/dist/reducers/selectorReducer.d.ts.map +1 -0
- package/dist/reducers/selectorReducer.js +40 -0
- package/dist/utils/inputUtils.d.ts +18 -0
- package/dist/utils/inputUtils.d.ts.map +1 -0
- package/dist/utils/inputUtils.js +67 -0
- package/dist/utils/worktree.d.ts.map +1 -1
- package/dist/utils/worktree.js +1 -2
- package/package.json +2 -2
- package/src/acp/agent.ts +10 -0
- package/src/components/BackgroundTaskManager.tsx +19 -58
- package/src/components/CommandSelector.tsx +53 -44
- package/src/components/ConfirmationSelector.tsx +18 -202
- package/src/components/DiscoverView.tsx +21 -11
- package/src/components/FileSelector.tsx +40 -35
- package/src/components/HelpView.tsx +37 -43
- package/src/components/HistorySearch.tsx +29 -36
- package/src/components/InputBox.tsx +14 -7
- package/src/components/InstalledView.tsx +21 -11
- package/src/components/MarketplaceDetail.tsx +48 -24
- package/src/components/MarketplaceView.tsx +25 -10
- package/src/components/McpManager.tsx +29 -54
- package/src/components/ModelSelector.tsx +30 -23
- package/src/components/PluginDetail.tsx +50 -27
- package/src/components/RewindCommand.tsx +38 -32
- package/src/components/SessionSelector.tsx +23 -20
- package/src/components/StatusLine.tsx +10 -1
- package/src/components/WorktreeExitPrompt.tsx +23 -13
- package/src/contexts/useChat.tsx +13 -31
- package/src/hooks/useInputManager.ts +273 -141
- package/src/managers/inputHandlers.ts +1 -6
- package/src/managers/inputReducer.ts +675 -7
- package/src/print-cli.ts +20 -11
- package/src/reducers/backgroundTaskManagerReducer.ts +110 -1
- package/src/reducers/confirmationReducer.ts +173 -1
- package/src/reducers/helpSelectorReducer.ts +77 -0
- package/src/reducers/mcpManagerReducer.ts +82 -1
- package/src/reducers/pluginDetailReducer.ts +42 -1
- package/src/reducers/questionReducer.ts +204 -0
- package/src/reducers/rewindSelectorReducer.ts +54 -0
- package/src/reducers/selectorReducer.ts +57 -0
- package/src/utils/inputUtils.ts +94 -0
- package/src/utils/worktree.ts +1 -7
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useReducer, useEffect } from "react";
|
|
3
3
|
import { Box, Text, useInput } from "ink";
|
|
4
4
|
import { AVAILABLE_COMMANDS } from "../constants/commands.js";
|
|
5
|
+
import { helpSelectorReducer } from "../reducers/helpSelectorReducer.js";
|
|
5
6
|
export const HelpView = ({ onCancel, commands = [], }) => {
|
|
6
|
-
const [activeTab, setActiveTab] = useState("general");
|
|
7
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
8
7
|
const MAX_VISIBLE_ITEMS = 10;
|
|
9
8
|
const tabs = [
|
|
10
9
|
"general",
|
|
@@ -13,29 +12,30 @@ export const HelpView = ({ onCancel, commands = [], }) => {
|
|
|
13
12
|
if (commands.length > 0) {
|
|
14
13
|
tabs.push("custom-commands");
|
|
15
14
|
}
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const [state, dispatch] = useReducer(helpSelectorReducer, {
|
|
16
|
+
selectedIndex: 0,
|
|
17
|
+
activeTab: "general",
|
|
18
|
+
pendingDecision: null,
|
|
19
|
+
});
|
|
20
|
+
const { selectedIndex, activeTab, pendingDecision } = state;
|
|
21
|
+
// Handle decisions from reducer
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (pendingDecision === "cancel") {
|
|
18
24
|
onCancel();
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
if (key.tab) {
|
|
22
|
-
setActiveTab((prev) => {
|
|
23
|
-
const currentIndex = tabs.indexOf(prev);
|
|
24
|
-
const nextIndex = (currentIndex + 1) % tabs.length;
|
|
25
|
-
return tabs[nextIndex];
|
|
26
|
-
});
|
|
27
|
-
setSelectedIndex(0);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
if (activeTab === "commands" || activeTab === "custom-commands") {
|
|
31
|
-
const currentCommands = activeTab === "commands" ? AVAILABLE_COMMANDS : commands;
|
|
32
|
-
if (key.upArrow) {
|
|
33
|
-
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
34
|
-
}
|
|
35
|
-
else if (key.downArrow) {
|
|
36
|
-
setSelectedIndex((prev) => Math.min(currentCommands.length - 1, prev + 1));
|
|
37
|
-
}
|
|
25
|
+
dispatch({ type: "CLEAR_DECISION" });
|
|
38
26
|
}
|
|
27
|
+
}, [pendingDecision, onCancel]);
|
|
28
|
+
const currentCommands = activeTab === "commands" ? AVAILABLE_COMMANDS : commands;
|
|
29
|
+
// Calculate visible window for commands
|
|
30
|
+
const startIndex = Math.max(0, Math.min(selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2), Math.max(0, currentCommands.length - MAX_VISIBLE_ITEMS)));
|
|
31
|
+
const visibleCommands = currentCommands.slice(startIndex, startIndex + MAX_VISIBLE_ITEMS);
|
|
32
|
+
useInput((_, key) => {
|
|
33
|
+
dispatch({
|
|
34
|
+
type: "HANDLE_KEY",
|
|
35
|
+
key,
|
|
36
|
+
maxIndex: activeTab === "general" ? 0 : currentCommands.length - 1,
|
|
37
|
+
tabs,
|
|
38
|
+
});
|
|
39
39
|
});
|
|
40
40
|
const helpItems = [
|
|
41
41
|
{ key: "@", description: "Reference files" },
|
|
@@ -53,10 +53,6 @@ export const HelpView = ({ onCancel, commands = [], }) => {
|
|
|
53
53
|
description: "Interrupt AI or command / Cancel selector / Close help",
|
|
54
54
|
},
|
|
55
55
|
];
|
|
56
|
-
// Calculate visible window for commands
|
|
57
|
-
const currentCommands = activeTab === "commands" ? AVAILABLE_COMMANDS : commands;
|
|
58
|
-
const startIndex = Math.max(0, Math.min(selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2), Math.max(0, currentCommands.length - MAX_VISIBLE_ITEMS)));
|
|
59
|
-
const visibleCommands = currentCommands.slice(startIndex, startIndex + MAX_VISIBLE_ITEMS);
|
|
60
56
|
const footerText = [
|
|
61
57
|
"Tab switch",
|
|
62
58
|
activeTab !== "general" && "↑↓ navigate",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HistorySearch.d.ts","sourceRoot":"","sources":["../../src/components/HistorySearch.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"HistorySearch.d.ts","sourceRoot":"","sources":["../../src/components/HistorySearch.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAE/D,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAMxE,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAuJtD,CAAC"}
|
|
@@ -1,48 +1,46 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import { useReducer, useEffect, useState } from "react";
|
|
3
3
|
import { Box, Text, useInput } from "ink";
|
|
4
4
|
import { PromptHistoryManager } from "wave-agent-sdk";
|
|
5
|
+
import { selectorReducer, } from "../reducers/selectorReducer.js";
|
|
5
6
|
export const HistorySearch = ({ searchQuery, onSelect, onCancel, }) => {
|
|
6
7
|
const MAX_VISIBLE_ITEMS = 5;
|
|
7
|
-
const [
|
|
8
|
+
const [state, dispatch] = useReducer(selectorReducer, {
|
|
9
|
+
selectedIndex: 0,
|
|
10
|
+
pendingDecision: null,
|
|
11
|
+
});
|
|
8
12
|
const [entries, setEntries] = useState([]);
|
|
9
|
-
const
|
|
10
|
-
const selectedIndexRef = React.useRef(0);
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
entriesRef.current = entries;
|
|
13
|
-
}, [entries]);
|
|
14
|
-
useEffect(() => {
|
|
15
|
-
selectedIndexRef.current = selectedIndex;
|
|
16
|
-
}, [selectedIndex]);
|
|
13
|
+
const { selectedIndex, pendingDecision } = state;
|
|
17
14
|
useEffect(() => {
|
|
18
15
|
const fetchHistory = async () => {
|
|
19
16
|
const results = await PromptHistoryManager.searchHistory(searchQuery);
|
|
20
17
|
const limitedResults = results.slice(0, 20);
|
|
21
|
-
setEntries(limitedResults);
|
|
22
|
-
|
|
18
|
+
setEntries(limitedResults);
|
|
19
|
+
dispatch({ type: "RESET_INDEX" });
|
|
23
20
|
};
|
|
24
21
|
fetchHistory();
|
|
25
22
|
}, [searchQuery]);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
selectedIndexRef.current < entriesRef.current.length) {
|
|
30
|
-
onSelect(entriesRef.current[selectedIndexRef.current]);
|
|
31
|
-
}
|
|
23
|
+
// Handle decisions from reducer
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!pendingDecision)
|
|
32
26
|
return;
|
|
27
|
+
if (pendingDecision === "select") {
|
|
28
|
+
if (entries.length > 0 && selectedIndex < entries.length) {
|
|
29
|
+
onSelect(entries[selectedIndex]);
|
|
30
|
+
}
|
|
33
31
|
}
|
|
34
|
-
if (
|
|
32
|
+
else if (pendingDecision === "cancel") {
|
|
35
33
|
onCancel();
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
if (key.upArrow) {
|
|
39
|
-
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
if (key.downArrow) {
|
|
43
|
-
setSelectedIndex((prev) => Math.min(entriesRef.current.length - 1, prev + 1));
|
|
44
|
-
return;
|
|
45
34
|
}
|
|
35
|
+
dispatch({ type: "CLEAR_DECISION" });
|
|
36
|
+
}, [pendingDecision, selectedIndex, entries, onSelect, onCancel]);
|
|
37
|
+
useInput((input, key) => {
|
|
38
|
+
dispatch({
|
|
39
|
+
type: "HANDLE_KEY",
|
|
40
|
+
key,
|
|
41
|
+
maxIndex: entries.length - 1,
|
|
42
|
+
hasInsert: false,
|
|
43
|
+
});
|
|
46
44
|
});
|
|
47
45
|
if (entries.length === 0) {
|
|
48
46
|
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" })] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAkBzC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,mDACe,CAAC;AAEnD,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,EAClD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACjC,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,
|
|
1
|
+
{"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAkBzC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,mDACe,CAAC;AAEnD,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,EAClD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACjC,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,CAoR5C,CAAC"}
|
|
@@ -19,7 +19,7 @@ import { useChat } from "../contexts/useChat.js";
|
|
|
19
19
|
export const INPUT_PLACEHOLDER_TEXT = "Type your message (use /help for more info)...";
|
|
20
20
|
export const INPUT_PLACEHOLDER_TEXT_PREFIX = INPUT_PLACEHOLDER_TEXT.substring(0, 10);
|
|
21
21
|
export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, }) => {
|
|
22
|
-
const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode,
|
|
22
|
+
const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, sessionId, workingDirectory, askBtw, currentModel, configuredModels, setModel, recreateAgent, } = useChat();
|
|
23
23
|
// Input manager with all input state and functionality (including images)
|
|
24
24
|
const { inputText, cursorPosition,
|
|
25
25
|
// Image management
|
|
@@ -33,7 +33,7 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
|
|
|
33
33
|
// Task/MCP Manager
|
|
34
34
|
showBackgroundTaskManager, showMcpManager, showRewindManager, showHelp, showStatusCommand, showPluginManager, showModelSelector, setShowBackgroundTaskManager, setShowMcpManager, setShowRewindManager, setShowHelp, setShowStatusCommand, setShowPluginManager, setShowModelSelector,
|
|
35
35
|
// Permission mode
|
|
36
|
-
permissionMode, setPermissionMode,
|
|
36
|
+
permissionMode, setPermissionMode,
|
|
37
37
|
// BTW state
|
|
38
38
|
btwState,
|
|
39
39
|
// Main handler
|
|
@@ -54,12 +54,20 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
|
|
|
54
54
|
useEffect(() => {
|
|
55
55
|
setPermissionMode(chatPermissionMode);
|
|
56
56
|
}, [chatPermissionMode, setPermissionMode]);
|
|
57
|
-
// Sync allowBypassInCycle from useChat to InputManager
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
setAllowBypassInCycle(chatAllowBypassInCycle);
|
|
60
|
-
}, [chatAllowBypassInCycle, setAllowBypassInCycle]);
|
|
61
57
|
// Use the InputManager's unified input handler
|
|
62
58
|
useInput(async (input, key) => {
|
|
59
|
+
// These views have their own useInput handlers that handle escape and navigation.
|
|
60
|
+
// If they are active, we should skip InputBox's global input handling to avoid
|
|
61
|
+
// duplicate dispatches or state update conflicts.
|
|
62
|
+
if (showRewindManager ||
|
|
63
|
+
showHelp ||
|
|
64
|
+
showStatusCommand ||
|
|
65
|
+
showPluginManager ||
|
|
66
|
+
showModelSelector ||
|
|
67
|
+
showBackgroundTaskManager ||
|
|
68
|
+
showMcpManager) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
63
71
|
await handleInput(input, key, attachedImages, clearImages);
|
|
64
72
|
});
|
|
65
73
|
const handleRewindCancel = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InstalledView.d.ts","sourceRoot":"","sources":["../../src/components/InstalledView.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"InstalledView.d.ts","sourceRoot":"","sources":["../../src/components/InstalledView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAKrD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EA8EjC,CAAC"}
|
|
@@ -1,25 +1,33 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useReducer, useEffect } from "react";
|
|
3
3
|
import { Box, Text, useInput } from "ink";
|
|
4
4
|
import { usePluginManagerContext } from "../contexts/PluginManagerContext.js";
|
|
5
|
+
import { selectorReducer } from "../reducers/selectorReducer.js";
|
|
5
6
|
export const InstalledView = () => {
|
|
6
7
|
const { installedPlugins, actions } = usePluginManagerContext();
|
|
7
|
-
const [
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
const [state, dispatch] = useReducer(selectorReducer, {
|
|
9
|
+
selectedIndex: 0,
|
|
10
|
+
pendingDecision: null,
|
|
11
|
+
});
|
|
12
|
+
const { selectedIndex, pendingDecision } = state;
|
|
13
|
+
useInput((_input, key) => {
|
|
14
|
+
dispatch({
|
|
15
|
+
type: "HANDLE_KEY",
|
|
16
|
+
key,
|
|
17
|
+
maxIndex: installedPlugins.length - 1,
|
|
18
|
+
hasInsert: false,
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (pendingDecision === "select") {
|
|
16
23
|
const plugin = installedPlugins[selectedIndex];
|
|
17
24
|
if (plugin) {
|
|
18
25
|
actions.setSelectedId(`${plugin.name}@${plugin.marketplace}`);
|
|
19
26
|
actions.setView("PLUGIN_DETAIL");
|
|
20
27
|
}
|
|
28
|
+
dispatch({ type: "CLEAR_DECISION" });
|
|
21
29
|
}
|
|
22
|
-
});
|
|
30
|
+
}, [pendingDecision, selectedIndex, installedPlugins, actions]);
|
|
23
31
|
if (installedPlugins.length === 0) {
|
|
24
32
|
return (_jsx(Box, { padding: 1, children: _jsx(Text, { dimColor: true, children: "No plugins installed." }) }));
|
|
25
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarketplaceDetail.d.ts","sourceRoot":"","sources":["../../src/components/MarketplaceDetail.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"MarketplaceDetail.d.ts","sourceRoot":"","sources":["../../src/components/MarketplaceDetail.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAK9D,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EA8IrC,CAAC"}
|
|
@@ -1,30 +1,38 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useReducer, useEffect, useMemo } from "react";
|
|
3
3
|
import { Box, Text, useInput } from "ink";
|
|
4
4
|
import { usePluginManagerContext } from "../contexts/PluginManagerContext.js";
|
|
5
|
+
import { selectorReducer } from "../reducers/selectorReducer.js";
|
|
5
6
|
export const MarketplaceDetail = () => {
|
|
6
7
|
const { state, marketplaces, actions } = usePluginManagerContext();
|
|
7
|
-
const [
|
|
8
|
+
const [selectorState, dispatch] = useReducer(selectorReducer, {
|
|
9
|
+
selectedIndex: 0,
|
|
10
|
+
pendingDecision: null,
|
|
11
|
+
});
|
|
12
|
+
const { selectedIndex: selectedActionIndex, pendingDecision } = selectorState;
|
|
8
13
|
const marketplace = marketplaces.find((m) => m.name === state.selectedId);
|
|
9
|
-
const ACTIONS = [
|
|
14
|
+
const ACTIONS = useMemo(() => [
|
|
10
15
|
{
|
|
11
16
|
id: "toggle-auto-update",
|
|
12
17
|
label: `${marketplace?.autoUpdate ? "Disable" : "Enable"} auto-update`,
|
|
13
18
|
},
|
|
14
19
|
{ id: "update", label: "Update marketplace" },
|
|
15
20
|
{ id: "remove", label: "Remove marketplace" },
|
|
16
|
-
];
|
|
17
|
-
useInput((
|
|
18
|
-
if (key.escape)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
], [marketplace?.autoUpdate]);
|
|
22
|
+
useInput((_input, key) => {
|
|
23
|
+
if (state.isLoading && !key.escape)
|
|
24
|
+
return;
|
|
25
|
+
dispatch({
|
|
26
|
+
type: "HANDLE_KEY",
|
|
27
|
+
key,
|
|
28
|
+
maxIndex: ACTIONS.length - 1,
|
|
29
|
+
hasInsert: false,
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (!pendingDecision)
|
|
34
|
+
return;
|
|
35
|
+
if (pendingDecision === "select" && marketplace && !state.isLoading) {
|
|
28
36
|
const action = ACTIONS[selectedActionIndex].id;
|
|
29
37
|
if (action === "toggle-auto-update") {
|
|
30
38
|
actions.toggleAutoUpdate(marketplace.name, !marketplace.autoUpdate);
|
|
@@ -36,7 +44,18 @@ export const MarketplaceDetail = () => {
|
|
|
36
44
|
actions.removeMarketplace(marketplace.name);
|
|
37
45
|
}
|
|
38
46
|
}
|
|
39
|
-
|
|
47
|
+
else if (pendingDecision === "cancel") {
|
|
48
|
+
actions.setView("MARKETPLACES");
|
|
49
|
+
}
|
|
50
|
+
dispatch({ type: "CLEAR_DECISION" });
|
|
51
|
+
}, [
|
|
52
|
+
pendingDecision,
|
|
53
|
+
selectedActionIndex,
|
|
54
|
+
marketplace,
|
|
55
|
+
state.isLoading,
|
|
56
|
+
actions,
|
|
57
|
+
ACTIONS,
|
|
58
|
+
]);
|
|
40
59
|
if (!marketplace) {
|
|
41
60
|
return (_jsx(Box, { children: _jsx(Text, { color: "red", children: "Marketplace not found." }) }));
|
|
42
61
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarketplaceView.d.ts","sourceRoot":"","sources":["../../src/components/MarketplaceView.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"MarketplaceView.d.ts","sourceRoot":"","sources":["../../src/components/MarketplaceView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAOrD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAkDnC,CAAC"}
|
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useReducer, useEffect } from "react";
|
|
3
3
|
import { Box, Text, useInput } from "ink";
|
|
4
4
|
import { usePluginManagerContext } from "../contexts/PluginManagerContext.js";
|
|
5
|
+
import { selectorReducer } from "../reducers/selectorReducer.js";
|
|
5
6
|
import { MarketplaceList } from "./MarketplaceList.js";
|
|
6
7
|
export const MarketplaceView = () => {
|
|
7
8
|
const { marketplaces, actions } = usePluginManagerContext();
|
|
8
|
-
const [
|
|
9
|
+
const [state, dispatch] = useReducer(selectorReducer, {
|
|
10
|
+
selectedIndex: 0,
|
|
11
|
+
pendingDecision: null,
|
|
12
|
+
});
|
|
13
|
+
const { selectedIndex, pendingDecision } = state;
|
|
9
14
|
useInput((input, key) => {
|
|
10
|
-
if (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
else if (key.downArrow) {
|
|
14
|
-
setSelectedIndex(Math.min(marketplaces.length - 1, selectedIndex + 1));
|
|
15
|
+
if (input === "a") {
|
|
16
|
+
actions.setView("ADD_MARKETPLACE");
|
|
17
|
+
return;
|
|
15
18
|
}
|
|
16
|
-
|
|
19
|
+
dispatch({
|
|
20
|
+
type: "HANDLE_KEY",
|
|
21
|
+
key,
|
|
22
|
+
maxIndex: marketplaces.length - 1,
|
|
23
|
+
hasInsert: false,
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (pendingDecision === "select") {
|
|
17
28
|
const mk = marketplaces[selectedIndex];
|
|
18
29
|
if (mk) {
|
|
19
30
|
actions.setSelectedId(mk.name);
|
|
20
31
|
actions.setView("MARKETPLACE_DETAIL");
|
|
21
32
|
}
|
|
33
|
+
dispatch({ type: "CLEAR_DECISION" });
|
|
22
34
|
}
|
|
23
|
-
|
|
24
|
-
actions.setView("ADD_MARKETPLACE");
|
|
25
|
-
}
|
|
26
|
-
});
|
|
35
|
+
}, [pendingDecision, selectedIndex, marketplaces, actions]);
|
|
27
36
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "green", children: "Press 'a' to add a new marketplace" }) }), _jsx(MarketplaceList, { marketplaces: marketplaces, selectedIndex: selectedIndex }), marketplaces.length > 0 && (_jsx(Box, { marginLeft: 4, marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press Enter for actions" }) }))] }));
|
|
28
37
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpManager.d.ts","sourceRoot":"","sources":["../../src/components/McpManager.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"McpManager.d.ts","sourceRoot":"","sources":["../../src/components/McpManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAErD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAMjD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D;AAQD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA6QhD,CAAC"}
|
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useReducer } from "react";
|
|
2
|
+
import { useReducer, useEffect } from "react";
|
|
3
3
|
import { Box, Text, useInput } from "ink";
|
|
4
4
|
import { mcpManagerReducer, } from "../reducers/mcpManagerReducer.js";
|
|
5
5
|
const initialState = {
|
|
6
6
|
selectedIndex: 0,
|
|
7
7
|
viewMode: "list",
|
|
8
|
+
pendingEffect: null,
|
|
8
9
|
};
|
|
9
10
|
export const McpManager = ({ onCancel, servers, onConnectServer, onDisconnectServer, }) => {
|
|
10
11
|
const [state, dispatch] = useReducer(mcpManagerReducer, initialState);
|
|
12
|
+
// Handle pending effects
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (!state.pendingEffect)
|
|
15
|
+
return;
|
|
16
|
+
const effect = state.pendingEffect;
|
|
17
|
+
dispatch({ type: "CLEAR_PENDING_EFFECT" });
|
|
18
|
+
switch (effect.type) {
|
|
19
|
+
case "CANCEL":
|
|
20
|
+
onCancel();
|
|
21
|
+
break;
|
|
22
|
+
case "CONNECT_SERVER":
|
|
23
|
+
onConnectServer(effect.serverName);
|
|
24
|
+
break;
|
|
25
|
+
case "DISCONNECT_SERVER":
|
|
26
|
+
onDisconnectServer(effect.serverName);
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}, [state.pendingEffect, onCancel, onConnectServer, onDisconnectServer]);
|
|
11
30
|
// Dynamically calculate selectedServer based on selectedIndex and servers
|
|
12
31
|
const selectedServer = state.viewMode === "detail" &&
|
|
13
32
|
servers.length > 0 &&
|
|
@@ -41,52 +60,14 @@ export const McpManager = ({ onCancel, servers, onConnectServer, onDisconnectSer
|
|
|
41
60
|
return "○";
|
|
42
61
|
}
|
|
43
62
|
};
|
|
44
|
-
const handleConnect = async (serverName) => {
|
|
45
|
-
await onConnectServer(serverName);
|
|
46
|
-
};
|
|
47
|
-
const handleDisconnect = async (serverName) => {
|
|
48
|
-
await onDisconnectServer(serverName);
|
|
49
|
-
};
|
|
50
63
|
useInput((input, key) => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (state.viewMode === "detail") {
|
|
59
|
-
dispatch({ type: "SET_VIEW_MODE", viewMode: "list" });
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
onCancel();
|
|
63
|
-
}
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
if (key.upArrow) {
|
|
67
|
-
dispatch({ type: "MOVE_UP", serverCount: servers.length });
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
if (key.downArrow) {
|
|
71
|
-
dispatch({ type: "MOVE_DOWN", serverCount: servers.length });
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
// Hotkeys for server actions
|
|
75
|
-
if (input === "c") {
|
|
76
|
-
const server = servers[state.selectedIndex];
|
|
77
|
-
if (server &&
|
|
78
|
-
(server.status === "disconnected" || server.status === "error")) {
|
|
79
|
-
handleConnect(server.name);
|
|
80
|
-
}
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
if (input === "d") {
|
|
84
|
-
const server = servers[state.selectedIndex];
|
|
85
|
-
if (server && server.status === "connected") {
|
|
86
|
-
handleDisconnect(server.name);
|
|
87
|
-
}
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
64
|
+
dispatch({
|
|
65
|
+
type: "HANDLE_KEY",
|
|
66
|
+
input,
|
|
67
|
+
key,
|
|
68
|
+
serverCount: servers.length,
|
|
69
|
+
servers: servers.map((s) => ({ name: s.name, status: s.status })),
|
|
70
|
+
});
|
|
90
71
|
});
|
|
91
72
|
if (state.viewMode === "detail" && selectedServer) {
|
|
92
73
|
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "cyan", bold: true, children: ["MCP Server Details: ", selectedServer.name] }) }), _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Status:" }), " ", _jsxs(Text, { color: getStatusColor(selectedServer.status), children: [getStatusIcon(selectedServer.status), " ", selectedServer.status] })] }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Command:" }), " ", selectedServer.config.command] }) }), selectedServer.config.args && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Args:" }), " ", selectedServer.config.args.join(" ")] }) })), selectedServer.toolCount !== undefined && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Tools:" }), " ", selectedServer.toolCount, " ", "tools"] }) })), selectedServer.capabilities && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Capabilities:" }), " ", selectedServer.capabilities.join(", ")] }) })), selectedServer.lastConnected && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Last Connected:" }), " ", formatTime(selectedServer.lastConnected)] }) })), selectedServer.error && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "red", children: "Error:" }), " ", selectedServer.error] }) }))] }), selectedServer.config.env &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModelSelector.d.ts","sourceRoot":"","sources":["../../src/components/ModelSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ModelSelector.d.ts","sourceRoot":"","sources":["../../src/components/ModelSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAIrD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAID,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA0HtD,CAAC"}
|
|
@@ -1,33 +1,43 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useReducer, useEffect } from "react";
|
|
3
3
|
import { Box, Text, useInput } from "ink";
|
|
4
|
+
import { selectorReducer } from "../reducers/selectorReducer.js";
|
|
4
5
|
const MAX_VISIBLE_ITEMS = 5;
|
|
5
6
|
export const ModelSelector = ({ onCancel, currentModel, configuredModels, onSelectModel, }) => {
|
|
6
|
-
const [
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const [state, dispatch] = useReducer(selectorReducer, {
|
|
8
|
+
selectedIndex: configuredModels.indexOf(currentModel) !== -1
|
|
9
|
+
? configuredModels.indexOf(currentModel)
|
|
10
|
+
: 0,
|
|
11
|
+
pendingDecision: null,
|
|
9
12
|
});
|
|
13
|
+
const { selectedIndex, pendingDecision } = state;
|
|
10
14
|
useInput((_input, key) => {
|
|
11
|
-
|
|
15
|
+
dispatch({
|
|
16
|
+
type: "HANDLE_KEY",
|
|
17
|
+
key,
|
|
18
|
+
maxIndex: configuredModels.length - 1,
|
|
19
|
+
hasInsert: false,
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (pendingDecision === "select") {
|
|
12
24
|
if (configuredModels.length > 0) {
|
|
13
25
|
onSelectModel(configuredModels[selectedIndex]);
|
|
14
26
|
}
|
|
15
27
|
onCancel();
|
|
16
|
-
|
|
28
|
+
dispatch({ type: "CLEAR_DECISION" });
|
|
17
29
|
}
|
|
18
|
-
if (
|
|
30
|
+
else if (pendingDecision === "cancel") {
|
|
19
31
|
onCancel();
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
if (key.upArrow) {
|
|
23
|
-
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
24
|
-
return;
|
|
32
|
+
dispatch({ type: "CLEAR_DECISION" });
|
|
25
33
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
}, [
|
|
35
|
+
pendingDecision,
|
|
36
|
+
selectedIndex,
|
|
37
|
+
configuredModels,
|
|
38
|
+
onSelectModel,
|
|
39
|
+
onCancel,
|
|
40
|
+
]);
|
|
31
41
|
// Calculate visible window
|
|
32
42
|
const startIndex = Math.max(0, Math.min(selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2), Math.max(0, configuredModels.length - MAX_VISIBLE_ITEMS)));
|
|
33
43
|
const visibleModels = configuredModels.slice(startIndex, startIndex + MAX_VISIBLE_ITEMS);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginDetail.d.ts","sourceRoot":"","sources":["../../src/components/PluginDetail.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"PluginDetail.d.ts","sourceRoot":"","sources":["../../src/components/PluginDetail.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAc9D,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAgLhC,CAAC"}
|