forked from CodebuffAI/codebuff
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsettings.ts
More file actions
179 lines (151 loc) · 4.85 KB
/
Copy pathsettings.ts
File metadata and controls
179 lines (151 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import fs from 'fs'
import path from 'path'
import { isFreebuffModelId } from '@codebuff/common/constants/freebuff-models'
import { getConfigDir } from './auth'
import { AGENT_MODES } from './constants'
import { logger } from './logger'
import type { AgentMode } from './constants'
const DEFAULT_SETTINGS: Settings = {
mode: 'DEFAULT' as const,
adsEnabled: true,
}
// Note: The old FREE mode has been renamed back to LITE; migrate on load.
/**
* Settings schema - add new settings here as the product evolves
*/
export interface Settings {
mode?: AgentMode
adsEnabled?: boolean
/** Last model the user picked in the freebuff model selector. Restored on
* next freebuff launch so users land in the queue for their preferred
* model without re-picking. Persisted as the canonical model id. */
freebuffModel?: string
/** @deprecated Use server-side fallbackToALaCarte setting instead */
alwaysUseALaCarte?: boolean
/** @deprecated Use server-side fallbackToALaCarte setting instead */
fallbackToALaCarte?: boolean
}
/**
* Get the settings file path
*/
export const getSettingsPath = (): string => {
return path.join(getConfigDir(), 'settings.json')
}
/**
* Ensure the config directory exists, creating it if necessary
*/
const ensureConfigDirExists = (): void => {
const configDir = getConfigDir()
if (!fs.existsSync(configDir)) {
fs.mkdirSync(configDir, { recursive: true })
}
}
/**
* Load all settings from file system
* @returns The saved settings object, with defaults for missing values
*/
export const loadSettings = (): Settings => {
const settingsPath = getSettingsPath()
if (!fs.existsSync(settingsPath)) {
ensureConfigDirExists()
// Create default settings file
fs.writeFileSync(settingsPath, JSON.stringify(DEFAULT_SETTINGS, null, 2))
return DEFAULT_SETTINGS
}
try {
const settingsFile = fs.readFileSync(settingsPath, 'utf8')
const parsed = JSON.parse(settingsFile)
return validateSettings(parsed)
} catch (error) {
logger.debug(
{
error: error instanceof Error ? error.message : String(error),
},
'Error reading settings',
)
return {}
}
}
/**
* Validate and sanitize settings from file
*/
const validateSettings = (parsed: unknown): Settings => {
if (typeof parsed !== 'object' || parsed === null) {
return {}
}
const settings: Settings = {}
const obj = parsed as Record<string, unknown>
// Validate mode; migrate the previously-saved 'FREE' value to 'LITE'.
if (typeof obj.mode === 'string') {
const normalized = obj.mode === 'FREE' ? 'LITE' : obj.mode
if (AGENT_MODES.includes(normalized as AgentMode)) {
settings.mode = normalized as AgentMode
}
}
// Validate adsEnabled
if (typeof obj.adsEnabled === 'boolean') {
settings.adsEnabled = obj.adsEnabled
}
// Validate freebuffModel — drop unknown ids so a removed model doesn't
// strand the user on a non-existent queue.
if (typeof obj.freebuffModel === 'string' && isFreebuffModelId(obj.freebuffModel)) {
settings.freebuffModel = obj.freebuffModel
}
// Validate alwaysUseALaCarte (legacy)
if (typeof obj.alwaysUseALaCarte === 'boolean') {
settings.alwaysUseALaCarte = obj.alwaysUseALaCarte
}
// Validate fallbackToALaCarte (legacy)
if (typeof obj.fallbackToALaCarte === 'boolean') {
settings.fallbackToALaCarte = obj.fallbackToALaCarte
}
return settings
}
/**
* Save settings to file system (merges with existing settings)
*/
export const saveSettings = (newSettings: Partial<Settings>): void => {
const settingsPath = getSettingsPath()
try {
ensureConfigDirExists()
// Load existing settings and merge
const existingSettings = loadSettings()
const mergedSettings = { ...existingSettings, ...newSettings }
fs.writeFileSync(settingsPath, JSON.stringify(mergedSettings, null, 2))
} catch (error) {
logger.debug(
{
error: error instanceof Error ? error.message : String(error),
},
'Error saving settings',
)
}
}
/**
* Load the saved agent mode preference
* @returns The saved mode, or 'DEFAULT' if not found or invalid
*/
export const loadModePreference = (): AgentMode => {
const settings = loadSettings()
return settings.mode ?? 'DEFAULT'
}
/**
* Save the agent mode preference
*/
export const saveModePreference = (mode: AgentMode): void => {
saveSettings({ mode })
}
/**
* Load the saved freebuff model preference. Returns undefined if none is
* saved yet — callers should fall back to DEFAULT_FREEBUFF_MODEL_ID.
*/
export const loadFreebuffModelPreference = (): string | undefined => {
return loadSettings().freebuffModel
}
/**
* Save the freebuff model preference. Called whenever the user picks a model
* in the waiting room so the next launch defaults to it.
*/
export const saveFreebuffModelPreference = (model: string): void => {
saveSettings({ freebuffModel: model })
}