514 lines · 16.2 KB · TypeScript
RawDownload
import { isElectron } from "~/env";import { isMacPlatform, isWindowsPlatform, normalizeSearchText } from "~/lib/utils"; export type SettingsPath =  | "/settings/general"  | "/settings/appearance"  | "/settings/keybindings"  | "/settings/providers"  | "/settings/integrations"  | "/settings/source-control"  | "/settings/connections"  | "/settings/archived"; export interface SettingsSearchItem {  readonly id: string;  readonly title: string;  readonly to: SettingsPath;  readonly targetId?: string;  /** Descriptions, option labels, and aliases people may remember instead of the title. */  readonly searchTerms?: ReadonlyArray<string>;  // Its row only renders in the desktop app, so a browser result would land on  // an anchor that isn't there.  readonly desktopOnly?: boolean;  readonly macOnly?: boolean;  // Its row only renders on Windows desktop, so other desktop platforms must  // not expose a result that points to a missing anchor.  readonly windowsOnly?: boolean;  readonly cloudOnly?: boolean;  readonly primaryOnly?: boolean;  readonly providerSettingsOnly?: boolean;  readonly localBackendManagementOnly?: boolean;  readonly wslAvailableOnly?: boolean;  readonly requiresThreadAutoSettlement?: boolean;} export interface SettingsSearchAvailability {  readonly hasCloudPublicConfig: boolean;  readonly hasPrimaryEnvironment: boolean;  readonly hasProviderSettingsEnvironment: boolean;  readonly canManageLocalBackend: boolean;  readonly isWslSettingsRowVisible: boolean;  readonly hasThreadAutoSettlement: boolean;} /** * Section labels in sidebar order. The sidebar nav and the search-result * subtitles both render from this record, so each label exists once. */export const SETTINGS_SECTION_LABELS: Readonly<Record<SettingsPath, string>> = {  "/settings/general": "General",  "/settings/appearance": "Appearance",  "/settings/keybindings": "Keybindings",  "/settings/providers": "Providers",  "/settings/integrations": "Integrations",  "/settings/source-control": "Source Control",  "/settings/connections": "Connections",  "/settings/archived": "Archive",}; /** * Searchable settings and stable destinations, in result order. Rows with a * dedicated anchor render their id and title via `searchableSetting`; items * that may not be mounted point at their nearest stable section instead. */export const SETTINGS_SEARCH_ITEMS = [  {    id: "color-scheme",    title: "Color scheme",    to: "/settings/appearance",    searchTerms: ["appearance light dark system mode"],    // The scheme tiles sit at the top of the Appearance section.    targetId: "appearance",  },  {    id: "theme",    title: "Themes",    to: "/settings/appearance",    searchTerms: ["appearance colors palette custom import"],    // Theme cards live directly under the scheme tiles; the section is the    // stable scroll destination for both.    targetId: "appearance",  },  {    // Prefixed because the slider control already owns the `appearance-contrast` id.    id: "setting-appearance-contrast",    title: "Contrast",    to: "/settings/appearance",    searchTerms: ["colors borders interface"],  },  {    // Prefixed because the slider control already owns the `glass-opacity` id.    id: "setting-glass-opacity",    title: "Glass opacity",    to: "/settings/appearance",    searchTerms: ["transparent transparency solid menus dialogs composer"],  },  {    id: "environment-identification",    title: "Environment identification",    to: "/settings/appearance",    searchTerms: ["dev nightly artwork pill label hide none"],    // The setting is stage-dependent, so its parent section is the stable destination.    targetId: "appearance",  },  {    id: "interface-font",    title: "Interface font",    to: "/settings/appearance",    searchTerms: ["typography family size system sans"],  },  {    id: "prompt-font",    title: "Prompt font",    to: "/settings/appearance",    searchTerms: ["typography family size composer input"],  },  {    id: "code-font",    title: "Code font",    to: "/settings/appearance",    searchTerms: ["typography family size monospace code blocks diffs file previews"],  },  {    id: "terminal-font",    title: "Terminal font",    to: "/settings/appearance",    searchTerms: ["typography family size monospace output"],  },  {    id: "font-smoothing",    title: "Font smoothing",    to: "/settings/appearance",    searchTerms: ["typography text grayscale anti aliasing macos thin"],    macOnly: true,  },  {    id: "word-wrap",    title: "Word wrap",    to: "/settings/appearance",    searchTerms: ["long lines code blocks tables diffs file previews"],  },  {    id: "project-grouping",    title: "Project grouping",    to: "/settings/general",    searchTerms: ["combine matching repositories environments sidebar"],  },  {    id: "auto-settle-inactive-threads",    title: "Auto-settle inactive threads",    to: "/settings/general",    searchTerms: ["sidebar inactivity days no activity automatically"],    requiresThreadAutoSettlement: true,  },  {    id: "auto-settle-merged-threads",    title: "Auto-settle merged threads",    to: "/settings/general",    searchTerms: ["pull request merge closed automatically sidebar"],    requiresThreadAutoSettlement: true,  },  {    id: "days-before-auto-settle",    title: "Days of inactivity before auto-settle",    to: "/settings/general",    targetId: "auto-settle-inactive-threads",    searchTerms: ["thread timeout activity sidebar"],    requiresThreadAutoSettlement: true,  },  {    id: "time-format",    title: "Time format",    to: "/settings/general",    searchTerms: ["timestamp clock locale system browser os 12 hour 24 hour"],  },  {    id: "hide-whitespace-changes",    title: "Hide whitespace changes",    to: "/settings/general",    searchTerms: ["diff ignore spaces edits default"],  },  {    id: "skills-in-slash-menu",    title: "Show skills in slash menu",    to: "/settings/general",    searchTerms: ["command menu dollar $ slash /"],  },  {    id: "provider-update-checks",    title: "Provider update checks",    to: "/settings/general",    searchTerms: ["installed cli versions newer available codex claude cursor grok opencode"],  },  {    id: "background-activity",    title: "Background activity",    to: "/settings/general",    searchTerms: [      "balanced performance battery saver advanced git fetch provider health refresh host power monitor idle policy",    ],  },  {    id: "new-threads",    title: "New threads",    to: "/settings/general",    searchTerms: ["default workspace mode draft local worktree"],  },  {    id: "start-from-origin",    title: "Start from origin",    to: "/settings/general",    targetId: "new-threads",    searchTerms: ["new worktrees latest matching remote branch local"],  },  {    id: "add-project-starts-in",    title: "Add project starts in",    to: "/settings/general",    searchTerms: ["base directory folder browser path home"],  },  {    id: "unpin-confirmation",    title: "Unpin confirmation",    to: "/settings/general",    searchTerms: ["ask before thread pinned section"],  },  {    id: "archive-confirmation",    title: "Archive confirmation",    to: "/settings/general",    searchTerms: ["ask before thread second click inline action"],  },  {    id: "delete-confirmation",    title: "Delete confirmation",    to: "/settings/general",    searchTerms: ["ask before thread chat history"],  },  {    id: "quit-confirmation",    title: "Hold to quit",    to: "/settings/general",    searchTerms: ["confirmation shortcut desktop app exit"],    desktopOnly: true,  },  {    id: "text-generation-model",    title: "Text generation model",    to: "/settings/general",    searchTerms: ["generated thread titles source control content default provider"],  },  {    id: "diagnostics",    title: "Diagnostics",    to: "/settings/general",    searchTerms: ["logs traces processes resource history failures spans cpu memory"],  },  {    id: "legacy-plan-mode",    title: "Plan mode (legacy)",    to: "/settings/general",    searchTerms: ["build plan composer old"],  },  {    id: "legacy-token-streaming",    title: "Stream token by token (legacy)",    to: "/settings/general",    searchTerms: ["response output old compatibility"],  },  {    id: "legacy-sidebar",    title: "Sidebar (legacy)",    to: "/settings/general",    searchTerms: ["project thread tree old flat list"],  },  {    id: "keybindings",    title: "Keybindings",    to: "/settings/keybindings",    searchTerms: ["keyboard shortcuts hotkeys commands bindings json"],  },  {    id: "providers",    title: "Providers",    to: "/settings/providers",    searchTerms: [      "agents cli codex claude cursor grok opencode instances authentication api key models configuration binary path config directory endpoint arguments environment variables display name accent color custom favorite hidden auto compact",    ],  },  {    id: "provider-health-check-interval",    title: "Health check interval",    to: "/settings/providers",    searchTerms: ["refresh availability versions auth state models background probes seconds off"],    providerSettingsOnly: true,  },  {    id: "agent-browser-access",    title: "Agent browser access",    to: "/settings/integrations",    searchTerms: ["allow open drive preview tools sessions"],  },  {    id: "browser-default-viewport",    title: "Default browser viewport",    to: "/settings/integrations",    searchTerms: ["preview size width height device desktop mobile rotate"],  },  {    id: "browser-default-zoom",    title: "Default browser zoom",    to: "/settings/integrations",    searchTerms: ["preview page scale tabs percent"],  },  {    id: "browser-default-appearance",    title: "Default browser appearance",    to: "/settings/integrations",    searchTerms: ["preview color scheme light dark system os"],  },  {    id: "browser-recording-frame-rate",    title: "Browser recording frame rate",    to: "/settings/integrations",  },  {    id: "browser-auto-show-floating-preview",    title: "Auto-show floating preview",    to: "/settings/integrations",    searchTerms: ["agent opens browser pop into view hide"],  },  {    id: "source-control",    title: "Source control",    to: "/settings/source-control",    searchTerms: [      "version control git github gitlab bitbucket azure devops hosting integrations credentials scan server environment",    ],  },  {    id: "git-fetch-interval",    title: "Git fetch interval",    to: "/settings/source-control",    searchTerms: [      "automatic remote branch refresh background credentials security keys seconds off",    ],    primaryOnly: true,  },  {    id: "source-control-writing-style",    title: "Source control writing style",    to: "/settings/source-control",    searchTerms: [      "repository conventions conventional commits custom instructions change descriptions request titles",    ],    primaryOnly: true,  },  {    id: "follow-change-request-templates",    title: "Follow change request templates",    to: "/settings/source-control",    searchTerms: ["repository pr pull request description structure"],    primaryOnly: true,  },  {    id: "source-control-writer-model",    title: "Source control writer model",    to: "/settings/source-control",    searchTerms: [      "override generated commit change request pr titles descriptions branch bookmark",    ],    primaryOnly: true,  },  {    id: "network-access",    title: "Network access",    to: "/settings/connections",    targetId: "connections-environment",    searchTerms: ["expose backend remote pairing local machine interfaces host restart"],    localBackendManagementOnly: true,  },  {    id: "tailscale-https",    title: "Tailscale HTTPS",    to: "/settings/connections",    targetId: "connections-environment",    searchTerms: ["serve magicdns endpoint remote secure network"],    desktopOnly: true,    localBackendManagementOnly: true,  },  {    id: "wsl-backend",    title: "WSL backend",    to: "/settings/connections",    searchTerms: [      "windows subsystem linux distro second server projects stop windows backend restart",    ],    desktopOnly: true,    windowsOnly: true,    localBackendManagementOnly: true,    wslAvailableOnly: true,  },  {    id: "t3-connect",    title: "T3 Connect",    to: "/settings/connections",    targetId: "connections-environment",    searchTerms: ["managed tunnel cloud other devices remote"],    desktopOnly: true,    cloudOnly: true,  },  {    id: "publish-agent-activity",    title: "Publish agent activity",    to: "/settings/connections",    targetId: "connections-environment",    searchTerms: ["mobile push notifications live activities cloud tunnel"],    cloudOnly: true,  },  {    id: "connections-environment",    title: "This environment",    to: "/settings/connections",    searchTerms: [      "connections server backend local remote access administrative permissions scope pairing links qr code authorized clients sessions revoke endpoint",    ],  },  {    id: "remote-environments",    title: "Remote environments",    to: "/settings/connections",    searchTerms: ["add pair backend host code ssh config agent tunnel saved t3 connect"],  },  {    id: "archive",    title: "Archived threads",    to: "/settings/archived",    searchTerms: ["restore reopen deleted history projects"],  },] as const satisfies ReadonlyArray<SettingsSearchItem>; export type SettingsSearchItemId = (typeof SETTINGS_SEARCH_ITEMS)[number]["id"]; const SEARCH_ITEMS_BY_ID = new Map(SETTINGS_SEARCH_ITEMS.map((item) => [item.id, item] as const)); /** * `id` and `title` props for the element a search item anchors to. Panels * spread (or pick from) this instead of restating the strings, so the catalog * and the rendered settings cannot drift apart. */export function searchableSetting(id: SettingsSearchItemId): {  readonly id: string;  readonly title: string;} {  const { id: anchorId, title } = SEARCH_ITEMS_BY_ID.get(id)!;  return { id: anchorId, title };} export function filterAvailableSettingsSearchItems(  availability: SettingsSearchAvailability,): ReadonlyArray<SettingsSearchItem> {  const items: ReadonlyArray<SettingsSearchItem> = SETTINGS_SEARCH_ITEMS;  return items.filter(    (item) =>      (!item.cloudOnly || availability.hasCloudPublicConfig) &&      (!item.primaryOnly || availability.hasPrimaryEnvironment) &&      (!item.providerSettingsOnly || availability.hasProviderSettingsEnvironment) &&      (!item.localBackendManagementOnly || availability.canManageLocalBackend) &&      (!item.wslAvailableOnly || availability.isWslSettingsRowVisible) &&      (!item.requiresThreadAutoSettlement || availability.hasThreadAutoSettlement),  );} export function searchSettings(  query: string,  items: ReadonlyArray<SettingsSearchItem> = SETTINGS_SEARCH_ITEMS,): ReadonlyArray<SettingsSearchItem> {  const normalizedQuery = normalizeSearchText(query);  if (normalizedQuery.length === 0) return [];  const queryTokens = normalizedQuery.split(" ");  const platform = typeof navigator === "undefined" ? "" : navigator.platform;   return items    .flatMap((item, index) => {      if (!isElectron && item.desktopOnly === true) return [];      if (item.macOnly && !isMacPlatform(platform)) return [];      if (item.windowsOnly && !isWindowsPlatform(platform)) return [];       const title = normalizeSearchText(item.title);      const fields = [        title,        normalizeSearchText(SETTINGS_SECTION_LABELS[item.to]),        ...(item.searchTerms ?? []).map(normalizeSearchText),      ];      if (!queryTokens.every((token) => fields.some((field) => field.includes(token)))) return [];       const exactPhraseField = fields.findIndex((field) => field.includes(normalizedQuery));      const rank =        title === normalizedQuery          ? 5

Lines 1–500 of 514.