import type { BotConfig } from '../bot-registry.js'; import { type FeedbackPolicyLayer } from './feedback-policy-resolver.js'; /** * 生效时机: * • immediate — 运行时读取实时 `bot.config`,热更新后下一条消息/事件即生效。 * • next-session — spawn CLI 时才读取,当前运行中的会话需 `/restart` 重启才换新值; * 新会话直接用新值。 */ export type ConfigEffect = 'immediate' | 'next-session'; export type ConfigFieldKind = 'string' | 'stringList' | 'boolean' | 'number' | 'enum' | 'cli' | 'dir' | 'allowedUsers' | 'json'; export interface ConfigFieldSpec { /** 用户面命令里用的字段名(大小写不敏感匹配,见 {@link findConfigField})。 */ key: string; /** bots.json / 内存 BotConfig 上的实际字段。 */ configKey: keyof BotConfig; kind: ConfigFieldKind; effect: ConfigEffect; /** 是否支持 `/config unset `(清回默认)。boolean 字段用 `set off` 即可,无需 unset。 */ clearable: boolean; /** kind==='enum' 时的合法取值(已小写)。 */ enumValues?: readonly string[]; /** kind==='string' 的最大长度(trim 后计),超出 coerce 报 too_long。缺省不限。 */ maxLen?: number; /** kind==='stringList' 的自定义解析器(自由文本 → 归一化数组)。缺省用 * customPassthroughCommands 的逗号/空格分隔解析;带参数的命令行字段 * (如 startupCommands)须指定按逗号/换行分隔、保留内部空格的解析器。 */ parseList?: (raw: string) => string[]; /** 一句话说明,进 `/config help` / `/config get`。 */ hint: string; } /** * Phase 1 可编辑的运营字段。**不含** allowedUsers 之外的权限字段、secret、brand * (绑定租户、需重启重建 client)、name(pm2 进程名,启动期绑定)。allowedUsers * 在此登记但走 {@link setBotAllowedUsers} 的专用异步路径(重解析 + 防自锁)。 */ export declare const CONFIG_FIELDS: readonly ConfigFieldSpec[]; /** 大小写不敏感地按 key 找字段 spec。 */ export declare function findConfigField(key: string): ConfigFieldSpec | undefined; /** 可设置字段名列表(用于报错提示 / help)。 */ export declare function settableFieldKeys(): string[]; /** 把 on/off 类输入解析成布尔,无法识别 → undefined。 */ export declare function parseBooleanValue(raw: string): boolean | undefined; export interface ConfigSnapshotRow { key: string; value: string; effect: ConfigEffect; } /** 当前可编辑字段的快照(供 `/config get`)。不含 secret。 */ export declare function getConfigSnapshot(larkAppId: string): { ok: true; rows: ConfigSnapshotRow[]; info: { cliId: string; brand: string; resolvedAdmins: number; workingDirs: string[]; }; } | { ok: false; }; export type ApplyFieldResult = { ok: true; oldText: string; newText: string; effect: ConfigEffect; } | { ok: false; reason: 'bot_not_registered' | 'bot_not_in_config' | string; }; export declare function setDisplayNameRefresher(fn: (() => void) | null): void; /** * 写入并热更新一个**已解析**的字段值(string / boolean / null=清除)。 * 调用方负责按 kind 校验后再传值;本函数只负责落盘 + 同步内存。 * 不处理 allowedUsers(异步,见 {@link setBotAllowedUsers})。 */ export declare function applyConfigField(larkAppId: string, spec: ConfigFieldSpec, value: unknown): Promise; export type SetFeedbackPolicyResult = { ok: true; } | { ok: false; reason: string; }; export declare function setBotFeedbackPolicy(larkAppId: string, policy: FeedbackPolicyLayer | null): Promise; export declare function setChatFeedbackPolicy(larkAppId: string, chatId: string, policy: FeedbackPolicyLayer | null): Promise; export type SetAllowedUsersResult = { ok: true; raw: string[]; resolved: string[]; } | { ok: false; reason: 'bot_not_registered' | 'bot_not_in_config' | 'self_lockout' | 'empty_resolved' | string; }; /** * 改 allowedUsers(管理员名单)。这是动信任根的敏感操作,与普通字段分开: * 1. 用 bot 凭证把邮箱/on_ 解析成 open_id(与启动期同一路径)。 * 2. **防自锁**:解析后名单必须仍含发起人的 open_id,否则拒绝——避免把自己踢出管理员。 * 3. 解析后非空才写。 * 4. 落盘原始条目(邮箱/on_/ou_,与 setup 一致),并同步内存 resolvedAllowedUsers / * rawAllowedUserResolution(与 daemon 启动期赋值同口径),无需重启。 * * confirm 二次确认由调用方(command-handler)处理,本函数只做校验 + 落盘。 */ export declare function setBotAllowedUsers(larkAppId: string, rawEntries: string[], senderOpenId: string | undefined): Promise; export type CoerceResult = { ok: true; value: unknown; } | { ok: false; reason: 'invalid_bool' | 'invalid_enum' | 'invalid_cli' | 'invalid_dir' | 'invalid_number' | 'invalid_json' | 'reserved_env' | 'empty' | 'too_long' | `invalid_mojo_config: ${string}`; }; /** * 把一个**原始**字段值(来自卡片下拉/输入或别处)按字段 kind 解析校验成可落盘的 * string|boolean。dir 在此做存在性检查(无 locale,返回结构化 reason,调用方再本地化)。 * allowedUsers 不走这里(异步,见 {@link setBotAllowedUsers})。 */ export declare function coerceConfigValue(spec: ConfigFieldSpec, raw: unknown): CoerceResult; /** * 渲染交互配置卡片所需的纯数据视图。card-builder 只吃这个(不反向 import store), * 避免循环依赖。`modelChoices` 由调用方按 cliId 解析后传入(command-handler / * card-handler 已 import CLI 适配器),缺省空数组 → 不渲染 model 下拉。 */ export interface ConfigCardData { larkAppId: string; botName: string; cliId: string; cliOptions: Array<{ id: string; label: string; }>; model: string | null; modelChoices: string[]; lang: string | null; /** 私聊单聊模式 p2pMode('chat' | 'thread' | 'group');null = 未设(默认 chat)。 */ p2pMode: string | null; brandLabel: string | null; defaultWorkingDir: string | null; /** 入群主动开工首轮 prompt(autoStartOnGroupJoinPrompt)。 */ autoStartPrompt: string | null; /** 额外放行透传的 slash 命令(customPassthroughCommands),空格分隔;null = 未设。 */ customPassthroughCommands: string | null; /** 开会话后自动发的命令(startupCommands),逗号分隔(命令自带空格参数,故不能空格分隔);null = 未设。 */ startupCommands: string | null; /** team 级默认角色文本(不在 bots.json,存独立角色文件)。 */ teamRole: string | null; /** messageQuota.defaultLimit(被授权人默认消息额度);null = 不限。 */ quota: number | null; admins: number; booleans: Array<{ key: string; on: boolean; }>; } export declare function getConfigCardData(larkAppId: string, modelChoices?: readonly string[]): ConfigCardData | null; //# sourceMappingURL=bot-config-store.d.ts.map