wave-code 1.0.10 → 1.1.0
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/bin/wave-code.js +8 -2
- package/dist/bundle/wave.mjs +3207 -0
- package/package.json +24 -25
- package/src/commands/update.ts +2 -7
- package/src/components/App.tsx +3 -7
- package/src/components/BtwDisplay.tsx +10 -1
- package/src/components/ChatInterface.tsx +21 -52
- package/src/components/ConfirmationDetails.tsx +144 -37
- package/src/components/DiffDisplay.tsx +335 -301
- package/src/components/InputBox.tsx +3 -1
- package/src/components/LoadingIndicator.tsx +16 -2
- package/src/components/MessageBlockItem.tsx +2 -4
- package/src/components/MessageList.tsx +75 -14
- package/src/components/ReasoningDisplay.tsx +2 -4
- package/src/components/SessionSelector.tsx +82 -11
- package/src/components/StatusCommand.tsx +2 -9
- package/src/components/ToolDisplay.tsx +2 -4
- package/src/contexts/useChat.tsx +156 -335
- package/src/daemon/commands.ts +57 -27
- package/src/daemon/jsonRpcClient.ts +1 -1
- package/src/daemon/socketClient.ts +2 -2
- package/src/hooks/useInputManager.ts +1 -1
- package/src/index.ts +57 -10
- package/src/managers/inputReducer.ts +186 -104
- package/src/print-cli.ts +21 -17
- package/src/reducers/selectorReducer.ts +10 -0
- package/src/session-selector-cli.tsx +269 -28
- package/src/stdio/agentBridge.ts +22 -21
- package/src/stdio/daemonServer.ts +3 -1
- package/src/utils/clipboard.ts +21 -0
- package/src/utils/highlightUtils.ts +46 -1
- package/src/utils/readPackageJson.ts +29 -0
- package/src/utils/streamingText.ts +11 -0
- package/src/utils/worktree.ts +191 -43
- package/dist/cli.d.ts +0 -6
- package/dist/cli.js +0 -53
- package/dist/commands/plugin/disable.d.ts +0 -5
- package/dist/commands/plugin/disable.js +0 -15
- package/dist/commands/plugin/enable.d.ts +0 -5
- package/dist/commands/plugin/enable.js +0 -15
- package/dist/commands/plugin/install.d.ts +0 -5
- package/dist/commands/plugin/install.js +0 -21
- package/dist/commands/plugin/list.d.ts +0 -1
- package/dist/commands/plugin/list.js +0 -31
- package/dist/commands/plugin/marketplace.d.ts +0 -10
- package/dist/commands/plugin/marketplace.js +0 -90
- package/dist/commands/plugin/uninstall.d.ts +0 -3
- package/dist/commands/plugin/uninstall.js +0 -16
- package/dist/commands/plugin/update.d.ts +0 -3
- package/dist/commands/plugin/update.js +0 -15
- package/dist/commands/update.d.ts +0 -1
- package/dist/commands/update.js +0 -97
- package/dist/components/AgentsManager.d.ts +0 -7
- package/dist/components/AgentsManager.js +0 -109
- package/dist/components/App.d.ts +0 -9
- package/dist/components/App.js +0 -76
- package/dist/components/BackgroundTaskManager.d.ts +0 -5
- package/dist/components/BackgroundTaskManager.js +0 -99
- package/dist/components/BangDisplay.d.ts +0 -8
- package/dist/components/BangDisplay.js +0 -17
- package/dist/components/BtwDisplay.d.ts +0 -7
- package/dist/components/BtwDisplay.js +0 -19
- package/dist/components/ChatInterface.d.ts +0 -2
- package/dist/components/ChatInterface.js +0 -61
- package/dist/components/CommandSelector.d.ts +0 -10
- package/dist/components/CommandSelector.js +0 -66
- package/dist/components/CompactDisplay.d.ts +0 -8
- package/dist/components/CompactDisplay.js +0 -13
- package/dist/components/ConfirmationDetails.d.ts +0 -9
- package/dist/components/ConfirmationDetails.js +0 -45
- package/dist/components/ConfirmationSelector.d.ts +0 -13
- package/dist/components/ConfirmationSelector.js +0 -127
- package/dist/components/DiffDisplay.d.ts +0 -8
- package/dist/components/DiffDisplay.js +0 -201
- package/dist/components/DiscoverView.d.ts +0 -2
- package/dist/components/DiscoverView.js +0 -37
- package/dist/components/FileSelector.d.ts +0 -11
- package/dist/components/FileSelector.js +0 -50
- package/dist/components/HelpView.d.ts +0 -7
- package/dist/components/HelpView.js +0 -74
- package/dist/components/HistorySearch.d.ts +0 -8
- package/dist/components/HistorySearch.js +0 -66
- package/dist/components/InputBox.d.ts +0 -24
- package/dist/components/InputBox.js +0 -149
- package/dist/components/InstalledView.d.ts +0 -2
- package/dist/components/InstalledView.js +0 -45
- package/dist/components/LoadingIndicator.d.ts +0 -10
- package/dist/components/LoadingIndicator.js +0 -6
- package/dist/components/LoginCommand.d.ts +0 -5
- package/dist/components/LoginCommand.js +0 -153
- package/dist/components/Markdown.d.ts +0 -5
- package/dist/components/Markdown.js +0 -127
- package/dist/components/MarketplaceAddForm.d.ts +0 -2
- package/dist/components/MarketplaceAddForm.js +0 -55
- package/dist/components/MarketplaceDetail.d.ts +0 -2
- package/dist/components/MarketplaceDetail.js +0 -74
- package/dist/components/MarketplaceList.d.ts +0 -8
- package/dist/components/MarketplaceList.js +0 -17
- package/dist/components/MarketplaceView.d.ts +0 -2
- package/dist/components/MarketplaceView.js +0 -41
- package/dist/components/McpManager.d.ts +0 -9
- package/dist/components/McpManager.js +0 -88
- package/dist/components/MessageBlockItem.d.ts +0 -8
- package/dist/components/MessageBlockItem.js +0 -15
- package/dist/components/MessageList.d.ts +0 -10
- package/dist/components/MessageList.js +0 -80
- package/dist/components/ModelSelector.d.ts +0 -8
- package/dist/components/ModelSelector.js +0 -45
- package/dist/components/Notifications.d.ts +0 -7
- package/dist/components/Notifications.js +0 -9
- package/dist/components/PlanDisplay.d.ts +0 -7
- package/dist/components/PlanDisplay.js +0 -6
- package/dist/components/PluginDetail.d.ts +0 -2
- package/dist/components/PluginDetail.js +0 -87
- package/dist/components/PluginList.d.ts +0 -13
- package/dist/components/PluginList.js +0 -15
- package/dist/components/PluginManagerShell.d.ts +0 -6
- package/dist/components/PluginManagerShell.js +0 -92
- package/dist/components/PluginManagerTypes.d.ts +0 -35
- package/dist/components/PluginManagerTypes.js +0 -1
- package/dist/components/QueuedMessageList.d.ts +0 -2
- package/dist/components/QueuedMessageList.js +0 -18
- package/dist/components/ReasoningDisplay.d.ts +0 -8
- package/dist/components/ReasoningDisplay.js +0 -13
- package/dist/components/RewindCommand.d.ts +0 -12
- package/dist/components/RewindCommand.js +0 -78
- package/dist/components/SessionSelector.d.ts +0 -12
- package/dist/components/SessionSelector.js +0 -47
- package/dist/components/StatusCommand.d.ts +0 -5
- package/dist/components/StatusCommand.js +0 -28
- package/dist/components/StatusLine.d.ts +0 -6
- package/dist/components/StatusLine.js +0 -9
- package/dist/components/TaskList.d.ts +0 -5
- package/dist/components/TaskList.js +0 -197
- package/dist/components/TaskNotificationMessage.d.ts +0 -5
- package/dist/components/TaskNotificationMessage.js +0 -12
- package/dist/components/ToolDisplay.d.ts +0 -9
- package/dist/components/ToolDisplay.js +0 -55
- package/dist/components/WorkflowManager.d.ts +0 -5
- package/dist/components/WorkflowManager.js +0 -102
- package/dist/components/WorktreeExitPrompt.d.ts +0 -12
- package/dist/components/WorktreeExitPrompt.js +0 -35
- package/dist/constants/commands.d.ts +0 -2
- package/dist/constants/commands.js +0 -92
- package/dist/contexts/PluginManagerContext.d.ts +0 -3
- package/dist/contexts/PluginManagerContext.js +0 -9
- package/dist/contexts/useAppConfig.d.ts +0 -10
- package/dist/contexts/useAppConfig.js +0 -13
- package/dist/contexts/useChat.d.ts +0 -101
- package/dist/contexts/useChat.js +0 -993
- package/dist/contracts/status.d.ts +0 -7
- package/dist/contracts/status.js +0 -1
- package/dist/daemon/commands.d.ts +0 -49
- package/dist/daemon/commands.js +0 -341
- package/dist/daemon/jsonRpcClient.d.ts +0 -38
- package/dist/daemon/jsonRpcClient.js +0 -129
- package/dist/daemon/socketClient.d.ts +0 -13
- package/dist/daemon/socketClient.js +0 -26
- package/dist/daemon-cli.d.ts +0 -10
- package/dist/daemon-cli.js +0 -15
- package/dist/hooks/useInputManager.d.ts +0 -75
- package/dist/hooks/useInputManager.js +0 -583
- package/dist/hooks/usePluginManager.d.ts +0 -4
- package/dist/hooks/usePluginManager.js +0 -265
- package/dist/hooks/useTasks.d.ts +0 -1
- package/dist/hooks/useTasks.js +0 -5
- package/dist/index.d.ts +0 -4
- package/dist/index.js +0 -447
- package/dist/managers/inputHandlers.d.ts +0 -30
- package/dist/managers/inputHandlers.js +0 -625
- package/dist/managers/inputReducer.d.ts +0 -271
- package/dist/managers/inputReducer.js +0 -1121
- package/dist/plugin-manager-cli.d.ts +0 -5
- package/dist/plugin-manager-cli.js +0 -12
- package/dist/print-cli.d.ts +0 -10
- package/dist/print-cli.js +0 -209
- package/dist/reducers/agentsManagerReducer.d.ts +0 -26
- package/dist/reducers/agentsManagerReducer.js +0 -54
- package/dist/reducers/backgroundTaskManagerReducer.d.ts +0 -62
- package/dist/reducers/backgroundTaskManagerReducer.js +0 -106
- package/dist/reducers/confirmationReducer.d.ts +0 -37
- package/dist/reducers/confirmationReducer.js +0 -193
- package/dist/reducers/helpSelectorReducer.d.ts +0 -25
- package/dist/reducers/helpSelectorReducer.js +0 -52
- package/dist/reducers/marketplaceAddFormReducer.d.ts +0 -24
- package/dist/reducers/marketplaceAddFormReducer.js +0 -58
- package/dist/reducers/mcpManagerReducer.d.ts +0 -37
- package/dist/reducers/mcpManagerReducer.js +0 -74
- package/dist/reducers/pluginDetailReducer.d.ts +0 -32
- package/dist/reducers/pluginDetailReducer.js +0 -70
- package/dist/reducers/questionReducer.d.ts +0 -82
- package/dist/reducers/questionReducer.js +0 -375
- package/dist/reducers/rewindSelectorReducer.d.ts +0 -21
- package/dist/reducers/rewindSelectorReducer.js +0 -37
- package/dist/reducers/selectorReducer.d.ts +0 -23
- package/dist/reducers/selectorReducer.js +0 -42
- package/dist/reducers/workflowManagerReducer.d.ts +0 -40
- package/dist/reducers/workflowManagerReducer.js +0 -100
- package/dist/session-selector-cli.d.ts +0 -3
- package/dist/session-selector-cli.js +0 -25
- package/dist/stdio/agentBridge.d.ts +0 -139
- package/dist/stdio/agentBridge.js +0 -999
- package/dist/stdio/daemonServer.d.ts +0 -67
- package/dist/stdio/daemonServer.js +0 -191
- package/dist/stdio/index.d.ts +0 -5
- package/dist/stdio/index.js +0 -5
- package/dist/stdio/jsonRpcConnection.d.ts +0 -39
- package/dist/stdio/jsonRpcConnection.js +0 -135
- package/dist/stdio/protocol.d.ts +0 -41
- package/dist/stdio/protocol.js +0 -26
- package/dist/stdio/stdioServer.d.ts +0 -36
- package/dist/stdio/stdioServer.js +0 -51
- package/dist/stdio-cli.d.ts +0 -8
- package/dist/stdio-cli.js +0 -15
- package/dist/types.d.ts +0 -20
- package/dist/types.js +0 -1
- package/dist/utils/bracketedPaste.d.ts +0 -39
- package/dist/utils/bracketedPaste.js +0 -122
- package/dist/utils/clipboard.d.ts +0 -21
- package/dist/utils/clipboard.js +0 -347
- package/dist/utils/constants.d.ts +0 -16
- package/dist/utils/constants.js +0 -18
- package/dist/utils/highlightUtils.d.ts +0 -1
- package/dist/utils/highlightUtils.js +0 -93
- package/dist/utils/inputUtils.d.ts +0 -17
- package/dist/utils/inputUtils.js +0 -67
- package/dist/utils/logger.d.ts +0 -71
- package/dist/utils/logger.js +0 -259
- package/dist/utils/markdownTable.d.ts +0 -34
- package/dist/utils/markdownTable.js +0 -302
- package/dist/utils/rewindCheckpoints.d.ts +0 -8
- package/dist/utils/rewindCheckpoints.js +0 -17
- package/dist/utils/throttle.d.ts +0 -14
- package/dist/utils/throttle.js +0 -55
- package/dist/utils/toolParameterTransforms.d.ts +0 -18
- package/dist/utils/toolParameterTransforms.js +0 -73
- package/dist/utils/usageSummary.d.ts +0 -28
- package/dist/utils/usageSummary.js +0 -121
- package/dist/utils/version.d.ts +0 -1
- package/dist/utils/version.js +0 -4
- package/dist/utils/worktree.d.ts +0 -35
- package/dist/utils/worktree.js +0 -219
|
@@ -1,625 +0,0 @@
|
|
|
1
|
-
import { PromptHistoryManager } from "wave-agent-sdk";
|
|
2
|
-
import { readClipboardImage } from "../utils/clipboard.js";
|
|
3
|
-
export const expandLongTextPlaceholders = (text, longTextMap) => {
|
|
4
|
-
let expandedText = text;
|
|
5
|
-
const longTextRegex = /\[LongText#(\d+)\]/g;
|
|
6
|
-
const matches = [...text.matchAll(longTextRegex)];
|
|
7
|
-
for (const match of matches) {
|
|
8
|
-
const placeholder = match[0];
|
|
9
|
-
const originalText = longTextMap[placeholder];
|
|
10
|
-
if (originalText) {
|
|
11
|
-
expandedText = expandedText.replace(placeholder, originalText);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
return expandedText;
|
|
15
|
-
};
|
|
16
|
-
export const handleSubmit = async (state, dispatch, callbacks, attachedImagesOverride) => {
|
|
17
|
-
if (state.inputText.trim()) {
|
|
18
|
-
const imageRegex = /\[Image #(\d+)\]/g;
|
|
19
|
-
const matches = [...state.inputText.matchAll(imageRegex)];
|
|
20
|
-
const attachedImages = attachedImagesOverride || state.attachedImages;
|
|
21
|
-
const referencedImages = matches
|
|
22
|
-
.map((match) => {
|
|
23
|
-
const imageId = parseInt(match[1], 10);
|
|
24
|
-
return attachedImages.find((img) => img.id === imageId);
|
|
25
|
-
})
|
|
26
|
-
.filter((img) => img !== undefined)
|
|
27
|
-
.map((img) => ({ path: img.path, mimeType: img.mimeType }));
|
|
28
|
-
const contentWithPlaceholders = state.inputText
|
|
29
|
-
.replace(imageRegex, "")
|
|
30
|
-
.trim();
|
|
31
|
-
if (contentWithPlaceholders === "/btw" ||
|
|
32
|
-
contentWithPlaceholders.startsWith("/btw ")) {
|
|
33
|
-
const question = contentWithPlaceholders.startsWith("/btw ")
|
|
34
|
-
? contentWithPlaceholders.substring(5).trim()
|
|
35
|
-
: "";
|
|
36
|
-
if (question) {
|
|
37
|
-
dispatch({
|
|
38
|
-
type: "SET_BTW_STATE",
|
|
39
|
-
payload: {
|
|
40
|
-
question,
|
|
41
|
-
isLoading: true,
|
|
42
|
-
answer: undefined,
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
// Bare /btw — show usage (aligned with Claude Code)
|
|
48
|
-
dispatch({
|
|
49
|
-
type: "SET_BTW_STATE",
|
|
50
|
-
payload: {
|
|
51
|
-
question: "",
|
|
52
|
-
isLoading: false,
|
|
53
|
-
answer: "Usage: /btw <your question>",
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
dispatch({ type: "CLEAR_INPUT" });
|
|
58
|
-
dispatch({ type: "RESET_HISTORY_NAVIGATION" });
|
|
59
|
-
dispatch({ type: "CLEAR_LONG_TEXT_MAP" });
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
PromptHistoryManager.addEntry(contentWithPlaceholders, callbacks.sessionId, state.longTextMap, callbacks.workdir).catch((err) => {
|
|
63
|
-
callbacks.logger?.error("Failed to save prompt history", err);
|
|
64
|
-
});
|
|
65
|
-
callbacks.onSendMessage?.(contentWithPlaceholders, referencedImages.length > 0 ? referencedImages : undefined, state.longTextMap);
|
|
66
|
-
dispatch({ type: "CLEAR_INPUT" });
|
|
67
|
-
dispatch({ type: "RESET_HISTORY_NAVIGATION" });
|
|
68
|
-
dispatch({ type: "CLEAR_LONG_TEXT_MAP" });
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
export const handlePasteImage = async (dispatch) => {
|
|
72
|
-
try {
|
|
73
|
-
const result = await readClipboardImage();
|
|
74
|
-
if (result.success && result.imagePath && result.mimeType) {
|
|
75
|
-
dispatch({
|
|
76
|
-
type: "ADD_IMAGE_AND_INSERT_PLACEHOLDER",
|
|
77
|
-
payload: { path: result.imagePath, mimeType: result.mimeType },
|
|
78
|
-
});
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
catch (error) {
|
|
84
|
-
console.warn("Failed to paste image from clipboard:", error);
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
export const cyclePermissionMode = (currentMode, dispatch, callbacks) => {
|
|
89
|
-
const modes = [
|
|
90
|
-
"default",
|
|
91
|
-
"acceptEdits",
|
|
92
|
-
"bypassPermissions",
|
|
93
|
-
"plan",
|
|
94
|
-
];
|
|
95
|
-
const currentIndex = modes.indexOf(currentMode);
|
|
96
|
-
const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % modes.length;
|
|
97
|
-
const nextMode = modes[nextIndex];
|
|
98
|
-
callbacks.logger?.debug("Cycling permission mode", {
|
|
99
|
-
from: currentMode,
|
|
100
|
-
to: nextMode,
|
|
101
|
-
});
|
|
102
|
-
dispatch({ type: "SET_PERMISSION_MODE", payload: nextMode });
|
|
103
|
-
callbacks.onPermissionModeChange?.(nextMode);
|
|
104
|
-
};
|
|
105
|
-
const SELECTOR_TRIGGERS = [
|
|
106
|
-
{
|
|
107
|
-
char: "@",
|
|
108
|
-
type: "ACTIVATE_FILE_SELECTOR",
|
|
109
|
-
shouldActivate: (char, pos, text) => char === "@" && (pos === 1 || /\s/.test(text[pos - 2])),
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
char: "/",
|
|
113
|
-
type: "ACTIVATE_COMMAND_SELECTOR",
|
|
114
|
-
shouldActivate: (char, pos, text, state) => char === "/" &&
|
|
115
|
-
!state.showFileSelector &&
|
|
116
|
-
(pos === 1 || /\s/.test(text[pos - 2])),
|
|
117
|
-
},
|
|
118
|
-
];
|
|
119
|
-
const getProjectedState = (state, char) => {
|
|
120
|
-
const beforeCursor = state.inputText.substring(0, state.cursorPosition);
|
|
121
|
-
const afterCursor = state.inputText.substring(state.cursorPosition);
|
|
122
|
-
const newInputText = beforeCursor + char + afterCursor;
|
|
123
|
-
const newCursorPosition = state.cursorPosition + char.length;
|
|
124
|
-
return { newInputText, newCursorPosition };
|
|
125
|
-
};
|
|
126
|
-
export const getAtSelectorPosition = (text, cursorPosition) => {
|
|
127
|
-
let i = cursorPosition - 1;
|
|
128
|
-
while (i >= 0 && !/\s/.test(text[i])) {
|
|
129
|
-
if (text[i] === "@") {
|
|
130
|
-
// Check if this @ is at the start or preceded by whitespace
|
|
131
|
-
if (i === 0 || /\s/.test(text[i - 1])) {
|
|
132
|
-
return i;
|
|
133
|
-
}
|
|
134
|
-
break;
|
|
135
|
-
}
|
|
136
|
-
i--;
|
|
137
|
-
}
|
|
138
|
-
return -1;
|
|
139
|
-
};
|
|
140
|
-
export const getSlashSelectorPosition = (text, cursorPosition) => {
|
|
141
|
-
let i = cursorPosition - 1;
|
|
142
|
-
while (i >= 0 && !/\s/.test(text[i])) {
|
|
143
|
-
if (text[i] === "/") {
|
|
144
|
-
// Check if this / is at the start or preceded by whitespace
|
|
145
|
-
if (i === 0 || /\s/.test(text[i - 1])) {
|
|
146
|
-
return i;
|
|
147
|
-
}
|
|
148
|
-
break;
|
|
149
|
-
}
|
|
150
|
-
i--;
|
|
151
|
-
}
|
|
152
|
-
return -1;
|
|
153
|
-
};
|
|
154
|
-
export const updateSearchQueriesForActiveSelectors = (state, dispatch, inputText, cursorPosition) => {
|
|
155
|
-
if (state.showFileSelector && state.atPosition >= 0) {
|
|
156
|
-
const queryStart = state.atPosition + 1;
|
|
157
|
-
const queryEnd = cursorPosition;
|
|
158
|
-
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
159
|
-
dispatch({ type: "SET_FILE_SEARCH_QUERY", payload: newQuery });
|
|
160
|
-
}
|
|
161
|
-
else if (state.showCommandSelector && state.slashPosition >= 0) {
|
|
162
|
-
const queryStart = state.slashPosition + 1;
|
|
163
|
-
const queryEnd = cursorPosition;
|
|
164
|
-
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
165
|
-
dispatch({ type: "SET_COMMAND_SEARCH_QUERY", payload: newQuery });
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
export const processSelectorInput = (state, dispatch, char) => {
|
|
169
|
-
const { newInputText, newCursorPosition } = getProjectedState(state, char);
|
|
170
|
-
const trigger = SELECTOR_TRIGGERS.find((t) => t.shouldActivate(char, newCursorPosition, newInputText, state));
|
|
171
|
-
if (trigger) {
|
|
172
|
-
dispatch({
|
|
173
|
-
type: trigger.type,
|
|
174
|
-
payload: newCursorPosition - 1,
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
const atPos = getAtSelectorPosition(newInputText, newCursorPosition);
|
|
179
|
-
let showFileSelector = state.showFileSelector;
|
|
180
|
-
let atPosition = state.atPosition;
|
|
181
|
-
if (atPos !== -1 && !state.showFileSelector) {
|
|
182
|
-
dispatch({
|
|
183
|
-
type: "ACTIVATE_FILE_SELECTOR",
|
|
184
|
-
payload: atPos,
|
|
185
|
-
});
|
|
186
|
-
showFileSelector = true;
|
|
187
|
-
atPosition = atPos;
|
|
188
|
-
}
|
|
189
|
-
const slashPos = getSlashSelectorPosition(newInputText, newCursorPosition);
|
|
190
|
-
let showCommandSelector = state.showCommandSelector;
|
|
191
|
-
let slashPosition = state.slashPosition;
|
|
192
|
-
if (slashPos !== -1 && !state.showCommandSelector) {
|
|
193
|
-
dispatch({
|
|
194
|
-
type: "ACTIVATE_COMMAND_SELECTOR",
|
|
195
|
-
payload: slashPos,
|
|
196
|
-
});
|
|
197
|
-
showCommandSelector = true;
|
|
198
|
-
slashPosition = slashPos;
|
|
199
|
-
}
|
|
200
|
-
updateSearchQueriesForActiveSelectors({
|
|
201
|
-
...state,
|
|
202
|
-
showFileSelector,
|
|
203
|
-
atPosition,
|
|
204
|
-
showCommandSelector,
|
|
205
|
-
slashPosition,
|
|
206
|
-
}, dispatch, newInputText, newCursorPosition);
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
export const handlePasteInput = (state, dispatch, callbacks, input) => {
|
|
210
|
-
const inputString = input;
|
|
211
|
-
if (inputString.length > 1) {
|
|
212
|
-
// Multi-char chunk: insert immediately (\r → \n normalizes CRLF
|
|
213
|
-
// terminals), matching the reducer's HANDLE_KEY path.
|
|
214
|
-
dispatch({
|
|
215
|
-
type: "INSERT_TEXT_WITH_PLACEHOLDER",
|
|
216
|
-
payload: inputString.replace(/\r/g, "\n"),
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
else {
|
|
220
|
-
let char = inputString;
|
|
221
|
-
if (char === "!" && state.cursorPosition === 0) {
|
|
222
|
-
char = "!";
|
|
223
|
-
}
|
|
224
|
-
dispatch({ type: "INSERT_TEXT", payload: char });
|
|
225
|
-
processSelectorInput(state, dispatch, char);
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
export const getWordEnd = (text, startPos) => {
|
|
229
|
-
let i = startPos;
|
|
230
|
-
while (i < text.length && !/\s/.test(text[i])) {
|
|
231
|
-
i++;
|
|
232
|
-
}
|
|
233
|
-
return i;
|
|
234
|
-
};
|
|
235
|
-
export const handleCommandSelect = (state, dispatch, callbacks, command) => {
|
|
236
|
-
if (state.slashPosition >= 0) {
|
|
237
|
-
const wordEnd = getWordEnd(state.inputText, state.slashPosition);
|
|
238
|
-
const beforeSlash = state.inputText.substring(0, state.slashPosition);
|
|
239
|
-
const afterWord = state.inputText.substring(wordEnd);
|
|
240
|
-
const newInput = beforeSlash + afterWord;
|
|
241
|
-
const newCursorPosition = beforeSlash.length;
|
|
242
|
-
dispatch({ type: "SET_INPUT_TEXT", payload: newInput });
|
|
243
|
-
dispatch({ type: "SET_CURSOR_POSITION", payload: newCursorPosition });
|
|
244
|
-
// Execute command asynchronously
|
|
245
|
-
(async () => {
|
|
246
|
-
let commandExecuted = false;
|
|
247
|
-
if (callbacks.onSendMessage && callbacks.onHasSlashCommand?.(command)) {
|
|
248
|
-
const fullCommand = `/${command}`;
|
|
249
|
-
try {
|
|
250
|
-
await callbacks.onSendMessage(fullCommand, undefined, {});
|
|
251
|
-
commandExecuted = true;
|
|
252
|
-
}
|
|
253
|
-
catch (error) {
|
|
254
|
-
console.error("Failed to execute slash command:", error);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
if (!commandExecuted) {
|
|
258
|
-
if (command === "tasks") {
|
|
259
|
-
dispatch({
|
|
260
|
-
type: "SET_SHOW_BACKGROUND_TASK_MANAGER",
|
|
261
|
-
payload: true,
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
else if (command === "mcp") {
|
|
265
|
-
dispatch({ type: "SET_SHOW_MCP_MANAGER", payload: true });
|
|
266
|
-
}
|
|
267
|
-
else if (command === "agents") {
|
|
268
|
-
dispatch({ type: "SET_SHOW_AGENTS_MANAGER", payload: true });
|
|
269
|
-
}
|
|
270
|
-
else if (command === "rewind") {
|
|
271
|
-
dispatch({ type: "SET_SHOW_REWIND_MANAGER", payload: true });
|
|
272
|
-
}
|
|
273
|
-
else if (command === "help") {
|
|
274
|
-
dispatch({ type: "SET_SHOW_HELP", payload: true });
|
|
275
|
-
}
|
|
276
|
-
else if (command === "status") {
|
|
277
|
-
dispatch({ type: "SET_SHOW_STATUS_COMMAND", payload: true });
|
|
278
|
-
}
|
|
279
|
-
else if (command === "btw") {
|
|
280
|
-
// Bare /btw executed via the command selector — show usage
|
|
281
|
-
// (aligned with Claude Code's empty-args message).
|
|
282
|
-
dispatch({
|
|
283
|
-
type: "SET_BTW_STATE",
|
|
284
|
-
payload: {
|
|
285
|
-
question: "",
|
|
286
|
-
isLoading: false,
|
|
287
|
-
answer: "Usage: /btw <your question>",
|
|
288
|
-
},
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
else if (command === "plugin") {
|
|
292
|
-
dispatch({ type: "SET_SHOW_PLUGIN_MANAGER", payload: true });
|
|
293
|
-
}
|
|
294
|
-
else if (command === "model") {
|
|
295
|
-
dispatch({ type: "SET_SHOW_MODEL_SELECTOR", payload: true });
|
|
296
|
-
}
|
|
297
|
-
else if (command === "workflows") {
|
|
298
|
-
dispatch({ type: "SET_SHOW_WORKFLOW_MANAGER", payload: true });
|
|
299
|
-
}
|
|
300
|
-
else if (command === "clear") {
|
|
301
|
-
await callbacks.onClearMessages?.();
|
|
302
|
-
}
|
|
303
|
-
else if (command === "compact") {
|
|
304
|
-
await callbacks.onCompact?.();
|
|
305
|
-
}
|
|
306
|
-
else if (command === "add-dir") {
|
|
307
|
-
await callbacks.onAddDir?.();
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
})();
|
|
311
|
-
dispatch({ type: "CANCEL_COMMAND_SELECTOR" });
|
|
312
|
-
callbacks.onInputTextChange?.(newInput);
|
|
313
|
-
callbacks.onCursorPositionChange?.(newCursorPosition);
|
|
314
|
-
return { newInput, newCursorPosition };
|
|
315
|
-
}
|
|
316
|
-
return { newInput: state.inputText, newCursorPosition: state.cursorPosition };
|
|
317
|
-
};
|
|
318
|
-
export const handleFileSelect = (state, dispatch, callbacks, filePath) => {
|
|
319
|
-
if (state.atPosition >= 0) {
|
|
320
|
-
const wordEnd = getWordEnd(state.inputText, state.atPosition);
|
|
321
|
-
const beforeAt = state.inputText.substring(0, state.atPosition);
|
|
322
|
-
const afterWord = state.inputText.substring(wordEnd);
|
|
323
|
-
const newInput = beforeAt + `@${filePath} ` + afterWord;
|
|
324
|
-
const newCursorPosition = beforeAt.length + filePath.length + 2;
|
|
325
|
-
dispatch({ type: "SET_INPUT_TEXT", payload: newInput });
|
|
326
|
-
dispatch({ type: "SET_CURSOR_POSITION", payload: newCursorPosition });
|
|
327
|
-
dispatch({ type: "CANCEL_FILE_SELECTOR" });
|
|
328
|
-
callbacks.onInputTextChange?.(newInput);
|
|
329
|
-
callbacks.onCursorPositionChange?.(newCursorPosition);
|
|
330
|
-
return { newInput, newCursorPosition };
|
|
331
|
-
}
|
|
332
|
-
return { newInput: state.inputText, newCursorPosition: state.cursorPosition };
|
|
333
|
-
};
|
|
334
|
-
export const checkForAtDeletion = (state, dispatch, cursorPosition) => {
|
|
335
|
-
if (state.showFileSelector && cursorPosition <= state.atPosition) {
|
|
336
|
-
dispatch({ type: "CANCEL_FILE_SELECTOR" });
|
|
337
|
-
return true;
|
|
338
|
-
}
|
|
339
|
-
return false;
|
|
340
|
-
};
|
|
341
|
-
export const checkForSlashDeletion = (state, dispatch, cursorPosition) => {
|
|
342
|
-
if (state.showCommandSelector && cursorPosition <= state.slashPosition) {
|
|
343
|
-
dispatch({ type: "CANCEL_COMMAND_SELECTOR" });
|
|
344
|
-
return true;
|
|
345
|
-
}
|
|
346
|
-
return false;
|
|
347
|
-
};
|
|
348
|
-
export const handleSelectorInput = (state, dispatch, callbacks, input, key) => {
|
|
349
|
-
if (key.backspace || key.delete) {
|
|
350
|
-
if (state.cursorPosition > 0) {
|
|
351
|
-
const newCursorPosition = state.cursorPosition - 1;
|
|
352
|
-
const beforeCursor = state.inputText.substring(0, state.cursorPosition - 1);
|
|
353
|
-
const afterCursor = state.inputText.substring(state.cursorPosition);
|
|
354
|
-
const newInputText = beforeCursor + afterCursor;
|
|
355
|
-
dispatch({ type: "DELETE_CHAR" });
|
|
356
|
-
// Check for special character deletion
|
|
357
|
-
checkForAtDeletion(state, dispatch, newCursorPosition);
|
|
358
|
-
checkForSlashDeletion(state, dispatch, newCursorPosition);
|
|
359
|
-
// Update search queries
|
|
360
|
-
updateSearchQueriesForActiveSelectors(state, dispatch, newInputText, newCursorPosition);
|
|
361
|
-
}
|
|
362
|
-
return true;
|
|
363
|
-
}
|
|
364
|
-
if (key.upArrow || key.downArrow || key.return || key.tab) {
|
|
365
|
-
return true;
|
|
366
|
-
}
|
|
367
|
-
if (key.leftArrow) {
|
|
368
|
-
const newCursorPosition = state.cursorPosition - 1;
|
|
369
|
-
dispatch({ type: "MOVE_CURSOR", payload: -1 });
|
|
370
|
-
checkForAtDeletion(state, dispatch, newCursorPosition);
|
|
371
|
-
checkForSlashDeletion(state, dispatch, newCursorPosition);
|
|
372
|
-
return true;
|
|
373
|
-
}
|
|
374
|
-
if (key.rightArrow) {
|
|
375
|
-
const newCursorPosition = state.cursorPosition + 1;
|
|
376
|
-
dispatch({ type: "MOVE_CURSOR", payload: 1 });
|
|
377
|
-
checkForAtDeletion(state, dispatch, newCursorPosition);
|
|
378
|
-
checkForSlashDeletion(state, dispatch, newCursorPosition);
|
|
379
|
-
return true;
|
|
380
|
-
}
|
|
381
|
-
if (input === " ") {
|
|
382
|
-
if (state.showFileSelector) {
|
|
383
|
-
dispatch({ type: "CANCEL_FILE_SELECTOR" });
|
|
384
|
-
return false;
|
|
385
|
-
}
|
|
386
|
-
else if (state.showCommandSelector) {
|
|
387
|
-
dispatch({ type: "CANCEL_COMMAND_SELECTOR" });
|
|
388
|
-
return false;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
if (input &&
|
|
392
|
-
!key.ctrl &&
|
|
393
|
-
!("alt" in key && key.alt) &&
|
|
394
|
-
!key.meta &&
|
|
395
|
-
!key.return &&
|
|
396
|
-
!key.tab &&
|
|
397
|
-
!key.escape &&
|
|
398
|
-
!key.leftArrow &&
|
|
399
|
-
!key.rightArrow &&
|
|
400
|
-
!("home" in key && key.home) &&
|
|
401
|
-
!("end" in key && key.end)) {
|
|
402
|
-
dispatch({ type: "INSERT_TEXT", payload: input });
|
|
403
|
-
processSelectorInput(state, dispatch, input);
|
|
404
|
-
return true;
|
|
405
|
-
}
|
|
406
|
-
return false;
|
|
407
|
-
};
|
|
408
|
-
export const handleNormalInput = async (state, dispatch, callbacks, input, key, clearImages) => {
|
|
409
|
-
if (key.return) {
|
|
410
|
-
await handleSubmit(state, dispatch, callbacks);
|
|
411
|
-
clearImages?.();
|
|
412
|
-
return true;
|
|
413
|
-
}
|
|
414
|
-
if (key.escape) {
|
|
415
|
-
if (state.showFileSelector) {
|
|
416
|
-
dispatch({ type: "CANCEL_FILE_SELECTOR" });
|
|
417
|
-
}
|
|
418
|
-
else if (state.showCommandSelector) {
|
|
419
|
-
dispatch({ type: "CANCEL_COMMAND_SELECTOR" });
|
|
420
|
-
}
|
|
421
|
-
else if (state.historyIndex !== -1) {
|
|
422
|
-
dispatch({ type: "RESET_HISTORY_NAVIGATION" });
|
|
423
|
-
}
|
|
424
|
-
return true;
|
|
425
|
-
}
|
|
426
|
-
if (key.upArrow) {
|
|
427
|
-
if (state.history.length === 0) {
|
|
428
|
-
let sessionIds = callbacks.sessionId
|
|
429
|
-
? [callbacks.sessionId]
|
|
430
|
-
: undefined;
|
|
431
|
-
if (callbacks.getFullMessageThread) {
|
|
432
|
-
try {
|
|
433
|
-
const thread = await callbacks.getFullMessageThread();
|
|
434
|
-
sessionIds = thread.sessionIds;
|
|
435
|
-
}
|
|
436
|
-
catch (error) {
|
|
437
|
-
callbacks.logger?.error("Failed to fetch ancestor session IDs", error);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
const history = await PromptHistoryManager.getHistory({
|
|
441
|
-
sessionId: sessionIds,
|
|
442
|
-
workdir: callbacks.workdir,
|
|
443
|
-
});
|
|
444
|
-
dispatch({ type: "SET_HISTORY_ENTRIES", payload: history });
|
|
445
|
-
}
|
|
446
|
-
dispatch({ type: "NAVIGATE_HISTORY", payload: "up" });
|
|
447
|
-
return true;
|
|
448
|
-
}
|
|
449
|
-
if (key.downArrow) {
|
|
450
|
-
dispatch({ type: "NAVIGATE_HISTORY", payload: "down" });
|
|
451
|
-
return true;
|
|
452
|
-
}
|
|
453
|
-
if (key.backspace || key.delete) {
|
|
454
|
-
if (state.cursorPosition > 0) {
|
|
455
|
-
const newCursorPosition = state.cursorPosition - 1;
|
|
456
|
-
const beforeCursor = state.inputText.substring(0, state.cursorPosition - 1);
|
|
457
|
-
const afterCursor = state.inputText.substring(state.cursorPosition);
|
|
458
|
-
const newInputText = beforeCursor + afterCursor;
|
|
459
|
-
dispatch({ type: "DELETE_CHAR" });
|
|
460
|
-
checkForAtDeletion(state, dispatch, newCursorPosition);
|
|
461
|
-
checkForSlashDeletion(state, dispatch, newCursorPosition);
|
|
462
|
-
// Reactivate file selector if cursor is now within an @word
|
|
463
|
-
const atPos = getAtSelectorPosition(newInputText, newCursorPosition);
|
|
464
|
-
let showFileSelector = state.showFileSelector;
|
|
465
|
-
let atPosition = state.atPosition;
|
|
466
|
-
if (atPos !== -1 && !state.showFileSelector) {
|
|
467
|
-
dispatch({
|
|
468
|
-
type: "ACTIVATE_FILE_SELECTOR",
|
|
469
|
-
payload: atPos,
|
|
470
|
-
});
|
|
471
|
-
showFileSelector = true;
|
|
472
|
-
atPosition = atPos;
|
|
473
|
-
}
|
|
474
|
-
const slashPos = getSlashSelectorPosition(newInputText, newCursorPosition);
|
|
475
|
-
let showCommandSelector = state.showCommandSelector;
|
|
476
|
-
let slashPosition = state.slashPosition;
|
|
477
|
-
if (slashPos !== -1 && !state.showCommandSelector) {
|
|
478
|
-
dispatch({
|
|
479
|
-
type: "ACTIVATE_COMMAND_SELECTOR",
|
|
480
|
-
payload: slashPos,
|
|
481
|
-
});
|
|
482
|
-
showCommandSelector = true;
|
|
483
|
-
slashPosition = slashPos;
|
|
484
|
-
}
|
|
485
|
-
updateSearchQueriesForActiveSelectors({
|
|
486
|
-
...state,
|
|
487
|
-
inputText: newInputText,
|
|
488
|
-
cursorPosition: newCursorPosition,
|
|
489
|
-
showFileSelector,
|
|
490
|
-
atPosition,
|
|
491
|
-
showCommandSelector,
|
|
492
|
-
slashPosition,
|
|
493
|
-
}, dispatch, newInputText, newCursorPosition);
|
|
494
|
-
}
|
|
495
|
-
return true;
|
|
496
|
-
}
|
|
497
|
-
if (key.leftArrow) {
|
|
498
|
-
dispatch({ type: "MOVE_CURSOR", payload: -1 });
|
|
499
|
-
return true;
|
|
500
|
-
}
|
|
501
|
-
if (key.rightArrow) {
|
|
502
|
-
dispatch({ type: "MOVE_CURSOR", payload: 1 });
|
|
503
|
-
return true;
|
|
504
|
-
}
|
|
505
|
-
if (key.ctrl && input === "v") {
|
|
506
|
-
handlePasteImage(dispatch).catch((error) => {
|
|
507
|
-
console.warn("Failed to handle paste image:", error);
|
|
508
|
-
});
|
|
509
|
-
return true;
|
|
510
|
-
}
|
|
511
|
-
if (key.ctrl && input === "r") {
|
|
512
|
-
dispatch({ type: "ACTIVATE_HISTORY_SEARCH" });
|
|
513
|
-
return true;
|
|
514
|
-
}
|
|
515
|
-
if (key.ctrl && input === "b") {
|
|
516
|
-
callbacks.onBackgroundCurrentTask?.();
|
|
517
|
-
return true;
|
|
518
|
-
}
|
|
519
|
-
if (input &&
|
|
520
|
-
!key.ctrl &&
|
|
521
|
-
!("alt" in key && key.alt) &&
|
|
522
|
-
!key.meta &&
|
|
523
|
-
!key.return &&
|
|
524
|
-
!key.escape &&
|
|
525
|
-
!key.backspace &&
|
|
526
|
-
!key.delete &&
|
|
527
|
-
!key.leftArrow &&
|
|
528
|
-
!key.rightArrow &&
|
|
529
|
-
!("home" in key && key.home) &&
|
|
530
|
-
!("end" in key && key.end)) {
|
|
531
|
-
handlePasteInput(state, dispatch, callbacks, input);
|
|
532
|
-
return true;
|
|
533
|
-
}
|
|
534
|
-
return false;
|
|
535
|
-
};
|
|
536
|
-
export const handleInput = async (state, dispatch, callbacks, input, key, clearImages) => {
|
|
537
|
-
// /btw overlay handling (mirrors inputReducer's HANDLE_KEY block; this
|
|
538
|
-
// handler is not wired, kept in sync for consistency). Active while a
|
|
539
|
-
// question is displayed, or the bare-/btw usage message shows. Only
|
|
540
|
-
// Escape dismisses; every other key is ignored.
|
|
541
|
-
if (state.btwState.question || state.btwState.answer) {
|
|
542
|
-
if (key.escape) {
|
|
543
|
-
dispatch({
|
|
544
|
-
type: "SET_BTW_STATE",
|
|
545
|
-
payload: {
|
|
546
|
-
question: "",
|
|
547
|
-
answer: undefined,
|
|
548
|
-
isLoading: false,
|
|
549
|
-
},
|
|
550
|
-
});
|
|
551
|
-
return true;
|
|
552
|
-
}
|
|
553
|
-
// Any other key while the overlay is up is ignored
|
|
554
|
-
return true;
|
|
555
|
-
}
|
|
556
|
-
if (key.escape) {
|
|
557
|
-
if (!(state.showFileSelector ||
|
|
558
|
-
state.showCommandSelector ||
|
|
559
|
-
state.showHistorySearch ||
|
|
560
|
-
state.showBackgroundTaskManager ||
|
|
561
|
-
state.showMcpManager ||
|
|
562
|
-
state.showRewindManager ||
|
|
563
|
-
state.showHelp ||
|
|
564
|
-
state.showStatusCommand ||
|
|
565
|
-
state.showPluginManager ||
|
|
566
|
-
state.showModelSelector ||
|
|
567
|
-
state.showWorkflowManager)) {
|
|
568
|
-
callbacks.onAbortMessage?.();
|
|
569
|
-
return true;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
if (key.tab && key.shift) {
|
|
573
|
-
cyclePermissionMode(state.permissionMode, dispatch, callbacks);
|
|
574
|
-
return true;
|
|
575
|
-
}
|
|
576
|
-
if (state.showFileSelector ||
|
|
577
|
-
state.showCommandSelector ||
|
|
578
|
-
state.showHistorySearch ||
|
|
579
|
-
state.showBackgroundTaskManager ||
|
|
580
|
-
state.showMcpManager ||
|
|
581
|
-
state.showRewindManager ||
|
|
582
|
-
state.showHelp ||
|
|
583
|
-
state.showStatusCommand ||
|
|
584
|
-
state.showPluginManager ||
|
|
585
|
-
state.showModelSelector ||
|
|
586
|
-
state.showWorkflowManager) {
|
|
587
|
-
if (state.showBackgroundTaskManager ||
|
|
588
|
-
state.showMcpManager ||
|
|
589
|
-
state.showRewindManager ||
|
|
590
|
-
state.showHelp ||
|
|
591
|
-
state.showStatusCommand ||
|
|
592
|
-
state.showPluginManager ||
|
|
593
|
-
state.showModelSelector ||
|
|
594
|
-
state.showWorkflowManager) {
|
|
595
|
-
return true;
|
|
596
|
-
}
|
|
597
|
-
if (state.showHistorySearch) {
|
|
598
|
-
if (key.escape) {
|
|
599
|
-
dispatch({ type: "CANCEL_HISTORY_SEARCH" });
|
|
600
|
-
return true;
|
|
601
|
-
}
|
|
602
|
-
if (key.backspace || key.delete) {
|
|
603
|
-
if (state.historySearchQuery.length > 0) {
|
|
604
|
-
dispatch({
|
|
605
|
-
type: "SET_HISTORY_SEARCH_QUERY",
|
|
606
|
-
payload: state.historySearchQuery.slice(0, -1),
|
|
607
|
-
});
|
|
608
|
-
}
|
|
609
|
-
return true;
|
|
610
|
-
}
|
|
611
|
-
if (input && !key.ctrl && !key.meta && !key.return && !key.tab) {
|
|
612
|
-
dispatch({
|
|
613
|
-
type: "SET_HISTORY_SEARCH_QUERY",
|
|
614
|
-
payload: state.historySearchQuery + input,
|
|
615
|
-
});
|
|
616
|
-
return true;
|
|
617
|
-
}
|
|
618
|
-
return true;
|
|
619
|
-
}
|
|
620
|
-
return handleSelectorInput(state, dispatch, callbacks, input, key);
|
|
621
|
-
}
|
|
622
|
-
else {
|
|
623
|
-
return await handleNormalInput(state, dispatch, callbacks, input, key, clearImages);
|
|
624
|
-
}
|
|
625
|
-
};
|