@google/gemini-cli 0.11.0-nightly.20251020.a96f0659 → 0.11.0-nightly.20251021.e72c00cf

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 (114) hide show
  1. package/dist/google-gemini-cli-0.11.0-nightly.20251020.a96f0659.tgz +0 -0
  2. package/dist/index.js +5 -5
  3. package/dist/index.js.map +1 -1
  4. package/dist/package.json +2 -2
  5. package/dist/src/commands/extensions/disable.js +8 -5
  6. package/dist/src/commands/extensions/disable.js.map +1 -1
  7. package/dist/src/commands/extensions/enable.js +5 -3
  8. package/dist/src/commands/extensions/enable.js.map +1 -1
  9. package/dist/src/commands/extensions/install.js +5 -4
  10. package/dist/src/commands/extensions/install.js.map +1 -1
  11. package/dist/src/commands/extensions/link.js +3 -2
  12. package/dist/src/commands/extensions/link.js.map +1 -1
  13. package/dist/src/commands/extensions/list.js +4 -3
  14. package/dist/src/commands/extensions/list.js.map +1 -1
  15. package/dist/src/commands/extensions/new.js +14 -20
  16. package/dist/src/commands/extensions/new.js.map +1 -1
  17. package/dist/src/commands/extensions/uninstall.js +3 -2
  18. package/dist/src/commands/extensions/uninstall.js.map +1 -1
  19. package/dist/src/commands/extensions/update.js +16 -16
  20. package/dist/src/commands/extensions/update.js.map +1 -1
  21. package/dist/src/commands/mcp/add.js +7 -4
  22. package/dist/src/commands/mcp/add.js.map +1 -1
  23. package/dist/src/commands/mcp/add.test.js +13 -3
  24. package/dist/src/commands/mcp/add.test.js.map +1 -1
  25. package/dist/src/commands/mcp/list.js +2 -2
  26. package/dist/src/commands/mcp/list.js.map +1 -1
  27. package/dist/src/config/config.d.ts +2 -3
  28. package/dist/src/config/config.integration.test.js +0 -30
  29. package/dist/src/config/config.integration.test.js.map +1 -1
  30. package/dist/src/config/config.js +21 -28
  31. package/dist/src/config/config.js.map +1 -1
  32. package/dist/src/config/config.test.js +109 -149
  33. package/dist/src/config/config.test.js.map +1 -1
  34. package/dist/src/config/extension.d.ts +3 -11
  35. package/dist/src/config/extension.js +24 -32
  36. package/dist/src/config/extension.js.map +1 -1
  37. package/dist/src/config/extension.test.js +33 -133
  38. package/dist/src/config/extension.test.js.map +1 -1
  39. package/dist/src/config/extensions/github.d.ts +3 -2
  40. package/dist/src/config/extensions/github.js +12 -9
  41. package/dist/src/config/extensions/github.js.map +1 -1
  42. package/dist/src/config/extensions/github.test.js +6 -5
  43. package/dist/src/config/extensions/github.test.js.map +1 -1
  44. package/dist/src/config/extensions/update.d.ts +5 -4
  45. package/dist/src/config/extensions/update.js +10 -6
  46. package/dist/src/config/extensions/update.js.map +1 -1
  47. package/dist/src/config/extensions/update.test.js +57 -57
  48. package/dist/src/config/extensions/update.test.js.map +1 -1
  49. package/dist/src/config/extensions/variableSchema.d.ts +2 -0
  50. package/dist/src/config/extensions/variableSchema.js.map +1 -1
  51. package/dist/src/config/policy.d.ts +3 -2
  52. package/dist/src/config/policy.js +20 -10
  53. package/dist/src/config/policy.js.map +1 -1
  54. package/dist/src/config/policy.test.js +58 -34
  55. package/dist/src/config/policy.test.js.map +1 -1
  56. package/dist/src/config/settings.js +3 -1
  57. package/dist/src/config/settings.js.map +1 -1
  58. package/dist/src/config/settings.test.js +9 -9
  59. package/dist/src/config/settings.test.js.map +1 -1
  60. package/dist/src/gemini.js +19 -15
  61. package/dist/src/gemini.js.map +1 -1
  62. package/dist/src/gemini.test.js +8 -0
  63. package/dist/src/gemini.test.js.map +1 -1
  64. package/dist/src/generated/git-commit.d.ts +2 -2
  65. package/dist/src/generated/git-commit.js +2 -2
  66. package/dist/src/nonInteractiveCli.js +2 -2
  67. package/dist/src/nonInteractiveCli.js.map +1 -1
  68. package/dist/src/services/prompt-processors/atFileProcessor.js +3 -2
  69. package/dist/src/services/prompt-processors/atFileProcessor.js.map +1 -1
  70. package/dist/src/ui/AppContainer.js +4 -2
  71. package/dist/src/ui/AppContainer.js.map +1 -1
  72. package/dist/src/ui/commands/directoryCommand.js +1 -1
  73. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  74. package/dist/src/ui/commands/directoryCommand.test.js +0 -1
  75. package/dist/src/ui/commands/directoryCommand.test.js.map +1 -1
  76. package/dist/src/ui/commands/memoryCommand.js +1 -1
  77. package/dist/src/ui/commands/memoryCommand.js.map +1 -1
  78. package/dist/src/ui/commands/memoryCommand.test.js +1 -1
  79. package/dist/src/ui/commands/memoryCommand.test.js.map +1 -1
  80. package/dist/src/ui/components/SettingsDialog.test.js +1 -20
  81. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  82. package/dist/src/ui/components/views/ExtensionsList.js +3 -4
  83. package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
  84. package/dist/src/ui/components/views/ExtensionsList.test.js +2 -9
  85. package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -1
  86. package/dist/src/ui/components/views/McpStatus.js +2 -2
  87. package/dist/src/ui/components/views/McpStatus.js.map +1 -1
  88. package/dist/src/ui/hooks/useExtensionUpdates.d.ts +2 -1
  89. package/dist/src/ui/hooks/useExtensionUpdates.js +5 -3
  90. package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
  91. package/dist/src/ui/hooks/useExtensionUpdates.test.js +22 -13
  92. package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
  93. package/dist/src/ui/utils/computeStats.js +5 -2
  94. package/dist/src/ui/utils/computeStats.js.map +1 -1
  95. package/dist/src/ui/utils/computeStats.test.d.ts +6 -0
  96. package/dist/src/ui/utils/computeStats.test.js +262 -0
  97. package/dist/src/ui/utils/computeStats.test.js.map +1 -0
  98. package/dist/src/utils/cleanup.test.d.ts +6 -0
  99. package/dist/src/utils/cleanup.test.js +49 -0
  100. package/dist/src/utils/cleanup.test.js.map +1 -0
  101. package/dist/src/utils/handleAutoUpdate.test.d.ts +6 -0
  102. package/dist/src/utils/handleAutoUpdate.test.js +225 -0
  103. package/dist/src/utils/handleAutoUpdate.test.js.map +1 -0
  104. package/dist/src/utils/sandbox-macos-permissive-open.sb +3 -1
  105. package/dist/src/utils/startupWarnings.test.d.ts +6 -0
  106. package/dist/src/utils/startupWarnings.test.js +61 -0
  107. package/dist/src/utils/startupWarnings.test.js.map +1 -0
  108. package/dist/src/validateNonInterActiveAuth.js +2 -2
  109. package/dist/src/validateNonInterActiveAuth.js.map +1 -1
  110. package/dist/src/zed-integration/zedIntegration.js +1 -2
  111. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  112. package/dist/tsconfig.tsbuildinfo +1 -1
  113. package/package.json +3 -3
  114. package/dist/google-gemini-cli-0.11.0-nightly.20251015.203bad7c.tgz +0 -0
@@ -0,0 +1,262 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect } from 'vitest';
7
+ import { calculateAverageLatency, calculateCacheHitRate, calculateErrorRate, computeSessionStats, } from './computeStats.js';
8
+ describe('calculateErrorRate', () => {
9
+ it('should return 0 if totalRequests is 0', () => {
10
+ const metrics = {
11
+ api: { totalRequests: 0, totalErrors: 0, totalLatencyMs: 0 },
12
+ tokens: {
13
+ prompt: 0,
14
+ candidates: 0,
15
+ total: 0,
16
+ cached: 0,
17
+ thoughts: 0,
18
+ tool: 0,
19
+ },
20
+ };
21
+ expect(calculateErrorRate(metrics)).toBe(0);
22
+ });
23
+ it('should calculate the error rate correctly', () => {
24
+ const metrics = {
25
+ api: { totalRequests: 10, totalErrors: 2, totalLatencyMs: 0 },
26
+ tokens: {
27
+ prompt: 0,
28
+ candidates: 0,
29
+ total: 0,
30
+ cached: 0,
31
+ thoughts: 0,
32
+ tool: 0,
33
+ },
34
+ };
35
+ expect(calculateErrorRate(metrics)).toBe(20);
36
+ });
37
+ });
38
+ describe('calculateAverageLatency', () => {
39
+ it('should return 0 if totalRequests is 0', () => {
40
+ const metrics = {
41
+ api: { totalRequests: 0, totalErrors: 0, totalLatencyMs: 1000 },
42
+ tokens: {
43
+ prompt: 0,
44
+ candidates: 0,
45
+ total: 0,
46
+ cached: 0,
47
+ thoughts: 0,
48
+ tool: 0,
49
+ },
50
+ };
51
+ expect(calculateAverageLatency(metrics)).toBe(0);
52
+ });
53
+ it('should calculate the average latency correctly', () => {
54
+ const metrics = {
55
+ api: { totalRequests: 10, totalErrors: 0, totalLatencyMs: 1500 },
56
+ tokens: {
57
+ prompt: 0,
58
+ candidates: 0,
59
+ total: 0,
60
+ cached: 0,
61
+ thoughts: 0,
62
+ tool: 0,
63
+ },
64
+ };
65
+ expect(calculateAverageLatency(metrics)).toBe(150);
66
+ });
67
+ });
68
+ describe('calculateCacheHitRate', () => {
69
+ it('should return 0 if prompt tokens is 0', () => {
70
+ const metrics = {
71
+ api: { totalRequests: 0, totalErrors: 0, totalLatencyMs: 0 },
72
+ tokens: {
73
+ prompt: 0,
74
+ candidates: 0,
75
+ total: 0,
76
+ cached: 100,
77
+ thoughts: 0,
78
+ tool: 0,
79
+ },
80
+ };
81
+ expect(calculateCacheHitRate(metrics)).toBe(0);
82
+ });
83
+ it('should calculate the cache hit rate correctly', () => {
84
+ const metrics = {
85
+ api: { totalRequests: 0, totalErrors: 0, totalLatencyMs: 0 },
86
+ tokens: {
87
+ prompt: 200,
88
+ candidates: 0,
89
+ total: 0,
90
+ cached: 50,
91
+ thoughts: 0,
92
+ tool: 0,
93
+ },
94
+ };
95
+ expect(calculateCacheHitRate(metrics)).toBe(25);
96
+ });
97
+ });
98
+ describe('computeSessionStats', () => {
99
+ it('should return all zeros for initial empty metrics', () => {
100
+ const metrics = {
101
+ models: {},
102
+ tools: {
103
+ totalCalls: 0,
104
+ totalSuccess: 0,
105
+ totalFail: 0,
106
+ totalDurationMs: 0,
107
+ totalDecisions: { accept: 0, reject: 0, modify: 0, auto_accept: 0 },
108
+ byName: {},
109
+ },
110
+ files: {
111
+ totalLinesAdded: 0,
112
+ totalLinesRemoved: 0,
113
+ },
114
+ };
115
+ const result = computeSessionStats(metrics);
116
+ expect(result).toEqual({
117
+ totalApiTime: 0,
118
+ totalToolTime: 0,
119
+ agentActiveTime: 0,
120
+ apiTimePercent: 0,
121
+ toolTimePercent: 0,
122
+ cacheEfficiency: 0,
123
+ totalDecisions: 0,
124
+ successRate: 0,
125
+ agreementRate: 0,
126
+ totalPromptTokens: 0,
127
+ totalCachedTokens: 0,
128
+ totalLinesAdded: 0,
129
+ totalLinesRemoved: 0,
130
+ });
131
+ });
132
+ it('should correctly calculate API and tool time percentages', () => {
133
+ const metrics = {
134
+ models: {
135
+ 'gemini-pro': {
136
+ api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 750 },
137
+ tokens: {
138
+ prompt: 10,
139
+ candidates: 10,
140
+ total: 20,
141
+ cached: 0,
142
+ thoughts: 0,
143
+ tool: 0,
144
+ },
145
+ },
146
+ },
147
+ tools: {
148
+ totalCalls: 1,
149
+ totalSuccess: 1,
150
+ totalFail: 0,
151
+ totalDurationMs: 250,
152
+ totalDecisions: { accept: 0, reject: 0, modify: 0, auto_accept: 0 },
153
+ byName: {},
154
+ },
155
+ files: {
156
+ totalLinesAdded: 0,
157
+ totalLinesRemoved: 0,
158
+ },
159
+ };
160
+ const result = computeSessionStats(metrics);
161
+ expect(result.totalApiTime).toBe(750);
162
+ expect(result.totalToolTime).toBe(250);
163
+ expect(result.agentActiveTime).toBe(1000);
164
+ expect(result.apiTimePercent).toBe(75);
165
+ expect(result.toolTimePercent).toBe(25);
166
+ });
167
+ it('should correctly calculate cache efficiency', () => {
168
+ const metrics = {
169
+ models: {
170
+ 'gemini-pro': {
171
+ api: { totalRequests: 2, totalErrors: 0, totalLatencyMs: 1000 },
172
+ tokens: {
173
+ prompt: 150,
174
+ candidates: 10,
175
+ total: 160,
176
+ cached: 50,
177
+ thoughts: 0,
178
+ tool: 0,
179
+ },
180
+ },
181
+ },
182
+ tools: {
183
+ totalCalls: 0,
184
+ totalSuccess: 0,
185
+ totalFail: 0,
186
+ totalDurationMs: 0,
187
+ totalDecisions: { accept: 0, reject: 0, modify: 0, auto_accept: 0 },
188
+ byName: {},
189
+ },
190
+ files: {
191
+ totalLinesAdded: 0,
192
+ totalLinesRemoved: 0,
193
+ },
194
+ };
195
+ const result = computeSessionStats(metrics);
196
+ expect(result.cacheEfficiency).toBeCloseTo(33.33); // 50 / 150
197
+ });
198
+ it('should correctly calculate success and agreement rates', () => {
199
+ const metrics = {
200
+ models: {},
201
+ tools: {
202
+ totalCalls: 10,
203
+ totalSuccess: 8,
204
+ totalFail: 2,
205
+ totalDurationMs: 1000,
206
+ totalDecisions: { accept: 6, reject: 2, modify: 2, auto_accept: 0 },
207
+ byName: {},
208
+ },
209
+ files: {
210
+ totalLinesAdded: 0,
211
+ totalLinesRemoved: 0,
212
+ },
213
+ };
214
+ const result = computeSessionStats(metrics);
215
+ expect(result.successRate).toBe(80); // 8 / 10
216
+ expect(result.agreementRate).toBe(60); // 6 / 10
217
+ });
218
+ it('should handle division by zero gracefully', () => {
219
+ const metrics = {
220
+ models: {},
221
+ tools: {
222
+ totalCalls: 0,
223
+ totalSuccess: 0,
224
+ totalFail: 0,
225
+ totalDurationMs: 0,
226
+ totalDecisions: { accept: 0, reject: 0, modify: 0, auto_accept: 0 },
227
+ byName: {},
228
+ },
229
+ files: {
230
+ totalLinesAdded: 0,
231
+ totalLinesRemoved: 0,
232
+ },
233
+ };
234
+ const result = computeSessionStats(metrics);
235
+ expect(result.apiTimePercent).toBe(0);
236
+ expect(result.toolTimePercent).toBe(0);
237
+ expect(result.cacheEfficiency).toBe(0);
238
+ expect(result.successRate).toBe(0);
239
+ expect(result.agreementRate).toBe(0);
240
+ });
241
+ it('should correctly include line counts', () => {
242
+ const metrics = {
243
+ models: {},
244
+ tools: {
245
+ totalCalls: 0,
246
+ totalSuccess: 0,
247
+ totalFail: 0,
248
+ totalDurationMs: 0,
249
+ totalDecisions: { accept: 0, reject: 0, modify: 0, auto_accept: 0 },
250
+ byName: {},
251
+ },
252
+ files: {
253
+ totalLinesAdded: 42,
254
+ totalLinesRemoved: 18,
255
+ },
256
+ };
257
+ const result = computeSessionStats(metrics);
258
+ expect(result.totalLinesAdded).toBe(42);
259
+ expect(result.totalLinesRemoved).toBe(18);
260
+ });
261
+ });
262
+ //# sourceMappingURL=computeStats.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computeStats.test.js","sourceRoot":"","sources":["../../../../src/ui/utils/computeStats.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,49 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { vi, describe, it, expect, beforeEach } from 'vitest';
7
+ describe('cleanup', () => {
8
+ let register;
9
+ let runExit;
10
+ beforeEach(async () => {
11
+ vi.resetModules();
12
+ const cleanupModule = await import('./cleanup.js');
13
+ register = cleanupModule.registerCleanup;
14
+ runExit = cleanupModule.runExitCleanup;
15
+ });
16
+ it('should run a registered synchronous function', async () => {
17
+ const cleanupFn = vi.fn();
18
+ register(cleanupFn);
19
+ await runExit();
20
+ expect(cleanupFn).toHaveBeenCalledTimes(1);
21
+ });
22
+ it('should run a registered asynchronous function', async () => {
23
+ const cleanupFn = vi.fn().mockResolvedValue(undefined);
24
+ register(cleanupFn);
25
+ await runExit();
26
+ expect(cleanupFn).toHaveBeenCalledTimes(1);
27
+ });
28
+ it('should run multiple registered functions', async () => {
29
+ const syncFn = vi.fn();
30
+ const asyncFn = vi.fn().mockResolvedValue(undefined);
31
+ register(syncFn);
32
+ register(asyncFn);
33
+ await runExit();
34
+ expect(syncFn).toHaveBeenCalledTimes(1);
35
+ expect(asyncFn).toHaveBeenCalledTimes(1);
36
+ });
37
+ it('should continue running cleanup functions even if one throws an error', async () => {
38
+ const errorFn = vi.fn().mockImplementation(() => {
39
+ throw new Error('test error');
40
+ });
41
+ const successFn = vi.fn();
42
+ register(errorFn);
43
+ register(successFn);
44
+ await expect(runExit()).resolves.not.toThrow();
45
+ expect(errorFn).toHaveBeenCalledTimes(1);
46
+ expect(successFn).toHaveBeenCalledTimes(1);
47
+ });
48
+ });
49
+ //# sourceMappingURL=cleanup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleanup.test.js","sourceRoot":"","sources":["../../../src/utils/cleanup.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAG9D,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,IAAI,QAAgC,CAAC;IACrC,IAAI,OAA8B,CAAC;IAEnC,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,EAAE,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACnD,QAAQ,GAAG,aAAa,CAAC,eAAe,CAAC;QACzC,OAAO,GAAG,aAAa,CAAC,cAAc,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1B,QAAQ,CAAC,SAAS,CAAC,CAAC;QAEpB,MAAM,OAAO,EAAE,CAAC;QAEhB,MAAM,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACvD,QAAQ,CAAC,SAAS,CAAC,CAAC;QAEpB,MAAM,OAAO,EAAE,CAAC;QAEhB,MAAM,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAErD,QAAQ,CAAC,MAAM,CAAC,CAAC;QACjB,QAAQ,CAAC,OAAO,CAAC,CAAC;QAElB,MAAM,OAAO,EAAE,CAAC;QAEhB,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACrF,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE;YAC9C,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QACH,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1B,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClB,QAAQ,CAAC,SAAS,CAAC,CAAC;QAEpB,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAE/C,MAAM,CAAC,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,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,225 @@
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 { getInstallationInfo, PackageManager } from './installationInfo.js';
8
+ import { updateEventEmitter } from './updateEventEmitter.js';
9
+ import EventEmitter from 'node:events';
10
+ import { handleAutoUpdate } from './handleAutoUpdate.js';
11
+ vi.mock('./installationInfo.js', async () => {
12
+ const actual = await vi.importActual('./installationInfo.js');
13
+ return {
14
+ ...actual,
15
+ getInstallationInfo: vi.fn(),
16
+ };
17
+ });
18
+ vi.mock('./updateEventEmitter.js', async () => {
19
+ const actual = await vi.importActual('./updateEventEmitter.js');
20
+ return {
21
+ ...actual,
22
+ updateEventEmitter: {
23
+ ...actual['updateEventEmitter'],
24
+ emit: vi.fn(),
25
+ },
26
+ };
27
+ });
28
+ const mockGetInstallationInfo = vi.mocked(getInstallationInfo);
29
+ const mockUpdateEventEmitter = vi.mocked(updateEventEmitter);
30
+ describe('handleAutoUpdate', () => {
31
+ let mockSpawn;
32
+ let mockUpdateInfo;
33
+ let mockSettings;
34
+ let mockChildProcess;
35
+ beforeEach(() => {
36
+ mockSpawn = vi.fn();
37
+ vi.clearAllMocks();
38
+ mockUpdateInfo = {
39
+ update: {
40
+ latest: '2.0.0',
41
+ current: '1.0.0',
42
+ type: 'major',
43
+ name: '@google/gemini-cli',
44
+ },
45
+ message: 'An update is available!',
46
+ };
47
+ mockSettings = {
48
+ merged: {
49
+ general: {
50
+ disableAutoUpdate: false,
51
+ },
52
+ },
53
+ };
54
+ mockChildProcess = Object.assign(new EventEmitter(), {
55
+ stdin: Object.assign(new EventEmitter(), {
56
+ write: vi.fn(),
57
+ end: vi.fn(),
58
+ }),
59
+ stderr: new EventEmitter(),
60
+ });
61
+ mockSpawn.mockReturnValue(mockChildProcess);
62
+ });
63
+ afterEach(() => {
64
+ vi.clearAllMocks();
65
+ });
66
+ it('should do nothing if update info is null', () => {
67
+ handleAutoUpdate(null, mockSettings, '/root', mockSpawn);
68
+ expect(mockGetInstallationInfo).not.toHaveBeenCalled();
69
+ expect(mockUpdateEventEmitter.emit).not.toHaveBeenCalled();
70
+ expect(mockSpawn).not.toHaveBeenCalled();
71
+ });
72
+ it('should do nothing if update nag is disabled', () => {
73
+ mockSettings.merged.general.disableUpdateNag = true;
74
+ handleAutoUpdate(mockUpdateInfo, mockSettings, '/root', mockSpawn);
75
+ expect(mockGetInstallationInfo).not.toHaveBeenCalled();
76
+ expect(mockUpdateEventEmitter.emit).not.toHaveBeenCalled();
77
+ expect(mockSpawn).not.toHaveBeenCalled();
78
+ });
79
+ it('should emit "update-received" but not update if auto-updates are disabled', () => {
80
+ mockSettings.merged.general.disableAutoUpdate = true;
81
+ mockGetInstallationInfo.mockReturnValue({
82
+ updateCommand: 'npm i -g @google/gemini-cli@latest',
83
+ updateMessage: 'Please update manually.',
84
+ isGlobal: true,
85
+ packageManager: PackageManager.NPM,
86
+ });
87
+ handleAutoUpdate(mockUpdateInfo, mockSettings, '/root', mockSpawn);
88
+ expect(mockUpdateEventEmitter.emit).toHaveBeenCalledTimes(1);
89
+ expect(mockUpdateEventEmitter.emit).toHaveBeenCalledWith('update-received', {
90
+ message: 'An update is available!\nPlease update manually.',
91
+ });
92
+ expect(mockSpawn).not.toHaveBeenCalled();
93
+ });
94
+ it.each([PackageManager.NPX, PackageManager.PNPX, PackageManager.BUNX])('should suppress update notifications when running via %s', (packageManager) => {
95
+ mockGetInstallationInfo.mockReturnValue({
96
+ updateCommand: undefined,
97
+ updateMessage: `Running via ${packageManager}, update not applicable.`,
98
+ isGlobal: false,
99
+ packageManager,
100
+ });
101
+ handleAutoUpdate(mockUpdateInfo, mockSettings, '/root', mockSpawn);
102
+ expect(mockUpdateEventEmitter.emit).not.toHaveBeenCalled();
103
+ expect(mockSpawn).not.toHaveBeenCalled();
104
+ });
105
+ it('should emit "update-received" but not update if no update command is found', () => {
106
+ mockGetInstallationInfo.mockReturnValue({
107
+ updateCommand: undefined,
108
+ updateMessage: 'Cannot determine update command.',
109
+ isGlobal: false,
110
+ packageManager: PackageManager.NPM,
111
+ });
112
+ handleAutoUpdate(mockUpdateInfo, mockSettings, '/root', mockSpawn);
113
+ expect(mockUpdateEventEmitter.emit).toHaveBeenCalledTimes(1);
114
+ expect(mockUpdateEventEmitter.emit).toHaveBeenCalledWith('update-received', {
115
+ message: 'An update is available!\nCannot determine update command.',
116
+ });
117
+ expect(mockSpawn).not.toHaveBeenCalled();
118
+ });
119
+ it('should combine update messages correctly', () => {
120
+ mockGetInstallationInfo.mockReturnValue({
121
+ updateCommand: undefined, // No command to prevent spawn
122
+ updateMessage: 'This is an additional message.',
123
+ isGlobal: false,
124
+ packageManager: PackageManager.NPM,
125
+ });
126
+ handleAutoUpdate(mockUpdateInfo, mockSettings, '/root', mockSpawn);
127
+ expect(mockUpdateEventEmitter.emit).toHaveBeenCalledTimes(1);
128
+ expect(mockUpdateEventEmitter.emit).toHaveBeenCalledWith('update-received', {
129
+ message: 'An update is available!\nThis is an additional message.',
130
+ });
131
+ });
132
+ it('should attempt to perform an update when conditions are met', async () => {
133
+ mockGetInstallationInfo.mockReturnValue({
134
+ updateCommand: 'npm i -g @google/gemini-cli@latest',
135
+ updateMessage: 'This is an additional message.',
136
+ isGlobal: false,
137
+ packageManager: PackageManager.NPM,
138
+ });
139
+ // Simulate successful execution
140
+ setTimeout(() => {
141
+ mockChildProcess.emit('close', 0);
142
+ }, 0);
143
+ handleAutoUpdate(mockUpdateInfo, mockSettings, '/root', mockSpawn);
144
+ expect(mockSpawn).toHaveBeenCalledOnce();
145
+ });
146
+ it('should emit "update-failed" when the update process fails', async () => {
147
+ await new Promise((resolve) => {
148
+ mockGetInstallationInfo.mockReturnValue({
149
+ updateCommand: 'npm i -g @google/gemini-cli@latest',
150
+ updateMessage: 'This is an additional message.',
151
+ isGlobal: false,
152
+ packageManager: PackageManager.NPM,
153
+ });
154
+ // Simulate failed execution
155
+ setTimeout(() => {
156
+ mockChildProcess.stderr.emit('data', 'An error occurred');
157
+ mockChildProcess.emit('close', 1);
158
+ resolve();
159
+ }, 0);
160
+ handleAutoUpdate(mockUpdateInfo, mockSettings, '/root', mockSpawn);
161
+ });
162
+ expect(mockUpdateEventEmitter.emit).toHaveBeenCalledWith('update-failed', {
163
+ message: 'Automatic update failed. Please try updating manually. (command: npm i -g @google/gemini-cli@2.0.0, stderr: An error occurred)',
164
+ });
165
+ });
166
+ it('should emit "update-failed" when the spawn function throws an error', async () => {
167
+ await new Promise((resolve) => {
168
+ mockGetInstallationInfo.mockReturnValue({
169
+ updateCommand: 'npm i -g @google/gemini-cli@latest',
170
+ updateMessage: 'This is an additional message.',
171
+ isGlobal: false,
172
+ packageManager: PackageManager.NPM,
173
+ });
174
+ // Simulate an error event
175
+ setTimeout(() => {
176
+ mockChildProcess.emit('error', new Error('Spawn error'));
177
+ resolve();
178
+ }, 0);
179
+ handleAutoUpdate(mockUpdateInfo, mockSettings, '/root', mockSpawn);
180
+ });
181
+ expect(mockUpdateEventEmitter.emit).toHaveBeenCalledWith('update-failed', {
182
+ message: 'Automatic update failed. Please try updating manually. (error: Spawn error)',
183
+ });
184
+ });
185
+ it('should use the "@nightly" tag for nightly updates', async () => {
186
+ mockUpdateInfo = {
187
+ ...mockUpdateInfo,
188
+ update: {
189
+ ...mockUpdateInfo.update,
190
+ latest: '2.0.0-nightly',
191
+ },
192
+ };
193
+ mockGetInstallationInfo.mockReturnValue({
194
+ updateCommand: 'npm i -g @google/gemini-cli@latest',
195
+ updateMessage: 'This is an additional message.',
196
+ isGlobal: false,
197
+ packageManager: PackageManager.NPM,
198
+ });
199
+ handleAutoUpdate(mockUpdateInfo, mockSettings, '/root', mockSpawn);
200
+ expect(mockSpawn).toHaveBeenCalledWith('npm i -g @google/gemini-cli@nightly', {
201
+ shell: true,
202
+ stdio: 'pipe',
203
+ });
204
+ });
205
+ it('should emit "update-success" when the update process succeeds', async () => {
206
+ await new Promise((resolve) => {
207
+ mockGetInstallationInfo.mockReturnValue({
208
+ updateCommand: 'npm i -g @google/gemini-cli@latest',
209
+ updateMessage: 'This is an additional message.',
210
+ isGlobal: false,
211
+ packageManager: PackageManager.NPM,
212
+ });
213
+ // Simulate successful execution
214
+ setTimeout(() => {
215
+ mockChildProcess.emit('close', 0);
216
+ resolve();
217
+ }, 0);
218
+ handleAutoUpdate(mockUpdateInfo, mockSettings, '/root', mockSpawn);
219
+ });
220
+ expect(mockUpdateEventEmitter.emit).toHaveBeenCalledWith('update-success', {
221
+ message: 'Update successful! The new version will be used on your next run.',
222
+ });
223
+ });
224
+ });
225
+ //# sourceMappingURL=handleAutoUpdate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handleAutoUpdate.test.js","sourceRoot":"","sources":["../../../src/utils/handleAutoUpdate.test.ts"],"names":[],"mappings":"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"}
@@ -22,4 +22,6 @@
22
22
  (literal "/dev/stdout")
23
23
  (literal "/dev/stderr")
24
24
  (literal "/dev/null")
25
- )
25
+ (literal "/dev/ptmx")
26
+ (regex #"^/dev/ttys[0-9]*$")
27
+ )
@@ -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,61 @@
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 { getStartupWarnings } from './startupWarnings.js';
8
+ import * as fs from 'node:fs/promises';
9
+ import { getErrorMessage } from '@google/gemini-cli-core';
10
+ vi.mock('node:fs/promises', { spy: true });
11
+ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
12
+ const actual = await importOriginal();
13
+ return {
14
+ ...actual,
15
+ getErrorMessage: vi.fn(),
16
+ };
17
+ });
18
+ describe('startupWarnings', () => {
19
+ beforeEach(() => {
20
+ vi.resetAllMocks();
21
+ });
22
+ it('should return warnings from the file and delete it', async () => {
23
+ const mockWarnings = 'Warning 1\nWarning 2';
24
+ vi.mocked(fs.access).mockResolvedValue();
25
+ vi.mocked(fs.readFile).mockResolvedValue(mockWarnings);
26
+ vi.mocked(fs.unlink).mockResolvedValue();
27
+ const warnings = await getStartupWarnings();
28
+ expect(fs.access).toHaveBeenCalled();
29
+ expect(fs.readFile).toHaveBeenCalled();
30
+ expect(fs.unlink).toHaveBeenCalled();
31
+ expect(warnings).toEqual(['Warning 1', 'Warning 2']);
32
+ });
33
+ it('should return an empty array if the file does not exist', async () => {
34
+ const error = new Error('File not found');
35
+ error.code = 'ENOENT';
36
+ vi.mocked(fs.access).mockRejectedValue(error);
37
+ const warnings = await getStartupWarnings();
38
+ expect(warnings).toEqual([]);
39
+ });
40
+ it('should return an error message if reading the file fails', async () => {
41
+ const error = new Error('Permission denied');
42
+ vi.mocked(fs.access).mockRejectedValue(error);
43
+ vi.mocked(getErrorMessage).mockReturnValue('Permission denied');
44
+ const warnings = await getStartupWarnings();
45
+ expect(warnings).toEqual([
46
+ 'Error checking/reading warnings file: Permission denied',
47
+ ]);
48
+ });
49
+ it('should return a warning if deleting the file fails', async () => {
50
+ const mockWarnings = 'Warning 1';
51
+ vi.mocked(fs.access).mockResolvedValue();
52
+ vi.mocked(fs.readFile).mockResolvedValue(mockWarnings);
53
+ vi.mocked(fs.unlink).mockRejectedValue(new Error('Permission denied'));
54
+ const warnings = await getStartupWarnings();
55
+ expect(warnings).toEqual([
56
+ 'Warning 1',
57
+ 'Warning: Could not delete temporary warnings file.',
58
+ ]);
59
+ });
60
+ });
61
+ //# sourceMappingURL=startupWarnings.test.js.map