Files
orca/src/shared/constants.ts
T
Vyacheslav ScherbininandNeil b654c3454a fix(persistence): stop rewriting migrated Compact profiles on every load (#34736)
The legacy Compact card-property migration returned the Compact preset even
when the stored list already was a current Compact preset, so every clean
reload of a Compact profile scheduled a full profile write. Treat both the
raw ['status'] and the normalized ['status', 'unread'] form (persisted by any
UI write) as already migrated.

Fixes #34828

Co-authored-by: Neil <neil@stably.ai>
2026-10-28 08:00:38 -07:00

280 lines
11 KiB
TypeScript

import type { GlobalSettings } from './global-settings-types'
import type { RepoHookSettings } from './orca-yaml-hook-types'
import type { PersistedState } from './persisted-state-types'
import type { PersistedUIState } from './persisted-ui-state-types'
import type { AgentActivityDisplayMode } from './ui-chrome-types'
import type { WorkspaceSessionState } from './workspace-session-state-types'
import { EMPTY_CODEX_RESET_CREDIT_ATTEMPT_LEDGER } from './codex-reset-credit-attempt-ledger'
import { DEFAULT_STATUS_BAR_ITEMS } from './status-bar-defaults'
import type { VoiceSettings } from './speech-types'
import { cloneDefaultWorkspaceStatuses } from './workspace-statuses'
import { DEFAULT_WORKTREE_CARD_PROPERTIES } from './worktree/card-properties'
import { DEFAULT_AGENTS_GROUP_BY, DEFAULT_AGENTS_READ_FILTER } from './agents-view-thread-filters'
import { DEFAULT_USAGE_PERCENTAGE_DISPLAY } from './usage-percentage-display'
import { DEFAULT_STATUS_BAR_USAGE_MODE } from './status-bar-usage-mode'
import { buildDefaultSettings } from './default-global-settings'
import { DEFAULT_SETUP_AGENT_STARTUP_POLICY } from './setup-agent-startup-policy'
import { DEFAULT_BROWSER_PAGE_ZOOM_LEVEL } from './browser-page-zoom'
import { getDefaultNotificationSettings } from './notification-settings-defaults'
import { getDefaultOnboardingState } from './onboarding-defaults'
import {
defaultTerminalFontFamily,
getDefaultPrimarySelectionMiddleClickPaste,
getDefaultTerminalRightClickToPaste
} from './terminal-platform-defaults'
export { DEFAULT_STATUS_BAR_ITEMS } from './status-bar-defaults'
export {
COMPACT_WORKTREE_CARD_PROPERTIES,
DEFAULT_WORKTREE_CARD_PROPERTIES,
TASK_WORKTREE_CARD_PROPERTIES,
getWorktreeCardModeProperties,
getWorktreeCardModeUpdates,
isCurrentCompactWorktreeCardProperties,
isDefaultedCompactWorktreeCardProperties,
normalizeWorktreeCardProperties
} from './worktree/card-properties'
export const SCHEMA_VERSION = 1
export const DEFAULT_APP_FONT_FAMILY = 'Geist'
export const DEFAULT_SHOW_SLEEPING_WORKSPACES = true
export const DEFAULT_HIDE_SLEEPING_WORKSPACES = false
export const DEFAULT_AGENT_ACTIVITY_DISPLAY_MODE: AgentActivityDisplayMode = 'compact'
export const DEFAULT_TERMINAL_INACTIVE_PANE_OPACITY = 0.9
export function normalizeAgentActivityDisplayMode(value: unknown): AgentActivityDisplayMode {
return value === 'full' || value === 'compact' ? value : DEFAULT_AGENT_ACTIVITY_DISPLAY_MODE
}
export const ORCA_BROWSER_PARTITION = 'persist:orca-browser'
// Why: inert blank-tab URL shared by main/renderer so the attach policy can allow just this one data URL and reject others.
export const ORCA_BROWSER_BLANK_URL = 'data:text/html,'
export const BROWSER_FAMILY_LABELS: Record<string, string> = {
chrome: 'Google Chrome',
chromium: 'Chromium',
comet: 'Comet',
helium: 'Helium',
vivaldi: 'Vivaldi',
arc: 'Arc',
edge: 'Microsoft Edge',
brave: 'Brave',
firefox: 'Firefox',
safari: 'Safari',
manual: 'File'
}
/** ProseMirror mounts whole documents. M-series Electron measurements at 300/450/600KB: longest tasks 0.66/1.02/1.41s; 600KB typing p95 39ms (#17134/#17147/#17158). Use cheap pre-parse byte guard, then source mode with Open anyway. */
export const RICH_MARKDOWN_MAX_SIZE_BYTES = 600 * 1024
export const DEFAULT_EDITOR_AUTO_SAVE_DELAY_MS = 1000
export const MIN_EDITOR_AUTO_SAVE_DELAY_MS = 250
export const MAX_EDITOR_AUTO_SAVE_DELAY_MS = 10_000
// Why: first-time seed only — doubles on each dismissal without starring; later thresholds live in starNagNextThreshold.
export const STAR_NAG_INITIAL_THRESHOLD = 35
/** Synthetic worktree id for PTYs not tied to any worktree; shared so main and renderer agree on the sentinel. */
export const ORPHAN_WORKTREE_ID = '__orphan__'
// Why: synthetic local workspace; persistence pruning must classify it without the repo catalog.
export const FLOATING_TERMINAL_WORKTREE_ID = 'global-floating-terminal'
export { DEFAULT_REPO_BADGE_COLOR, REPO_COLORS } from './repo-badge-color'
/** Expose the stock root so callers can distinguish an untouched default from a user-selected directory. */
export function getDefaultWorkspaceDir(homeDir: string): string {
const separator = homeDir.includes('\\') ? '\\' : '/'
const trimmedHomeDir = homeDir.replace(/[\\/]+$/, '')
return [trimmedHomeDir, 'orca', 'workspaces'].join(separator)
}
export function getDefaultSettings(homedir: string): GlobalSettings {
return buildDefaultSettings({
workspaceDir: getDefaultWorkspaceDir(homedir),
appFontFamily: DEFAULT_APP_FONT_FAMILY,
editorAutoSaveDelayMs: DEFAULT_EDITOR_AUTO_SAVE_DELAY_MS,
primarySelectionMiddleClickPaste: getDefaultPrimarySelectionMiddleClickPaste(),
primarySelectionDefaultedForLinux:
typeof process !== 'undefined' && process.platform === 'linux',
terminalFontFamily: defaultTerminalFontFamily(),
terminalInactivePaneOpacity: DEFAULT_TERMINAL_INACTIVE_PANE_OPACITY,
terminalRightClickToPaste: getDefaultTerminalRightClickToPaste(),
notifications: getDefaultNotificationSettings(),
voice: getDefaultVoiceSettings()
})
}
export function getDefaultVoiceSettings(): VoiceSettings {
return {
enabled: false,
sttModel: '',
modelsDir: '',
language: 'en',
dictationMode: 'toggle' as const,
terminalConfirmBeforeInsert: false,
userModels: [],
openAiApiKeyConfigured: false,
microphoneDeviceId: null,
microphoneDeviceLabel: null
}
}
export function getDefaultRepoHookSettings(): RepoHookSettings {
return {
mode: 'auto',
setupRunPolicy: 'run-by-default',
setupAgentStartupPolicy: DEFAULT_SETUP_AGENT_STARTUP_POLICY,
scripts: {
setup: '',
archive: ''
}
}
}
export function getDefaultPersistedState(homedir: string): PersistedState {
return {
schemaVersion: SCHEMA_VERSION,
repos: [],
projects: [],
projectHostSetups: [],
projectGroups: [],
folderWorkspaces: [],
sparsePresetsByRepo: {},
retiredWorktreeNamesByRepo: {},
retiredWorktreeNamesByNamespace: {},
worktreeMeta: {},
worktreeLineageById: {},
workspaceLineageByChildKey: {},
settings: getDefaultSettings(homedir),
ui: getDefaultUIState(),
githubCache: { pr: {}, issue: {} },
workspaceSession: getDefaultWorkspaceSession(),
workspaceSessionsByHostId: {},
sshTargets: [],
sshTargetGenerationCounter: 0,
deletedSshConfigAliases: [],
sshRemotePtyLeases: [],
sshPtyConsumerRecoveries: [],
migrationUnsupportedPtyEntries: [],
legacyPaneKeyAliasEntries: [],
automations: [],
automationRuns: [],
onboarding: getDefaultOnboardingState(),
featureInteractionTelemetryBuckets: {},
codexResetCreditAttemptLedger: structuredClone(EMPTY_CODEX_RESET_CREDIT_ATTEMPT_LEDGER)
}
}
/** Creates fresh UI defaults with completed migration markers so new profiles are not treated as legacy installations. */
export function getDefaultUIState(): PersistedUIState {
return {
lastActiveRepoId: null,
lastActiveWorktreeId: null,
activeView: 'terminal',
sidebarWidth: 280,
rightSidebarOpen: true,
rightSidebarTab: 'explorer',
rightSidebarExplorerView: 'files',
rightSidebarWidth: 350,
markdownTocPanelWidth: 240,
combinedDiffFileTreeWidth: 256,
groupBy: 'repo',
sortBy: 'recent',
projectOrderBy: 'manual',
showActiveOnly: false,
hideSleepingWorkspaces: DEFAULT_HIDE_SLEEPING_WORKSPACES,
workspaceHostScope: 'all',
visibleWorkspaceHostIds: null,
workspaceHostOrder: [],
automationHostFilter: { kind: 'all' },
manualRepoOrder: [],
showSleepingWorkspaces: DEFAULT_SHOW_SLEEPING_WORKSPACES,
hideDefaultBranchWorkspace: false,
hideAutomationGeneratedWorkspaces: false,
hideCliCreatedWorkspaces: false,
hideDetachedHeadWorkspaces: false,
hideWorkspacesFromOtherDevices: false,
alwaysShowDefaultBranchWorkspace: true,
_explorerDisplayRootMigrated: true,
explorerDisplayRootByWorktree: {},
showDotfilesByWorktree: {},
filterRepoIds: [],
agentsVisibleHostIds: null,
agentsFilterRepoIds: [],
agentsHideWorkspacesFromOtherDevices: false,
agentsHideAutomationGeneratedWorkspaces: false,
agentsHideCliCreatedWorkspaces: false,
agentsShowChildAgents: false,
agentsCompactMode: true,
agentsShowSearch: true,
agentsReadFilter: DEFAULT_AGENTS_READ_FILTER,
agentsGroupBy: DEFAULT_AGENTS_GROUP_BY,
collapsedGroups: [],
uiZoomLevel: 0,
editorFontZoomLevel: 0,
worktreeCardProperties: [...DEFAULT_WORKTREE_CARD_PROPERTIES],
_worktreeCardModeDefaulted: true,
agentActivityDisplayMode: DEFAULT_AGENT_ACTIVITY_DISPLAY_MODE,
workspaceStatuses: cloneDefaultWorkspaceStatuses(),
workspaceBoardOpacity: 1,
workspaceBoardColumnWidth: 308,
syncTaskStatusFromWorkspaceBoard: false,
_workspaceStatusesDefaultOrderMigrated: true,
_workspaceStatusesReorderedDefaultRepaired: true,
_workspaceStatusesDefaultWorkflowMigrated: true,
_workspaceStatusesDefaultVisualsMigrated: true,
statusBarItems: [...DEFAULT_STATUS_BAR_ITEMS],
statusBarVisible: true,
usagePercentageDisplay: DEFAULT_USAGE_PERCENTAGE_DISPLAY,
statusBarUsageMode: DEFAULT_STATUS_BAR_USAGE_MODE,
dismissedUpdateVersion: null,
dismissedUnexpectedSignoutVersion: null,
lastUpdateCheckAt: null,
trustedOrcaHooks: {},
setupScriptPromptDismissedRepoIds: [],
acknowledgedAgentsByPaneKey: {},
activityClearedAtByPaneKey: {},
manuallyUnreadTurnsByPaneKey: {},
setupGuideSidebarDismissed: false,
setupGuideBrowserMilestoneMigrated: true,
setupGuideBrowserMilestoneLegacyComplete: false,
browserImportHintHidden: false,
trayMinimizeNoticeShown: false,
// Why: fresh profiles start on the new default, so nothing was overridden to report.
osc52ClipboardDefaultOnNoticePending: false,
mobileEmulatorTabIntroDismissed: false,
mobileEmulatorAgentSetupDismissed: false,
// Why: only upgraded profiles saw the old ordering, so only they get the one-time notice.
projectOrderManualDefaultNoticeDismissed: true,
// Why: only upgraded profiles saw the old default, so only they get the one-time change notice.
usagePercentageDisplayChangeNoticeDismissed: true,
statusBarCompactChangeNoticeDismissed: true,
workspaceCleanup: { dismissals: {} },
featureTipsSeenIds: [],
featureInteractions: {},
contextualToursSeenIds: [],
browserDefaultZoomLevel: DEFAULT_BROWSER_PAGE_ZOOM_LEVEL
}
}
export function getDefaultWorkspaceSession(): WorkspaceSessionState {
return {
activeRepoId: null,
activeWorktreeId: null,
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {},
openFilesByWorktree: {},
markdownFrontmatterVisible: {},
browserTabsByWorktree: {},
browserPagesByWorkspace: {},
activeBrowserTabIdByWorktree: {},
activeFileIdByWorktree: {},
activeTabTypeByWorktree: {},
browserUrlHistory: [],
defaultTerminalTabsAppliedByWorktreeId: {}
}
}