@google/gemini-cli 0.21.2 → 0.22.0-preview.1
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.
- package/dist/package.json +3 -2
- package/dist/src/commands/extensions/disable.js.map +1 -1
- package/dist/src/commands/extensions/disable.test.js.map +1 -1
- package/dist/src/commands/extensions/enable.js.map +1 -1
- package/dist/src/commands/extensions/enable.test.js.map +1 -1
- package/dist/src/commands/extensions/examples/mcp-server/example.test.js +1 -1
- package/dist/src/commands/extensions/examples/mcp-server/example.test.js.map +1 -1
- package/dist/src/commands/extensions/examples/mcp-server/example.test.ts +4 -12
- package/dist/src/commands/extensions/link.test.js.map +1 -1
- package/dist/src/commands/extensions/list.test.js +0 -1
- package/dist/src/commands/extensions/list.test.js.map +1 -1
- package/dist/src/commands/extensions/uninstall.js.map +1 -1
- package/dist/src/commands/extensions/uninstall.test.js.map +1 -1
- package/dist/src/commands/extensions/update.test.js.map +1 -1
- package/dist/src/config/config.js +2 -3
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/extension-manager.js +8 -9
- package/dist/src/config/extension-manager.js.map +1 -1
- package/dist/src/config/extension.test.js +4 -4
- package/dist/src/config/extension.test.js.map +1 -1
- package/dist/src/config/extensions/extensionSettings.js +1 -1
- package/dist/src/config/extensions/extensionSettings.js.map +1 -1
- package/dist/src/config/extensions/extensionSettings.test.js +27 -0
- package/dist/src/config/extensions/extensionSettings.test.js.map +1 -1
- package/dist/src/config/extensions/github_fetch.js.map +1 -1
- package/dist/src/config/settings-validation.d.ts +23 -0
- package/dist/src/config/settings-validation.js +249 -0
- package/dist/src/config/settings-validation.js.map +1 -0
- package/dist/src/config/settings-validation.test.js +322 -0
- package/dist/src/config/settings-validation.test.js.map +1 -0
- package/dist/src/config/settings.js +23 -2
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/config/settings.test.js +23 -0
- package/dist/src/config/settings.test.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +9 -0
- package/dist/src/config/settingsSchema.js +9 -0
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/config/settingsSchema.test.js.map +1 -1
- package/dist/src/{utils/version.d.ts → config/settings_repro.test.d.ts} +1 -1
- package/dist/src/config/settings_repro.test.js +162 -0
- package/dist/src/config/settings_repro.test.js.map +1 -0
- package/dist/src/gemini.js +2 -3
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/gemini.test.js +3 -5
- package/dist/src/gemini.test.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/nonInteractiveCli.js +4 -4
- package/dist/src/nonInteractiveCli.js.map +1 -1
- package/dist/src/nonInteractiveCli.test.js +0 -2
- package/dist/src/nonInteractiveCli.test.js.map +1 -1
- package/dist/src/services/FileCommandLoader.test.js.map +1 -1
- package/dist/src/ui/AppContainer.js +6 -0
- package/dist/src/ui/AppContainer.js.map +1 -1
- package/dist/src/ui/auth/ApiAuthDialog.js +36 -3
- package/dist/src/ui/auth/ApiAuthDialog.js.map +1 -1
- package/dist/src/ui/auth/ApiAuthDialog.test.js +26 -2
- package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -1
- package/dist/src/ui/auth/AuthDialog.js +1 -2
- package/dist/src/ui/auth/AuthDialog.js.map +1 -1
- package/dist/src/ui/auth/AuthDialog.test.js +11 -2
- package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
- package/dist/src/ui/auth/useAuth.js +7 -4
- package/dist/src/ui/auth/useAuth.js.map +1 -1
- package/dist/src/ui/auth/useAuth.test.js +2 -2
- package/dist/src/ui/auth/useAuth.test.js.map +1 -1
- package/dist/src/ui/commands/aboutCommand.js +2 -3
- package/dist/src/ui/commands/aboutCommand.js.map +1 -1
- package/dist/src/ui/commands/aboutCommand.test.js +3 -6
- package/dist/src/ui/commands/aboutCommand.test.js.map +1 -1
- package/dist/src/ui/commands/bugCommand.js +2 -3
- package/dist/src/ui/commands/bugCommand.js.map +1 -1
- package/dist/src/ui/commands/bugCommand.test.js +3 -3
- package/dist/src/ui/commands/bugCommand.test.js.map +1 -1
- package/dist/src/ui/commands/chatCommand.test.js.map +1 -1
- package/dist/src/ui/commands/ideCommand.test.js.map +1 -1
- package/dist/src/ui/commands/initCommand.js +10 -50
- package/dist/src/ui/commands/initCommand.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.js +1 -2
- package/dist/src/ui/commands/mcpCommand.js.map +1 -1
- package/dist/src/ui/commands/restoreCommand.js +1 -3
- package/dist/src/ui/commands/restoreCommand.js.map +1 -1
- package/dist/src/ui/components/DialogManager.js +1 -1
- package/dist/src/ui/components/DialogManager.js.map +1 -1
- package/dist/src/ui/components/ModelStatsDisplay.js +1 -1
- package/dist/src/ui/components/ModelStatsDisplay.js.map +1 -1
- package/dist/src/ui/components/ModelStatsDisplay.test.js +7 -0
- package/dist/src/ui/components/ModelStatsDisplay.test.js.map +1 -1
- package/dist/src/ui/components/QuittingDisplay.test.js.map +1 -1
- package/dist/src/ui/components/SessionSummaryDisplay.test.js +1 -0
- package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +1 -1
- package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
- package/dist/src/ui/components/StatsDisplay.d.ts +1 -1
- package/dist/src/ui/components/StatsDisplay.js +11 -15
- package/dist/src/ui/components/StatsDisplay.js.map +1 -1
- package/dist/src/ui/components/StatsDisplay.test.js +41 -0
- package/dist/src/ui/components/StatsDisplay.test.js.map +1 -1
- package/dist/src/ui/components/ToolStatsDisplay.js.map +1 -1
- package/dist/src/ui/components/messages/Todo.js.map +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +20 -0
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
- package/dist/src/ui/components/shared/VirtualizedList.js.map +1 -1
- package/dist/src/ui/components/shared/text-buffer.js +5 -3
- package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
- package/dist/src/ui/components/shared/text-buffer.test.js +25 -0
- package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
- package/dist/src/ui/constants/tips.js +0 -1
- package/dist/src/ui/constants/tips.js.map +1 -1
- package/dist/src/ui/contexts/SessionContext.d.ts +1 -0
- package/dist/src/ui/contexts/SessionContext.js +2 -1
- package/dist/src/ui/contexts/SessionContext.js.map +1 -1
- package/dist/src/ui/contexts/SessionContext.test.js +3 -0
- package/dist/src/ui/contexts/SessionContext.test.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.d.ts +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.js +25 -14
- package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.test.js +42 -33
- package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +1 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.js +2 -1
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
- package/dist/src/ui/hooks/useIncludeDirsTrust.test.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
- package/dist/src/ui/hooks/useSelectionList.js.map +1 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js +14 -4
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/utils/clipboardUtils.d.ts +20 -0
- package/dist/src/ui/utils/clipboardUtils.js +82 -4
- package/dist/src/ui/utils/clipboardUtils.js.map +1 -1
- package/dist/src/ui/utils/clipboardUtils.test.js +123 -1
- package/dist/src/ui/utils/clipboardUtils.test.js.map +1 -1
- package/dist/src/ui/utils/commandUtils.test.js.map +1 -1
- package/dist/src/ui/utils/computeStats.js +2 -0
- package/dist/src/ui/utils/computeStats.js.map +1 -1
- package/dist/src/ui/utils/computeStats.test.js +9 -0
- package/dist/src/ui/utils/computeStats.test.js.map +1 -1
- package/dist/src/utils/deepMerge.js +7 -2
- package/dist/src/utils/deepMerge.js.map +1 -1
- package/dist/src/utils/deepMerge.test.js +21 -0
- package/dist/src/utils/deepMerge.test.js.map +1 -1
- package/dist/src/utils/envVarResolver.js.map +1 -1
- package/dist/src/utils/envVarResolver.test.js.map +1 -1
- package/dist/src/utils/errors.test.js +9 -1
- package/dist/src/utils/errors.test.js.map +1 -1
- package/dist/src/validateNonInterActiveAuth.js.map +1 -1
- package/dist/src/zed-integration/acp.test.js +8 -16
- package/dist/src/zed-integration/acp.test.js.map +1 -1
- package/dist/src/zed-integration/connection.js.map +1 -1
- package/dist/src/zed-integration/fileSystemService.d.ts +0 -1
- package/dist/src/zed-integration/fileSystemService.js +0 -3
- package/dist/src/zed-integration/fileSystemService.js.map +1 -1
- package/dist/src/zed-integration/fileSystemService.test.js +0 -8
- package/dist/src/zed-integration/fileSystemService.test.js.map +1 -1
- package/dist/src/zed-integration/zedIntegration.js +3 -2
- package/dist/src/zed-integration/zedIntegration.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -3
- package/dist/google-gemini-cli-0.21.1.tgz +0 -0
- package/dist/src/utils/version.js +0 -15
- package/dist/src/utils/version.js.map +0 -1
- package/dist/src/utils/version.test.js +0 -39
- package/dist/src/utils/version.test.js.map +0 -1
- /package/dist/src/{utils/version.test.d.ts → config/settings-validation.test.d.ts} +0 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { getSettingsSchema, SETTINGS_SCHEMA_DEFINITIONS, } from './settingsSchema.js';
|
|
8
|
+
// Helper to build Zod schema from the JSON-schema-like definitions
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
+
function buildZodSchemaFromJsonSchema(def) {
|
|
11
|
+
if (def.anyOf) {
|
|
12
|
+
return z.union(
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
def.anyOf.map((d) => buildZodSchemaFromJsonSchema(d)));
|
|
15
|
+
}
|
|
16
|
+
if (def.type === 'string') {
|
|
17
|
+
if (def.enum)
|
|
18
|
+
return z.enum(def.enum);
|
|
19
|
+
return z.string();
|
|
20
|
+
}
|
|
21
|
+
if (def.type === 'number')
|
|
22
|
+
return z.number();
|
|
23
|
+
if (def.type === 'boolean')
|
|
24
|
+
return z.boolean();
|
|
25
|
+
if (def.type === 'array') {
|
|
26
|
+
if (def.items) {
|
|
27
|
+
return z.array(buildZodSchemaFromJsonSchema(def.items));
|
|
28
|
+
}
|
|
29
|
+
return z.array(z.unknown());
|
|
30
|
+
}
|
|
31
|
+
if (def.type === 'object') {
|
|
32
|
+
let schema;
|
|
33
|
+
if (def.properties) {
|
|
34
|
+
const shape = {};
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
for (const [key, propDef] of Object.entries(def.properties)) {
|
|
37
|
+
let propSchema = buildZodSchemaFromJsonSchema(propDef);
|
|
38
|
+
if (def.required &&
|
|
39
|
+
Array.isArray(def.required) &&
|
|
40
|
+
def.required.includes(key)) {
|
|
41
|
+
// keep it required
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
propSchema = propSchema.optional();
|
|
45
|
+
}
|
|
46
|
+
shape[key] = propSchema;
|
|
47
|
+
}
|
|
48
|
+
schema = z.object(shape).passthrough();
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
schema = z.object({}).passthrough();
|
|
52
|
+
}
|
|
53
|
+
if (def.additionalProperties === false) {
|
|
54
|
+
schema = schema.strict();
|
|
55
|
+
}
|
|
56
|
+
else if (typeof def.additionalProperties === 'object') {
|
|
57
|
+
schema = schema.catchall(buildZodSchemaFromJsonSchema(def.additionalProperties));
|
|
58
|
+
}
|
|
59
|
+
return schema;
|
|
60
|
+
}
|
|
61
|
+
return z.unknown();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Builds a Zod enum schema from options array
|
|
65
|
+
*/
|
|
66
|
+
function buildEnumSchema(options) {
|
|
67
|
+
if (!options || options.length === 0) {
|
|
68
|
+
throw new Error(`Enum type must have options defined. Check your settings schema definition.`);
|
|
69
|
+
}
|
|
70
|
+
const values = options.map((opt) => opt.value);
|
|
71
|
+
if (values.every((v) => typeof v === 'string')) {
|
|
72
|
+
return z.enum(values);
|
|
73
|
+
}
|
|
74
|
+
else if (values.every((v) => typeof v === 'number')) {
|
|
75
|
+
return z.union(values.map((v) => z.literal(v)));
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
return z.union(values.map((v) => z.literal(v)));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Builds a Zod object shape from properties record
|
|
83
|
+
*/
|
|
84
|
+
function buildObjectShapeFromProperties(properties) {
|
|
85
|
+
const shape = {};
|
|
86
|
+
for (const [key, childDef] of Object.entries(properties)) {
|
|
87
|
+
shape[key] = buildZodSchemaFromDefinition(childDef);
|
|
88
|
+
}
|
|
89
|
+
return shape;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Builds a Zod schema for primitive types (string, number, boolean)
|
|
93
|
+
*/
|
|
94
|
+
function buildPrimitiveSchema(type) {
|
|
95
|
+
switch (type) {
|
|
96
|
+
case 'string':
|
|
97
|
+
return z.string();
|
|
98
|
+
case 'number':
|
|
99
|
+
return z.number();
|
|
100
|
+
case 'boolean':
|
|
101
|
+
return z.boolean();
|
|
102
|
+
default:
|
|
103
|
+
return z.unknown();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const REF_SCHEMAS = {};
|
|
107
|
+
// Initialize REF_SCHEMAS
|
|
108
|
+
for (const [name, def] of Object.entries(SETTINGS_SCHEMA_DEFINITIONS)) {
|
|
109
|
+
REF_SCHEMAS[name] = buildZodSchemaFromJsonSchema(def);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Recursively builds a Zod schema from a SettingDefinition
|
|
113
|
+
*/
|
|
114
|
+
function buildZodSchemaFromDefinition(definition) {
|
|
115
|
+
let baseSchema;
|
|
116
|
+
// Special handling for TelemetrySettings which can be boolean or object
|
|
117
|
+
if (definition.ref === 'TelemetrySettings') {
|
|
118
|
+
const objectSchema = REF_SCHEMAS['TelemetrySettings'];
|
|
119
|
+
if (objectSchema) {
|
|
120
|
+
return z.union([z.boolean(), objectSchema]).optional();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Handle refs using registry
|
|
124
|
+
if (definition.ref && definition.ref in REF_SCHEMAS) {
|
|
125
|
+
return REF_SCHEMAS[definition.ref].optional();
|
|
126
|
+
}
|
|
127
|
+
switch (definition.type) {
|
|
128
|
+
case 'string':
|
|
129
|
+
case 'number':
|
|
130
|
+
case 'boolean':
|
|
131
|
+
baseSchema = buildPrimitiveSchema(definition.type);
|
|
132
|
+
break;
|
|
133
|
+
case 'enum': {
|
|
134
|
+
baseSchema = buildEnumSchema(definition.options);
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
case 'array':
|
|
138
|
+
if (definition.items) {
|
|
139
|
+
const itemSchema = buildZodSchemaFromCollection(definition.items);
|
|
140
|
+
baseSchema = z.array(itemSchema);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
baseSchema = z.array(z.unknown());
|
|
144
|
+
}
|
|
145
|
+
break;
|
|
146
|
+
case 'object':
|
|
147
|
+
if (definition.properties) {
|
|
148
|
+
const shape = buildObjectShapeFromProperties(definition.properties);
|
|
149
|
+
baseSchema = z.object(shape).passthrough();
|
|
150
|
+
if (definition.additionalProperties) {
|
|
151
|
+
const additionalSchema = buildZodSchemaFromCollection(definition.additionalProperties);
|
|
152
|
+
baseSchema = z.object(shape).catchall(additionalSchema);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else if (definition.additionalProperties) {
|
|
156
|
+
const valueSchema = buildZodSchemaFromCollection(definition.additionalProperties);
|
|
157
|
+
baseSchema = z.record(z.string(), valueSchema);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
baseSchema = z.record(z.string(), z.unknown());
|
|
161
|
+
}
|
|
162
|
+
break;
|
|
163
|
+
default:
|
|
164
|
+
baseSchema = z.unknown();
|
|
165
|
+
}
|
|
166
|
+
// Make all fields optional since settings are partial
|
|
167
|
+
return baseSchema.optional();
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Builds a Zod schema from a SettingCollectionDefinition
|
|
171
|
+
*/
|
|
172
|
+
function buildZodSchemaFromCollection(collection) {
|
|
173
|
+
if (collection.ref && collection.ref in REF_SCHEMAS) {
|
|
174
|
+
return REF_SCHEMAS[collection.ref];
|
|
175
|
+
}
|
|
176
|
+
switch (collection.type) {
|
|
177
|
+
case 'string':
|
|
178
|
+
case 'number':
|
|
179
|
+
case 'boolean':
|
|
180
|
+
return buildPrimitiveSchema(collection.type);
|
|
181
|
+
case 'enum': {
|
|
182
|
+
return buildEnumSchema(collection.options);
|
|
183
|
+
}
|
|
184
|
+
case 'array':
|
|
185
|
+
if (collection.properties) {
|
|
186
|
+
const shape = buildObjectShapeFromProperties(collection.properties);
|
|
187
|
+
return z.array(z.object(shape));
|
|
188
|
+
}
|
|
189
|
+
return z.array(z.unknown());
|
|
190
|
+
case 'object':
|
|
191
|
+
if (collection.properties) {
|
|
192
|
+
const shape = buildObjectShapeFromProperties(collection.properties);
|
|
193
|
+
return z.object(shape).passthrough();
|
|
194
|
+
}
|
|
195
|
+
return z.record(z.string(), z.unknown());
|
|
196
|
+
default:
|
|
197
|
+
return z.unknown();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Builds the complete Zod schema for Settings from SETTINGS_SCHEMA
|
|
202
|
+
*/
|
|
203
|
+
function buildSettingsZodSchema() {
|
|
204
|
+
const schema = getSettingsSchema();
|
|
205
|
+
const shape = {};
|
|
206
|
+
for (const [key, definition] of Object.entries(schema)) {
|
|
207
|
+
shape[key] = buildZodSchemaFromDefinition(definition);
|
|
208
|
+
}
|
|
209
|
+
return z.object(shape).passthrough();
|
|
210
|
+
}
|
|
211
|
+
export const settingsZodSchema = buildSettingsZodSchema();
|
|
212
|
+
/**
|
|
213
|
+
* Validates settings data against the Zod schema
|
|
214
|
+
*/
|
|
215
|
+
export function validateSettings(data) {
|
|
216
|
+
const result = settingsZodSchema.safeParse(data);
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Format a Zod error into a helpful error message
|
|
221
|
+
*/
|
|
222
|
+
export function formatValidationError(error, filePath) {
|
|
223
|
+
const lines = [];
|
|
224
|
+
lines.push(`Invalid configuration in ${filePath}:`);
|
|
225
|
+
lines.push('');
|
|
226
|
+
const MAX_ERRORS_TO_DISPLAY = 5;
|
|
227
|
+
const displayedIssues = error.issues.slice(0, MAX_ERRORS_TO_DISPLAY);
|
|
228
|
+
for (const issue of displayedIssues) {
|
|
229
|
+
const path = issue.path.reduce((acc, curr) => typeof curr === 'number'
|
|
230
|
+
? `${acc}[${curr}]`
|
|
231
|
+
: `${acc ? acc + '.' : ''}${curr}`, '');
|
|
232
|
+
lines.push(`Error in: ${path || '(root)'}`);
|
|
233
|
+
lines.push(` ${issue.message}`);
|
|
234
|
+
if (issue.code === 'invalid_type') {
|
|
235
|
+
const expected = issue.expected;
|
|
236
|
+
const received = issue.received;
|
|
237
|
+
lines.push(`Expected: ${expected}, but received: ${received}`);
|
|
238
|
+
}
|
|
239
|
+
lines.push('');
|
|
240
|
+
}
|
|
241
|
+
if (error.issues.length > MAX_ERRORS_TO_DISPLAY) {
|
|
242
|
+
lines.push(`...and ${error.issues.length - MAX_ERRORS_TO_DISPLAY} more errors.`);
|
|
243
|
+
lines.push('');
|
|
244
|
+
}
|
|
245
|
+
lines.push('Please fix the configuration and try again.');
|
|
246
|
+
lines.push('See: https://github.com/google-gemini/gemini-cli/blob/main/docs/get-started/configuration.md');
|
|
247
|
+
return lines.join('\n');
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=settings-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-validation.js","sourceRoot":"","sources":["../../../src/config/settings-validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/// <reference types="vitest/globals" />
|
|
7
|
+
import { describe, it, expect } from 'vitest';
|
|
8
|
+
import { validateSettings, formatValidationError, settingsZodSchema, } from './settings-validation.js';
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
describe('settings-validation', () => {
|
|
11
|
+
describe('validateSettings', () => {
|
|
12
|
+
it('should accept valid settings with correct model.name as string', () => {
|
|
13
|
+
const validSettings = {
|
|
14
|
+
model: {
|
|
15
|
+
name: 'gemini-2.0-flash-exp',
|
|
16
|
+
maxSessionTurns: 10,
|
|
17
|
+
},
|
|
18
|
+
ui: {
|
|
19
|
+
theme: 'dark',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
const result = validateSettings(validSettings);
|
|
23
|
+
expect(result.success).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
it('should reject model.name as object instead of string', () => {
|
|
26
|
+
const invalidSettings = {
|
|
27
|
+
model: {
|
|
28
|
+
name: {
|
|
29
|
+
skipNextSpeakerCheck: true,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
const result = validateSettings(invalidSettings);
|
|
34
|
+
expect(result.success).toBe(false);
|
|
35
|
+
expect(result.error).toBeDefined();
|
|
36
|
+
if (result.error) {
|
|
37
|
+
const issues = result.error.issues;
|
|
38
|
+
expect(issues.length).toBeGreaterThan(0);
|
|
39
|
+
expect(issues[0]?.path).toEqual(['model', 'name']);
|
|
40
|
+
expect(issues[0]?.code).toBe('invalid_type');
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
it('should accept valid model.summarizeToolOutput structure', () => {
|
|
44
|
+
const validSettings = {
|
|
45
|
+
model: {
|
|
46
|
+
summarizeToolOutput: {
|
|
47
|
+
run_shell_command: {
|
|
48
|
+
tokenBudget: 500,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
const result = validateSettings(validSettings);
|
|
54
|
+
expect(result.success).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
it('should reject invalid model.summarizeToolOutput structure', () => {
|
|
57
|
+
const invalidSettings = {
|
|
58
|
+
model: {
|
|
59
|
+
summarizeToolOutput: {
|
|
60
|
+
run_shell_command: {
|
|
61
|
+
tokenBudget: 500,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
// First test with valid structure
|
|
67
|
+
let result = validateSettings(invalidSettings);
|
|
68
|
+
expect(result.success).toBe(true);
|
|
69
|
+
// Now test with wrong type (string instead of object)
|
|
70
|
+
const actuallyInvalidSettings = {
|
|
71
|
+
model: {
|
|
72
|
+
summarizeToolOutput: 'invalid',
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
result = validateSettings(actuallyInvalidSettings);
|
|
76
|
+
expect(result.success).toBe(false);
|
|
77
|
+
if (result.error) {
|
|
78
|
+
expect(result.error.issues.length).toBeGreaterThan(0);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
it('should accept empty settings object', () => {
|
|
82
|
+
const emptySettings = {};
|
|
83
|
+
const result = validateSettings(emptySettings);
|
|
84
|
+
expect(result.success).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
it('should accept unknown top-level keys (for migration compatibility)', () => {
|
|
87
|
+
const settingsWithUnknownKey = {
|
|
88
|
+
unknownKey: 'some value',
|
|
89
|
+
};
|
|
90
|
+
const result = validateSettings(settingsWithUnknownKey);
|
|
91
|
+
expect(result.success).toBe(true);
|
|
92
|
+
// Unknown keys are allowed via .passthrough() for migration scenarios
|
|
93
|
+
});
|
|
94
|
+
it('should accept nested valid settings', () => {
|
|
95
|
+
const validSettings = {
|
|
96
|
+
ui: {
|
|
97
|
+
theme: 'dark',
|
|
98
|
+
hideWindowTitle: true,
|
|
99
|
+
footer: {
|
|
100
|
+
hideCWD: false,
|
|
101
|
+
hideModelInfo: true,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
tools: {
|
|
105
|
+
sandbox: 'inherit',
|
|
106
|
+
autoAccept: false,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
const result = validateSettings(validSettings);
|
|
110
|
+
expect(result.success).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
it('should validate array types correctly', () => {
|
|
113
|
+
const validSettings = {
|
|
114
|
+
tools: {
|
|
115
|
+
allowed: ['git', 'npm'],
|
|
116
|
+
exclude: ['dangerous-tool'],
|
|
117
|
+
},
|
|
118
|
+
context: {
|
|
119
|
+
includeDirectories: ['/path/1', '/path/2'],
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
const result = validateSettings(validSettings);
|
|
123
|
+
expect(result.success).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
it('should reject invalid types in arrays', () => {
|
|
126
|
+
const invalidSettings = {
|
|
127
|
+
tools: {
|
|
128
|
+
allowed: ['git', 123],
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
const result = validateSettings(invalidSettings);
|
|
132
|
+
expect(result.success).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
it('should validate boolean fields correctly', () => {
|
|
135
|
+
const validSettings = {
|
|
136
|
+
general: {
|
|
137
|
+
vimMode: true,
|
|
138
|
+
disableAutoUpdate: false,
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
const result = validateSettings(validSettings);
|
|
142
|
+
expect(result.success).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
it('should reject non-boolean values for boolean fields', () => {
|
|
145
|
+
const invalidSettings = {
|
|
146
|
+
general: {
|
|
147
|
+
vimMode: 'yes',
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
const result = validateSettings(invalidSettings);
|
|
151
|
+
expect(result.success).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
it('should validate number fields correctly', () => {
|
|
154
|
+
const validSettings = {
|
|
155
|
+
model: {
|
|
156
|
+
maxSessionTurns: 50,
|
|
157
|
+
compressionThreshold: 0.2,
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
const result = validateSettings(validSettings);
|
|
161
|
+
expect(result.success).toBe(true);
|
|
162
|
+
});
|
|
163
|
+
it('should validate complex nested mcpServers configuration', () => {
|
|
164
|
+
const invalidSettings = {
|
|
165
|
+
mcpServers: {
|
|
166
|
+
'my-server': {
|
|
167
|
+
command: 123, // Should be string
|
|
168
|
+
args: ['arg1'],
|
|
169
|
+
env: {
|
|
170
|
+
VAR: 'value',
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
const result = validateSettings(invalidSettings);
|
|
176
|
+
expect(result.success).toBe(false);
|
|
177
|
+
if (result.error) {
|
|
178
|
+
expect(result.error.issues.length).toBeGreaterThan(0);
|
|
179
|
+
// Path should be mcpServers.my-server.command
|
|
180
|
+
const issue = result.error.issues.find((i) => i.path.includes('command'));
|
|
181
|
+
expect(issue).toBeDefined();
|
|
182
|
+
expect(issue?.code).toBe('invalid_type');
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
it('should validate complex nested customThemes configuration', () => {
|
|
186
|
+
const invalidSettings = {
|
|
187
|
+
ui: {
|
|
188
|
+
customThemes: {
|
|
189
|
+
'my-theme': {
|
|
190
|
+
type: 'custom',
|
|
191
|
+
// Missing 'name' property which is required
|
|
192
|
+
text: {
|
|
193
|
+
primary: '#ffffff',
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
const result = validateSettings(invalidSettings);
|
|
200
|
+
expect(result.success).toBe(false);
|
|
201
|
+
if (result.error) {
|
|
202
|
+
expect(result.error.issues.length).toBeGreaterThan(0);
|
|
203
|
+
// Should complain about missing 'name'
|
|
204
|
+
const issue = result.error.issues.find((i) => i.code === 'invalid_type' && i.message.includes('Required'));
|
|
205
|
+
expect(issue).toBeDefined();
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
describe('formatValidationError', () => {
|
|
210
|
+
it('should format error with file path and helpful message for model.name', () => {
|
|
211
|
+
const invalidSettings = {
|
|
212
|
+
model: {
|
|
213
|
+
name: {
|
|
214
|
+
skipNextSpeakerCheck: true,
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
const result = validateSettings(invalidSettings);
|
|
219
|
+
expect(result.success).toBe(false);
|
|
220
|
+
if (result.error) {
|
|
221
|
+
const formatted = formatValidationError(result.error, '/path/to/settings.json');
|
|
222
|
+
expect(formatted).toContain('/path/to/settings.json');
|
|
223
|
+
expect(formatted).toContain('model.name');
|
|
224
|
+
expect(formatted).toContain('Expected: string, but received: object');
|
|
225
|
+
expect(formatted).toContain('Please fix the configuration and try again.');
|
|
226
|
+
expect(formatted).toContain('https://github.com/google-gemini/gemini-cli');
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
it('should format error for model.summarizeToolOutput', () => {
|
|
230
|
+
const invalidSettings = {
|
|
231
|
+
model: {
|
|
232
|
+
summarizeToolOutput: 'wrong type',
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
const result = validateSettings(invalidSettings);
|
|
236
|
+
expect(result.success).toBe(false);
|
|
237
|
+
if (result.error) {
|
|
238
|
+
const formatted = formatValidationError(result.error, '~/.gemini/settings.json');
|
|
239
|
+
expect(formatted).toContain('~/.gemini/settings.json');
|
|
240
|
+
expect(formatted).toContain('model.summarizeToolOutput');
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
it('should include link to documentation', () => {
|
|
244
|
+
const invalidSettings = {
|
|
245
|
+
model: {
|
|
246
|
+
name: { invalid: 'object' }, // model.name should be a string
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
const result = validateSettings(invalidSettings);
|
|
250
|
+
expect(result.success).toBe(false);
|
|
251
|
+
if (result.error) {
|
|
252
|
+
const formatted = formatValidationError(result.error, 'test.json');
|
|
253
|
+
expect(formatted).toContain('https://github.com/google-gemini/gemini-cli');
|
|
254
|
+
expect(formatted).toContain('configuration.md');
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
it('should list all validation errors', () => {
|
|
258
|
+
const invalidSettings = {
|
|
259
|
+
model: {
|
|
260
|
+
name: { invalid: 'object' },
|
|
261
|
+
maxSessionTurns: 'not a number',
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
const result = validateSettings(invalidSettings);
|
|
265
|
+
expect(result.success).toBe(false);
|
|
266
|
+
if (result.error) {
|
|
267
|
+
const formatted = formatValidationError(result.error, 'test.json');
|
|
268
|
+
// Should have multiple errors listed
|
|
269
|
+
expect(formatted.match(/Error in:/g)?.length).toBeGreaterThan(1);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
it('should format array paths correctly (e.g. tools.allowed[0])', () => {
|
|
273
|
+
const invalidSettings = {
|
|
274
|
+
tools: {
|
|
275
|
+
allowed: ['git', 123], // 123 is invalid, expected string
|
|
276
|
+
},
|
|
277
|
+
};
|
|
278
|
+
const result = validateSettings(invalidSettings);
|
|
279
|
+
expect(result.success).toBe(false);
|
|
280
|
+
if (result.error) {
|
|
281
|
+
const formatted = formatValidationError(result.error, 'test.json');
|
|
282
|
+
expect(formatted).toContain('tools.allowed[1]');
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
it('should limit the number of displayed errors', () => {
|
|
286
|
+
const invalidSettings = {
|
|
287
|
+
tools: {
|
|
288
|
+
// Create 6 invalid items to trigger the limit
|
|
289
|
+
allowed: [1, 2, 3, 4, 5, 6],
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
const result = validateSettings(invalidSettings);
|
|
293
|
+
expect(result.success).toBe(false);
|
|
294
|
+
if (result.error) {
|
|
295
|
+
const formatted = formatValidationError(result.error, 'test.json');
|
|
296
|
+
// Should see the first 5
|
|
297
|
+
expect(formatted).toContain('tools.allowed[0]');
|
|
298
|
+
expect(formatted).toContain('tools.allowed[4]');
|
|
299
|
+
// Should NOT see the 6th
|
|
300
|
+
expect(formatted).not.toContain('tools.allowed[5]');
|
|
301
|
+
// Should see the summary
|
|
302
|
+
expect(formatted).toContain('...and 1 more errors.');
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
describe('settingsZodSchema', () => {
|
|
307
|
+
it('should be a valid Zod object schema', () => {
|
|
308
|
+
expect(settingsZodSchema).toBeInstanceOf(z.ZodObject);
|
|
309
|
+
});
|
|
310
|
+
it('should have optional fields', () => {
|
|
311
|
+
// All top-level fields should be optional
|
|
312
|
+
const shape = settingsZodSchema.shape;
|
|
313
|
+
expect(shape['model']).toBeDefined();
|
|
314
|
+
expect(shape['ui']).toBeDefined();
|
|
315
|
+
expect(shape['tools']).toBeDefined();
|
|
316
|
+
// Test that empty object is valid (all fields optional)
|
|
317
|
+
const result = settingsZodSchema.safeParse({});
|
|
318
|
+
expect(result.success).toBe(true);
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
//# sourceMappingURL=settings-validation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-validation.test.js","sourceRoot":"","sources":["../../../src/config/settings-validation.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,7 @@ import { getSettingsSchema, } from './settingsSchema.js';
|
|
|
17
17
|
import { resolveEnvVarsInObject } from '../utils/envVarResolver.js';
|
|
18
18
|
import { customDeepMerge } from '../utils/deepMerge.js';
|
|
19
19
|
import { updateSettingsFilePreservingFormat } from '../utils/commentJson.js';
|
|
20
|
+
import { validateSettings, formatValidationError, } from './settings-validation.js';
|
|
20
21
|
import { SettingPaths } from './settingPaths.js';
|
|
21
22
|
function getMergeStrategyForPath(path) {
|
|
22
23
|
let current = undefined;
|
|
@@ -184,7 +185,7 @@ export function needsMigration(settings) {
|
|
|
184
185
|
if (v1Key === v2Path || !(v1Key in settings)) {
|
|
185
186
|
return false;
|
|
186
187
|
}
|
|
187
|
-
// If a key exists that is
|
|
188
|
+
// If a key exists that is a V1 key and a V2 container (like 'model'),
|
|
188
189
|
// we need to check the type. If it's an object, it's a V2 container and not
|
|
189
190
|
// a V1 key that needs migration.
|
|
190
191
|
if (KNOWN_V2_CONTAINERS.has(v1Key) &&
|
|
@@ -204,6 +205,16 @@ function migrateSettingsToV2(flatSettings) {
|
|
|
204
205
|
const flatKeys = new Set(Object.keys(flatSettings));
|
|
205
206
|
for (const [oldKey, newPath] of Object.entries(MIGRATION_MAP)) {
|
|
206
207
|
if (flatKeys.has(oldKey)) {
|
|
208
|
+
// If the key exists and is a V2 container (like 'model'), and the value is an object,
|
|
209
|
+
// it is likely already migrated or partially migrated. We should not move it
|
|
210
|
+
// to the mapped V2 path (e.g. 'model' -> 'model.name').
|
|
211
|
+
// Instead, let it fall through to the "Carry over" section to be merged.
|
|
212
|
+
if (KNOWN_V2_CONTAINERS.has(oldKey) &&
|
|
213
|
+
typeof flatSettings[oldKey] === 'object' &&
|
|
214
|
+
flatSettings[oldKey] !== null &&
|
|
215
|
+
!Array.isArray(flatSettings[oldKey])) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
207
218
|
setNestedProperty(v2Settings, newPath, flatSettings[oldKey]);
|
|
208
219
|
flatKeys.delete(oldKey);
|
|
209
220
|
}
|
|
@@ -224,7 +235,7 @@ function migrateSettingsToV2(flatSettings) {
|
|
|
224
235
|
newValue !== null &&
|
|
225
236
|
!Array.isArray(newValue)) {
|
|
226
237
|
const pathAwareGetStrategy = (path) => getMergeStrategyForPath([remainingKey, ...path]);
|
|
227
|
-
v2Settings[remainingKey] = customDeepMerge(pathAwareGetStrategy, {},
|
|
238
|
+
v2Settings[remainingKey] = customDeepMerge(pathAwareGetStrategy, {}, existingValue, newValue);
|
|
228
239
|
}
|
|
229
240
|
else {
|
|
230
241
|
v2Settings[remainingKey] = newValue;
|
|
@@ -481,10 +492,20 @@ export function loadSettings(workspaceDir = process.cwd()) {
|
|
|
481
492
|
settingsObject = migratedSettings;
|
|
482
493
|
}
|
|
483
494
|
}
|
|
495
|
+
// Validate settings structure with Zod after migration
|
|
496
|
+
const validationResult = validateSettings(settingsObject);
|
|
497
|
+
if (!validationResult.success && validationResult.error) {
|
|
498
|
+
const errorMessage = formatValidationError(validationResult.error, filePath);
|
|
499
|
+
throw new FatalConfigError(errorMessage);
|
|
500
|
+
}
|
|
484
501
|
return { settings: settingsObject, rawJson: content };
|
|
485
502
|
}
|
|
486
503
|
}
|
|
487
504
|
catch (error) {
|
|
505
|
+
// Preserve FatalConfigError with formatted validation messages
|
|
506
|
+
if (error instanceof FatalConfigError) {
|
|
507
|
+
throw error;
|
|
508
|
+
}
|
|
488
509
|
settingsErrors.push({
|
|
489
510
|
message: getErrorMessage(error),
|
|
490
511
|
path: filePath,
|