@google/gemini-cli 0.26.0-preview.0 → 0.27.0-nightly.20260122.61040d0eb

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 (212) hide show
  1. package/dist/google-gemini-cli-0.27.0-nightly.20260121.97aac696f.tgz +0 -0
  2. package/dist/package.json +2 -2
  3. package/dist/src/commands/extensions.js +4 -1
  4. package/dist/src/commands/extensions.js.map +1 -1
  5. package/dist/src/commands/hooks/migrate.js +0 -1
  6. package/dist/src/commands/hooks/migrate.js.map +1 -1
  7. package/dist/src/commands/hooks/migrate.test.js +0 -1
  8. package/dist/src/commands/hooks/migrate.test.js.map +1 -1
  9. package/dist/src/commands/hooks.js +4 -1
  10. package/dist/src/commands/hooks.js.map +1 -1
  11. package/dist/src/commands/mcp.js +4 -1
  12. package/dist/src/commands/mcp.js.map +1 -1
  13. package/dist/src/commands/skills.js +4 -1
  14. package/dist/src/commands/skills.js.map +1 -1
  15. package/dist/src/config/config.d.ts +3 -0
  16. package/dist/src/config/config.js +15 -3
  17. package/dist/src/config/config.js.map +1 -1
  18. package/dist/src/config/config.test.js +92 -1
  19. package/dist/src/config/config.test.js.map +1 -1
  20. package/dist/src/config/extension.test.js +1 -0
  21. package/dist/src/config/extension.test.js.map +1 -1
  22. package/dist/src/config/keyBindings.d.ts +7 -5
  23. package/dist/src/config/keyBindings.js +34 -32
  24. package/dist/src/config/keyBindings.js.map +1 -1
  25. package/dist/src/config/keyBindings.test.js +8 -5
  26. package/dist/src/config/keyBindings.test.js.map +1 -1
  27. package/dist/src/config/sandboxConfig.test.js +11 -5
  28. package/dist/src/config/sandboxConfig.test.js.map +1 -1
  29. package/dist/src/config/settingsSchema.d.ts +3 -3
  30. package/dist/src/config/settingsSchema.js +3 -3
  31. package/dist/src/config/settingsSchema.js.map +1 -1
  32. package/dist/src/config/settingsSchema.test.js +1 -1
  33. package/dist/src/config/settingsSchema.test.js.map +1 -1
  34. package/dist/src/gemini.js +5 -4
  35. package/dist/src/gemini.js.map +1 -1
  36. package/dist/src/gemini.test.js +140 -10
  37. package/dist/src/gemini.test.js.map +1 -1
  38. package/dist/src/generated/git-commit.d.ts +2 -2
  39. package/dist/src/generated/git-commit.js +2 -2
  40. package/dist/src/generated/git-commit.js.map +1 -1
  41. package/dist/src/nonInteractiveCli.js +11 -3
  42. package/dist/src/nonInteractiveCli.js.map +1 -1
  43. package/dist/src/nonInteractiveCli.test.js +186 -0
  44. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  45. package/dist/src/test-utils/render.js +6 -2
  46. package/dist/src/test-utils/render.js.map +1 -1
  47. package/dist/src/ui/AppContainer.js +31 -15
  48. package/dist/src/ui/AppContainer.js.map +1 -1
  49. package/dist/src/ui/AppContainer.test.js +132 -19
  50. package/dist/src/ui/AppContainer.test.js.map +1 -1
  51. package/dist/src/ui/auth/ApiAuthDialog.test.js +5 -5
  52. package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -1
  53. package/dist/src/ui/auth/LoginWithGoogleRestartDialog.test.js +6 -6
  54. package/dist/src/ui/auth/LoginWithGoogleRestartDialog.test.js.map +1 -1
  55. package/dist/src/ui/commands/directoryCommand.js +8 -20
  56. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  57. package/dist/src/ui/commands/directoryCommand.test.js +38 -13
  58. package/dist/src/ui/commands/directoryCommand.test.js.map +1 -1
  59. package/dist/src/ui/commands/policiesCommand.js +32 -20
  60. package/dist/src/ui/commands/policiesCommand.js.map +1 -1
  61. package/dist/src/ui/commands/policiesCommand.test.js +7 -4
  62. package/dist/src/ui/commands/policiesCommand.test.js.map +1 -1
  63. package/dist/src/ui/commands/skillsCommand.js +6 -4
  64. package/dist/src/ui/commands/skillsCommand.js.map +1 -1
  65. package/dist/src/ui/commands/skillsCommand.test.js +17 -3
  66. package/dist/src/ui/commands/skillsCommand.test.js.map +1 -1
  67. package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.js +1 -0
  68. package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.js.map +1 -1
  69. package/dist/src/ui/components/{AutoAcceptIndicator.d.ts → ApprovalModeIndicator.d.ts} +2 -2
  70. package/dist/src/ui/components/{AutoAcceptIndicator.js → ApprovalModeIndicator.js} +8 -3
  71. package/dist/src/ui/components/ApprovalModeIndicator.js.map +1 -0
  72. package/dist/src/ui/components/{AutoAcceptIndicator.test.js → ApprovalModeIndicator.test.js} +13 -7
  73. package/dist/src/ui/components/ApprovalModeIndicator.test.js.map +1 -0
  74. package/dist/src/ui/components/Composer.js +4 -4
  75. package/dist/src/ui/components/Composer.js.map +1 -1
  76. package/dist/src/ui/components/Composer.test.js +6 -6
  77. package/dist/src/ui/components/Composer.test.js.map +1 -1
  78. package/dist/src/ui/components/Footer.test.js +7 -0
  79. package/dist/src/ui/components/Footer.test.js.map +1 -1
  80. package/dist/src/ui/components/InputPrompt.js +2 -1
  81. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  82. package/dist/src/ui/components/MultiFolderTrustDialog.test.js +3 -2
  83. package/dist/src/ui/components/MultiFolderTrustDialog.test.js.map +1 -1
  84. package/dist/src/ui/components/SessionBrowser.js +3 -2
  85. package/dist/src/ui/components/SessionBrowser.js.map +1 -1
  86. package/dist/src/ui/components/SessionBrowser.test.js +10 -3
  87. package/dist/src/ui/components/SessionBrowser.test.js.map +1 -1
  88. package/dist/src/ui/components/ShellInputPrompt.test.js +17 -8
  89. package/dist/src/ui/components/ShellInputPrompt.test.js.map +1 -1
  90. package/dist/src/ui/components/messages/RedirectionConfirmation.test.js +2 -4
  91. package/dist/src/ui/components/messages/RedirectionConfirmation.test.js.map +1 -1
  92. package/dist/src/ui/components/messages/ToolConfirmationMessage.d.ts +3 -2
  93. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +12 -35
  94. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  95. package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js +20 -7
  96. package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js.map +1 -1
  97. package/dist/src/ui/components/messages/ToolGroupMessage.js +1 -1
  98. package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
  99. package/dist/src/ui/components/messages/ToolGroupMessage.test.js +100 -19
  100. package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
  101. package/dist/src/ui/components/shared/TextInput.test.js +32 -24
  102. package/dist/src/ui/components/shared/TextInput.test.js.map +1 -1
  103. package/dist/src/ui/components/shared/text-buffer.test.js +62 -42
  104. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
  105. package/dist/src/ui/constants/tips.js +2 -2
  106. package/dist/src/ui/constants/tips.js.map +1 -1
  107. package/dist/src/ui/constants.d.ts +1 -0
  108. package/dist/src/ui/constants.js +1 -0
  109. package/dist/src/ui/constants.js.map +1 -1
  110. package/dist/src/ui/contexts/KeypressContext.d.ts +3 -2
  111. package/dist/src/ui/contexts/KeypressContext.js +31 -24
  112. package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
  113. package/dist/src/ui/contexts/KeypressContext.test.js +153 -40
  114. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  115. package/dist/src/ui/contexts/MouseContext.test.js +8 -8
  116. package/dist/src/ui/contexts/MouseContext.test.js.map +1 -1
  117. package/dist/src/ui/contexts/ToolActionsContext.d.ts +20 -0
  118. package/dist/src/ui/contexts/ToolActionsContext.js +74 -0
  119. package/dist/src/ui/contexts/ToolActionsContext.js.map +1 -0
  120. package/dist/src/ui/contexts/ToolActionsContext.test.d.ts +6 -0
  121. package/dist/src/ui/contexts/ToolActionsContext.test.js +135 -0
  122. package/dist/src/ui/contexts/ToolActionsContext.test.js.map +1 -0
  123. package/dist/src/ui/contexts/UIStateContext.d.ts +1 -1
  124. package/dist/src/ui/hooks/keyToAnsi.js +1 -1
  125. package/dist/src/ui/hooks/keyToAnsi.js.map +1 -1
  126. package/dist/src/ui/hooks/toolMapping.js +5 -8
  127. package/dist/src/ui/hooks/toolMapping.js.map +1 -1
  128. package/dist/src/ui/hooks/toolMapping.test.js +23 -0
  129. package/dist/src/ui/hooks/toolMapping.test.js.map +1 -1
  130. package/dist/src/ui/hooks/{useAutoAcceptIndicator.d.ts → useApprovalModeIndicator.d.ts} +2 -2
  131. package/dist/src/ui/hooks/{useAutoAcceptIndicator.js → useApprovalModeIndicator.js} +25 -11
  132. package/dist/src/ui/hooks/useApprovalModeIndicator.js.map +1 -0
  133. package/dist/src/ui/hooks/{useAutoAcceptIndicator.test.js → useApprovalModeIndicator.test.js} +56 -31
  134. package/dist/src/ui/hooks/useApprovalModeIndicator.test.js.map +1 -0
  135. package/dist/src/ui/hooks/useGeminiStream.d.ts +1 -1
  136. package/dist/src/ui/hooks/useGeminiStream.js +2 -2
  137. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  138. package/dist/src/ui/hooks/useGeminiStream.test.js +17 -18
  139. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  140. package/dist/src/ui/hooks/useIncludeDirsTrust.d.ts +1 -1
  141. package/dist/src/ui/hooks/useIncludeDirsTrust.js +9 -20
  142. package/dist/src/ui/hooks/useIncludeDirsTrust.js.map +1 -1
  143. package/dist/src/ui/hooks/useIncludeDirsTrust.test.js +33 -12
  144. package/dist/src/ui/hooks/useIncludeDirsTrust.test.js.map +1 -1
  145. package/dist/src/ui/hooks/useKeypress.test.js +10 -3
  146. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
  147. package/dist/src/ui/hooks/useLoadingIndicator.d.ts +7 -1
  148. package/dist/src/ui/hooks/useLoadingIndicator.js +3 -3
  149. package/dist/src/ui/hooks/useLoadingIndicator.js.map +1 -1
  150. package/dist/src/ui/hooks/useLoadingIndicator.test.js +17 -9
  151. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  152. package/dist/src/ui/hooks/usePhraseCycler.d.ts +2 -2
  153. package/dist/src/ui/hooks/usePhraseCycler.js +4 -14
  154. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  155. package/dist/src/ui/hooks/usePhraseCycler.test.js +13 -42
  156. package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
  157. package/dist/src/ui/hooks/useSelectionList.test.js +6 -3
  158. package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
  159. package/dist/src/ui/hooks/useShellInactivityStatus.d.ts +26 -0
  160. package/dist/src/ui/hooks/useShellInactivityStatus.js +46 -0
  161. package/dist/src/ui/hooks/useShellInactivityStatus.js.map +1 -0
  162. package/dist/src/ui/hooks/useShellInactivityStatus.test.d.ts +6 -0
  163. package/dist/src/ui/hooks/useShellInactivityStatus.test.js +84 -0
  164. package/dist/src/ui/hooks/useShellInactivityStatus.test.js.map +1 -0
  165. package/dist/src/ui/hooks/useToolExecutionScheduler.d.ts +30 -0
  166. package/dist/src/ui/hooks/useToolExecutionScheduler.js +113 -0
  167. package/dist/src/ui/hooks/useToolExecutionScheduler.js.map +1 -0
  168. package/dist/src/ui/hooks/useToolExecutionScheduler.test.d.ts +6 -0
  169. package/dist/src/ui/hooks/useToolExecutionScheduler.test.js +296 -0
  170. package/dist/src/ui/hooks/useToolExecutionScheduler.test.js.map +1 -0
  171. package/dist/src/ui/hooks/useToolScheduler.d.ts +29 -0
  172. package/dist/src/ui/hooks/useToolScheduler.js +30 -0
  173. package/dist/src/ui/hooks/useToolScheduler.js.map +1 -0
  174. package/dist/src/ui/hooks/useToolSchedulerFacade.test.d.ts +6 -0
  175. package/dist/src/ui/hooks/useToolSchedulerFacade.test.js +45 -0
  176. package/dist/src/ui/hooks/useToolSchedulerFacade.test.js.map +1 -0
  177. package/dist/src/ui/hooks/useTurnActivityMonitor.d.ts +16 -0
  178. package/dist/src/ui/hooks/useTurnActivityMonitor.js +49 -0
  179. package/dist/src/ui/hooks/useTurnActivityMonitor.js.map +1 -0
  180. package/dist/src/ui/hooks/useTurnActivityMonitor.test.d.ts +6 -0
  181. package/dist/src/ui/hooks/useTurnActivityMonitor.test.js +97 -0
  182. package/dist/src/ui/hooks/useTurnActivityMonitor.test.js.map +1 -0
  183. package/dist/src/ui/hooks/vim.js +5 -3
  184. package/dist/src/ui/hooks/vim.js.map +1 -1
  185. package/dist/src/ui/hooks/vim.test.js +3 -2
  186. package/dist/src/ui/hooks/vim.test.js.map +1 -1
  187. package/dist/src/ui/keyMatchers.js +5 -13
  188. package/dist/src/ui/keyMatchers.js.map +1 -1
  189. package/dist/src/ui/keyMatchers.test.js +23 -20
  190. package/dist/src/ui/keyMatchers.test.js.map +1 -1
  191. package/dist/src/ui/types.d.ts +5 -3
  192. package/dist/src/ui/types.js.map +1 -1
  193. package/dist/src/ui/utils/directoryUtils.d.ts +10 -0
  194. package/dist/src/ui/utils/directoryUtils.js +12 -0
  195. package/dist/src/ui/utils/directoryUtils.js.map +1 -1
  196. package/dist/src/utils/cleanup.js +15 -0
  197. package/dist/src/utils/cleanup.js.map +1 -1
  198. package/dist/src/utils/handleAutoUpdate.test.js +3 -0
  199. package/dist/src/utils/handleAutoUpdate.test.js.map +1 -1
  200. package/dist/src/utils/windowTitle.d.ts +2 -1
  201. package/dist/src/utils/windowTitle.js +8 -1
  202. package/dist/src/utils/windowTitle.js.map +1 -1
  203. package/dist/src/utils/windowTitle.test.js +25 -1
  204. package/dist/src/utils/windowTitle.test.js.map +1 -1
  205. package/dist/tsconfig.tsbuildinfo +1 -1
  206. package/package.json +3 -3
  207. package/dist/src/ui/components/AutoAcceptIndicator.js.map +0 -1
  208. package/dist/src/ui/components/AutoAcceptIndicator.test.js.map +0 -1
  209. package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +0 -1
  210. package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +0 -1
  211. /package/dist/src/ui/components/{AutoAcceptIndicator.test.d.ts → ApprovalModeIndicator.test.d.ts} +0 -0
  212. /package/dist/src/ui/hooks/{useAutoAcceptIndicator.test.d.ts → useApprovalModeIndicator.test.d.ts} +0 -0
@@ -0,0 +1,296 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
7
+ import { act } from 'react';
8
+ import { renderHook } from '../../test-utils/render.js';
9
+ import { useToolExecutionScheduler } from './useToolExecutionScheduler.js';
10
+ import { MessageBusType, ToolConfirmationOutcome, Scheduler, } from '@google/gemini-cli-core';
11
+ import { createMockMessageBus } from '@google/gemini-cli-core/src/test-utils/mock-message-bus.js';
12
+ // Mock Core Scheduler
13
+ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
14
+ const actual = await importOriginal();
15
+ return {
16
+ ...actual,
17
+ Scheduler: vi.fn().mockImplementation(() => ({
18
+ schedule: vi.fn().mockResolvedValue([]),
19
+ cancelAll: vi.fn(),
20
+ })),
21
+ };
22
+ });
23
+ const createMockTool = (overrides = {}) => ({
24
+ name: 'test_tool',
25
+ displayName: 'Test Tool',
26
+ description: 'A test tool',
27
+ kind: 'function',
28
+ parameterSchema: {},
29
+ isOutputMarkdown: false,
30
+ build: vi.fn(),
31
+ ...overrides,
32
+ });
33
+ const createMockInvocation = (overrides = {}) => ({
34
+ getDescription: () => 'Executing test tool',
35
+ shouldConfirmExecute: vi.fn(),
36
+ execute: vi.fn(),
37
+ params: {},
38
+ toolLocations: [],
39
+ ...overrides,
40
+ });
41
+ describe('useToolExecutionScheduler', () => {
42
+ let mockConfig;
43
+ let mockMessageBus;
44
+ beforeEach(() => {
45
+ vi.clearAllMocks();
46
+ mockMessageBus = createMockMessageBus();
47
+ mockConfig = {
48
+ getMessageBus: () => mockMessageBus,
49
+ };
50
+ });
51
+ it('initializes with empty tool calls', () => {
52
+ const { result } = renderHook(() => useToolExecutionScheduler(vi.fn().mockResolvedValue(undefined), mockConfig, () => undefined));
53
+ const [toolCalls] = result.current;
54
+ expect(toolCalls).toEqual([]);
55
+ });
56
+ it('updates tool calls when MessageBus emits TOOL_CALLS_UPDATE', () => {
57
+ const { result } = renderHook(() => useToolExecutionScheduler(vi.fn().mockResolvedValue(undefined), mockConfig, () => undefined));
58
+ const mockToolCall = {
59
+ status: 'executing',
60
+ request: {
61
+ callId: 'call-1',
62
+ name: 'test_tool',
63
+ args: {},
64
+ isClientInitiated: false,
65
+ prompt_id: 'p1',
66
+ },
67
+ tool: createMockTool(),
68
+ invocation: createMockInvocation(),
69
+ liveOutput: 'Loading...',
70
+ };
71
+ act(() => {
72
+ void mockMessageBus.publish({
73
+ type: MessageBusType.TOOL_CALLS_UPDATE,
74
+ toolCalls: [mockToolCall],
75
+ });
76
+ });
77
+ const [toolCalls] = result.current;
78
+ expect(toolCalls).toHaveLength(1);
79
+ // Expect Core Object structure, not Display Object
80
+ expect(toolCalls[0]).toMatchObject({
81
+ request: { callId: 'call-1', name: 'test_tool' },
82
+ status: 'executing', // Core status
83
+ liveOutput: 'Loading...',
84
+ responseSubmittedToGemini: false,
85
+ });
86
+ });
87
+ it('injects onConfirm callback for awaiting_approval tools (Adapter Pattern)', async () => {
88
+ const { result } = renderHook(() => useToolExecutionScheduler(vi.fn().mockResolvedValue(undefined), mockConfig, () => undefined));
89
+ const mockToolCall = {
90
+ status: 'awaiting_approval',
91
+ request: {
92
+ callId: 'call-1',
93
+ name: 'test_tool',
94
+ args: {},
95
+ isClientInitiated: false,
96
+ prompt_id: 'p1',
97
+ },
98
+ tool: createMockTool(),
99
+ invocation: createMockInvocation({
100
+ getDescription: () => 'Confirming test tool',
101
+ }),
102
+ confirmationDetails: { type: 'info', title: 'Confirm', prompt: 'Sure?' },
103
+ correlationId: 'corr-123',
104
+ };
105
+ act(() => {
106
+ void mockMessageBus.publish({
107
+ type: MessageBusType.TOOL_CALLS_UPDATE,
108
+ toolCalls: [mockToolCall],
109
+ });
110
+ });
111
+ const [toolCalls] = result.current;
112
+ const call = toolCalls[0];
113
+ if (call.status !== 'awaiting_approval') {
114
+ throw new Error('Expected status to be awaiting_approval');
115
+ }
116
+ const confirmationDetails = call.confirmationDetails;
117
+ expect(confirmationDetails).toBeDefined();
118
+ expect(typeof confirmationDetails.onConfirm).toBe('function');
119
+ // Test that onConfirm publishes to MessageBus
120
+ const publishSpy = vi.spyOn(mockMessageBus, 'publish');
121
+ await confirmationDetails.onConfirm(ToolConfirmationOutcome.ProceedOnce);
122
+ expect(publishSpy).toHaveBeenCalledWith({
123
+ type: MessageBusType.TOOL_CONFIRMATION_RESPONSE,
124
+ correlationId: 'corr-123',
125
+ confirmed: true,
126
+ requiresUserConfirmation: false,
127
+ outcome: ToolConfirmationOutcome.ProceedOnce,
128
+ payload: undefined,
129
+ });
130
+ });
131
+ it('injects onConfirm with payload (Inline Edit support)', async () => {
132
+ const { result } = renderHook(() => useToolExecutionScheduler(vi.fn().mockResolvedValue(undefined), mockConfig, () => undefined));
133
+ const mockToolCall = {
134
+ status: 'awaiting_approval',
135
+ request: {
136
+ callId: 'call-1',
137
+ name: 'test_tool',
138
+ args: {},
139
+ isClientInitiated: false,
140
+ prompt_id: 'p1',
141
+ },
142
+ tool: createMockTool(),
143
+ invocation: createMockInvocation(),
144
+ confirmationDetails: { type: 'edit', title: 'Edit', filePath: 'test.ts' },
145
+ correlationId: 'corr-edit',
146
+ };
147
+ act(() => {
148
+ void mockMessageBus.publish({
149
+ type: MessageBusType.TOOL_CALLS_UPDATE,
150
+ toolCalls: [mockToolCall],
151
+ });
152
+ });
153
+ const [toolCalls] = result.current;
154
+ const call = toolCalls[0];
155
+ if (call.status !== 'awaiting_approval') {
156
+ throw new Error('Expected awaiting_approval');
157
+ }
158
+ const confirmationDetails = call.confirmationDetails;
159
+ const publishSpy = vi.spyOn(mockMessageBus, 'publish');
160
+ const mockPayload = { newContent: 'updated code' };
161
+ await confirmationDetails.onConfirm(ToolConfirmationOutcome.ProceedOnce, mockPayload);
162
+ expect(publishSpy).toHaveBeenCalledWith({
163
+ type: MessageBusType.TOOL_CONFIRMATION_RESPONSE,
164
+ correlationId: 'corr-edit',
165
+ confirmed: true,
166
+ requiresUserConfirmation: false,
167
+ outcome: ToolConfirmationOutcome.ProceedOnce,
168
+ payload: mockPayload,
169
+ });
170
+ });
171
+ it('preserves responseSubmittedToGemini flag across updates', () => {
172
+ const { result } = renderHook(() => useToolExecutionScheduler(vi.fn().mockResolvedValue(undefined), mockConfig, () => undefined));
173
+ const mockToolCall = {
174
+ status: 'success',
175
+ request: {
176
+ callId: 'call-1',
177
+ name: 'test',
178
+ args: {},
179
+ isClientInitiated: false,
180
+ prompt_id: 'p1',
181
+ },
182
+ tool: createMockTool(),
183
+ invocation: createMockInvocation(),
184
+ response: {
185
+ callId: 'call-1',
186
+ resultDisplay: 'OK',
187
+ responseParts: [],
188
+ error: undefined,
189
+ errorType: undefined,
190
+ },
191
+ };
192
+ // 1. Initial success
193
+ act(() => {
194
+ void mockMessageBus.publish({
195
+ type: MessageBusType.TOOL_CALLS_UPDATE,
196
+ toolCalls: [mockToolCall],
197
+ });
198
+ });
199
+ // 2. Mark as submitted
200
+ act(() => {
201
+ const [, , markAsSubmitted] = result.current;
202
+ markAsSubmitted(['call-1']);
203
+ });
204
+ expect(result.current[0][0].responseSubmittedToGemini).toBe(true);
205
+ // 3. Receive another update (should preserve the true flag)
206
+ act(() => {
207
+ void mockMessageBus.publish({
208
+ type: MessageBusType.TOOL_CALLS_UPDATE,
209
+ toolCalls: [mockToolCall],
210
+ });
211
+ });
212
+ expect(result.current[0][0].responseSubmittedToGemini).toBe(true);
213
+ });
214
+ it('updates lastToolOutputTime when tools are executing', () => {
215
+ vi.useFakeTimers();
216
+ const { result } = renderHook(() => useToolExecutionScheduler(vi.fn().mockResolvedValue(undefined), mockConfig, () => undefined));
217
+ const startTime = Date.now();
218
+ vi.advanceTimersByTime(1000);
219
+ act(() => {
220
+ void mockMessageBus.publish({
221
+ type: MessageBusType.TOOL_CALLS_UPDATE,
222
+ toolCalls: [
223
+ {
224
+ status: 'executing',
225
+ request: {
226
+ callId: 'call-1',
227
+ name: 'test',
228
+ args: {},
229
+ isClientInitiated: false,
230
+ prompt_id: 'p1',
231
+ },
232
+ tool: createMockTool(),
233
+ invocation: createMockInvocation(),
234
+ },
235
+ ],
236
+ });
237
+ });
238
+ const [, , , , , lastOutputTime] = result.current;
239
+ expect(lastOutputTime).toBeGreaterThan(startTime);
240
+ vi.useRealTimers();
241
+ });
242
+ it('delegates cancelAll to the Core Scheduler', () => {
243
+ const { result } = renderHook(() => useToolExecutionScheduler(vi.fn().mockResolvedValue(undefined), mockConfig, () => undefined));
244
+ const [, , , , cancelAll] = result.current;
245
+ const signal = new AbortController().signal;
246
+ // We need to find the mock instance of Scheduler
247
+ // Since we used vi.mock at top level, we can get it from vi.mocked(Scheduler)
248
+ const schedulerInstance = vi.mocked(Scheduler).mock.results[0].value;
249
+ cancelAll(signal);
250
+ expect(schedulerInstance.cancelAll).toHaveBeenCalled();
251
+ });
252
+ it('resolves the schedule promise when scheduler resolves', async () => {
253
+ const onComplete = vi.fn().mockResolvedValue(undefined);
254
+ const completedToolCall = {
255
+ status: 'success',
256
+ request: {
257
+ callId: 'call-1',
258
+ name: 'test',
259
+ args: {},
260
+ isClientInitiated: false,
261
+ prompt_id: 'p1',
262
+ },
263
+ tool: createMockTool(),
264
+ invocation: createMockInvocation(),
265
+ response: {
266
+ callId: 'call-1',
267
+ responseParts: [],
268
+ resultDisplay: 'Success',
269
+ error: undefined,
270
+ errorType: undefined,
271
+ },
272
+ };
273
+ // Mock the specific return value for this test
274
+ const { Scheduler } = await import('@google/gemini-cli-core');
275
+ vi.mocked(Scheduler).mockImplementation(() => ({
276
+ schedule: vi.fn().mockResolvedValue([completedToolCall]),
277
+ cancelAll: vi.fn(),
278
+ }));
279
+ const { result } = renderHook(() => useToolExecutionScheduler(onComplete, mockConfig, () => undefined));
280
+ const [, schedule] = result.current;
281
+ const signal = new AbortController().signal;
282
+ let completedResult = [];
283
+ await act(async () => {
284
+ completedResult = await schedule({
285
+ callId: 'call-1',
286
+ name: 'test',
287
+ args: {},
288
+ isClientInitiated: false,
289
+ prompt_id: 'p1',
290
+ }, signal);
291
+ });
292
+ expect(completedResult).toEqual([completedToolCall]);
293
+ expect(onComplete).toHaveBeenCalledWith([completedToolCall]);
294
+ });
295
+ });
296
+ //# sourceMappingURL=useToolExecutionScheduler.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useToolExecutionScheduler.test.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useToolExecutionScheduler.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { Config, EditorType, CompletedToolCall, ToolCallRequestInfo } from '@google/gemini-cli-core';
7
+ import { type TrackedToolCall as LegacyTrackedToolCall, type TrackedScheduledToolCall, type TrackedValidatingToolCall, type TrackedWaitingToolCall, type TrackedExecutingToolCall, type TrackedCompletedToolCall, type TrackedCancelledToolCall, type MarkToolsAsSubmittedFn, type CancelAllFn } from './useReactToolScheduler.js';
8
+ import { type TrackedToolCall as NewTrackedToolCall } from './useToolExecutionScheduler.js';
9
+ export type { TrackedScheduledToolCall, TrackedValidatingToolCall, TrackedWaitingToolCall, TrackedExecutingToolCall, TrackedCompletedToolCall, TrackedCancelledToolCall, };
10
+ export type TrackedToolCall = LegacyTrackedToolCall | NewTrackedToolCall;
11
+ export type ScheduleFn = (request: ToolCallRequestInfo | ToolCallRequestInfo[], signal: AbortSignal) => Promise<void | CompletedToolCall[]>;
12
+ export type UseToolSchedulerReturn = [
13
+ TrackedToolCall[],
14
+ ScheduleFn,
15
+ MarkToolsAsSubmittedFn,
16
+ React.Dispatch<React.SetStateAction<TrackedToolCall[]>>,
17
+ CancelAllFn,
18
+ number
19
+ ];
20
+ /**
21
+ * Facade hook that switches between the Legacy and Event-Driven schedulers
22
+ * based on configuration.
23
+ *
24
+ * Note: This conditionally calls hooks, which technically violates the standard
25
+ * Rules of Hooks linting. However, this is safe here because
26
+ * `config.isEventDrivenSchedulerEnabled()` is static for the lifetime of the
27
+ * application session (it essentially acts as a compile-time feature flag).
28
+ */
29
+ export declare function useToolScheduler(onComplete: (tools: CompletedToolCall[]) => Promise<void>, config: Config, getPreferredEditor: () => EditorType | undefined): UseToolSchedulerReturn;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { useReactToolScheduler, } from './useReactToolScheduler.js';
7
+ import { useToolExecutionScheduler, } from './useToolExecutionScheduler.js';
8
+ /**
9
+ * Facade hook that switches between the Legacy and Event-Driven schedulers
10
+ * based on configuration.
11
+ *
12
+ * Note: This conditionally calls hooks, which technically violates the standard
13
+ * Rules of Hooks linting. However, this is safe here because
14
+ * `config.isEventDrivenSchedulerEnabled()` is static for the lifetime of the
15
+ * application session (it essentially acts as a compile-time feature flag).
16
+ */
17
+ export function useToolScheduler(onComplete, config, getPreferredEditor) {
18
+ const isEventDriven = config.isEventDrivenSchedulerEnabled();
19
+ // Note: We return the hooks directly without casting. They return compatible
20
+ // tuple structures, but use explicit tuple signatures rather than the
21
+ // UseToolSchedulerReturn named type to avoid circular dependencies back to
22
+ // this facade.
23
+ if (isEventDriven) {
24
+ // eslint-disable-next-line react-hooks/rules-of-hooks
25
+ return useToolExecutionScheduler(onComplete, config, getPreferredEditor);
26
+ }
27
+ // eslint-disable-next-line react-hooks/rules-of-hooks
28
+ return useReactToolScheduler(onComplete, config, getPreferredEditor);
29
+ }
30
+ //# sourceMappingURL=useToolScheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useToolScheduler.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useToolScheduler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,EACL,qBAAqB,GAUtB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,yBAAyB,GAE1B,MAAM,gCAAgC,CAAC;AA+BxC;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAC9B,UAAyD,EACzD,MAAc,EACd,kBAAgD;IAEhD,MAAM,aAAa,GAAG,MAAM,CAAC,6BAA6B,EAAE,CAAC;IAE7D,6EAA6E;IAC7E,sEAAsE;IACtE,2EAA2E;IAC3E,eAAe;IACf,IAAI,aAAa,EAAE,CAAC;QAClB,sDAAsD;QACtD,OAAO,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC3E,CAAC;IAED,sDAAsD;IACtD,OAAO,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;AACvE,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
7
+ import { renderHook } from '../../test-utils/render.js';
8
+ import { useToolScheduler } from './useToolScheduler.js';
9
+ import { useReactToolScheduler } from './useReactToolScheduler.js';
10
+ import { useToolExecutionScheduler } from './useToolExecutionScheduler.js';
11
+ vi.mock('./useReactToolScheduler.js', () => ({
12
+ useReactToolScheduler: vi.fn().mockReturnValue(['legacy']),
13
+ }));
14
+ vi.mock('./useToolExecutionScheduler.js', () => ({
15
+ useToolExecutionScheduler: vi.fn().mockReturnValue(['modern']),
16
+ }));
17
+ describe('useToolScheduler (Facade)', () => {
18
+ let mockConfig;
19
+ beforeEach(() => {
20
+ vi.clearAllMocks();
21
+ });
22
+ it('delegates to useReactToolScheduler when event-driven scheduler is disabled', () => {
23
+ mockConfig = {
24
+ isEventDrivenSchedulerEnabled: () => false,
25
+ };
26
+ const onComplete = vi.fn();
27
+ const getPreferredEditor = vi.fn();
28
+ const { result } = renderHook(() => useToolScheduler(onComplete, mockConfig, getPreferredEditor));
29
+ expect(result.current).toEqual(['legacy']);
30
+ expect(useReactToolScheduler).toHaveBeenCalledWith(onComplete, mockConfig, getPreferredEditor);
31
+ expect(useToolExecutionScheduler).not.toHaveBeenCalled();
32
+ });
33
+ it('delegates to useToolExecutionScheduler when event-driven scheduler is enabled', () => {
34
+ mockConfig = {
35
+ isEventDrivenSchedulerEnabled: () => true,
36
+ };
37
+ const onComplete = vi.fn();
38
+ const getPreferredEditor = vi.fn();
39
+ const { result } = renderHook(() => useToolScheduler(onComplete, mockConfig, getPreferredEditor));
40
+ expect(result.current).toEqual(['modern']);
41
+ expect(useToolExecutionScheduler).toHaveBeenCalledWith(onComplete, mockConfig, getPreferredEditor);
42
+ expect(useReactToolScheduler).not.toHaveBeenCalled();
43
+ });
44
+ });
45
+ //# sourceMappingURL=useToolSchedulerFacade.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useToolSchedulerFacade.test.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useToolSchedulerFacade.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAG3E,EAAE,CAAC,IAAI,CAAC,4BAA4B,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3C,qBAAqB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC;CAC3D,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,gCAAgC,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/C,yBAAyB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC;CAC/D,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,IAAI,UAAkB,CAAC;IAEvB,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,UAAU,GAAG;YACX,6BAA6B,EAAE,GAAG,EAAE,CAAC,KAAK;SACtB,CAAC;QAEvB,MAAM,UAAU,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,kBAAkB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAEnC,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CACjC,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE,kBAAkB,CAAC,CAC7D,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,qBAAqB,CAAC,CAAC,oBAAoB,CAChD,UAAU,EACV,UAAU,EACV,kBAAkB,CACnB,CAAC;QACF,MAAM,CAAC,yBAAyB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,GAAG,EAAE;QACvF,UAAU,GAAG;YACX,6BAA6B,EAAE,GAAG,EAAE,CAAC,IAAI;SACrB,CAAC;QAEvB,MAAM,UAAU,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,kBAAkB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAEnC,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CACjC,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE,kBAAkB,CAAC,CAC7D,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,yBAAyB,CAAC,CAAC,oBAAoB,CACpD,UAAU,EACV,UAAU,EACV,kBAAkB,CACnB,CAAC;QACF,MAAM,CAAC,qBAAqB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { StreamingState } from '../types.js';
7
+ import { type TrackedToolCall } from './useReactToolScheduler.js';
8
+ export interface TurnActivityStatus {
9
+ operationStartTime: number;
10
+ isRedirectionActive: boolean;
11
+ }
12
+ /**
13
+ * Monitors the activity of a Gemini turn to detect when a new operation starts
14
+ * and whether it involves shell redirections that should suppress inactivity prompts.
15
+ */
16
+ export declare const useTurnActivityMonitor: (streamingState: StreamingState, activePtyId: number | string | null | undefined, pendingToolCalls?: TrackedToolCall[]) => TurnActivityStatus;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { useState, useEffect, useRef, useMemo } from 'react';
7
+ import { StreamingState } from '../types.js';
8
+ import { hasRedirection } from '@google/gemini-cli-core';
9
+ import {} from './useReactToolScheduler.js';
10
+ /**
11
+ * Monitors the activity of a Gemini turn to detect when a new operation starts
12
+ * and whether it involves shell redirections that should suppress inactivity prompts.
13
+ */
14
+ export const useTurnActivityMonitor = (streamingState, activePtyId, pendingToolCalls = []) => {
15
+ const [operationStartTime, setOperationStartTime] = useState(0);
16
+ // Reset operation start time whenever a new operation begins.
17
+ // We consider an operation to have started when we enter Responding state,
18
+ // OR when the active PTY changes (meaning a new command started within the turn).
19
+ const prevPtyIdRef = useRef(undefined);
20
+ const prevStreamingStateRef = useRef(undefined);
21
+ useEffect(() => {
22
+ const isNowResponding = streamingState === StreamingState.Responding;
23
+ const wasResponding = prevStreamingStateRef.current === StreamingState.Responding;
24
+ const ptyChanged = activePtyId !== prevPtyIdRef.current;
25
+ if (isNowResponding && (!wasResponding || ptyChanged)) {
26
+ setOperationStartTime(Date.now());
27
+ }
28
+ else if (!isNowResponding && wasResponding) {
29
+ setOperationStartTime(0);
30
+ }
31
+ prevPtyIdRef.current = activePtyId;
32
+ prevStreamingStateRef.current = streamingState;
33
+ }, [streamingState, activePtyId]);
34
+ // Detect redirection in the current query or tool calls.
35
+ // We derive this directly during render to ensure it's accurate from the first frame.
36
+ const isRedirectionActive = useMemo(() =>
37
+ // Check active tool calls for run_shell_command
38
+ pendingToolCalls.some((tc) => {
39
+ if (tc.request.name !== 'run_shell_command')
40
+ return false;
41
+ const command = tc.request.args?.command || '';
42
+ return hasRedirection(command);
43
+ }), [pendingToolCalls]);
44
+ return {
45
+ operationStartTime,
46
+ isRedirectionActive,
47
+ };
48
+ };
49
+ //# sourceMappingURL=useTurnActivityMonitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTurnActivityMonitor.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useTurnActivityMonitor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAwB,MAAM,4BAA4B,CAAC;AAOlE;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,cAA8B,EAC9B,WAA+C,EAC/C,mBAAsC,EAAE,EACpB,EAAE;IACtB,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEhE,8DAA8D;IAC9D,2EAA2E;IAC3E,kFAAkF;IAClF,MAAM,YAAY,GAAG,MAAM,CAAqC,SAAS,CAAC,CAAC;IAC3E,MAAM,qBAAqB,GAAG,MAAM,CAA6B,SAAS,CAAC,CAAC;IAE5E,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,eAAe,GAAG,cAAc,KAAK,cAAc,CAAC,UAAU,CAAC;QACrE,MAAM,aAAa,GACjB,qBAAqB,CAAC,OAAO,KAAK,cAAc,CAAC,UAAU,CAAC;QAC9D,MAAM,UAAU,GAAG,WAAW,KAAK,YAAY,CAAC,OAAO,CAAC;QAExD,IAAI,eAAe,IAAI,CAAC,CAAC,aAAa,IAAI,UAAU,CAAC,EAAE,CAAC;YACtD,qBAAqB,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACpC,CAAC;aAAM,IAAI,CAAC,eAAe,IAAI,aAAa,EAAE,CAAC;YAC7C,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC3B,CAAC;QAED,YAAY,CAAC,OAAO,GAAG,WAAW,CAAC;QACnC,qBAAqB,CAAC,OAAO,GAAG,cAAc,CAAC;IACjD,CAAC,EAAE,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC;IAElC,yDAAyD;IACzD,sFAAsF;IACtF,MAAM,mBAAmB,GAAG,OAAO,CACjC,GAAG,EAAE;IACH,gDAAgD;IAChD,gBAAgB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE;QAC3B,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,mBAAmB;YAAE,OAAO,KAAK,CAAC;QAE1D,MAAM,OAAO,GACV,EAAE,CAAC,OAAO,CAAC,IAA6B,EAAE,OAAO,IAAI,EAAE,CAAC;QAC3D,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC,CAAC,EACJ,CAAC,gBAAgB,CAAC,CACnB,CAAC;IAEF,OAAO;QACL,kBAAkB;QAClB,mBAAmB;KACpB,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,97 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
7
+ import { renderHook } from '../../test-utils/render.js';
8
+ import { useTurnActivityMonitor } from './useTurnActivityMonitor.js';
9
+ import { StreamingState } from '../types.js';
10
+ import { hasRedirection } from '@google/gemini-cli-core';
11
+ import {} from './useReactToolScheduler.js';
12
+ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
13
+ const actual = await importOriginal();
14
+ return {
15
+ ...actual,
16
+ hasRedirection: vi.fn(),
17
+ };
18
+ });
19
+ describe('useTurnActivityMonitor', () => {
20
+ beforeEach(() => {
21
+ vi.useFakeTimers();
22
+ vi.setSystemTime(1000);
23
+ vi.mocked(hasRedirection).mockImplementation((query) => query.includes('>') || query.includes('>>'));
24
+ });
25
+ afterEach(() => {
26
+ vi.clearAllMocks();
27
+ vi.useRealTimers();
28
+ });
29
+ it('should set operationStartTime when entering Responding state', () => {
30
+ const { result, rerender } = renderHook(({ state }) => useTurnActivityMonitor(state, null, []), {
31
+ initialProps: { state: StreamingState.Idle },
32
+ });
33
+ expect(result.current.operationStartTime).toBe(0);
34
+ rerender({ state: StreamingState.Responding });
35
+ expect(result.current.operationStartTime).toBe(1000);
36
+ });
37
+ it('should reset operationStartTime when PTY ID changes while responding', () => {
38
+ const { result, rerender } = renderHook(({ state, ptyId }) => useTurnActivityMonitor(state, ptyId, []), {
39
+ initialProps: {
40
+ state: StreamingState.Responding,
41
+ ptyId: 'pty-1',
42
+ },
43
+ });
44
+ expect(result.current.operationStartTime).toBe(1000);
45
+ vi.setSystemTime(2000);
46
+ rerender({ state: StreamingState.Responding, ptyId: 'pty-2' });
47
+ expect(result.current.operationStartTime).toBe(2000);
48
+ });
49
+ it('should detect redirection from tool calls', () => {
50
+ // Force mock implementation to ensure it's active
51
+ vi.mocked(hasRedirection).mockImplementation((q) => q.includes('>'));
52
+ const { result, rerender } = renderHook(({ state, pendingToolCalls }) => useTurnActivityMonitor(state, null, pendingToolCalls), {
53
+ initialProps: {
54
+ state: StreamingState.Responding,
55
+ pendingToolCalls: [],
56
+ },
57
+ });
58
+ expect(result.current.isRedirectionActive).toBe(false);
59
+ // Test non-redirected tool call
60
+ rerender({
61
+ state: StreamingState.Responding,
62
+ pendingToolCalls: [
63
+ {
64
+ request: {
65
+ name: 'run_shell_command',
66
+ args: { command: 'ls -la' },
67
+ },
68
+ status: 'executing',
69
+ },
70
+ ],
71
+ });
72
+ expect(result.current.isRedirectionActive).toBe(false);
73
+ // Test tool call redirection
74
+ rerender({
75
+ state: StreamingState.Responding,
76
+ pendingToolCalls: [
77
+ {
78
+ request: {
79
+ name: 'run_shell_command',
80
+ args: { command: 'ls > tool_out.txt' },
81
+ },
82
+ status: 'executing',
83
+ },
84
+ ],
85
+ });
86
+ expect(result.current.isRedirectionActive).toBe(true);
87
+ });
88
+ it('should reset everything when idle', () => {
89
+ const { result, rerender } = renderHook(({ state }) => useTurnActivityMonitor(state, 'pty-1', []), {
90
+ initialProps: { state: StreamingState.Responding },
91
+ });
92
+ expect(result.current.operationStartTime).toBe(1000);
93
+ rerender({ state: StreamingState.Idle });
94
+ expect(result.current.operationStartTime).toBe(0);
95
+ });
96
+ });
97
+ //# sourceMappingURL=useTurnActivityMonitor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTurnActivityMonitor.test.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useTurnActivityMonitor.test.ts"],"names":[],"mappings":"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"}
@@ -206,8 +206,9 @@ export function useVim(buffer, onSubmit) {
206
206
  }
207
207
  // Special handling for Enter key to allow command submission (lower priority than completion)
208
208
  if (normalizedKey.name === 'return' &&
209
+ !normalizedKey.alt &&
209
210
  !normalizedKey.ctrl &&
210
- !normalizedKey.meta) {
211
+ !normalizedKey.cmd) {
211
212
  if (buffer.text.trim() && onSubmit) {
212
213
  // Handle command submission directly
213
214
  const submittedValue = buffer.text;
@@ -229,9 +230,10 @@ export function useVim(buffer, onSubmit) {
229
230
  const normalizeKey = useCallback((key) => ({
230
231
  name: key.name || '',
231
232
  sequence: key.sequence || '',
232
- ctrl: key.ctrl || false,
233
- meta: key.meta || false,
234
233
  shift: key.shift || false,
234
+ alt: key.alt || false,
235
+ ctrl: key.ctrl || false,
236
+ cmd: key.cmd || false,
235
237
  insertable: key.insertable || false,
236
238
  }), []);
237
239
  /**