Files
orca/src/shared/default-global-settings.ts
Kelvin Amoaba a6dd56b429 feat(workspace-cleanup): store cleanup rules in settings with per-project overrides (#41398)
Adds off-by-default workspace cleanup rules (merged, unchanged, inactive,
automation runs, orchestration workers, keep-when) to global settings and
an inherit/off/custom override on each repo. resolveWorkspaceCleanupPolicy
is the single source of truth for the coming background runner, and the
rules are exposed to paired clients through settings.get/settings.update.
No UI and no behaviour change yet.
2026-11-12 05:43:15 +00:00

324 lines
14 KiB
TypeScript

import type { GlobalSettings } from './global-settings-types'
import type { NotificationSettings } from './notification-settings-types'
import type { VoiceSettings } from './speech-types'
import { DEFAULT_TERMINAL_FONT_WEIGHT_BOLD } from './terminal/appearance/terminal-fonts'
import { getDefaultTerminalQuickCommands } from './terminal/quick-commands/terminal-quick-commands'
import { TASK_PROVIDERS } from './work-items/task-providers'
import { getDefaultSourceControlAiSettings } from './source-control/ai/settings/source-control-ai-settings'
import { DEFAULT_APP_ICON_ID } from './app-icon'
import { DEFAULT_OPEN_IN_APPLICATIONS } from './open-in-applications'
import { DEFAULT_NATIVE_CHAT_IDLE_STOP_MINUTES } from './native-chat/native-chat-idle-stop'
import { DEFAULT_DISABLED_TUI_AGENTS } from './agent-launch/catalog/tui-agent-selection'
import { UI_LANGUAGE_SYSTEM } from './ui-language'
import {
DEFAULT_LEFT_SIDEBAR_TINT_COLOR,
DEFAULT_LEFT_SIDEBAR_TINT_OPACITY
} from './left-sidebar-appearance'
import { DEFAULT_SOURCE_CONTROL_GROUP_ORDER } from './source-control/listing/source-control-group-order'
import { DESKTOP_TERMINAL_SCROLLBACK_ROWS_DEFAULT } from './terminal/replay/terminal-scrollback-policy'
import { NESTED_WORKER_MAX_DEPTH_DEFAULT } from './orchestration/workers/nested-worker-depth'
import { getDefaultWorkspaceCleanupRules } from './workspace-cleanup/workspace-cleanup-policy'
export function buildDefaultSettings(args: {
workspaceDir: string
appFontFamily: string
editorAutoSaveDelayMs: number
primarySelectionMiddleClickPaste: boolean
primarySelectionDefaultedForLinux: boolean
terminalFontFamily: string
terminalFontWeight: number
terminalFontWeightWindowsRegular?: GlobalSettings['terminalFontWeightWindowsRegular']
terminalInactivePaneOpacity: number
terminalRightClickToPaste: boolean
notifications: NotificationSettings
voice: VoiceSettings
}): GlobalSettings {
return {
workspaceDir: args.workspaceDir,
worktreeVisibilityDefaults: { external: 'hide' },
workspaceCleanupPolicy: getDefaultWorkspaceCleanupRules(),
nestWorkspaces: true,
workspaceDirHistory: [],
refreshLocalBaseRefOnWorktreeCreate: false,
localBaseRefSuggestionDismissed: false,
autoRenameBranchFromWork: true,
autoRenameBranchFromWorkDefaultedOn: true,
branchPrefix: 'git-username',
branchPrefixCustom: '',
jiraIssueKeyCasing: 'lowercase',
theme: 'system',
pluginAppTheme: null,
pluginAppThemeLight: null,
pluginAppThemeDark: null,
editorThemeLight: null,
editorThemeDark: null,
pluginIconTheme: null,
leftSidebarAppearanceMode: 'default',
leftSidebarTintColor: DEFAULT_LEFT_SIDEBAR_TINT_COLOR,
leftSidebarTintOpacity: DEFAULT_LEFT_SIDEBAR_TINT_OPACITY,
uiLanguage: UI_LANGUAGE_SYSTEM,
uiLanguagePortugueseMigrationApplied: true,
appIcon: DEFAULT_APP_ICON_ID,
appFontFamily: args.appFontFamily,
editorAutoSave: false,
editorFormatOnSave: false,
editorInsertFinalNewline: false,
editorAutoSaveDelayMs: args.editorAutoSaveDelayMs,
editorMinimapEnabled: false,
// Why empty: the editor keeps following the terminal font unless the user opts in.
editorFontFamily: '',
editorWordWrap: true,
richMarkdownSpellcheckEnabled: true,
markdownDefaultViewMode: 'rich',
markdownReviewToolsEnabled: true,
primarySelectionMiddleClickPaste: args.primarySelectionMiddleClickPaste,
primarySelectionMiddleClickPasteDefaultedForLinux: args.primarySelectionDefaultedForLinux,
primarySelectionMiddleClickPasteDefaultedForTerminalDefaults:
args.primarySelectionMiddleClickPaste,
terminalFontSize: 14,
terminalFontFamily: args.terminalFontFamily,
terminalFontWeight: args.terminalFontWeight,
terminalFontWeightWindowsRegular: args.terminalFontWeightWindowsRegular,
terminalFontWeightBold: DEFAULT_TERMINAL_FONT_WEIGHT_BOLD,
terminalLineHeight: 1,
terminalScrollSensitivity: 1.15,
terminalFastScrollSensitivity: 5,
terminalTuiScrollSensitivity: 1,
terminalTuiScrollSensitivityDefaultedToOne: true,
// Why: "auto" uses WebGL when supported, falling back to DOM on renderer failure or software/unknown GPU.
terminalGpuAcceleration: 'auto',
// Why 'auto': enable ligatures only for known ligature fonts, never forced. Resolver in shared/terminal-ligatures.ts.
terminalLigatures: 'auto',
// Lazy image addon stays off the critical path and creates canvas layers only on first image; decoder setup still has overhead.
terminalInlineImages: true,
terminalCursorStyle: 'block',
terminalCursorStyleDefaultedToBlock: true,
terminalCursorBlink: true,
terminalThemeDark: 'Ghostty Default Style Dark',
terminalDividerColorDark: '#3f3f46',
terminalUseSeparateLightTheme: true,
terminalColorOverridesSplit: true,
terminalThemeLight: 'Builtin Tango Light',
claudeCodeThemeSync: false,
terminalCustomThemes: [],
terminalDividerColorLight: '#d4d4d8',
terminalInactivePaneOpacity: args.terminalInactivePaneOpacity,
terminalActivePaneOpacity: 1,
terminalPaneOpacityTransitionMs: 140,
terminalDividerThicknessPx: 3,
// Why: Windows paste-on-right-click matches native convention; macOS/Linux keep right-click for the context menu.
terminalRightClickToPaste: args.terminalRightClickToPaste,
terminalRightClickToPasteDefaultedForPlatform: true,
terminalWindowsShell: 'powershell.exe',
terminalDefaultShell: '',
terminalWindowsWslDistro: null,
localAccountRuntime: 'auto',
localAccountRuntimeDefaultedToAutoForAllUsers: true,
localAccountWslDistro: null,
localWindowsRuntimeDefault: { kind: 'windows-host' },
// Why: prefer modern PowerShell when installed, falling back to inbox Windows PowerShell.
terminalWindowsPowerShellImplementation: 'auto',
terminalMouseHideWhileTyping: false,
terminalQuickCommands: getDefaultTerminalQuickCommands(),
// Why: opt-in only, matching Ghostty's default (upgrades never enable it unexpectedly).
terminalFocusFollowsMouse: false,
// Why: xterm's default; turning it off keeps a scrolled-up reading position while typing.
terminalScrollOnUserInput: true,
windowBackgroundBlur: false,
reduceVisualEffects: false,
minimizeToTrayOnClose: false,
// Why: default-on everywhere so it round-trips across platforms; only darwin acts on it.
showMenuBarIcon: true,
terminalClipboardOnSelect: false,
// Trim only the shared leading-space gutter, preserving relative indentation.
terminalCopyTrimsGutter: true,
// Default OSC52 supports Zellij/tmux/nvim with queries disabled and capped writes; the stamp migrates persisted false once in both Electron and web localStorage stores.
terminalAllowOsc52Clipboard: true,
terminalAllowOsc52ClipboardDefaultedOnForAllUsers: true,
claudeAgentTeamsMode: 'off',
terminalScrollbackRows: DESKTOP_TERMINAL_SCROLLBACK_ROWS_DEFAULT,
httpProxyUrl: '',
httpProxyBypassRules: '',
nodeDistMirrorUrl: '',
electronHttp1CompatibilityMode: false,
openLinksInApp: false,
localhostWorktreeLabelsEnabled: false,
openLinksInAppPreferencePrompted: false,
openLinksInAppModifierInverts: false,
openLinksInAppInBackground: false,
terminalLinkActionPopoverEnabled: true,
terminalLinkClickBehavior: 'actions',
terminalUrlMiddleClickBehavior: 'open',
browserExtensionsEnabled: true,
agentDefaultSurface: 'terminal',
nativeChatResumeWorkOnRestart: true,
nativeChatQueueFollowUps: true,
nativeChatAutoContinueAfterUsageLimit: false,
nativeChatIdleStopMinutes: DEFAULT_NATIVE_CHAT_IDLE_STOP_MINUTES,
nativeChatInlineVisuals: true,
nativeChatLinkPreviews: true,
nativeChatOpenedPullRequests: true,
nativeChatScrollToLatestOnSend: true,
nativeChatTurnDiffSummary: true,
nativeChatInheritShellEnvironment: true,
nativeChatShellEnvironmentVariables: [],
nativeChatSessionOptions: {},
// New chats of agents on their own settings; others start in their agent permission.
nativeChatPermissionMode: 'full-access',
openInApplications: [...DEFAULT_OPEN_IN_APPLICATIONS],
rightSidebarOpenByDefault: true,
showGitIgnoredFiles: true,
followSymlinkedDirectories: false,
sourceControlViewMode: 'list',
sourceControlGroupOrder: DEFAULT_SOURCE_CONTROL_GROUP_ORDER,
sourceControlCompareAgainstUpstream: false,
showTitlebarAppName: true,
showTasksButton: true,
showAutomationsButton: true,
artifactsEnabled: true,
// New profiles only; stored profiles without the key load as false (normalizeLoadedGlobalSettings).
artifactSharingEnabled: true,
agentSkillSharingEnabled: false,
nestedWorkerMaxDepth: NESTED_WORKER_MAX_DEPTH_DEFAULT,
nestedWorkerMaxDepthDefaultedToFour: true,
orchestrationWorkerAutoReleaseEnabled: true,
orchestrationCoordinatorApprovalsEnabled: false,
showArtifactsButton: false,
showSkillsButton: false,
showMobileButton: true,
showPinnedWorktreesInGroups: false,
ctrlTabOrderMode: 'mru',
// Why: Orca-first keeps core shortcuts working from a focused terminal; TUI-ownership users opt in.
terminalShortcutPolicy: 'orca-first',
floatingTerminalEnabled: true,
browserClientHostedRemoteEnabled: true,
floatingTerminalDefaultedForAllUsers: true,
floatingTerminalCwd: '~',
floatingTerminalTrustedCwds: [],
floatingTerminalCwdMigratedToAppWorkspace: true,
floatingTerminalTriggerLocation: 'floating-button',
notifications: args.notifications,
diffDefaultView: 'inline',
diffWordWrap: false,
diffShowWhitespace: false,
diffCollapseUnchangedRegions: false,
combinedDiffFileTreeVisibleByDefault: false,
prBotAuthorOverrides: [],
promptCacheTimerEnabled: false,
promptCacheTtlMs: 300_000,
codexManagedAccounts: [],
activeCodexManagedAccountId: null,
activeCodexManagedAccountIdsByRuntime: { host: null, wsl: {} },
claudeManagedAccounts: [],
activeClaudeManagedAccountId: null,
terminalScopeHistoryByWorktree: true,
terminalHiddenViewParking: true,
// Default-on kill switches use !== false so older persisted settings retain behavior.
terminalSshViewParking: true,
terminalHiddenWorktreeRetentionBudget: true,
browserGuestWorktreeRetentionBudget: true,
terminalMainSideEffectAuthority: true,
terminalHiddenDeliveryGate: true,
terminalModelQueryAuthority: true,
defaultTuiAgent: null,
disabledTuiAgents: [...DEFAULT_DISABLED_TUI_AGENTS],
pluginSystemEnabled: true,
pluginSystemDefaultedOn: true,
disabledPlugins: [],
pluginConsents: {},
devPluginPaths: [],
claudeAgentTeamsDefaultDisabledMigrated: true,
sshRemoteCliControlExistingHostsMigrated: true,
skipDeleteWorktreeConfirm: false,
alwaysForceDeleteWorktrees: false,
alwaysForceDeletePreservedBranches: false,
skipCloseTerminalWithRunningProcessConfirm: false,
skipDeleteAutomationConfirm: false,
skipDeleteArtifactConfirm: false,
skipCodexRateLimitResetConfirm: false,
defaultTaskViewPreset: 'all',
defaultTaskSource: 'github',
visibleTaskProviders: [...TASK_PROVIDERS],
visibleTaskProvidersDefaultedForJira: true,
defaultRepoSelection: null,
defaultLinearTeamSelection: null,
opencodeSessionCookie: '',
opencodeWorkspaceId: '',
minimaxGroupId: '',
minimaxUsageModels: 'general',
minimaxEndpoint: 'overseas',
zcodePlanSite: 'zai',
geminiCliOAuthEnabled: false,
agentCmdOverrides: {},
// Arguments hold only the user's own text; the permission flag comes from the choice below.
agentDefaultArgs: {},
agentLaunchChoices: {},
agentDefaultEnv: {},
agentYoloDefaultsMigrated: true,
agentPermissionDefault: 'full-access',
agentPermissionOverrides: {},
agentStatusHooksEnabled: true,
claudeSubagentNavigationEnabled: true,
agentWorkspaceTrustEnabled: true,
agentWorkspaceTrustExistingReposMigrated: true,
codexTerminalServerIsolation: true,
codexSharedServerWarning: true,
tabAutoGenerateTitle: false,
confirmClosePinnedTab: true,
editorPreviewTabsEnabled: true,
keepComputerAwakeWhileAgentsRun: false,
// Why: 'auto' probes keyboard layout so non-US users can type Option chars like @/€/[ out of the box (issue #903). See src/renderer/src/lib/keyboard-layout/*.
terminalMacOptionAsAlt: 'auto',
terminalMacOptionAsAltMigrated: false,
terminalJISYenToBackslash: false,
experimentalMobile: false,
mobileEmulatorEnabled: true,
mobileEmulatorDefaultDeviceUdid: null,
androidSdkPath: null,
// Why: indefinite hold — the "Restore" banner is the explicit return action, no wall-clock guess. See docs/mobile-fit-hold.md.
mobileAutoRestoreFitMs: null,
// Why: Anywhere (Relay + local) is the default; local-only is written only on explicit same-network choice.
mobilePairingConnectionMode: 'automatic',
mobilePairingCustomAddress: null,
mobilePairingCustomAddresses: [],
machineName: '',
// Why: off keeps the cosmetic overlay unmounted for users who never opt in.
experimentalPet: false,
experimentalActivity: false,
experimentalActivityDefaultedOffForAllUsers: true,
experimentalTerminalAttention: false,
experimentalAgentHibernation: false,
agentHibernationIdleMs: 30 * 60 * 1000,
experimentalNewWorktreeCardStyle: false,
experimentalEphemeralVms: false,
experimentalConnectors: false,
experimentalWslHosts: false,
experimentalOrchestrationPanel: false,
compactWorktreeCards: false,
// Why: local desktop stays the default until the user picks a saved runtime environment.
activeRuntimeEnvironmentId: null,
// Why: hydrate a stable empty shape so renderer optional-chained reads never hit undefined.
githubProjects: {
pinned: [],
recent: [],
lastViewByProject: {},
activeProject: null
},
// Why: keep agent/model maps empty so first use follows the default agent's model, not a frozen stale choice.
commitMessageAi: {
enabled: true,
agentId: null,
selectedModelByAgent: {},
discoveredModelsByAgent: {},
selectedModelByAgentByHost: {},
discoveredModelsByAgentByHost: {},
selectedThinkingByModel: {},
customPrompt: '',
customAgentCommand: ''
},
sourceControlAi: getDefaultSourceControlAiSettings(),
voice: args.voice,
voiceDictationModeDefaultedToAuto: true
}
}