/** * Global CLI config at ~/.shadok-ai/config.json (mode 600). The Telegram bot * token is **per launch directory** (`tokens[cwd]`), so each instance you run * from a different directory has its own bot — like the channel list. Port is * global. * * Per-cwd token semantics: * undefined → never asked for this dir yet (first run should prompt) * null → asked and deliberately skipped (never prompt again) * string → the token */ export interface Config { port?: number; /** @deprecated legacy single global token — migrated into `tokens` on boot. */ telegramToken?: string | null; /** Per launch-directory bot token, keyed by absolute cwd. */ tokens?: Record; /** Per launch-directory allowed Telegram chats (env TELEGRAM_ALLOWED_CHATS wins). */ telegramAllowed?: Record; /** Per launch-directory on/off switch for the Telegram bridge (default on). */ telegramEnabled?: Record; /** Optional GUI password (also settable via SHADOK_GUI_PASSWORD). */ guiPassword?: string; /** * Auto-apply a newer npm release (GUI checkbox). Authoritative once set; * when unset the server falls back to the SHADOK_AUTOUPDATE env var. */ autoUpdate?: boolean; /** * Opt-in to the shared-ledger reflex (docs/.../2026-08-25-shared-ledger-design). * OFF by default: it appends a "verify status before you assert/act" paragraph * to EVERY agent's pilot prompt, a behavioural change that must be opt-in. * Falls back to the SHADOK_LEDGER env var when unset. Takes effect at an * agent's next (re)spawn. */ ledgerEnabled?: boolean; /** * Which release stream to follow: "alpha" (every merge) or "beta" (only a * promoted version). Absent means "beta" — an instance that predates this * setting keeps updating, just on the calmer channel. * Design: docs/superpowers/specs/2026-08-23-update-channels-design.md */ updateChannel?: "alpha" | "beta"; /** * Permission mode every spawned agent starts in (a `claude --permission-mode` * value: "auto" | "acceptEdits" | "manual" | "plan" | "dontAsk" | * "bypassPermissions", or "default" for no flag). Authoritative once set; * else the SHADOK_PERMISSION_MODE env var, else the built-in default "auto" * (the Shift+Tab "auto mode on"). */ permissionMode?: string; /** * Default IANA time zone for `daily` crons ("Europe/Paris"). Without it the * hour follows the machine's zone — so a server running UTC shifts every * schedule silently. A cron can override it through its own `tz`. */ timezone?: string; /** * Per launch-directory cockpit name, keyed by absolute cwd. Shown in the * header brand and the browser tab so several cockpits (one per directory) * stay distinguishable. Absent = the default "shadok-ai". */ cockpitTitle?: Record; /** * Per launch-directory colour palette (an accent key like "emerald"), keyed by * absolute cwd. Absent = the default "amber". Like the name, it re-themes only * this instance and survives a reload. */ cockpitTheme?: Record; } export declare const SHADOK_DIR: string; export declare function loadConfig(): Config; export declare function saveConfig(cfg: Config): void; /** This directory's token entry (undefined = never asked). */ export declare function tokenForCwd(cfg: Config, cwd: string): string | null | undefined; export declare function setTokenForCwd(cfg: Config, cwd: string, token: string | null): void; /** * The effective token for an instance launched in `cwd`: an explicit env var * always wins, otherwise this directory's configured token. No global fallback — * a different directory gets a different bot (or none). */ export declare function effectiveToken(cfg: Config, cwd: string, env?: NodeJS.ProcessEnv): string | null; /** This directory's cockpit name, or null when none is set (→ default brand). */ export declare function titleForCwd(cfg: Config, cwd: string): string | null; /** * Set (or clear) this directory's cockpit name and persist. An empty/blank * title removes the entry so the cockpit falls back to the default brand. */ export declare function setTitleForCwd(cfg: Config, cwd: string, title: string): void; /** Known colour palettes; the first, "amber", is the default (stored as absent). */ export declare const COCKPIT_THEMES: readonly ["amber", "emerald", "azure", "violet", "rose", "cyan"]; /** This directory's palette key, or null for the default ("amber"). */ export declare function themeForCwd(cfg: Config, cwd: string): string | null; /** * Set (or clear) this directory's palette and persist. The default ("amber") and * any unknown key clear the entry, so the instance falls back to the default. */ export declare function setThemeForCwd(cfg: Config, cwd: string, theme: string): void; export interface TelegramConfig { token: string | null; envOverride: boolean; enabled: boolean; allowedChats: string[]; } /** Resolve the effective Telegram config for `cwd`: env overrides config. */ export declare function telegramConfig(cfg: Config, cwd: string, env?: NodeJS.ProcessEnv): TelegramConfig; export interface TelegramPatch { token?: string | null; enabled?: boolean; allowedChats?: string[]; } /** * Merge a UI patch into a copy of `cfg` (pure — caller persists). A token is * stored only when NOT under an env override; "" / null removes it. Absent keys * are left untouched. */ export declare function applyTelegramPatch(cfg: Config, cwd: string, patch: TelegramPatch, envOverride: boolean): Config; /** Pull TELEGRAM_BOT_TOKEN out of a shell-style env file body. */ export declare function parseLegacyToken(raw: string): string | null; /** * One-time migration of the OLD global token (the `telegram.env` file and the * legacy `telegramToken` config field, both global) into this directory's token * — but only for an already-established instance (`established`, i.e. it has a * bound Telegram group), so an existing setup keeps its bot while a brand-new * directory is prompted for its own. Both global sources are consumed (env file * renamed, config field deleted) so they never leak to another directory. */ export declare function migrateLegacyToken(cfg: Config, cwd: string, established: boolean): void;