Sweep every first-party crate source (1956 .rs files) to the project comment guidelines: delete redundant restatements, decorative banners, change narration, and end-of-line comments; keep and tighten the crucial ones (invariants, bug rationale, SAFETY blocks, ported-source attribution). No functional code changed. Every edit is proven comment-only against the prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a separate doctest-fence check. Where removing a comment made rustfmt or clippy want to re-lay-out adjacent code, the minimal triggering comment is restored so code tokens stay byte-identical. Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy --workspace --all-targets (0 warnings). Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for these guidelines (flags banners, end-of-line comments, change narration, and commented-out code).
1229 lines
48 KiB
Rust
1229 lines
48 KiB
Rust
//! Default settings catalog — declares every user-tunable preference
|
|
//! registered in the settings modal.
|
|
//!
|
|
//! Defaults come from `UiConfig::default()` for SHELL/SHARED settings.
|
|
//! The `defaults_match_ui_config_default` test enforces this.
|
|
|
|
use super::registry::{
|
|
DynamicEnumSource, EnumChoice, SettingCategory, SettingKind, SettingMeta, SettingOwner,
|
|
};
|
|
use crate::appearance::ScrollMode;
|
|
use crate::appearance::TextSelection;
|
|
use crate::appearance::permission_cursor::DefaultSelectedPermission;
|
|
|
|
use kigi_shell::agent::config::UiConfig;
|
|
use kigi_tools::implementations::kigi::ask_user_question;
|
|
|
|
// Int bounds for `max_thoughts_width`.
|
|
//
|
|
// Stored as `u16` in `UiConfig`, exposed as `i64` for registry uniformity.
|
|
// 40 = min readable width on 80-col terminal; 500 = max before
|
|
// "obviously wrong" territory. `pub(crate)` so the dispatcher's clamp
|
|
// and the shell helper's defensive clamp share these bounds.
|
|
pub(crate) const MAX_THOUGHTS_WIDTH_MIN: i64 = 40;
|
|
pub(crate) const MAX_THOUGHTS_WIDTH_MAX: i64 = 500;
|
|
|
|
/// Registry key for `max_thoughts_width`. Shared between the registry
|
|
/// definition and the live-wrap-preview gate in the int stepper.
|
|
pub(crate) const MAX_THOUGHTS_WIDTH_KEY: &str = "max_thoughts_width";
|
|
|
|
// Theme choice catalogs.
|
|
//
|
|
// Canonical names MUST match `ThemeKind::display_name()`.
|
|
// Shared by `theme`, `auto_dark_theme`, and `auto_light_theme`;
|
|
// auto-* sub-pickers drop "auto" to avoid circular reference.
|
|
// Bounded by `MAX_PICKER_CHOICES`.
|
|
|
|
/// Full theme catalog including the "auto" meta-variant. Used by `theme` only.
|
|
const THEME_CHOICES: &[EnumChoice] = &[
|
|
EnumChoice {
|
|
canonical: "auto",
|
|
display: "Auto",
|
|
description: "Follow system dark/light appearance.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "kiginight",
|
|
display: "Kigi Night",
|
|
description: "Neutral dark with magenta accent.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "kigiday",
|
|
display: "Kigi Day",
|
|
description: "Light theme for bright environments.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "tokyonight",
|
|
display: "Tokyo Night",
|
|
description: "Dark + blue-tinted; needs truecolor.",
|
|
},
|
|
// ASCII "Rose Pine Moon" (not "Rosé") for cross-terminal compatibility.
|
|
EnumChoice {
|
|
canonical: "rosepine-moon",
|
|
display: "Rose Pine Moon",
|
|
description: "Muted dark with mauve accents; needs truecolor.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "oscura-midnight",
|
|
display: "Oscura Midnight",
|
|
description: "Deep dark with warm accents; needs truecolor.",
|
|
},
|
|
];
|
|
|
|
// Permission-mode catalog.
|
|
//
|
|
// Persisted values map onto runtime flags:
|
|
// "always-approve" ↔ yolo_mode = true (auto-approve all)
|
|
// "auto" ↔ auto_mode = true (LLM classifier; not full yolo)
|
|
// "ask" ↔ both false (interactive prompts)
|
|
// "default" ↔ both false (agent's default — currently Ask)
|
|
//
|
|
// Canonical strings match `load_permission_mode`. `supports_preview:
|
|
// false` because toggling YOLO drains the permission queue (unsafe
|
|
// for per-keystroke preview).
|
|
//
|
|
// Adding new modes requires: (1) `PermissionModeKind` variant,
|
|
// (2) `EnumChoice` here, (3) `set_yolo_mode_inner` update,
|
|
// (4) `load_permission_mode` arm, (5) tests. `Plan` is excluded —
|
|
// it lives on its own `plan_mode` setting.
|
|
|
|
// Choice order: safe → classifier → unsafe (Default → Ask → Auto → Always approve).
|
|
// "Always approve" at the end creates a speed bump against
|
|
// accidental selection.
|
|
const PERMISSION_MODE_CHOICES: &[EnumChoice] = &[
|
|
// "default" = agent's default behavior. Same as "ask" at runtime;
|
|
// distinct on disk and in the modal indicator.
|
|
EnumChoice {
|
|
canonical: "default",
|
|
display: "Default",
|
|
description: "Use the agent's default permission behavior (currently equivalent to Ask).",
|
|
},
|
|
EnumChoice {
|
|
canonical: "ask",
|
|
display: "Ask",
|
|
description: "Prompt for permission before tool actions.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "auto",
|
|
display: "Auto",
|
|
description: "LLM classifier approves safe tools; dangerous actions may still prompt or deny.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "always-approve",
|
|
display: "Always approve",
|
|
description: "Auto-approve every tool action. Skips ALL permission prompts.",
|
|
},
|
|
];
|
|
|
|
// Default-selected-permission catalog.
|
|
//
|
|
// Persisted to `[ui].default_selected_permission` in config.toml. Controls
|
|
// which row the cursor preselects on the FIRST permission prompt of a
|
|
// session; after the user confirms any prompt, the cursor sticks to the
|
|
// last-used option kind. `always_allow_all_sessions` (the effective default)
|
|
// lands the cursor on the "Always allow on all sessions" / enable-always-approve
|
|
// row explicitly, via `is_enable_always_approve_option` — not via index 0; the
|
|
// other three map onto `acp::PermissionOptionKind::{AllowOnce, AllowAlways,
|
|
// Reject*}`.
|
|
//
|
|
// `supports_preview: false` — permission prompts aren't open in the modal
|
|
// background, so there's no live preview surface.
|
|
//
|
|
// Order matches the live permission prompt rendering (YOLO -> always-allow
|
|
// -> allow-once -> reject) so the picker mirrors what the user sees on the
|
|
// real prompt.
|
|
// Canonicals + display labels come from `DefaultSelectedPermission` (the
|
|
// single source of truth) so this table can never drift from the parser,
|
|
// the dispatch toast, or the cursor logic.
|
|
const DEFAULT_SELECTED_PERMISSION_CHOICES: &[EnumChoice] = &[
|
|
EnumChoice {
|
|
canonical: DefaultSelectedPermission::AlwaysAllowAllSessions.as_canonical(),
|
|
display: DefaultSelectedPermission::AlwaysAllowAllSessions.display(),
|
|
description: "",
|
|
},
|
|
EnumChoice {
|
|
canonical: DefaultSelectedPermission::AllowCommandAlways.as_canonical(),
|
|
display: DefaultSelectedPermission::AllowCommandAlways.display(),
|
|
description: "",
|
|
},
|
|
EnumChoice {
|
|
canonical: DefaultSelectedPermission::AllowOnce.as_canonical(),
|
|
display: DefaultSelectedPermission::AllowOnce.display(),
|
|
description: "",
|
|
},
|
|
EnumChoice {
|
|
canonical: DefaultSelectedPermission::Reject.as_canonical(),
|
|
display: DefaultSelectedPermission::Reject.display(),
|
|
description: "",
|
|
},
|
|
];
|
|
|
|
// Plan-mode catalog.
|
|
//
|
|
// PAGER-owned, per-session, ACP-mediated via `session/set_mode`.
|
|
// NOT persisted to config.toml — resets every session start.
|
|
//
|
|
// Uses `on`/`off` canonical strings (not the shell's `plan`/`default`
|
|
// wire ids). `Ask` mode is intentionally not exposed here — it's
|
|
// only reachable via Shift+Tab.
|
|
//
|
|
// `supports_preview: false` — toggling fires an ACP request that
|
|
// gates tool dispatch. Commit on Enter only.
|
|
const PLAN_MODE_CHOICES: &[EnumChoice] = &[
|
|
EnumChoice {
|
|
canonical: "off",
|
|
display: "Off",
|
|
description: "Agent runs tools and edits files directly (default).",
|
|
},
|
|
EnumChoice {
|
|
canonical: "on",
|
|
display: "On",
|
|
description: "Agent summarises a plan and asks for approval before running tools.",
|
|
},
|
|
];
|
|
|
|
// Mermaid-rendering catalog.
|
|
//
|
|
// SHELL-owned: persisted to `[ui].render_mermaid`, with a pager-side
|
|
// process-wide cache mirror (`appearance::cache::*_render_mermaid`) for the
|
|
// render hot path. Canonicals match `RenderMermaid::as_canonical`.
|
|
|
|
const RENDER_MERMAID_CHOICES: &[EnumChoice] = &[
|
|
EnumChoice {
|
|
canonical: "auto",
|
|
display: "Auto",
|
|
description: "Show diagrams with a clickable row to open/copy the rendered image.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "on",
|
|
display: "On",
|
|
description: "Same as auto: always show the clickable affordance row.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "off",
|
|
display: "Off",
|
|
description: "Always show the raw Mermaid source as a code block.",
|
|
},
|
|
];
|
|
|
|
// Scroll-input catalog. SHELL-owned, persisted to `[ui].scroll_mode`.
|
|
// Canonical strings match `ScrollMode::as_canonical` (pinned by test).
|
|
const SCROLL_MODE_CHOICES: &[EnumChoice] = &[
|
|
EnumChoice {
|
|
canonical: ScrollMode::Auto.as_canonical(),
|
|
display: "Auto-detect",
|
|
description: "Detect wheel vs trackpad per gesture from event timing. Default.",
|
|
},
|
|
EnumChoice {
|
|
canonical: ScrollMode::Wheel.as_canonical(),
|
|
display: "Mouse wheel",
|
|
description: "Always treat scrolling as wheel notches (fixed lines per tick).",
|
|
},
|
|
EnumChoice {
|
|
canonical: ScrollMode::Trackpad.as_canonical(),
|
|
display: "Trackpad",
|
|
description: "Always treat scrolling as a trackpad (fractional accumulation).",
|
|
},
|
|
];
|
|
|
|
const TEXT_SELECTION_CHOICES: &[EnumChoice] = &[
|
|
EnumChoice {
|
|
canonical: TextSelection::Flash.as_canonical(),
|
|
display: "Flash after copy",
|
|
description: "Brief highlight on mouse-up, then clear. Double-click toggles fold. Default.",
|
|
},
|
|
EnumChoice {
|
|
canonical: TextSelection::Hold.as_canonical(),
|
|
display: "Hold until dismissed",
|
|
description: "Keep the selection visible until Esc, click, or scroll. Double-click toggles fold.",
|
|
},
|
|
EnumChoice {
|
|
canonical: TextSelection::WordSelect.as_canonical(),
|
|
display: "Word select (terminal-like)",
|
|
description: "Double-click selects & copies a word, triple-click a line; selection stays until dismissed.",
|
|
},
|
|
];
|
|
|
|
// Hunk-tracker-mode catalog. SHELL-owned, persisted to `[ui].hunk_tracker_mode`.
|
|
// `disabled` is accepted as an alias for `off` at parse time but not surfaced
|
|
// as a choice.
|
|
const HUNK_TRACKER_MODE_CHOICES: &[EnumChoice] = &[
|
|
EnumChoice {
|
|
canonical: "agent_only",
|
|
display: "Agent only",
|
|
description: "Track only files the agent edits (default).",
|
|
},
|
|
EnumChoice {
|
|
canonical: "all_dirty",
|
|
display: "All dirty",
|
|
description: "Track every git-dirty file, including external edits.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "off",
|
|
display: "Off",
|
|
description: "Disable hunk tracking entirely. Also disables LOC tracking.",
|
|
},
|
|
];
|
|
|
|
const SCREEN_MODE_CHOICES: &[EnumChoice] = &[
|
|
EnumChoice {
|
|
canonical: "fullscreen",
|
|
display: "Fullscreen",
|
|
description: "Open plain kigi in the standard fullscreen TUI. Default when unset.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "minimal",
|
|
display: "Minimal",
|
|
description: "Open plain kigi in scrollback-native (minimal) mode.",
|
|
},
|
|
];
|
|
|
|
/// Concrete-only theme catalog (excludes "auto"). Used by both
|
|
/// `auto_dark_theme` and `auto_light_theme`. No dark/light filtering —
|
|
/// the user can pair any theme with any system-appearance bucket.
|
|
const CONCRETE_THEME_CHOICES: &[EnumChoice] = &[
|
|
EnumChoice {
|
|
canonical: "kiginight",
|
|
display: "Kigi Night",
|
|
description: "Neutral dark with magenta accent.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "kigiday",
|
|
display: "Kigi Day",
|
|
description: "Light theme for bright environments.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "tokyonight",
|
|
display: "Tokyo Night",
|
|
description: "Dark + blue-tinted; needs truecolor.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "rosepine-moon",
|
|
display: "Rose Pine Moon",
|
|
description: "Muted dark with mauve accents; needs truecolor.",
|
|
},
|
|
EnumChoice {
|
|
canonical: "oscura-midnight",
|
|
display: "Oscura Midnight",
|
|
description: "Deep dark with warm accents; needs truecolor.",
|
|
},
|
|
];
|
|
|
|
/// Child settings shown inside the "Show contextual hints" group sub-sheet.
|
|
/// Keys match the `[ui.contextual_hints]` serde fields (namespaced so they stay
|
|
/// globally unique — bare `plan_mode` collides with the plan-mode enum row).
|
|
/// They are registered as normal Bool settings but hidden from the top-level
|
|
/// list (`build_rows` skips any key that is a group child).
|
|
const CONTEXTUAL_HINTS_CHILDREN: &[&str] = &[
|
|
"contextual_hints.undo",
|
|
"contextual_hints.plan_mode",
|
|
"contextual_hints.image_input",
|
|
"contextual_hints.send_now",
|
|
"contextual_hints.small_screen",
|
|
"contextual_hints.word_select",
|
|
];
|
|
|
|
/// Build the catalog. Called once at process start via
|
|
/// `SettingsRegistry::defaults()`.
|
|
pub fn default_settings() -> Vec<SettingMeta> {
|
|
// Shell schema defaults, used as registry source of truth.
|
|
let ui_default = UiConfig::default();
|
|
|
|
vec![
|
|
SettingMeta {
|
|
key: "compact_mode",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shared,
|
|
label: "Compact mode",
|
|
description: "Reduce padding around messages for more content density. \
|
|
Auto-enabled while the terminal is 20 rows or shorter.",
|
|
keywords: &[
|
|
"compact", "density", "padding", "tight", "small", "screen", "auto",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.compact_mode,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
SettingMeta {
|
|
key: "screen_mode",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shell,
|
|
label: "Default screen mode",
|
|
description: "How plain kigi opens next time: Fullscreen (default when unset) or \
|
|
Minimal. Writes [ui] screen_mode in config.toml. Restart required. \
|
|
Switch this session only with /minimal or /fullscreen.",
|
|
keywords: &[
|
|
"screen",
|
|
"mode",
|
|
"minimal",
|
|
"fullscreen",
|
|
"full",
|
|
"scrollback",
|
|
"native",
|
|
"alt-screen",
|
|
"render",
|
|
"default",
|
|
],
|
|
kind: SettingKind::Enum {
|
|
default: "fullscreen",
|
|
choices: SCREEN_MODE_CHOICES,
|
|
supports_preview: false,
|
|
},
|
|
restart_required: true,
|
|
hidden_in_minimal: false,
|
|
},
|
|
SettingMeta {
|
|
key: "show_timestamps",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shared,
|
|
label: "Show timestamps",
|
|
description: "Show clock time next to user messages and agent responses.",
|
|
keywords: &["timestamps", "time", "clock", "date"],
|
|
kind: SettingKind::Bool {
|
|
// `Option<bool>` — `None` treated as `true`.
|
|
default: ui_default.show_timestamps.unwrap_or(true),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
SettingMeta {
|
|
key: "show_timeline",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shared,
|
|
label: "Timeline sidebar",
|
|
description: "Per-turn tick rail in place of the scrollbar: hover previews a turn, click jumps to it.",
|
|
keywords: &["timeline", "sidebar", "ticks", "turns", "navigator", "rail"],
|
|
kind: SettingKind::Bool {
|
|
// Single source: UiConfig::SHOW_TIMELINE_DEFAULT (opt-in).
|
|
default: ui_default.show_timeline_enabled(),
|
|
},
|
|
restart_required: false,
|
|
// Minimal mode has no interactive scrollback pane for the rail.
|
|
hidden_in_minimal: true,
|
|
},
|
|
SettingMeta {
|
|
// Persisted key stays `simple_mode`; the user-facing label
|
|
// distinguishes the PROMPT vim-mode (this setting) from the
|
|
// scrollback `vim_mode` keybindings below.
|
|
key: "simple_mode",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shared,
|
|
label: "Disable vim input mode",
|
|
description: "Use plain readline-style input instead of vim keys in the prompt. Experimental.",
|
|
keywords: &[
|
|
"simple",
|
|
"ascii",
|
|
"minimal",
|
|
"plain",
|
|
"vim",
|
|
"readline",
|
|
"experimental",
|
|
"editor",
|
|
"input",
|
|
"prompt",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
// `Option<bool>` — `None` treated as `true`.
|
|
default: ui_default.simple_mode.unwrap_or(true),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned, persisted to `[ui].vim_mode` in config.toml.
|
|
// Defaults to the same value main's `appearance::persist::VIM_MODE_DEFAULT`
|
|
// shipped with. Bundled next to `simple_mode` because they pair up:
|
|
// simple_mode controls the input editor's vim behaviour,
|
|
// vim_mode controls the scrollback's vim behaviour.
|
|
SettingMeta {
|
|
key: "vim_mode",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shell,
|
|
label: "Vim scrollback navigation",
|
|
description: "Enable vim keys (h/j/k/l, gg/G, /) for navigating the scrollback. Does not affect the input prompt.",
|
|
keywords: &[
|
|
"vim",
|
|
"scrollback",
|
|
"navigation",
|
|
"hjkl",
|
|
"keys",
|
|
"keybindings",
|
|
"scroll",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.vim_mode.unwrap_or(false),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
SettingMeta {
|
|
key: "theme",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shared,
|
|
label: "Theme",
|
|
description: "Color theme for the pager UI.",
|
|
keywords: &[
|
|
"theme",
|
|
"color",
|
|
"colour",
|
|
"palette",
|
|
"appearance",
|
|
"dark",
|
|
"light",
|
|
],
|
|
kind: SettingKind::Enum {
|
|
// `Option<String>` — `None` resolved to "kiginight".
|
|
default: "kiginight",
|
|
choices: THEME_CHOICES,
|
|
supports_preview: true,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: true,
|
|
},
|
|
SettingMeta {
|
|
key: "auto_dark_theme",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shared,
|
|
label: "Auto dark theme",
|
|
description: "Theme to use when the system is in dark mode (only with theme=auto).",
|
|
keywords: &["auto", "dark", "theme", "system", "appearance", "night"],
|
|
kind: SettingKind::Enum {
|
|
// `Option<String>` — `None` falls back to "kiginight".
|
|
default: "kiginight",
|
|
choices: CONCRETE_THEME_CHOICES,
|
|
supports_preview: true,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: true,
|
|
},
|
|
SettingMeta {
|
|
key: "auto_light_theme",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shared,
|
|
label: "Auto light theme",
|
|
description: "Theme to use when the system is in light mode (only with theme=auto).",
|
|
keywords: &["auto", "light", "theme", "system", "appearance", "day"],
|
|
kind: SettingKind::Enum {
|
|
// `Option<String>` — `None` falls back to "kigiday".
|
|
default: "kigiday",
|
|
choices: CONCRETE_THEME_CHOICES,
|
|
supports_preview: true,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: true,
|
|
},
|
|
// SHELL-owned: persisted to `[ui].render_mermaid`, with a pager-side
|
|
// process-wide cache mirror (like `vim_mode`). Default pinned to "auto"
|
|
// by `defaults_match_ui_config_default`.
|
|
SettingMeta {
|
|
key: "render_mermaid",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shell,
|
|
label: "Render Mermaid diagrams",
|
|
description: "How ```mermaid code blocks are shown: auto/on add a clickable row to \
|
|
open the rendered diagram; off shows the raw source.",
|
|
keywords: &[
|
|
"mermaid",
|
|
"diagram",
|
|
"diagrams",
|
|
"render",
|
|
"flowchart",
|
|
"graph",
|
|
"chart",
|
|
],
|
|
kind: SettingKind::Enum {
|
|
default: "auto",
|
|
choices: RENDER_MERMAID_CHOICES,
|
|
supports_preview: false,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// Security-relevant: "always-approve" bypasses all permission prompts.
|
|
// Modal reads live state from `PagerLocalSnapshot.yolo_mode`
|
|
// (not `ui.permission_mode`) to reflect Ctrl+O toggles immediately.
|
|
SettingMeta {
|
|
key: "permission_mode",
|
|
category: SettingCategory::Agent,
|
|
owner: SettingOwner::Shell,
|
|
label: "Permission mode",
|
|
description: "Default uses the agent's built-in behavior; \
|
|
Ask prompts for each tool action; \
|
|
Auto uses an LLM classifier for risky tools; \
|
|
Always approve grants all permissions automatically.",
|
|
keywords: &[
|
|
"permission",
|
|
"approve",
|
|
"yolo",
|
|
"agent",
|
|
"always",
|
|
"ask",
|
|
"auto",
|
|
"classifier",
|
|
"tool",
|
|
"danger",
|
|
],
|
|
kind: SettingKind::Enum {
|
|
default: "ask",
|
|
choices: PERMISSION_MODE_CHOICES,
|
|
supports_preview: false,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned `[ui].remember_tool_approvals`. Gates the per-tool
|
|
// "Always allow …" prompt options. `restart_required` — resolved at
|
|
// permission-manager spawn (also fed by env/requirements/managed/remote settings).
|
|
SettingMeta {
|
|
key: "remember_tool_approvals",
|
|
category: SettingCategory::Agent,
|
|
owner: SettingOwner::Shell,
|
|
label: "Remember tool approvals",
|
|
description: "Show \"Always allow\" options in permission prompts so you can stop \
|
|
being re-asked about a specific command or tool. Applies in ask and \
|
|
auto; Always-approve still skips all prompts. Restart required.",
|
|
keywords: &[
|
|
"permission",
|
|
"approve",
|
|
"approval",
|
|
"always",
|
|
"allow",
|
|
"remember",
|
|
"tool",
|
|
"command",
|
|
"kubectl",
|
|
"ask",
|
|
"again",
|
|
"whitelist",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.remember_tool_approvals.unwrap_or(false),
|
|
},
|
|
restart_required: true,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// PAGER-owned; default pinned by `defaults_match_pager_state`.
|
|
SettingMeta {
|
|
key: "multiline_mode",
|
|
category: SettingCategory::Editor,
|
|
owner: SettingOwner::Pager,
|
|
label: "Multiline",
|
|
description: "When on, Enter inserts a newline and Shift+Enter sends. Resets each session.",
|
|
keywords: &["multiline", "newline", "input", "editor", "enter"],
|
|
kind: SettingKind::Bool { default: false },
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned. Reads from `pager.current_model_name` (not
|
|
// `cfg.models.default`) so the modal reflects `/model` switches.
|
|
// Empty-string default = "no opinion" / use shell's resolution.
|
|
SettingMeta {
|
|
key: "default_model",
|
|
category: SettingCategory::Models,
|
|
owner: SettingOwner::Shell,
|
|
label: "Default model",
|
|
description: "Model used for new sessions. Changing this also switches the active session. Pick `(no override)` to clear.",
|
|
keywords: &["model", "default", "agent", "llm", "kigi", "switch"],
|
|
kind: SettingKind::DynamicEnum {
|
|
default: "",
|
|
source: DynamicEnumSource::ActiveModelCatalog,
|
|
supports_preview: false,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHARED. `u16` in UiConfig, widened to `i64` for registry.
|
|
// Width changes apply on the next render frame.
|
|
SettingMeta {
|
|
key: MAX_THOUGHTS_WIDTH_KEY,
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shared,
|
|
label: "Max thoughts width",
|
|
description: "Column width budget for the agent's thoughts panel (40-500, default 120).",
|
|
keywords: &[
|
|
"thoughts",
|
|
"width",
|
|
"max",
|
|
"thinking",
|
|
"panel",
|
|
"reasoning",
|
|
"columns",
|
|
],
|
|
kind: SettingKind::Int {
|
|
default: ui_default.max_thoughts_width as i64,
|
|
min: MAX_THOUGHTS_WIDTH_MIN,
|
|
max: MAX_THOUGHTS_WIDTH_MAX,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned: `[ui].show_thinking_blocks` + process-wide cache. Default ON.
|
|
SettingMeta {
|
|
key: "show_thinking_blocks",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shell,
|
|
label: "Show thinking blocks",
|
|
description: "Show agent thinking/reasoning blocks in the scrollback while streaming.",
|
|
keywords: &[
|
|
"thinking",
|
|
"reasoning",
|
|
"thoughts",
|
|
"blocks",
|
|
"show",
|
|
"hide",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.show_thinking_blocks.unwrap_or(true),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned: `[ui].prompt_suggestions` + process-wide cache. Default ON.
|
|
// The `KIGI_PROMPT_SUGGESTIONS` env var overrides at runtime.
|
|
SettingMeta {
|
|
key: "prompt_suggestions",
|
|
category: SettingCategory::Editor,
|
|
owner: SettingOwner::Shell,
|
|
label: "Prompt suggestions",
|
|
description: "After each turn, predict your likely next prompt and show it as \
|
|
ghost text in the input (Tab to accept). Uses a small model call \
|
|
per turn.",
|
|
keywords: &[
|
|
"prompt",
|
|
"suggestion",
|
|
"suggestions",
|
|
"autocomplete",
|
|
"ghost",
|
|
"tab",
|
|
"predict",
|
|
"next",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.prompt_suggestions.unwrap_or(true),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// PAGER-owned, persisted to `[scrollback.scroll].respect_manual_folds`
|
|
// in pager.toml (NOT config.toml). Live value is the appearance
|
|
// config (`AppView::set_appearance` fans changes out to every agent);
|
|
// the flag is read at use time, so no restart.
|
|
SettingMeta {
|
|
key: "respect_manual_folds",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Pager,
|
|
label: "Respect manual folds",
|
|
description: "Keep manually folded blocks as-is while streaming and stop \
|
|
auto-scroll when expanding a block. Experimental.",
|
|
keywords: &[
|
|
"fold", "pin", "collapse", "expand", "thinking", "follow", "scroll",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: crate::appearance::ScrollConfig::default().respect_manual_folds,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned: `[ui].group_tool_verbs` + process-wide cache. Default ON.
|
|
SettingMeta {
|
|
key: "group_tool_verbs",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shell,
|
|
label: "Group tool calls",
|
|
description: "Fold consecutive read/search/list tool calls and subagent rows into \
|
|
one summary row; finished thoughts fold into the group too.",
|
|
keywords: &[
|
|
"group", "tool", "verbs", "fold", "collapse", "read", "search", "summary",
|
|
"thinking", "subagent",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.group_tool_verbs.unwrap_or(true),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned: `[ui].collapsed_edit_blocks` + process-wide cache.
|
|
// Default OFF (rollout flag; remote settings / managed config can enable).
|
|
SettingMeta {
|
|
key: "collapsed_edit_blocks",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shell,
|
|
label: "Collapsed edit blocks",
|
|
description: "Show edits as one-line +N/-M diffstat summaries and merge \
|
|
back-to-back edits to the same file into one block; expand a \
|
|
row to see the diffs.",
|
|
keywords: &[
|
|
"edit",
|
|
"edits",
|
|
"diff",
|
|
"diffstat",
|
|
"collapse",
|
|
"collapsed",
|
|
"summary",
|
|
"expand",
|
|
"one-line",
|
|
"merge",
|
|
"coalesce",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.collapsed_edit_blocks.unwrap_or(false),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned: `[ui.display_refresh].auto_cadence_enabled`. Restart-
|
|
// required (cadence pinned at startup); hidden in minimal.
|
|
SettingMeta {
|
|
key: "display_refresh_auto_cadence",
|
|
category: SettingCategory::Appearance,
|
|
owner: SettingOwner::Shell,
|
|
label: "Match display refresh rate",
|
|
description: "On high-refresh displays, the TUI will stream/scroll faster \
|
|
to match the display. Off keeps the classic ~60 Hz cadence. \
|
|
Restart required.",
|
|
keywords: &[
|
|
"display", "refresh", "rate", "hz", "cadence", "fps", "smooth", "scroll", "stream",
|
|
"high", "120", "144",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default
|
|
.display_refresh
|
|
.auto_cadence_enabled
|
|
.unwrap_or(false),
|
|
},
|
|
restart_required: true,
|
|
hidden_in_minimal: true,
|
|
},
|
|
// SHELL-owned, persisted to `[ui].scroll_speed` in config.toml.
|
|
SettingMeta {
|
|
key: "scroll_speed",
|
|
category: SettingCategory::Mouse,
|
|
owner: SettingOwner::Shell,
|
|
label: "Scroll speed",
|
|
description: "Mouse-wheel and trackpad scroll speed multiplier (1-100). Higher = faster.",
|
|
keywords: &[
|
|
"scroll", "speed", "mouse", "wheel", "trackpad", "fast", "slow",
|
|
],
|
|
kind: SettingKind::Int {
|
|
default: ui_default.scroll_speed.unwrap_or(50) as i64,
|
|
min: 1,
|
|
max: 100,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned `auto` | `wheel` | `trackpad` on `[ui].scroll_mode`.
|
|
SettingMeta {
|
|
key: "scroll_mode",
|
|
category: SettingCategory::Mouse,
|
|
owner: SettingOwner::Shell,
|
|
label: "Scroll input",
|
|
description: "Force wheel or trackpad scroll behavior when auto-detection \
|
|
misreads your device.",
|
|
keywords: &[
|
|
"scroll", "mode", "wheel", "trackpad", "mouse", "detect", "force", "input",
|
|
],
|
|
kind: SettingKind::Enum {
|
|
default: ui_default
|
|
.scroll_mode
|
|
.as_deref()
|
|
.and_then(ScrollMode::from_canonical)
|
|
.unwrap_or_default()
|
|
.as_canonical(),
|
|
choices: SCROLL_MODE_CHOICES,
|
|
supports_preview: false,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned, persisted to `[ui].scroll_lines`. One knob for BOTH
|
|
// wheel and trackpad lines-per-tick; the registered default 3 matches
|
|
// most terminal profiles, but until the user first commits a value
|
|
// the per-terminal profile stays in charge (cache unset → no override).
|
|
SettingMeta {
|
|
key: "scroll_lines",
|
|
category: SettingCategory::Mouse,
|
|
owner: SettingOwner::Shell,
|
|
label: "Scroll lines",
|
|
description: "Lines per scroll tick for both wheel and trackpad (1-10). \
|
|
Until set, each terminal's own profile applies.",
|
|
keywords: &[
|
|
"scroll", "lines", "tick", "notch", "wheel", "trackpad", "mouse",
|
|
],
|
|
kind: SettingKind::Int {
|
|
default: ui_default.scroll_lines.map(i64::from).unwrap_or(3),
|
|
min: 1,
|
|
max: 10,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned: `[ui].invert_scroll` + process-wide cache. Default OFF.
|
|
SettingMeta {
|
|
key: "invert_scroll",
|
|
category: SettingCategory::Mouse,
|
|
owner: SettingOwner::Shell,
|
|
label: "Invert scroll",
|
|
description: "Reverse vertical scroll direction (natural scrolling).",
|
|
keywords: &[
|
|
"invert",
|
|
"scroll",
|
|
"natural",
|
|
"direction",
|
|
"reverse",
|
|
"mouse",
|
|
"trackpad",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.invert_scroll.unwrap_or(false),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned `flash` | `hold` on `[ui].keep_text_selection`.
|
|
SettingMeta {
|
|
key: "keep_text_selection",
|
|
category: SettingCategory::Mouse,
|
|
owner: SettingOwner::Shell,
|
|
label: "Text selection",
|
|
description: "How long in-app selection stays on screen and what double-click does (fold vs. select & copy a word). For your terminal or multiplexer's own selection, hold Shift while dragging (native copy).",
|
|
keywords: &[
|
|
"selection",
|
|
"drag",
|
|
"copy",
|
|
"flash",
|
|
"hold",
|
|
"shift",
|
|
"native",
|
|
"mouse",
|
|
"tmux",
|
|
"double",
|
|
"double-click",
|
|
"word",
|
|
"terminal",
|
|
],
|
|
kind: SettingKind::Enum {
|
|
default: TextSelection::Flash.as_canonical(),
|
|
choices: TEXT_SELECTION_CHOICES,
|
|
supports_preview: false,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned, persisted to `[ui].default_selected_permission` in
|
|
// config.toml. Read by the pager via `appearance::permission_cursor`.
|
|
// Canonical `always_allow_all_sessions` (the effective default) lands
|
|
// the first prompt's cursor on the enable-always-approve row;
|
|
// subsequent prompts stick to the last-used kind.
|
|
SettingMeta {
|
|
key: "default_selected_permission",
|
|
category: SettingCategory::Agent,
|
|
owner: SettingOwner::Shell,
|
|
label: "Default selected permission",
|
|
description: "Which row the cursor preselects on permission prompts.",
|
|
keywords: &[
|
|
"permission",
|
|
"approval",
|
|
"cursor",
|
|
"preselect",
|
|
"default",
|
|
"sticky",
|
|
"last",
|
|
"used",
|
|
"yes",
|
|
"no",
|
|
"reject",
|
|
"allow",
|
|
],
|
|
kind: SettingKind::Enum {
|
|
default: DefaultSelectedPermission::AlwaysAllowAllSessions.as_canonical(),
|
|
choices: DEFAULT_SELECTED_PERMISSION_CHOICES,
|
|
supports_preview: false,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned `[toolset.ask_user_question].timeout_enabled`. Surfaces
|
|
// the user-config layer of the tiered timeout gate (requirements/env/
|
|
// managed/remote settings feed the effective value at agent build); the
|
|
// default is the resolver-shared const. `restart_required` — resolved
|
|
// when an agent is built, like `remember_tool_approvals`.
|
|
SettingMeta {
|
|
key: "toolset.ask_user_question.timeout_enabled",
|
|
category: SettingCategory::Agent,
|
|
owner: SettingOwner::Shell,
|
|
label: "Ask-Question timeout",
|
|
description: "When on, the ask_user_question tool will time out after a set period \
|
|
of time instead of infinitely blocking.",
|
|
keywords: &[
|
|
"ask",
|
|
"question",
|
|
"questionnaire",
|
|
"timeout",
|
|
"ask_user_question",
|
|
"block",
|
|
"wait",
|
|
"forever",
|
|
"tool",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: ask_user_question::DEFAULT_ASK_USER_QUESTION_TIMEOUT_ENABLED,
|
|
},
|
|
restart_required: true,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// PAGER-owned, ACP-mediated. Reads from
|
|
// `PagerLocalSnapshot.plan_mode_active`. Default "off" matches
|
|
// `AgentView::new`'s `plan_mode_active = false`.
|
|
SettingMeta {
|
|
key: "plan_mode",
|
|
category: SettingCategory::Agent,
|
|
owner: SettingOwner::Pager,
|
|
label: "Plan mode",
|
|
description: "When on, the agent summarises a plan before running tools or making edits.",
|
|
keywords: &[
|
|
"plan", "mode", "agent", "summary", "approval", "review", "session",
|
|
],
|
|
kind: SettingKind::Enum {
|
|
default: "off",
|
|
choices: PLAN_MODE_CHOICES,
|
|
supports_preview: false,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned startup-time settings (restart_required: true).
|
|
// The running pager doesn't re-read these mid-session.
|
|
SettingMeta {
|
|
key: "show_tips",
|
|
category: SettingCategory::Advanced,
|
|
owner: SettingOwner::Shell,
|
|
label: "Show tips",
|
|
description: "Show the tip-of-the-day banner on startup. Restart required.",
|
|
keywords: &[
|
|
"tips", "tip", "show", "banner", "welcome", "startup", "launch",
|
|
],
|
|
kind: SettingKind::Bool { default: true },
|
|
restart_required: true,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// Contextual hints: one Advanced row that opens a sub-sheet of per-tip
|
|
// toggles. Applies live (restart_required: false); the group carries no
|
|
// value and its children are hidden from the top-level list.
|
|
SettingMeta {
|
|
key: "contextual_hints",
|
|
category: SettingCategory::Advanced,
|
|
owner: SettingOwner::Shell,
|
|
label: "Show contextual hints",
|
|
description: "Show brief, in-context keyboard hints as you work; \
|
|
toggle each one individually.",
|
|
keywords: &[
|
|
"contextual",
|
|
"hints",
|
|
"tips",
|
|
"undo",
|
|
"plan",
|
|
"nudge",
|
|
"image",
|
|
"clipboard",
|
|
"ephemeral",
|
|
"send",
|
|
"interject",
|
|
"queue",
|
|
// Child-specific terms: the per-tip children are hidden from the
|
|
// top-level list, so mirror their search words here to keep a
|
|
// query like "ctrl+z" or "shift+tab" from dead-ending.
|
|
"ctrl+z",
|
|
"draft",
|
|
"wipe",
|
|
"mode",
|
|
"shift+tab",
|
|
"paste",
|
|
"input",
|
|
"enter",
|
|
"follow-up",
|
|
"small",
|
|
"screen",
|
|
"compact",
|
|
],
|
|
kind: SettingKind::Group {
|
|
children: CONTEXTUAL_HINTS_CHILDREN,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
SettingMeta {
|
|
key: "auto_update",
|
|
category: SettingCategory::Advanced,
|
|
owner: SettingOwner::Shell,
|
|
label: "Auto-update",
|
|
description: "Automatically download and install pager updates on startup. \
|
|
Restart required.",
|
|
keywords: &[
|
|
"auto", "update", "updates", "upgrade", "version", "install", "channel",
|
|
],
|
|
kind: SettingKind::Bool { default: true },
|
|
restart_required: true,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// SHELL-owned, persisted to `[ui].hunk_tracker_mode`. Restart-required:
|
|
// the mode is read once when the session connects.
|
|
SettingMeta {
|
|
key: "hunk_tracker_mode",
|
|
category: SettingCategory::Advanced,
|
|
owner: SettingOwner::Shell,
|
|
label: "Hunk tracker",
|
|
description: "Which file changes the agent tracks as hunks. \
|
|
Off disables tracking (and LOC stats) entirely. \
|
|
Restart required.",
|
|
keywords: &[
|
|
"hunk", "tracker", "tracking", "diff", "changes", "git", "loc", "off", "disable",
|
|
],
|
|
kind: SettingKind::Enum {
|
|
default: "agent_only",
|
|
choices: HUNK_TRACKER_MODE_CHOICES,
|
|
supports_preview: false,
|
|
},
|
|
restart_required: true,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// Contextual-hint children (hidden from the top-level list; reached via
|
|
// the group sub-sheet). Default ON — `None` (inherit) reads as `true`.
|
|
SettingMeta {
|
|
key: "contextual_hints.undo",
|
|
category: SettingCategory::Advanced,
|
|
owner: SettingOwner::Shell,
|
|
label: "Undo",
|
|
description: "Remind you that Ctrl+Z restores the prompt after you clear it.",
|
|
keywords: &["undo", "ctrl+z", "draft", "wipe", "hint"],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.contextual_hints.undo.unwrap_or(true),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
SettingMeta {
|
|
key: "contextual_hints.plan_mode",
|
|
category: SettingCategory::Advanced,
|
|
owner: SettingOwner::Shell,
|
|
label: "Plan mode",
|
|
description: "Suggest plan mode (Shift+Tab) when your prompt looks like a \
|
|
planning request.",
|
|
keywords: &["plan", "mode", "nudge", "shift+tab", "hint"],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.contextual_hints.plan_mode.unwrap_or(true),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
SettingMeta {
|
|
key: "contextual_hints.image_input",
|
|
category: SettingCategory::Advanced,
|
|
owner: SettingOwner::Shell,
|
|
label: "Image input",
|
|
description: "Offer to paste an image when one is on the clipboard and the \
|
|
model accepts images.",
|
|
keywords: &["image", "clipboard", "paste", "input", "hint"],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.contextual_hints.image_input.unwrap_or(true),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
SettingMeta {
|
|
key: "contextual_hints.send_now",
|
|
category: SettingCategory::Advanced,
|
|
owner: SettingOwner::Shell,
|
|
label: "Send now",
|
|
description: "After you queue a follow-up mid-turn, remind you that Enter \
|
|
on an empty prompt sends the top queued item now.",
|
|
keywords: &[
|
|
"send",
|
|
"now",
|
|
"interject",
|
|
"queue",
|
|
"follow-up",
|
|
"enter",
|
|
"empty",
|
|
"hint",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.contextual_hints.send_now.unwrap_or(true),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
SettingMeta {
|
|
key: "contextual_hints.small_screen",
|
|
category: SettingCategory::Advanced,
|
|
owner: SettingOwner::Shell,
|
|
label: "Small screen",
|
|
description: "Suggest /compact-mode once per run when the terminal \
|
|
is short on rows.",
|
|
keywords: &["small", "screen", "compact", "space", "rows", "hint"],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.contextual_hints.small_screen.unwrap_or(true),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
SettingMeta {
|
|
key: "contextual_hints.word_select",
|
|
category: SettingCategory::Advanced,
|
|
owner: SettingOwner::Shell,
|
|
label: "Word select",
|
|
description: "After double-clicking conversation text while Text selection \
|
|
is fold/nav, remind you that Word select lives in Settings.",
|
|
keywords: &[
|
|
"word",
|
|
"select",
|
|
"double",
|
|
"double-click",
|
|
"click",
|
|
"fold",
|
|
"selection",
|
|
"settings",
|
|
"hint",
|
|
],
|
|
kind: SettingKind::Bool {
|
|
default: ui_default.contextual_hints.word_select.unwrap_or(true),
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
// TodoGate (runtime turn-end backstop):
|
|
//
|
|
// Only the CLI flag (`--todo-gate`) is wired. Settings-modal
|
|
// entries for `[reminder.todo_gate]` are deferred — the modal
|
|
// dispatcher requires per-key action arms in
|
|
// `settings_modal.rs` + `app/dispatch.rs` + `settings/registry.rs`
|
|
// that don't yet have a place to land.
|
|
// SHELL-owned. `restart_required: false` — the config-reloader
|
|
// rebroadcasts UI changes; mid-session forks pick up new values.
|
|
// Empty-string default = "no opinion" / use shell's resolution.
|
|
SettingMeta {
|
|
key: "fork_secondary_model",
|
|
category: SettingCategory::Models,
|
|
owner: SettingOwner::Shell,
|
|
label: "Fork secondary model",
|
|
description: "Model used for the secondary agent when forking. Pick `(no override)` to clear.",
|
|
keywords: &[
|
|
"fork",
|
|
"secondary",
|
|
"model",
|
|
"agent",
|
|
"subagent",
|
|
"branch",
|
|
"models",
|
|
],
|
|
kind: SettingKind::DynamicEnum {
|
|
default: "",
|
|
source: DynamicEnumSource::ActiveModelCatalog,
|
|
supports_preview: false,
|
|
},
|
|
restart_required: false,
|
|
hidden_in_minimal: false,
|
|
},
|
|
]
|
|
}
|