init helder
This commit is contained in:
93
src/main/config.ts
Normal file
93
src/main/config.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
||||
import { join } from 'node:path'
|
||||
|
||||
/**
|
||||
* Project-scoped settings, living in `.helder/` in the opened project's root.
|
||||
* - config.default.json full built-in defaults, REGENERATED on every launch
|
||||
* (live documentation; the app never reads user edits here)
|
||||
* - config.json sparse — only user-overridden values
|
||||
* - theme.css custom CSS over the built-in dark theme; the CODE FONT
|
||||
* and FONT SIZE live here (as CSS vars), not in the JSON
|
||||
* Effective value = config.json over config.default.json, merged key by key.
|
||||
*/
|
||||
export interface HelderConfig {
|
||||
ai: { command: string; autoLaunch: boolean }
|
||||
editor: { autoSave: boolean; tabSize: number }
|
||||
git: { confirmDiscard: boolean }
|
||||
terminal: { shell: string | null }
|
||||
}
|
||||
|
||||
export const DEFAULTS: HelderConfig = {
|
||||
ai: { command: 'claude', autoLaunch: true },
|
||||
editor: { autoSave: false, tabSize: 4 },
|
||||
git: { confirmDiscard: true },
|
||||
terminal: { shell: null },
|
||||
}
|
||||
|
||||
const THEME_TEMPLATE = `/* Helder theme — custom CSS applied OVER the built-in dark theme.
|
||||
* This file is created once and never overwritten; edit it freely.
|
||||
* The code font and font size live here (not in config.json). Uncomment and
|
||||
* tweak any variable below; you can also override any --token from the built-in
|
||||
* theme (see the design tokens in the app's styles). */
|
||||
:root {
|
||||
/* Code surfaces (editor + terminals) */
|
||||
/* --code-font: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; */
|
||||
/* --code-size: 13px; */ /* editor font size */
|
||||
/* --term-size: 12.5px; */ /* terminal font size */
|
||||
|
||||
/* Example accent override: */
|
||||
/* --accent: #4d8dff; */
|
||||
}
|
||||
`
|
||||
|
||||
let current: HelderConfig = DEFAULTS
|
||||
let themeCss = ''
|
||||
|
||||
function isPlainObject(v: unknown): v is Record<string, unknown> {
|
||||
return !!v && typeof v === 'object' && !Array.isArray(v)
|
||||
}
|
||||
|
||||
function deepMerge<T>(base: T, over: unknown): T {
|
||||
if (!isPlainObject(base) || !isPlainObject(over)) return base
|
||||
const out: Record<string, unknown> = { ...base }
|
||||
for (const key of Object.keys(over)) {
|
||||
const b = (base as Record<string, unknown>)[key]
|
||||
const o = over[key]
|
||||
if (isPlainObject(b) && isPlainObject(o)) out[key] = deepMerge(b, o)
|
||||
else if (o !== undefined) out[key] = o
|
||||
}
|
||||
return out as T
|
||||
}
|
||||
|
||||
/** (Re)resolve config + theme for a project root, regenerating the defaults file. */
|
||||
export async function resolveConfig(root: string): Promise<void> {
|
||||
const dir = join(root, '.helder')
|
||||
try {
|
||||
await mkdir(dir, { recursive: true })
|
||||
// Always regenerate the defaults file — it documents every setting.
|
||||
await writeFile(join(dir, 'config.default.json'), JSON.stringify(DEFAULTS, null, 2) + '\n')
|
||||
|
||||
let override: unknown = {}
|
||||
try { override = JSON.parse(await readFile(join(dir, 'config.json'), 'utf8')) } catch { /* none / invalid */ }
|
||||
current = deepMerge(DEFAULTS, override)
|
||||
|
||||
try {
|
||||
themeCss = await readFile(join(dir, 'theme.css'), 'utf8')
|
||||
} catch {
|
||||
themeCss = THEME_TEMPLATE
|
||||
await writeFile(join(dir, 'theme.css'), THEME_TEMPLATE)
|
||||
}
|
||||
} catch {
|
||||
// Read-only / inaccessible root: fall back to built-in defaults.
|
||||
current = DEFAULTS
|
||||
themeCss = ''
|
||||
}
|
||||
}
|
||||
|
||||
export function getConfig(): HelderConfig {
|
||||
return current
|
||||
}
|
||||
|
||||
export function getThemeCss(): string {
|
||||
return themeCss
|
||||
}
|
||||
Reference in New Issue
Block a user