mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-02-01 22:48:03 +00:00
chore: autogenerate settings documentation (#12451)
This commit is contained in:
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -90,6 +90,12 @@ jobs:
|
||||
- name: 'Run Prettier'
|
||||
run: 'node scripts/lint.js --prettier'
|
||||
|
||||
- name: 'Build docs prerequisites'
|
||||
run: 'npm run predocs:settings'
|
||||
|
||||
- name: 'Verify settings docs'
|
||||
run: 'npm run docs:settings -- --check'
|
||||
|
||||
- name: 'Run sensitive keyword linter'
|
||||
run: 'node scripts/lint.js --sensitive-keywords'
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@ overridden by higher numbers):
|
||||
Gemini CLI uses JSON settings files for persistent configuration. There are four
|
||||
locations for these files:
|
||||
|
||||
> **Tip:** JSON-aware editors can use autocomplete and validation by pointing to
|
||||
> the generated schema at `schemas/settings.schema.json` in this repository.
|
||||
> When working outside the repo, reference the hosted schema at
|
||||
> `https://raw.githubusercontent.com/google-gemini/gemini-cli/main/schemas/settings.schema.json`.
|
||||
|
||||
- **System defaults file:**
|
||||
- **Location:** `/etc/gemini-cli/system-defaults.json` (Linux),
|
||||
`C:\ProgramData\gemini-cli\system-defaults.json` (Windows) or
|
||||
@@ -89,6 +94,8 @@ contain other project-specific files related to Gemini CLI's operation, such as:
|
||||
Settings are organized into categories. All settings should be placed within
|
||||
their corresponding top-level category object in your `settings.json` file.
|
||||
|
||||
<!-- SETTINGS-AUTOGEN:START -->
|
||||
|
||||
#### `general`
|
||||
|
||||
- **`general.preferredEditor`** (string):
|
||||
@@ -96,11 +103,11 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
- **Default:** `undefined`
|
||||
|
||||
- **`general.vimMode`** (boolean):
|
||||
- **Description:** Enable Vim keybindings.
|
||||
- **Description:** Enable Vim keybindings
|
||||
- **Default:** `false`
|
||||
|
||||
- **`general.disableAutoUpdate`** (boolean):
|
||||
- **Description:** Disable automatic updates.
|
||||
- **Description:** Disable automatic updates
|
||||
- **Default:** `false`
|
||||
|
||||
- **`general.disableUpdateNag`** (boolean):
|
||||
@@ -108,34 +115,55 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
- **Default:** `false`
|
||||
|
||||
- **`general.checkpointing.enabled`** (boolean):
|
||||
- **Description:** Enable session checkpointing for recovery.
|
||||
- **Description:** Enable session checkpointing for recovery
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`general.enablePromptCompletion`** (boolean):
|
||||
- **Description:** Enable AI-powered prompt completion suggestions while
|
||||
typing.
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`general.retryFetchErrors`** (boolean):
|
||||
- **Description:** Retry on "exception TypeError: fetch failed sending
|
||||
request" errors.
|
||||
- **Default:** `false`
|
||||
|
||||
- **`general.debugKeystrokeLogging`** (boolean):
|
||||
- **Description:** Enable debug logging of keystrokes to the console.
|
||||
- **Default:** `false`
|
||||
|
||||
- **`general.sessionRetention.enabled`** (boolean):
|
||||
- **Description:** Enable automatic session cleanup.
|
||||
- **Description:** Enable automatic session cleanup
|
||||
- **Default:** `false`
|
||||
|
||||
- **`general.sessionRetention.maxAge`** (string):
|
||||
- **Description:** Maximum age of sessions to keep (e.g., "30d", "7d", "24h",
|
||||
"1w")
|
||||
- **Default:** `undefined`
|
||||
|
||||
- **`general.sessionRetention.maxCount`** (number):
|
||||
- **Description:** Alternative: Maximum number of sessions to keep (most
|
||||
recent)
|
||||
- **Default:** `undefined`
|
||||
|
||||
- **`general.sessionRetention.minRetention`** (string):
|
||||
- **Description:** Minimum retention period (safety limit, defaults to "1d")
|
||||
- **Default:** `"1d"`
|
||||
|
||||
#### `output`
|
||||
|
||||
- **`output.format`** (string):
|
||||
- **`output.format`** (enum):
|
||||
- **Description:** The format of the CLI output.
|
||||
- **Default:** `"text"`
|
||||
- **Values:** `"text"`, `"json"`, `"stream-json"`
|
||||
- **Values:** `"text"`, `"json"`
|
||||
|
||||
#### `ui`
|
||||
|
||||
- **`ui.theme`** (string):
|
||||
- **Description:** The color theme for the UI. See [Themes](../cli/themes.md)
|
||||
for available options.
|
||||
- **Description:** The color theme for the UI. See the CLI themes guide for
|
||||
available options.
|
||||
- **Default:** `undefined`
|
||||
|
||||
- **`ui.customThemes`** (object):
|
||||
@@ -143,20 +171,21 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
- **Default:** `{}`
|
||||
|
||||
- **`ui.hideWindowTitle`** (boolean):
|
||||
- **Description:** Hide the window title bar.
|
||||
- **Description:** Hide the window title bar
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`ui.showStatusInTitle`** (boolean):
|
||||
- **Description:** Show Gemini CLI status and thoughts in the terminal window
|
||||
title.
|
||||
title
|
||||
- **Default:** `false`
|
||||
|
||||
- **`ui.hideTips`** (boolean):
|
||||
- **Description:** Hide helpful tips in the UI.
|
||||
- **Description:** Hide helpful tips in the UI
|
||||
- **Default:** `false`
|
||||
|
||||
- **`ui.hideBanner`** (boolean):
|
||||
- **Description:** Hide the application banner.
|
||||
- **Description:** Hide the application banner
|
||||
- **Default:** `false`
|
||||
|
||||
- **`ui.hideContextSummary`** (boolean):
|
||||
@@ -164,10 +193,6 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
input.
|
||||
- **Default:** `false`
|
||||
|
||||
- **`ui.hideFooter`** (boolean):
|
||||
- **Description:** Hide the footer from the UI.
|
||||
- **Default:** `false`
|
||||
|
||||
- **`ui.footer.hideCWD`** (boolean):
|
||||
- **Description:** Hide the current working directory path in the footer.
|
||||
- **Default:** `false`
|
||||
@@ -180,8 +205,16 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
- **Description:** Hide the model name and context usage in the footer.
|
||||
- **Default:** `false`
|
||||
|
||||
- **`ui.footer.hideContextPercentage`** (boolean):
|
||||
- **Description:** Hides the context window remaining percentage.
|
||||
- **Default:** `true`
|
||||
|
||||
- **`ui.hideFooter`** (boolean):
|
||||
- **Description:** Hide the footer from the UI
|
||||
- **Default:** `false`
|
||||
|
||||
- **`ui.showMemoryUsage`** (boolean):
|
||||
- **Description:** Display memory usage information in the UI.
|
||||
- **Description:** Display memory usage information in the UI
|
||||
- **Default:** `false`
|
||||
|
||||
- **`ui.showLineNumbers`** (boolean):
|
||||
@@ -190,32 +223,34 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
|
||||
- **`ui.showCitations`** (boolean):
|
||||
- **Description:** Show citations for generated text in the chat.
|
||||
- **Default:** `true`
|
||||
- **Default:** `false`
|
||||
|
||||
- **`ui.useFullWidth`** (boolean):
|
||||
- **Description:** Use the entire width of the terminal for output.
|
||||
- **Default:** `false`
|
||||
|
||||
- **`ui.customWittyPhrases`** (array):
|
||||
- **Description:** Custom witty phrases to display during loading. When
|
||||
provided, the CLI cycles through these instead of the defaults.
|
||||
- **Default:** `[]`
|
||||
|
||||
- **`ui.accessibility.disableLoadingPhrases`** (boolean):
|
||||
- **Description:** Disable loading phrases for accessibility.
|
||||
- **Description:** Disable loading phrases for accessibility
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`ui.accessibility.screenReader`** (boolean):
|
||||
- **Description:** Show plaintext interactive view that is more screen reader
|
||||
friendly.
|
||||
- **Description:** Render output in plain-text to be more screen reader
|
||||
accessible
|
||||
- **Default:** `false`
|
||||
|
||||
- **`ui.customWittyPhrases`** (array of strings):
|
||||
- **Description:** A list of custom phrases to display during loading states.
|
||||
When provided, the CLI will cycle through these phrases instead of the
|
||||
default ones.
|
||||
- **Default:** `[]`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
#### `ide`
|
||||
|
||||
- **`ide.enabled`** (boolean):
|
||||
- **Description:** Enable IDE integration mode.
|
||||
- **Description:** Enable IDE integration mode
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`ide.hasSeenNudge`** (boolean):
|
||||
- **Description:** Whether the user has seen the IDE integration nudge.
|
||||
@@ -224,8 +259,9 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
#### `privacy`
|
||||
|
||||
- **`privacy.usageStatisticsEnabled`** (boolean):
|
||||
- **Description:** Enable collection of usage statistics.
|
||||
- **Description:** Enable collection of usage statistics
|
||||
- **Default:** `true`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
#### `model`
|
||||
|
||||
@@ -239,32 +275,26 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
- **Default:** `-1`
|
||||
|
||||
- **`model.summarizeToolOutput`** (object):
|
||||
- **Description:** Enables or disables the summarization of tool output. You
|
||||
can specify the token budget for the summarization using the `tokenBudget`
|
||||
setting. Note: Currently only the `run_shell_command` tool is supported. For
|
||||
example `{"run_shell_command": {"tokenBudget": 2000}}`
|
||||
- **Description:** Enables or disables summarization of tool output. Configure
|
||||
per-tool token budgets (for example {"run_shell_command": {"tokenBudget":
|
||||
2000}}). Currently only the run_shell_command tool supports summarization.
|
||||
- **Default:** `undefined`
|
||||
|
||||
- **`model.compressionThreshold`** (number):
|
||||
- **Description:** Sets the threshold for chat history compression as a
|
||||
fraction of the model's total token limit. This is a value between 0 and 1
|
||||
that applies to both automatic compression and the manual `/compress`
|
||||
command. For example, a value of `0.6` will trigger compression when the
|
||||
chat history exceeds 60% of the token limit.
|
||||
- **Description:** The fraction of context usage at which to trigger context
|
||||
compression (e.g. 0.2, 0.3).
|
||||
- **Default:** `0.2`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`model.skipNextSpeakerCheck`** (boolean):
|
||||
- **Description:** Skip the next speaker check.
|
||||
- **Default:** `false`
|
||||
|
||||
- **`model.enableShellOutputEfficiency`** (boolean):
|
||||
- **Description:** Optimizes shell tool commands for token efficiency.
|
||||
- **Default:** `true`
|
||||
|
||||
#### `context`
|
||||
|
||||
- **`context.fileName`** (string or array of strings):
|
||||
- **Description:** The name of the context file(s).
|
||||
- **`context.fileName`** (string | string[]):
|
||||
- **Description:** The name of the context file or files to load into memory.
|
||||
Accepts either a single string or an array of strings.
|
||||
- **Default:** `undefined`
|
||||
|
||||
- **`context.importFormat`** (string):
|
||||
@@ -280,42 +310,51 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
Missing directories will be skipped with a warning.
|
||||
- **Default:** `[]`
|
||||
|
||||
- **`context.loadFromIncludeDirectories`** (boolean):
|
||||
- **Description:** Controls the behavior of the `/memory refresh` command. If
|
||||
set to `true`, `GEMINI.md` files should be loaded from all directories that
|
||||
are added. If set to `false`, `GEMINI.md` should only be loaded from the
|
||||
current directory.
|
||||
- **`context.loadMemoryFromIncludeDirectories`** (boolean):
|
||||
- **Description:** Controls how /memory refresh loads GEMINI.md files. When
|
||||
true, include directories are scanned; when false, only the current
|
||||
directory is used.
|
||||
- **Default:** `false`
|
||||
|
||||
- **`context.fileFiltering.respectGitIgnore`** (boolean):
|
||||
- **Description:** Respect .gitignore files when searching.
|
||||
- **Description:** Respect .gitignore files when searching
|
||||
- **Default:** `true`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`context.fileFiltering.respectGeminiIgnore`** (boolean):
|
||||
- **Description:** Respect .geminiignore files when searching.
|
||||
- **Description:** Respect .geminiignore files when searching
|
||||
- **Default:** `true`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`context.fileFiltering.enableRecursiveFileSearch`** (boolean):
|
||||
- **Description:** Whether to enable searching recursively for filenames under
|
||||
the current tree when completing `@` prefixes in the prompt.
|
||||
- **Description:** Enable recursive file search functionality when completing
|
||||
@ references in the prompt.
|
||||
- **Default:** `true`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`context.fileFiltering.disableFuzzySearch`** (boolean):
|
||||
- **Description:** Disable fuzzy search when searching for files.
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
#### `tools`
|
||||
|
||||
- **`tools.sandbox`** (boolean or string):
|
||||
- **Description:** Sandbox execution environment (can be a boolean or a path
|
||||
string).
|
||||
- **`tools.sandbox`** (boolean | string):
|
||||
- **Description:** Sandbox execution environment. Set to a boolean to enable
|
||||
or disable the sandbox, or provide a string path to a sandbox profile.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`tools.shell.enableInteractiveShell`** (boolean):
|
||||
- **Description:** Enables interactive terminal for running shell commands. If
|
||||
an interactive session cannot be started, it will fall back to a standard
|
||||
shell.
|
||||
- **Description:** Use node-pty for an interactive shell experience. Fallback
|
||||
to child_process still applies.
|
||||
- **Default:** `true`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`tools.shell.pager`** (string):
|
||||
- **Description:** The pager command to use for shell output. Defaults to
|
||||
`cat`.
|
||||
- **Default:** `"cat"`
|
||||
|
||||
- **`tools.shell.showColor`** (boolean):
|
||||
- **Description:** Show color in shell output.
|
||||
@@ -326,42 +365,37 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
considered safe (e.g., read-only operations).
|
||||
- **Default:** `false`
|
||||
|
||||
- **`tools.core`** (array of strings):
|
||||
- **Description:** This can be used to restrict the set of built-in tools
|
||||
[with an allowlist](../cli/enterprise.md#restricting-tool-access). See
|
||||
[Built-in Tools](../core/tools-api.md#built-in-tools) for a list of core
|
||||
tools. The match semantics are the same as `tools.allowed`.
|
||||
- **`tools.core`** (array):
|
||||
- **Description:** Restrict the set of built-in tools with an allowlist. Match
|
||||
semantics mirror tools.allowed; see the built-in tools documentation for
|
||||
available names.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`tools.exclude`** (array of strings):
|
||||
- **`tools.allowed`** (array):
|
||||
- **Description:** Tool names that bypass the confirmation dialog. Useful for
|
||||
trusted commands (for example ["run_shell_command(git)",
|
||||
"run_shell_command(npm test)"]). See shell tool command restrictions for
|
||||
matching details.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`tools.exclude`** (array):
|
||||
- **Description:** Tool names to exclude from discovery.
|
||||
- **Default:** `undefined`
|
||||
|
||||
- **`tools.allowed`** (array of strings):
|
||||
- **Description:** A list of tool names that will bypass the confirmation
|
||||
dialog. This is useful for tools that you trust and use frequently. For
|
||||
example, `["run_shell_command(git)", "run_shell_command(npm test)"]` will
|
||||
skip the confirmation dialog to run any `git` and `npm test` commands. See
|
||||
[Shell Tool command restrictions](../tools/shell.md#command-restrictions)
|
||||
for details on prefix matching, command chaining, etc.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`tools.discoveryCommand`** (string):
|
||||
- **Description:** Command to run for tool discovery.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`tools.callCommand`** (string):
|
||||
- **Description:** Defines a custom shell command for calling a specific tool
|
||||
that was discovered using `tools.discoveryCommand`. The shell command must
|
||||
meet the following criteria:
|
||||
- It must take function `name` (exactly as in
|
||||
[function declaration](https://ai.google.dev/gemini-api/docs/function-calling#function-declarations))
|
||||
as the first command line argument.
|
||||
- It must read function arguments as JSON on `stdin`, analogous to
|
||||
[`functionCall.args`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#functioncall).
|
||||
- It must return function output as JSON on `stdout`, analogous to
|
||||
[`functionResponse.response.content`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#functionresponse).
|
||||
- **Description:** Defines a custom shell command for invoking discovered
|
||||
tools. The command must take the tool name as the first argument, read JSON
|
||||
arguments from stdin, and emit JSON results on stdout.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`tools.useRipgrep`** (boolean):
|
||||
- **Description:** Use ripgrep for file content search instead of the fallback
|
||||
@@ -371,36 +405,51 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
- **`tools.enableToolOutputTruncation`** (boolean):
|
||||
- **Description:** Enable truncation of large tool outputs.
|
||||
- **Default:** `true`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`tools.truncateToolOutputThreshold`** (number):
|
||||
- **Description:** Truncate tool output if it is larger than this many
|
||||
characters. Set to -1 to disable.
|
||||
- **Default:** `20000`
|
||||
- **Default:** `4000000`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`tools.truncateToolOutputLines`** (number):
|
||||
- **Description:** The number of lines to keep when truncating tool output.
|
||||
- **Default:** `1000`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`tools.enableMessageBusIntegration`** (boolean):
|
||||
- **Description:** Enable policy-based tool confirmation via message bus
|
||||
integration. When enabled, tools will automatically respect policy engine
|
||||
integration. When enabled, tools automatically respect policy engine
|
||||
decisions (ALLOW/DENY/ASK_USER) without requiring individual tool
|
||||
implementations.
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`tools.enableHooks`** (boolean):
|
||||
- **Description:** Enable the hooks system for intercepting and customizing
|
||||
Gemini CLI behavior. When enabled, hooks configured in settings will execute
|
||||
at appropriate lifecycle events (BeforeTool, AfterTool, BeforeModel, etc.).
|
||||
Requires MessageBus integration.
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
#### `mcp`
|
||||
|
||||
- **`mcp.serverCommand`** (string):
|
||||
- **Description:** Command to start an MCP server.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`mcp.allowed`** (array of strings):
|
||||
- **Description:** An allowlist of MCP servers to allow.
|
||||
- **`mcp.allowed`** (array):
|
||||
- **Description:** A list of MCP servers to allow.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`mcp.excluded`** (array of strings):
|
||||
- **Description:** A denylist of MCP servers to exclude.
|
||||
- **`mcp.excluded`** (array):
|
||||
- **Description:** A list of MCP servers to exclude.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
#### `useSmartEdit`
|
||||
|
||||
@@ -411,38 +460,50 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
#### `useWriteTodos`
|
||||
|
||||
- **`useWriteTodos`** (boolean):
|
||||
- **Description:** Enable the write_todos tool.
|
||||
- **Description:** Enable the write_todos_list tool.
|
||||
- **Default:** `false`
|
||||
|
||||
#### `security`
|
||||
|
||||
- **`security.disableYoloMode`** (boolean):
|
||||
- **Description:** Disable YOLO mode, even if enabled by a flag.
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`security.folderTrust.enabled`** (boolean):
|
||||
- **Description:** Setting to track whether Folder trust is enabled.
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`security.auth.selectedType`** (string):
|
||||
- **Description:** The currently selected authentication type.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`security.auth.enforcedType`** (string):
|
||||
- **Description:** The required auth type (useful for enterprises).
|
||||
- **Description:** The required auth type. If this does not match the selected
|
||||
auth type, the user will be prompted to re-authenticate.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`security.auth.useExternal`** (boolean):
|
||||
- **Description:** Whether to use an external authentication flow.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
#### `advanced`
|
||||
|
||||
- **`advanced.autoConfigureMemory`** (boolean):
|
||||
- **Description:** Automatically configure Node.js memory limits.
|
||||
- **Description:** Automatically configure Node.js memory limits
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`advanced.dnsResolutionOrder`** (string):
|
||||
- **Description:** The DNS resolution order.
|
||||
- **Default:** `undefined`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`advanced.excludedEnvVars`** (array of strings):
|
||||
- **`advanced.excludedEnvVars`** (array):
|
||||
- **Description:** Environment variables to exclude from project context.
|
||||
- **Default:** `["DEBUG","DEBUG_MODE"]`
|
||||
|
||||
@@ -452,10 +513,56 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
|
||||
#### `experimental`
|
||||
|
||||
- **`experimental.extensionManagement`** (boolean):
|
||||
- **Description:** Enable extension management features.
|
||||
- **Default:** `true`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.extensionReloading`** (boolean):
|
||||
- **Description:** Enables extension loading/unloading within the CLI session.
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.useModelRouter`** (boolean):
|
||||
- **Description:** Enable model routing to route requests to the best model
|
||||
based on complexity.
|
||||
- **Default:** `true`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.codebaseInvestigatorSettings.enabled`** (boolean):
|
||||
- **Description:** Enable the Codebase Investigator agent.
|
||||
- **Default:** `false`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.codebaseInvestigatorSettings.maxNumTurns`** (number):
|
||||
- **Description:** Maximum number of turns for the Codebase Investigator
|
||||
agent.
|
||||
- **Default:** `15`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.codebaseInvestigatorSettings.maxTimeMinutes`** (number):
|
||||
- **Description:** Maximum time for the Codebase Investigator agent (in
|
||||
minutes).
|
||||
- **Default:** `5`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.codebaseInvestigatorSettings.thinkingBudget`** (number):
|
||||
- **Description:** The thinking budget for the Codebase Investigator agent.
|
||||
- **Default:** `-1`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
- **`experimental.codebaseInvestigatorSettings.model`** (string):
|
||||
- **Description:** The model to use for the Codebase Investigator agent.
|
||||
- **Default:** `"gemini-2.5-pro"`
|
||||
- **Requires restart:** Yes
|
||||
|
||||
#### `hooks`
|
||||
|
||||
- **`hooks`** (object):
|
||||
- **Description:** Hook configurations for intercepting and customizing agent
|
||||
behavior.
|
||||
- **Default:** `{}`
|
||||
<!-- SETTINGS-AUTOGEN:END -->
|
||||
|
||||
#### `mcpServers`
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
"auth:docker": "gcloud auth configure-docker us-west1-docker.pkg.dev",
|
||||
"auth": "npm run auth:npm && npm run auth:docker",
|
||||
"generate": "node scripts/generate-git-commit-info.js",
|
||||
"predocs:settings": "npm run build --workspace @google/gemini-cli-core",
|
||||
"schema:settings": "tsx ./scripts/generate-settings-schema.ts",
|
||||
"docs:settings": "tsx ./scripts/generate-settings-doc.ts",
|
||||
"build": "node scripts/build.js",
|
||||
"build-and-start": "npm run build && npm run start",
|
||||
"build:vscode": "node scripts/build_vscode_companion.js",
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
getSettingsSchema,
|
||||
SETTINGS_SCHEMA_DEFINITIONS,
|
||||
type SettingCollectionDefinition,
|
||||
type SettingDefinition,
|
||||
type Settings,
|
||||
type SettingsSchema,
|
||||
@@ -335,4 +337,50 @@ describe('SettingsSchema', () => {
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('has JSON schema definitions for every referenced ref', () => {
|
||||
const schema = getSettingsSchema();
|
||||
const referenced = new Set<string>();
|
||||
|
||||
const visitDefinition = (definition: SettingDefinition) => {
|
||||
if (definition.ref) {
|
||||
referenced.add(definition.ref);
|
||||
expect(SETTINGS_SCHEMA_DEFINITIONS).toHaveProperty(definition.ref);
|
||||
}
|
||||
if (definition.properties) {
|
||||
Object.values(definition.properties).forEach(visitDefinition);
|
||||
}
|
||||
if (definition.items) {
|
||||
visitCollection(definition.items);
|
||||
}
|
||||
if (definition.additionalProperties) {
|
||||
visitCollection(definition.additionalProperties);
|
||||
}
|
||||
};
|
||||
|
||||
const visitCollection = (collection: SettingCollectionDefinition) => {
|
||||
if (collection.ref) {
|
||||
referenced.add(collection.ref);
|
||||
expect(SETTINGS_SCHEMA_DEFINITIONS).toHaveProperty(collection.ref);
|
||||
return;
|
||||
}
|
||||
if (collection.properties) {
|
||||
Object.values(collection.properties).forEach(visitDefinition);
|
||||
}
|
||||
if (collection.type === 'array' && collection.properties) {
|
||||
Object.values(collection.properties).forEach(visitDefinition);
|
||||
}
|
||||
};
|
||||
|
||||
Object.values(schema).forEach(visitDefinition);
|
||||
|
||||
// Ensure definitions map doesn't accumulate stale entries.
|
||||
Object.keys(SETTINGS_SCHEMA_DEFINITIONS).forEach((key) => {
|
||||
if (!referenced.has(key)) {
|
||||
throw new Error(
|
||||
`Definition "${key}" is exported but never referenced in the schema`,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// IMPORTANT: When adding a new setting, especially one with `showInDialog: true`,
|
||||
// please ensure it is also documented in `docs/get-started/configuration.md`.
|
||||
// IMPORTANT: After adding or updating settings, run `npm run docs:settings`
|
||||
// to regenerate the settings reference in `docs/get-started/configuration.md`.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
import type {
|
||||
@@ -57,6 +57,30 @@ export interface SettingEnumOption {
|
||||
label: string;
|
||||
}
|
||||
|
||||
function oneLine(strings: TemplateStringsArray, ...values: unknown[]): string {
|
||||
let result = '';
|
||||
for (let i = 0; i < strings.length; i++) {
|
||||
result += strings[i];
|
||||
if (i < values.length) {
|
||||
result += String(values[i]);
|
||||
}
|
||||
}
|
||||
return result.replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
export interface SettingCollectionDefinition {
|
||||
type: SettingsType;
|
||||
description?: string;
|
||||
properties?: SettingsSchema;
|
||||
/** Enum type options */
|
||||
options?: readonly SettingEnumOption[];
|
||||
/**
|
||||
* Optional reference identifier for generators that emit a `$ref`.
|
||||
* For example, a JSON schema generator can use this to point to a shared definition.
|
||||
*/
|
||||
ref?: string;
|
||||
}
|
||||
|
||||
export enum MergeStrategy {
|
||||
// Replace the old value with the new value. This is the default.
|
||||
REPLACE = 'replace',
|
||||
@@ -83,6 +107,18 @@ export interface SettingDefinition {
|
||||
mergeStrategy?: MergeStrategy;
|
||||
/** Enum type options */
|
||||
options?: readonly SettingEnumOption[];
|
||||
/**
|
||||
* For collection types (e.g. arrays), describes the shape of each item.
|
||||
*/
|
||||
items?: SettingCollectionDefinition;
|
||||
/**
|
||||
* For map-like objects without explicit `properties`, describes the shape of the values.
|
||||
*/
|
||||
additionalProperties?: SettingCollectionDefinition;
|
||||
/**
|
||||
* Optional reference identifier for generators that emit a `$ref`.
|
||||
*/
|
||||
ref?: string;
|
||||
}
|
||||
|
||||
export interface SettingsSchema {
|
||||
@@ -108,6 +144,10 @@ const SETTINGS_SCHEMA = {
|
||||
description: 'Configuration for MCP servers.',
|
||||
showInDialog: false,
|
||||
mergeStrategy: MergeStrategy.SHALLOW_MERGE,
|
||||
additionalProperties: {
|
||||
type: 'object',
|
||||
ref: 'MCPServerConfig',
|
||||
},
|
||||
},
|
||||
|
||||
general: {
|
||||
@@ -294,7 +334,8 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'UI',
|
||||
requiresRestart: false,
|
||||
default: undefined as string | undefined,
|
||||
description: 'The color theme for the UI.',
|
||||
description:
|
||||
'The color theme for the UI. See the CLI themes guide for available options.',
|
||||
showInDialog: false,
|
||||
},
|
||||
customThemes: {
|
||||
@@ -305,6 +346,10 @@ const SETTINGS_SCHEMA = {
|
||||
default: {} as Record<string, CustomTheme>,
|
||||
description: 'Custom theme definitions.',
|
||||
showInDialog: false,
|
||||
additionalProperties: {
|
||||
type: 'object',
|
||||
ref: 'CustomTheme',
|
||||
},
|
||||
},
|
||||
hideWindowTitle: {
|
||||
type: 'boolean',
|
||||
@@ -452,8 +497,12 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'UI',
|
||||
requiresRestart: false,
|
||||
default: [] as string[],
|
||||
description: 'Custom witty phrases to display during loading.',
|
||||
description: oneLine`
|
||||
Custom witty phrases to display during loading.
|
||||
When provided, the CLI cycles through these instead of the defaults.
|
||||
`,
|
||||
showInDialog: false,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
accessibility: {
|
||||
type: 'object',
|
||||
@@ -547,6 +596,7 @@ const SETTINGS_SCHEMA = {
|
||||
default: undefined as TelemetrySettings | undefined,
|
||||
description: 'Telemetry configuration.',
|
||||
showInDialog: false,
|
||||
ref: 'TelemetrySettings',
|
||||
},
|
||||
|
||||
model: {
|
||||
@@ -585,8 +635,18 @@ const SETTINGS_SCHEMA = {
|
||||
default: undefined as
|
||||
| Record<string, { tokenBudget?: number }>
|
||||
| undefined,
|
||||
description: 'Settings for summarizing tool output.',
|
||||
description: oneLine`
|
||||
Enables or disables summarization of tool output.
|
||||
Configure per-tool token budgets (for example {"run_shell_command": {"tokenBudget": 2000}}).
|
||||
Currently only the run_shell_command tool supports summarization.
|
||||
`,
|
||||
showInDialog: false,
|
||||
additionalProperties: {
|
||||
type: 'object',
|
||||
description:
|
||||
'Per-tool summarization settings with an optional tokenBudget.',
|
||||
ref: 'SummarizeToolOutputSettings',
|
||||
},
|
||||
},
|
||||
compressionThreshold: {
|
||||
type: 'number',
|
||||
@@ -620,12 +680,14 @@ const SETTINGS_SCHEMA = {
|
||||
showInDialog: false,
|
||||
properties: {
|
||||
fileName: {
|
||||
type: 'object',
|
||||
type: 'string',
|
||||
label: 'Context File Name',
|
||||
category: 'Context',
|
||||
requiresRestart: false,
|
||||
default: undefined as string | string[] | undefined,
|
||||
description: 'The name of the context file.',
|
||||
ref: 'StringOrStringArray',
|
||||
description:
|
||||
'The name of the context file or files to load into memory. Accepts either a single string or an array of strings.',
|
||||
showInDialog: false,
|
||||
},
|
||||
importFormat: {
|
||||
@@ -652,9 +714,12 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'Context',
|
||||
requiresRestart: false,
|
||||
default: [] as string[],
|
||||
description:
|
||||
'Additional directories to include in the workspace context. Missing directories will be skipped with a warning.',
|
||||
description: oneLine`
|
||||
Additional directories to include in the workspace context.
|
||||
Missing directories will be skipped with a warning.
|
||||
`,
|
||||
showInDialog: false,
|
||||
items: { type: 'string' },
|
||||
mergeStrategy: MergeStrategy.CONCAT,
|
||||
},
|
||||
loadMemoryFromIncludeDirectories: {
|
||||
@@ -663,7 +728,10 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'Context',
|
||||
requiresRestart: false,
|
||||
default: false,
|
||||
description: 'Whether to load memory files from include directories.',
|
||||
description: oneLine`
|
||||
Controls how /memory refresh loads GEMINI.md files.
|
||||
When true, include directories are scanned; when false, only the current directory is used.
|
||||
`,
|
||||
showInDialog: true,
|
||||
},
|
||||
fileFiltering: {
|
||||
@@ -699,7 +767,9 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'Context',
|
||||
requiresRestart: true,
|
||||
default: true,
|
||||
description: 'Enable recursive file search functionality',
|
||||
description: oneLine`
|
||||
Enable recursive file search functionality when completing @ references in the prompt.
|
||||
`,
|
||||
showInDialog: true,
|
||||
},
|
||||
disableFuzzySearch: {
|
||||
@@ -726,13 +796,16 @@ const SETTINGS_SCHEMA = {
|
||||
showInDialog: false,
|
||||
properties: {
|
||||
sandbox: {
|
||||
type: 'object',
|
||||
type: 'string',
|
||||
label: 'Sandbox',
|
||||
category: 'Tools',
|
||||
requiresRestart: true,
|
||||
default: undefined as boolean | string | undefined,
|
||||
description:
|
||||
'Sandbox execution environment (can be a boolean or a path string).',
|
||||
ref: 'BooleanOrString',
|
||||
description: oneLine`
|
||||
Sandbox execution environment.
|
||||
Set to a boolean to enable or disable the sandbox, or provide a string path to a sandbox profile.
|
||||
`,
|
||||
showInDialog: false,
|
||||
},
|
||||
shell: {
|
||||
@@ -750,8 +823,10 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'Tools',
|
||||
requiresRestart: true,
|
||||
default: true,
|
||||
description:
|
||||
'Use node-pty for an interactive shell experience. Fallback to child_process still applies.',
|
||||
description: oneLine`
|
||||
Use node-pty for an interactive shell experience.
|
||||
Fallback to child_process still applies.
|
||||
`,
|
||||
showInDialog: true,
|
||||
},
|
||||
pager: {
|
||||
@@ -781,8 +856,9 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'Tools',
|
||||
requiresRestart: false,
|
||||
default: false,
|
||||
description:
|
||||
'Automatically accept and execute tool calls that are considered safe (e.g., read-only operations).',
|
||||
description: oneLine`
|
||||
Automatically accept and execute tool calls that are considered safe (e.g., read-only operations).
|
||||
`,
|
||||
showInDialog: true,
|
||||
},
|
||||
core: {
|
||||
@@ -791,8 +867,12 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'Tools',
|
||||
requiresRestart: true,
|
||||
default: undefined as string[] | undefined,
|
||||
description: 'Paths to core tool definitions.',
|
||||
description: oneLine`
|
||||
Restrict the set of built-in tools with an allowlist.
|
||||
Match semantics mirror tools.allowed; see the built-in tools documentation for available names.
|
||||
`,
|
||||
showInDialog: false,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
allowed: {
|
||||
type: 'array',
|
||||
@@ -800,9 +880,13 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'Advanced',
|
||||
requiresRestart: true,
|
||||
default: undefined as string[] | undefined,
|
||||
description:
|
||||
'A list of tool names that will bypass the confirmation dialog.',
|
||||
description: oneLine`
|
||||
Tool names that bypass the confirmation dialog.
|
||||
Useful for trusted commands (for example ["run_shell_command(git)", "run_shell_command(npm test)"]).
|
||||
See shell tool command restrictions for matching details.
|
||||
`,
|
||||
showInDialog: false,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
exclude: {
|
||||
type: 'array',
|
||||
@@ -812,6 +896,7 @@ const SETTINGS_SCHEMA = {
|
||||
default: undefined as string[] | undefined,
|
||||
description: 'Tool names to exclude from discovery.',
|
||||
showInDialog: false,
|
||||
items: { type: 'string' },
|
||||
mergeStrategy: MergeStrategy.UNION,
|
||||
},
|
||||
discoveryCommand: {
|
||||
@@ -829,7 +914,10 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'Tools',
|
||||
requiresRestart: true,
|
||||
default: undefined as string | undefined,
|
||||
description: 'Command to run for tool calls.',
|
||||
description: oneLine`
|
||||
Defines a custom shell command for invoking discovered tools.
|
||||
The command must take the tool name as the first argument, read JSON arguments from stdin, and emit JSON results on stdout.
|
||||
`,
|
||||
showInDialog: false,
|
||||
},
|
||||
useRipgrep: {
|
||||
@@ -876,8 +964,10 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'Tools',
|
||||
requiresRestart: true,
|
||||
default: false,
|
||||
description:
|
||||
'Enable policy-based tool confirmation via message bus integration. When enabled, tools will automatically respect policy engine decisions (ALLOW/DENY/ASK_USER) without requiring individual tool implementations.',
|
||||
description: oneLine`
|
||||
Enable policy-based tool confirmation via message bus integration.
|
||||
When enabled, tools automatically respect policy engine decisions (ALLOW/DENY/ASK_USER) without requiring individual tool implementations.
|
||||
`,
|
||||
showInDialog: true,
|
||||
},
|
||||
enableHooks: {
|
||||
@@ -919,6 +1009,7 @@ const SETTINGS_SCHEMA = {
|
||||
default: undefined as string[] | undefined,
|
||||
description: 'A list of MCP servers to allow.',
|
||||
showInDialog: false,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
excluded: {
|
||||
type: 'array',
|
||||
@@ -928,6 +1019,7 @@ const SETTINGS_SCHEMA = {
|
||||
default: undefined as string[] | undefined,
|
||||
description: 'A list of MCP servers to exclude.',
|
||||
showInDialog: false,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1064,6 +1156,7 @@ const SETTINGS_SCHEMA = {
|
||||
default: ['DEBUG', 'DEBUG_MODE'] as string[],
|
||||
description: 'Environment variables to exclude from project context.',
|
||||
showInDialog: false,
|
||||
items: { type: 'string' },
|
||||
mergeStrategy: MergeStrategy.UNION,
|
||||
},
|
||||
bugCommand: {
|
||||
@@ -1074,6 +1167,7 @@ const SETTINGS_SCHEMA = {
|
||||
default: undefined as BugCommandSettings | undefined,
|
||||
description: 'Configuration for the bug report command.',
|
||||
showInDialog: false,
|
||||
ref: 'BugCommandSettings',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1196,6 +1290,7 @@ const SETTINGS_SCHEMA = {
|
||||
default: [] as string[],
|
||||
description: 'List of disabled extensions.',
|
||||
showInDialog: false,
|
||||
items: { type: 'string' },
|
||||
mergeStrategy: MergeStrategy.UNION,
|
||||
},
|
||||
workspacesWithMigrationNudge: {
|
||||
@@ -1207,6 +1302,7 @@ const SETTINGS_SCHEMA = {
|
||||
description:
|
||||
'List of workspaces for which the migration nudge has been shown.',
|
||||
showInDialog: false,
|
||||
items: { type: 'string' },
|
||||
mergeStrategy: MergeStrategy.UNION,
|
||||
},
|
||||
},
|
||||
@@ -1227,6 +1323,274 @@ const SETTINGS_SCHEMA = {
|
||||
|
||||
export type SettingsSchemaType = typeof SETTINGS_SCHEMA;
|
||||
|
||||
export type SettingsJsonSchemaDefinition = Record<string, unknown>;
|
||||
|
||||
export const SETTINGS_SCHEMA_DEFINITIONS: Record<
|
||||
string,
|
||||
SettingsJsonSchemaDefinition
|
||||
> = {
|
||||
MCPServerConfig: {
|
||||
type: 'object',
|
||||
description:
|
||||
'Definition of a Model Context Protocol (MCP) server configuration.',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
command: {
|
||||
type: 'string',
|
||||
description: 'Executable invoked for stdio transport.',
|
||||
},
|
||||
args: {
|
||||
type: 'array',
|
||||
description: 'Command-line arguments for the stdio transport command.',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
env: {
|
||||
type: 'object',
|
||||
description: 'Environment variables to set for the server process.',
|
||||
additionalProperties: { type: 'string' },
|
||||
},
|
||||
cwd: {
|
||||
type: 'string',
|
||||
description: 'Working directory for the server process.',
|
||||
},
|
||||
url: {
|
||||
type: 'string',
|
||||
description: 'SSE transport URL.',
|
||||
},
|
||||
httpUrl: {
|
||||
type: 'string',
|
||||
description: 'Streaming HTTP transport URL.',
|
||||
},
|
||||
headers: {
|
||||
type: 'object',
|
||||
description: 'Additional HTTP headers sent to the server.',
|
||||
additionalProperties: { type: 'string' },
|
||||
},
|
||||
tcp: {
|
||||
type: 'string',
|
||||
description: 'TCP address for websocket transport.',
|
||||
},
|
||||
timeout: {
|
||||
type: 'number',
|
||||
description: 'Timeout in milliseconds for MCP requests.',
|
||||
},
|
||||
trust: {
|
||||
type: 'boolean',
|
||||
description:
|
||||
'Marks the server as trusted. Trusted servers may gain additional capabilities.',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
description: 'Human-readable description of the server.',
|
||||
},
|
||||
includeTools: {
|
||||
type: 'array',
|
||||
description:
|
||||
'Subset of tools that should be enabled for this server. When omitted all tools are enabled.',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
excludeTools: {
|
||||
type: 'array',
|
||||
description:
|
||||
'Tools that should be disabled for this server even if exposed.',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
extension: {
|
||||
type: 'object',
|
||||
description:
|
||||
'Metadata describing the Gemini CLI extension that owns this MCP server.',
|
||||
additionalProperties: { type: ['string', 'boolean', 'number'] },
|
||||
},
|
||||
oauth: {
|
||||
type: 'object',
|
||||
description: 'OAuth configuration for authenticating with the server.',
|
||||
additionalProperties: true,
|
||||
},
|
||||
authProviderType: {
|
||||
type: 'string',
|
||||
description:
|
||||
'Authentication provider used for acquiring credentials (for example `dynamic_discovery`).',
|
||||
enum: [
|
||||
'dynamic_discovery',
|
||||
'google_credentials',
|
||||
'service_account_impersonation',
|
||||
],
|
||||
},
|
||||
targetAudience: {
|
||||
type: 'string',
|
||||
description:
|
||||
'OAuth target audience (CLIENT_ID.apps.googleusercontent.com).',
|
||||
},
|
||||
targetServiceAccount: {
|
||||
type: 'string',
|
||||
description:
|
||||
'Service account email to impersonate (name@project.iam.gserviceaccount.com).',
|
||||
},
|
||||
},
|
||||
},
|
||||
TelemetrySettings: {
|
||||
type: 'object',
|
||||
description: 'Telemetry configuration for Gemini CLI.',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
enabled: {
|
||||
type: 'boolean',
|
||||
description: 'Enables telemetry emission.',
|
||||
},
|
||||
target: {
|
||||
type: 'string',
|
||||
description:
|
||||
'Telemetry destination (for example `stderr`, `stdout`, or `otlp`).',
|
||||
},
|
||||
otlpEndpoint: {
|
||||
type: 'string',
|
||||
description: 'Endpoint for OTLP exporters.',
|
||||
},
|
||||
otlpProtocol: {
|
||||
type: 'string',
|
||||
description: 'Protocol for OTLP exporters.',
|
||||
enum: ['grpc', 'http'],
|
||||
},
|
||||
logPrompts: {
|
||||
type: 'boolean',
|
||||
description: 'Whether prompts are logged in telemetry payloads.',
|
||||
},
|
||||
outfile: {
|
||||
type: 'string',
|
||||
description: 'File path for writing telemetry output.',
|
||||
},
|
||||
useCollector: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to forward telemetry to an OTLP collector.',
|
||||
},
|
||||
},
|
||||
},
|
||||
BugCommandSettings: {
|
||||
type: 'object',
|
||||
description: 'Configuration for the bug report helper command.',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
urlTemplate: {
|
||||
type: 'string',
|
||||
description:
|
||||
'Template used to open a bug report URL. Variables in the template are populated at runtime.',
|
||||
},
|
||||
},
|
||||
required: ['urlTemplate'],
|
||||
},
|
||||
SummarizeToolOutputSettings: {
|
||||
type: 'object',
|
||||
description:
|
||||
'Controls summarization behavior for individual tools. All properties are optional.',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
tokenBudget: {
|
||||
type: 'number',
|
||||
description:
|
||||
'Maximum number of tokens used when summarizing tool output.',
|
||||
},
|
||||
},
|
||||
},
|
||||
CustomTheme: {
|
||||
type: 'object',
|
||||
description:
|
||||
'Custom theme definition used for styling Gemini CLI output. Colors are provided as hex strings or named ANSI colors.',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string',
|
||||
enum: ['custom'],
|
||||
default: 'custom',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
description: 'Theme display name.',
|
||||
},
|
||||
text: {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
primary: { type: 'string' },
|
||||
secondary: { type: 'string' },
|
||||
link: { type: 'string' },
|
||||
accent: { type: 'string' },
|
||||
},
|
||||
},
|
||||
background: {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
primary: { type: 'string' },
|
||||
diff: {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
added: { type: 'string' },
|
||||
removed: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
border: {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
default: { type: 'string' },
|
||||
focused: { type: 'string' },
|
||||
},
|
||||
},
|
||||
ui: {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
comment: { type: 'string' },
|
||||
symbol: { type: 'string' },
|
||||
gradient: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
status: {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
error: { type: 'string' },
|
||||
success: { type: 'string' },
|
||||
warning: { type: 'string' },
|
||||
},
|
||||
},
|
||||
Background: { type: 'string' },
|
||||
Foreground: { type: 'string' },
|
||||
LightBlue: { type: 'string' },
|
||||
AccentBlue: { type: 'string' },
|
||||
AccentPurple: { type: 'string' },
|
||||
AccentCyan: { type: 'string' },
|
||||
AccentGreen: { type: 'string' },
|
||||
AccentYellow: { type: 'string' },
|
||||
AccentRed: { type: 'string' },
|
||||
DiffAdded: { type: 'string' },
|
||||
DiffRemoved: { type: 'string' },
|
||||
Comment: { type: 'string' },
|
||||
Gray: { type: 'string' },
|
||||
DarkGray: { type: 'string' },
|
||||
GradientColors: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
},
|
||||
},
|
||||
required: ['type', 'name'],
|
||||
},
|
||||
StringOrStringArray: {
|
||||
description: 'Accepts either a single string or an array of strings.',
|
||||
anyOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
|
||||
},
|
||||
BooleanOrString: {
|
||||
description: 'Accepts either a boolean flag or a string command name.',
|
||||
anyOf: [{ type: 'boolean' }, { type: 'string' }],
|
||||
},
|
||||
};
|
||||
|
||||
export function getSettingsSchema(): SettingsSchemaType {
|
||||
return SETTINGS_SCHEMA;
|
||||
}
|
||||
|
||||
1229
schemas/settings.schema.json
Normal file
1229
schemas/settings.schema.json
Normal file
File diff suppressed because it is too large
Load Diff
201
scripts/generate-settings-doc.ts
Normal file
201
scripts/generate-settings-doc.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { readFile, writeFile } from 'node:fs/promises';
|
||||
import { generateSettingsSchema } from './generate-settings-schema.js';
|
||||
import {
|
||||
escapeBackticks,
|
||||
formatDefaultValue,
|
||||
formatWithPrettier,
|
||||
normalizeForCompare,
|
||||
} from './utils/autogen.js';
|
||||
|
||||
import type {
|
||||
SettingDefinition,
|
||||
SettingsSchema,
|
||||
SettingsSchemaType,
|
||||
} from '../packages/cli/src/config/settingsSchema.js';
|
||||
|
||||
const START_MARKER = '<!-- SETTINGS-AUTOGEN:START -->';
|
||||
const END_MARKER = '<!-- SETTINGS-AUTOGEN:END -->';
|
||||
|
||||
const MANUAL_TOP_LEVEL = new Set(['mcpServers', 'telemetry', 'extensions']);
|
||||
|
||||
interface DocEntry {
|
||||
path: string;
|
||||
type: string;
|
||||
description: string;
|
||||
defaultValue: string;
|
||||
requiresRestart: boolean;
|
||||
enumValues?: string[];
|
||||
}
|
||||
|
||||
export async function main(argv = process.argv.slice(2)) {
|
||||
const checkOnly = argv.includes('--check');
|
||||
|
||||
await generateSettingsSchema({ checkOnly });
|
||||
|
||||
const repoRoot = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'..',
|
||||
);
|
||||
const docPath = path.join(repoRoot, 'docs/get-started/configuration.md');
|
||||
|
||||
const { getSettingsSchema } = await loadSettingsSchemaModule();
|
||||
const schema = getSettingsSchema();
|
||||
const sections = collectEntries(schema);
|
||||
const generatedBlock = renderSections(sections);
|
||||
|
||||
const doc = await readFile(docPath, 'utf8');
|
||||
const startIndex = doc.indexOf(START_MARKER);
|
||||
const endIndex = doc.indexOf(END_MARKER);
|
||||
|
||||
if (startIndex === -1 || endIndex === -1 || startIndex >= endIndex) {
|
||||
throw new Error(
|
||||
`Could not locate documentation markers (${START_MARKER}, ${END_MARKER}).`,
|
||||
);
|
||||
}
|
||||
|
||||
const before = doc.slice(0, startIndex + START_MARKER.length);
|
||||
const after = doc.slice(endIndex);
|
||||
const formattedDoc = await formatWithPrettier(
|
||||
`${before}\n${generatedBlock}\n${after}`,
|
||||
docPath,
|
||||
);
|
||||
|
||||
if (normalizeForCompare(doc) === normalizeForCompare(formattedDoc)) {
|
||||
if (!checkOnly) {
|
||||
console.log('Settings documentation already up to date.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkOnly) {
|
||||
console.error(
|
||||
'Settings documentation is out of date. Run `npm run docs:settings` to regenerate.',
|
||||
);
|
||||
process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
await writeFile(docPath, formattedDoc);
|
||||
console.log('Settings documentation regenerated.');
|
||||
}
|
||||
|
||||
async function loadSettingsSchemaModule() {
|
||||
const modulePath = '../packages/cli/src/config/settingsSchema.ts';
|
||||
return import(modulePath);
|
||||
}
|
||||
|
||||
function collectEntries(schema: SettingsSchemaType) {
|
||||
const sections = new Map<string, DocEntry[]>();
|
||||
|
||||
const visit = (
|
||||
current: SettingsSchema,
|
||||
pathSegments: string[],
|
||||
topLevel?: string,
|
||||
) => {
|
||||
for (const [key, definition] of Object.entries(current)) {
|
||||
if (pathSegments.length === 0 && MANUAL_TOP_LEVEL.has(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newPathSegments = [...pathSegments, key];
|
||||
const sectionKey = topLevel ?? key;
|
||||
const hasChildren =
|
||||
definition.type === 'object' &&
|
||||
definition.properties &&
|
||||
Object.keys(definition.properties).length > 0;
|
||||
|
||||
if (!hasChildren) {
|
||||
if (!sections.has(sectionKey)) {
|
||||
sections.set(sectionKey, []);
|
||||
}
|
||||
|
||||
sections.get(sectionKey)!.push({
|
||||
path: newPathSegments.join('.'),
|
||||
type: formatType(definition),
|
||||
description: formatDescription(definition),
|
||||
defaultValue: formatDefaultValue(definition.default, {
|
||||
quoteStrings: true,
|
||||
}),
|
||||
requiresRestart: Boolean(definition.requiresRestart),
|
||||
enumValues: definition.options?.map((option) =>
|
||||
formatDefaultValue(option.value, { quoteStrings: true }),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (hasChildren && definition.properties) {
|
||||
visit(definition.properties, newPathSegments, sectionKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
visit(schema, []);
|
||||
return sections;
|
||||
}
|
||||
|
||||
function formatDescription(definition: SettingDefinition) {
|
||||
if (definition.description?.trim()) {
|
||||
return definition.description.trim();
|
||||
}
|
||||
return 'Description not provided.';
|
||||
}
|
||||
|
||||
function formatType(definition: SettingDefinition): string {
|
||||
switch (definition.ref) {
|
||||
case 'StringOrStringArray':
|
||||
return 'string | string[]';
|
||||
case 'BooleanOrString':
|
||||
return 'boolean | string';
|
||||
default:
|
||||
return definition.type;
|
||||
}
|
||||
}
|
||||
|
||||
function renderSections(sections: Map<string, DocEntry[]>) {
|
||||
const lines: string[] = [];
|
||||
|
||||
for (const [section, entries] of sections) {
|
||||
if (entries.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lines.push(`#### \`${section}\``);
|
||||
lines.push('');
|
||||
|
||||
for (const entry of entries) {
|
||||
lines.push(`- **\`${entry.path}\`** (${entry.type}):`);
|
||||
lines.push(` - **Description:** ${entry.description}`);
|
||||
lines.push(` - **Default:** \`${escapeBackticks(entry.defaultValue)}\``);
|
||||
|
||||
if (entry.enumValues && entry.enumValues.length > 0) {
|
||||
const values = entry.enumValues
|
||||
.map((value) => `\`${escapeBackticks(value)}\``)
|
||||
.join(', ');
|
||||
lines.push(` - **Values:** ${values}`);
|
||||
}
|
||||
|
||||
if (entry.requiresRestart) {
|
||||
lines.push(' - **Requires restart:** Yes');
|
||||
}
|
||||
|
||||
lines.push('');
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join('\n').trimEnd();
|
||||
}
|
||||
|
||||
if (process.argv[1]) {
|
||||
const entryUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
||||
if (entryUrl === import.meta.url) {
|
||||
await main();
|
||||
}
|
||||
}
|
||||
354
scripts/generate-settings-schema.ts
Normal file
354
scripts/generate-settings-schema.ts
Normal file
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
||||
|
||||
import {
|
||||
getSettingsSchema,
|
||||
type SettingCollectionDefinition,
|
||||
type SettingDefinition,
|
||||
type SettingsSchema,
|
||||
type SettingsSchemaType,
|
||||
SETTINGS_SCHEMA_DEFINITIONS,
|
||||
type SettingsJsonSchemaDefinition,
|
||||
} from '../packages/cli/src/config/settingsSchema.js';
|
||||
import {
|
||||
formatDefaultValue,
|
||||
formatWithPrettier,
|
||||
normalizeForCompare,
|
||||
} from './utils/autogen.js';
|
||||
|
||||
const OUTPUT_RELATIVE_PATH = ['schemas', 'settings.schema.json'];
|
||||
const SCHEMA_ID =
|
||||
'https://raw.githubusercontent.com/google-gemini/gemini-cli/main/schemas/settings.schema.json';
|
||||
|
||||
type JsonPrimitive = string | number | boolean | null;
|
||||
type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue };
|
||||
|
||||
interface JsonSchema {
|
||||
[key: string]: JsonValue | JsonSchema | JsonSchema[] | undefined;
|
||||
$schema?: string;
|
||||
$id?: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
markdownDescription?: string;
|
||||
type?: string | string[];
|
||||
enum?: JsonPrimitive[];
|
||||
default?: JsonValue;
|
||||
properties?: Record<string, JsonSchema>;
|
||||
items?: JsonSchema;
|
||||
additionalProperties?: boolean | JsonSchema;
|
||||
required?: string[];
|
||||
$ref?: string;
|
||||
anyOf?: JsonSchema[];
|
||||
}
|
||||
|
||||
interface GenerateOptions {
|
||||
checkOnly: boolean;
|
||||
}
|
||||
|
||||
export async function generateSettingsSchema(
|
||||
options: GenerateOptions,
|
||||
): Promise<void> {
|
||||
const repoRoot = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'..',
|
||||
);
|
||||
const outputPath = path.join(repoRoot, ...OUTPUT_RELATIVE_PATH);
|
||||
await mkdir(path.dirname(outputPath), { recursive: true });
|
||||
|
||||
const schemaObject = buildSchemaObject(getSettingsSchema());
|
||||
const formatted = await formatWithPrettier(
|
||||
JSON.stringify(schemaObject, null, 2),
|
||||
outputPath,
|
||||
);
|
||||
|
||||
let existing: string | undefined;
|
||||
try {
|
||||
existing = await readFile(outputPath, 'utf8');
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
existing &&
|
||||
normalizeForCompare(existing) === normalizeForCompare(formatted)
|
||||
) {
|
||||
if (!options.checkOnly) {
|
||||
console.log('Settings JSON schema already up to date.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.checkOnly) {
|
||||
console.error(
|
||||
'Settings JSON schema is out of date. Run `npm run schema:settings` to regenerate.',
|
||||
);
|
||||
process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
await writeFile(outputPath, formatted);
|
||||
console.log('Settings JSON schema regenerated.');
|
||||
}
|
||||
|
||||
export async function main(argv = process.argv.slice(2)): Promise<void> {
|
||||
const checkOnly = argv.includes('--check');
|
||||
await generateSettingsSchema({ checkOnly });
|
||||
}
|
||||
|
||||
function buildSchemaObject(schema: SettingsSchemaType): JsonSchema {
|
||||
const defs = new Map<string, JsonSchema>(
|
||||
Object.entries(SETTINGS_SCHEMA_DEFINITIONS as Record<string, JsonSchema>),
|
||||
);
|
||||
|
||||
const root: JsonSchema = {
|
||||
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
||||
$id: SCHEMA_ID,
|
||||
title: 'Gemini CLI Settings',
|
||||
description:
|
||||
'Configuration file schema for Gemini CLI settings. This schema enables IDE completion for `settings.json`.',
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {},
|
||||
};
|
||||
|
||||
for (const [key, definition] of Object.entries(schema)) {
|
||||
root.properties![key] = buildSettingSchema(definition, [key], defs);
|
||||
}
|
||||
|
||||
if (defs.size > 0) {
|
||||
root.$defs = Object.fromEntries(defs.entries());
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
function buildSettingSchema(
|
||||
definition: SettingDefinition,
|
||||
pathSegments: string[],
|
||||
defs: Map<string, JsonSchema>,
|
||||
): JsonSchema {
|
||||
const base: JsonSchema = {
|
||||
title: definition.label,
|
||||
description: definition.description,
|
||||
markdownDescription: buildMarkdownDescription(definition),
|
||||
};
|
||||
|
||||
if (definition.default !== undefined) {
|
||||
base.default = definition.default as JsonValue;
|
||||
}
|
||||
|
||||
const schemaShape = definition.ref
|
||||
? buildRefSchema(definition.ref, defs)
|
||||
: buildSchemaForType(definition, pathSegments, defs);
|
||||
|
||||
return { ...base, ...schemaShape };
|
||||
}
|
||||
|
||||
function buildCollectionSchema(
|
||||
collection: SettingCollectionDefinition,
|
||||
pathSegments: string[],
|
||||
defs: Map<string, JsonSchema>,
|
||||
): JsonSchema {
|
||||
if (collection.ref) {
|
||||
return buildRefSchema(collection.ref, defs);
|
||||
}
|
||||
return buildSchemaForType(collection, pathSegments, defs);
|
||||
}
|
||||
|
||||
function buildSchemaForType(
|
||||
source: SettingDefinition | SettingCollectionDefinition,
|
||||
pathSegments: string[],
|
||||
defs: Map<string, JsonSchema>,
|
||||
): JsonSchema {
|
||||
switch (source.type) {
|
||||
case 'boolean':
|
||||
case 'string':
|
||||
case 'number':
|
||||
return { type: source.type };
|
||||
case 'enum':
|
||||
return buildEnumSchema(source.options);
|
||||
case 'array': {
|
||||
const itemPath = [...pathSegments, '<items>'];
|
||||
const items = isSettingDefinition(source)
|
||||
? source.items
|
||||
? buildCollectionSchema(source.items, itemPath, defs)
|
||||
: {}
|
||||
: source.properties
|
||||
? buildInlineObjectSchema(source.properties, itemPath, defs)
|
||||
: {};
|
||||
return { type: 'array', items };
|
||||
}
|
||||
case 'object':
|
||||
return isSettingDefinition(source)
|
||||
? buildObjectDefinitionSchema(source, pathSegments, defs)
|
||||
: buildObjectCollectionSchema(source, pathSegments, defs);
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function buildEnumSchema(
|
||||
options:
|
||||
| SettingDefinition['options']
|
||||
| SettingCollectionDefinition['options'],
|
||||
): JsonSchema {
|
||||
const values = options?.map((option) => option.value) ?? [];
|
||||
const inferred = inferTypeFromValues(values);
|
||||
return {
|
||||
type: inferred ?? undefined,
|
||||
enum: values,
|
||||
};
|
||||
}
|
||||
|
||||
function buildObjectDefinitionSchema(
|
||||
definition: SettingDefinition,
|
||||
pathSegments: string[],
|
||||
defs: Map<string, JsonSchema>,
|
||||
): JsonSchema {
|
||||
const properties = definition.properties
|
||||
? buildObjectProperties(definition.properties, pathSegments, defs)
|
||||
: undefined;
|
||||
|
||||
const schema: JsonSchema = {
|
||||
type: 'object',
|
||||
};
|
||||
|
||||
if (properties && Object.keys(properties).length > 0) {
|
||||
schema.properties = properties;
|
||||
}
|
||||
|
||||
if (definition.additionalProperties) {
|
||||
schema.additionalProperties = buildCollectionSchema(
|
||||
definition.additionalProperties,
|
||||
[...pathSegments, '<additionalProperties>'],
|
||||
defs,
|
||||
);
|
||||
} else if (!definition.properties) {
|
||||
schema.additionalProperties = true;
|
||||
} else {
|
||||
schema.additionalProperties = false;
|
||||
}
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
function buildObjectCollectionSchema(
|
||||
collection: SettingCollectionDefinition,
|
||||
pathSegments: string[],
|
||||
defs: Map<string, JsonSchema>,
|
||||
): JsonSchema {
|
||||
if (collection.properties) {
|
||||
return buildInlineObjectSchema(collection.properties, pathSegments, defs);
|
||||
}
|
||||
return { type: 'object', additionalProperties: true };
|
||||
}
|
||||
|
||||
function buildObjectProperties(
|
||||
properties: SettingsSchema,
|
||||
pathSegments: string[],
|
||||
defs: Map<string, JsonSchema>,
|
||||
): Record<string, JsonSchema> {
|
||||
const result: Record<string, JsonSchema> = {};
|
||||
for (const [childKey, childDefinition] of Object.entries(properties)) {
|
||||
result[childKey] = buildSettingSchema(
|
||||
childDefinition,
|
||||
[...pathSegments, childKey],
|
||||
defs,
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function buildInlineObjectSchema(
|
||||
properties: SettingsSchema,
|
||||
pathSegments: string[],
|
||||
defs: Map<string, JsonSchema>,
|
||||
): JsonSchema {
|
||||
const childSchemas = buildObjectProperties(properties, pathSegments, defs);
|
||||
return {
|
||||
type: 'object',
|
||||
properties: childSchemas,
|
||||
additionalProperties: false,
|
||||
};
|
||||
}
|
||||
|
||||
function buildRefSchema(
|
||||
ref: string,
|
||||
defs: Map<string, JsonSchema>,
|
||||
): JsonSchema {
|
||||
ensureDefinition(ref, defs);
|
||||
return { $ref: `#/$defs/${ref}` };
|
||||
}
|
||||
|
||||
function isSettingDefinition(
|
||||
source: SettingDefinition | SettingCollectionDefinition,
|
||||
): source is SettingDefinition {
|
||||
return 'label' in source;
|
||||
}
|
||||
|
||||
function buildMarkdownDescription(definition: SettingDefinition): string {
|
||||
const lines: string[] = [];
|
||||
|
||||
if (definition.description?.trim()) {
|
||||
lines.push(definition.description.trim());
|
||||
} else {
|
||||
lines.push('Description not provided.');
|
||||
}
|
||||
|
||||
lines.push('');
|
||||
lines.push(`- Category: \`${definition.category}\``);
|
||||
lines.push(
|
||||
`- Requires restart: \`${definition.requiresRestart ? 'yes' : 'no'}\``,
|
||||
);
|
||||
|
||||
if (definition.default !== undefined) {
|
||||
lines.push(`- Default: \`${formatDefaultValue(definition.default)}\``);
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
function inferTypeFromValues(
|
||||
values: Array<string | number>,
|
||||
): string | undefined {
|
||||
if (values.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (values.every((value) => typeof value === 'string')) {
|
||||
return 'string';
|
||||
}
|
||||
if (values.every((value) => typeof value === 'number')) {
|
||||
return 'number';
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function ensureDefinition(ref: string, defs: Map<string, JsonSchema>): void {
|
||||
if (defs.has(ref)) {
|
||||
return;
|
||||
}
|
||||
const predefined = SETTINGS_SCHEMA_DEFINITIONS[ref] as
|
||||
| SettingsJsonSchemaDefinition
|
||||
| undefined;
|
||||
if (predefined) {
|
||||
defs.set(ref, predefined as JsonSchema);
|
||||
} else {
|
||||
defs.set(ref, { description: `Definition for ${ref}` });
|
||||
}
|
||||
}
|
||||
|
||||
if (process.argv[1]) {
|
||||
const entryUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
||||
if (entryUrl === import.meta.url) {
|
||||
await main();
|
||||
}
|
||||
}
|
||||
16
scripts/tests/generate-settings-doc.test.ts
Normal file
16
scripts/tests/generate-settings-doc.test.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { main as generateDocs } from '../generate-settings-doc.ts';
|
||||
|
||||
describe('generate-settings-doc', () => {
|
||||
it('keeps documentation in sync in check mode', async () => {
|
||||
const previousExitCode = process.exitCode;
|
||||
await expect(generateDocs(['--check'])).resolves.toBeUndefined();
|
||||
expect(process.exitCode).toBe(previousExitCode);
|
||||
});
|
||||
});
|
||||
16
scripts/tests/generate-settings-schema.test.ts
Normal file
16
scripts/tests/generate-settings-schema.test.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { main as generateSchema } from '../generate-settings-schema.ts';
|
||||
|
||||
describe('generate-settings-schema', () => {
|
||||
it('keeps schema in sync in check mode', async () => {
|
||||
const previousExitCode = process.exitCode;
|
||||
await expect(generateSchema(['--check'])).resolves.toBeUndefined();
|
||||
expect(process.exitCode).toBe(previousExitCode);
|
||||
});
|
||||
});
|
||||
@@ -10,7 +10,7 @@ export default defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'node',
|
||||
include: ['scripts/tests/**/*.test.js'],
|
||||
include: ['scripts/tests/**/*.test.{js,ts}'],
|
||||
setupFiles: ['scripts/tests/test-setup.ts'],
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
|
||||
83
scripts/utils/autogen.ts
Normal file
83
scripts/utils/autogen.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import prettier from 'prettier';
|
||||
|
||||
export async function formatWithPrettier(content: string, filePath: string) {
|
||||
const options = await prettier.resolveConfig(filePath);
|
||||
return prettier.format(content, {
|
||||
...options,
|
||||
filepath: filePath,
|
||||
});
|
||||
}
|
||||
|
||||
export function normalizeForCompare(content: string): string {
|
||||
return content.replace(/\r\n/g, '\n').trimEnd();
|
||||
}
|
||||
|
||||
export function escapeBackticks(value: string): string {
|
||||
return value.replace(/\\/g, '\\\\').replace(/`/g, '\\`');
|
||||
}
|
||||
|
||||
export interface FormatDefaultValueOptions {
|
||||
/**
|
||||
* When true, string values are JSON-stringified, including surrounding quotes.
|
||||
* Defaults to false to return raw string content.
|
||||
*/
|
||||
quoteStrings?: boolean;
|
||||
}
|
||||
|
||||
export function formatDefaultValue(
|
||||
value: unknown,
|
||||
options: FormatDefaultValueOptions = {},
|
||||
): string {
|
||||
const { quoteStrings = false } = options;
|
||||
|
||||
if (value === undefined) {
|
||||
return 'undefined';
|
||||
}
|
||||
|
||||
if (value === null) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return quoteStrings ? JSON.stringify(value) : value;
|
||||
}
|
||||
|
||||
if (typeof value === 'number' || typeof value === 'boolean') {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
if (value.length === 0) {
|
||||
return '[]';
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(value);
|
||||
} catch {
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof value === 'object') {
|
||||
try {
|
||||
const json = JSON.stringify(value);
|
||||
if (json === '{}') {
|
||||
return '{}';
|
||||
}
|
||||
return json;
|
||||
} catch {
|
||||
return '[object Object]';
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.stringify(value);
|
||||
} catch {
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user