@google/gemini-cli 0.12.0-preview.4 → 0.13.0-nightly.20251031.c89bc30d

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 (254) hide show
  1. package/dist/google-gemini-cli-0.13.0-nightly.20251029.cca41edc.tgz +0 -0
  2. package/dist/package.json +2 -2
  3. package/dist/src/commands/extensions/install.js +2 -2
  4. package/dist/src/commands/extensions/install.js.map +1 -1
  5. package/dist/src/commands/extensions/install.test.js +27 -16
  6. package/dist/src/commands/extensions/install.test.js.map +1 -1
  7. package/dist/src/commands/extensions/link.js +2 -2
  8. package/dist/src/commands/extensions/link.js.map +1 -1
  9. package/dist/src/commands/extensions/update.js +3 -2
  10. package/dist/src/commands/extensions/update.js.map +1 -1
  11. package/dist/src/commands/extensions/validate.d.ts +12 -0
  12. package/dist/src/commands/extensions/validate.js +83 -0
  13. package/dist/src/commands/extensions/validate.js.map +1 -0
  14. package/dist/src/commands/extensions/validate.test.d.ts +6 -0
  15. package/dist/src/commands/extensions/validate.test.js +93 -0
  16. package/dist/src/commands/extensions/validate.test.js.map +1 -0
  17. package/dist/src/commands/extensions.js +2 -0
  18. package/dist/src/commands/extensions.js.map +1 -1
  19. package/dist/src/config/auth.js +0 -5
  20. package/dist/src/config/auth.js.map +1 -1
  21. package/dist/src/config/auth.test.js +1 -3
  22. package/dist/src/config/auth.test.js.map +1 -1
  23. package/dist/src/config/config.js +2 -1
  24. package/dist/src/config/config.js.map +1 -1
  25. package/dist/src/config/config.test.js +6 -10
  26. package/dist/src/config/config.test.js.map +1 -1
  27. package/dist/src/config/extensions/update.d.ts +2 -2
  28. package/dist/src/config/extensions/update.js +28 -22
  29. package/dist/src/config/extensions/update.js.map +1 -1
  30. package/dist/src/config/sandboxConfig.d.ts +1 -1
  31. package/dist/src/config/sandboxConfig.js +6 -3
  32. package/dist/src/config/sandboxConfig.js.map +1 -1
  33. package/dist/src/config/settings.js +2 -2
  34. package/dist/src/config/settings.js.map +1 -1
  35. package/dist/src/config/settings.test.js +13 -53
  36. package/dist/src/config/settings.test.js.map +1 -1
  37. package/dist/src/config/settingsSchema.d.ts +25 -7
  38. package/dist/src/config/settingsSchema.js +24 -6
  39. package/dist/src/config/settingsSchema.js.map +1 -1
  40. package/dist/src/config/settingsSchema.test.js +2 -0
  41. package/dist/src/config/settingsSchema.test.js.map +1 -1
  42. package/dist/src/gemini.js +8 -1
  43. package/dist/src/gemini.js.map +1 -1
  44. package/dist/src/gemini.test.js +1 -0
  45. package/dist/src/gemini.test.js.map +1 -1
  46. package/dist/src/generated/git-commit.d.ts +2 -2
  47. package/dist/src/generated/git-commit.js +2 -2
  48. package/dist/src/generated/git-commit.js.map +1 -1
  49. package/dist/src/nonInteractiveCli.d.ts +9 -1
  50. package/dist/src/nonInteractiveCli.js +16 -1
  51. package/dist/src/nonInteractiveCli.js.map +1 -1
  52. package/dist/src/nonInteractiveCli.test.js +209 -103
  53. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  54. package/dist/src/test-utils/async.d.ts +9 -0
  55. package/dist/src/test-utils/async.js +29 -0
  56. package/dist/src/test-utils/async.js.map +1 -0
  57. package/dist/src/test-utils/render.d.ts +2 -1
  58. package/dist/src/test-utils/render.js +23 -1
  59. package/dist/src/test-utils/render.js.map +1 -1
  60. package/dist/src/test-utils/render.test.js +29 -4
  61. package/dist/src/test-utils/render.test.js.map +1 -1
  62. package/dist/src/ui/App.test.js +1 -1
  63. package/dist/src/ui/App.test.js.map +1 -1
  64. package/dist/src/ui/AppContainer.js +33 -4
  65. package/dist/src/ui/AppContainer.js.map +1 -1
  66. package/dist/src/ui/AppContainer.test.js +205 -99
  67. package/dist/src/ui/AppContainer.test.js.map +1 -1
  68. package/dist/src/ui/auth/ApiAuthDialog.d.ts +14 -0
  69. package/dist/src/ui/auth/ApiAuthDialog.js +26 -0
  70. package/dist/src/ui/auth/ApiAuthDialog.js.map +1 -0
  71. package/dist/src/ui/auth/ApiAuthDialog.test.d.ts +6 -0
  72. package/dist/src/ui/auth/ApiAuthDialog.test.js +91 -0
  73. package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -0
  74. package/dist/src/ui/auth/AuthDialog.js +7 -3
  75. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  76. package/dist/src/ui/auth/AuthDialog.test.js +1 -1
  77. package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
  78. package/dist/src/ui/auth/useAuth.d.ts +2 -0
  79. package/dist/src/ui/auth/useAuth.js +31 -2
  80. package/dist/src/ui/auth/useAuth.js.map +1 -1
  81. package/dist/src/ui/components/AnsiOutput.test.js +1 -1
  82. package/dist/src/ui/components/AnsiOutput.test.js.map +1 -1
  83. package/dist/src/ui/components/Composer.test.js +1 -1
  84. package/dist/src/ui/components/Composer.test.js.map +1 -1
  85. package/dist/src/ui/components/ConsentPrompt.test.js +18 -8
  86. package/dist/src/ui/components/ConsentPrompt.test.js.map +1 -1
  87. package/dist/src/ui/components/ContextSummaryDisplay.test.js +11 -6
  88. package/dist/src/ui/components/ContextSummaryDisplay.test.js.map +1 -1
  89. package/dist/src/ui/components/DialogManager.js +4 -0
  90. package/dist/src/ui/components/DialogManager.js.map +1 -1
  91. package/dist/src/ui/components/FolderTrustDialog.test.js +4 -3
  92. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  93. package/dist/src/ui/components/Footer.js +3 -2
  94. package/dist/src/ui/components/Footer.js.map +1 -1
  95. package/dist/src/ui/components/Footer.test.js +59 -0
  96. package/dist/src/ui/components/Footer.test.js.map +1 -1
  97. package/dist/src/ui/components/Header.test.js +9 -5
  98. package/dist/src/ui/components/Header.test.js.map +1 -1
  99. package/dist/src/ui/components/Help.test.js +5 -3
  100. package/dist/src/ui/components/Help.test.js.map +1 -1
  101. package/dist/src/ui/components/InputPrompt.test.js +139 -111
  102. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  103. package/dist/src/ui/components/LoadingIndicator.test.js +27 -14
  104. package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -1
  105. package/dist/src/ui/components/ModelDialog.test.js +20 -10
  106. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  107. package/dist/src/ui/components/ModelStatsDisplay.test.js +1 -1
  108. package/dist/src/ui/components/ModelStatsDisplay.test.js.map +1 -1
  109. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +11 -10
  110. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
  111. package/dist/src/ui/components/PrepareLabel.test.js +13 -7
  112. package/dist/src/ui/components/PrepareLabel.test.js.map +1 -1
  113. package/dist/src/ui/components/ProQuotaDialog.test.js +14 -6
  114. package/dist/src/ui/components/ProQuotaDialog.test.js.map +1 -1
  115. package/dist/src/ui/components/QueuedMessageDisplay.test.js +11 -6
  116. package/dist/src/ui/components/QueuedMessageDisplay.test.js.map +1 -1
  117. package/dist/src/ui/components/SessionSummaryDisplay.test.js +1 -1
  118. package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +1 -1
  119. package/dist/src/ui/components/SettingsDialog.test.js +438 -512
  120. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  121. package/dist/src/ui/components/StatsDisplay.test.js +1 -1
  122. package/dist/src/ui/components/StatsDisplay.test.js.map +1 -1
  123. package/dist/src/ui/components/ThemeDialog.test.js +3 -2
  124. package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
  125. package/dist/src/ui/components/ToolStatsDisplay.test.js +1 -1
  126. package/dist/src/ui/components/ToolStatsDisplay.test.js.map +1 -1
  127. package/dist/src/ui/components/messages/CompressionMessage.test.js +25 -17
  128. package/dist/src/ui/components/messages/CompressionMessage.test.js.map +1 -1
  129. package/dist/src/ui/components/messages/DiffRenderer.test.js +1 -1
  130. package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
  131. package/dist/src/ui/components/messages/Todo.js +27 -5
  132. package/dist/src/ui/components/messages/Todo.js.map +1 -1
  133. package/dist/src/ui/components/messages/Todo.test.js +20 -8
  134. package/dist/src/ui/components/messages/Todo.test.js.map +1 -1
  135. package/dist/src/ui/components/messages/ToolGroupMessage.test.js +29 -15
  136. package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
  137. package/dist/src/ui/components/shared/BaseSelectionList.test.js +12 -11
  138. package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
  139. package/dist/src/ui/components/shared/MaxSizedBox.test.js +43 -22
  140. package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -1
  141. package/dist/src/ui/components/shared/TextInput.d.ts +15 -0
  142. package/dist/src/ui/components/shared/TextInput.js +38 -0
  143. package/dist/src/ui/components/shared/TextInput.js.map +1 -0
  144. package/dist/src/ui/components/shared/TextInput.test.d.ts +6 -0
  145. package/dist/src/ui/components/shared/TextInput.test.js +242 -0
  146. package/dist/src/ui/components/shared/TextInput.test.js.map +1 -0
  147. package/dist/src/ui/components/shared/text-buffer.d.ts +8 -2
  148. package/dist/src/ui/components/shared/text-buffer.js +28 -13
  149. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  150. package/dist/src/ui/components/shared/text-buffer.test.js +137 -0
  151. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
  152. package/dist/src/ui/components/views/ChatList.test.js +7 -4
  153. package/dist/src/ui/components/views/ChatList.test.js.map +1 -1
  154. package/dist/src/ui/components/views/ExtensionsList.js +1 -0
  155. package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
  156. package/dist/src/ui/components/views/ExtensionsList.test.js +13 -5
  157. package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -1
  158. package/dist/src/ui/components/views/McpStatus.test.js +23 -12
  159. package/dist/src/ui/components/views/McpStatus.test.js.map +1 -1
  160. package/dist/src/ui/contexts/KeypressContext.test.js +132 -252
  161. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  162. package/dist/src/ui/contexts/SessionContext.test.js +9 -5
  163. package/dist/src/ui/contexts/SessionContext.test.js.map +1 -1
  164. package/dist/src/ui/contexts/UIActionsContext.d.ts +2 -0
  165. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  166. package/dist/src/ui/contexts/UIStateContext.d.ts +2 -0
  167. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  168. package/dist/src/ui/hooks/atCommandProcessor.js +29 -7
  169. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  170. package/dist/src/ui/hooks/atCommandProcessor.test.js +163 -64
  171. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  172. package/dist/src/ui/hooks/shellCommandProcessor.test.js +47 -34
  173. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
  174. package/dist/src/ui/hooks/slashCommandProcessor.test.js +141 -104
  175. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
  176. package/dist/src/ui/hooks/useAtCompletion.test.js +23 -21
  177. package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -1
  178. package/dist/src/ui/hooks/useCommandCompletion.test.js +16 -15
  179. package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
  180. package/dist/src/ui/hooks/useConsoleMessages.test.js +1 -1
  181. package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -1
  182. package/dist/src/ui/hooks/useEditorSettings.test.js +1 -1
  183. package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
  184. package/dist/src/ui/hooks/useExtensionUpdates.d.ts +1 -1
  185. package/dist/src/ui/hooks/useExtensionUpdates.js +9 -3
  186. package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
  187. package/dist/src/ui/hooks/useExtensionUpdates.test.js +10 -9
  188. package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
  189. package/dist/src/ui/hooks/useFocus.test.js +1 -1
  190. package/dist/src/ui/hooks/useFocus.test.js.map +1 -1
  191. package/dist/src/ui/hooks/useFolderTrust.test.js +7 -6
  192. package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
  193. package/dist/src/ui/hooks/useGeminiStream.test.js +39 -38
  194. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  195. package/dist/src/ui/hooks/useGitBranchName.test.js +5 -4
  196. package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
  197. package/dist/src/ui/hooks/useIdeTrustListener.test.js +25 -11
  198. package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -1
  199. package/dist/src/ui/hooks/useKeypress.test.js +1 -1
  200. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
  201. package/dist/src/ui/hooks/useLoadingIndicator.test.js +1 -1
  202. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  203. package/dist/src/ui/hooks/useMemoryMonitor.test.js +1 -1
  204. package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -1
  205. package/dist/src/ui/hooks/useMessageQueue.test.js +5 -4
  206. package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
  207. package/dist/src/ui/hooks/useModelCommand.test.js +7 -4
  208. package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -1
  209. package/dist/src/ui/hooks/usePhraseCycler.test.js +46 -16
  210. package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
  211. package/dist/src/ui/hooks/usePrivacySettings.test.js +11 -7
  212. package/dist/src/ui/hooks/usePrivacySettings.test.js.map +1 -1
  213. package/dist/src/ui/hooks/useQuotaAndFallback.test.js +28 -14
  214. package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
  215. package/dist/src/ui/hooks/useSelectionList.test.js +116 -109
  216. package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
  217. package/dist/src/ui/hooks/useShellHistory.test.js +25 -17
  218. package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
  219. package/dist/src/ui/hooks/useSlashCompletion.js +18 -7
  220. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  221. package/dist/src/ui/hooks/useSlashCompletion.test.js +244 -111
  222. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  223. package/dist/src/ui/hooks/useTimer.test.js +1 -1
  224. package/dist/src/ui/hooks/useTimer.test.js.map +1 -1
  225. package/dist/src/ui/hooks/useToolScheduler.test.js +6 -2
  226. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  227. package/dist/src/ui/hooks/vim.test.js +6 -21
  228. package/dist/src/ui/hooks/vim.test.js.map +1 -1
  229. package/dist/src/ui/state/extensions.d.ts +1 -0
  230. package/dist/src/ui/state/extensions.js +1 -0
  231. package/dist/src/ui/state/extensions.js.map +1 -1
  232. package/dist/src/ui/types.d.ts +1 -0
  233. package/dist/src/ui/types.js +2 -0
  234. package/dist/src/ui/types.js.map +1 -1
  235. package/dist/src/ui/utils/clipboardUtils.js +2 -2
  236. package/dist/src/ui/utils/clipboardUtils.js.map +1 -1
  237. package/dist/src/ui/utils/updateCheck.js +6 -3
  238. package/dist/src/ui/utils/updateCheck.js.map +1 -1
  239. package/dist/src/ui/utils/updateCheck.test.js +5 -1
  240. package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
  241. package/dist/src/utils/commentJson.js +2 -2
  242. package/dist/src/utils/commentJson.js.map +1 -1
  243. package/dist/src/utils/commentJson.test.js +7 -6
  244. package/dist/src/utils/commentJson.test.js.map +1 -1
  245. package/dist/src/utils/version.js +6 -2
  246. package/dist/src/utils/version.js.map +1 -1
  247. package/dist/src/zed-integration/acp.js +2 -1
  248. package/dist/src/zed-integration/acp.js.map +1 -1
  249. package/dist/tsconfig.tsbuildinfo +1 -1
  250. package/package.json +3 -3
  251. package/dist/google-gemini-cli-0.12.0-preview.3.tgz +0 -0
  252. package/dist/src/utils/package.d.ts +0 -12
  253. package/dist/src/utils/package.js +0 -24
  254. package/dist/src/utils/package.js.map +0 -1
@@ -4,10 +4,11 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  import { describe, it, expect, vi } from 'vitest';
7
+ import { act, useState } from 'react';
7
8
  import { renderHook } from '../../test-utils/render.js';
9
+ import { waitFor } from '../../test-utils/async.js';
8
10
  import { useSlashCompletion } from './useSlashCompletion.js';
9
11
  import { CommandKind } from '../commands/types.js';
10
- import { useState } from 'react';
11
12
  function createTestCommand(command) {
12
13
  return {
13
14
  kind: CommandKind.BUILT_IN, // default for tests
@@ -153,27 +154,67 @@ describe('useSlashCompletion', () => {
153
154
  }),
154
155
  createTestCommand({ name: 'chat', description: 'Manage chat history' }),
155
156
  ];
156
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/', slashCommands, mockCommandContext));
157
- await vi.waitFor(() => {
158
- expect(result.current.suggestions.length).toBe(slashCommands.length);
159
- expect(result.current.suggestions.map((s) => s.label)).toEqual(expect.arrayContaining(['help', 'clear', 'memory', 'chat', 'stats']));
157
+ let result;
158
+ let unmount;
159
+ await act(async () => {
160
+ const hook = renderHook(() => useTestHarnessForSlashCompletion(true, '/', slashCommands, mockCommandContext));
161
+ result = hook.result;
162
+ unmount = hook.unmount;
160
163
  });
164
+ await act(async () => {
165
+ await waitFor(() => {
166
+ expect(result.current.suggestions.length).toBe(slashCommands.length);
167
+ expect(result.current.suggestions.map((s) => s.label)).toEqual(expect.arrayContaining([
168
+ 'help',
169
+ 'clear',
170
+ 'memory',
171
+ 'chat',
172
+ 'stats',
173
+ ]));
174
+ });
175
+ });
176
+ unmount();
161
177
  });
162
178
  it('should filter commands based on partial input', async () => {
163
179
  const slashCommands = [
164
180
  createTestCommand({ name: 'memory', description: 'Manage memory' }),
165
181
  ];
166
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/mem', slashCommands, mockCommandContext));
167
- await vi.waitFor(() => {
168
- expect(result.current.suggestions).toEqual([
169
- {
170
- label: 'memory',
171
- value: 'memory',
172
- description: 'Manage memory',
173
- commandKind: CommandKind.BUILT_IN,
174
- },
175
- ]);
182
+ const setSuggestions = vi.fn();
183
+ const setIsLoadingSuggestions = vi.fn();
184
+ const setIsPerfectMatch = vi.fn();
185
+ let result;
186
+ let unmount;
187
+ await act(async () => {
188
+ const hook = renderHook(() => useSlashCompletion({
189
+ enabled: true,
190
+ query: '/mem',
191
+ slashCommands,
192
+ commandContext: mockCommandContext,
193
+ setSuggestions,
194
+ setIsLoadingSuggestions,
195
+ setIsPerfectMatch,
196
+ }));
197
+ result = hook.result;
198
+ unmount = hook.unmount;
199
+ });
200
+ await act(async () => {
201
+ await waitFor(() => {
202
+ expect(setSuggestions).toHaveBeenCalledWith([
203
+ {
204
+ label: 'memory',
205
+ value: 'memory',
206
+ description: 'Manage memory',
207
+ commandKind: CommandKind.BUILT_IN,
208
+ },
209
+ ]);
210
+ expect(result.current.completionStart).toBe(1);
211
+ expect(result.current.completionEnd).toBe(4);
212
+ });
176
213
  });
214
+ await act(async () => {
215
+ await new Promise((resolve) => setTimeout(resolve, 50));
216
+ });
217
+ unmount();
177
218
  });
178
219
  it('should suggest commands based on partial altNames', async () => {
179
220
  const slashCommands = [
@@ -183,8 +224,14 @@ describe('useSlashCompletion', () => {
183
224
  description: 'check session stats. Usage: /stats [model|tools]',
184
225
  }),
185
226
  ];
186
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/usag', slashCommands, mockCommandContext));
187
- await vi.waitFor(() => {
227
+ let result;
228
+ let unmount;
229
+ await act(async () => {
230
+ const hook = renderHook(() => useTestHarnessForSlashCompletion(true, '/usag', slashCommands, mockCommandContext));
231
+ result = hook.result;
232
+ unmount = hook.unmount;
233
+ });
234
+ await waitFor(() => {
188
235
  expect(result.current.suggestions).toEqual([
189
236
  {
190
237
  label: 'stats',
@@ -193,7 +240,9 @@ describe('useSlashCompletion', () => {
193
240
  commandKind: CommandKind.BUILT_IN,
194
241
  },
195
242
  ]);
243
+ expect(result.current.completionStart).toBe(1);
196
244
  });
245
+ unmount();
197
246
  });
198
247
  it('should NOT provide suggestions for a perfectly typed command that is a leaf node', async () => {
199
248
  const slashCommands = [
@@ -203,8 +252,18 @@ describe('useSlashCompletion', () => {
203
252
  action: vi.fn(),
204
253
  }),
205
254
  ];
206
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/clear', slashCommands, mockCommandContext));
207
- expect(result.current.suggestions).toHaveLength(0);
255
+ let result;
256
+ let unmount;
257
+ await act(async () => {
258
+ const hook = renderHook(() => useTestHarnessForSlashCompletion(true, '/clear', slashCommands, mockCommandContext));
259
+ result = hook.result;
260
+ unmount = hook.unmount;
261
+ });
262
+ await waitFor(() => {
263
+ expect(result.current.suggestions).toHaveLength(0);
264
+ expect(result.current.completionStart).toBe(1);
265
+ });
266
+ unmount();
208
267
  });
209
268
  it.each([['/?'], ['/usage']])('should not suggest commands when altNames is fully typed', async (query) => {
210
269
  const mockSlashCommands = [
@@ -221,22 +280,51 @@ describe('useSlashCompletion', () => {
221
280
  action: vi.fn(),
222
281
  }),
223
282
  ];
224
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, query, mockSlashCommands, mockCommandContext));
225
- expect(result.current.suggestions).toHaveLength(0);
283
+ let result;
284
+ let unmount;
285
+ await act(async () => {
286
+ const hook = renderHook(() => useTestHarnessForSlashCompletion(true, query, mockSlashCommands, mockCommandContext));
287
+ result = hook.result;
288
+ unmount = hook.unmount;
289
+ });
290
+ await waitFor(() => {
291
+ expect(result.current.suggestions).toHaveLength(0);
292
+ expect(result.current.completionStart).toBe(1);
293
+ });
294
+ unmount();
226
295
  });
227
296
  it('should not provide suggestions for a fully typed command that has no sub-commands or argument completion', async () => {
228
297
  const slashCommands = [
229
298
  createTestCommand({ name: 'clear', description: 'Clear the screen' }),
230
299
  ];
231
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/clear ', slashCommands, mockCommandContext));
232
- expect(result.current.suggestions).toHaveLength(0);
300
+ let result;
301
+ let unmount;
302
+ await act(async () => {
303
+ const hook = renderHook(() => useTestHarnessForSlashCompletion(true, '/clear ', slashCommands, mockCommandContext));
304
+ result = hook.result;
305
+ unmount = hook.unmount;
306
+ });
307
+ await waitFor(() => {
308
+ expect(result.current.suggestions).toHaveLength(0);
309
+ });
310
+ unmount();
233
311
  });
234
312
  it('should not provide suggestions for an unknown command', async () => {
235
313
  const slashCommands = [
236
314
  createTestCommand({ name: 'help', description: 'Show help' }),
237
315
  ];
238
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/unknown-command', slashCommands, mockCommandContext));
239
- expect(result.current.suggestions).toHaveLength(0);
316
+ let result;
317
+ let unmount;
318
+ await act(async () => {
319
+ const hook = renderHook(() => useTestHarnessForSlashCompletion(true, '/unknown-command', slashCommands, mockCommandContext));
320
+ result = hook.result;
321
+ unmount = hook.unmount;
322
+ });
323
+ await waitFor(() => {
324
+ expect(result.current.suggestions).toHaveLength(0);
325
+ expect(result.current.completionStart).toBe(1);
326
+ });
327
+ unmount();
240
328
  });
241
329
  it('should not suggest hidden commands', async () => {
242
330
  const slashCommands = [
@@ -250,11 +338,18 @@ describe('useSlashCompletion', () => {
250
338
  hidden: true,
251
339
  }),
252
340
  ];
253
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/', slashCommands, mockCommandContext));
254
- await vi.waitFor(() => {
341
+ let result;
342
+ let unmount;
343
+ await act(async () => {
344
+ const hook = renderHook(() => useTestHarnessForSlashCompletion(true, '/', slashCommands, mockCommandContext));
345
+ result = hook.result;
346
+ unmount = hook.unmount;
347
+ });
348
+ await waitFor(() => {
255
349
  expect(result.current.suggestions.length).toBe(1);
256
350
  expect(result.current.suggestions[0].label).toBe('visible');
257
351
  });
352
+ unmount();
258
353
  });
259
354
  });
260
355
  describe('Sub-Commands', () => {
@@ -269,8 +364,8 @@ describe('useSlashCompletion', () => {
269
364
  ],
270
365
  }),
271
366
  ];
272
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/memory ', slashCommands, mockCommandContext));
273
- await vi.waitFor(() => {
367
+ const { result, unmount } = renderHook(() => useTestHarnessForSlashCompletion(true, '/memory ', slashCommands, mockCommandContext));
368
+ await waitFor(() => {
274
369
  expect(result.current.suggestions).toHaveLength(2);
275
370
  expect(result.current.suggestions).toEqual(expect.arrayContaining([
276
371
  {
@@ -287,6 +382,7 @@ describe('useSlashCompletion', () => {
287
382
  },
288
383
  ]));
289
384
  });
385
+ unmount();
290
386
  });
291
387
  it('should suggest all sub-commands when the query ends with the parent command and a space', async () => {
292
388
  const slashCommands = [
@@ -299,8 +395,8 @@ describe('useSlashCompletion', () => {
299
395
  ],
300
396
  }),
301
397
  ];
302
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/memory ', slashCommands, mockCommandContext));
303
- await vi.waitFor(() => {
398
+ const { result, unmount } = renderHook(() => useTestHarnessForSlashCompletion(true, '/memory ', slashCommands, mockCommandContext));
399
+ await waitFor(() => {
304
400
  expect(result.current.suggestions).toHaveLength(2);
305
401
  expect(result.current.suggestions).toEqual(expect.arrayContaining([
306
402
  {
@@ -317,6 +413,7 @@ describe('useSlashCompletion', () => {
317
413
  },
318
414
  ]));
319
415
  });
416
+ unmount();
320
417
  });
321
418
  it('should filter sub-commands by prefix', async () => {
322
419
  const slashCommands = [
@@ -329,8 +426,8 @@ describe('useSlashCompletion', () => {
329
426
  ],
330
427
  }),
331
428
  ];
332
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/memory a', slashCommands, mockCommandContext));
333
- await vi.waitFor(() => {
429
+ const { result, unmount } = renderHook(() => useTestHarnessForSlashCompletion(true, '/memory a', slashCommands, mockCommandContext));
430
+ await waitFor(() => {
334
431
  expect(result.current.suggestions).toEqual([
335
432
  {
336
433
  label: 'add',
@@ -339,7 +436,9 @@ describe('useSlashCompletion', () => {
339
436
  commandKind: CommandKind.BUILT_IN,
340
437
  },
341
438
  ]);
439
+ expect(result.current.completionStart).toBe(8);
342
440
  });
441
+ unmount();
343
442
  });
344
443
  it('should provide no suggestions for an invalid sub-command', async () => {
345
444
  const slashCommands = [
@@ -352,8 +451,14 @@ describe('useSlashCompletion', () => {
352
451
  ],
353
452
  }),
354
453
  ];
355
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/memory dothisnow', slashCommands, mockCommandContext));
356
- expect(result.current.suggestions).toHaveLength(0);
454
+ const { result, unmount } = renderHook(() => useTestHarnessForSlashCompletion(true, '/memory dothisnow', slashCommands, mockCommandContext));
455
+ await act(async () => {
456
+ await waitFor(() => {
457
+ expect(result.current.suggestions).toHaveLength(0);
458
+ expect(result.current.completionStart).toBe(8);
459
+ });
460
+ });
461
+ unmount();
357
462
  });
358
463
  });
359
464
  describe('Argument Completion', () => {
@@ -379,22 +484,29 @@ describe('useSlashCompletion', () => {
379
484
  ],
380
485
  }),
381
486
  ];
382
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/chat resume my-ch', slashCommands, mockCommandContext));
383
- await vi.waitFor(() => {
384
- expect(mockCompletionFn).toHaveBeenCalledWith(expect.objectContaining({
385
- invocation: {
386
- raw: '/chat resume my-ch',
387
- name: 'resume',
388
- args: 'my-ch',
389
- },
390
- }), 'my-ch');
487
+ const { result, unmount } = renderHook(() => useTestHarnessForSlashCompletion(true, '/chat resume my-ch', slashCommands, mockCommandContext));
488
+ await act(async () => {
489
+ await waitFor(() => {
490
+ expect(mockCompletionFn).toHaveBeenCalledWith(expect.objectContaining({
491
+ invocation: {
492
+ raw: '/chat resume my-ch',
493
+ name: 'resume',
494
+ args: 'my-ch',
495
+ },
496
+ }), 'my-ch');
497
+ });
391
498
  });
392
- await vi.waitFor(() => {
393
- expect(result.current.suggestions).toEqual([
394
- { label: 'my-chat-tag-1', value: 'my-chat-tag-1' },
395
- { label: 'my-chat-tag-2', value: 'my-chat-tag-2' },
396
- ]);
499
+ await act(async () => {
500
+ await waitFor(() => {
501
+ expect(result.current.suggestions).toEqual([
502
+ { label: 'my-chat-tag-1', value: 'my-chat-tag-1' },
503
+ { label: 'my-chat-tag-2', value: 'my-chat-tag-2' },
504
+ ]);
505
+ expect(result.current.completionStart).toBe(13);
506
+ expect(result.current.isLoadingSuggestions).toBe(false);
507
+ });
397
508
  });
509
+ unmount();
398
510
  });
399
511
  it('should call command.completion with an empty string when args start with a space', async () => {
400
512
  const mockCompletionFn = vi
@@ -413,37 +525,41 @@ describe('useSlashCompletion', () => {
413
525
  ],
414
526
  }),
415
527
  ];
416
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/chat resume ', slashCommands, mockCommandContext));
417
- await vi.waitFor(() => {
418
- expect(mockCompletionFn).toHaveBeenCalledWith(expect.objectContaining({
419
- invocation: {
420
- raw: '/chat resume',
421
- name: 'resume',
422
- args: '',
423
- },
424
- }), '');
528
+ const { result, unmount } = renderHook(() => useTestHarnessForSlashCompletion(true, '/chat resume ', slashCommands, mockCommandContext));
529
+ await act(async () => {
530
+ await waitFor(() => {
531
+ expect(mockCompletionFn).toHaveBeenCalledWith(expect.objectContaining({
532
+ invocation: {
533
+ raw: '/chat resume ',
534
+ name: 'resume',
535
+ args: '',
536
+ },
537
+ }), '');
538
+ });
425
539
  });
426
- await vi.waitFor(() => {
427
- expect(result.current.suggestions).toHaveLength(3);
540
+ await act(async () => {
541
+ await waitFor(() => {
542
+ expect(result.current.suggestions).toHaveLength(3);
543
+ expect(result.current.completionStart).toBe(13);
544
+ });
428
545
  });
546
+ unmount();
429
547
  });
430
548
  it('should handle completion function that returns null', async () => {
431
- const completionFn = vi.fn().mockResolvedValue(null);
549
+ const mockCompletionFn = vi.fn().mockResolvedValue(null);
432
550
  const slashCommands = [
433
551
  createTestCommand({
434
- name: 'chat',
435
- description: 'Manage chat history',
436
- subCommands: [
437
- createTestCommand({
438
- name: 'resume',
439
- description: 'Resume a saved chat',
440
- completion: completionFn,
441
- }),
442
- ],
552
+ name: 'test',
553
+ description: 'Test command',
554
+ completion: mockCompletionFn,
443
555
  }),
444
556
  ];
445
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/chat resume ', slashCommands, mockCommandContext));
446
- expect(result.current.suggestions).toHaveLength(0);
557
+ const { result, unmount } = renderHook(() => useTestHarnessForSlashCompletion(true, '/test arg', slashCommands, mockCommandContext));
558
+ await waitFor(() => {
559
+ expect(result.current.suggestions).toEqual([]);
560
+ expect(result.current.isLoadingSuggestions).toBe(false);
561
+ });
562
+ unmount();
447
563
  });
448
564
  });
449
565
  describe('Command Kind Information', () => {
@@ -462,21 +578,24 @@ describe('useSlashCompletion', () => {
462
578
  action: vi.fn(),
463
579
  },
464
580
  ];
465
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/', slashCommands, mockCommandContext));
466
- expect(result.current.suggestions).toEqual(expect.arrayContaining([
467
- {
468
- label: 'summarize',
469
- value: 'summarize',
470
- description: 'Summarize content',
471
- commandKind: CommandKind.MCP_PROMPT,
472
- },
473
- {
474
- label: 'help',
475
- value: 'help',
476
- description: 'Show help',
477
- commandKind: CommandKind.BUILT_IN,
478
- },
479
- ]));
581
+ const { result, unmount } = renderHook(() => useTestHarnessForSlashCompletion(true, '/', slashCommands, mockCommandContext));
582
+ await waitFor(() => {
583
+ expect(result.current.suggestions).toEqual(expect.arrayContaining([
584
+ {
585
+ label: 'summarize',
586
+ value: 'summarize',
587
+ description: 'Summarize content',
588
+ commandKind: CommandKind.MCP_PROMPT,
589
+ },
590
+ {
591
+ label: 'help',
592
+ value: 'help',
593
+ description: 'Show help',
594
+ commandKind: CommandKind.BUILT_IN,
595
+ },
596
+ ]));
597
+ });
598
+ unmount();
480
599
  });
481
600
  it('should include commandKind when filtering MCP commands by prefix', async () => {
482
601
  const slashCommands = [
@@ -493,8 +612,8 @@ describe('useSlashCompletion', () => {
493
612
  action: vi.fn(),
494
613
  },
495
614
  ];
496
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/summ', slashCommands, mockCommandContext));
497
- await vi.waitFor(() => {
615
+ const { result, unmount } = renderHook(() => useTestHarnessForSlashCompletion(true, '/summ', slashCommands, mockCommandContext));
616
+ await waitFor(() => {
498
617
  expect(result.current.suggestions).toEqual([
499
618
  {
500
619
  label: 'summarize',
@@ -503,7 +622,9 @@ describe('useSlashCompletion', () => {
503
622
  commandKind: CommandKind.MCP_PROMPT,
504
623
  },
505
624
  ]);
625
+ expect(result.current.completionStart).toBe(1);
506
626
  });
627
+ unmount();
507
628
  });
508
629
  it('should include commandKind for sub-commands', async () => {
509
630
  const slashCommands = [
@@ -527,21 +648,24 @@ describe('useSlashCompletion', () => {
527
648
  ],
528
649
  },
529
650
  ];
530
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/memory', slashCommands, mockCommandContext));
531
- expect(result.current.suggestions).toEqual(expect.arrayContaining([
532
- {
533
- label: 'show',
534
- value: 'show',
535
- description: 'Show memory',
536
- commandKind: CommandKind.BUILT_IN,
537
- },
538
- {
539
- label: 'add',
540
- value: 'add',
541
- description: 'Add to memory',
542
- commandKind: CommandKind.MCP_PROMPT,
543
- },
544
- ]));
651
+ const { result, unmount } = renderHook(() => useTestHarnessForSlashCompletion(true, '/memory', slashCommands, mockCommandContext));
652
+ await waitFor(() => {
653
+ expect(result.current.suggestions).toEqual(expect.arrayContaining([
654
+ {
655
+ label: 'show',
656
+ value: 'show',
657
+ description: 'Show memory',
658
+ commandKind: CommandKind.BUILT_IN,
659
+ },
660
+ {
661
+ label: 'add',
662
+ value: 'add',
663
+ description: 'Add to memory',
664
+ commandKind: CommandKind.MCP_PROMPT,
665
+ },
666
+ ]));
667
+ });
668
+ unmount();
545
669
  });
546
670
  it('should include commandKind for file commands', async () => {
547
671
  const slashCommands = [
@@ -552,8 +676,8 @@ describe('useSlashCompletion', () => {
552
676
  action: vi.fn(),
553
677
  },
554
678
  ];
555
- const { result } = renderHook(() => useTestHarnessForSlashCompletion(true, '/custom', slashCommands, mockCommandContext));
556
- await vi.waitFor(() => {
679
+ const { result, unmount } = renderHook(() => useTestHarnessForSlashCompletion(true, '/custom', slashCommands, mockCommandContext));
680
+ await waitFor(() => {
557
681
  expect(result.current.suggestions).toEqual([
558
682
  {
559
683
  label: 'custom-script',
@@ -562,10 +686,12 @@ describe('useSlashCompletion', () => {
562
686
  commandKind: CommandKind.FILE,
563
687
  },
564
688
  ]);
689
+ expect(result.current.completionStart).toBe(1);
565
690
  });
691
+ unmount();
566
692
  });
567
693
  });
568
- it('should not call shared callbacks when disabled', () => {
694
+ it('should not call shared callbacks when disabled', async () => {
569
695
  const mockSetSuggestions = vi.fn();
570
696
  const mockSetIsLoadingSuggestions = vi.fn();
571
697
  const mockSetIsPerfectMatch = vi.fn();
@@ -575,7 +701,7 @@ describe('useSlashCompletion', () => {
575
701
  description: 'Show help',
576
702
  }),
577
703
  ];
578
- const { rerender } = renderHook(({ enabled, query }) => useSlashCompletion({
704
+ const { rerender, unmount } = renderHook(({ enabled, query }) => useSlashCompletion({
579
705
  enabled,
580
706
  query,
581
707
  slashCommands,
@@ -593,10 +719,17 @@ describe('useSlashCompletion', () => {
593
719
  // Change query while disabled (simulating @ completion typing)
594
720
  rerender({ enabled: false, query: '@src/file.ts' });
595
721
  rerender({ enabled: false, query: '@src/file.tsx' });
722
+ // Wait for any internal async operations to settle to avoid act warnings
723
+ await act(async () => {
724
+ await new Promise((resolve) => setTimeout(resolve, 0));
725
+ });
596
726
  // Should not have called shared callbacks during @ completion typing
597
- expect(mockSetSuggestions).not.toHaveBeenCalled();
598
- expect(mockSetIsLoadingSuggestions).not.toHaveBeenCalled();
599
- expect(mockSetIsPerfectMatch).not.toHaveBeenCalled();
727
+ await waitFor(() => {
728
+ expect(mockSetSuggestions).not.toHaveBeenCalled();
729
+ expect(mockSetIsLoadingSuggestions).not.toHaveBeenCalled();
730
+ expect(mockSetIsPerfectMatch).not.toHaveBeenCalled();
731
+ });
732
+ unmount();
600
733
  });
601
734
  });
602
735
  //# sourceMappingURL=useSlashCompletion.test.js.map