@google/gemini-cli 0.1.21 → 0.1.22

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 (283) hide show
  1. package/README.md +26 -28
  2. package/dist/package.json +2 -2
  3. package/dist/src/commands/mcp/add.js +21 -10
  4. package/dist/src/commands/mcp/add.js.map +1 -1
  5. package/dist/src/commands/mcp/remove.js +2 -2
  6. package/dist/src/commands/mcp/remove.js.map +1 -1
  7. package/dist/src/config/auth.js +4 -3
  8. package/dist/src/config/auth.js.map +1 -1
  9. package/dist/src/config/auth.test.d.ts +6 -0
  10. package/dist/src/config/auth.test.js +57 -0
  11. package/dist/src/config/auth.test.js.map +1 -0
  12. package/dist/src/config/config.d.ts +1 -0
  13. package/dist/src/config/config.js +18 -11
  14. package/dist/src/config/config.js.map +1 -1
  15. package/dist/src/config/keyBindings.js +3 -2
  16. package/dist/src/config/keyBindings.js.map +1 -1
  17. package/dist/src/config/keyBindings.test.d.ts +6 -0
  18. package/dist/src/config/keyBindings.test.js +51 -0
  19. package/dist/src/config/keyBindings.test.js.map +1 -0
  20. package/dist/src/config/sandboxConfig.js +3 -3
  21. package/dist/src/config/sandboxConfig.js.map +1 -1
  22. package/dist/src/config/settings.js +7 -7
  23. package/dist/src/config/settings.js.map +1 -1
  24. package/dist/src/config/settingsSchema.test.d.ts +6 -0
  25. package/dist/src/config/settingsSchema.test.js +195 -0
  26. package/dist/src/config/settingsSchema.test.js.map +1 -0
  27. package/dist/src/config/trustedFolders.d.ts +2 -1
  28. package/dist/src/config/trustedFolders.js +7 -1
  29. package/dist/src/config/trustedFolders.js.map +1 -1
  30. package/dist/src/config/trustedFolders.test.d.ts +6 -0
  31. package/dist/src/config/trustedFolders.test.js +160 -0
  32. package/dist/src/config/trustedFolders.test.js.map +1 -0
  33. package/dist/src/gemini.js +17 -7
  34. package/dist/src/gemini.js.map +1 -1
  35. package/dist/src/gemini.test.d.ts +6 -0
  36. package/dist/src/gemini.test.js +193 -0
  37. package/dist/src/gemini.test.js.map +1 -0
  38. package/dist/src/generated/git-commit.d.ts +2 -1
  39. package/dist/src/generated/git-commit.js +2 -1
  40. package/dist/src/generated/git-commit.js.map +1 -1
  41. package/dist/src/nonInteractiveCli.js +1 -3
  42. package/dist/src/nonInteractiveCli.js.map +1 -1
  43. package/dist/src/services/BuiltinCommandLoader.test.d.ts +6 -0
  44. package/dist/src/services/BuiltinCommandLoader.test.js +108 -0
  45. package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -0
  46. package/dist/src/services/CommandService.test.d.ts +6 -0
  47. package/dist/src/services/CommandService.test.js +232 -0
  48. package/dist/src/services/CommandService.test.js.map +1 -0
  49. package/dist/src/services/FileCommandLoader.js +10 -8
  50. package/dist/src/services/FileCommandLoader.js.map +1 -1
  51. package/dist/src/services/McpPromptLoader.js +3 -3
  52. package/dist/src/services/McpPromptLoader.js.map +1 -1
  53. package/dist/src/services/prompt-processors/argumentProcessor.d.ts +2 -7
  54. package/dist/src/services/prompt-processors/argumentProcessor.js +2 -10
  55. package/dist/src/services/prompt-processors/argumentProcessor.js.map +1 -1
  56. package/dist/src/services/prompt-processors/shellProcessor.d.ts +16 -13
  57. package/dist/src/services/prompt-processors/shellProcessor.js +133 -40
  58. package/dist/src/services/prompt-processors/shellProcessor.js.map +1 -1
  59. package/dist/src/services/prompt-processors/types.d.ts +2 -0
  60. package/dist/src/services/prompt-processors/types.js +2 -0
  61. package/dist/src/services/prompt-processors/types.js.map +1 -1
  62. package/dist/src/test-utils/customMatchers.d.ts +14 -0
  63. package/dist/src/test-utils/customMatchers.js +46 -0
  64. package/dist/src/test-utils/customMatchers.js.map +1 -0
  65. package/dist/src/test-utils/mockCommandContext.d.ts +18 -0
  66. package/dist/src/test-utils/mockCommandContext.js +86 -0
  67. package/dist/src/test-utils/mockCommandContext.js.map +1 -0
  68. package/dist/src/test-utils/mockCommandContext.test.d.ts +6 -0
  69. package/dist/src/test-utils/mockCommandContext.test.js +51 -0
  70. package/dist/src/test-utils/mockCommandContext.test.js.map +1 -0
  71. package/dist/src/test-utils/render.d.ts +8 -0
  72. package/dist/src/test-utils/render.js +10 -0
  73. package/dist/src/test-utils/render.js.map +1 -0
  74. package/dist/src/ui/App.js +10 -8
  75. package/dist/src/ui/App.js.map +1 -1
  76. package/dist/src/ui/IdeIntegrationNudge.js +3 -3
  77. package/dist/src/ui/IdeIntegrationNudge.js.map +1 -1
  78. package/dist/src/ui/commands/aboutCommand.js +8 -5
  79. package/dist/src/ui/commands/aboutCommand.js.map +1 -1
  80. package/dist/src/ui/commands/bugCommand.js +6 -4
  81. package/dist/src/ui/commands/bugCommand.js.map +1 -1
  82. package/dist/src/ui/commands/chatCommand.js +8 -6
  83. package/dist/src/ui/commands/chatCommand.js.map +1 -1
  84. package/dist/src/ui/commands/docsCommand.js +1 -1
  85. package/dist/src/ui/commands/docsCommand.js.map +1 -1
  86. package/dist/src/ui/commands/ideCommand.js +2 -2
  87. package/dist/src/ui/commands/ideCommand.js.map +1 -1
  88. package/dist/src/ui/commands/setupGithubCommand.test.d.ts +6 -0
  89. package/dist/src/ui/commands/setupGithubCommand.test.js +74 -0
  90. package/dist/src/ui/commands/setupGithubCommand.test.js.map +1 -0
  91. package/dist/src/ui/components/AboutBox.d.ts +1 -0
  92. package/dist/src/ui/components/AboutBox.js +1 -1
  93. package/dist/src/ui/components/AboutBox.js.map +1 -1
  94. package/dist/src/ui/components/AuthDialog.js +8 -8
  95. package/dist/src/ui/components/AuthDialog.js.map +1 -1
  96. package/dist/src/ui/components/AuthDialog.test.d.ts +6 -0
  97. package/dist/src/ui/components/AuthDialog.test.js +242 -0
  98. package/dist/src/ui/components/AuthDialog.test.js.map +1 -0
  99. package/dist/src/ui/components/ContextSummaryDisplay.js +1 -1
  100. package/dist/src/ui/components/FolderTrustDialog.test.d.ts +6 -0
  101. package/dist/src/ui/components/FolderTrustDialog.test.js +26 -0
  102. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -0
  103. package/dist/src/ui/components/Footer.d.ts +1 -0
  104. package/dist/src/ui/components/Footer.js +3 -2
  105. package/dist/src/ui/components/Footer.js.map +1 -1
  106. package/dist/src/ui/components/Header.test.d.ts +6 -0
  107. package/dist/src/ui/components/Header.test.js +37 -0
  108. package/dist/src/ui/components/Header.test.js.map +1 -0
  109. package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
  110. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  111. package/dist/src/ui/components/HistoryItemDisplay.test.d.ts +6 -0
  112. package/dist/src/ui/components/HistoryItemDisplay.test.js +91 -0
  113. package/dist/src/ui/components/HistoryItemDisplay.test.js.map +1 -0
  114. package/dist/src/ui/components/InputPrompt.js +0 -4
  115. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  116. package/dist/src/ui/components/LoadingIndicator.test.d.ts +6 -0
  117. package/dist/src/ui/components/LoadingIndicator.test.js +190 -0
  118. package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -0
  119. package/dist/src/ui/components/SettingsDialog.test.d.ts +6 -0
  120. package/dist/src/ui/components/SettingsDialog.test.js +555 -0
  121. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -0
  122. package/dist/src/ui/components/ShellConfirmationDialog.js +2 -1
  123. package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
  124. package/dist/src/ui/components/ShellConfirmationDialog.test.d.ts +6 -0
  125. package/dist/src/ui/components/ShellConfirmationDialog.test.js +40 -0
  126. package/dist/src/ui/components/ShellConfirmationDialog.test.js.map +1 -0
  127. package/dist/src/ui/components/StatsDisplay.js +1 -1
  128. package/dist/src/ui/components/StatsDisplay.js.map +1 -1
  129. package/dist/src/ui/components/messages/DiffRenderer.js +10 -1
  130. package/dist/src/ui/components/messages/DiffRenderer.js.map +1 -1
  131. package/dist/src/ui/components/messages/DiffRenderer.test.d.ts +6 -0
  132. package/dist/src/ui/components/messages/DiffRenderer.test.js +239 -0
  133. package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -0
  134. package/dist/src/ui/components/messages/InfoMessage.js +2 -1
  135. package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
  136. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +2 -1
  137. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  138. package/dist/src/ui/components/messages/ToolConfirmationMessage.test.d.ts +6 -0
  139. package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js +37 -0
  140. package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js.map +1 -0
  141. package/dist/src/ui/components/messages/ToolMessage.test.d.ts +6 -0
  142. package/dist/src/ui/components/messages/ToolMessage.test.js +118 -0
  143. package/dist/src/ui/components/messages/ToolMessage.test.js.map +1 -0
  144. package/dist/src/ui/components/shared/MaxSizedBox.js +1 -1
  145. package/dist/src/ui/components/shared/MaxSizedBox.js.map +1 -1
  146. package/dist/src/ui/components/shared/MaxSizedBox.test.d.ts +6 -0
  147. package/dist/src/ui/components/shared/MaxSizedBox.test.js +154 -0
  148. package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -0
  149. package/dist/src/ui/components/shared/RadioButtonSelect.js +1 -1
  150. package/dist/src/ui/components/shared/RadioButtonSelect.js.map +1 -1
  151. package/dist/src/ui/components/shared/RadioButtonSelect.test.d.ts +6 -0
  152. package/dist/src/ui/components/shared/RadioButtonSelect.test.js +111 -0
  153. package/dist/src/ui/components/shared/RadioButtonSelect.test.js.map +1 -0
  154. package/dist/src/ui/contexts/KeypressContext.d.ts +30 -0
  155. package/dist/src/ui/contexts/KeypressContext.js +310 -0
  156. package/dist/src/ui/contexts/KeypressContext.js.map +1 -0
  157. package/dist/src/ui/contexts/KeypressContext.test.d.ts +6 -0
  158. package/dist/src/ui/contexts/KeypressContext.test.js +220 -0
  159. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -0
  160. package/dist/src/ui/contexts/SessionContext.d.ts +1 -0
  161. package/dist/src/ui/contexts/SessionContext.js +2 -1
  162. package/dist/src/ui/contexts/SessionContext.js.map +1 -1
  163. package/dist/src/ui/hooks/atCommandProcessor.js +9 -9
  164. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  165. package/dist/src/ui/hooks/atCommandProcessor.test.d.ts +6 -0
  166. package/dist/src/ui/hooks/atCommandProcessor.test.js +802 -0
  167. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -0
  168. package/dist/src/ui/hooks/shellCommandProcessor.test.d.ts +6 -0
  169. package/dist/src/ui/hooks/shellCommandProcessor.test.js +328 -0
  170. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -0
  171. package/dist/src/ui/hooks/slashCommandProcessor.js +7 -7
  172. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  173. package/dist/src/ui/hooks/useAtCompletion.js +3 -5
  174. package/dist/src/ui/hooks/useAtCompletion.js.map +1 -1
  175. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.d.ts +6 -0
  176. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +191 -0
  177. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -0
  178. package/dist/src/ui/hooks/useEditorSettings.test.d.ts +6 -0
  179. package/dist/src/ui/hooks/useEditorSettings.test.js +164 -0
  180. package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -0
  181. package/dist/src/ui/hooks/useFolderTrust.d.ts +2 -2
  182. package/dist/src/ui/hooks/useFolderTrust.js +23 -5
  183. package/dist/src/ui/hooks/useFolderTrust.js.map +1 -1
  184. package/dist/src/ui/hooks/useGitBranchName.test.d.ts +6 -0
  185. package/dist/src/ui/hooks/useGitBranchName.test.js +175 -0
  186. package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -0
  187. package/dist/src/ui/hooks/useHistoryManager.test.d.ts +6 -0
  188. package/dist/src/ui/hooks/useHistoryManager.test.js +171 -0
  189. package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -0
  190. package/dist/src/ui/hooks/useInputHistory.test.d.ts +6 -0
  191. package/dist/src/ui/hooks/useInputHistory.test.js +207 -0
  192. package/dist/src/ui/hooks/useInputHistory.test.js.map +1 -0
  193. package/dist/src/ui/hooks/useKeypress.d.ts +4 -24
  194. package/dist/src/ui/hooks/useKeypress.js +9 -330
  195. package/dist/src/ui/hooks/useKeypress.js.map +1 -1
  196. package/dist/src/ui/hooks/useLoadingIndicator.test.d.ts +6 -0
  197. package/dist/src/ui/hooks/useLoadingIndicator.test.js +91 -0
  198. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -0
  199. package/dist/src/ui/hooks/useReverseSearchCompletion.test.d.ts +6 -0
  200. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +163 -0
  201. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -0
  202. package/dist/src/ui/hooks/useShellHistory.test.d.ts +6 -0
  203. package/dist/src/ui/hooks/useShellHistory.test.js +162 -0
  204. package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -0
  205. package/dist/src/ui/hooks/useSlashCompletion.test.d.ts +6 -0
  206. package/dist/src/ui/hooks/useSlashCompletion.test.js +272 -0
  207. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -0
  208. package/dist/src/ui/hooks/useThemeCommand.js +1 -1
  209. package/dist/src/ui/hooks/useThemeCommand.js.map +1 -1
  210. package/dist/src/ui/hooks/useTimer.test.d.ts +6 -0
  211. package/dist/src/ui/hooks/useTimer.test.js +90 -0
  212. package/dist/src/ui/hooks/useTimer.test.js.map +1 -0
  213. package/dist/src/ui/hooks/useToolScheduler.test.d.ts +6 -0
  214. package/dist/src/ui/hooks/useToolScheduler.test.js +841 -0
  215. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -0
  216. package/dist/src/ui/keyMatchers.test.d.ts +6 -0
  217. package/dist/src/ui/keyMatchers.test.js +276 -0
  218. package/dist/src/ui/keyMatchers.test.js.map +1 -0
  219. package/dist/src/ui/themes/color-utils.test.d.ts +6 -0
  220. package/dist/src/ui/themes/color-utils.test.js +197 -0
  221. package/dist/src/ui/themes/color-utils.test.js.map +1 -0
  222. package/dist/src/ui/themes/theme-manager.js +1 -1
  223. package/dist/src/ui/themes/theme-manager.js.map +1 -1
  224. package/dist/src/ui/themes/theme-manager.test.d.ts +6 -0
  225. package/dist/src/ui/themes/theme-manager.test.js +83 -0
  226. package/dist/src/ui/themes/theme-manager.test.js.map +1 -0
  227. package/dist/src/ui/types.d.ts +2 -0
  228. package/dist/src/ui/types.js.map +1 -1
  229. package/dist/src/ui/utils/CodeColorizer.js +1 -1
  230. package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
  231. package/dist/src/ui/utils/InlineMarkdownRenderer.js +8 -1
  232. package/dist/src/ui/utils/InlineMarkdownRenderer.js.map +1 -1
  233. package/dist/src/ui/utils/MarkdownDisplay.test.d.ts +6 -0
  234. package/dist/src/ui/utils/MarkdownDisplay.test.js +151 -0
  235. package/dist/src/ui/utils/MarkdownDisplay.test.js.map +1 -0
  236. package/dist/src/ui/utils/clipboardUtils.test.d.ts +6 -0
  237. package/dist/src/ui/utils/clipboardUtils.test.js +65 -0
  238. package/dist/src/ui/utils/clipboardUtils.test.js.map +1 -0
  239. package/dist/src/ui/utils/commandUtils.test.d.ts +6 -0
  240. package/dist/src/ui/utils/commandUtils.test.js +294 -0
  241. package/dist/src/ui/utils/commandUtils.test.js.map +1 -0
  242. package/dist/src/ui/utils/displayUtils.test.d.ts +6 -0
  243. package/dist/src/ui/utils/displayUtils.test.js +42 -0
  244. package/dist/src/ui/utils/displayUtils.test.js.map +1 -0
  245. package/dist/src/ui/utils/formatters.test.d.ts +6 -0
  246. package/dist/src/ui/utils/formatters.test.js +56 -0
  247. package/dist/src/ui/utils/formatters.test.js.map +1 -0
  248. package/dist/src/ui/utils/markdownUtilities.test.d.ts +6 -0
  249. package/dist/src/ui/utils/markdownUtilities.test.js +42 -0
  250. package/dist/src/ui/utils/markdownUtilities.test.js.map +1 -0
  251. package/dist/src/ui/utils/platformConstants.d.ts +5 -0
  252. package/dist/src/ui/utils/platformConstants.js +5 -0
  253. package/dist/src/ui/utils/platformConstants.js.map +1 -1
  254. package/dist/src/ui/utils/terminalSetup.js +7 -7
  255. package/dist/src/ui/utils/terminalSetup.js.map +1 -1
  256. package/dist/src/ui/utils/updateCheck.js +1 -1
  257. package/dist/src/ui/utils/updateCheck.js.map +1 -1
  258. package/dist/src/ui/utils/updateCheck.test.d.ts +6 -0
  259. package/dist/src/ui/utils/updateCheck.test.js +145 -0
  260. package/dist/src/ui/utils/updateCheck.test.js.map +1 -0
  261. package/dist/src/utils/gitUtils.test.d.ts +6 -0
  262. package/dist/src/utils/gitUtils.test.js +113 -0
  263. package/dist/src/utils/gitUtils.test.js.map +1 -0
  264. package/dist/src/utils/installationInfo.test.d.ts +6 -0
  265. package/dist/src/utils/installationInfo.test.js +242 -0
  266. package/dist/src/utils/installationInfo.test.js.map +1 -0
  267. package/dist/src/utils/readStdin.js +10 -0
  268. package/dist/src/utils/readStdin.js.map +1 -1
  269. package/dist/src/utils/sandbox.js +62 -60
  270. package/dist/src/utils/sandbox.js.map +1 -1
  271. package/dist/src/utils/settingsUtils.test.d.ts +6 -0
  272. package/dist/src/utils/settingsUtils.test.js +514 -0
  273. package/dist/src/utils/settingsUtils.test.js.map +1 -0
  274. package/dist/src/utils/userStartupWarnings.test.d.ts +6 -0
  275. package/dist/src/utils/userStartupWarnings.test.js +67 -0
  276. package/dist/src/utils/userStartupWarnings.test.js.map +1 -0
  277. package/dist/src/utils/version.js +1 -1
  278. package/dist/src/utils/version.js.map +1 -1
  279. package/dist/src/validateNonInterActiveAuth.js +3 -3
  280. package/dist/src/validateNonInterActiveAuth.js.map +1 -1
  281. package/dist/src/zed-integration/schema.d.ts +322 -322
  282. package/dist/tsconfig.tsbuildinfo +1 -1
  283. package/package.json +3 -3
@@ -0,0 +1,191 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, vi, beforeEach, } from 'vitest';
7
+ import { renderHook, act } from '@testing-library/react';
8
+ import { useAutoAcceptIndicator } from './useAutoAcceptIndicator.js';
9
+ import { Config, ApprovalMode, } from '@google/gemini-cli-core';
10
+ import { useKeypress } from './useKeypress.js';
11
+ vi.mock('./useKeypress.js');
12
+ vi.mock('@google/gemini-cli-core', async () => {
13
+ const actualServerModule = (await vi.importActual('@google/gemini-cli-core'));
14
+ return {
15
+ ...actualServerModule,
16
+ Config: vi.fn(),
17
+ };
18
+ });
19
+ describe('useAutoAcceptIndicator', () => {
20
+ let mockConfigInstance;
21
+ let capturedUseKeypressHandler;
22
+ let mockedUseKeypress;
23
+ beforeEach(() => {
24
+ vi.resetAllMocks();
25
+ Config.mockImplementation(() => {
26
+ const instanceGetApprovalModeMock = vi.fn();
27
+ const instanceSetApprovalModeMock = vi.fn();
28
+ const instance = {
29
+ getApprovalMode: instanceGetApprovalModeMock,
30
+ setApprovalMode: instanceSetApprovalModeMock,
31
+ getCoreTools: vi.fn().mockReturnValue([]),
32
+ getToolDiscoveryCommand: vi.fn().mockReturnValue(undefined),
33
+ getTargetDir: vi.fn().mockReturnValue('.'),
34
+ getApiKey: vi.fn().mockReturnValue('test-api-key'),
35
+ getModel: vi.fn().mockReturnValue('test-model'),
36
+ getSandbox: vi.fn().mockReturnValue(false),
37
+ getDebugMode: vi.fn().mockReturnValue(false),
38
+ getQuestion: vi.fn().mockReturnValue(undefined),
39
+ getFullContext: vi.fn().mockReturnValue(false),
40
+ getUserAgent: vi.fn().mockReturnValue('test-user-agent'),
41
+ getUserMemory: vi.fn().mockReturnValue(''),
42
+ getGeminiMdFileCount: vi.fn().mockReturnValue(0),
43
+ getToolRegistry: vi
44
+ .fn()
45
+ .mockReturnValue({ discoverTools: vi.fn() }),
46
+ };
47
+ instanceSetApprovalModeMock.mockImplementation((value) => {
48
+ instanceGetApprovalModeMock.mockReturnValue(value);
49
+ });
50
+ return instance;
51
+ });
52
+ mockedUseKeypress = useKeypress;
53
+ mockedUseKeypress.mockImplementation((handler, _options) => {
54
+ capturedUseKeypressHandler = handler;
55
+ });
56
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
+ mockConfigInstance = new Config();
58
+ });
59
+ it('should initialize with ApprovalMode.AUTO_EDIT if config.getApprovalMode returns ApprovalMode.AUTO_EDIT', () => {
60
+ mockConfigInstance.getApprovalMode.mockReturnValue(ApprovalMode.AUTO_EDIT);
61
+ const { result } = renderHook(() => useAutoAcceptIndicator({
62
+ config: mockConfigInstance,
63
+ }));
64
+ expect(result.current).toBe(ApprovalMode.AUTO_EDIT);
65
+ expect(mockConfigInstance.getApprovalMode).toHaveBeenCalledTimes(1);
66
+ });
67
+ it('should initialize with ApprovalMode.DEFAULT if config.getApprovalMode returns ApprovalMode.DEFAULT', () => {
68
+ mockConfigInstance.getApprovalMode.mockReturnValue(ApprovalMode.DEFAULT);
69
+ const { result } = renderHook(() => useAutoAcceptIndicator({
70
+ config: mockConfigInstance,
71
+ }));
72
+ expect(result.current).toBe(ApprovalMode.DEFAULT);
73
+ expect(mockConfigInstance.getApprovalMode).toHaveBeenCalledTimes(1);
74
+ });
75
+ it('should initialize with ApprovalMode.YOLO if config.getApprovalMode returns ApprovalMode.YOLO', () => {
76
+ mockConfigInstance.getApprovalMode.mockReturnValue(ApprovalMode.YOLO);
77
+ const { result } = renderHook(() => useAutoAcceptIndicator({
78
+ config: mockConfigInstance,
79
+ }));
80
+ expect(result.current).toBe(ApprovalMode.YOLO);
81
+ expect(mockConfigInstance.getApprovalMode).toHaveBeenCalledTimes(1);
82
+ });
83
+ it('should toggle the indicator and update config when Shift+Tab or Ctrl+Y is pressed', () => {
84
+ mockConfigInstance.getApprovalMode.mockReturnValue(ApprovalMode.DEFAULT);
85
+ const { result } = renderHook(() => useAutoAcceptIndicator({
86
+ config: mockConfigInstance,
87
+ }));
88
+ expect(result.current).toBe(ApprovalMode.DEFAULT);
89
+ act(() => {
90
+ capturedUseKeypressHandler({
91
+ name: 'tab',
92
+ shift: true,
93
+ });
94
+ });
95
+ expect(mockConfigInstance.setApprovalMode).toHaveBeenCalledWith(ApprovalMode.AUTO_EDIT);
96
+ expect(result.current).toBe(ApprovalMode.AUTO_EDIT);
97
+ act(() => {
98
+ capturedUseKeypressHandler({ name: 'y', ctrl: true });
99
+ });
100
+ expect(mockConfigInstance.setApprovalMode).toHaveBeenCalledWith(ApprovalMode.YOLO);
101
+ expect(result.current).toBe(ApprovalMode.YOLO);
102
+ act(() => {
103
+ capturedUseKeypressHandler({ name: 'y', ctrl: true });
104
+ });
105
+ expect(mockConfigInstance.setApprovalMode).toHaveBeenCalledWith(ApprovalMode.DEFAULT);
106
+ expect(result.current).toBe(ApprovalMode.DEFAULT);
107
+ act(() => {
108
+ capturedUseKeypressHandler({ name: 'y', ctrl: true });
109
+ });
110
+ expect(mockConfigInstance.setApprovalMode).toHaveBeenCalledWith(ApprovalMode.YOLO);
111
+ expect(result.current).toBe(ApprovalMode.YOLO);
112
+ act(() => {
113
+ capturedUseKeypressHandler({
114
+ name: 'tab',
115
+ shift: true,
116
+ });
117
+ });
118
+ expect(mockConfigInstance.setApprovalMode).toHaveBeenCalledWith(ApprovalMode.AUTO_EDIT);
119
+ expect(result.current).toBe(ApprovalMode.AUTO_EDIT);
120
+ act(() => {
121
+ capturedUseKeypressHandler({
122
+ name: 'tab',
123
+ shift: true,
124
+ });
125
+ });
126
+ expect(mockConfigInstance.setApprovalMode).toHaveBeenCalledWith(ApprovalMode.DEFAULT);
127
+ expect(result.current).toBe(ApprovalMode.DEFAULT);
128
+ });
129
+ it('should not toggle if only one key or other keys combinations are pressed', () => {
130
+ mockConfigInstance.getApprovalMode.mockReturnValue(ApprovalMode.DEFAULT);
131
+ renderHook(() => useAutoAcceptIndicator({
132
+ config: mockConfigInstance,
133
+ }));
134
+ act(() => {
135
+ capturedUseKeypressHandler({
136
+ name: 'tab',
137
+ shift: false,
138
+ });
139
+ });
140
+ expect(mockConfigInstance.setApprovalMode).not.toHaveBeenCalled();
141
+ act(() => {
142
+ capturedUseKeypressHandler({
143
+ name: 'unknown',
144
+ shift: true,
145
+ });
146
+ });
147
+ expect(mockConfigInstance.setApprovalMode).not.toHaveBeenCalled();
148
+ act(() => {
149
+ capturedUseKeypressHandler({
150
+ name: 'a',
151
+ shift: false,
152
+ ctrl: false,
153
+ });
154
+ });
155
+ expect(mockConfigInstance.setApprovalMode).not.toHaveBeenCalled();
156
+ act(() => {
157
+ capturedUseKeypressHandler({ name: 'y', ctrl: false });
158
+ });
159
+ expect(mockConfigInstance.setApprovalMode).not.toHaveBeenCalled();
160
+ act(() => {
161
+ capturedUseKeypressHandler({ name: 'a', ctrl: true });
162
+ });
163
+ expect(mockConfigInstance.setApprovalMode).not.toHaveBeenCalled();
164
+ act(() => {
165
+ capturedUseKeypressHandler({ name: 'y', shift: true });
166
+ });
167
+ expect(mockConfigInstance.setApprovalMode).not.toHaveBeenCalled();
168
+ act(() => {
169
+ capturedUseKeypressHandler({
170
+ name: 'a',
171
+ ctrl: true,
172
+ shift: true,
173
+ });
174
+ });
175
+ expect(mockConfigInstance.setApprovalMode).not.toHaveBeenCalled();
176
+ });
177
+ it('should update indicator when config value changes externally (useEffect dependency)', () => {
178
+ mockConfigInstance.getApprovalMode.mockReturnValue(ApprovalMode.DEFAULT);
179
+ const { result, rerender } = renderHook((props) => useAutoAcceptIndicator(props), {
180
+ initialProps: {
181
+ config: mockConfigInstance,
182
+ },
183
+ });
184
+ expect(result.current).toBe(ApprovalMode.DEFAULT);
185
+ mockConfigInstance.getApprovalMode.mockReturnValue(ApprovalMode.AUTO_EDIT);
186
+ rerender({ config: mockConfigInstance });
187
+ expect(result.current).toBe(ApprovalMode.AUTO_EDIT);
188
+ expect(mockConfigInstance.getApprovalMode).toHaveBeenCalledTimes(3);
189
+ });
190
+ });
191
+ //# sourceMappingURL=useAutoAcceptIndicator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAutoAcceptIndicator.test.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useAutoAcceptIndicator.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};
@@ -0,0 +1,164 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { afterEach, beforeEach, describe, expect, it, vi, } from 'vitest';
7
+ import { act } from 'react';
8
+ import { renderHook } from '@testing-library/react';
9
+ import { useEditorSettings } from './useEditorSettings.js';
10
+ import { SettingScope } from '../../config/settings.js';
11
+ import { MessageType } from '../types.js';
12
+ import { checkHasEditorType, allowEditorTypeInSandbox, } from '@google/gemini-cli-core';
13
+ vi.mock('@google/gemini-cli-core', async () => {
14
+ const actual = await vi.importActual('@google/gemini-cli-core');
15
+ return {
16
+ ...actual,
17
+ checkHasEditorType: vi.fn(() => true),
18
+ allowEditorTypeInSandbox: vi.fn(() => true),
19
+ };
20
+ });
21
+ const mockCheckHasEditorType = vi.mocked(checkHasEditorType);
22
+ const mockAllowEditorTypeInSandbox = vi.mocked(allowEditorTypeInSandbox);
23
+ describe('useEditorSettings', () => {
24
+ let mockLoadedSettings;
25
+ let mockSetEditorError;
26
+ let mockAddItem;
27
+ beforeEach(() => {
28
+ vi.resetAllMocks();
29
+ mockLoadedSettings = {
30
+ setValue: vi.fn(),
31
+ };
32
+ mockSetEditorError = vi.fn();
33
+ mockAddItem = vi.fn();
34
+ // Reset mock implementations to default
35
+ mockCheckHasEditorType.mockReturnValue(true);
36
+ mockAllowEditorTypeInSandbox.mockReturnValue(true);
37
+ });
38
+ afterEach(() => {
39
+ vi.restoreAllMocks();
40
+ });
41
+ it('should initialize with dialog closed', () => {
42
+ const { result } = renderHook(() => useEditorSettings(mockLoadedSettings, mockSetEditorError, mockAddItem));
43
+ expect(result.current.isEditorDialogOpen).toBe(false);
44
+ });
45
+ it('should open editor dialog when openEditorDialog is called', () => {
46
+ const { result } = renderHook(() => useEditorSettings(mockLoadedSettings, mockSetEditorError, mockAddItem));
47
+ act(() => {
48
+ result.current.openEditorDialog();
49
+ });
50
+ expect(result.current.isEditorDialogOpen).toBe(true);
51
+ });
52
+ it('should close editor dialog when exitEditorDialog is called', () => {
53
+ const { result } = renderHook(() => useEditorSettings(mockLoadedSettings, mockSetEditorError, mockAddItem));
54
+ act(() => {
55
+ result.current.openEditorDialog();
56
+ result.current.exitEditorDialog();
57
+ });
58
+ expect(result.current.isEditorDialogOpen).toBe(false);
59
+ });
60
+ it('should handle editor selection successfully', () => {
61
+ const { result } = renderHook(() => useEditorSettings(mockLoadedSettings, mockSetEditorError, mockAddItem));
62
+ const editorType = 'vscode';
63
+ const scope = SettingScope.User;
64
+ act(() => {
65
+ result.current.openEditorDialog();
66
+ result.current.handleEditorSelect(editorType, scope);
67
+ });
68
+ expect(mockLoadedSettings.setValue).toHaveBeenCalledWith(scope, 'preferredEditor', editorType);
69
+ expect(mockAddItem).toHaveBeenCalledWith({
70
+ type: MessageType.INFO,
71
+ text: 'Editor preference set to "vscode" in User settings.',
72
+ }, expect.any(Number));
73
+ expect(mockSetEditorError).toHaveBeenCalledWith(null);
74
+ expect(result.current.isEditorDialogOpen).toBe(false);
75
+ });
76
+ it('should handle clearing editor preference (undefined editor)', () => {
77
+ const { result } = renderHook(() => useEditorSettings(mockLoadedSettings, mockSetEditorError, mockAddItem));
78
+ const scope = SettingScope.Workspace;
79
+ act(() => {
80
+ result.current.openEditorDialog();
81
+ result.current.handleEditorSelect(undefined, scope);
82
+ });
83
+ expect(mockLoadedSettings.setValue).toHaveBeenCalledWith(scope, 'preferredEditor', undefined);
84
+ expect(mockAddItem).toHaveBeenCalledWith({
85
+ type: MessageType.INFO,
86
+ text: 'Editor preference cleared in Workspace settings.',
87
+ }, expect.any(Number));
88
+ expect(mockSetEditorError).toHaveBeenCalledWith(null);
89
+ expect(result.current.isEditorDialogOpen).toBe(false);
90
+ });
91
+ it('should handle different editor types', () => {
92
+ const { result } = renderHook(() => useEditorSettings(mockLoadedSettings, mockSetEditorError, mockAddItem));
93
+ const editorTypes = ['cursor', 'windsurf', 'vim'];
94
+ const scope = SettingScope.User;
95
+ editorTypes.forEach((editorType) => {
96
+ act(() => {
97
+ result.current.handleEditorSelect(editorType, scope);
98
+ });
99
+ expect(mockLoadedSettings.setValue).toHaveBeenCalledWith(scope, 'preferredEditor', editorType);
100
+ expect(mockAddItem).toHaveBeenCalledWith({
101
+ type: MessageType.INFO,
102
+ text: `Editor preference set to "${editorType}" in User settings.`,
103
+ }, expect.any(Number));
104
+ });
105
+ });
106
+ it('should handle different setting scopes', () => {
107
+ const { result } = renderHook(() => useEditorSettings(mockLoadedSettings, mockSetEditorError, mockAddItem));
108
+ const editorType = 'vscode';
109
+ const scopes = [SettingScope.User, SettingScope.Workspace];
110
+ scopes.forEach((scope) => {
111
+ act(() => {
112
+ result.current.handleEditorSelect(editorType, scope);
113
+ });
114
+ expect(mockLoadedSettings.setValue).toHaveBeenCalledWith(scope, 'preferredEditor', editorType);
115
+ expect(mockAddItem).toHaveBeenCalledWith({
116
+ type: MessageType.INFO,
117
+ text: `Editor preference set to "vscode" in ${scope} settings.`,
118
+ }, expect.any(Number));
119
+ });
120
+ });
121
+ it('should not set preference for unavailable editors', () => {
122
+ const { result } = renderHook(() => useEditorSettings(mockLoadedSettings, mockSetEditorError, mockAddItem));
123
+ mockCheckHasEditorType.mockReturnValue(false);
124
+ const editorType = 'vscode';
125
+ const scope = SettingScope.User;
126
+ act(() => {
127
+ result.current.openEditorDialog();
128
+ result.current.handleEditorSelect(editorType, scope);
129
+ });
130
+ expect(mockLoadedSettings.setValue).not.toHaveBeenCalled();
131
+ expect(mockAddItem).not.toHaveBeenCalled();
132
+ expect(result.current.isEditorDialogOpen).toBe(true);
133
+ });
134
+ it('should not set preference for editors not allowed in sandbox', () => {
135
+ const { result } = renderHook(() => useEditorSettings(mockLoadedSettings, mockSetEditorError, mockAddItem));
136
+ mockAllowEditorTypeInSandbox.mockReturnValue(false);
137
+ const editorType = 'vscode';
138
+ const scope = SettingScope.User;
139
+ act(() => {
140
+ result.current.openEditorDialog();
141
+ result.current.handleEditorSelect(editorType, scope);
142
+ });
143
+ expect(mockLoadedSettings.setValue).not.toHaveBeenCalled();
144
+ expect(mockAddItem).not.toHaveBeenCalled();
145
+ expect(result.current.isEditorDialogOpen).toBe(true);
146
+ });
147
+ it('should handle errors during editor selection', () => {
148
+ const { result } = renderHook(() => useEditorSettings(mockLoadedSettings, mockSetEditorError, mockAddItem));
149
+ const errorMessage = 'Failed to save settings';
150
+ mockLoadedSettings.setValue.mockImplementation(() => {
151
+ throw new Error(errorMessage);
152
+ });
153
+ const editorType = 'vscode';
154
+ const scope = SettingScope.User;
155
+ act(() => {
156
+ result.current.openEditorDialog();
157
+ result.current.handleEditorSelect(editorType, scope);
158
+ });
159
+ expect(mockSetEditorError).toHaveBeenCalledWith(`Failed to set editor preference: Error: ${errorMessage}`);
160
+ expect(mockAddItem).not.toHaveBeenCalled();
161
+ expect(result.current.isEditorDialogOpen).toBe(true);
162
+ });
163
+ });
164
+ //# sourceMappingURL=useEditorSettings.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEditorSettings.test.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useEditorSettings.test.ts"],"names":[],"mappings":"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"}
@@ -3,10 +3,10 @@
3
3
  * Copyright 2025 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { type Config } from '@google/gemini-cli-core';
7
6
  import { LoadedSettings } from '../../config/settings.js';
8
7
  import { FolderTrustChoice } from '../components/FolderTrustDialog.js';
9
- export declare const useFolderTrust: (settings: LoadedSettings, config: Config) => {
8
+ export declare const useFolderTrust: (settings: LoadedSettings, onTrustChange: (isTrusted: boolean | undefined) => void) => {
9
+ isTrusted: boolean | undefined;
10
10
  isFolderTrustDialogOpen: boolean;
11
11
  handleFolderTrustSelect: (choice: FolderTrustChoice) => void;
12
12
  };
@@ -3,12 +3,23 @@
3
3
  * Copyright 2025 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { useState, useCallback } from 'react';
6
+ import { useState, useCallback, useEffect } from 'react';
7
7
  import { FolderTrustChoice } from '../components/FolderTrustDialog.js';
8
- import { loadTrustedFolders, TrustLevel } from '../../config/trustedFolders.js';
8
+ import { loadTrustedFolders, TrustLevel, isWorkspaceTrusted, } from '../../config/trustedFolders.js';
9
9
  import * as process from 'process';
10
- export const useFolderTrust = (settings, config) => {
11
- const [isFolderTrustDialogOpen, setIsFolderTrustDialogOpen] = useState(config.isTrustedFolder() === undefined);
10
+ export const useFolderTrust = (settings, onTrustChange) => {
11
+ const [isTrusted, setIsTrusted] = useState(undefined);
12
+ const [isFolderTrustDialogOpen, setIsFolderTrustDialogOpen] = useState(false);
13
+ const { folderTrust, folderTrustFeature } = settings.merged;
14
+ useEffect(() => {
15
+ const trusted = isWorkspaceTrusted({
16
+ folderTrust,
17
+ folderTrustFeature,
18
+ });
19
+ setIsTrusted(trusted);
20
+ setIsFolderTrustDialogOpen(trusted === undefined);
21
+ onTrustChange(trusted);
22
+ }, [onTrustChange, folderTrust, folderTrustFeature]);
12
23
  const handleFolderTrustSelect = useCallback((choice) => {
13
24
  const trustedFolders = loadTrustedFolders();
14
25
  const cwd = process.cwd();
@@ -27,9 +38,16 @@ export const useFolderTrust = (settings, config) => {
27
38
  return;
28
39
  }
29
40
  trustedFolders.setValue(cwd, trustLevel);
41
+ const trusted = isWorkspaceTrusted({
42
+ folderTrust,
43
+ folderTrustFeature,
44
+ });
45
+ setIsTrusted(trusted);
30
46
  setIsFolderTrustDialogOpen(false);
31
- }, []);
47
+ onTrustChange(trusted);
48
+ }, [onTrustChange, folderTrust, folderTrustFeature]);
32
49
  return {
50
+ isTrusted,
33
51
  isFolderTrustDialogOpen,
34
52
  handleFolderTrustSelect,
35
53
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useFolderTrust.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useFolderTrust.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAG9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAChF,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAwB,EAAE,MAAc,EAAE,EAAE;IACzE,MAAM,CAAC,uBAAuB,EAAE,0BAA0B,CAAC,GAAG,QAAQ,CACpE,MAAM,CAAC,eAAe,EAAE,KAAK,SAAS,CACvC,CAAC;IAEF,MAAM,uBAAuB,GAAG,WAAW,CAAC,CAAC,MAAyB,EAAE,EAAE;QACxE,MAAM,cAAc,GAAG,kBAAkB,EAAE,CAAC;QAC5C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1B,IAAI,UAAsB,CAAC;QAE3B,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,iBAAiB,CAAC,YAAY;gBACjC,UAAU,GAAG,UAAU,CAAC,YAAY,CAAC;gBACrC,MAAM;YACR,KAAK,iBAAiB,CAAC,YAAY;gBACjC,UAAU,GAAG,UAAU,CAAC,YAAY,CAAC;gBACrC,MAAM;YACR,KAAK,iBAAiB,CAAC,YAAY;gBACjC,UAAU,GAAG,UAAU,CAAC,YAAY,CAAC;gBACrC,MAAM;YACR;gBACE,OAAO;QACX,CAAC;QAED,cAAc,CAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QACzC,0BAA0B,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL,uBAAuB;QACvB,uBAAuB;KACxB,CAAC;AACJ,CAAC,CAAC"}
1
+ {"version":3,"file":"useFolderTrust.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useFolderTrust.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,QAAwB,EACxB,aAAuD,EACvD,EAAE;IACF,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAsB,SAAS,CAAC,CAAC;IAC3E,MAAM,CAAC,uBAAuB,EAAE,0BAA0B,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE9E,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC5D,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,kBAAkB,CAAC;YACjC,WAAW;YACX,kBAAkB;SACP,CAAC,CAAC;QACf,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,0BAA0B,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC;QAClD,aAAa,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC,EAAE,CAAC,aAAa,EAAE,WAAW,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAErD,MAAM,uBAAuB,GAAG,WAAW,CACzC,CAAC,MAAyB,EAAE,EAAE;QAC5B,MAAM,cAAc,GAAG,kBAAkB,EAAE,CAAC;QAC5C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1B,IAAI,UAAsB,CAAC;QAE3B,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,iBAAiB,CAAC,YAAY;gBACjC,UAAU,GAAG,UAAU,CAAC,YAAY,CAAC;gBACrC,MAAM;YACR,KAAK,iBAAiB,CAAC,YAAY;gBACjC,UAAU,GAAG,UAAU,CAAC,YAAY,CAAC;gBACrC,MAAM;YACR,KAAK,iBAAiB,CAAC,YAAY;gBACjC,UAAU,GAAG,UAAU,CAAC,YAAY,CAAC;gBACrC,MAAM;YACR;gBACE,OAAO;QACX,CAAC;QAED,cAAc,CAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,kBAAkB,CAAC;YACjC,WAAW;YACX,kBAAkB;SACP,CAAC,CAAC;QACf,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,0BAA0B,CAAC,KAAK,CAAC,CAAC;QAClC,aAAa,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC,EACD,CAAC,aAAa,EAAE,WAAW,EAAE,kBAAkB,CAAC,CACjD,CAAC;IAEF,OAAO;QACL,SAAS;QACT,uBAAuB;QACvB,uBAAuB;KACxB,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};
@@ -0,0 +1,175 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { afterEach, beforeEach, describe, expect, it, vi, } from 'vitest';
7
+ import { act } from 'react';
8
+ import { renderHook } from '@testing-library/react';
9
+ import { useGitBranchName } from './useGitBranchName.js';
10
+ import { fs, vol } from 'memfs'; // For mocking fs
11
+ import { EventEmitter } from 'node:events';
12
+ import { exec as mockExec } from 'node:child_process';
13
+ // Mock child_process
14
+ vi.mock('child_process');
15
+ // Mock fs and fs/promises
16
+ vi.mock('node:fs', async () => {
17
+ const memfs = await vi.importActual('memfs');
18
+ return memfs.fs;
19
+ });
20
+ vi.mock('node:fs/promises', async () => {
21
+ const memfs = await vi.importActual('memfs');
22
+ return memfs.fs.promises;
23
+ });
24
+ const CWD = '/test/project';
25
+ const GIT_HEAD_PATH = `${CWD}/.git/HEAD`;
26
+ describe('useGitBranchName', () => {
27
+ beforeEach(() => {
28
+ vol.reset(); // Reset in-memory filesystem
29
+ vol.fromJSON({
30
+ [GIT_HEAD_PATH]: 'ref: refs/heads/main',
31
+ });
32
+ vi.useFakeTimers(); // Use fake timers for async operations
33
+ });
34
+ afterEach(() => {
35
+ vi.restoreAllMocks();
36
+ vi.clearAllTimers();
37
+ });
38
+ it('should return branch name', async () => {
39
+ mockExec.mockImplementation((_command, _options, callback) => {
40
+ callback?.(null, 'main\n', '');
41
+ return new EventEmitter();
42
+ });
43
+ const { result, rerender } = renderHook(() => useGitBranchName(CWD));
44
+ await act(async () => {
45
+ vi.runAllTimers(); // Advance timers to trigger useEffect and exec callback
46
+ rerender(); // Rerender to get the updated state
47
+ });
48
+ expect(result.current).toBe('main');
49
+ });
50
+ it('should return undefined if git command fails', async () => {
51
+ mockExec.mockImplementation((_command, _options, callback) => {
52
+ callback?.(new Error('Git error'), '', 'error output');
53
+ return new EventEmitter();
54
+ });
55
+ const { result, rerender } = renderHook(() => useGitBranchName(CWD));
56
+ expect(result.current).toBeUndefined();
57
+ await act(async () => {
58
+ vi.runAllTimers();
59
+ rerender();
60
+ });
61
+ expect(result.current).toBeUndefined();
62
+ });
63
+ it('should return short commit hash if branch is HEAD (detached state)', async () => {
64
+ mockExec.mockImplementation((command, _options, callback) => {
65
+ if (command === 'git rev-parse --abbrev-ref HEAD') {
66
+ callback?.(null, 'HEAD\n', '');
67
+ }
68
+ else if (command === 'git rev-parse --short HEAD') {
69
+ callback?.(null, 'a1b2c3d\n', '');
70
+ }
71
+ return new EventEmitter();
72
+ });
73
+ const { result, rerender } = renderHook(() => useGitBranchName(CWD));
74
+ await act(async () => {
75
+ vi.runAllTimers();
76
+ rerender();
77
+ });
78
+ expect(result.current).toBe('a1b2c3d');
79
+ });
80
+ it('should return undefined if branch is HEAD and getting commit hash fails', async () => {
81
+ mockExec.mockImplementation((command, _options, callback) => {
82
+ if (command === 'git rev-parse --abbrev-ref HEAD') {
83
+ callback?.(null, 'HEAD\n', '');
84
+ }
85
+ else if (command === 'git rev-parse --short HEAD') {
86
+ callback?.(new Error('Git error'), '', 'error output');
87
+ }
88
+ return new EventEmitter();
89
+ });
90
+ const { result, rerender } = renderHook(() => useGitBranchName(CWD));
91
+ await act(async () => {
92
+ vi.runAllTimers();
93
+ rerender();
94
+ });
95
+ expect(result.current).toBeUndefined();
96
+ });
97
+ it('should update branch name when .git/HEAD changes', async ({ skip }) => {
98
+ skip(); // TODO: fix
99
+ mockExec.mockImplementationOnce((_command, _options, callback) => {
100
+ callback?.(null, 'main\n', '');
101
+ return new EventEmitter();
102
+ });
103
+ const { result, rerender } = renderHook(() => useGitBranchName(CWD));
104
+ await act(async () => {
105
+ vi.runAllTimers();
106
+ rerender();
107
+ });
108
+ expect(result.current).toBe('main');
109
+ // Simulate a branch change
110
+ mockExec.mockImplementationOnce((_command, _options, callback) => {
111
+ callback?.(null, 'develop\n', '');
112
+ return new EventEmitter();
113
+ });
114
+ // Simulate file change event
115
+ // Ensure the watcher is set up before triggering the change
116
+ await act(async () => {
117
+ fs.writeFileSync(GIT_HEAD_PATH, 'ref: refs/heads/develop'); // Trigger watcher
118
+ vi.runAllTimers(); // Process timers for watcher and exec
119
+ rerender();
120
+ });
121
+ expect(result.current).toBe('develop');
122
+ });
123
+ it('should handle watcher setup error silently', async () => {
124
+ // Remove .git/HEAD to cause an error in fs.watch setup
125
+ vol.unlinkSync(GIT_HEAD_PATH);
126
+ mockExec.mockImplementation((_command, _options, callback) => {
127
+ callback?.(null, 'main\n', '');
128
+ return new EventEmitter();
129
+ });
130
+ const { result, rerender } = renderHook(() => useGitBranchName(CWD));
131
+ await act(async () => {
132
+ vi.runAllTimers();
133
+ rerender();
134
+ });
135
+ expect(result.current).toBe('main'); // Branch name should still be fetched initially
136
+ // Try to trigger a change that would normally be caught by the watcher
137
+ mockExec.mockImplementationOnce((_command, _options, callback) => {
138
+ callback?.(null, 'develop\n', '');
139
+ return new EventEmitter();
140
+ });
141
+ // This write would trigger the watcher if it was set up
142
+ // but since it failed, the branch name should not update
143
+ // We need to create the file again for writeFileSync to not throw
144
+ vol.fromJSON({
145
+ [GIT_HEAD_PATH]: 'ref: refs/heads/develop',
146
+ });
147
+ await act(async () => {
148
+ fs.writeFileSync(GIT_HEAD_PATH, 'ref: refs/heads/develop');
149
+ vi.runAllTimers();
150
+ rerender();
151
+ });
152
+ // Branch name should not change because watcher setup failed
153
+ expect(result.current).toBe('main');
154
+ });
155
+ it('should cleanup watcher on unmount', async ({ skip }) => {
156
+ skip(); // TODO: fix
157
+ const closeMock = vi.fn();
158
+ const watchMock = vi.spyOn(fs, 'watch').mockReturnValue({
159
+ close: closeMock,
160
+ });
161
+ mockExec.mockImplementation((_command, _options, callback) => {
162
+ callback?.(null, 'main\n', '');
163
+ return new EventEmitter();
164
+ });
165
+ const { unmount, rerender } = renderHook(() => useGitBranchName(CWD));
166
+ await act(async () => {
167
+ vi.runAllTimers();
168
+ rerender();
169
+ });
170
+ unmount();
171
+ expect(watchMock).toHaveBeenCalledWith(GIT_HEAD_PATH, expect.any(Function));
172
+ expect(closeMock).toHaveBeenCalled();
173
+ });
174
+ });
175
+ //# sourceMappingURL=useGitBranchName.test.js.map