import type { ProjectScanOptions } from './services/project-scanner.js'; import { type Locale } from './i18n/types.js'; import type { VoiceConfig } from './services/voice/types.js'; import type { VcMeetingConsumerProfileConfig } from './types.js'; export type RepoPickerMode = 'all' | 'repos'; export type LocalCliOpenMode = 'attach' | 'resume'; export type CodexNotifierNotifyWhen = 'locked_only' | 'always'; /** Keep the configurable prefix short enough to leave useful room for the * caller-provided group name. Count UTF-16 code units to match HTML * `maxLength` and the rest of the dashboard's string validation. */ export declare const GROUP_NAME_PREFIX_MAX_LENGTH = 32; /** Normalize the machine-wide prefix used by the `/group` slash command. * Missing/blank/invalid values are treated as disabled on the forgiving read * path; the Dashboard write path rejects invalid non-blank values. */ export declare function normalizeGroupNamePrefix(raw: unknown): string | undefined; export interface WhiteboardConfig { /** Optional local project whiteboard. Off by default; enabling it must not create boards by itself. */ enabled?: boolean; } export interface CodexNotifierGlobalConfig { /** 实验性机器级开关。缺省关闭;关闭后保留已信任 Hook,但 Hook 会快速跳过。 */ enabled?: boolean; /** 发送完成通知的 Bot App ID;启用时必须显式选择。 */ targetBotAppId?: string; /** 默认仅锁屏时发送飞书消息;always 表示每次任务完成都发送。 */ notifyWhen?: CodexNotifierNotifyWhen; } export interface HostOverloadAlertGlobalConfig { /** 机器级过载告警开关。缺省关闭。开启后由所选「通知 Bot」的 daemon 每 30s * 采样整机 load/内存,越过过载线时给该 Bot 的管理员发飞书私信、恢复时再发一条。 */ enabled?: boolean; /** 发送过载告警的 Bot App ID;启用时必须显式选择。只有该 Bot 自己的 daemon * 会采样并发送(它就跑在本机),故无需跨 daemon 投递队列。 */ targetBotAppId?: string; /** 进入过载的 load 阈值:load15 > cpuCount * 此值。缺省 1.5。退出线按固定 * 比例(95%)从它派生,保证 hysteresis(exit < enter)。 */ enterLoadRatio?: number; /** 进入过载的已用内存占比阈值(0..1)。缺省 0.92。退出线同样按 95% 派生。 */ enterMemUsedFrac?: number; /** 过载卡上「重启浏览器」按钮的可配置目标清单。缺省内置 Arc / Chrome / Edge * (见 core/browser-restart.ts 的 DEFAULT_BROWSER_TARGETS)。此处按 bundleId * 合并覆盖:同 bundleId 覆盖 label/openArgs/enabled;新 bundleId 追加; * enabled:false 关闭某个默认项。绝不写死浏览器,加新浏览器只改配置。 */ browserRestartTargets?: HostOverloadBrowserTargetConfig[]; } /** 单个可重启浏览器目标的配置项(全部可选,仅 bundleId 必填才生效)。 */ export interface HostOverloadBrowserTargetConfig { /** macOS CFBundleIdentifier,如 company.thebrowser.Browser。唯一定位键。 */ bundleId: string; /** 卡片显示名,如 Arc / Chrome / Edge。缺省回退为 bundleId。 */ label?: string; /** 重启时透传给 `open -b --args …` 的额外参数(如 Chromium 的 * --restore-last-session 强制恢复标签)。 */ openArgs?: string[]; /** 置 false 则该浏览器永不出现在卡片上(用于关掉某个默认项)。 */ enabled?: boolean; } /** * 共享会议角色预设条目。刻意不带 `agentAppId`:执行方永远是「被拉进这场会议的 * 那个 bot」,在合并进 per-bot 配置时才绑定。历史上预设把 `agentAppId` 写死, * 结果拉 A 进会却把 B 拉进监听群——共享目录从类型上就消灭了这条路径。 */ export type VcMeetingSharedConsumerProfile = Omit; /** 全 fleet 共享的会议角色预设目录。任何没有自己 `consumerProfiles` 的 bot * 都继承这份目录。 */ export interface VcMeetingSharedConsumerCatalog { profiles: VcMeetingSharedConsumerProfile[]; defaultMode: 'listenOnly' | 'agents'; defaultConsumerIds: string[]; } export interface VcMeetingAgentGlobalConfig { /** Machine-wide VC meeting listener kill-switch. Missing means enabled for * backwards compatibility; per-bot vcMeetingAgent.enabled still controls * whether a given bot responds to meetings. */ enabled?: boolean; /** DEPRECATED (2026-08): the single-listener pin is retired — every bot with * VC active handles the meeting events it receives. Kept only so an existing * config round-trips without data loss; readers must ignore it. */ listenerBotAppId?: string; /** 共享角色预设目录,见 {@link VcMeetingSharedConsumerCatalog}。 */ consumerCatalog?: VcMeetingSharedConsumerCatalog; } export interface WorkflowFeatureGlobalConfig { /** Machine-wide v3 Workflow kill-switch. Missing / `enabled !== false` * preserves the legacy behavior (feature ON). Set false to turn the whole * workflow feature off on this host: the `/workflow` grill + Saved-Workflow * run/save entries are refused, the `botmux-workflow` family of skills stops * being advertised/installed, and the CLI authoring/run subcommands refuse. * In-flight run management (cancel / retry / grant) stays available so a run * started before the flip can still be wound down. The multi-bot * `botmux-orchestrate` skill is intentionally NOT gated by this — it is a * separate long-running-orchestration capability, not a v3 workflow. */ enabled?: boolean; } export interface GlobalConfig { lang?: Locale; /** Machine-wide default prefix for groups created via `/group` or `/g`. * Other creation paths intentionally ignore it. Missing means disabled. */ groupNamePrefix?: string; /** Machine-wide repo picker display mode. Missing / 'all' preserves legacy * behavior (repos + linked worktrees). 'repos' lists only main worktrees in * selection cards; explicit /repo /abs/path/to/worktree still works. */ repoPickerMode?: RepoPickerMode; /** Machine-wide dashboard settings. These are intentionally global rather * than per-bot: they govern the dashboard security boundary and the default * terminal-opening behavior of cards emitted by all daemons on this host. */ dashboard?: DashboardGlobalConfig; /** TTS engine + credentials for the voice-summary feature. See * services/voice/types.ts. Presence (with usable creds) gates the * "🔊 语音总结" button. */ voice?: VoiceConfig; /** Machine-wide auto-update / auto-restart schedule. Off unless explicitly * enabled. Only the primary daemon (bot-0) acts on it — see core/maintenance.ts. */ maintenance?: MaintenanceConfig; /** Optional local project whiteboard. Disabled unless explicitly enabled. */ whiteboard?: WhiteboardConfig; /** Codex App/CLI 独立任务完成通知。机器级、默认关闭,由 Dashboard 管理。 */ codexNotifier?: CodexNotifierGlobalConfig; /** 机器过载告警。机器级、默认关闭,由 Dashboard 管理;走所选「通知 Bot」发送。 */ hostOverloadAlert?: HostOverloadAlertGlobalConfig; /** Machine-wide meeting listener kill-switch. Missing / enabled !== false * preserves legacy behavior; set false to stop accepting new VC meetings * and skip restore/readiness for this host. */ vcMeetingAgent?: VcMeetingAgentGlobalConfig; /** Machine-wide v3 Workflow kill-switch. Missing / enabled !== false keeps * the feature ON (legacy behavior); set false to disable it host-wide. The * `BOTMUX_WORKFLOW_ENABLED` env var overrides this when set. */ workflow?: WorkflowFeatureGlobalConfig; /** Optional HTTP(S) proxy for the daemon's own outbound downloads (e.g. the * HD2D office assets). Node's global fetch ignores HTTP_PROXY/HTTPS_PROXY, * so hosts behind a proxy must set this (or the env vars, which we read as a * fallback). Form: `http://host:port` or `http://user:pass@host:port`. */ httpProxy?: string; /** OAuth redirect base for user authorization (/login). When set (e.g. * `http://10.1.2.3:7891`, typically this host's dashboard origin), auth * links redirect to `/oauth/callback`, which the dashboard receives * and completes automatically — the zero-copy-paste flow for daemons that * do NOT run on the user's own machine. Missing → the legacy * `http://127.0.0.1:9768/callback` paste-back flow. */ oauthRedirectBase?: string; /** Machine-wide user skill registry policy. Skill package storage itself lives under * ~/.botmux/skills and is managed by services/skill-registry-store.ts. */ skills?: GlobalSkillConfig; /** Plugin ids enabled for every bot. Per-bot plugin ids are additive. */ plugins?: string[]; /** 远程访问. When true (and this machine is bound to the central platform), * session web-terminal links, Feishu card terminal buttons, and connector * webhook URLs use the central-platform machine subdomain instead of local * host:port URLs. Off by default — only local links are emitted. Gated in * buildTerminalUrl / publicWebhookUrl via isRemoteAccessEnabled(). */ remoteAccess?: boolean; /** Machine-wide timezone for USER scheduled tasks (scheduler). An IANA name * (e.g. 'Asia/Shanghai'). Overrides the host's auto-detected local zone for * cron firing, one-shot「明天HH:MM」parsing, and all schedule displays — * see utils/timezone.ts `scheduleTimeZone()`. Absent ⇒ follow the host zone. * Stored lenient here; final IANA validity is enforced on write * (settings-write-applier) and re-checked at resolve time. */ scheduleTimeZone?: string; } export interface GlobalSkillConfig { trustProjectSkills?: 'off' | 'trusted' | 'all'; delivery?: 'auto' | 'prompt' | 'native'; /** Machine-wide default for how botmux's **built-in bridge skills** * (botmux-send / botmux-schedule / …) reach CLIs that only support a GLOBAL * skills directory (codex/gemini/opencode/… — everything with `skillsDir`, * i.e. no per-session `--plugin-dir` injection like Claude Code): * - `global`: install the skill files into the CLI's shared global dir * (e.g. `~/.codex/skills`). Full native experience, but the user's own * standalone `codex`/`gemini` sees & can mis-fire them. Right for hosts * whose users NEVER run those CLIs by hand. * - `prompt` (default): don't touch the global dir; inject a compact skill * catalog into the session prompt and let the model pull full instructions * on demand via `botmux skill show `. Session-scoped → no leak. * - `off`: inject neither files nor catalog — only the routing hints + a * pointer at `botmux --help`. Lightest; relies on CLI help completeness. * A per-bot `skillInjection` (bots.json) overrides this. Unset ⇒ `prompt`. */ builtinInjection?: 'global' | 'prompt' | 'off'; } export interface MaintenanceConfig { /** At `time` (once/day) update the owning npm/pnpm/Bun global install to the * latest version — download/install only, never restarts on its own. * Disabled for local-dev and unsupported install layouts. */ autoUpdate?: MaintenanceTask; /** When enabled (and autoUpdate is on), restart right after a successful * auto-update that installed a newer version, to apply it. No schedule of * its own — reuses autoUpdate's time, fires only when there's a pending * update. */ autoRestart?: MaintenanceToggle; } export interface MaintenanceTask { enabled?: boolean; /** Local-time (Asia/Shanghai) "HH:MM", once per day. */ time?: string; } export interface MaintenanceToggle { enabled?: boolean; } export interface HerdrTraexPluginConfig { enabled?: boolean; /** herdr plugin source: `owner/repo[/subdir]` passed to `herdr plugin install`. */ source?: string; /** Optional git ref (tag / branch / commit SHA) → `--ref`. Prefer a pinned SHA. */ ref?: string; } export interface DashboardGlobalConfig { /** When true, dashboard GET/HEAD pages and JSON APIs are public read-only; * mutations still require the active dashboard token. */ publicReadOnly?: boolean; /** When true, terminal buttons on Feishu cards use Feishu's sidebar web_url * wrapper. Default false opens the terminal URL directly. */ openTerminalInFeishu?: boolean; /** Opt in to native "Open " buttons on supported desktop hosts. * Default false. When enabled, localCliOpenMode defaults to 'attach' so a * botmux-managed persistent backend enters the same underlying CLI and * preserves Feishu continuity. ZMX uses its native local terminal while * Feishu remains plain text; 'resume' starts a separate CLI resume process * and may break that continuity. */ enableLocalCliOpen?: boolean; /** How native "Open " buttons launch on macOS. Missing defaults to * 'attach': attach to the current managed/adopted backend session when an * exact attach target is available. 'resume' keeps the prior direct CLI * resume behavior for supported CLIs. */ localCliOpenMode?: LocalCliOpenMode; /** Experimental current-chat bot discovery via Lark `/members/bots`. Default * ON (absent ⇒ enabled); set false to disable from the dashboard. Read live * by the daemon — see config.ts `resolveChatBotDiscoveryConfig`. */ chatBotDiscovery?: boolean; /** Installed plugin Dashboard pages pinned into the main sidebar. This is a * machine-wide display preference and does not enable the plugin for a Bot. */ pinnedPlugins?: string[]; /** Opt-in TraeX herdr plugin bootstrap. Default OFF; source/ref are operator-supplied. */ herdrTraexPlugin?: HerdrTraexPluginConfig; /** Experimental: globally enable RPC input mode for RPC-capable codex-family * bots (codex / traex) — user input goes via the app-server JSON-RPC channel * instead of a tmux paste, bypassing codex's terminal paste-drop. Default OFF * (absent ⇒ off); flip on to enable fleet-wide. Read live by the daemon — * see config.ts `codexRpcInputDefault`. A per-bot `codexRpcInput: true` still * force-enables regardless of this global default. */ codexRpcInput?: boolean; /** Whether botmux auto-bypasses Codex's interactive hook-trust gate ("Press t * to trust") for Codex-family plain-TUI launches (codex / traex). Codex 0.14x * gates the botmux-installed ~/.codex/hooks.json behind a manual trust prompt, * and every botmux upgrade rewrites the hook script → its hash changes → the * gate re-fires; a botmux-managed pane has no human to press `t`, so the first * turn wedges. When enabled, the adapter passes `--dangerously-bypass-hook-trust`. * Default ON (ABSENT ⇒ ON — only an explicit `false` disables): a headless * fleet needs it to not wedge. This is a SEPARATE knob from the approval/sandbox * bypass: the flag trusts ALL hook sources codex sees (user/project/plugin), not * only botmux's, so an operator who does not want project/plugin `.codex/hooks.json` * auto-trusted can turn it off. Still ANDed with the per-bot `!disableCliBypass` * fail-closed lower bound (a restricted bot never gets it regardless). Read live * by the daemon — see config.ts `bypassCodexHookTrust`. */ bypassCodexHookTrust?: boolean; /** Experimental: inject the "no visible output" anti-resend guidance into the * botmux routing hints. Counters Claude Code (≥2.1.212) thinking-only nudges * that make a model resend after a silent `botmux send`-only turn. Default OFF * (absent ⇒ off): mainly helps when Claude Code drives a non-Claude backend * model; harmless but unnecessary otherwise. Read live — see config.ts * `noVisibleOutputHint`. */ noVisibleOutputHint?: boolean; } /** True when `s` is a valid 24h "HH:MM" (leading zero optional on hours). * Shared by the config reader and the dashboard PUT validator. */ export declare function isValidHhMm(s: string): boolean; /** Validate a maintenance patch from the dashboard PUT. Type-strict on enabled * (both keys) and on autoUpdate's time. autoRestart is a toggle — any `time` * on it is ignored (it reuses autoUpdate's schedule). */ export declare function parseMaintenancePatch(body: unknown): { ok: true; patch: MaintenanceConfig; } | { ok: false; error: string; }; export declare function globalConfigPath(): string; /** Typed view of the global config. Validates `lang` so a malformed file * can't propagate a bad value into the i18n module. */ export declare function readGlobalConfig(): GlobalConfig; /** Drop the short-TTL read cache so the next readGlobalConfig re-reads from * disk. Same-process writes invalidate automatically (mergeGlobalConfig); this * is for cross-process freshness on demand — e.g. the dashboard process after * `botmux bind` (a different process) flips remoteAccess on, so the post-bind * dashboard URL reflects the new value without waiting out the TTL. */ export declare function invalidateGlobalConfigCache(): void; /** Live VC meeting listener global config. Missing config means enabled. * * This path is checked at every VC event ingress. Use a file mtime cache * instead of the general 2s readGlobalConfig TTL so dashboard flips take effect * across all daemon processes without restart and without parsing the file on * every event. */ export declare function globalVcMeetingAgentConfigLive(): VcMeetingAgentGlobalConfig; /** 共享角色预设目录(live 读,随 mtime 失效)。undefined = 还没配置过。 */ export declare function globalVcMeetingSharedConsumerCatalog(): VcMeetingSharedConsumerCatalog | undefined; /** * 未经归一化的共享目录原始值(可能是 undefined / 任意形状)。写路径用它算乐观 * 并发 revision——手改配置即使被 forgiving 读路径归一化掉,也必须让 revision 变。 */ export declare function rawGlobalVcMeetingSharedConsumerCatalog(): unknown; /** * 写共享角色预设目录。`null` 清空目录(所有 bot 回到「无预设」)。 * * `mergeGlobalConfig` 只做顶层 key 合并,所以这里先读出现有 `vcMeetingAgent` * 对象再整体写回——否则会把同一层的 `enabled` 抹掉。未知字段原样保留。 */ export declare function writeGlobalVcMeetingSharedConsumerCatalog(catalog: VcMeetingSharedConsumerCatalog | null): void; export declare function isGlobalVcMeetingAgentEnabled(): boolean; export declare function globalVcMeetingAgentListenerBotAppId(): string | undefined; /** 远程访问 enabled? Reads the (short-TTL cached) global config — cheap enough to * call per link. False unless explicitly enabled. Gates whether central-platform * URLs are emitted (see buildTerminalUrl / publicWebhookUrl). */ export declare function isRemoteAccessEnabled(): boolean; /** Machine-wide v3 Workflow feature kill-switch. * * Missing / `workflow.enabled !== false` means ON (backwards compatible — the * feature has always been on). An explicit `false` in `~/.botmux/config.json` * disables it. The `BOTMUX_WORKFLOW_ENABLED` env var, when set to a non-empty * value, OVERRIDES the config file either way (`true`/`1`/`yes`/`on` ⇒ enabled, * anything else ⇒ disabled) — it is both the escape hatch if the config gate * misfires and the channel the worker injects into CLI panes so a pane's * `botmux workflow …` subcommand agrees with the daemon that spawned it. * * Read live off the short-TTL config cache so a dashboard toggle takes effect on * the next session/turn without a daemon restart (mirrors whiteboardEnabled / * isGlobalVcMeetingAgentEnabled). */ export declare function isWorkflowFeatureEnabled(env?: NodeJS.ProcessEnv): boolean; /** Derive repo-picker scan options from the machine-wide `repoPickerMode`. * 'repos' hides linked worktrees from selection cards; anything else * (default 'all') lists repos + their worktrees. Shared by every scan * entry point (daemon spawn paths + `/repo`) so they stay consistent. */ export declare function repoPickerScanOptions(): ProjectScanOptions; /** Merge a patch into the on-disk config, preserving unknown keys. Creates * the file (and parent dir) on first write. Use `null` to explicitly delete * a known key from the file. */ export declare function mergeGlobalConfig(patch: Partial>): void; /** Merge only the dashboard sub-config, preserving unknown keys inside that * object so a newer client can safely share the same config file. */ export declare function mergeDashboardConfig(patch: DashboardGlobalConfig): DashboardGlobalConfig; /** 写入 notifier 的完整已知配置,同时保留配置块内的未来字段。 */ export declare function writeCodexNotifierConfig(config: CodexNotifierGlobalConfig): CodexNotifierGlobalConfig; /** 写入机器过载告警的完整已知配置,同时保留配置块内的未来字段。 */ export declare function writeHostOverloadAlertConfig(config: HostOverloadAlertGlobalConfig): HostOverloadAlertGlobalConfig; /** Merge only the maintenance sub-config, preserving unknown sibling keys. * Shallow-merges at the task level (autoUpdate / autoRestart): callers send * the full task object, so a present key replaces it wholesale. */ export declare function mergeMaintenanceConfig(patch: MaintenanceConfig): MaintenanceConfig; /** Convenience: set the global UI locale (or clear it when `null`). */ export declare function setGlobalLocale(loc: Locale | null): void; //# sourceMappingURL=global-config.d.ts.map