import type { CliId } from '../adapters/cli/types.js'; import { type CliRuntimeConfig } from '../adapters/cli/runtime.js'; export declare const CLI_ID_CHOICES: Record; /** * 有序 CLI 选项 (id + 展示名), 顺序与 setup 交互菜单 (CLI_ID_CHOICES 序号) * 一致. dashboard "添加机器人" 的 CLI 下拉直接读这里, 避免再抄一份 * 列表. 单一事实源: CLI_ID_CHOICES 的值序. */ export declare const CLI_OPTIONS: ReadonlyArray<{ id: CliId; label: string; }>; /** * 把 setup 里"CLI 适配器"那一格的原始输入解析成合法的 CliId. * - 空 → undefined (调用方决定 "preserve current" 还是套默认 'claude-code') * - 序号 (CLI_ID_CHOICES 的键) → 映射成 cliId * - 已是合法 cliId 字面值 → 原样返回 * - 其它 → throw (typo 不该静默落盘成 cliId) */ export declare function resolveCliId(input: string | undefined): CliId | undefined; /** 去掉手机号里的空格与连字符(用户可能填 "+86 130-1111-2222"),便于校验/解析。 */ export declare function normalizeMobileEntry(entry: string): string; /** 是否是手机号形式的 allowedUsers 条目(已归一化空格/连字符后判定)。 */ export declare function isMobileEntry(entry: string): boolean; /** * 手机号规范化匹配键:把一个已归一化的手机号折叠成**唯一**的 E.164 数字键,用于 * 把飞书 `batch_get_id` 响应里回带的号码对回本地请求的号码。请求侧和响应侧都过 * 本函数,键相等即同一号码。 * * 规则(**不能像早期实现那样无脑剥 `+` 再一律当中国裸号**——那会让美国 `+1 3XX…` * 与中国裸号 `13X…` 折叠成同键,把 owner 绑到错的人 / 顶掉另一个 owner): * - `+` 开头:`+` 是权威国家码,直接剥掉 `+` 得到「国家码+号码」的 E.164 数字串 * (`+8613011112222`→`8613011112222`,`+14155550123`→`14155550123`)。 * - 无 `+` 的纯 11 位、以 1 开头:按配置契约(MOBILE_RE:裸号只接受中国 11 位) * 判定为中国大陆号,补 `86`(`13011112222`→`8613011112222`),从而与带 `+86` * 的请求/响应对齐。 * - 其它(已带 `86` 前缀等):原样。 * * 安全取舍:若飞书对海外号回带时**丢掉了 `+`**,海外裸号会被误判成中国号而与请求 * 不等 → 判 definitive miss(owner 用邮箱/union_id 兜底),这是 fail-closed 的**漏配**; * 绝不会把两个不同的人折叠成同一 owner(那才是危险的错配)。宁可漏配不可错配。 */ export declare function canonicalMobileKey(normalized: string): string; /** * 单个 allowedUsers 条目是否需要「启动/刷新时经飞书 contact API 解析成本 app * 的 open_id」。运行时权限(canTalk/canOperate)只认原生 ou_,故 email / union_id * (on_) / 手机号 / 甚至字面 ou_(要做跨 app 诊断)都要走一次解析;只有无法寻址 * 的裸串(邮箱前缀等)不需要。 * * 这是解析闸的**唯一真源**——daemon 启动闸、throw 兜底、allowed-users-apply 的 * needsContactResolve 全都调它,避免「新增一种身份格式后各处平行谓词漏改」导致 * 该格式在入口校验通过、却在某个解析闸被静默跳过(手机号 owner 冷启动自锁即 * 此类 bug)。新增身份格式时**只改这里**。 */ export declare function entryNeedsContactResolve(entry: string): boolean; /** * 合法的 allowedUsers 条目: * - on_xxx union_id — 跨应用稳定,推荐 * - 完整邮箱 — 人类可读,推荐 * - 手机号 — 大陆号直填 11 位;海外号带 + 区号。适合无企业邮箱的个人用户 * - ou_xxx open_id — 仅对签发该 ID 的同一应用有效,不推荐跨 bot 复用 * 裸邮箱前缀(如 "alice")不合法:解析器只认 ou_/on_、完整邮箱或手机号。 */ export declare function isValidAllowedUserEntry(entry: string): boolean; /** 返回非法的 allowedUsers 条目(既不是 ou_ 也不是完整邮箱,典型是裸邮箱前缀)。 */ export declare function findInvalidAllowedUserEntries(entries: string[]): string[]; /** * 是否存在能解析成 owner 的 allowedUsers 条目(ou_ 或完整邮箱)。 * owner = resolvedAllowedUsers 里第一个 ou_;完整邮箱会在启动时解析成 ou_,故二者都可作 owner。 */ export declare function hasOwnerEntry(allowedUsers: string[] | undefined): boolean; export interface BotConfigEditInput { name?: string; larkAppId?: string; larkAppSecret?: string; cliChoice?: string; cliPathOverride?: string; /** * Structured compatible-runtime edit. Three states: * - undefined -> preserve current value * - object -> validate/set it and write an equal legacy path shadow * - null -> clear it and its equal legacy path shadow */ cliRuntime?: CliRuntimeConfig | null; /** * 通用启动前缀(如 "aiden x claude")。三态: * - undefined → 不动 * - string → 设置(空串 / "-" 视为清空) * - null → 清空(选了普通 CLI 时清掉旧的 aiden×* 前缀) * 调用方(setup picker / dashboard)用 resolveCliSelection 解析选择项后传入, * 避免 bot-config-editor 反向依赖 cli-selection(会成循环 import)。 */ wrapperCli?: string | null; /** * Model 字段三态语义(setup 不再交互式询问 model,此字段仅由切换 CLI 时的 * 强制清空逻辑设 null;改 model 走 /config 卡片或手动编辑 bots.json): * - undefined → 这次编辑不动 model,保持原值 * - string → 设为这个 model * - null → 清空(删字段,回到 CLI 默认) */ model?: string | null; backendType?: string; workingDir?: string; /** * 固定默认目录:新话题直接在此目录启动、不弹仓库选择卡片(与 /config 的 * defaultWorkingDir 同字段)。与 workingDir(仓库选择卡片的扫描根)互补: * 留空不动;输入 - 清空、回到弹卡模式。目录存在性由调用方在写盘前校验。 */ defaultWorkingDir?: string; allowedUsers?: string; allowedChatGroups?: string; /** * 平台团队页是否展示这个 bot(默认 ON)。三态字符串: * - undefined → 不动 * - 'true' / 'false' → 设置('true' 落盘为删字段=默认 ON;'false' 落盘 false) * - '' / '-' → 清空(回到默认 ON) */ showInTeam?: string; } /** * 校验:配置了 allowedChatGroups 就必须有 owner。 * 否则群成员只拿到 canTalk,没人在 allowedUsers 里 → canOperate 对所有人关闭(连 owner 都没有), * /restart、/close、获取写链接、/grant 等敏感操作全不可用。setup 写盘前调用,抛错由调用方捕获中止写盘。 */ export declare function assertOwnerWhenChatGroups(config: { allowedUsers?: string[]; allowedChatGroups?: string[]; }): void; export interface RemoveBotConfigResult { bots: T[]; removed: T; index: number; } export declare function normalizeBotProcessName(input: string | undefined): string | undefined; export declare function botProcessName(bot: { name?: unknown; }, index: number, prefix?: string): string; /** * Sanitize a bot entry's `env` object into a clean `KEY -> string` map (valid * env-var names + string/number/boolean values; botmux-reserved keys dropped). * Thin wrapper over {@link sanitizePerBotEnv} for callers that hold a bot entry. */ export declare function botProcessEnv(bot: { env?: unknown; }): Record; export declare function normalizeBotConfig>(bot: T): T; export declare function parseBotConfigsJson = Record>(content: string, filePath?: string): T[]; export declare function assertUniqueBotProcessNames(bots: Array<{ name?: unknown; }>, prefix?: string): void; export declare function parseBotSelection(input: string, bots: Array<{ larkAppId?: string; name?: unknown; }>): number | undefined; export declare function removeBotConfig(bots: T[], selection: string): RemoveBotConfigResult | undefined; export declare function applyBotConfigEdits>(bot: T, input: BotConfigEditInput): T; //# sourceMappingURL=bot-config-editor.d.ts.map