/** * Configuration layer for twinkly-mcp. * * Resolution order (lowest → highest precedence): * defaults ← config file ← environment variables ← CLI flags * * `parseConfig` is a pure function with all I/O injected, so it is fully * unit-testable without touching the real process env, argv, or filesystem. * `loadConfig` is the thin production wrapper that wires in the real sources. */ import { z } from 'zod'; /** Tool categories that can be selectively enabled via `tools`. */ export declare const TOOL_GROUPS: readonly ["discovery", "status", "power", "color", "effects", "movies", "admin"]; export type ToolGroup = (typeof TOOL_GROUPS)[number]; export declare const TRANSPORTS: readonly ["stdio", "http"]; export declare const LOG_LEVELS: readonly ["error", "warn", "info", "debug"]; /** A single named Twinkly device. */ declare const deviceSchema: z.ZodObject<{ name: z.ZodString; ip: z.ZodString; }, "strip", z.ZodTypeAny, { name: string; ip: string; }, { name: string; ip: string; }>; export type DeviceConfig = z.infer; declare const configSchema: z.ZodEffects, "many">; defaultDevice: z.ZodOptional; discovery: z.ZodBoolean; transport: z.ZodEnum<["stdio", "http"]>; port: z.ZodNumber; readonly: z.ZodBoolean; /** `undefined` means "all groups enabled". */ tools: z.ZodOptional, "many">>; allowAdmin: z.ZodBoolean; timeoutMs: z.ZodNumber; logLevel: z.ZodEnum<["error", "warn", "info", "debug"]>; }, "strip", z.ZodTypeAny, { discovery: boolean; devices: { name: string; ip: string; }[]; transport: "stdio" | "http"; port: number; readonly: boolean; allowAdmin: boolean; timeoutMs: number; logLevel: "error" | "warn" | "info" | "debug"; defaultDevice?: string | undefined; tools?: ("discovery" | "status" | "power" | "color" | "effects" | "movies" | "admin")[] | undefined; }, { discovery: boolean; devices: { name: string; ip: string; }[]; transport: "stdio" | "http"; port: number; readonly: boolean; allowAdmin: boolean; timeoutMs: number; logLevel: "error" | "warn" | "info" | "debug"; defaultDevice?: string | undefined; tools?: ("discovery" | "status" | "power" | "color" | "effects" | "movies" | "admin")[] | undefined; }>, { discovery: boolean; devices: { name: string; ip: string; }[]; transport: "stdio" | "http"; port: number; readonly: boolean; allowAdmin: boolean; timeoutMs: number; logLevel: "error" | "warn" | "info" | "debug"; defaultDevice?: string | undefined; tools?: ("discovery" | "status" | "power" | "color" | "effects" | "movies" | "admin")[] | undefined; }, { discovery: boolean; devices: { name: string; ip: string; }[]; transport: "stdio" | "http"; port: number; readonly: boolean; allowAdmin: boolean; timeoutMs: number; logLevel: "error" | "warn" | "info" | "debug"; defaultDevice?: string | undefined; tools?: ("discovery" | "status" | "power" | "color" | "effects" | "movies" | "admin")[] | undefined; }>; export type TwinklyMcpConfig = z.infer; /** Name used for the single device implied by `TWINKLY_IP` / `--ip`. */ export declare const IMPLICIT_DEVICE_NAME = "default"; export declare class ConfigError extends Error { readonly name = "ConfigError"; } /** Raw, un-normalized fragment contributed by one source (file/env/cli). */ interface ConfigFragment { devices?: DeviceConfig[]; defaultDevice?: string; discovery?: boolean; transport?: string; port?: number; readonly?: boolean; tools?: string[]; allowAdmin?: boolean; timeoutMs?: number; logLevel?: string; } export interface ParseSources { /** Parsed contents of a config file, if any. */ file?: ConfigFragment; /** `process.env` (or a stand-in). */ env?: Record; /** CLI args without the `node script` prefix (i.e. `process.argv.slice(2)`). */ argv?: string[]; } /** * Merge all sources and validate. Throws {@link ConfigError} with a readable * message on any invalid input. */ export declare function parseConfig(sources?: ParseSources): TwinklyMcpConfig; /** Resolve which config file path to read, from `--config` or `TWINKLY_CONFIG`. */ export declare function resolveConfigPath(env: Record, argv: string[]): string | undefined; export interface LoadConfigDeps { env?: Record; argv?: string[]; readFile?: (path: string) => string; } /** Production entry point: reads the real env, argv, and (optional) config file. */ export declare function loadConfig(deps?: LoadConfigDeps): TwinklyMcpConfig; export {};