import type { Accessor } from "solid-js" import type { Preferences, ExpansionPreference, ToolInputsVisibilityPreference, } from "../../stores/preferences" import type { Command } from "../commands" import { tGlobal } from "../i18n" import { runtimeEnv } from "../runtime-env" export type BehaviorSettingKind = "toggle" | "enum" export type BehaviorToggleSetting = { kind: "toggle" id: string titleKey: string subtitleKey: string get: (preferences: Preferences) => boolean set: (next: boolean) => void disabled?: () => boolean } export type BehaviorEnumSetting = { kind: "enum" id: string titleKey: string subtitleKey: string get: (preferences: Preferences) => T set: (next: T) => void options: Array<{ value: T; labelKey: string }> disabled?: () => boolean } export type BehaviorSetting = BehaviorToggleSetting | BehaviorEnumSetting export type BehaviorRegistryActions = { preferences: Accessor updatePreferences?: (updates: Partial) => void toggleShowThinkingBlocks: () => void toggleKeyboardShortcutHints: () => void toggleShowTimelineTools: () => void toggleUsageMetrics: () => void toggleAutoCleanupBlankSessions: () => void togglePromptSubmitOnEnter: () => void setDiffViewMode: (mode: "split" | "unified") => void setToolOutputExpansion: (mode: ExpansionPreference) => void setDiagnosticsExpansion: (mode: ExpansionPreference) => void setThinkingBlocksExpansion: (mode: ExpansionPreference) => void setToolInputsVisibility: (mode: ToolInputsVisibilityPreference) => void } function splitKeywords(key: string): string[] { return tGlobal(key) .split(",") .map((value) => value.trim()) .filter(Boolean) } function setBooleanByToggle(getCurrent: () => boolean, toggle: () => void, next: boolean) { if (getCurrent() === next) return toggle() } export function getBehaviorSettings(actions: BehaviorRegistryActions): BehaviorSetting[] { const prefs = actions.preferences const updatePreferences = actions.updatePreferences return [ { kind: "toggle", id: "behavior.keyboardShortcutHints", titleKey: "settings.behavior.keyboardHints.title", subtitleKey: "settings.behavior.keyboardHints.subtitle", get: (p) => Boolean(p.showKeyboardShortcutHints ?? true), set: (next) => { if (updatePreferences) { updatePreferences({ showKeyboardShortcutHints: next }) return } setBooleanByToggle( () => Boolean(prefs().showKeyboardShortcutHints ?? true), actions.toggleKeyboardShortcutHints, next, ) }, disabled: () => runtimeEnv.host === "web", }, { kind: "toggle", id: "behavior.thinkingBlocks", titleKey: "settings.behavior.thinking.title", subtitleKey: "settings.behavior.thinking.subtitle", get: (p) => Boolean(p.showThinkingBlocks), set: (next) => { if (updatePreferences) { updatePreferences({ showThinkingBlocks: next }) return } setBooleanByToggle( () => Boolean(prefs().showThinkingBlocks), actions.toggleShowThinkingBlocks, next, ) }, }, { kind: "enum", id: "behavior.thinkingBlocksDefault", titleKey: "settings.behavior.thinkingDefault.title", subtitleKey: "settings.behavior.thinkingDefault.subtitle", get: (p) => (p.thinkingBlocksExpansion ?? "expanded") as ExpansionPreference, set: (next) => { if (updatePreferences) { updatePreferences({ thinkingBlocksExpansion: next as ExpansionPreference }) return } actions.setThinkingBlocksExpansion(next as ExpansionPreference) }, options: [ { value: "expanded", labelKey: "commands.common.expanded" }, { value: "collapsed", labelKey: "commands.common.collapsed" }, ], }, { kind: "toggle", id: "behavior.timelineToolCalls", titleKey: "settings.behavior.timelineTools.title", subtitleKey: "settings.behavior.timelineTools.subtitle", get: (p) => Boolean(p.showTimelineTools), set: (next) => { if (updatePreferences) { updatePreferences({ showTimelineTools: next }) return } setBooleanByToggle( () => Boolean(prefs().showTimelineTools), actions.toggleShowTimelineTools, next, ) }, }, { kind: "enum", id: "behavior.diffViewMode", titleKey: "settings.behavior.diffView.title", subtitleKey: "settings.behavior.diffView.subtitle", get: (p) => (p.diffViewMode ?? "split") as "split" | "unified", set: (next) => { if (updatePreferences) { updatePreferences({ diffViewMode: next as "split" | "unified" }) return } actions.setDiffViewMode(next as "split" | "unified") }, options: [ { value: "split", labelKey: "settings.behavior.diffView.option.split" }, { value: "unified", labelKey: "settings.behavior.diffView.option.unified" }, ], }, { kind: "enum", id: "behavior.toolOutputsDefault", titleKey: "settings.behavior.toolOutputsDefault.title", subtitleKey: "settings.behavior.toolOutputsDefault.subtitle", get: (p) => (p.toolOutputExpansion ?? "expanded") as ExpansionPreference, set: (next) => { if (updatePreferences) { updatePreferences({ toolOutputExpansion: next as ExpansionPreference }) return } actions.setToolOutputExpansion(next as ExpansionPreference) }, options: [ { value: "expanded", labelKey: "commands.common.expanded" }, { value: "collapsed", labelKey: "commands.common.collapsed" }, ], }, { kind: "enum", id: "behavior.diagnosticsDefault", titleKey: "settings.behavior.diagnosticsDefault.title", subtitleKey: "settings.behavior.diagnosticsDefault.subtitle", get: (p) => (p.diagnosticsExpansion ?? "expanded") as ExpansionPreference, set: (next) => { if (updatePreferences) { updatePreferences({ diagnosticsExpansion: next as ExpansionPreference }) return } actions.setDiagnosticsExpansion(next as ExpansionPreference) }, options: [ { value: "expanded", labelKey: "commands.common.expanded" }, { value: "collapsed", labelKey: "commands.common.collapsed" }, ], }, { kind: "enum", id: "behavior.toolInputsVisibility", titleKey: "settings.behavior.toolInputsVisibility.title", subtitleKey: "settings.behavior.toolInputsVisibility.subtitle", get: (p) => (p.toolInputsVisibility ?? "hidden") as ToolInputsVisibilityPreference, set: (next) => { if (updatePreferences) { updatePreferences({ toolInputsVisibility: next as ToolInputsVisibilityPreference }) return } actions.setToolInputsVisibility(next as ToolInputsVisibilityPreference) }, options: [ { value: "hidden", labelKey: "commands.common.hidden" }, { value: "collapsed", labelKey: "commands.common.collapsed" }, { value: "expanded", labelKey: "commands.common.expanded" }, ], }, { kind: "toggle", id: "behavior.usageMetrics", titleKey: "settings.behavior.usageMetrics.title", subtitleKey: "settings.behavior.usageMetrics.subtitle", get: (p) => Boolean(p.showUsageMetrics ?? true), set: (next) => { if (updatePreferences) { updatePreferences({ showUsageMetrics: next }) return } setBooleanByToggle( () => Boolean(prefs().showUsageMetrics ?? true), actions.toggleUsageMetrics, next, ) }, }, { kind: "toggle", id: "behavior.autoCleanupBlankSessions", titleKey: "settings.behavior.autoCleanup.title", subtitleKey: "settings.behavior.autoCleanup.subtitle", get: (p) => Boolean(p.autoCleanupBlankSessions), set: (next) => { if (updatePreferences) { updatePreferences({ autoCleanupBlankSessions: next }) return } setBooleanByToggle( () => Boolean(prefs().autoCleanupBlankSessions), actions.toggleAutoCleanupBlankSessions, next, ) }, }, { kind: "toggle", id: "behavior.promptSubmitOnEnter", titleKey: "settings.behavior.promptSubmit.title", subtitleKey: "settings.behavior.promptSubmit.subtitle", get: (p) => Boolean(p.promptSubmitOnEnter), set: (next) => { if (updatePreferences) { updatePreferences({ promptSubmitOnEnter: next }) return } setBooleanByToggle( () => Boolean(prefs().promptSubmitOnEnter), actions.togglePromptSubmitOnEnter, next, ) }, }, ] } export function getBehaviorCommands(actions: BehaviorRegistryActions): Command[] { return [ { id: "prompt-submit-shortcut", label: () => actions.preferences().promptSubmitOnEnter ? tGlobal("commands.promptSubmitShortcut.label.swapped") : tGlobal("commands.promptSubmitShortcut.label.default"), description: () => tGlobal("commands.promptSubmitShortcut.description"), category: "Input & Focus", keywords: () => splitKeywords("commands.promptSubmitShortcut.keywords"), action: actions.togglePromptSubmitOnEnter, }, { id: "thinking", label: () => tGlobal( actions.preferences().showThinkingBlocks ? "commands.thinkingBlocks.label.hide" : "commands.thinkingBlocks.label.show", ), description: () => tGlobal("commands.thinkingBlocks.description"), category: "System", keywords: () => ["/thinking", ...splitKeywords("commands.thinkingBlocks.keywords")], action: actions.toggleShowThinkingBlocks, }, { id: "timeline-tools", label: () => tGlobal( actions.preferences().showTimelineTools ? "commands.timelineToolCalls.label.hide" : "commands.timelineToolCalls.label.show", ), description: () => tGlobal("commands.timelineToolCalls.description"), category: "System", keywords: () => splitKeywords("commands.timelineToolCalls.keywords"), action: actions.toggleShowTimelineTools, }, { id: "keyboard-shortcut-hints", label: () => tGlobal( actions.preferences().showKeyboardShortcutHints ? "commands.keyboardShortcutHints.label.hide" : "commands.keyboardShortcutHints.label.show", ), description: () => tGlobal( runtimeEnv.host === "web" ? "commands.keyboardShortcutHints.description.disabledWeb" : "commands.keyboardShortcutHints.description", ), category: "System", keywords: () => splitKeywords("commands.keyboardShortcutHints.keywords"), disabled: () => runtimeEnv.host === "web", action: actions.toggleKeyboardShortcutHints, }, { id: "thinking-default-visibility", label: () => { const mode = actions.preferences().thinkingBlocksExpansion ?? "expanded" const state = mode === "expanded" ? tGlobal("commands.common.expanded") : tGlobal("commands.common.collapsed") return tGlobal("commands.thinkingBlocksDefault.label", { state }) }, description: () => tGlobal("commands.thinkingBlocksDefault.description"), category: "System", keywords: () => ["/thinking", ...splitKeywords("commands.thinkingBlocksDefault.keywords")], action: () => { const mode = actions.preferences().thinkingBlocksExpansion ?? "expanded" const next: ExpansionPreference = mode === "expanded" ? "collapsed" : "expanded" actions.setThinkingBlocksExpansion(next) }, }, { id: "diff-view-split", label: () => { const prefix = (actions.preferences().diffViewMode || "split") === "split" ? "✓ " : "" return `${prefix}${tGlobal("commands.diffViewSplit.label")}` }, description: () => tGlobal("commands.diffViewSplit.description"), category: "System", keywords: () => splitKeywords("commands.diffViewSplit.keywords"), action: () => actions.setDiffViewMode("split"), }, { id: "diff-view-unified", label: () => { const prefix = (actions.preferences().diffViewMode || "split") === "unified" ? "✓ " : "" return `${prefix}${tGlobal("commands.diffViewUnified.label")}` }, description: () => tGlobal("commands.diffViewUnified.description"), category: "System", keywords: () => splitKeywords("commands.diffViewUnified.keywords"), action: () => actions.setDiffViewMode("unified"), }, { id: "tool-output-default-visibility", label: () => { const mode = actions.preferences().toolOutputExpansion || "expanded" const state = mode === "expanded" ? tGlobal("commands.common.expanded") : tGlobal("commands.common.collapsed") return tGlobal("commands.toolOutputsDefault.label", { state }) }, description: () => tGlobal("commands.toolOutputsDefault.description"), category: "System", keywords: () => splitKeywords("commands.toolOutputsDefault.keywords"), action: () => { const mode = actions.preferences().toolOutputExpansion || "expanded" const next: ExpansionPreference = mode === "expanded" ? "collapsed" : "expanded" actions.setToolOutputExpansion(next) }, }, { id: "diagnostics-default-visibility", label: () => { const mode = actions.preferences().diagnosticsExpansion || "expanded" const state = mode === "expanded" ? tGlobal("commands.common.expanded") : tGlobal("commands.common.collapsed") return tGlobal("commands.diagnosticsDefault.label", { state }) }, description: () => tGlobal("commands.diagnosticsDefault.description"), category: "System", keywords: () => splitKeywords("commands.diagnosticsDefault.keywords"), action: () => { const mode = actions.preferences().diagnosticsExpansion || "expanded" const next: ExpansionPreference = mode === "expanded" ? "collapsed" : "expanded" actions.setDiagnosticsExpansion(next) }, }, { id: "tool-inputs-visibility", label: () => { const mode = actions.preferences().toolInputsVisibility || "hidden" const state = mode === "expanded" ? tGlobal("commands.common.expanded") : mode === "collapsed" ? tGlobal("commands.common.collapsed") : tGlobal("commands.common.hidden") return tGlobal("commands.toolInputsVisibility.label", { state }) }, description: () => tGlobal("commands.toolInputsVisibility.description"), category: "System", keywords: () => splitKeywords("commands.toolInputsVisibility.keywords"), action: () => { const mode = actions.preferences().toolInputsVisibility || "hidden" const next: ToolInputsVisibilityPreference = mode === "hidden" ? "collapsed" : mode === "collapsed" ? "expanded" : "hidden" actions.setToolInputsVisibility(next) }, }, { id: "token-usage-visibility", label: () => { const visible = actions.preferences().showUsageMetrics ?? true const state = visible ? tGlobal("commands.common.visible") : tGlobal("commands.common.hidden") return tGlobal("commands.tokenUsageDisplay.label", { state }) }, description: () => tGlobal("commands.tokenUsageDisplay.description"), category: "System", keywords: () => splitKeywords("commands.tokenUsageDisplay.keywords"), action: actions.toggleUsageMetrics, }, { id: "auto-cleanup-blank-sessions", label: () => { const enabled = actions.preferences().autoCleanupBlankSessions const state = enabled ? tGlobal("commands.common.enabled") : tGlobal("commands.common.disabled") return tGlobal("commands.autoCleanupBlankSessions.label", { state }) }, description: () => tGlobal("commands.autoCleanupBlankSessions.description"), category: "System", keywords: () => splitKeywords("commands.autoCleanupBlankSessions.keywords"), action: actions.toggleAutoCleanupBlankSessions, }, ] } export function registerBehaviorCommands(register: (command: Command) => void, actions: BehaviorRegistryActions) { const commands = getBehaviorCommands(actions) commands.forEach((command) => register(command)) }