/** * Serializable configuration and defaults for the sidebar host half. Loader * schema validation normally fills defaults; {@link resolveSidebarConfig} * applies the same defaults for direct callers that bypass the Loader. * @module dsh-better-sidebar/config */ import z from 'schemastery' import { SIDEBAR_PREFS_DEFAULTS, SIDEBAR_PREFS_NS, WIDTH_PERCENT_DEFAULT, WIDTH_PERCENT_MAX, WIDTH_PERCENT_MIN, type SidebarPrefs, } from './prefs-shared.ts' export { SIDEBAR_PREFS_DEFAULTS, SIDEBAR_PREFS_NS, WIDTH_PERCENT_DEFAULT, WIDTH_PERCENT_MAX, WIDTH_PERCENT_MIN, type SidebarPrefs, } from './prefs-shared.ts' /** Tunable sidebar host limits (every field optional; defaults fill in). */ export interface SidebarConfig { /** Read cap of one text file (bytes); larger files return truncated. */ readLimit?: number /** Media route cap (bytes); larger binaries are refused. */ mediaLimit?: number /** Explorer row bound of one level. */ listLimit?: number /** Terminals per session. */ terminalsPerSession?: number /** How long a disconnected terminal process survives awaiting a reconnect. */ reconnectGraceMs?: number } /** Schemastery schema for the plugin configuration. */ export const Config: z = z.object({ readLimit: z.number().step(1).min(1).default(512 * 1024), mediaLimit: z.number().step(1).min(1).default(20 * 1024 * 1024), listLimit: z.number().step(1).min(1).default(1000), terminalsPerSession: z.number().step(1).min(1).default(3), reconnectGraceMs: z.number().step(1).min(0).default(30_000), }) /** Fully defaulted sidebar host settings. */ export interface ResolvedSidebarConfig { readLimit: number mediaLimit: number listLimit: number terminalsPerSession: number reconnectGraceMs: number } /** * Apply direct-call defaults after Loader schema validation has normally run. * * @param config - Deployment-provided sidebar host settings. * @returns Complete settings consumed by the host half. */ export function resolveSidebarConfig(config: SidebarConfig | undefined): ResolvedSidebarConfig { return { readLimit: config?.readLimit ?? 512 * 1024, mediaLimit: config?.mediaLimit ?? 20 * 1024 * 1024, listLimit: config?.listLimit ?? 1000, terminalsPerSession: config?.terminalsPerSession ?? 3, reconnectGraceMs: config?.reconnectGraceMs ?? 30_000, } } // ── User-facing "Side card" preferences ───────────────────────────────────── /** Schemastery schema for the user-facing preferences (validated by the settings service). */ export const PrefsSchema: z = z.object({ openByDefault: z.boolean().default(true), defaultWidthPercent: z.number().step(1).min(WIDTH_PERCENT_MIN).max(WIDTH_PERCENT_MAX).default(WIDTH_PERCENT_DEFAULT), autoOpenSubagent: z.boolean().default(true), agentTerminalTools: z.boolean().default(false), // Per-feature enable switches are OPEN maps (any tab/viewer id, built-in or // external): an absent key means enabled, so old documents resolve to {} // (everything on) with no migration. Non-boolean values fail validation. tabsEnabled: z.dict(z.boolean()).default({}), viewersEnabled: z.dict(z.boolean()).default({}), })