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.
Files changed (242) hide show
  1. package/bin/wave-code.js +8 -2
  2. package/dist/bundle/wave.mjs +3207 -0
  3. package/package.json +24 -25
  4. package/src/commands/update.ts +2 -7
  5. package/src/components/App.tsx +3 -7
  6. package/src/components/BtwDisplay.tsx +10 -1
  7. package/src/components/ChatInterface.tsx +21 -52
  8. package/src/components/ConfirmationDetails.tsx +144 -37
  9. package/src/components/DiffDisplay.tsx +335 -301
  10. package/src/components/InputBox.tsx +3 -1
  11. package/src/components/LoadingIndicator.tsx +16 -2
  12. package/src/components/MessageBlockItem.tsx +2 -4
  13. package/src/components/MessageList.tsx +75 -14
  14. package/src/components/ReasoningDisplay.tsx +2 -4
  15. package/src/components/SessionSelector.tsx +82 -11
  16. package/src/components/StatusCommand.tsx +2 -9
  17. package/src/components/ToolDisplay.tsx +2 -4
  18. package/src/contexts/useChat.tsx +156 -335
  19. package/src/daemon/commands.ts +57 -27
  20. package/src/daemon/jsonRpcClient.ts +1 -1
  21. package/src/daemon/socketClient.ts +2 -2
  22. package/src/hooks/useInputManager.ts +1 -1
  23. package/src/index.ts +57 -10
  24. package/src/managers/inputReducer.ts +186 -104
  25. package/src/print-cli.ts +21 -17
  26. package/src/reducers/selectorReducer.ts +10 -0
  27. package/src/session-selector-cli.tsx +269 -28
  28. package/src/stdio/agentBridge.ts +22 -21
  29. package/src/stdio/daemonServer.ts +3 -1
  30. package/src/utils/clipboard.ts +21 -0
  31. package/src/utils/highlightUtils.ts +46 -1
  32. package/src/utils/readPackageJson.ts +29 -0
  33. package/src/utils/streamingText.ts +11 -0
  34. package/src/utils/worktree.ts +191 -43
  35. package/dist/cli.d.ts +0 -6
  36. package/dist/cli.js +0 -53
  37. package/dist/commands/plugin/disable.d.ts +0 -5
  38. package/dist/commands/plugin/disable.js +0 -15
  39. package/dist/commands/plugin/enable.d.ts +0 -5
  40. package/dist/commands/plugin/enable.js +0 -15
  41. package/dist/commands/plugin/install.d.ts +0 -5
  42. package/dist/commands/plugin/install.js +0 -21
  43. package/dist/commands/plugin/list.d.ts +0 -1
  44. package/dist/commands/plugin/list.js +0 -31
  45. package/dist/commands/plugin/marketplace.d.ts +0 -10
  46. package/dist/commands/plugin/marketplace.js +0 -90
  47. package/dist/commands/plugin/uninstall.d.ts +0 -3
  48. package/dist/commands/plugin/uninstall.js +0 -16
  49. package/dist/commands/plugin/update.d.ts +0 -3
  50. package/dist/commands/plugin/update.js +0 -15
  51. package/dist/commands/update.d.ts +0 -1
  52. package/dist/commands/update.js +0 -97
  53. package/dist/components/AgentsManager.d.ts +0 -7
  54. package/dist/components/AgentsManager.js +0 -109
  55. package/dist/components/App.d.ts +0 -9
  56. package/dist/components/App.js +0 -76
  57. package/dist/components/BackgroundTaskManager.d.ts +0 -5
  58. package/dist/components/BackgroundTaskManager.js +0 -99
  59. package/dist/components/BangDisplay.d.ts +0 -8
  60. package/dist/components/BangDisplay.js +0 -17
  61. package/dist/components/BtwDisplay.d.ts +0 -7
  62. package/dist/components/BtwDisplay.js +0 -19
  63. package/dist/components/ChatInterface.d.ts +0 -2
  64. package/dist/components/ChatInterface.js +0 -61
  65. package/dist/components/CommandSelector.d.ts +0 -10
  66. package/dist/components/CommandSelector.js +0 -66
  67. package/dist/components/CompactDisplay.d.ts +0 -8
  68. package/dist/components/CompactDisplay.js +0 -13
  69. package/dist/components/ConfirmationDetails.d.ts +0 -9
  70. package/dist/components/ConfirmationDetails.js +0 -45
  71. package/dist/components/ConfirmationSelector.d.ts +0 -13
  72. package/dist/components/ConfirmationSelector.js +0 -127
  73. package/dist/components/DiffDisplay.d.ts +0 -8
  74. package/dist/components/DiffDisplay.js +0 -201
  75. package/dist/components/DiscoverView.d.ts +0 -2
  76. package/dist/components/DiscoverView.js +0 -37
  77. package/dist/components/FileSelector.d.ts +0 -11
  78. package/dist/components/FileSelector.js +0 -50
  79. package/dist/components/HelpView.d.ts +0 -7
  80. package/dist/components/HelpView.js +0 -74
  81. package/dist/components/HistorySearch.d.ts +0 -8
  82. package/dist/components/HistorySearch.js +0 -66
  83. package/dist/components/InputBox.d.ts +0 -24
  84. package/dist/components/InputBox.js +0 -149
  85. package/dist/components/InstalledView.d.ts +0 -2
  86. package/dist/components/InstalledView.js +0 -45
  87. package/dist/components/LoadingIndicator.d.ts +0 -10
  88. package/dist/components/LoadingIndicator.js +0 -6
  89. package/dist/components/LoginCommand.d.ts +0 -5
  90. package/dist/components/LoginCommand.js +0 -153
  91. package/dist/components/Markdown.d.ts +0 -5
  92. package/dist/components/Markdown.js +0 -127
  93. package/dist/components/MarketplaceAddForm.d.ts +0 -2
  94. package/dist/components/MarketplaceAddForm.js +0 -55
  95. package/dist/components/MarketplaceDetail.d.ts +0 -2
  96. package/dist/components/MarketplaceDetail.js +0 -74
  97. package/dist/components/MarketplaceList.d.ts +0 -8
  98. package/dist/components/MarketplaceList.js +0 -17
  99. package/dist/components/MarketplaceView.d.ts +0 -2
  100. package/dist/components/MarketplaceView.js +0 -41
  101. package/dist/components/McpManager.d.ts +0 -9
  102. package/dist/components/McpManager.js +0 -88
  103. package/dist/components/MessageBlockItem.d.ts +0 -8
  104. package/dist/components/MessageBlockItem.js +0 -15
  105. package/dist/components/MessageList.d.ts +0 -10
  106. package/dist/components/MessageList.js +0 -80
  107. package/dist/components/ModelSelector.d.ts +0 -8
  108. package/dist/components/ModelSelector.js +0 -45
  109. package/dist/components/Notifications.d.ts +0 -7
  110. package/dist/components/Notifications.js +0 -9
  111. package/dist/components/PlanDisplay.d.ts +0 -7
  112. package/dist/components/PlanDisplay.js +0 -6
  113. package/dist/components/PluginDetail.d.ts +0 -2
  114. package/dist/components/PluginDetail.js +0 -87
  115. package/dist/components/PluginList.d.ts +0 -13
  116. package/dist/components/PluginList.js +0 -15
  117. package/dist/components/PluginManagerShell.d.ts +0 -6
  118. package/dist/components/PluginManagerShell.js +0 -92
  119. package/dist/components/PluginManagerTypes.d.ts +0 -35
  120. package/dist/components/PluginManagerTypes.js +0 -1
  121. package/dist/components/QueuedMessageList.d.ts +0 -2
  122. package/dist/components/QueuedMessageList.js +0 -18
  123. package/dist/components/ReasoningDisplay.d.ts +0 -8
  124. package/dist/components/ReasoningDisplay.js +0 -13
  125. package/dist/components/RewindCommand.d.ts +0 -12
  126. package/dist/components/RewindCommand.js +0 -78
  127. package/dist/components/SessionSelector.d.ts +0 -12
  128. package/dist/components/SessionSelector.js +0 -47
  129. package/dist/components/StatusCommand.d.ts +0 -5
  130. package/dist/components/StatusCommand.js +0 -28
  131. package/dist/components/StatusLine.d.ts +0 -6
  132. package/dist/components/StatusLine.js +0 -9
  133. package/dist/components/TaskList.d.ts +0 -5
  134. package/dist/components/TaskList.js +0 -197
  135. package/dist/components/TaskNotificationMessage.d.ts +0 -5
  136. package/dist/components/TaskNotificationMessage.js +0 -12
  137. package/dist/components/ToolDisplay.d.ts +0 -9
  138. package/dist/components/ToolDisplay.js +0 -55
  139. package/dist/components/WorkflowManager.d.ts +0 -5
  140. package/dist/components/WorkflowManager.js +0 -102
  141. package/dist/components/WorktreeExitPrompt.d.ts +0 -12
  142. package/dist/components/WorktreeExitPrompt.js +0 -35
  143. package/dist/constants/commands.d.ts +0 -2
  144. package/dist/constants/commands.js +0 -92
  145. package/dist/contexts/PluginManagerContext.d.ts +0 -3
  146. package/dist/contexts/PluginManagerContext.js +0 -9
  147. package/dist/contexts/useAppConfig.d.ts +0 -10
  148. package/dist/contexts/useAppConfig.js +0 -13
  149. package/dist/contexts/useChat.d.ts +0 -101
  150. package/dist/contexts/useChat.js +0 -993
  151. package/dist/contracts/status.d.ts +0 -7
  152. package/dist/contracts/status.js +0 -1
  153. package/dist/daemon/commands.d.ts +0 -49
  154. package/dist/daemon/commands.js +0 -341
  155. package/dist/daemon/jsonRpcClient.d.ts +0 -38
  156. package/dist/daemon/jsonRpcClient.js +0 -129
  157. package/dist/daemon/socketClient.d.ts +0 -13
  158. package/dist/daemon/socketClient.js +0 -26
  159. package/dist/daemon-cli.d.ts +0 -10
  160. package/dist/daemon-cli.js +0 -15
  161. package/dist/hooks/useInputManager.d.ts +0 -75
  162. package/dist/hooks/useInputManager.js +0 -583
  163. package/dist/hooks/usePluginManager.d.ts +0 -4
  164. package/dist/hooks/usePluginManager.js +0 -265
  165. package/dist/hooks/useTasks.d.ts +0 -1
  166. package/dist/hooks/useTasks.js +0 -5
  167. package/dist/index.d.ts +0 -4
  168. package/dist/index.js +0 -447
  169. package/dist/managers/inputHandlers.d.ts +0 -30
  170. package/dist/managers/inputHandlers.js +0 -625
  171. package/dist/managers/inputReducer.d.ts +0 -271
  172. package/dist/managers/inputReducer.js +0 -1121
  173. package/dist/plugin-manager-cli.d.ts +0 -5
  174. package/dist/plugin-manager-cli.js +0 -12
  175. package/dist/print-cli.d.ts +0 -10
  176. package/dist/print-cli.js +0 -209
  177. package/dist/reducers/agentsManagerReducer.d.ts +0 -26
  178. package/dist/reducers/agentsManagerReducer.js +0 -54
  179. package/dist/reducers/backgroundTaskManagerReducer.d.ts +0 -62
  180. package/dist/reducers/backgroundTaskManagerReducer.js +0 -106
  181. package/dist/reducers/confirmationReducer.d.ts +0 -37
  182. package/dist/reducers/confirmationReducer.js +0 -193
  183. package/dist/reducers/helpSelectorReducer.d.ts +0 -25
  184. package/dist/reducers/helpSelectorReducer.js +0 -52
  185. package/dist/reducers/marketplaceAddFormReducer.d.ts +0 -24
  186. package/dist/reducers/marketplaceAddFormReducer.js +0 -58
  187. package/dist/reducers/mcpManagerReducer.d.ts +0 -37
  188. package/dist/reducers/mcpManagerReducer.js +0 -74
  189. package/dist/reducers/pluginDetailReducer.d.ts +0 -32
  190. package/dist/reducers/pluginDetailReducer.js +0 -70
  191. package/dist/reducers/questionReducer.d.ts +0 -82
  192. package/dist/reducers/questionReducer.js +0 -375
  193. package/dist/reducers/rewindSelectorReducer.d.ts +0 -21
  194. package/dist/reducers/rewindSelectorReducer.js +0 -37
  195. package/dist/reducers/selectorReducer.d.ts +0 -23
  196. package/dist/reducers/selectorReducer.js +0 -42
  197. package/dist/reducers/workflowManagerReducer.d.ts +0 -40
  198. package/dist/reducers/workflowManagerReducer.js +0 -100
  199. package/dist/session-selector-cli.d.ts +0 -3
  200. package/dist/session-selector-cli.js +0 -25
  201. package/dist/stdio/agentBridge.d.ts +0 -139
  202. package/dist/stdio/agentBridge.js +0 -999
  203. package/dist/stdio/daemonServer.d.ts +0 -67
  204. package/dist/stdio/daemonServer.js +0 -191
  205. package/dist/stdio/index.d.ts +0 -5
  206. package/dist/stdio/index.js +0 -5
  207. package/dist/stdio/jsonRpcConnection.d.ts +0 -39
  208. package/dist/stdio/jsonRpcConnection.js +0 -135
  209. package/dist/stdio/protocol.d.ts +0 -41
  210. package/dist/stdio/protocol.js +0 -26
  211. package/dist/stdio/stdioServer.d.ts +0 -36
  212. package/dist/stdio/stdioServer.js +0 -51
  213. package/dist/stdio-cli.d.ts +0 -8
  214. package/dist/stdio-cli.js +0 -15
  215. package/dist/types.d.ts +0 -20
  216. package/dist/types.js +0 -1
  217. package/dist/utils/bracketedPaste.d.ts +0 -39
  218. package/dist/utils/bracketedPaste.js +0 -122
  219. package/dist/utils/clipboard.d.ts +0 -21
  220. package/dist/utils/clipboard.js +0 -347
  221. package/dist/utils/constants.d.ts +0 -16
  222. package/dist/utils/constants.js +0 -18
  223. package/dist/utils/highlightUtils.d.ts +0 -1
  224. package/dist/utils/highlightUtils.js +0 -93
  225. package/dist/utils/inputUtils.d.ts +0 -17
  226. package/dist/utils/inputUtils.js +0 -67
  227. package/dist/utils/logger.d.ts +0 -71
  228. package/dist/utils/logger.js +0 -259
  229. package/dist/utils/markdownTable.d.ts +0 -34
  230. package/dist/utils/markdownTable.js +0 -302
  231. package/dist/utils/rewindCheckpoints.d.ts +0 -8
  232. package/dist/utils/rewindCheckpoints.js +0 -17
  233. package/dist/utils/throttle.d.ts +0 -14
  234. package/dist/utils/throttle.js +0 -55
  235. package/dist/utils/toolParameterTransforms.d.ts +0 -18
  236. package/dist/utils/toolParameterTransforms.js +0 -73
  237. package/dist/utils/usageSummary.d.ts +0 -28
  238. package/dist/utils/usageSummary.js +0 -121
  239. package/dist/utils/version.d.ts +0 -1
  240. package/dist/utils/version.js +0 -4
  241. package/dist/utils/worktree.d.ts +0 -35
  242. 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
- };