@google/gemini-cli 0.12.0-nightly.20251023.c4c0c0d1 → 0.12.0-preview.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 (248) hide show
  1. package/README.md +7 -5
  2. package/dist/package.json +3 -3
  3. package/dist/src/commands/extensions/disable.d.ts +1 -1
  4. package/dist/src/commands/extensions/disable.js +5 -4
  5. package/dist/src/commands/extensions/disable.js.map +1 -1
  6. package/dist/src/commands/extensions/enable.d.ts +1 -1
  7. package/dist/src/commands/extensions/enable.js +3 -2
  8. package/dist/src/commands/extensions/enable.js.map +1 -1
  9. package/dist/src/commands/extensions/install.js +2 -1
  10. package/dist/src/commands/extensions/install.js.map +1 -1
  11. package/dist/src/commands/extensions/install.test.js +1 -0
  12. package/dist/src/commands/extensions/install.test.js.map +1 -1
  13. package/dist/src/commands/extensions/link.js +2 -1
  14. package/dist/src/commands/extensions/link.js.map +1 -1
  15. package/dist/src/commands/extensions/list.js +2 -2
  16. package/dist/src/commands/extensions/list.js.map +1 -1
  17. package/dist/src/commands/extensions/uninstall.js +2 -1
  18. package/dist/src/commands/extensions/uninstall.js.map +1 -1
  19. package/dist/src/commands/extensions/update.js +2 -2
  20. package/dist/src/commands/extensions/update.js.map +1 -1
  21. package/dist/src/commands/mcp/list.js +2 -2
  22. package/dist/src/commands/mcp/list.js.map +1 -1
  23. package/dist/src/config/config.d.ts +6 -3
  24. package/dist/src/config/config.js +56 -11
  25. package/dist/src/config/config.js.map +1 -1
  26. package/dist/src/config/config.test.js +208 -175
  27. package/dist/src/config/config.test.js.map +1 -1
  28. package/dist/src/config/extension-manager.d.ts +23 -10
  29. package/dist/src/config/extension-manager.js +90 -64
  30. package/dist/src/config/extension-manager.js.map +1 -1
  31. package/dist/src/config/extension.test.js +183 -76
  32. package/dist/src/config/extension.test.js.map +1 -1
  33. package/dist/src/config/extensions/extensionEnablement.d.ts +1 -1
  34. package/dist/src/config/extensions/extensionEnablement.js +3 -2
  35. package/dist/src/config/extensions/extensionEnablement.js.map +1 -1
  36. package/dist/src/config/extensions/extensionEnablement.test.js +10 -10
  37. package/dist/src/config/extensions/extensionEnablement.test.js.map +1 -1
  38. package/dist/src/config/extensions/extensionSettings.d.ts +3 -3
  39. package/dist/src/config/extensions/extensionSettings.js +74 -24
  40. package/dist/src/config/extensions/extensionSettings.js.map +1 -1
  41. package/dist/src/config/extensions/extensionSettings.test.js +145 -24
  42. package/dist/src/config/extensions/extensionSettings.test.js.map +1 -1
  43. package/dist/src/config/extensions/github.js +3 -3
  44. package/dist/src/config/extensions/github.js.map +1 -1
  45. package/dist/src/config/extensions/github.test.js +1 -1
  46. package/dist/src/config/extensions/github.test.js.map +1 -1
  47. package/dist/src/config/extensions/github_fetch.d.ts +1 -1
  48. package/dist/src/config/extensions/github_fetch.js +13 -1
  49. package/dist/src/config/extensions/github_fetch.js.map +1 -1
  50. package/dist/src/config/extensions/github_fetch.test.d.ts +6 -0
  51. package/dist/src/config/extensions/github_fetch.test.js +169 -0
  52. package/dist/src/config/extensions/github_fetch.test.js.map +1 -0
  53. package/dist/src/config/extensions/update.js +7 -6
  54. package/dist/src/config/extensions/update.js.map +1 -1
  55. package/dist/src/config/extensions/update.test.js +54 -30
  56. package/dist/src/config/extensions/update.test.js.map +1 -1
  57. package/dist/src/config/keyBindings.js +1 -1
  58. package/dist/src/config/keyBindings.js.map +1 -1
  59. package/dist/src/config/policies/read-only.toml +56 -0
  60. package/dist/src/config/policies/write.toml +63 -0
  61. package/dist/src/config/policies/yolo.toml +31 -0
  62. package/dist/src/config/policy-engine.integration.test.js +41 -38
  63. package/dist/src/config/policy-engine.integration.test.js.map +1 -1
  64. package/dist/src/config/policy-toml-loader.d.ts +46 -0
  65. package/dist/src/config/policy-toml-loader.js +314 -0
  66. package/dist/src/config/policy-toml-loader.js.map +1 -0
  67. package/dist/src/config/policy-toml-loader.test.d.ts +6 -0
  68. package/dist/src/config/policy-toml-loader.test.js +626 -0
  69. package/dist/src/config/policy-toml-loader.test.js.map +1 -0
  70. package/dist/src/config/policy.d.ts +9 -2
  71. package/dist/src/config/policy.js +139 -110
  72. package/dist/src/config/policy.js.map +1 -1
  73. package/dist/src/config/policy.test.js +780 -82
  74. package/dist/src/config/policy.test.js.map +1 -1
  75. package/dist/src/config/settings.test.js +6 -6
  76. package/dist/src/config/settings.test.js.map +1 -1
  77. package/dist/src/core/initializer.js +2 -1
  78. package/dist/src/core/initializer.js.map +1 -1
  79. package/dist/src/gemini.js +6 -17
  80. package/dist/src/gemini.js.map +1 -1
  81. package/dist/src/gemini.test.js +27 -2
  82. package/dist/src/gemini.test.js.map +1 -1
  83. package/dist/src/generated/git-commit.d.ts +2 -2
  84. package/dist/src/generated/git-commit.js +2 -2
  85. package/dist/src/generated/git-commit.js.map +1 -1
  86. package/dist/src/nonInteractiveCli.js +16 -4
  87. package/dist/src/nonInteractiveCli.js.map +1 -1
  88. package/dist/src/nonInteractiveCli.test.js +67 -12
  89. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  90. package/dist/src/test-utils/render.d.ts +12 -0
  91. package/dist/src/test-utils/render.js +28 -1
  92. package/dist/src/test-utils/render.js.map +1 -1
  93. package/dist/src/test-utils/render.test.d.ts +6 -0
  94. package/dist/src/test-utils/render.test.js +54 -0
  95. package/dist/src/test-utils/render.test.js.map +1 -0
  96. package/dist/src/ui/AppContainer.js +29 -23
  97. package/dist/src/ui/AppContainer.js.map +1 -1
  98. package/dist/src/ui/AppContainer.test.js +8 -0
  99. package/dist/src/ui/AppContainer.test.js.map +1 -1
  100. package/dist/src/ui/commands/directoryCommand.js +1 -1
  101. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  102. package/dist/src/ui/commands/extensionsCommand.js +45 -1
  103. package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
  104. package/dist/src/ui/commands/extensionsCommand.test.js +64 -1
  105. package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -1
  106. package/dist/src/ui/commands/memoryCommand.js +1 -1
  107. package/dist/src/ui/commands/memoryCommand.js.map +1 -1
  108. package/dist/src/ui/commands/memoryCommand.test.js +3 -1
  109. package/dist/src/ui/commands/memoryCommand.test.js.map +1 -1
  110. package/dist/src/ui/components/ConsoleSummaryDisplay.js +1 -1
  111. package/dist/src/ui/components/ConsoleSummaryDisplay.js.map +1 -1
  112. package/dist/src/ui/components/DetailedMessagesDisplay.js +1 -1
  113. package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
  114. package/dist/src/ui/components/FolderTrustDialog.test.js +4 -4
  115. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  116. package/dist/src/ui/components/Footer.js +1 -1
  117. package/dist/src/ui/components/Footer.js.map +1 -1
  118. package/dist/src/ui/components/Footer.test.js +24 -0
  119. package/dist/src/ui/components/Footer.test.js.map +1 -1
  120. package/dist/src/ui/components/Help.test.js +0 -1
  121. package/dist/src/ui/components/Help.test.js.map +1 -1
  122. package/dist/src/ui/components/InputPrompt.test.js +442 -342
  123. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  124. package/dist/src/ui/components/ModelDialog.test.js +5 -5
  125. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  126. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +11 -12
  127. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
  128. package/dist/src/ui/components/SettingsDialog.test.js +13 -14
  129. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  130. package/dist/src/ui/components/ThemeDialog.test.js +1 -2
  131. package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
  132. package/dist/src/ui/components/shared/BaseSelectionList.test.js +11 -12
  133. package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
  134. package/dist/src/ui/components/shared/text-buffer.test.js +2 -1
  135. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
  136. package/dist/src/ui/components/views/ExtensionsList.d.ts +1 -1
  137. package/dist/src/ui/components/views/ExtensionsList.js +4 -1
  138. package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
  139. package/dist/src/ui/contexts/KeypressContext.d.ts +3 -2
  140. package/dist/src/ui/contexts/KeypressContext.js +114 -64
  141. package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
  142. package/dist/src/ui/contexts/KeypressContext.test.js +166 -482
  143. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  144. package/dist/src/ui/contexts/SessionContext.test.js +27 -13
  145. package/dist/src/ui/contexts/SessionContext.test.js.map +1 -1
  146. package/dist/src/ui/hooks/atCommandProcessor.js +2 -2
  147. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  148. package/dist/src/ui/hooks/shellCommandProcessor.test.js +18 -2
  149. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
  150. package/dist/src/ui/hooks/slashCommandProcessor.test.js +74 -80
  151. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
  152. package/dist/src/ui/hooks/useAtCompletion.test.js +32 -23
  153. package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -1
  154. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +2 -1
  155. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -1
  156. package/dist/src/ui/hooks/useCommandCompletion.test.js +79 -78
  157. package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
  158. package/dist/src/ui/hooks/useConsoleMessages.test.js +26 -9
  159. package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -1
  160. package/dist/src/ui/hooks/useEditorSettings.test.js +40 -34
  161. package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
  162. package/dist/src/ui/hooks/useExtensionUpdates.d.ts +1 -2
  163. package/dist/src/ui/hooks/useExtensionUpdates.js +4 -2
  164. package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
  165. package/dist/src/ui/hooks/useExtensionUpdates.test.js +37 -26
  166. package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
  167. package/dist/src/ui/hooks/useFlickerDetector.test.js +9 -5
  168. package/dist/src/ui/hooks/useFlickerDetector.test.js.map +1 -1
  169. package/dist/src/ui/hooks/useFocus.test.js +25 -9
  170. package/dist/src/ui/hooks/useFocus.test.js.map +1 -1
  171. package/dist/src/ui/hooks/useFolderTrust.test.js +45 -22
  172. package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
  173. package/dist/src/ui/hooks/useGeminiStream.js +56 -19
  174. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  175. package/dist/src/ui/hooks/useGeminiStream.test.js +155 -74
  176. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  177. package/dist/src/ui/hooks/useGitBranchName.test.js +29 -16
  178. package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
  179. package/dist/src/ui/hooks/useHistoryManager.test.js +2 -1
  180. package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -1
  181. package/dist/src/ui/hooks/useIdeTrustListener.test.js +24 -7
  182. package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -1
  183. package/dist/src/ui/hooks/useInputHistory.test.js +2 -1
  184. package/dist/src/ui/hooks/useInputHistory.test.js.map +1 -1
  185. package/dist/src/ui/hooks/useInputHistoryStore.test.js +2 -1
  186. package/dist/src/ui/hooks/useInputHistoryStore.test.js.map +1 -1
  187. package/dist/src/ui/hooks/useKeypress.test.js +94 -113
  188. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
  189. package/dist/src/ui/hooks/useLoadingIndicator.test.js +24 -6
  190. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  191. package/dist/src/ui/hooks/useMemoryMonitor.test.js +10 -5
  192. package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -1
  193. package/dist/src/ui/hooks/useMessageQueue.test.js +61 -45
  194. package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
  195. package/dist/src/ui/hooks/useModelCommand.test.js +18 -11
  196. package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -1
  197. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js +2 -2
  198. package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js.map +1 -1
  199. package/dist/src/ui/hooks/usePhraseCycler.js +1 -1
  200. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  201. package/dist/src/ui/hooks/usePhraseCycler.test.js +83 -110
  202. package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
  203. package/dist/src/ui/hooks/usePrivacySettings.test.js +26 -10
  204. package/dist/src/ui/hooks/usePrivacySettings.test.js.map +1 -1
  205. package/dist/src/ui/hooks/useQuotaAndFallback.js +13 -14
  206. package/dist/src/ui/hooks/useQuotaAndFallback.js.map +1 -1
  207. package/dist/src/ui/hooks/useQuotaAndFallback.test.js +33 -40
  208. package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
  209. package/dist/src/ui/hooks/useReactToolScheduler.d.ts +8 -1
  210. package/dist/src/ui/hooks/useReactToolScheduler.js +37 -26
  211. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
  212. package/dist/src/ui/hooks/useReactToolScheduler.test.js +1 -1
  213. package/dist/src/ui/hooks/useReactToolScheduler.test.js.map +1 -1
  214. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +2 -2
  215. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -1
  216. package/dist/src/ui/hooks/useSelectionList.test.js +193 -132
  217. package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
  218. package/dist/src/ui/hooks/useShellHistory.test.js +40 -16
  219. package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
  220. package/dist/src/ui/hooks/useSlashCompletion.test.js +54 -49
  221. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  222. package/dist/src/ui/hooks/useTimer.test.js +43 -14
  223. package/dist/src/ui/hooks/useTimer.test.js.map +1 -1
  224. package/dist/src/ui/hooks/useToolScheduler.test.js +163 -74
  225. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  226. package/dist/src/ui/hooks/vim.test.js +251 -356
  227. package/dist/src/ui/hooks/vim.test.js.map +1 -1
  228. package/dist/src/ui/keyMatchers.test.js +3 -3
  229. package/dist/src/ui/keyMatchers.test.js.map +1 -1
  230. package/dist/src/ui/utils/textOutput.d.ts +25 -0
  231. package/dist/src/ui/utils/textOutput.js +49 -0
  232. package/dist/src/ui/utils/textOutput.js.map +1 -0
  233. package/dist/src/ui/utils/textOutput.test.d.ts +6 -0
  234. package/dist/src/ui/utils/textOutput.test.js +79 -0
  235. package/dist/src/ui/utils/textOutput.test.js.map +1 -0
  236. package/dist/src/ui/utils/updateCheck.d.ts +7 -1
  237. package/dist/src/ui/utils/updateCheck.js +27 -26
  238. package/dist/src/ui/utils/updateCheck.js.map +1 -1
  239. package/dist/src/ui/utils/updateCheck.test.js +19 -49
  240. package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
  241. package/dist/src/utils/handleAutoUpdate.js +9 -3
  242. package/dist/src/utils/handleAutoUpdate.js.map +1 -1
  243. package/dist/src/zed-integration/zedIntegration.d.ts +2 -2
  244. package/dist/src/zed-integration/zedIntegration.js +9 -16
  245. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  246. package/dist/tsconfig.tsbuildinfo +1 -1
  247. package/package.json +4 -4
  248. package/dist/google-gemini-cli-0.12.0-nightly.20251022.0542de95.tgz +0 -0
@@ -4,12 +4,13 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  import { describe, it, expect, vi, beforeEach } from 'vitest';
7
- import { renderHook, act, waitFor } from '@testing-library/react';
7
+ import { act } from 'react';
8
+ import { renderHook } from '../../test-utils/render.js';
8
9
  import { useGeminiStream } from './useGeminiStream.js';
9
10
  import { useKeypress } from './useKeypress.js';
10
11
  import * as atCommandProcessor from './atCommandProcessor.js';
11
12
  import { useReactToolScheduler } from './useReactToolScheduler.js';
12
- import { ApprovalMode, AuthType, GeminiEventType as ServerGeminiEventType, ToolErrorType, ToolConfirmationOutcome, tokenLimit, } from '@google/gemini-cli-core';
13
+ import { ApprovalMode, AuthType, GeminiEventType as ServerGeminiEventType, ToolErrorType, ToolConfirmationOutcome, tokenLimit, debugLogger, } from '@google/gemini-cli-core';
13
14
  import { MessageType, StreamingState } from '../types.js';
14
15
  // --- MOCKS ---
15
16
  const mockSendMessageStream = vi
@@ -175,8 +176,9 @@ describe('useGeminiStream', () => {
175
176
  mockUseReactToolScheduler.mockReturnValue([
176
177
  [], // Default to empty array for toolCalls
177
178
  mockScheduleToolCalls,
178
- mockCancelAllToolCalls,
179
179
  mockMarkToolsAsSubmitted,
180
+ vi.fn(), // setToolCallsForDisplay
181
+ mockCancelAllToolCalls,
180
182
  ]);
181
183
  // Reset mocks for GeminiClient instance methods (startChat and sendMessageStream)
182
184
  // The GeminiClient constructor itself is mocked at the module level.
@@ -197,35 +199,62 @@ describe('useGeminiStream', () => {
197
199
  setValue: vi.fn(),
198
200
  };
199
201
  const renderTestHook = (initialToolCalls = [], geminiClient) => {
200
- let currentToolCalls = initialToolCalls;
201
- const setToolCalls = (newToolCalls) => {
202
- currentToolCalls = newToolCalls;
203
- };
204
- mockUseReactToolScheduler.mockImplementation(() => [
205
- currentToolCalls,
206
- mockScheduleToolCalls,
207
- mockCancelAllToolCalls,
208
- mockMarkToolsAsSubmitted,
209
- ]);
210
202
  const client = geminiClient || mockConfig.getGeminiClient();
203
+ const initialProps = {
204
+ client,
205
+ history: [],
206
+ addItem: mockAddItem,
207
+ config: mockConfig,
208
+ onDebugMessage: mockOnDebugMessage,
209
+ handleSlashCommand: mockHandleSlashCommand,
210
+ shellModeActive: false,
211
+ loadedSettings: mockLoadedSettings,
212
+ toolCalls: initialToolCalls,
213
+ };
211
214
  const { result, rerender } = renderHook((props) => {
212
- // Update the mock's return value if new toolCalls are passed in props
213
- if (props.toolCalls) {
214
- setToolCalls(props.toolCalls);
215
- }
215
+ // This mock needs to be stateful. When setToolCallsForDisplay is called,
216
+ // it should trigger a rerender with the new state.
217
+ const mockSetToolCallsForDisplay = vi.fn((updater) => {
218
+ const newToolCalls = typeof updater === 'function' ? updater(props.toolCalls) : updater;
219
+ rerender({ ...props, toolCalls: newToolCalls });
220
+ });
221
+ // Create a stateful mock for cancellation that updates the toolCalls state.
222
+ const statefulCancelAllToolCalls = vi.fn((...args) => {
223
+ // Call the original spy so `toHaveBeenCalled` checks still work.
224
+ mockCancelAllToolCalls(...args);
225
+ const newToolCalls = props.toolCalls.map((tc) => {
226
+ // Only cancel tools that are in a cancellable state.
227
+ if (tc.status === 'awaiting_approval' ||
228
+ tc.status === 'executing' ||
229
+ tc.status === 'scheduled' ||
230
+ tc.status === 'validating') {
231
+ // A real cancelled tool call has a response object.
232
+ // We need to simulate this to avoid type errors downstream.
233
+ return {
234
+ ...tc,
235
+ status: 'cancelled',
236
+ response: {
237
+ callId: tc.request.callId,
238
+ responseParts: [],
239
+ resultDisplay: 'Request cancelled.',
240
+ },
241
+ responseSubmittedToGemini: true, // Mark as "processed"
242
+ };
243
+ }
244
+ return tc;
245
+ });
246
+ rerender({ ...props, toolCalls: newToolCalls });
247
+ });
248
+ mockUseReactToolScheduler.mockImplementation(() => [
249
+ props.toolCalls,
250
+ mockScheduleToolCalls,
251
+ mockMarkToolsAsSubmitted,
252
+ mockSetToolCallsForDisplay,
253
+ statefulCancelAllToolCalls, // Use the stateful mock
254
+ ]);
216
255
  return useGeminiStream(props.client, props.history, props.addItem, props.config, props.loadedSettings, props.onDebugMessage, props.handleSlashCommand, props.shellModeActive, () => 'vscode', () => { }, () => Promise.resolve(), false, () => { }, () => { }, () => { }, () => { }, 80, 24);
217
256
  }, {
218
- initialProps: {
219
- client,
220
- history: [],
221
- addItem: mockAddItem,
222
- config: mockConfig,
223
- onDebugMessage: mockOnDebugMessage,
224
- handleSlashCommand: mockHandleSlashCommand,
225
- shellModeActive: false,
226
- loadedSettings: mockLoadedSettings,
227
- toolCalls: initialToolCalls,
228
- },
257
+ initialProps,
229
258
  });
230
259
  return {
231
260
  result,
@@ -341,7 +370,7 @@ describe('useGeminiStream', () => {
341
370
  let capturedOnComplete = null;
342
371
  mockUseReactToolScheduler.mockImplementation((onComplete) => {
343
372
  capturedOnComplete = onComplete;
344
- return [[], mockScheduleToolCalls, mockMarkToolsAsSubmitted];
373
+ return [[], mockScheduleToolCalls, mockMarkToolsAsSubmitted, vi.fn()];
345
374
  });
346
375
  renderHook(() => useGeminiStream(new MockedGeminiClientClass(mockConfig), [], mockAddItem, mockConfig, mockLoadedSettings, mockOnDebugMessage, mockHandleSlashCommand, false, () => 'vscode', () => { }, () => Promise.resolve(), false, () => { }, () => { }, () => { }, () => { }, 80, 24));
347
376
  // Trigger the onComplete callback with completed tools
@@ -350,7 +379,7 @@ describe('useGeminiStream', () => {
350
379
  await capturedOnComplete(completedToolCalls);
351
380
  }
352
381
  });
353
- await waitFor(() => {
382
+ await vi.waitFor(() => {
354
383
  expect(mockMarkToolsAsSubmitted).toHaveBeenCalledTimes(1);
355
384
  expect(mockSendMessageStream).toHaveBeenCalledTimes(1);
356
385
  });
@@ -390,7 +419,7 @@ describe('useGeminiStream', () => {
390
419
  let capturedOnComplete = null;
391
420
  mockUseReactToolScheduler.mockImplementation((onComplete) => {
392
421
  capturedOnComplete = onComplete;
393
- return [[], mockScheduleToolCalls, mockMarkToolsAsSubmitted];
422
+ return [[], mockScheduleToolCalls, mockMarkToolsAsSubmitted, vi.fn()];
394
423
  });
395
424
  renderHook(() => useGeminiStream(client, [], mockAddItem, mockConfig, mockLoadedSettings, mockOnDebugMessage, mockHandleSlashCommand, false, () => 'vscode', () => { }, () => Promise.resolve(), false, () => { }, () => { }, () => { }, () => { }, 80, 24));
396
425
  // Trigger the onComplete callback with cancelled tools
@@ -399,7 +428,7 @@ describe('useGeminiStream', () => {
399
428
  await capturedOnComplete(cancelledToolCalls);
400
429
  }
401
430
  });
402
- await waitFor(() => {
431
+ await vi.waitFor(() => {
403
432
  expect(mockMarkToolsAsSubmitted).toHaveBeenCalledWith(['1']);
404
433
  expect(client.addHistory).toHaveBeenCalledWith({
405
434
  role: 'user',
@@ -473,7 +502,7 @@ describe('useGeminiStream', () => {
473
502
  let capturedOnComplete = null;
474
503
  mockUseReactToolScheduler.mockImplementation((onComplete) => {
475
504
  capturedOnComplete = onComplete;
476
- return [[], mockScheduleToolCalls, mockMarkToolsAsSubmitted];
505
+ return [[], mockScheduleToolCalls, mockMarkToolsAsSubmitted, vi.fn()];
477
506
  });
478
507
  renderHook(() => useGeminiStream(client, [], mockAddItem, mockConfig, mockLoadedSettings, mockOnDebugMessage, mockHandleSlashCommand, false, () => 'vscode', () => { }, () => Promise.resolve(), false, () => { }, () => { }, () => { }, () => { }, 80, 24));
479
508
  // Trigger the onComplete callback with multiple cancelled tools
@@ -482,7 +511,7 @@ describe('useGeminiStream', () => {
482
511
  await capturedOnComplete(allCancelledTools);
483
512
  }
484
513
  });
485
- await waitFor(() => {
514
+ await vi.waitFor(() => {
486
515
  // The tools should be marked as submitted locally
487
516
  expect(mockMarkToolsAsSubmitted).toHaveBeenCalledWith([
488
517
  'cancel-1',
@@ -552,6 +581,7 @@ describe('useGeminiStream', () => {
552
581
  currentToolCalls,
553
582
  mockScheduleToolCalls,
554
583
  mockMarkToolsAsSubmitted,
584
+ vi.fn(), // setToolCallsForDisplay
555
585
  ];
556
586
  });
557
587
  const { result, rerender } = renderHook(() => useGeminiStream(new MockedGeminiClientClass(mockConfig), [], mockAddItem, mockConfig, mockLoadedSettings, mockOnDebugMessage, mockHandleSlashCommand, false, () => 'vscode', () => { }, () => Promise.resolve(), false, () => { }, () => { }, () => { }, () => { }, 80, 24));
@@ -565,6 +595,7 @@ describe('useGeminiStream', () => {
565
595
  completedToolCalls,
566
596
  mockScheduleToolCalls,
567
597
  mockMarkToolsAsSubmitted,
598
+ vi.fn(), // setToolCallsForDisplay
568
599
  ];
569
600
  });
570
601
  act(() => {
@@ -580,7 +611,7 @@ describe('useGeminiStream', () => {
580
611
  }
581
612
  });
582
613
  // 5. Wait for submitQuery to be called
583
- await waitFor(() => {
614
+ await vi.waitFor(() => {
584
615
  expect(mockSendMessageStream).toHaveBeenCalledWith(toolCallResponseParts, expect.any(AbortSignal), 'prompt-id-4');
585
616
  });
586
617
  // 6. After submission, the state should remain Responding until the stream completes.
@@ -618,13 +649,13 @@ describe('useGeminiStream', () => {
618
649
  result.current.submitQuery('test query');
619
650
  });
620
651
  // Wait for the first part of the response
621
- await waitFor(() => {
652
+ await vi.waitFor(() => {
622
653
  expect(result.current.streamingState).toBe(StreamingState.Responding);
623
654
  });
624
655
  // Simulate escape key press
625
656
  simulateEscapeKeyPress();
626
657
  // Verify cancellation message is added
627
- await waitFor(() => {
658
+ await vi.waitFor(() => {
628
659
  expect(mockAddItem).toHaveBeenCalledWith({
629
660
  type: MessageType.INFO,
630
661
  text: 'Request cancelled.',
@@ -690,7 +721,7 @@ describe('useGeminiStream', () => {
690
721
  await act(async () => {
691
722
  result.current.submitQuery('long running query');
692
723
  });
693
- await waitFor(() => {
724
+ await vi.waitFor(() => {
694
725
  expect(result.current.streamingState).toBe(StreamingState.Responding);
695
726
  });
696
727
  // Cancel the request
@@ -707,7 +738,7 @@ describe('useGeminiStream', () => {
707
738
  // The final state should be idle after cancellation
708
739
  expect(result.current.streamingState).toBe(StreamingState.Idle);
709
740
  });
710
- it('should not cancel if a tool call is in progress (not just responding)', async () => {
741
+ it('should cancel if a tool call is in progress', async () => {
711
742
  const toolCalls = [
712
743
  {
713
744
  request: { callId: 'call1', name: 'tool1', args: {} },
@@ -727,14 +758,64 @@ describe('useGeminiStream', () => {
727
758
  liveOutput: '...',
728
759
  },
729
760
  ];
730
- const abortSpy = vi.spyOn(AbortController.prototype, 'abort');
731
761
  const { result } = renderTestHook(toolCalls);
732
762
  // State is `Responding` because a tool is running
733
763
  expect(result.current.streamingState).toBe(StreamingState.Responding);
734
764
  // Try to cancel
735
765
  simulateEscapeKeyPress();
736
- // Nothing should happen because the state is not `Responding`
737
- expect(abortSpy).not.toHaveBeenCalled();
766
+ // The cancel function should be called
767
+ expect(mockCancelAllToolCalls).toHaveBeenCalled();
768
+ });
769
+ it('should cancel a request when a tool is awaiting confirmation', async () => {
770
+ const mockOnConfirm = vi.fn().mockResolvedValue(undefined);
771
+ const toolCalls = [
772
+ {
773
+ request: {
774
+ callId: 'confirm-call',
775
+ name: 'some_tool',
776
+ args: {},
777
+ isClientInitiated: false,
778
+ prompt_id: 'prompt-id-1',
779
+ },
780
+ status: 'awaiting_approval',
781
+ responseSubmittedToGemini: false,
782
+ tool: {
783
+ name: 'some_tool',
784
+ description: 'a tool',
785
+ build: vi.fn().mockImplementation((_) => ({
786
+ getDescription: () => `Mock description`,
787
+ })),
788
+ },
789
+ invocation: {
790
+ getDescription: () => `Mock description`,
791
+ },
792
+ confirmationDetails: {
793
+ type: 'edit',
794
+ title: 'Confirm Edit',
795
+ onConfirm: mockOnConfirm,
796
+ fileName: 'file.txt',
797
+ filePath: '/test/file.txt',
798
+ fileDiff: 'fake diff',
799
+ originalContent: 'old',
800
+ newContent: 'new',
801
+ },
802
+ },
803
+ ];
804
+ const { result } = renderTestHook(toolCalls);
805
+ // State is `WaitingForConfirmation` because a tool is awaiting approval
806
+ expect(result.current.streamingState).toBe(StreamingState.WaitingForConfirmation);
807
+ // Try to cancel
808
+ simulateEscapeKeyPress();
809
+ // The imperative cancel function should be called on the scheduler
810
+ expect(mockCancelAllToolCalls).toHaveBeenCalled();
811
+ // A cancellation message should be added to history
812
+ await vi.waitFor(() => {
813
+ expect(mockAddItem).toHaveBeenCalledWith(expect.objectContaining({
814
+ text: 'Request cancelled.',
815
+ }), expect.any(Number));
816
+ });
817
+ // The final state should be idle
818
+ expect(result.current.streamingState).toBe(StreamingState.Idle);
738
819
  });
739
820
  });
740
821
  describe('Slash Command Handling', () => {
@@ -749,7 +830,7 @@ describe('useGeminiStream', () => {
749
830
  await act(async () => {
750
831
  await result.current.submitQuery('/memory add "test fact"');
751
832
  });
752
- await waitFor(() => {
833
+ await vi.waitFor(() => {
753
834
  expect(mockScheduleToolCalls).toHaveBeenCalledWith([
754
835
  expect.objectContaining({
755
836
  name: 'save_memory',
@@ -769,7 +850,7 @@ describe('useGeminiStream', () => {
769
850
  await act(async () => {
770
851
  await result.current.submitQuery('/help');
771
852
  });
772
- await waitFor(() => {
853
+ await vi.waitFor(() => {
773
854
  expect(mockHandleSlashCommand).toHaveBeenCalledWith('/help');
774
855
  expect(mockScheduleToolCalls).not.toHaveBeenCalled();
775
856
  expect(mockSendMessageStream).not.toHaveBeenCalled(); // No LLM call made
@@ -785,7 +866,7 @@ describe('useGeminiStream', () => {
785
866
  await act(async () => {
786
867
  await result.current.submitQuery('/my-custom-command');
787
868
  });
788
- await waitFor(() => {
869
+ await vi.waitFor(() => {
789
870
  expect(mockHandleSlashCommand).toHaveBeenCalledWith('/my-custom-command');
790
871
  expect(localMockSendMessageStream).not.toHaveBeenCalledWith('/my-custom-command', expect.anything(), expect.anything());
791
872
  expect(localMockSendMessageStream).toHaveBeenCalledWith('This is the actual prompt from the command file.', expect.any(AbortSignal), expect.any(String));
@@ -802,7 +883,7 @@ describe('useGeminiStream', () => {
802
883
  await act(async () => {
803
884
  await result.current.submitQuery('/emptycmd');
804
885
  });
805
- await waitFor(() => {
886
+ await vi.waitFor(() => {
806
887
  expect(mockHandleSlashCommand).toHaveBeenCalledWith('/emptycmd');
807
888
  expect(localMockSendMessageStream).toHaveBeenCalledWith('', expect.any(AbortSignal), expect.any(String));
808
889
  });
@@ -812,7 +893,7 @@ describe('useGeminiStream', () => {
812
893
  await act(async () => {
813
894
  await result.current.submitQuery('// This is a line comment');
814
895
  });
815
- await waitFor(() => {
896
+ await vi.waitFor(() => {
816
897
  expect(mockHandleSlashCommand).not.toHaveBeenCalled();
817
898
  expect(localMockSendMessageStream).toHaveBeenCalledWith('// This is a line comment', expect.any(AbortSignal), expect.any(String));
818
899
  });
@@ -822,7 +903,7 @@ describe('useGeminiStream', () => {
822
903
  await act(async () => {
823
904
  await result.current.submitQuery('/* This is a block comment */');
824
905
  });
825
- await waitFor(() => {
906
+ await vi.waitFor(() => {
826
907
  expect(mockHandleSlashCommand).not.toHaveBeenCalled();
827
908
  expect(localMockSendMessageStream).toHaveBeenCalledWith('/* This is a block comment */', expect.any(AbortSignal), expect.any(String));
828
909
  });
@@ -832,7 +913,7 @@ describe('useGeminiStream', () => {
832
913
  await act(async () => {
833
914
  await result.current.submitQuery('/about');
834
915
  });
835
- await waitFor(() => {
916
+ await vi.waitFor(() => {
836
917
  expect(mockHandleSlashCommand).not.toHaveBeenCalled();
837
918
  });
838
919
  });
@@ -871,7 +952,7 @@ describe('useGeminiStream', () => {
871
952
  let capturedOnComplete = null;
872
953
  mockUseReactToolScheduler.mockImplementation((onComplete) => {
873
954
  capturedOnComplete = onComplete;
874
- return [[], mockScheduleToolCalls, mockMarkToolsAsSubmitted];
955
+ return [[], mockScheduleToolCalls, mockMarkToolsAsSubmitted, vi.fn()];
875
956
  });
876
957
  renderHook(() => useGeminiStream(new MockedGeminiClientClass(mockConfig), [], mockAddItem, mockConfig, mockLoadedSettings, mockOnDebugMessage, mockHandleSlashCommand, false, () => 'vscode', () => { }, mockPerformMemoryRefresh, false, () => { }, () => { }, () => { }, () => { }, 80, 24));
877
958
  // Trigger the onComplete callback with the completed save_memory tool
@@ -880,7 +961,7 @@ describe('useGeminiStream', () => {
880
961
  await capturedOnComplete([completedToolCall]);
881
962
  }
882
963
  });
883
- await waitFor(() => {
964
+ await vi.waitFor(() => {
884
965
  expect(mockPerformMemoryRefresh).toHaveBeenCalledTimes(1);
885
966
  });
886
967
  });
@@ -908,7 +989,7 @@ describe('useGeminiStream', () => {
908
989
  await result.current.submitQuery('test query');
909
990
  });
910
991
  // 3. Assertion
911
- await waitFor(() => {
992
+ await vi.waitFor(() => {
912
993
  expect(mockParseAndFormatApiError).toHaveBeenCalledWith('Rate limit exceeded', mockAuthType, undefined, 'gemini-2.5-pro', 'gemini-2.5-flash');
913
994
  });
914
995
  });
@@ -1129,8 +1210,8 @@ describe('useGeminiStream', () => {
1129
1210
  expect(mockOnConfirm).not.toHaveBeenCalled();
1130
1211
  });
1131
1212
  it('should handle errors gracefully when auto-approving tool calls', async () => {
1132
- const consoleSpy = vi
1133
- .spyOn(console, 'error')
1213
+ const debuggerSpy = vi
1214
+ .spyOn(debugLogger, 'warn')
1134
1215
  .mockImplementation(() => { });
1135
1216
  const mockOnConfirmSuccess = vi.fn().mockResolvedValue(undefined);
1136
1217
  const mockOnConfirmError = vi
@@ -1206,8 +1287,8 @@ describe('useGeminiStream', () => {
1206
1287
  expect(mockOnConfirmSuccess).toHaveBeenCalledTimes(1);
1207
1288
  expect(mockOnConfirmError).toHaveBeenCalledTimes(1);
1208
1289
  // Error should be logged
1209
- expect(consoleSpy).toHaveBeenCalledWith('Failed to auto-approve tool call call2:', expect.any(Error));
1210
- consoleSpy.mockRestore();
1290
+ expect(debuggerSpy).toHaveBeenCalledWith('Failed to auto-approve tool call call2:', expect.any(Error));
1291
+ debuggerSpy.mockRestore();
1211
1292
  });
1212
1293
  it('should skip tool calls without confirmationDetails', async () => {
1213
1294
  const awaitingApprovalToolCalls = [
@@ -1363,7 +1444,7 @@ describe('useGeminiStream', () => {
1363
1444
  await result.current.submitQuery('Generate long text');
1364
1445
  });
1365
1446
  // Check that the info message was added
1366
- await waitFor(() => {
1447
+ await vi.waitFor(() => {
1367
1448
  expect(mockAddItem).toHaveBeenCalledWith({
1368
1449
  type: 'info',
1369
1450
  text: '⚠️ Response truncated due to token limits.',
@@ -1392,7 +1473,7 @@ describe('useGeminiStream', () => {
1392
1473
  await result.current.submitQuery('Test overflow');
1393
1474
  });
1394
1475
  // Check that the message was added without suggestion
1395
- await waitFor(() => {
1476
+ await vi.waitFor(() => {
1396
1477
  expect(mockAddItem).toHaveBeenCalledWith({
1397
1478
  type: 'info',
1398
1479
  text: `Sending this message (20 tokens) might exceed the remaining context window limit (80 tokens).`,
@@ -1417,7 +1498,7 @@ describe('useGeminiStream', () => {
1417
1498
  await result.current.submitQuery('Test overflow');
1418
1499
  });
1419
1500
  // Check that the message was added with suggestion
1420
- await waitFor(() => {
1501
+ await vi.waitFor(() => {
1421
1502
  expect(mockAddItem).toHaveBeenCalledWith({
1422
1503
  type: 'info',
1423
1504
  text: `Sending this message (30 tokens) might exceed the remaining context window limit (70 tokens). Please try reducing the size of your message or use the \`/compress\` command to compress the chat history.`,
@@ -1443,7 +1524,7 @@ describe('useGeminiStream', () => {
1443
1524
  await result.current.submitQuery('Test overflow');
1444
1525
  });
1445
1526
  // Check that onCancelSubmit was called
1446
- await waitFor(() => {
1527
+ await vi.waitFor(() => {
1447
1528
  expect(onCancelSubmitSpy).toHaveBeenCalled();
1448
1529
  });
1449
1530
  });
@@ -1553,7 +1634,7 @@ describe('useGeminiStream', () => {
1553
1634
  await act(async () => {
1554
1635
  await result.current.submitQuery(`Test ${reason}`);
1555
1636
  });
1556
- await waitFor(() => {
1637
+ await vi.waitFor(() => {
1557
1638
  expect(mockAddItem).toHaveBeenCalledWith({
1558
1639
  type: 'info',
1559
1640
  text: message,
@@ -1626,7 +1707,7 @@ describe('useGeminiStream', () => {
1626
1707
  await result.current.submitQuery('First query');
1627
1708
  });
1628
1709
  // Wait for the first response to complete
1629
- await waitFor(() => {
1710
+ await vi.waitFor(() => {
1630
1711
  expect(mockAddItem).toHaveBeenCalledWith(expect.objectContaining({
1631
1712
  type: 'gemini',
1632
1713
  text: 'Some response content',
@@ -1651,7 +1732,7 @@ describe('useGeminiStream', () => {
1651
1732
  // We can verify this by checking that the LoadingIndicator would not show the previous thought
1652
1733
  // The actual thought state is internal to the hook, but we can verify the behavior
1653
1734
  // by ensuring the second response doesn't show the previous thought
1654
- await waitFor(() => {
1735
+ await vi.waitFor(() => {
1655
1736
  expect(mockAddItem).toHaveBeenCalledWith(expect.objectContaining({
1656
1737
  type: 'gemini',
1657
1738
  text: 'New response content',
@@ -1710,7 +1791,7 @@ describe('useGeminiStream', () => {
1710
1791
  await result.current.submitQuery('Test query');
1711
1792
  });
1712
1793
  // Verify cancellation message was added
1713
- await waitFor(() => {
1794
+ await vi.waitFor(() => {
1714
1795
  expect(mockAddItem).toHaveBeenCalledWith(expect.objectContaining({
1715
1796
  type: 'info',
1716
1797
  text: 'User cancelled the request.',
@@ -1737,7 +1818,7 @@ describe('useGeminiStream', () => {
1737
1818
  await result.current.submitQuery('Test query');
1738
1819
  });
1739
1820
  // Verify error message was added
1740
- await waitFor(() => {
1821
+ await vi.waitFor(() => {
1741
1822
  expect(mockAddItem).toHaveBeenCalledWith(expect.objectContaining({
1742
1823
  type: 'error',
1743
1824
  }), expect.any(Number));
@@ -1771,7 +1852,7 @@ describe('useGeminiStream', () => {
1771
1852
  await act(async () => {
1772
1853
  await result.current.submitQuery('test query');
1773
1854
  });
1774
- await waitFor(() => {
1855
+ await vi.waitFor(() => {
1775
1856
  expect(result.current.loopDetectionConfirmationRequest).not.toBeNull();
1776
1857
  expect(typeof result.current.loopDetectionConfirmationRequest?.onComplete).toBe('function');
1777
1858
  });
@@ -1807,7 +1888,7 @@ describe('useGeminiStream', () => {
1807
1888
  await result.current.submitQuery('test query');
1808
1889
  });
1809
1890
  // Wait for confirmation request to be set
1810
- await waitFor(() => {
1891
+ await vi.waitFor(() => {
1811
1892
  expect(result.current.loopDetectionConfirmationRequest).not.toBeNull();
1812
1893
  });
1813
1894
  // Simulate user selecting "disable"
@@ -1826,7 +1907,7 @@ describe('useGeminiStream', () => {
1826
1907
  text: 'Loop detection has been disabled for this session. Retrying request...',
1827
1908
  }, expect.any(Number));
1828
1909
  // Verify that the request was retried
1829
- await waitFor(() => {
1910
+ await vi.waitFor(() => {
1830
1911
  expect(mockSendMessageStream).toHaveBeenCalledTimes(2);
1831
1912
  expect(mockSendMessageStream).toHaveBeenNthCalledWith(2, 'test query', expect.any(AbortSignal), expect.any(String));
1832
1913
  });
@@ -1850,7 +1931,7 @@ describe('useGeminiStream', () => {
1850
1931
  await result.current.submitQuery('test query');
1851
1932
  });
1852
1933
  // Wait for confirmation request to be set
1853
- await waitFor(() => {
1934
+ await vi.waitFor(() => {
1854
1935
  expect(result.current.loopDetectionConfirmationRequest).not.toBeNull();
1855
1936
  });
1856
1937
  // Simulate user selecting "keep"
@@ -1883,7 +1964,7 @@ describe('useGeminiStream', () => {
1883
1964
  await act(async () => {
1884
1965
  await result.current.submitQuery('first query');
1885
1966
  });
1886
- await waitFor(() => {
1967
+ await vi.waitFor(() => {
1887
1968
  expect(result.current.loopDetectionConfirmationRequest).not.toBeNull();
1888
1969
  });
1889
1970
  // Simulate user selecting "keep" for first request
@@ -1919,7 +2000,7 @@ describe('useGeminiStream', () => {
1919
2000
  await act(async () => {
1920
2001
  await result.current.submitQuery('second query');
1921
2002
  });
1922
- await waitFor(() => {
2003
+ await vi.waitFor(() => {
1923
2004
  expect(result.current.loopDetectionConfirmationRequest).not.toBeNull();
1924
2005
  });
1925
2006
  // Simulate user selecting "disable" for second request
@@ -1935,7 +2016,7 @@ describe('useGeminiStream', () => {
1935
2016
  text: 'Loop detection has been disabled for this session. Retrying request...',
1936
2017
  }, expect.any(Number));
1937
2018
  // Verify that the request was retried
1938
- await waitFor(() => {
2019
+ await vi.waitFor(() => {
1939
2020
  expect(mockSendMessageStream).toHaveBeenCalledTimes(3); // 1st query, 2nd query, retry of 2nd query
1940
2021
  expect(mockSendMessageStream).toHaveBeenNthCalledWith(3, 'second query', expect.any(AbortSignal), expect.any(String));
1941
2022
  });
@@ -1955,14 +2036,14 @@ describe('useGeminiStream', () => {
1955
2036
  await result.current.submitQuery('test query');
1956
2037
  });
1957
2038
  // Verify that the content was added to history before the loop detection dialog
1958
- await waitFor(() => {
2039
+ await vi.waitFor(() => {
1959
2040
  expect(mockAddItem).toHaveBeenCalledWith(expect.objectContaining({
1960
2041
  type: 'gemini',
1961
2042
  text: 'Some response content',
1962
2043
  }), expect.any(Number));
1963
2044
  });
1964
2045
  // Then verify loop detection confirmation request was set
1965
- await waitFor(() => {
2046
+ await vi.waitFor(() => {
1966
2047
  expect(result.current.loopDetectionConfirmationRequest).not.toBeNull();
1967
2048
  });
1968
2049
  });