dsh-agent-toolkit 0.2.9 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +103 -87
- package/lib/client.js.map +1 -1
- package/lib/index.js +77 -14
- package/lib/index.js.map +1 -1
- package/package.json +8 -4
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["z","z","MAX_BODY_BYTES","json","readJsonBody","z","readJsonBody","z","readJsonBody","z","CreateBodySchema","z","UpdateBodySchema","z","z","readJsonBody"],"sources":["../src/agents/store.ts","../src/channels/basic-tools.ts","../src/agents/builtin.ts","../src/agents/import-yaml.ts","../src/agents/registry.ts","../src/agents/tool-catalog.ts","../src/shared/storage.ts","../src/prompt/defaults.ts","../src/prompt/match.ts","../src/prompt/index.ts","../src/prompt/layer-source.ts","../src/shared/webserver.ts","../src/shared/http.ts","../src/prompt/api.ts","../src/prompt/persona.ts","../src/delegate/tool.ts","../src/delegate/index.ts","../src/delegate/active.ts","../src/delegate/routes.ts","../src/delegate/api.ts","../src/agents/api.ts","../src/agents/create-command.ts","../src/channels/agent-setup.ts","../src/channels/agents-port.ts","../src/channels/feishu/api.ts","../src/channels/directive.ts","../src/channels/feishu/parse.ts","../src/channels/feishu/cards.ts","../src/channels/feishu/reply.ts","../src/channels/approval/feishu.ts","../src/channels/feishu/card-action.ts","../src/channels/feishu/index.ts","../src/bots/store.ts","../src/channels/outbound.ts","../src/channels/inbound.ts","../src/channels/ports.ts","../src/channels/role-assembly.ts","../src/channels/router.ts","../src/channels/approval/center.ts","../src/channels/runtime.ts","../src/channels/scope-joiner.ts","../src/channels/tool-scope.ts","../src/channels/approval/answerer.ts","../src/bots/api.ts","../src/bots/register-app.ts","../src/bots/index.ts","../src/agents/bot-preset.ts","../src/agents/team-preset.ts","../src/schedule/store.ts","../src/schedule/api.ts","../src/schedule/executor.ts","../src/schedule/timing.ts","../src/schedule/scheduler.ts","../src/schedule/service.ts","../src/schedule/tools.ts","../src/schedule/index.ts","../src/index.ts"],"sourcesContent":["/** agents 注册表存储域声明:记录 schema + domain 布局的单一来源。 */\r\nimport { z } from 'zod'\r\nimport { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport type { LayerConfig } from '../prompt/types.ts'\r\n\r\n/** Agent id 约束:'main' 或小写字母开头、仅 [a-z0-9-]、总长 ≤ 32。 */\r\nexport const AGENT_ID_RE = /^(?:main|[a-z][a-z0-9-]{0,31})$/\r\n\r\n/** 一条 Agent 注册表记录。tools 仅白名单。 */\r\nexport interface AgentRecord {\r\n id: string // 'main' 或 [a-z0-9-] slug\r\n name: string\r\n description?: string\r\n persona?: string // 角色唯一可自定义提示层(固定分层中的 persona 层文本)\r\n /** @deprecated 仅迁移输入:旧版多分层,createRegistry 读取时拼接进 persona 后剥离。 */\r\n promptLayers?: LayerConfig[]\r\n model?: { provider: string; model: string }\r\n tools?: { allow: string[] } // 仅白名单;空数组拒绝(min(1) 语义)\r\n builtin?: boolean\r\n /** 团队可见性:省略/true = 出现在 Agent 团队名册并可被委派;false = 隐藏。bot 绑定不受此字段影响。 */\r\n visibleInTeam?: boolean\r\n}\r\n\r\nexport const LayerConfigSchema = z.object({\r\n name: z.string(),\r\n order: z.number(),\r\n text: z.string(),\r\n})\r\n\r\nexport const AgentRecordSchema: z.ZodType<AgentRecord> = z.object({\r\n id: z.string().regex(AGENT_ID_RE),\r\n name: z.string().min(1),\r\n description: z.string().optional(),\r\n persona: z.string().optional(),\r\n promptLayers: z.array(LayerConfigSchema).optional(),\r\n model: z.object({ provider: z.string(), model: z.string() }).optional(),\r\n tools: z.object({ allow: z.array(z.string()).min(1) }).optional(),\r\n builtin: z.boolean().optional(),\r\n visibleInTeam: z.boolean().optional(),\r\n})\r\n\r\n/** domain 名/表名受 UNIT_NAME_RE 约束(^[a-z][a-z0-9_]*$),不允许连字符。 */\r\nexport const agentToolkitDomain = defineDomain({\r\n name: 'dsh_agent_toolkit',\r\n version: 1,\r\n tables: {\r\n agents: domainTable<string, AgentRecord>(AgentRecordSchema),\r\n // meta 表存一次性标记(如 roles_yaml_imported),schema 无法表达则独立成表。\r\n meta: domainTable<string, { value: string }>(z.object({ value: z.string() })),\r\n // 分层提示词层列表:单行 JSON(key 常量 'layers'),整体替换语义,与 agents 表同构校验。\r\n prompt_layers: domainTable<string, { layers: LayerConfig[] }>(z.object({ layers: z.array(LayerConfigSchema) })),\r\n },\r\n})\r\n\r\n/**\r\n * 旧记录迁移:promptLayers 按 order 升序拼接进 persona(忽略纯空白层;persona 已存在不覆盖),\r\n * 剥离 promptLayers 返回新对象;无需迁移返回原引用(调用方按引用比较决定是否写回)。\r\n */\r\nexport function migrateAgentRecord(record: AgentRecord): AgentRecord {\r\n if (record.promptLayers === undefined) return record\r\n const { promptLayers, ...rest } = record\r\n const joined = [...promptLayers]\r\n .sort((a, b) => a.order - b.order)\r\n .map((layer) => layer.text)\r\n .filter((text) => text.trim().length > 0)\r\n .join('\\n\\n')\r\n const persona = rest.persona ?? joined\r\n return persona.length > 0 ? { ...rest, persona } : rest\r\n}\r\n\r\n/** 团队可见性判定:缺省(undefined)与 true 均可见;仅显式 false 隐藏。 */\r\nexport function isTeamVisible(role: Pick<AgentRecord, 'visibleInTeam'>): boolean {\r\n return role.visibleInTeam !== false\r\n}\r\n","/** 基础工具行(与 dsh standard agent preset 同源):persona / instructions / shell / fs / fs-search。\r\n * 源:archive/2026-08-26-merged-plugins/agent-team/presets/team/agent.cordis.yml 的基础工具行,\r\n * 逐行对照 deepseek-harness/apps/cli/config/agent-presets/standard/agent.cordis.yml 核对 id 与 config。\r\n * shell 双行按平台互斥(win32 用 pwsh,其余用 bash),与两 preset 的 disabled 条件一致。\r\n * 这些行由 tool-scope.ts 一次性挂进 bot 会话共用的 standing scope(祖先层),agent 经\r\n * setupAgentScope join 加入——宿主 tools.restrict() 只能过滤继承面,挂进 agentCtx own 层\r\n * 的白名单会抛 unknown global tools(2026-09-03 事故)。 */\r\n\r\nexport interface BasicTool {\r\n /** 插件包名(preset 行的 name 字段)。 */\r\n id: string\r\n /** 插件 config(preset 行的 config 字段;无则省略)。 */\r\n config?: Record<string, unknown>\r\n}\r\n\r\nexport const BASIC_TOOLS: BasicTool[] = [\r\n {\r\n id: '@deepseek-ai/dsh-persona',\r\n config: { text: 'You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}. If you need information or a decision from the user, ask directly in your reply and wait for their next message.' },\r\n },\r\n {\r\n id: '@deepseek-ai/dsh-agent-instructions',\r\n config: { maxBytes: 65536 },\r\n },\r\n ...(process.platform === 'win32'\r\n ? [{ id: '@deepseek-ai/dsh-tool-pwsh' }]\r\n : [{ id: '@deepseek-ai/dsh-tool-bash' }]),\r\n { id: '@deepseek-ai/dsh-tool-fs' },\r\n {\r\n id: '@deepseek-ai/dsh-tool-fs-search',\r\n config: { sampleOverCapGlobResults: false },\r\n },\r\n]\r\n\r\n/** 内置工具名常量(兜底名单):agentPresets 缺席或 standing 枚举失败时,Agents 面板名册\r\n * 与存量迁移回退到这份常量。语义已降级为\"兜底\",不再承诺是完整原生工具面——完整面 =\r\n * 团队 preset 动态枚举(agents/tool-catalog.ts)。explorer 只读白名单仍从本常量派生\r\n * (刻意的最小集,不追求完整)。 */\r\nexport const NATIVE_TOOL_NAMES: readonly string[] = [\r\n process.platform === 'win32' ? 'pwsh' : 'bash',\r\n 'read',\r\n 'write',\r\n 'edit',\r\n 'read_image',\r\n 'glob',\r\n 'grep',\r\n]\r\n","/** 内置保底 Agent 记录:main + explorer(只读白名单 10 个)/ general(preset 面全量 20 个、禁二级委派)。 */\r\nimport { NATIVE_TOOL_NAMES } from '../channels/basic-tools.ts'\r\nimport type { AgentRecord } from './store.ts'\r\n\r\nconst SHELL_NAME = process.platform === 'win32' ? 'pwsh' : 'bash'\r\n\r\n/** 旧版 explorer 默认白名单(5 个):存量条件式迁移的等值比对基准。\r\n * 独立于 EXPLORER_READONLY_ALLOW 保留旧派生式——比对基准不可随新名单漂移。\r\n * shell 名平台互斥(win32=pwsh、其余=bash),必须从 NATIVE_TOOL_NAMES 派生不可写死。 */\r\nexport const LEGACY_EXPLORER_ALLOW: readonly string[] = NATIVE_TOOL_NAMES.filter((n) => n !== 'write' && n !== 'edit')\r\n\r\n/** explorer 默认白名单(10 个):只读基础五件(shell/read/read_image/glob/grep,旧派生不变)\r\n * + preset 面只读安全五件(web_search/todo_write/job_list/job_output/skill——skill 加载的是\r\n * 指令文本,本身只读,用户决策默认可用)。\r\n * 编排类(ralph/workflow)、写文件类(write/edit)、job_kill、ask_user_question、\r\n * goal 三件套、exit_plan_mode 不进只读名单。 */\r\nexport const EXPLORER_READONLY_ALLOW: readonly string[] = [\r\n ...LEGACY_EXPLORER_ALLOW,\r\n 'web_search', 'todo_write', 'job_list', 'job_output', 'skill',\r\n]\r\n\r\n/** general 默认白名单(20 个):agent-team preset standing 面全量(2026-09-08 实测枚举),\r\n * 不含 team_delegate(禁二级委派)与 run_code(宿主 Code Mode 保留名,restrict 拒收)。\r\n * 静态名单:preset 面日后新增工具不自动进入,需人工再梳理(见 spec 非目标)。 */\r\nexport const GENERAL_ALLOW: readonly string[] = [\r\n SHELL_NAME, 'read', 'write', 'edit', 'read_image', 'glob', 'grep',\r\n 'todo_write', 'web_search', 'ask_user_question', 'skill', 'exit_plan_mode',\r\n 'job_list', 'job_output', 'job_kill', 'create_goal', 'get_goal', 'update_goal',\r\n 'ralph', 'workflow',\r\n]\r\n\r\nexport const BUILTIN_AGENTS: readonly AgentRecord[] = [\r\n {\r\n id: 'main',\r\n name: '主 Agent',\r\n builtin: true,\r\n },\r\n {\r\n id: 'explorer',\r\n name: 'Explorer',\r\n description: '快速只读代码库探索:定位文件/符号、回答结构与调用关系问题,不做任何修改',\r\n persona: `你是代码库探索员。快速定位与任务相关的文件与符号,回答关于代码结构、\r\n调用关系、实现位置的问题。你只读不写:不修改任何文件、不运行有副作用的命令。\r\n输出结论清单,每条附文件路径与行号;信息不足时说明缺口,不要猜测。`,\r\n builtin: true,\r\n tools: { allow: [...EXPLORER_READONLY_ALLOW] },\r\n },\r\n {\r\n id: 'general',\r\n name: 'General',\r\n description: '通用多步骤任务执行:可读可写、可运行命令,完成实现/修复类任务',\r\n persona: `你是通用执行员。按任务书独立完成多步骤工作,可以读写文件、运行命令。\r\n动手前先阅读相关 AGENTS.md 并遵循项目约定;完成后运行与改动相关的检查\r\n(测试/类型检查)验证改动,并在最终输出中报告验证结果。`,\r\n builtin: true,\r\n tools: { allow: [...GENERAL_ALLOW] },\r\n },\r\n]\r\n","/** 首启导入:把旧 agent-team 角色名册 $DSH_HOME/agent-team/roles/*.yml 一次性并入注册表。 */\r\nimport { readdir, readFile } from 'node:fs/promises'\r\nimport { join } from 'node:path'\r\nimport { z } from 'zod'\r\nimport yaml from 'js-yaml'\r\nimport { resolveDshHome } from '@deepseek-ai/dsh-home-paths'\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport type { AgentRecord } from './store.ts'\r\nimport { AGENT_ID_RE } from './store.ts'\r\n\r\n/** 导入一次性标记在 meta 表中的键。 */\r\nexport const ROLES_YAML_IMPORTED_KEY = 'roles_yaml_imported'\r\n\r\nexport interface ImportRolesContext {\r\n agents: KvTable<string, AgentRecord>\r\n meta: KvTable<string, { value: string }>\r\n warn: (msg: string) => void\r\n}\r\n\r\nexport interface ImportResult {\r\n /** 成功导入(覆盖/新增)的条数。 */\r\n imported: number\r\n /** 解析失败被跳过的文件名列表。 */\r\n skipped: string[]\r\n}\r\n\r\nconst RoleYamlSchema = z.object({\r\n name: z.string().optional(),\r\n description: z.string().min(1),\r\n persona: z.string().min(1),\r\n provider: z.string().optional(),\r\n model: z.string().optional(),\r\n tools: z.object({\r\n allow: z.array(z.string()).optional(),\r\n }).optional(),\r\n})\r\n\r\n/**\r\n * 解析校验单个角色 YAML 文件并转成 AgentRecord。\r\n * @param text - 文件内容。\r\n * @param source - 用于错误信息的来源名(通常是文件路径)。\r\n * @param fileName - 文件名(去 .yml),name 省略时的取值;显式 name 须与它一致。\r\n * @throws YAML 语法错误、结构非法、name 与文件名不一致、id 非法、tools 空。\r\n */\r\nexport function parseRoleYaml(text: string, source: string, fileName: string): AgentRecord {\r\n let parsed: unknown\r\n try {\r\n parsed = yaml.load(text)\r\n } catch (error) {\r\n throw new Error(`dsh-agent-toolkit: 角色文件 ${source} 不是合法 YAML:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n const hasTools = parsed !== null && typeof parsed === 'object' && 'tools' in (parsed as object)\r\n let raw: z.infer<typeof RoleYamlSchema>\r\n try {\r\n raw = RoleYamlSchema.parse(parsed)\r\n } catch (error) {\r\n throw new Error(`dsh-agent-toolkit: 角色文件 ${source} 校验失败:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n const id = raw.name ?? fileName\r\n if (raw.name !== undefined && raw.name !== fileName) {\r\n throw new Error(`dsh-agent-toolkit: 角色文件 ${source} 的 name \"${raw.name}\" 与文件名 \"${fileName}\" 不一致(省略 name 即取文件名)`)\r\n }\r\n if (!AGENT_ID_RE.test(id)) {\r\n throw new Error(`dsh-agent-toolkit: 角色 id \"${id}\" 非法(${source}):只允许小写字母、数字、-,且以小写字母开头`)\r\n }\r\n if (hasTools && raw.tools !== undefined && (raw.tools.allow?.length ?? 0) === 0) {\r\n throw new Error(`dsh-agent-toolkit: 角色文件 ${source} 的 tools 为空:allow 至少配一个(不需要限制请整段省略 tools)`)\r\n }\r\n const model = raw.provider !== undefined && raw.model !== undefined ? { provider: raw.provider, model: raw.model } : undefined\r\n const tools = hasTools && raw.tools !== undefined && raw.tools.allow !== undefined && raw.tools.allow.length > 0\r\n ? { allow: raw.tools.allow }\r\n : undefined\r\n return {\r\n id,\r\n name: id,\r\n description: raw.description,\r\n persona: raw.persona,\r\n ...(model !== undefined ? { model } : {}),\r\n ...(tools !== undefined ? { tools } : {}),\r\n }\r\n}\r\n\r\n/** 一个角色 YAML 文件引用:完整文件名 + 完整路径 + 去 .yml 的文件名(name 缺省取值)。 */\r\ninterface RoleFileRef {\r\n name: string\r\n path: string\r\n fileName: string\r\n}\r\n\r\n/**\r\n * 枚举 roles 目录下全部 .yml 角色文件,按文件名字典序返回。\r\n * 共享骨架(readdir/ENOENT/过滤/排序/文件名推导)——YAML 文件命名约定只在这里维护。\r\n * @param dir - roles 目录绝对路径。\r\n * @returns 文件引用列表;目录不存在或无 .yml 文件时返回空列表(静默跳过,属正常态)。\r\n * @throws 目录存在但不可读(非 ENOENT)。读取/解析的严格与宽容由调用方自行处理。\r\n */\r\nasync function enumerateRoleFiles(dir: string): Promise<RoleFileRef[]> {\r\n let entries: string[]\r\n try {\r\n entries = await readdir(dir)\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return []\r\n throw new Error(`dsh-agent-toolkit: 角色目录不可读:${dir}(${error instanceof Error ? error.message : String(error)})`)\r\n }\r\n return entries\r\n .filter(f => f.endsWith('.yml'))\r\n .sort()\r\n .map(file => ({ name: file, path: join(dir, file), fileName: file.slice(0, -'.yml'.length) }))\r\n}\r\n\r\n/**\r\n * 读取 roles 目录下全部 .yml 角色文件,按文件名字典序返回(严格模式:任一文件非法即抛错)。\r\n * @param dir - roles 目录绝对路径。\r\n * @returns 角色记录列表;目录不存在或无 .yml 文件时返回空列表(静默跳过,属正常态)。\r\n * @throws 目录存在但不可读(非 ENOENT)、任一文件不可读/非法。\r\n */\r\nexport async function loadRolesDir(dir: string): Promise<AgentRecord[]> {\r\n const refs = await enumerateRoleFiles(dir)\r\n const records: AgentRecord[] = []\r\n for (const ref of refs) {\r\n let text: string\r\n try {\r\n text = await readFile(ref.path, 'utf8')\r\n } catch (error) {\r\n throw new Error(`dsh-agent-toolkit: 角色文件不可读:${ref.path}(${error instanceof Error ? error.message : String(error)})`)\r\n }\r\n records.push(parseRoleYaml(text, ref.path, ref.fileName))\r\n }\r\n return records\r\n}\r\n\r\n/**\r\n * 首启一次性导入:meta 表 roles_yaml_imported 标记短路;逐文件解析失败 warn 跳过(不阻塞激活);\r\n * 同名 YAML 覆盖内置保底记录。\r\n * @param ctx - agents/meta 表句柄与 warn 通道。\r\n * @param rolesDir - roles 目录;缺省为 $DSH_HOME/agent-team/roles。\r\n */\r\nexport async function importRolesYaml(ctx: ImportRolesContext, rolesDir?: string): Promise<ImportResult> {\r\n const result: ImportResult = { imported: 0, skipped: [] }\r\n if (ctx.meta.get(ROLES_YAML_IMPORTED_KEY) !== undefined) return result\r\n const dir = rolesDir ?? join(resolveDshHome(), 'agent-team', 'roles')\r\n let refs: RoleFileRef[]\r\n try {\r\n refs = await enumerateRoleFiles(dir)\r\n } catch (error) {\r\n // 目录不可读(非 ENOENT):warn 后标记完成,不阻塞激活。\r\n ctx.warn(error instanceof Error ? error.message : String(error))\r\n await markImported(ctx)\r\n return result\r\n }\r\n for (const ref of refs) {\r\n try {\r\n const text = await readFile(ref.path, 'utf8')\r\n const record = parseRoleYaml(text, ref.path, ref.fileName)\r\n await ctx.agents.put(record.id, record)\r\n result.imported++\r\n } catch (error) {\r\n result.skipped.push(ref.name)\r\n ctx.warn(`dsh-agent-toolkit: 角色文件 ${ref.path} 导入失败,已跳过:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n }\r\n await markImported(ctx)\r\n return result\r\n}\r\n\r\nasync function markImported(ctx: ImportRolesContext): Promise<void> {\r\n await ctx.meta.put(ROLES_YAML_IMPORTED_KEY, { value: '1' })\r\n}\r\n","/** Agent 注册表:内存缓存 + 持久化回写 + 订阅通知;main 置顶、内置保底不可删。 */\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport { AgentRecordSchema, migrateAgentRecord, type AgentRecord } from './store.ts'\r\nimport { BUILTIN_AGENTS, EXPLORER_READONLY_ALLOW, GENERAL_ALLOW, LEGACY_EXPLORER_ALLOW } from './builtin.ts'\r\nimport { importRolesYaml } from './import-yaml.ts'\r\nimport { NATIVE_TOOL_NAMES } from '../channels/basic-tools.ts'\r\n\r\nexport interface AgentRegistry {\r\n /** main 置顶,其余按 id 字典序。 */\r\n list(): AgentRecord[]\r\n get(id: string): AgentRecord | undefined\r\n /** main 的 name/builtin 不可改;builtin 可改配置不可删。 */\r\n upsert(record: AgentRecord): Promise<void>\r\n /** main 与 builtin 抛错。 */\r\n remove(id: string): Promise<void>\r\n /** UI/委派提示段热更新用;返回退订函数。 */\r\n subscribe(listener: () => void): () => void\r\n}\r\n\r\n/** tools.allow 一次性并入原生工具名的 meta 表标记键。 */\r\nexport const TOOLS_NATIVE_MIGRATED_KEY = 'tools_native_migrated'\r\n\r\n/** explorer 只读白名单一次性并入的 meta 表标记键。 */\r\nexport const EXPLORER_READONLY_MIGRATED_KEY = 'explorer_readonly_migrated'\r\n\r\n/** tools.allow 一次性并入「preset 面 − 原生常量」差集的 meta 表标记键。 */\r\nexport const TOOLS_PRESET_MIGRATED_KEY = 'tools_preset_catalog_migrated'\r\n\r\n/** 内置角色工具名单重选(explorer 5→10 / general 无→20)一次性迁移的 meta 表标记键。 */\r\nexport const BUILTIN_TOOLS_RECATALOG_MIGRATED_KEY = 'builtin_tools_recatalog_migrated'\r\n\r\n/**\r\n * 打开 dsh_agent_toolkit 域 → 首启 YAML 导入 → 旧记录迁移(promptLayers/原生并入/preset 差集并入/explorer 只读/内置名单重选)→\r\n * 缺 main/explorer/general 时种入内置 → 构建内存缓存。域由 apply 统一 open(storage-domain 同名单开),此处只消费表句柄。\r\n */\r\nexport async function createRegistry(\r\n warn: (msg: string) => void,\r\n tables: { agents: KvTable<string, AgentRecord>; meta: KvTable<string, { value: string }> },\r\n /** 动态 preset 工具面(tool-catalog.ts);缺席 = 跳过 preset 并入迁移(不置标记)。 */\r\n listPresetTools?: () => Promise<string[]>,\r\n): Promise<AgentRegistry> {\r\n const { agents, meta } = tables\r\n\r\n await importRolesYaml({ agents, meta, warn })\r\n\r\n // 旧记录迁移:promptLayers → persona(逐条幂等);tools.allow 一次性并入原生工具名\r\n // (meta 标记幂等——UI 从未提供原生工具勾选项,存量白名单缺原生名非用户本意;\r\n // 标记置位后用户再编辑 allow 不会被回收改)。\r\n const nativeMigrated = meta.get(TOOLS_NATIVE_MIGRATED_KEY) !== undefined\r\n for (const [id, record] of agents.entries()) {\r\n let next = migrateAgentRecord(record)\r\n if (!nativeMigrated && next.tools !== undefined) {\r\n const allow = next.tools.allow\r\n const missing = NATIVE_TOOL_NAMES.filter((name) => !allow.includes(name))\r\n if (missing.length > 0) next = { ...next, tools: { allow: [...allow, ...missing] } }\r\n }\r\n if (next !== record) await agents.put(id, next)\r\n }\r\n if (!nativeMigrated) await meta.put(TOOLS_NATIVE_MIGRATED_KEY, { value: '1' })\r\n\r\n // preset 并入:UI 从未提供 preset 工具名,存量自定义白名单缺它们非用户本意。\r\n // 并入集 = preset 面 − NATIVE_TOOL_NAMES(native 名一直在 UI 可勾,用户不勾是有意排除,\r\n // 不回收改);builtin 记录跳过(explorer 只读白名单是插件设计,不 widen)。\r\n // 枚举失败/服务缺席:跳过且不置标记,下次启动重试。\r\n if (meta.get(TOOLS_PRESET_MIGRATED_KEY) === undefined && listPresetTools !== undefined) {\r\n let extra: string[] | undefined\r\n try {\r\n const surface = await listPresetTools()\r\n extra = surface.filter((n) => !NATIVE_TOOL_NAMES.includes(n))\r\n } catch {\r\n extra = undefined\r\n }\r\n // 空差集(= 回退常量减常量,如 agentPresets 缺席/枚举失败回退后差集为空)不置标记:\r\n // 置上会永久跳过重试;下次启动重试为空差集是无害幂等 no-op。\r\n if (extra !== undefined && extra.length > 0) {\r\n for (const [id, record] of agents.entries()) {\r\n if (record.builtin === true || record.tools === undefined) continue\r\n const missing = extra.filter((n) => !record.tools!.allow.includes(n))\r\n if (missing.length > 0) await agents.put(id, { ...record, tools: { allow: [...record.tools!.allow, ...missing] } })\r\n }\r\n await meta.put(TOOLS_PRESET_MIGRATED_KEY, { value: '1' })\r\n }\r\n }\r\n\r\n // explorer 只读白名单一次性迁移:deny 语义取消后 explorer 失去硬约束,此处补派生白名单恢复。\r\n // 先于 seedBuiltins 执行:新装环境的 explorer 由种入直接携带白名单,不经过本迁移与原生并入。\r\n const explorerMigrated = meta.get(EXPLORER_READONLY_MIGRATED_KEY) !== undefined\r\n if (!explorerMigrated) {\r\n const explorer = agents.get('explorer')\r\n if (explorer !== undefined && explorer.tools === undefined) {\r\n await agents.put('explorer', { ...explorer, tools: { allow: [...EXPLORER_READONLY_ALLOW] } })\r\n }\r\n await meta.put(EXPLORER_READONLY_MIGRATED_KEY, { value: '1' })\r\n }\r\n\r\n // 内置名单重选一次性迁移(2026-09-08):explorer 旧默认 → 新 10 个;general 无 tools\r\n // → preset 面全量 20 个。条件式:仅更新仍是旧默认值的 builtin 记录(用户面板改过的 =\r\n // 自定义,跳过)。explorer 旧默认有两种形状:纯净 5 个(seed/只读迁移写入的 LEGACY 派生\r\n // 顺序)与原生并入加写后的 7 个([...LEGACY, write, edit]——0.2.x 时代 native 合并不\r\n // 跳过 builtin 记录,真实存量多为此形状);7 个形状替换后 write/edit 随之移除,只读\r\n // 约束随新名单恢复。同 id 非 builtin 记录是用户数据,不动。无外部依赖,跑完即置标记。\r\n if (meta.get(BUILTIN_TOOLS_RECATALOG_MIGRATED_KEY) === undefined) {\r\n const explorer = agents.get('explorer')\r\n const legacyShapes: readonly (readonly string[])[] = [LEGACY_EXPLORER_ALLOW, [...LEGACY_EXPLORER_ALLOW, 'write', 'edit']]\r\n if (explorer?.builtin === true && explorer.tools !== undefined\r\n && legacyShapes.some((shape) => explorer.tools!.allow.length === shape.length\r\n && explorer.tools!.allow.every((n, i) => n === shape[i]))) {\r\n await agents.put('explorer', { ...explorer, tools: { allow: [...EXPLORER_READONLY_ALLOW] } })\r\n }\r\n const general = agents.get('general')\r\n if (general?.builtin === true && general.tools === undefined) {\r\n await agents.put('general', { ...general, tools: { allow: [...GENERAL_ALLOW] } })\r\n }\r\n await meta.put(BUILTIN_TOOLS_RECATALOG_MIGRATED_KEY, { value: '1' })\r\n }\r\n\r\n await seedBuiltins(agents)\r\n\r\n const cache = new Map<string, AgentRecord>()\r\n for (const [id, record] of agents.entries()) cache.set(id, record)\r\n\r\n const listeners = new Set<() => void>()\r\n const notify = () => {\r\n for (const listener of [...listeners]) listener()\r\n }\r\n\r\n return {\r\n list(): AgentRecord[] {\r\n const main = cache.get('main')\r\n const rest = [...cache.entries()]\r\n .filter(([id]) => id !== 'main')\r\n .map(([, record]) => record)\r\n .sort((a, b) => a.id.localeCompare(b.id))\r\n return main === undefined ? rest : [main, ...rest]\r\n },\r\n get(id: string): AgentRecord | undefined {\r\n return cache.get(id)\r\n },\r\n async upsert(record: AgentRecord): Promise<void> {\r\n const parsed = AgentRecordSchema.safeParse(record)\r\n if (!parsed.success) {\r\n throw new Error(`dsh-agent-toolkit: Agent 记录校验失败:${parsed.error.message}`)\r\n }\r\n const normalized = migrateAgentRecord(parsed.data)\r\n const existing = cache.get(record.id)\r\n if (record.id === 'main' && existing !== undefined) {\r\n if (existing.name !== record.name || existing.builtin !== record.builtin) {\r\n throw new Error('dsh-agent-toolkit: 主 Agent(main)的 name/builtin 字段不可修改')\r\n }\r\n }\r\n if (existing?.builtin === true && record.builtin !== true) {\r\n throw new Error(`dsh-agent-toolkit: 内置角色 ${record.id} 的 builtin 标记不可修改`)\r\n }\r\n await agents.put(record.id, normalized)\r\n cache.set(record.id, normalized)\r\n notify()\r\n },\r\n async remove(id: string): Promise<void> {\r\n if (id === 'main') throw new Error('dsh-agent-toolkit: 主 Agent(main)不可删除')\r\n const existing = cache.get(id)\r\n if (existing?.builtin === true) {\r\n throw new Error(`dsh-agent-toolkit: 内置角色 ${id} 不可删除`)\r\n }\r\n const deleted = await agents.delete(id)\r\n if (deleted) {\r\n cache.delete(id)\r\n notify()\r\n }\r\n },\r\n subscribe(listener: () => void): () => void {\r\n listeners.add(listener)\r\n return () => { listeners.delete(listener) }\r\n },\r\n }\r\n}\r\n\r\nasync function seedBuiltins(agents: KvTable<string, AgentRecord>): Promise<void> {\r\n for (const builtin of BUILTIN_AGENTS) {\r\n if (agents.get(builtin.id) === undefined) {\r\n await agents.put(builtin.id, builtin)\r\n }\r\n }\r\n}\r\n","/** 动态工具名册:团队 preset 面经宿主 standing mount 枚举(standingKeyFor + scoped schemas),\r\n * agentPresets 缺席/枚举失败回退 NATIVE_TOOL_NAMES 常量。每次调用现算,不缓存——standing\r\n * mount 由宿主按 composition 文件代际缓存,view 遍历是纯内存操作。\r\n * 设计:docs/superpowers/specs/2026-09-07-dynamic-tool-catalog-design.md */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { RUN_CODE_NAME } from '@deepseek-ai/dsh-tools'\r\nimport type { ScopeKey } from '@deepseek-ai/dsh-scope'\r\n// type-only 激活 dsh-tools 对 cordis Context 的声明合并(ctx.tools)。\r\nimport type {} from '@deepseek-ai/dsh-tools'\r\nimport { NATIVE_TOOL_NAMES } from '../channels/basic-tools.ts'\r\n\r\n/** agentPresets 服务的结构类型(可选服务经 ctx.get 读取,team-preset.ts AgentPresetsLike 先例)。*/\r\ninterface PresetStandingLike {\r\n standingKeyFor(id?: string): Promise<ScopeKey>\r\n}\r\n\r\n/** Agents 面板/迁移/创建命令共用的工具名册。*/\r\nexport interface ToolCatalog {\r\n /** 团队 preset 工具面(不含 global 名与 run_code 保留名,字典序)。*/\r\n listPresetTools(): Promise<string[]>\r\n /** 顶层注册表全局工具名(不含 run_code 保留名)。*/\r\n listGlobalTools(): string[]\r\n}\r\n\r\nexport function createToolCatalog(ctx: Context, presetId: string): ToolCatalog {\r\n return {\r\n async listPresetTools() {\r\n // 惰性解析(attachments 教训:apply 期一次性捕获会吃到未注册的 undefined)。\r\n const presets = ctx.get('agentPresets', false) as PresetStandingLike | undefined\r\n if (presets === undefined) return [...NATIVE_TOOL_NAMES]\r\n try {\r\n const key = await presets.standingKeyFor(presetId)\r\n const global = new Set(ctx.tools.schemas().map((s) => s.name))\r\n return ctx.tools.schemas(key).map((s) => s.name)\r\n .filter((n) => !global.has(n) && n !== RUN_CODE_NAME)\r\n .sort()\r\n } catch (error) {\r\n ctx.logger.warn(\r\n `dsh-agent-toolkit: 枚举 preset \"${presetId}\" 工具面失败,回退内置常量:${error instanceof Error ? error.message : String(error)}`,\r\n )\r\n return [...NATIVE_TOOL_NAMES]\r\n }\r\n },\r\n listGlobalTools() {\r\n return ctx.tools.schemas().map((s) => s.name).filter((n) => n !== RUN_CODE_NAME)\r\n },\r\n }\r\n}\r\n","/** shared storage 助手:安全打开存储域(open 失败挂 rejection handler)并在卸载时关闭。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { Domain, DomainSpec } from '@deepseek-ai/dsh-storage-domain'\r\n\r\n/** 类型擦除后的存储域句柄(跨 spec 泛型的统一承载面)。 */\r\nexport type DomainHandle = Domain<DomainSpec>\r\n\r\nexport function openDomainSafely(\r\n ctx: Context,\r\n domain: DomainSpec,\r\n warn: (msg: string) => void,\r\n beforeClose?: () => void | Promise<void>,\r\n): Promise<DomainHandle> {\r\n const ready = ctx.storageDomain.open(domain)\r\n // open 失败(version-mismatch/malformed-medium/invalid-record)时创建即挂\r\n // rejection handler:避免 unhandled rejection 崩掉宿主进程(Node 默认 throw)。\r\n // ready 仍保持 reject,调用方仍感知失败而不次生崩溃。\r\n ready.catch((error) => {\r\n warn(error instanceof Error ? error.message : String(error))\r\n })\r\n // 域句柄由本 fiber 持有:卸载时 close(消费方自己不关闭)。open 失败时\r\n // close 无从谈起,吞掉该 rejection,避免卸载路径次生崩溃。\r\n ctx.effect(() => async () => {\r\n // beforeClose 在 close 前排空消费方自己的写链(如 usage 的 tail):close 一旦\r\n // 开始(disposing=true)就拒绝新入队的写,未落队的采集会被静默丢弃。drain\r\n // 失败不阻断 close——卸载路径不因 drain 异常次生崩溃。\r\n await Promise.resolve(beforeClose?.()).catch(() => undefined)\r\n await ready.then((domain) => domain.close()).catch(() => undefined)\r\n })\r\n return ready\r\n}\r\n","// 默认文本改写自 opencode(MIT 许可,https://github.com/anomalyco/opencode,\r\n// packages/opencode/src/session/prompt/*.txt @ dev 分支):剔除 opencode 专有内容\r\n// (身份自述、具体工具名、/help /bug ctrl+p、issues URL、opencode.ai),保留模型族\r\n// 行为指导。身份首句刻意不写——dsh 原生 `harness:identity` 段(order -100)已覆盖身份。\r\nimport type { LayerConfig, Rule } from './types.ts'\r\n\r\n/** 通用基座层文本(default.txt 改写版)。 */\r\nexport const BASE_TEXT = `IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming. You may use URLs provided by the user in their messages or local files.\r\n\r\n# Tone and style\r\nYou should be concise, direct, and to the point. When you run a non-trivial shell command, explain what the command does and why you are running it, so the user understands what you are doing (this is especially important when the command changes the user's system).\r\nYour output will be displayed on a command line interface. You can use GitHub-flavored markdown for formatting; it will be rendered in a monospace font using the CommonMark specification.\r\nOutput text to communicate with the user; all text you output outside of tool use is displayed to the user. Only use tools to complete tasks. Never use tools or code comments as a means to communicate with the user during the session.\r\nIf you cannot or will not help the user with something, do not preach about why or what it could lead to. Offer helpful alternatives if possible, and otherwise keep your response to 1-2 sentences.\r\nOnly use emojis if the user explicitly requests it. Avoid using emojis in all communication unless asked.\r\nIMPORTANT: Minimize output tokens as much as possible while maintaining helpfulness, quality, and accuracy. Only address the specific query or task at hand, avoiding tangential information unless absolutely critical. If you can answer in 1-3 sentences or a short paragraph, please do.\r\nIMPORTANT: Do not answer with unnecessary preamble or postamble (such as explaining your code or summarizing your actions) unless the user asks you to.\r\nKeep responses short: answer the user's question directly, without elaboration. Avoid introductions, conclusions, and restatements such as \"The answer is ...\" or \"Here is what I will do next ...\".\r\n<example>\r\nuser: what is 2+2?\r\nassistant: 4\r\n</example>\r\n\r\n<example>\r\nuser: what files are in the directory src/?\r\nassistant: [lists files and sees foo.c, bar.c, baz.c]\r\nuser: which file contains the implementation of foo?\r\nassistant: src/foo.c\r\n</example>\r\n\r\n# Proactiveness\r\nBe proactive only when the user asks you to do something. Strike a balance between:\r\n1. Doing the right thing when asked, including follow-up actions the request implies.\r\n2. Not surprising the user with actions taken without asking.\r\nIf the user asks how to approach something, answer the question first instead of immediately jumping into action.\r\nDo not add a code-explanation summary unless requested. After working on a file, just stop.\r\n\r\n# Following conventions\r\nWhen making changes to files, first understand the file's code conventions. Mimic code style, use existing libraries and utilities, and follow existing patterns.\r\n- NEVER assume that a given library is available, even if it is well known. Whenever you write code that uses a library or framework, first check that this codebase already uses it (neighboring files, package manifests such as package.json or cargo.toml).\r\n- When you create a new component, first look at existing components: framework choice, naming conventions, typing, and other conventions.\r\n- When you edit a piece of code, read its surrounding context (especially its imports) and make the change idiomatic to it.\r\n- Always follow security best practices. Never introduce code that exposes or logs secrets and keys. Never commit secrets or keys to the repository.\r\n\r\n# Code style\r\n- IMPORTANT: DO NOT ADD ***ANY*** COMMENTS unless asked.\r\n\r\n# Doing tasks\r\nFor software engineering tasks (fixing bugs, adding features, refactoring, explaining code, and more):\r\n- Use the available search tools extensively, in parallel and sequentially, to understand the codebase and the user's query.\r\n- Implement the solution using all tools available to you.\r\n- Verify the solution with tests where possible. NEVER assume a specific test framework or test script; check the README or search the codebase to determine the testing approach.\r\n- When you have completed a task, run the project's lint and typecheck commands if they exist. If you cannot find the correct command, ask the user for it.\r\n- NEVER commit changes unless the user explicitly asks you to.\r\n\r\nTool results and user messages may include <system-reminder> tags. They contain useful information and reminders. They are NOT part of the user's provided input or the tool result.\r\n\r\n# Tool usage policy\r\n- For file or content search, prefer dedicated search tools over shell commands to reduce context usage.\r\n- You can call multiple tools in a single response. Batch independent calls together for optimal performance; run dependent calls sequentially.\r\n\r\nBefore you begin work, think about what the code you are editing is supposed to do, based on filenames and directory structure.\r\n\r\n# Code references\r\nWhen referencing specific functions or pieces of code, use the pattern \\`file_path:line_number\\` so the user can easily navigate to the source location.`\r\n\r\n/** 模型族行为指导文本(anthropic/gemini/beast/codex/gpt/kimi 改写版,\r\n * 内容按下文\"6 个模型族 TEXT 的改写契约\"逐条产出,英文,不写身份首句)。 */\r\nexport const ANTHROPIC_TEXT = `IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming. You may use URLs provided by the user in their messages or local files.\r\n\r\n# Tone and style\r\n- Only use emojis if the user explicitly requests it. Avoid using emojis in all communication unless asked.\r\n- Your output will be displayed on a command line interface. Your responses should be short and concise. You can use GitHub-flavored markdown for formatting, and it will be rendered in a monospace font using the CommonMark specification.\r\n- Output text to communicate with the user; all text you output outside of tool use is displayed to the user. Only use tools to complete tasks. Never use shell commands or code comments as a means to communicate with the user during the session.\r\n- NEVER create files unless they are absolutely necessary for achieving your goal. ALWAYS prefer editing an existing file to creating a new one.\r\n\r\n# Professional objectivity\r\nPrioritize technical accuracy and truthfulness over validating the user's beliefs. Focus on facts and problem-solving, providing direct, objective technical information without unnecessary superlatives, praise, or emotional validation. Apply the same rigorous standards to all ideas and disagree when necessary, even if it may not be what the user wants to hear. Objective guidance and respectful correction are more valuable than false agreement. Whenever there is uncertainty, investigate to find the truth first rather than instinctively confirming the user's beliefs.\r\n\r\n# Planning and tracking\r\nUse a task list frequently to plan and track your work, giving the user visibility into your progress. These lists are also helpful for breaking down larger, complex tasks into smaller steps. Mark each task as completed as soon as you are done; do not batch up multiple tasks before marking them completed.\r\n\r\n# Doing tasks\r\nThe user will primarily request software engineering tasks: fixing bugs, adding new functionality, refactoring code, explaining code, and more. Search the codebase to understand the user's query, implement the solution using all tools available to you, then verify it. Tool results and user messages may include <system-reminder> tags. They contain useful information and reminders; they are authoritative and are NOT part of the user's provided input or the tool result.\r\n\r\n# Tool usage policy\r\n- For file or content search, prefer dedicated search tools over shell commands to reduce context usage.\r\n- Prefer dedicated editing tools over shell for modifying files.\r\n- You can call multiple tools in a single response. Make all independent tool calls in parallel; run dependent calls sequentially. Never use placeholders or guess missing parameters in tool calls.\r\n\r\n# Code references\r\nWhen referencing specific functions or pieces of code, use the pattern \\`file_path:line_number\\` so the user can easily navigate to the source location.`\r\n\r\nexport const GEMINI_TEXT = `# Core Mandates\r\n\r\n- **Conventions:** Rigorously adhere to existing project conventions when reading or modifying code. Analyze surrounding code, tests, and configuration first.\r\n- **Libraries/Frameworks:** NEVER assume a library or framework is available or appropriate. Verify its established usage within the project (check imports and configuration files, or observe neighboring files) before employing it.\r\n- **Style & Structure:** Mimic the style (formatting, naming), structure, framework choices, typing, and architectural patterns of existing code in the project.\r\n- **Idiomatic Changes:** When editing, understand the local context (imports, functions, classes) to ensure your changes integrate naturally and idiomatically.\r\n- **Comments:** Add code comments sparingly. Focus on *why* something is done, especially for complex logic, rather than *what* is done. Only add high-value comments if necessary for clarity or if requested by the user. Do not edit comments that are separate from the code you are changing. *NEVER* talk to the user or describe your changes through comments.\r\n- **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions.\r\n- **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first; do not just do it.\r\n- **Explaining Changes:** After completing a code modification or file operation, do not provide summaries unless asked.\r\n- **Path Construction:** Before using any file system tool, construct the full absolute path for the file argument. Always combine the absolute path of the project root with the file's path relative to the root. If the user provides a relative path, resolve it against the root to create an absolute path.\r\n- **Do Not Revert Changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they resulted in an error or if the user has explicitly asked you to revert them.\r\n\r\n# Primary Workflows\r\n\r\n## Software Engineering Tasks\r\nWhen requested to fix bugs, add features, refactor, or explain code, follow this sequence:\r\n1. **Understand:** Think about the request and the relevant codebase context. Search extensively (in parallel if independent) to understand file structures, existing patterns, and conventions. Read to validate any assumptions.\r\n2. **Plan:** Build a coherent, grounded plan for how you intend to resolve the task. Share an extremely concise yet clear plan with the user if it would help. Use a self-verification loop by writing unit tests where relevant; use output logs or debug statements as part of this loop to arrive at a solution.\r\n3. **Implement:** Act on the plan using available tools, strictly adhering to the project's established conventions.\r\n4. **Verify (Tests):** If applicable and feasible, verify the changes using the project's testing procedures. Identify the correct test commands and frameworks by examining README files and build or package configuration; NEVER assume standard test commands.\r\n5. **Verify (Standards):** After making code changes, execute the project-specific build, lint, and type-checking commands you have identified. If unsure about these commands, ask the user.\r\n\r\n## New Applications\r\nAutonomously implement and deliver a visually appealing, substantially complete, functional prototype:\r\n1. **Understand Requirements:** Analyze the request to identify core features, desired user experience, visual aesthetic, application type and platform, and explicit constraints. If critical information for planning is missing or ambiguous, ask concise, targeted clarification questions.\r\n2. **Propose Plan:** Formulate an internal development plan and present a clear, concise summary covering the application's type and core purpose, key technologies, main features, interaction model, and the approach to a polished visual design and user experience.\r\n3. **User Approval:** Obtain user approval for the proposed plan before implementing.\r\n4. **Implementation:** Autonomously implement each feature and design element per the approved plan. Use placeholder assets only when essential for progress, intending to replace them with more refined versions or instructing the user on replacement during polishing.\r\n5. **Verify:** Review work against the original request and approved plan. Fix bugs, deviations, and placeholders where feasible. Build the application and ensure there are no compile errors.\r\n6. **Solicit Feedback:** Provide instructions on how to start the application and request user feedback.\r\n\r\n# Operational Guidelines\r\n\r\n## Tone and Style (CLI Interaction)\r\n- **Concise & Direct:** Adopt a professional, direct, and concise tone suitable for a CLI environment.\r\n- **Minimal Output:** Aim for fewer than 3 lines of text output (excluding tool use and code generation) per response whenever practical. Focus strictly on the user's query.\r\n- **Clarity over Brevity (When Needed):** While conciseness is key, prioritize clarity for essential explanations or when seeking necessary clarification.\r\n- **No Chitchat:** Avoid conversational filler, preambles, or postambles. Get straight to the action or answer.\r\n- **Formatting:** Use GitHub-flavored Markdown. Responses will be rendered in monospace.\r\n- **Tools vs. Text:** Use tools for actions; text output only for communication. Do not add explanatory comments within tool calls or code blocks unless specifically part of the required code.\r\n- **Handling Inability:** If unable or unwilling to fulfill a request, state so briefly (1-2 sentences) without excessive justification. Offer alternatives if appropriate.\r\n\r\n## Security and Safety Rules\r\n- **Explain Critical Commands:** Before executing commands that modify the file system, codebase, or system state, provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety.\r\n- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.\r\n\r\n## Tool Usage\r\n- **File Paths:** Always use absolute paths when referring to files with file tools. Relative paths are not supported; you must provide an absolute path.\r\n- **Parallelism:** Execute multiple independent tool calls in parallel when feasible.\r\n- **Command Execution:** Run shell commands for actual system commands and terminal operations, remembering to explain modifying commands first.\r\n- **Respect User Confirmations:** Tool calls will first require confirmation from the user, where they will either approve or cancel. If a user cancels a call, respect their choice and do not try to make the call again; it is okay to request it again only if the user asks on a subsequent prompt.\r\n\r\n# Final Reminder\r\nYour core function is efficient and safe assistance. Balance extreme conciseness with the crucial need for clarity, especially regarding safety and potential system modifications. Always prioritize user control and project conventions. Never make assumptions about the contents of files; instead read to ensure you are not making broad assumptions. Keep going until the user's query is completely resolved.`\r\n\r\nexport const BEAST_TEXT = `Keep going until the user's query is completely resolved, before ending your turn and yielding back to the user.\r\n\r\nYour thinking should be thorough, and it is fine if it is very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\r\n\r\nYou MUST iterate and keep going until the problem is solved. You have everything you need to resolve this problem. Fully solve it autonomously before coming back. Only terminate your turn when you are sure the problem is solved and all items have been checked off. Go through the problem step by step, verify that your changes are correct, and never end your turn without having truly and completely solved the problem. When you say you are going to make a tool call, make sure you ACTUALLY make the tool call instead of ending your turn.\r\n\r\nYour knowledge may be out of date because your training date is in the past. Use available search means to verify your understanding of third-party packages and dependencies is up to date every time you install or implement one. It is not enough to just search; you must also read the content of the pages you find and gather all relevant information until you have everything you need.\r\n\r\nAlways tell the user what you are going to do before making a tool call with a single concise sentence.\r\n\r\nTake your time and think through every step. Check your solution rigorously and watch out for boundary cases, especially with the changes you made. Your solution must be perfect; if not, continue working on it. Test your code rigorously using the tools provided, many times, to catch all edge cases. If it is not robust, iterate more. Failing to test your code rigorously is the number one failure mode; make sure you handle all edge cases and run existing tests if they are provided.\r\n\r\nPlan extensively before each function call, and reflect extensively on the outcomes of the previous calls. Do not do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully. Keep working until the problem is completely solved and all items in the todo list are checked off; do not end your turn until you have completed all steps and verified that everything is working correctly.\r\n\r\n# Workflow\r\n1. Fetch any URLs provided by the user using the search tool.\r\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Break down the problem into manageable parts, considering the expected behavior, edge cases, potential pitfalls, the larger context of the codebase, and the dependencies and interactions with other parts of the code.\r\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\r\n4. Research the problem using available search means by reading relevant articles, documentation, and forums.\r\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps and display the plan as a todo list, checking off each item as you go.\r\n6. Implement the fix incrementally. Make small, testable code changes.\r\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\r\n8. Test frequently. Run tests after each change to verify correctness.\r\n9. Iterate until the root cause is fixed and all tests pass.\r\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\r\n\r\n## Debugging\r\n- Make code changes only if you have high confidence they can solve the problem.\r\n- When debugging, determine the root cause rather than addressing symptoms. Use print statements, logs, or temporary code to inspect program state and test your hypotheses. Revisit your assumptions if unexpected behavior occurs.\r\n- Always read enough context to understand the code before editing; avoid re-reading files whose content has not changed.\r\n\r\n# Communication\r\nCommunicate clearly and concisely in a casual, friendly yet professional tone. Avoid unnecessary explanations, repetition, and filler. Always write code directly to the correct files, and do not display code to the user unless they specifically ask for it.\r\n\r\n# Memory\r\nRemember user preferences expressed across the session and apply them consistently.\r\n\r\n# Git\r\nNever stage and commit files automatically unless the user explicitly tells you to.`\r\n\r\nexport const CODEX_TEXT = `## Editing constraints\r\n- Default to ASCII when editing or creating files. Only introduce non-ASCII or other Unicode characters when there is a clear justification and the file already uses them.\r\n- Only add comments if they are necessary to make a non-obvious block easier to understand.\r\n\r\n## Tool usage\r\n- Prefer dedicated tools over shell for file operations: use an editing tool to modify files, a reading tool to view files, and search tools to find files by name or search file contents.\r\n- Use shell for terminal operations: git, builds, tests, and running scripts.\r\n- Run tool calls in parallel when neither call needs the other's output; otherwise run them sequentially.\r\n\r\n## Git and workspace hygiene\r\n- You may be in a dirty git worktree.\r\n * NEVER revert existing changes you did not make unless explicitly requested, since these changes were made by the user.\r\n * If asked to make a commit or code edits and there are unrelated changes to your work or changes you did not make in those files, do not revert those changes.\r\n * If the changes are in files you have touched recently, read them carefully and understand how you can work with the changes rather than reverting them.\r\n * If the changes are in unrelated files, just ignore them and do not revert them.\r\n- Do not amend commits unless explicitly requested.\r\n- **NEVER** use destructive commands like \\`git reset --hard\\` or \\`git checkout --\\` unless specifically requested or approved by the user.\r\n\r\n## Frontend tasks\r\nWhen doing frontend design tasks, avoid collapsing into bland, generic layouts. Aim for interfaces that feel intentional and deliberate.\r\n- Typography: Use expressive, purposeful fonts and avoid default stacks.\r\n- Color & Look: Choose a clear visual direction; define CSS variables; avoid generic defaults.\r\n- Motion: Use a few meaningful animations (page-load, staggered reveals) instead of generic micro-motions.\r\n- Background: Don't rely on flat, single-color backgrounds; use gradients, shapes, or subtle patterns to build atmosphere.\r\n- Overall: Avoid boilerplate layouts and interchangeable UI patterns. Vary themes, type families, and visual languages across outputs.\r\n- Ensure the page loads properly on both desktop and mobile.\r\nException: If working within an existing website or design system, preserve the established patterns, structure, and visual language.\r\n\r\n## Presenting your work and final message\r\n- Default: be very concise; friendly coding teammate tone.\r\n- Default: do the work without asking questions. Treat short tasks as sufficient direction; infer missing details by reading the codebase and following existing conventions.\r\n- Questions: only ask when you are truly blocked after checking relevant context AND you cannot safely pick a reasonable default. This usually means one of: the request is ambiguous in a way that materially changes the result and you cannot disambiguate by reading the repo; the action is destructive or irreversible, touches production, or changes billing or security posture; you need a secret or credential or value that cannot be inferred.\r\n- If you must ask: do all non-blocked work first, then ask exactly one targeted question, include your recommended default, and state what would change based on the answer.\r\n- Never ask permission questions like \"Should I proceed?\"; proceed with the most reasonable option and mention what you did.\r\n- For substantial work, summarize clearly and follow the final-answer formatting rules.\r\n- Skip heavy formatting for simple confirmations.\r\n- Don't dump large files you have written; reference paths only.\r\n- Offer logical next steps (tests, commits, build) briefly; add verify steps if you could not do something.\r\n- For code changes: lead with a quick explanation of the change, then give more details on the context covering where and why the change was made. If there are natural next steps, suggest them at the end of your response.\r\n\r\n## Final answer structure and style guidelines\r\n- Plain text; the CLI handles styling. Use structure only when it helps scannability.\r\n- Headers: optional; short Title Case (1-3 words); add only if they truly help.\r\n- Bullets: use -; merge related points; keep to one line when possible; keep phrasing consistent.\r\n- Monospace: use inline code for commands, paths, env vars, code ids, and inline examples; never combine with bold.\r\n- Code samples or multi-line snippets should be wrapped in fenced code blocks; include a language tag as often as possible.\r\n- Structure: group related bullets; order sections general to specific.\r\n- Tone: collaborative, concise, factual; present tense, active voice; self-contained.\r\n- Don'ts: no nested bullets or hierarchies; no ANSI codes; don't cram unrelated keywords; avoid naming formatting styles in answers.\r\n- File references: reference files with inline code so paths are clickable; each reference should have a standalone path; optionally include line/column (1-based) using the pattern \\`file_path:line_number\\`.`\r\n\r\nexport const GPT_TEXT = `Be a deeply pragmatic, effective software engineer. Take engineering quality seriously; collaboration comes through as direct, factual statements. Communicate efficiently, keeping the user clearly informed about ongoing actions without unnecessary detail. Build context by examining the codebase first without making assumptions or jumping to conclusions. Think through the nuances of the code you encounter and embody the mentality of a skilled senior software engineer.\r\n\r\n## Editing Approach\r\n\r\n- The best changes are often the smallest correct changes.\r\n- When you are weighing two correct approaches, prefer the more minimal one (less new names, helpers, tests, and so on).\r\n- Keep things in one function unless composable or reusable.\r\n- Do not add backward-compatibility code unless there is a concrete need, such as persisted data, shipped behavior, external consumers, or an explicit user requirement; if unclear, ask one short question instead of guessing.\r\n\r\n## Autonomy and persistence\r\n\r\nUnless the user explicitly asks for a plan, asks a question about the code, is brainstorming potential solutions, or some other intent makes it clear that code should not be written, assume the user wants you to make code changes or run tools to solve the user's problem. In these cases it is bad to output your proposed solution in a message; you should go ahead and actually implement the change. If you encounter challenges or blockers, attempt to resolve them yourself.\r\n\r\nPersist until the task is fully handled end-to-end within the current turn whenever feasible: do not stop at analysis or partial fixes; carry changes through implementation, verification, and a clear explanation of outcomes unless the user explicitly pauses or redirects you.\r\n\r\nIf you notice unexpected changes in the worktree or staging area that you did not make, continue with your task. NEVER revert, undo, or modify changes you did not make unless the user explicitly asks you to. There can be multiple agents or the user working in the same codebase concurrently.\r\n\r\n## Editing constraints\r\n\r\n- Default to ASCII when editing or creating files. Only introduce non-ASCII or other Unicode characters when there is a clear justification and the file already uses them.\r\n- Add succinct code comments that explain what is going on if code is not self-explanatory. Do not add comments like \"assigns the value to the variable\"; a brief comment might be useful ahead of a complex code block. Usage of these comments should be rare.\r\n- Use dedicated tools rather than scripts for reading and writing files when a simple dedicated tool call would suffice.\r\n- You may be in a dirty git worktree.\r\n * NEVER revert existing changes you did not make unless explicitly requested, since these changes were made by the user.\r\n * If asked to make a commit or code edits and there are unrelated changes to your work or changes you did not make in those files, do not revert those changes.\r\n * If the changes are in files you have touched recently, read them carefully and understand how you can work with them rather than reverting them.\r\n * If the changes are in unrelated files, just ignore them and do not revert them.\r\n- Do not amend a commit unless explicitly requested.\r\n- **NEVER** use destructive commands like \\`git reset --hard\\` or \\`git checkout --\\` unless specifically requested or approved by the user.\r\n\r\n## Special user requests\r\n\r\nIf the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command, do so.\r\n\r\nIf the user pastes an error description or a bug report, help them diagnose the root cause. You can try to reproduce it if it seems feasible with the available tools.\r\n\r\nIf the user asks for a \"review\", default to a code review mindset: prioritize identifying bugs, risks, behavioural regressions, and missing tests. Findings must be the primary focus of the response; keep summaries or overviews brief and only after enumerating the issues. Present findings first, ordered by severity with file/line references, followed by open questions or assumptions, and offer a change summary only as a secondary detail. If no findings are discovered, state that explicitly and mention any residual risks or testing gaps.\r\n\r\n## Frontend tasks\r\n\r\nWhen doing frontend design tasks, avoid collapsing into \"AI slop\" or safe, average-looking layouts.\r\n- Ensure the page loads properly on both desktop and mobile.\r\n- Overall: Avoid boilerplate layouts and interchangeable UI patterns. Vary themes, type families, and visual languages across outputs.\r\nException: If working within an existing website or design system, preserve the established patterns, structure, and visual language.\r\n\r\n# Working with the user\r\n\r\n## General\r\n\r\nDo not begin responses with conversational interjections or meta commentary. Avoid openers such as acknowledgements or framing phrases.\r\n\r\nBalance conciseness to not overwhelm the user with appropriate detail for the request. Do not narrate abstractly; explain what you are doing and why.\r\n\r\n## Formatting rules\r\n\r\nYour responses are rendered as GitHub-flavored Markdown.\r\n\r\nNever use nested bullets. Keep lists flat (single level). If you need hierarchy, split into separate lists or sections. For numbered lists, only use the \\`1. 2. 3.\\` style markers (with a period), never \\`1)\\`.\r\n\r\nHeaders are optional, only use them when you think they are necessary. If you do use them, use short Title Case (1-3 words). Don't add a blank line.\r\n\r\nUse inline code blocks for commands, paths, environment variables, function names, inline examples, and keywords.\r\n\r\nCode samples or multi-line snippets should be wrapped in fenced code blocks. Include a language tag when possible.\r\n\r\nDon't use emojis or em dashes unless explicitly instructed.\r\n\r\n## Progress and final responses\r\n\r\nKeep intermediate progress updates short and send them only when they add meaningful new information: a discovery, a tradeoff, a blocker, a substantial plan, or the start of a non-trivial edit or verification step. Do not narrate routine reads, searches, obvious next steps, or minor confirmations. Do not begin responses with conversational interjections or meta commentary. Before substantial work, send a short update describing your first step. Before editing files, send an update describing the edit.\r\n\r\nMatch the final answer to the complexity of the task. Structure it if necessary, ordering sections from general to specific to supporting. If the task is simple, answer with a one-liner. If the user asks for a code explanation, include code references. For simple tasks, just state the outcome without heavy formatting. For large or complex changes, lead with the solution, then explain what you did and why. For casual chat, just chat. If something could not be done (tests, builds, and so on), say so. Suggest next steps only when they are natural and useful; if you list options, use numbered items.`\r\n\r\nexport const KIMI_TEXT = `Your primary goal is to help users with software engineering tasks by taking action: use the tools available to you to make real changes on the user's system. You should also answer questions when asked.\r\n\r\n# Prompt and Tool Use\r\n\r\nThe user's messages may contain questions and/or task descriptions. Read them, understand them, and do what the user requested. For simple questions or greetings that do not involve any information in the working directory or on the internet, reply directly. For anything else, default to taking action with tools. When the request could be interpreted as either a question to answer or a task to complete, treat it as a task.\r\n\r\nWhen handling the user's request, if it involves creating, modifying, or running code or files, you MUST use the appropriate tools to make actual changes; do not just describe the solution in text. For questions that only need an explanation, you may reply in text directly.\r\n\r\nIf a subagent tool is available, you can use it to delegate a focused subtask to a subagent instance. When delegating, provide a complete prompt with all necessary context because a newly created subagent does not automatically see your context.\r\n\r\nYou can output any number of tool calls in a single response. If you anticipate making multiple non-interfering tool calls, make them in parallel to significantly improve efficiency. The results of the tool calls will be returned to you; determine your next action based on the results.\r\n\r\nTool results and user messages may include <system-reminder> tags. These are authoritative system directives that you MUST follow. They may override or constrain your normal behavior, and they bear no direct relation to the specific tool results or user messages in which they appear.\r\n\r\nWhen responding to the user, you MUST use the same language as the user, unless explicitly instructed to do otherwise.\r\n\r\n# General Guidelines for Coding\r\n\r\nWhen building something from scratch, you should:\r\n- Understand the user's requirements.\r\n- Ask the user for clarification if there is anything unclear.\r\n- Design the architecture and make a plan for the implementation.\r\n- Write the code in a modular and maintainable way.\r\n\r\nAlways use tools to implement your code changes: use editing tools to create or modify source files. Code that only appears in your text response is NOT saved to the file system and will not take effect. Use shell to run and test your code after writing it. Iterate: if tests fail, read the error, fix the code, and re-test.\r\n\r\nWhen working on an existing codebase, you should:\r\n- Understand the codebase by reading it with tools before making changes. Identify the ultimate goal and the most important criteria to achieve it.\r\n- For a bug fix, check error logs or failed tests, scan the codebase to find the root cause, and figure out a fix. If the user mentioned failed tests, make sure they pass after the changes.\r\n- For a feature, design the architecture and write the code with minimal intrusion into existing code. Add new tests if the project already has tests.\r\n- For a refactor, update all call sites if the interface changes. DO NOT change existing logic, especially in tests; focus only on fixing errors caused by the interface changes.\r\n- Make MINIMAL changes to achieve the goal. This is very important to your performance.\r\n- Follow the coding style of existing code in the project.\r\n\r\nDO NOT run git commit, git push, git reset, git rebase, or any other git mutations unless explicitly asked to do so. Ask for confirmation each time you need to do git mutations, even if the user has confirmed in earlier conversations.\r\n\r\n# General Guidelines for Research and Data Processing\r\n\r\nSearch on the Internet if possible, with carefully-designed search queries to improve efficiency and accuracy. Use proper tools or shell commands to process or generate files, ensuring that third-party packages are installed in a virtual or isolated environment if needed. Once you generate or edit any files, read them again before proceeding to ensure the content is as expected. Avoid installing or deleting anything outside of the current working directory; if you have to, ask the user for confirmation.\r\n\r\n# Working Environment\r\n\r\nThe operating environment is not in a sandbox. Any actions you do will immediately affect the user's system, so you MUST be extremely cautious. Unless explicitly instructed to do so, never access (read, write, or execute) files outside of the working directory. Use absolute paths for file operations.\r\n\r\n# Project Information\r\n\r\nMarkdown files named AGENTS.md usually contain the background, structure, coding styles, user preferences, and other relevant information about the project. You should read the project's AGENTS.md and README files to understand its conventions and preferences. If they are empty or insufficient, check README files or AGENTS.md files in subdirectories for more information.\r\n\r\n# Ultimate Reminders\r\n\r\nAt any time, you should be HELPFUL, CONCISE, and ACCURATE. Be thorough in your actions: test what you build and verify what you change, not in your explanations.\r\n- Never diverge from the requirements and goals of the task you work on. Stay on track.\r\n- Never give the user more than what they want.\r\n- Try your best to avoid hallucination. Do fact checking before providing any factual information.\r\n- Think about the best approach, then take action decisively.\r\n- Do not give up too early.\r\n- ALWAYS keep it stupidly simple. Do not overcomplicate things.\r\n- When the task requires creating or modifying files, always use tools to do so. Never treat displaying code in your response as a substitute for actually writing it to the file system.`\r\n\r\n/** DeepSeek 官方建议蒸馏(仅追加,不覆盖 base)。 */\r\nexport const DEEPSEEK_APPEND = `Notes for DeepSeek models:\r\n- Tool calls follow the OpenAI function-calling style; pass arguments strictly according to each tool's JSON schema.\r\n- Reasoning models (e.g. deepseek-reasoner) emit their reasoning before the final answer; do not ask them to skip the thinking process.`\r\n\r\n/** 智谱官方建议蒸馏(仅追加,不覆盖 base)。 */\r\nexport const GLM_APPEND = `Notes for GLM models:\r\n- Tool calls follow the OpenAI function-calling style; pass arguments strictly according to each tool's JSON schema.\r\n- For thinking-enabled GLM models, the reasoning_content of each message must be passed back verbatim on the next request; never drop or rewrite it.\r\n- With interleaved thinking, keep the reasoning context across tool-call rounds.`\r\n\r\n/** 默认语义层(固定层栈的唯一可编辑层):persona。\r\n * 结构固定——UI 与服务端均不允许增删层、改名、改序,仅文本可编辑。\r\n * persona 注册为普通 prompt-stack:persona(order 10),排在内置模型层\r\n * prompt-stack:base(order 0)之后;默认空串:dsh「空段不渲染」,未填写时行为零变化。\r\n * persona 是唯一可编辑存储层;base 为内置模型层(保留层名,不进存储),见 index.ts。 */\r\nexport const DEFAULT_LAYERS: LayerConfig[] = [\r\n { name: 'persona', order: 10, text: '' },\r\n]\r\n\r\n/** 默认模型规则(顺序即同分仲裁序,勿调整)。 */\r\nexport const DEFAULT_RULES: Rule[] = [\r\n { match: { modelPattern: 'claude*' }, overrides: { base: ANTHROPIC_TEXT } },\r\n { match: { modelPattern: 'gemini-*' }, overrides: { base: GEMINI_TEXT } },\r\n { match: { modelPattern: 'gpt-4*' }, overrides: { base: BEAST_TEXT } },\r\n { match: { modelPattern: 'o1*' }, overrides: { base: BEAST_TEXT } },\r\n { match: { modelPattern: 'o3*' }, overrides: { base: BEAST_TEXT } },\r\n { match: { modelPattern: 'gpt*codex*' }, overrides: { base: CODEX_TEXT } },\r\n { match: { modelPattern: 'gpt*' }, overrides: { base: GPT_TEXT } },\r\n { match: { modelPattern: 'kimi*' }, overrides: { base: KIMI_TEXT } },\r\n // kimi 官方模型 id 不带 kimi 前缀(k2、k3-256k 等),且常挂在自定义 provider 名下。\r\n { match: { modelPattern: 'k2*' }, overrides: { base: KIMI_TEXT } },\r\n { match: { modelPattern: 'k3*' }, overrides: { base: KIMI_TEXT } },\r\n { match: { provider: 'moonshotai' }, overrides: { base: KIMI_TEXT } },\r\n { match: { provider: 'moonshotai-cn' }, overrides: { base: KIMI_TEXT } },\r\n { match: { provider: 'kimi-for-coding' }, overrides: { base: KIMI_TEXT } },\r\n { match: { modelPattern: 'deepseek*' }, append: DEEPSEEK_APPEND },\r\n { match: { modelPattern: 'glm-*' }, append: GLM_APPEND },\r\n]\r\n","/** 模型规则匹配:glob 编译、AND 打分、最高分选择。 */\r\nimport type { Rule, RuleMatch } from './types.ts'\r\n\r\n/** 正则元字符(`*` 与 `?` 除外——它们是 glob 通配符,之后单独展开)。 */\r\nconst REGEXP_META = /[.+^${}()|[\\]\\\\]/g\r\n\r\n/**\r\n * 把 glob(`*` = 任意串,`?` = 单字符)编译为锚定全串的正则。\r\n * @param pattern - 非空 glob;空或全空白抛错(激活期响亮报错的调用点在 apply)。\r\n * @returns 锚定全串的正则。\r\n */\r\nexport function globToRegExp(pattern: string): RegExp {\r\n if (pattern.trim() === '') {\r\n throw new Error('prompt-stack: modelPattern must be a non-empty glob')\r\n }\r\n const source = pattern\r\n .replace(REGEXP_META, '\\\\$&')\r\n .replaceAll('*', '.*')\r\n .replaceAll('?', '.')\r\n return new RegExp(`^${source}$`)\r\n}\r\n\r\n/**\r\n * 给一条规则的 match 打分:任一指定字段不匹配则整条不命中(返回 0);\r\n * 命中分值为 model=4 / modelPattern=2 / provider=1 的累加。\r\n * @param match - 规则的匹配条件。\r\n * @param provider - 当前 agent 的 provider(创建期配置),可缺失。\r\n * @param model - 当前 agent 的模型 id,可缺失。\r\n * @returns 命中分值,0 表示不命中。\r\n */\r\nexport function scoreRule(match: RuleMatch, provider: string | undefined, model: string | undefined): number {\r\n let score = 0\r\n if (match.provider !== undefined) {\r\n if (match.provider !== provider) return 0\r\n score += 1\r\n }\r\n if (match.model !== undefined) {\r\n if (match.model !== model) return 0\r\n score += 4\r\n }\r\n if (match.modelPattern !== undefined) {\r\n if (model === undefined || !globToRegExp(match.modelPattern).test(model)) return 0\r\n score += 2\r\n }\r\n return score\r\n}\r\n\r\n/**\r\n * 选出唯一命中规则:最高分者,同分取配置序靠前者。\r\n * @param rules - 配置中的规则数组(顺序即优先级仲裁序)。\r\n * @param provider - 当前 agent 的 provider,可缺失。\r\n * @param model - 当前 agent 的模型 id,可缺失。\r\n * @returns 命中规则;无命中返回 undefined。\r\n */\r\nexport function selectRule(rules: readonly Rule[], provider: string | undefined, model: string | undefined): Rule | undefined {\r\n let best: Rule | undefined\r\n let bestScore = 0\r\n for (const rule of rules) {\r\n const score = scoreRule(rule.match, provider, model)\r\n if (score > bestScore) {\r\n best = rule\r\n bestScore = score\r\n }\r\n }\r\n return best\r\n}\r\n","/** prompt 模块:内置模型层(按模型规则整体覆盖)+ persona 可编辑层 + model-notes 自动层。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\n// type-only 导入激活声明合并:Context.systemPrompt 与 AssembleContext.agent。\r\nimport type { Agent } from '@deepseek-ai/dsh-agent'\r\nimport type { AssembleContext } from '@deepseek-ai/dsh-system-prompt'\r\nimport { BASE_TEXT } from './defaults.ts'\r\nimport { globToRegExp, selectRule } from './match.ts'\r\nimport type { Config as ConfigT, LayerConfig, Rule } from './types.ts'\r\n\r\nexport type { Config, LayerConfig, Rule, RuleMatch } from './types.ts'\r\n\r\n/** 固定追加层的层名(保留,用户层不得使用)。 */\r\nexport const MODEL_NOTES_LAYER = 'model-notes'\r\n\r\n/** 内置模型层名(保留):固定注册 prompt-stack:base 段、不进存储,仍是 rules overrides 的合法目标。 */\r\nexport const BASE_LAYER = 'base'\r\n\r\nconst BASE_SECTION = `prompt-stack:${BASE_LAYER}`\r\n\r\n/** 原生身份段名与原生文本(与 dsh system-prompt 宿主一致;覆盖判定的基准值)。 */\r\nconst IDENTITY_SECTION = 'harness:identity'\r\nconst NATIVE_IDENTITY_TEXT = 'You are an AI agent powered by DeepSeek Harness.'\r\n\r\n/** 运行时层视图:setupPrompt 只消费 get/getIdentity + subscribe,不关心存储细节(测试可注入假实现)。 */\r\nexport interface LayerView {\r\n get(): LayerConfig[]\r\n /** identity 段覆盖文本(空串 = 原生)。 */\r\n getIdentity(): string\r\n subscribe(listener: () => void): () => void\r\n}\r\n\r\n/** 层列表语义校验:空、层名重复、保留层名(base/model-notes)。 */\r\nexport function validateLayers(layers: LayerConfig[]): void {\r\n if (layers.length === 0) {\r\n throw new Error('prompt-stack: config.layers must define at least one layer')\r\n }\r\n const names = new Set<string>()\r\n for (const layer of layers) {\r\n if (layer.name === MODEL_NOTES_LAYER || layer.name === BASE_LAYER) {\r\n throw new Error(`prompt-stack: layer name \"${layer.name}\" is reserved`)\r\n }\r\n if (names.has(layer.name)) {\r\n throw new Error(`prompt-stack: duplicate layer name \"${layer.name}\"`)\r\n }\r\n names.add(layer.name)\r\n }\r\n}\r\n\r\n/**\r\n * 激活期校验(dsh「误配置响亮失败」惯例):空 layers、层名重复、保留层名、\r\n * overrides 引用未知层(内置 base 与 model-notes 之外的存储层名)、空 match、非法 glob 全部抛错。\r\n */\r\nexport function validateConfig(config: ConfigT): void {\r\n validateLayers(config.layers)\r\n const names = new Set([BASE_LAYER, ...config.layers.map(layer => layer.name)])\r\n for (const [index, rule] of config.rules.entries()) {\r\n const { provider, model, modelPattern } = rule.match\r\n if (provider === undefined && model === undefined && modelPattern === undefined) {\r\n throw new Error(`prompt-stack: rules[${index}].match must set at least one of provider, model, modelPattern`)\r\n }\r\n if (modelPattern !== undefined) globToRegExp(modelPattern)\r\n for (const key of Object.keys(rule.overrides ?? {})) {\r\n if (!names.has(key)) {\r\n throw new Error(`prompt-stack: rules[${index}].overrides references unknown layer \"${key}\"`)\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 固定注册 prompt-stack:base(模型层,order 0)+ 每个存储层一个段 + model-notes。\r\n * 文本在每次组装时按当前 agent 的 provider/model 选唯一命中规则(最高分、同分取配置序靠前),\r\n * 模型层用 overrides.base 整体替换内置 BASE_TEXT,存储层用 overrides 替换该层文本。\r\n * 裸组装(无 agent)静默用默认文本。deployment:persona 槽位还原生,本模块不触碰。\r\n *\r\n * 运行时选模型与首条消息钉住语义不变(见 waterfall 注释)。\r\n */\r\nexport function setupPrompt(ctx: Context, config: { source: LayerView; rules: Rule[] }): void {\r\n const { source, rules } = config\r\n const hitRule = (context: AssembleContext): Rule | undefined =>\r\n selectRule(rules, context.agent?.options?.provider, context.agent?.options?.model)\r\n // 子 Agent 隔离:模型层/persona 不泄漏进子 Agent 组装;model-notes 是模型层\r\n // (模型的通用使用说明),主子共用、按子的生效模型命中规则。\r\n const isSubagent = (context: AssembleContext): boolean =>\r\n context.agent?.session?.header?.origin === 'subagent'\r\n\r\n // 层文本可经 UI 修改:registerSections 先 dispose 上一轮再按当前层重注册,\r\n // source 变更时经 subscribe 触发。base 与 model-notes 恒注册,不随层集变化。\r\n let disposers: Array<() => void> = []\r\n const registerSections = (): void => {\r\n for (const dispose of disposers) dispose()\r\n disposers = []\r\n const layers = source.get()\r\n validateLayers(layers)\r\n const notesOrder = Math.max(0, ...layers.map(layer => layer.order)) + 1\r\n disposers.push(ctx.systemPrompt.section({\r\n name: BASE_SECTION,\r\n order: 0,\r\n text: (context) =>\r\n isSubagent(context) ? '' : (hitRule(context)?.overrides?.[BASE_LAYER] ?? BASE_TEXT),\r\n }))\r\n for (const layer of layers) {\r\n disposers.push(ctx.systemPrompt.section({\r\n name: `prompt-stack:${layer.name}`,\r\n order: layer.order,\r\n text: (context) =>\r\n isSubagent(context) ? '' : (hitRule(context)?.overrides?.[layer.name] ?? layer.text),\r\n }))\r\n }\r\n disposers.push(ctx.systemPrompt.section({\r\n name: `prompt-stack:${MODEL_NOTES_LAYER}`,\r\n order: notesOrder,\r\n text: (context) => hitRule(context)?.append ?? '',\r\n }))\r\n }\r\n registerSections()\r\n ctx.effect(() => source.subscribe(registerSections))\r\n\r\n const notesSection = `prompt-stack:${MODEL_NOTES_LAYER}`\r\n // 首条消息钉住:每个会话的首次组装解析出的 provider/model 缓存起来,会话中途\r\n // 切模型不再改写系统提示词(对话的行为契约保持稳定)。键带 session id:\r\n // clear/新会话(id 变化)自动重新解析。HMR 重挂载换新闭包,缓存随之重置。\r\n const pinned = new WeakMap<Agent, { sessionId: unknown; provider: string | undefined; model: string | undefined }>()\r\n ctx.on('system-prompt/assemble', async (_assembly, context, next) => {\r\n const assembled = await next()\r\n let provider = assembled.variables.provider ?? context.agent?.options?.provider\r\n let model = assembled.variables.model ?? context.agent?.options?.model\r\n const agent = context.agent\r\n if (agent !== undefined) {\r\n const cached = pinned.get(agent)\r\n if (cached !== undefined && cached.sessionId === agent.session.id) {\r\n provider = cached.provider\r\n model = cached.model\r\n } else if (provider !== undefined || model !== undefined) {\r\n pinned.set(agent, { sessionId: agent.session.id, provider, model })\r\n }\r\n }\r\n const rule = selectRule(rules, provider, model)\r\n const layers = source.get()\r\n // 本插件全局注册各段在本次组装的产出(不含钉住改写)。scoped 同名段(bot 角色\r\n // persona 等)经 dsh 原生 shadow 机制已覆盖全局段,其文本 ≠ 本插件产出,\r\n // 据此识别并跳过、不介入 shadow(spec §3「对主 Agent persona 层 waterfall 不介入」)。\r\n const ownSection = (section: { name: string }): string | undefined => {\r\n if (section.name === BASE_SECTION) {\r\n return isSubagent(context) ? '' : (hitRule(context)?.overrides?.[BASE_LAYER] ?? BASE_TEXT)\r\n }\r\n const layer = layers.find(l => section.name === `prompt-stack:${l.name}`)\r\n if (layer === undefined) return undefined\r\n return isSubagent(context) ? '' : (hitRule(context)?.overrides?.[layer.name] ?? layer.text)\r\n }\r\n const sections = assembled.sections.map((section) => {\r\n // identity 覆盖:非空覆盖文本整份替换原生身份句(空 = 还原原生;子 Agent 隔离;\r\n // 段文本 ≠ 原生常量即 scoped shadow,不介入——同下方 ownSection 守卫语义)。\r\n if (section.name === IDENTITY_SECTION) {\r\n const override = source.getIdentity()\r\n if (override === '' || isSubagent(context) || section.text !== NATIVE_IDENTITY_TEXT) return section\r\n return { ...section, text: override }\r\n }\r\n if (section.name === notesSection) {\r\n return { ...section, text: rule?.append ?? '' }\r\n }\r\n const own = ownSection(section)\r\n if (own === undefined || section.text !== own) return section\r\n if (section.name === BASE_SECTION) {\r\n return { ...section, text: isSubagent(context) ? '' : (rule?.overrides?.[BASE_LAYER] ?? BASE_TEXT) }\r\n }\r\n const layer = layers.find(l => section.name === `prompt-stack:${l.name}`)!\r\n return { ...section, text: isSubagent(context) ? '' : (rule?.overrides?.[layer.name] ?? layer.text) }\r\n })\r\n return { ...assembled, sections }\r\n })\r\n}\r\n","/** 分层提示词层源:内存缓存 + prompt_layers 表回写 + 订阅通知;Config 仅作首启种子。 */\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport type { LayerConfig } from './types.ts'\r\nimport { validateLayers, type LayerView } from './index.ts'\r\n\r\n/** prompt_layers 表单行的 key 常量。 */\r\nexport const PROMPT_LAYERS_KEY = 'layers'\r\n/** meta 表首启种子一次性标记键。 */\r\nexport const PROMPT_LAYERS_SEEDED_KEY = 'prompt_layers_seeded'\r\n\r\nexport interface PromptLayersRow {\r\n layers: LayerConfig[]\r\n /** identity 段覆盖文本(可选,仅非空时写入;空/缺省 = 原生句)。 */\r\n identity?: string\r\n}\r\n\r\n/** 层源的完整能力:setupPrompt 只消费 get/getIdentity/subscribe(LayerView),存储层消费 set/setIdentity/reset。 */\r\nexport interface LayerSource extends LayerView {\r\n /** 校验 → 写表 → 更新内存 → 通知订阅者。 */\r\n set(layers: LayerConfig[]): Promise<void>\r\n /** 写入 identity 覆盖文本(空串 = 还原原生)→ 更新内存 → 通知订阅者。 */\r\n setIdentity(text: string): Promise<void>\r\n /** 清表 + 清种子标记 → 重写种子 → 通知订阅者。连带清空 identity 覆盖。 */\r\n reset(): Promise<void>\r\n}\r\n\r\nexport interface PromptLayerTables {\r\n promptLayers: KvTable<string, PromptLayersRow>\r\n meta: KvTable<string, { value: string }>\r\n}\r\n\r\n/** 组装存储行:identity 仅非空时落字段(空串 = 还原原生,不留残字段)。 */\r\nfunction row(layers: LayerConfig[], identity: string): PromptLayersRow {\r\n return identity === '' ? { layers } : { layers, identity }\r\n}\r\n\r\n/** 固定结构校验:name+order 多重集合必须等于种子(仅 text 可变)。 */\r\nexport function validateFixedLayers(layers: LayerConfig[], seedLayers: LayerConfig[]): void {\r\n const key = (layer: LayerConfig): string => `${layer.name}@${String(layer.order)}`\r\n const seed = seedLayers.map(key).sort()\r\n const actual = layers.map(key).sort()\r\n if (actual.length !== seed.length || actual.some((k, i) => k !== seed[i])) {\r\n throw new Error(`prompt-stack: layer structure is fixed (${seedLayers.map(l => l.name).join(', ')}); only layer text is editable`)\r\n }\r\n}\r\n\r\n/** 按种子结构 reconcile 已存储层:同名层保留已存文本(order 以种子为准)、补缺失、丢多余。 */\r\nexport function reconcileLayers(stored: LayerConfig[], seedLayers: LayerConfig[]): LayerConfig[] {\r\n return seedLayers.map(seed => ({\r\n ...seed,\r\n text: stored.find(layer => layer.name === seed.name)?.text ?? seed.text,\r\n }))\r\n}\r\n\r\n/**\r\n * 打开层源。域由 apply 统一 open(storage-domain 同名单开),本函数只消费表句柄。\r\n * 首启(表无数据)种入 Config 种子并置标记;此后读存储并按种子结构 reconcile\r\n * (层栈固定化迁移:保留已编辑文本、补新层、丢多余层)。\r\n */\r\nexport async function openLayerSource(tables: PromptLayerTables, seedLayers: LayerConfig[]): Promise<LayerSource> {\r\n const { promptLayers, meta } = tables\r\n validateLayers(seedLayers)\r\n let cache: LayerConfig[]\r\n let identity: string\r\n const existing = promptLayers.get(PROMPT_LAYERS_KEY)\r\n if (existing !== undefined) {\r\n // 不再 validateLayers(existing.layers):旧存储可能含已退役的层名(如 base),\r\n // reconcile 负责对齐种子结构,校验只针对 reconcile 后的结果(恒合法,防御性保留)。\r\n cache = reconcileLayers(existing.layers, seedLayers)\r\n validateLayers(cache)\r\n identity = existing.identity ?? ''\r\n await promptLayers.put(PROMPT_LAYERS_KEY, row(cache, identity))\r\n } else {\r\n cache = seedLayers\r\n identity = ''\r\n await promptLayers.put(PROMPT_LAYERS_KEY, { layers: cache })\r\n }\r\n if (meta.get(PROMPT_LAYERS_SEEDED_KEY) === undefined) {\r\n await meta.put(PROMPT_LAYERS_SEEDED_KEY, { value: '1' })\r\n }\r\n\r\n const listeners = new Set<() => void>()\r\n const notify = (): void => { for (const listener of [...listeners]) listener() }\r\n\r\n return {\r\n get: () => cache,\r\n getIdentity: () => identity,\r\n async set(layers: LayerConfig[]): Promise<void> {\r\n validateLayers(layers)\r\n validateFixedLayers(layers, seedLayers)\r\n await promptLayers.put(PROMPT_LAYERS_KEY, row(layers, identity))\r\n cache = layers\r\n notify()\r\n },\r\n async setIdentity(text: string): Promise<void> {\r\n await promptLayers.put(PROMPT_LAYERS_KEY, row(cache, text))\r\n identity = text\r\n notify()\r\n },\r\n async reset(): Promise<void> {\r\n await promptLayers.delete(PROMPT_LAYERS_KEY)\r\n await meta.delete(PROMPT_LAYERS_SEEDED_KEY)\r\n await promptLayers.put(PROMPT_LAYERS_KEY, { layers: seedLayers })\r\n await meta.put(PROMPT_LAYERS_SEEDED_KEY, { value: '1' })\r\n cache = seedLayers\r\n identity = ''\r\n notify()\r\n },\r\n subscribe(listener: () => void): () => void {\r\n listeners.add(listener)\r\n return () => { listeners.delete(listener) }\r\n },\r\n }\r\n}\r\n","/** shared webServer 助手:可选服务模式下注册路由(headless/CLI 无 webServer 时惰性、不注册、不抛错)。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\n\r\nexport function registerOptionalRoutes(\r\n ctx: Context,\r\n register: (webCtx: Context) => () => void,\r\n): void {\r\n // 经 ctx.inject 子 fiber 等待 webServer 挂载后再注册:子 fiber 未激活时惰性、\r\n // 随父 fiber 卸载而清理;webServer 永不出现时任何分支都不注册。注册走\r\n // ctx.effect 接线 disposer(\"Registrations are effects\"),HMR 重挂不会因\r\n // 重复 exact 路径抛错。\r\n ctx.inject(['webServer'], (webCtx) => {\r\n webCtx.effect(() => register(webCtx))\r\n })\r\n}\r\n","import type { IncomingMessage, ServerResponse } from 'node:http'\r\n\r\nexport const MAX_BODY_BYTES = 64 * 1024\r\n\r\nexport function json(res: ServerResponse, code: number, body: unknown): void {\r\n res.writeHead(code, { 'content-type': 'application/json' }).end(JSON.stringify(body))\r\n}\r\n\r\n/** 读 JSON body;超限 413 / 非法 JSON 400(已写响应时返回 undefined)。 */\r\nexport async function readJsonBody(req: IncomingMessage, res: ServerResponse): Promise<unknown | undefined> {\r\n const chunks: Buffer[] = []\r\n let received = 0\r\n for await (const chunk of req) {\r\n const buffer = chunk as Buffer\r\n received += buffer.byteLength\r\n if (received > MAX_BODY_BYTES) {\r\n json(res, 413, { error: 'body too large' })\r\n req.destroy()\r\n return undefined\r\n }\r\n chunks.push(buffer)\r\n }\r\n try {\r\n return JSON.parse(Buffer.concat(chunks).toString('utf8'))\r\n } catch {\r\n json(res, 400, { error: 'invalid JSON body' })\r\n return undefined\r\n }\r\n}\r\n","/** 分层提示词 RPC 端点组:读(layers+rules+seed+native 探测)、写(PUT 全量替换)、reset。 */\r\nimport type { IncomingMessage, ServerResponse } from 'node:http'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { z } from 'zod'\r\nimport { registerOptionalRoutes } from '../shared/webserver.ts'\r\nimport { json, readJsonBody } from '../shared/http.ts'\r\nimport { LayerConfigSchema } from '../agents/store.ts'\r\nimport { BASE_TEXT } from './defaults.ts'\r\nimport { validateLayers } from './index.ts'\r\nimport { validateFixedLayers, type LayerSource } from './layer-source.ts'\r\nimport type { LayerConfig, Rule } from './types.ts'\r\n\r\n/** 裸组装探测结果:原生 sections / 动态 contexts 的名称与当前文本(只读展示用)。 */\r\nexport interface NativeProbe {\r\n sections: Array<{ name: string; text: string }>\r\n contexts: Array<{ name: string; text: string }>\r\n}\r\n\r\nexport interface PromptLayersApiDeps {\r\n source: LayerSource\r\n rules: Rule[]\r\n seedLayers: LayerConfig[]\r\n /** 裸 assemble 探测(apply 闭包注入);失败降级为空列表,不阻塞主数据。 */\r\n probe: () => Promise<NativeProbe>\r\n}\r\n\r\nconst LayersBodySchema = z.object({ layers: z.array(LayerConfigSchema), identityOverride: z.string().optional() })\r\n\r\nexport function createPromptLayersApiHandler(deps: PromptLayersApiDeps): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\r\n return async (req, res) => {\r\n const url = new URL(req.url ?? '/', 'http://127.0.0.1')\r\n const sub = url.pathname.replace(/^\\/dsh-agent-toolkit\\/api\\/prompt-layers/, '') || '/'\r\n const method = req.method ?? 'GET'\r\n\r\n if (sub === '/' && method === 'GET') {\r\n let native: NativeProbe = { sections: [], contexts: [] }\r\n try {\r\n native = await deps.probe()\r\n } catch { /* 探测失败降级为空,layers/rules/seedLayers 主数据照常返回 */ }\r\n json(res, 200, { layers: deps.source.get(), rules: deps.rules, seedLayers: deps.seedLayers, native, modelFallbackText: BASE_TEXT, identityOverride: deps.source.getIdentity() })\r\n return\r\n }\r\n\r\n if (sub === '/' && method === 'PUT') {\r\n const body = await readJsonBody(req, res)\r\n if (body === undefined) return\r\n const parsed = LayersBodySchema.safeParse(body)\r\n if (!parsed.success) {\r\n json(res, 400, { error: parsed.error.issues[0]?.message ?? 'invalid layers body' })\r\n return\r\n }\r\n try {\r\n validateLayers(parsed.data.layers)\r\n validateFixedLayers(parsed.data.layers, deps.seedLayers)\r\n } catch (error) {\r\n json(res, 400, { error: error instanceof Error ? error.message : String(error) })\r\n return\r\n }\r\n try {\r\n await deps.source.set(parsed.data.layers)\r\n if (parsed.data.identityOverride !== undefined) {\r\n await deps.source.setIdentity(parsed.data.identityOverride)\r\n }\r\n } catch (error) {\r\n json(res, 500, { error: error instanceof Error ? error.message : String(error) })\r\n return\r\n }\r\n json(res, 200, { ok: true })\r\n return\r\n }\r\n\r\n if (sub === '/reset' && method === 'POST') {\r\n try {\r\n await deps.source.reset()\r\n } catch (error) {\r\n json(res, 500, { error: error instanceof Error ? error.message : String(error) })\r\n return\r\n }\r\n json(res, 200, { ok: true })\r\n return\r\n }\r\n\r\n if (sub === '/reset' || sub === '/') {\r\n json(res, 405, { error: 'method not allowed' })\r\n return\r\n }\r\n json(res, 404, { error: 'not found' })\r\n }\r\n}\r\n\r\n/** 注册 /dsh-agent-toolkit/api/prompt-layers 前缀路由(webServer 可选服务,缺席惰性不注册)。 */\r\nexport function setupPromptLayersApi(ctx: Context, deps: PromptLayersApiDeps): void {\r\n const handler = createPromptLayersApiHandler(deps)\r\n registerOptionalRoutes(ctx, (webCtx) => {\r\n const dispose = webCtx.webServer.register({ kind: 'prefix', path: '/dsh-agent-toolkit/api/prompt-layers', handler })\r\n return () => dispose()\r\n })\r\n}\r\n","/** 委派子 Agent 的 persona 装配:契约段 + 内置模型层(按子的模型改写)+ 角色 persona。 */\r\nimport { BASE_TEXT } from './defaults.ts'\r\nimport { selectRule } from './match.ts'\r\nimport type { Rule } from './types.ts'\r\n\r\nconst SECTION_A = (roleName: string): string => `你是团队中的一名成员(角色:${roleName}),由主 Agent 委派任务。\r\n- 你看不到主对话;任务书包含你完成工作所需的全部上下文。\r\n- 你的最终输出会作为结果完整返回给主 Agent:直接给出结论与必要细节。\r\n- 你不能再次委派他人;任务需要拆分时,自己按顺序完成。`\r\n\r\nconst SECTION_B = `能力使用守则:\r\n- 你可以使用与主 Agent 相同的工具与 MCP 资源,但只在任务必需时调用。\r\n- 动手修改代码前,先阅读项目根目录及涉及目录的 AGENTS.md,并遵循其中约定。\r\n- 产生或修改文件后,运行相关检查(测试、类型检查)验证你的改动。`\r\n\r\n/**\r\n * 子 Agent 提示词 = 契约段 A/B + 模型层文本(命中规则 overrides.base 整份替换内置\r\n * BASE_TEXT)+ 角色 persona(非空时,排在模型层之后)+ 命中规则的 append(model-notes)。\r\n * 全局 persona 层是主 Agent 的人设,不进入子 Agent(子的角色由 role.persona 顶替)。\r\n */\r\nexport function buildAgentPersona(\r\n config: { rules: Rule[] },\r\n role: { name: string; persona?: string },\r\n model?: { provider?: string; model?: string },\r\n): string {\r\n const rule = selectRule(config.rules, model?.provider, model?.model)\r\n const texts = [rule?.overrides?.base ?? BASE_TEXT]\r\n if (role.persona !== undefined && role.persona.trim().length > 0) texts.push(role.persona)\r\n if (rule?.append !== undefined) texts.push(rule.append)\r\n return [SECTION_A(role.name), SECTION_B, ...texts].join('\\n\\n')\r\n}\r\n","/** team_delegate 工具:查角色 → 一次性 spawn 前台委派 → 规范 JSON 返回。 */\r\nimport type { Agent } from '@deepseek-ai/dsh-agent'\r\nimport type { ContentBlock } from '@deepseek-ai/dsh-llm'\r\nimport type { JsonValue } from '@deepseek-ai/dsh-session'\r\nimport { defineTool, RUN_CODE_NAME } from '@deepseek-ai/dsh-tools'\r\nimport type { SubagentResult, SubagentRun, SubagentStartRequest } from '@deepseek-ai/dsh-subagent'\r\nimport { isTeamVisible, type AgentRecord } from '../agents/store.ts'\r\nimport type { ActiveRoutes, DelegateRoute } from './active.ts'\r\n\r\n/** createDelegateTool 的外部依赖。 */\r\nexport interface DelegateToolDeps {\r\n /** 当前生效名册(闭包返回同一数组;查找与错误清单均排除 main)。 */\r\n readonly roster: () => readonly AgentRecord[]\r\n /** ctx.subagents 的 provider 名(默认 'spawn')。 */\r\n readonly provider: string\r\n /** 成员 persona 装配(生产为 buildAgentPersona,测试注入假实现)。 */\r\n readonly buildPersona: (role: AgentRecord) => string\r\n /** 委派入口:生产为 ctx.subagents.start.bind(ctx.subagents),测试注入假实现。 */\r\n readonly startRun: (provider: string, request: SubagentStartRequest) => Promise<SubagentRun>\r\n /** 在途表:运行中委派卡 chip 的数据源。 */\r\n readonly active: ActiveRoutes\r\n /** 持久路由写入(子会话头部 chip 数据源);实现方保证不抛错语义由调用处 catch 兜底。 */\r\n readonly recordRoute: (childSessionId: string, route: DelegateRoute) => Promise<void>\r\n /** 父会话真实可见工具面(生产走 scopeOf(agent.ctx) + scoped schemas;测试注入 fake)。 */\r\n readonly visibleSurface: (agent: Agent) => string[]\r\n /** 未知名 warn-drop 日志(生产 ctx.logger.warn)。 */\r\n readonly warn: (msg: string) => void\r\n}\r\n\r\n/** 非 completed 的 stopReason 意味着成员未干净完成。 */\r\nfunction stopReasonError(result: SubagentResult): string | undefined {\r\n switch (result.stopReason) {\r\n case 'completed': return undefined\r\n case 'aborted': return '成员运行被取消'\r\n case 'error': return '成员运行失败'\r\n case 'max-tokens': return '成员在结束前触及 token 上限'\r\n case 'refusal': return '成员拒绝了该任务'\r\n default: return `成员运行异常结束(${String(result.stopReason)})`\r\n }\r\n}\r\n\r\n/** 报错时附上成员已产出的部分文本,让截断/取消的真实产出仍回到主 Agent。 */\r\nfunction withPartialText(error: string, output: ContentBlock[]): string {\r\n const text = output\r\n .filter((block): block is Extract<ContentBlock, { type: 'text' }> => block.type === 'text')\r\n .map(block => block.text)\r\n .join('')\r\n return text.length === 0 ? error : `${error}\\n成员中断前的部分产出:\\n${text}`\r\n}\r\n\r\n/** 收集并释放一次前台运行;dispose 失败不掩盖独立的结果失败。 */\r\nasync function settleForegroundRun(run: SubagentRun, roleId: string, route?: DelegateRoute) {\r\n // 本地 run 的 run.id 契约上即子 session id(dsh-subagent types.ts:249-255)。\r\n const childSessionId = String(run.id)\r\n const [execution] = await Promise.allSettled([\r\n run.result.then((result) => {\r\n const error = stopReasonError(result)\r\n if (error !== undefined) throw new Error(withPartialText(error, result.output))\r\n return {\r\n kind: 'foreground' as const,\r\n role: roleId,\r\n runId: String(run.id),\r\n childSessionId,\r\n output: result.output as unknown as JsonValue[],\r\n ...route !== undefined ? { provider: route.provider, model: route.model } : {},\r\n }\r\n }),\r\n ])\r\n const [disposal] = await Promise.allSettled([Promise.resolve().then(() => run.dispose())])\r\n if (execution.status === 'rejected') {\r\n if (disposal.status === 'rejected') {\r\n throw new AggregateError([execution.reason, disposal.reason],\r\n `成员运行失败:${String(execution.reason)};dispose 失败:${String(disposal.reason)}`)\r\n }\r\n throw execution.reason\r\n }\r\n if (disposal.status === 'rejected') throw disposal.reason\r\n return execution.value\r\n}\r\n\r\n/**\r\n * 创建 team_delegate 工具。\r\n * @param toolName - 模型可见工具名(Config.toolName,默认 team_delegate)。\r\n * @param deps - 名册、provider、persona 装配与委派入口。\r\n * @returns defineTool 产物,交给 ctx.tools.register。\r\n *\r\n * 工具注册是 standing scope 的单次注册,description 无法内嵌名册;名册对模型的\r\n * 可见性走系统提示团队段(index.ts)。\r\n */\r\nexport function createDelegateTool(toolName: string, deps: DelegateToolDeps) {\r\n const tool = defineTool({\r\n name: toolName,\r\n description:\r\n 'Delegate a self-contained task to a team member (a separate agent with its own persona and '\r\n + 'optional model override). The member does NOT see this conversation — give it a complete, '\r\n + 'standalone prompt. Available members and their descriptions are listed in the team section '\r\n + 'of the system prompt. This call waits for the member and returns its result.',\r\n parameters: {\r\n role: { type: 'string', required: true, description: 'The member to delegate to. Must be one of the listed names.' },\r\n description: { type: 'string', required: true, description: 'A short (3-5 word) description of the delegated task, for display.' },\r\n prompt: { type: 'string', required: true, description: 'The complete, self-contained task for the member. It does not share this conversation\\'s context, so include everything it needs.' },\r\n },\r\n output: {\r\n schema: {\r\n type: 'object',\r\n additionalProperties: false,\r\n properties: {\r\n kind: { type: 'string', required: true, const: 'foreground' },\r\n role: { type: 'string', required: true },\r\n runId: { type: 'string', required: true },\r\n childSessionId: { type: 'string', required: true },\r\n output: { type: 'array', required: true, items: { type: 'json' } },\r\n provider: { type: 'string' },\r\n model: { type: 'string' },\r\n },\r\n },\r\n render: (_args, value) => [{\r\n type: 'text' as const,\r\n text: (value.output as { type: string; text?: string }[])\r\n .filter(block => block.type === 'text' && typeof block.text === 'string')\r\n .map(block => block.text).join(''),\r\n }],\r\n // 浏览器半委派卡经 tool/result 的持久化 meta 读子会话坐标(回放可重建)。\r\n presentationMeta: (_args, value) => ({\r\n role: value.role as string,\r\n runId: value.runId as string,\r\n childSessionId: value.childSessionId as string,\r\n ...typeof value.provider === 'string' && typeof value.model === 'string'\r\n ? { provider: value.provider, model: value.model }\r\n : {},\r\n }),\r\n },\r\n // 成员不改父会话;父方无写操作。与内置 subagent 工具同款。\r\n isConcurrencySafe: () => true,\r\n // generic 兜底(浏览器半缺席/回放旧事件时降级;generic title 在 Web 不渲染,\r\n // 供 headless 与日志使用)。\r\n presentCall: (args) => ({\r\n card: 'generic' as const,\r\n title: `委派 · ${args.role}: ${args.description}`,\r\n rawInput: args.prompt,\r\n }),\r\n presentResult: (_args, result) => (result.isError ? undefined : { card: 'generic' as const }),\r\n async execute(args, exec) {\r\n const parent: Agent | undefined = exec.agent\r\n if (!parent) throw new Error('team_delegate 需要调用方 agent(exec.agent 为空)')\r\n // 主 Agent 与团队不可见角色不可委派:查找与错误清单都排除。\r\n const roster = deps.roster().filter(r => r.id !== 'main' && isTeamVisible(r))\r\n const role = roster.find(r => r.id === args.role)\r\n if (!role) {\r\n throw new Error(`未知角色 \"${args.role}\"。可用角色:${roster.map(r => r.id).join(', ')}`)\r\n }\r\n const persona = deps.buildPersona(role)\r\n // 白名单与父会话真实可见面求交(warn-drop 未知名)——宿主 child-agent 对 toolFilter\r\n // 直接 restrict,未知名响亮失败(spawn-in-process 测试 \"an unknown toolFilter name\r\n // fails the spawn loudly\" 佐证);与 bot 会话路径(channels/agent-setup.ts)对称,\r\n // 消除两条路径的白名单有效性不对称。求交为空抛错防静默零工具子会话。\r\n let toolFilter: { allow: string[] } | undefined\r\n if (role.tools !== undefined) {\r\n const visible = new Set(deps.visibleSurface(parent).filter((n) => n !== RUN_CODE_NAME))\r\n const effective = role.tools.allow.filter((n) => visible.has(n))\r\n const dropped = role.tools.allow.filter((n) => !visible.has(n))\r\n if (dropped.length > 0) {\r\n deps.warn(`dsh-agent-toolkit: 角色 ${role.id} 白名单含本会话不可见工具,委派时忽略:${dropped.join(', ')}`)\r\n }\r\n if (effective.length === 0) {\r\n throw new Error(`dsh-agent-toolkit: 角色 ${role.id} 工具白名单求交后为空(原 ${role.tools.allow.length} 个均不可见):${role.tools.allow.join(', ')}`)\r\n }\r\n toolFilter = { allow: effective }\r\n }\r\n const request: SubagentStartRequest = {\r\n label: `role:${role.id}: ${args.description}`,\r\n prompt: [{ type: 'text', text: args.prompt } as ContentBlock],\r\n parent,\r\n persona,\r\n maxDepth: 1, // 禁止套娃:成员(深度 1)再委派时 childDepth 2 > 1,provider 响亮拒绝\r\n signal: exec.signal,\r\n ...role.model !== undefined\r\n ? { agentOptions: { provider: role.model.provider, model: role.model.model } }\r\n : {},\r\n ...toolFilter !== undefined\r\n ? { toolFilter }\r\n : {},\r\n } as SubagentStartRequest\r\n // 路由解析与 spawn driver resolveChildAgentOptions 同源:角色覆盖 ?? 父 options。\r\n // 字段为空串视为未配置;任一缺失整体省略(不猜部署默认——显示错值比不显示更糟)。\r\n const route: DelegateRoute | undefined =\r\n (role.model !== undefined && role.model.provider !== '' && role.model.model !== ''\r\n ? role.model\r\n : undefined)\r\n ?? (typeof parent.options.provider === 'string' && parent.options.provider !== ''\r\n && typeof parent.options.model === 'string' && parent.options.model !== ''\r\n ? { provider: parent.options.provider, model: parent.options.model }\r\n : undefined)\r\n const parentSessionId = String(parent.session.id)\r\n if (route !== undefined) deps.active.set(parentSessionId, role.id, route)\r\n try {\r\n const run = await deps.startRun(deps.provider, request)\r\n if (route !== undefined) {\r\n // 展示向写入失败不阻断委派(域关闭等异常吞掉)。\r\n await deps.recordRoute(String(run.id), route).catch(() => undefined)\r\n }\r\n return await settleForegroundRun(run, role.id, route)\r\n } finally {\r\n if (route !== undefined) deps.active.delete(parentSessionId, role.id)\r\n }\r\n },\r\n })\r\n return tool\r\n}\r\n","/** delegate 模块:注册表驱动的 team_delegate 委派工具 + 函数式团队提示段。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { scopeOf } from '@deepseek-ai/dsh-scope'\r\nimport type { SubagentProvider } from '@deepseek-ai/dsh-subagent'\r\nimport { isTeamVisible, type AgentRecord } from '../agents/store.ts'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport { buildAgentPersona } from '../prompt/persona.ts'\r\nimport type { Rule } from '../prompt/types.ts'\r\nimport { createDelegateTool } from './tool.ts'\r\nimport type { ActiveRoutes, DelegateRoute } from './active.ts'\r\n\r\nexport type { DelegateToolDeps } from './tool.ts'\r\nexport { createDelegateTool } from './tool.ts'\r\n\r\n/** 团队名册段在 prompt 中的位置:紧随内置 subagent 段(116.5)之后。 */\r\nconst TEAM_SECTION_ORDER = 116.6\r\n\r\n/**\r\n * 团队名册段文本:仅当该 agent scope 的可见工具里确有委派工具时渲染,否则空\r\n * (空段渲染时被丢弃)。工具白名单 restrict 只作用于 tools 视图,名册段必须\r\n * 自行按 `tools.get(name, scope)` 联动,否则没勾委派的 bot 提示词仍会出现委派段落。\r\n */\r\nexport function teamSectionText(\r\n toolName: string,\r\n roles: readonly Pick<AgentRecord, 'id' | 'name' | 'description' | 'visibleInTeam'>[],\r\n toolVisible: boolean,\r\n): string {\r\n if (!toolVisible) return ''\r\n const rosterText = roles\r\n .filter(r => r.id !== 'main' && isTeamVisible(r))\r\n .map(r => `${r.id}: ${r.description ?? r.name}`)\r\n .join('\\n')\r\n return `你有一组可委派的成员:用 ${toolName} 把自包含的子任务委派给合适的成员,成员结果会作为工具返回值回到本对话。\\n可用成员:\\n${rosterText}`\r\n}\r\n\r\nexport interface DelegateConfig {\r\n /** ctx.subagents provider 名(默认 'spawn')。 */\r\n provider: string\r\n /** 模型可见工具名(默认 'team_delegate')。注意:浏览器半委派卡按 'team_delegate' key 注册,改名后卡片不生效(落 generic 兜底)。 */\r\n toolName: string\r\n /** 按模型规则(Task 7 产物)。 */\r\n rules: Rule[]\r\n}\r\n\r\n/** setupDelegate 的存储/在途通道(Task 3 DelegateToolDeps 的两个新字段)。 */\r\nexport interface DelegateChannels {\r\n readonly active: ActiveRoutes\r\n readonly recordRoute: (childSessionId: string, route: DelegateRoute) => Promise<void>\r\n}\r\n\r\n/**\r\n * 挂载 team_delegate 工具与函数式团队提示段。\r\n * provider 能力守卫与生命周期镜像同归档 tool-subagent:persona/depthLimit 缺失响亮报错,\r\n * 工具随 provider 在场与否挂载/摘除。名册来自注册表(main 排除),工具与提示段都经\r\n * 闭包读取 registry,UI 改角色后新会话即生效。\r\n */\r\nexport function setupDelegate(ctx: Context, config: DelegateConfig, registry: AgentRegistry, channels: DelegateChannels): void {\r\n const { provider, toolName } = config\r\n let disposeTool: (() => void) | undefined\r\n let providerFailed = false\r\n const mountTool = (p: SubagentProvider): void => {\r\n const missing: string[] = []\r\n if (!p.capabilities.persona) missing.push('persona')\r\n if (!p.capabilities.depthLimit) missing.push('depthLimit')\r\n if (missing.length > 0) {\r\n throw new Error(\r\n `dsh-agent-toolkit: provider \"${p.name}\" 缺少 team_delegate 委派必需能力 ${missing.join('/')}(固定发送 persona 与 maxDepth:1)——请配置具备 persona 与 depthLimit 能力的 provider(如 spawn/fork)`,\r\n )\r\n }\r\n if (disposeTool === undefined) {\r\n disposeTool = ctx.tools.register(createDelegateTool(toolName, {\r\n roster: () => registry.list(),\r\n provider,\r\n buildPersona: (role: AgentRecord) =>\r\n buildAgentPersona({ rules: config.rules }, role, role.model),\r\n startRun: (pr, request) => ctx.subagents.start(pr, request),\r\n active: channels.active,\r\n recordRoute: channels.recordRoute,\r\n // 父会话真实可见面:scoped schemas = global + 祖先层,与 bot 路径同款手段\r\n // (scopeOf 对未 scoped ctx 返回 undefined,schemas 接受 undefined 为顶层视图——\r\n // channels/agent-setup.ts:41 先例)。\r\n visibleSurface: (agent) => agent.ctx.tools.schemas(scopeOf(agent.ctx)).map((s) => s.name),\r\n warn: (msg) => { ctx.logger.warn(msg) },\r\n }))\r\n }\r\n }\r\n ctx.on('subagent/provider-added', (p) => {\r\n if (p.name !== provider || providerFailed) return\r\n try {\r\n mountTool(p)\r\n } catch (error) {\r\n providerFailed = true\r\n ctx.logger.error(error instanceof Error ? error.message : String(error))\r\n }\r\n })\r\n ctx.on('subagent/provider-removed', (removed) => {\r\n if (removed !== provider) return\r\n providerFailed = false\r\n if (disposeTool !== undefined) {\r\n disposeTool()\r\n disposeTool = undefined\r\n }\r\n })\r\n const present = ctx.subagents.getProvider(provider)\r\n if (present !== undefined) {\r\n mountTool(present)\r\n } else {\r\n ctx.logger.info(`dsh-agent-toolkit: subagent provider \"${provider}\" 尚未注册;team_delegate 将等它出现时挂载`)\r\n }\r\n ctx.systemPrompt.section({\r\n name: 'plugin:dsh-agent-toolkit:team',\r\n order: TEAM_SECTION_ORDER, // 紧随内置 subagent 段(116.5)之后,同归档 agent-team\r\n text: (context) => teamSectionText(\r\n config.toolName,\r\n registry.list(),\r\n // 该 agent scope 的可见工具里确有委派工具才渲染:被白名单 restrict 掉、或\r\n // provider 未挂载(工具没注册)的会话不再出现委派段落(tools.get 对被\r\n // restrict 掉的全局工具返回 absent)。\r\n ctx.tools.get(config.toolName, context.scope) !== undefined,\r\n ),\r\n })\r\n}\r\n","/** 在途委派路由表:运行中委派卡模型 chip 的数据源(进程内,HMR/重启即清空,settle 后由 presentationMeta 兜底)。 */\r\n\r\n/** 一条已解析的委派路由(委派时确定,全程一致)。 */\r\nexport interface DelegateRoute {\r\n readonly provider: string\r\n readonly model: string\r\n}\r\n\r\nexport interface ActiveRoutes {\r\n /** startRun 前写入;同 key 并发委派后写覆盖(纯展示,可接受)。 */\r\n set(parentSessionId: string, roleId: string, route: DelegateRoute): void\r\n /** 端点读取;无条目返回 undefined。 */\r\n get(parentSessionId: string, roleId: string): DelegateRoute | undefined\r\n /** try/finally 删除(startRun 抛错、settle 成功/出错都删)。 */\r\n delete(parentSessionId: string, roleId: string): void\r\n}\r\n\r\nexport function createActiveRoutes(): ActiveRoutes {\r\n const map = new Map<string, DelegateRoute>()\r\n const key = (sessionId: string, roleId: string): string => `${sessionId}:${roleId}`\r\n return {\r\n set: (sessionId, roleId, route) => { map.set(key(sessionId, roleId), route) },\r\n get: (sessionId, roleId) => map.get(key(sessionId, roleId)),\r\n delete: (sessionId, roleId) => { map.delete(key(sessionId, roleId)) },\r\n }\r\n}\r\n","/** 委派路由持久存储域:子会话头部 chip 的数据源(schema 与 domain 布局的单一来源在本文件)。 */\r\nimport { z } from 'zod'\r\nimport { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'\r\n\r\n/** 一条持久化的委派路由记录。at = 写入时间戳(预留清理依据,暂无自动清理)。 */\r\nexport interface DelegationRouteRecord {\r\n provider: string\r\n model: string\r\n at: number\r\n}\r\n\r\nexport const DelegationRouteRecordSchema = z.object({\r\n provider: z.string(),\r\n model: z.string(),\r\n at: z.number(),\r\n})\r\n\r\n// 独立于 agentToolkitDomain(v1 布局不变):domain version 是格式版本,\r\n// 改既有域表结构会 version-mismatch 拒绝存量介质且无迁移。\r\nexport const delegationRoutesDomain = defineDomain({\r\n name: 'dsh_agent_toolkit_routes',\r\n version: 1,\r\n tables: {\r\n // key = childSessionId(本地 run 的 run.id 契约上即子 session id)\r\n routes: domainTable<string, DelegationRouteRecord>(DelegationRouteRecordSchema),\r\n },\r\n})\r\n","/** delegate RPC 端点:在途委派路由(运行中委派卡)+ 持久委派路由(子会话头部 chip)。 */\r\nimport type { IncomingMessage, ServerResponse } from 'node:http'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { json } from '../shared/http.ts'\r\nimport { registerOptionalRoutes } from '../shared/webserver.ts'\r\nimport type { ActiveRoutes } from './active.ts'\r\nimport type { DelegationRouteRecord } from './routes.ts'\r\n\r\nexport interface DelegateApiDeps {\r\n readonly active: ActiveRoutes\r\n /** 持久路由表读面(KvTable.get 同步读)。 */\r\n readonly routes: { get(childSessionId: string): DelegationRouteRecord | undefined }\r\n}\r\n\r\nexport function createDelegateApiHandler(deps: DelegateApiDeps): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\r\n return async (req, res) => {\r\n const url = new URL(req.url ?? '/', 'http://127.0.0.1')\r\n const sub = url.pathname.replace(/^\\/dsh-agent-toolkit\\/api/, '') || '/'\r\n if (req.method !== 'GET') {\r\n json(res, 405, { error: 'method not allowed' })\r\n return\r\n }\r\n if (sub === '/delegate/active') {\r\n const route = deps.active.get(url.searchParams.get('session') ?? '', url.searchParams.get('role') ?? '')\r\n if (route === undefined) {\r\n json(res, 404, { error: 'not found' })\r\n return\r\n }\r\n json(res, 200, { provider: route.provider, model: route.model })\r\n return\r\n }\r\n if (sub === '/delegate/route') {\r\n const record = deps.routes.get(url.searchParams.get('session') ?? '')\r\n if (record === undefined) {\r\n json(res, 404, { error: 'not found' })\r\n return\r\n }\r\n json(res, 200, { provider: record.provider, model: record.model })\r\n return\r\n }\r\n json(res, 404, { error: 'not found' })\r\n }\r\n}\r\n\r\n/**\r\n * 注册 delegate 路由(恒启用,与 agents 同策略)。webServer 为可选服务:\r\n * 缺席时经 registerOptionalRoutes 惰性不注册。prefix 先于 /api 兜底前缀命中。\r\n */\r\nexport function setupDelegateApi(ctx: Context, deps: DelegateApiDeps): void {\r\n const handler = createDelegateApiHandler(deps)\r\n registerOptionalRoutes(ctx, (webCtx) => {\r\n const unregister = webCtx.webServer.register({ kind: 'prefix', path: '/dsh-agent-toolkit/api/delegate', handler })\r\n return () => unregister()\r\n })\r\n}\r\n","/** Agents RPC 端点组:注册表 CRUD + providers/models 级联 + 工具名列表。核心恒启用(不随 feishu 门控)。 */\r\nimport type { IncomingMessage, ServerResponse } from 'node:http'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { json, readJsonBody } from '../shared/http.ts'\r\nimport { registerOptionalRoutes } from '../shared/webserver.ts'\r\nimport { AgentRecordSchema } from './store.ts'\r\nimport type { AgentRegistry } from './registry.ts'\r\n\r\n/** 一个可选的 provider 路由(id = agentOptions.provider 的值)。 */\r\nexport interface ProviderOption { id: string; name: string }\r\n/** 一个可选的模型条目(id = agentOptions.model 的值)。 */\r\nexport interface ModelOption { id: string; name: string }\r\n\r\nexport interface AgentsApiDeps {\r\n registry: AgentRegistry\r\n listTools(): string[]\r\n /** 团队 preset 工具面(tool-catalog 动态枚举,含回退)。 */\r\n listPresetTools(): Promise<string[]>\r\n listProviders(): ProviderOption[]\r\n /** 失败由调用方(路由)兜底为空数组,不抛错。 */\r\n listModels(provider: string): Promise<ModelOption[]>\r\n}\r\n\r\nexport function createAgentsApiHandler(deps: AgentsApiDeps): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\r\n return async (req, res) => {\r\n const url = new URL(req.url ?? '/', 'http://127.0.0.1')\r\n const sub = url.pathname.replace(/^\\/dsh-agent-toolkit\\/api/, '') || '/'\r\n const method = req.method ?? 'GET'\r\n\r\n if (sub === '/agents' && method === 'GET') {\r\n json(res, 200, deps.registry.list())\r\n return\r\n }\r\n\r\n if (sub === '/tools' && method === 'GET') {\r\n // 分组名册:preset = agent-team standing 面动态枚举(缺席回退常量),global = 顶层注册表。\r\n json(res, 200, { preset: await deps.listPresetTools(), global: deps.listTools() })\r\n return\r\n }\r\n\r\n if (sub === '/providers' && method === 'GET') {\r\n json(res, 200, deps.listProviders())\r\n return\r\n }\r\n\r\n const modelsMatch = /^\\/providers\\/([^/]+)\\/models$/.exec(sub)\r\n if (modelsMatch !== null && method === 'GET') {\r\n // 模型列举可能走网络(adapter 探测),失败静默降级为空数组。\r\n let models: ModelOption[] = []\r\n try {\r\n models = await deps.listModels(decodeURIComponent(modelsMatch[1]))\r\n } catch {\r\n models = []\r\n }\r\n json(res, 200, models)\r\n return\r\n }\r\n\r\n const agentMatch = /^\\/agents\\/([^/]+)$/.exec(sub)\r\n if (agentMatch !== null) {\r\n const id = decodeURIComponent(agentMatch[1])\r\n\r\n if (method === 'PUT') {\r\n const body = await readJsonBody(req, res)\r\n if (body === undefined) return\r\n // builtin 是服务端保留字段:剥离客户端携带值(防经 PUT 自创不可删记录),\r\n // id 以资源路径为准(覆盖 body.id),保证一致性。\r\n const bodyRecord: Record<string, unknown> = { ...(body as Record<string, unknown>) }\r\n delete bodyRecord.builtin\r\n const candidate: Record<string, unknown> = { ...bodyRecord, id }\r\n // 服务端保留字段回填:builtin 由既有记录决定(客户端不携带),否则 registry 的\r\n // \"内置标记不可修改\" 守卫会让所有内置角色/主 Agent 的配置编辑必然 409。\r\n const existing = deps.registry.get(id)\r\n if (existing?.builtin === true) candidate.builtin = true\r\n const parsed = AgentRecordSchema.safeParse(candidate)\r\n if (!parsed.success) {\r\n json(res, 400, { error: parsed.error.issues[0]?.message ?? 'invalid agent record' })\r\n return\r\n }\r\n try {\r\n await deps.registry.upsert(parsed.data)\r\n } catch (error) {\r\n json(res, 409, { error: error instanceof Error ? error.message : String(error) })\r\n return\r\n }\r\n json(res, 200, { ok: true })\r\n return\r\n }\r\n\r\n if (method === 'DELETE') {\r\n if (deps.registry.get(id) === undefined) {\r\n json(res, 404, { error: `agent \"${id}\" 不存在` })\r\n return\r\n }\r\n try {\r\n await deps.registry.remove(id)\r\n } catch (error) {\r\n json(res, 409, { error: error instanceof Error ? error.message : String(error) })\r\n return\r\n }\r\n json(res, 200, { ok: true })\r\n return\r\n }\r\n\r\n json(res, 405, { error: 'method not allowed' })\r\n return\r\n }\r\n\r\n if (['/agents', '/providers', '/tools'].some((p) => sub === p || sub.startsWith(`${p}/`))) {\r\n json(res, 405, { error: 'method not allowed' })\r\n return\r\n }\r\n json(res, 404, { error: 'not found' })\r\n }\r\n}\r\n\r\n/**\r\n * 注册 agents 核心 RPC 路由(恒启用,不随 modules.feishu 门控——Agents 面板总是挂载,\r\n * 这些端点缺失即「加载失败」)。webServer 为可选服务:缺席时经 registerOptionalRoutes\r\n * 惰性不注册。挂载点与 bots 同处 /dsh-agent-toolkit/api 前缀,但按路径空间拆成独立\r\n * prefix/exact 条目(webServer 精确先于最长前缀),互不重叠:\r\n * - prefix /dsh-agent-toolkit/api/agents → /agents 与 /agents/:id\r\n * - prefix /dsh-agent-toolkit/api/providers → /providers 与 /providers/:p/models\r\n * - exact /dsh-agent-toolkit/api/tools\r\n * - prefix /dsh-agent-toolkit/api → 兜底:api 前缀下未被更具体路由(bots/usage)\r\n * 认领的未知路径仍回 404 JSON(与旧统一分发行为字节一致)。\r\n */\r\nexport function setupAgentsApi(ctx: Context, deps: AgentsApiDeps): void {\r\n const handler = createAgentsApiHandler(deps)\r\n registerOptionalRoutes(ctx, (webCtx) => {\r\n const dispose = [\r\n webCtx.webServer.register({ kind: 'prefix', path: '/dsh-agent-toolkit/api/agents', handler }),\r\n webCtx.webServer.register({ kind: 'prefix', path: '/dsh-agent-toolkit/api/providers', handler }),\r\n webCtx.webServer.register({ kind: 'exact', path: '/dsh-agent-toolkit/api/tools', handler }),\r\n webCtx.webServer.register({ kind: 'prefix', path: '/dsh-agent-toolkit/api', handler }),\r\n ]\r\n return () => dispose.forEach((unregister) => unregister())\r\n })\r\n}\r\n","/**\r\n * /create-agent 命令:返回引导文本驱动主 Agent 完成\r\n * 「访谈澄清 → 推荐配置 → 用户确认 → 复用面板 HTTP API 落库」全流程。\r\n * 设计:docs/superpowers/specs/2026-09-02-create-agent-command-design.md\r\n */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { createUserMessage } from '@deepseek-ai/dsh-llm'\r\nimport type { AgentRegistry } from './registry.ts'\r\n\r\n/** buildCreateAgentGuidance 的输入。 */\r\nexport interface CreateAgentGuidanceInput {\r\n /** 命令行内联需求(已 trim,可空串)。 */\r\n requirement: string\r\n /** 现有 Agent id 列表(含 main),不可复用。 */\r\n agentIds: string[]\r\n /** 团队 preset 工具名(动态名册)。 */\r\n presetTools: string[]\r\n /** 顶层注册表全局工具名。 */\r\n globalTools: string[]\r\n /** web 宿主回环 origin(如 http://127.0.0.1:3080);undefined = headless/CLI 降级。 */\r\n origin: string | undefined\r\n}\r\n\r\n/** 拼装 /create-agent 的引导文本(模型面契约,文案为规格锁定内容)。 */\r\nexport function buildCreateAgentGuidance(input: CreateAgentGuidanceInput): string {\r\n const lines: string[] = [\r\n '# 交互式创建 Agent 团队成员',\r\n '',\r\n '## 工作流(三步)',\r\n '1. 澄清需求:需求不明确时用 ask_user_question 向用户提问,整个流程提问总次数不超过 5 次,不重复问已确认的信息;',\r\n '2. 生成推荐并请用户确认:推荐 id / name / description / persona / tools 五个字段(id 是团队内唯一标识,name 是显示名,description 是职责一句话描述,persona 是系统提示词个性段,tools 是工具白名单);',\r\n '3. 迭代:用户有修改意见时按意见修订名称、描述、个性和工具后再次确认,直到用户明确确认。',\r\n ]\r\n if (input.requirement !== '') {\r\n lines.push(\r\n '',\r\n '## 用户初始需求',\r\n `用户已在命令中提供初始需求:「${input.requirement}」。请据此减少提问轮次,仅就不明确的点提问。`,\r\n )\r\n }\r\n lines.push(\r\n '',\r\n '## 现有 Agent id(不可复用)',\r\n input.agentIds.join(', '),\r\n 'id 规则:小写字母开头,仅含小写字母/数字/连字符([a-z0-9-]),最长 32 字符。',\r\n '',\r\n '## 可用工具清单',\r\n `团队 preset 工具:${input.presetTools.join(', ')}`,\r\n `全局工具:${input.globalTools.join(', ')}`,\r\n '省略 tools 字段表示不限制(Agent 可使用全部工具)。一旦给出白名单,该 Agent 只有列出的工具可用:通常应保留 read/glob/grep/shell 等基础工具,否则失去读文件/搜索/执行命令等基本能力(最终取舍按需求判断,如只读角色可去掉 write/edit)。',\r\n )\r\n if (input.origin === undefined) {\r\n lines.push(\r\n '',\r\n '## 落库',\r\n '当前宿主无 web 服务,无法自动落库。用户确认推荐后,请把最终配置完整输出给用户,并提示其打开 Agents 面板按推荐内容手动创建。',\r\n )\r\n } else {\r\n lines.push(\r\n '',\r\n '## 落库(用户明确确认后执行)',\r\n '用你的 shell 工具调用 Agents 面板同一 HTTP 端点完成创建:',\r\n `1. 先 GET ${input.origin}/dsh-agent-toolkit/api/agents 复核所选 id 仍未被占用;`,\r\n `2. 再 PUT ${input.origin}/dsh-agent-toolkit/api/agents/<id>,请求体为 JSON(不要在 body 中携带 id 或 builtin 字段):`,\r\n ' {\"name\":\"...\",\"description\":\"...\",\"persona\":\"...\",\"tools\":{\"allow\":[\"...\"]}}',\r\n ' (description/persona/tools 均可省略;省略 tools 表示不限制)',\r\n '3. curl 示例(Windows 的 pwsh 里用 curl.exe):',\r\n ` curl.exe -s -X PUT \"${input.origin}/dsh-agent-toolkit/api/agents/<id>\" -H \"Content-Type: application/json\" -d \"{\\\\\"name\\\\\":\\\\\"...\\\\\"}\"`,\r\n `4. 返回 200 后必须再 GET ${input.origin}/dsh-agent-toolkit/api/agents,在返回列表中找到该 id 的记录,把它的 name/description/persona/tools 关键字段展示给用户,作为落库证据;`,\r\n '5. 落库成功后告知用户可在 Agents 面板查看、并可被 team_delegate 委派;任一步返回 4xx 则把错误信息展示给用户,修正后重试。',\r\n )\r\n }\r\n return lines.join('\\n')\r\n}\r\n\r\n/** setupCreateAgentCommand 的依赖。 */\r\nexport interface CreateAgentCommandDeps {\r\n registry: AgentRegistry\r\n listTools(): string[]\r\n listPresetTools(): Promise<string[]>\r\n}\r\n\r\n/**\r\n * 注册 /create-agent。webServer 为可选服务按仓库规则经 ctx.get 读取(不进 inject),\r\n * 缺席(headless/CLI)时 origin 为 undefined,引导文本落库节降级为手动创建指引。\r\n *\r\n * 命令结果(command/done)是 log-only、不进模型:引导文本必须经 agent.followup\r\n * 投递为 user 消息驱动主 Agent(与 channels/inbound.ts 同一机制),命令卡只回执短文案。\r\n */\r\nexport function setupCreateAgentCommand(ctx: Context, deps: CreateAgentCommandDeps): void {\r\n ctx.commands.register({\r\n name: 'create-agent',\r\n description: '交互式创建 Agent 团队成员:访谈澄清需求 → 推荐配置 → 确认后经面板 API 落库',\r\n input: { hint: '初始需求描述,可空' },\r\n handler: async ({ rawInput, agent }: { rawInput: string; agent: { followup(message: unknown): void } }) => {\r\n const webServer = ctx.get('webServer') as { port: number } | undefined\r\n const origin = webServer === undefined ? undefined : `http://127.0.0.1:${webServer.port}`\r\n const text = buildCreateAgentGuidance({\r\n requirement: rawInput.trim(),\r\n agentIds: deps.registry.list().map((agent) => agent.id),\r\n presetTools: await deps.listPresetTools(),\r\n globalTools: deps.listTools(),\r\n origin,\r\n })\r\n // source 用 kind 'user'(与 ACP/inbound 先例一致):命令由用户敲入,引导消息即用户发起。\r\n agent.followup(createUserMessage({\r\n content: [{ type: 'text', text }],\r\n source: { kind: 'user' },\r\n }))\r\n return { kind: 'success', text: '已向主 Agent 发出创建 Agent 引导,请继续对话完成访谈与确认。' }\r\n },\r\n })\r\n}\r\n","/** agent 创建/恢复的作用域组合:加入作用域组合(preset 或基础工具 standing scope 回退)→ persona/tools 创作期注入。\r\n * hooks.tools 先与该会话真实可见面求交(warn-drop 未知名)——同一白名单同时喂委派 toolFilter(父 preset 面)\r\n * 与 bot 会话(agent-bot 面),求交消除两条路径的有效性不对称。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\n// type-only 激活 dsh-system-prompt / dsh-tools 对 cordis Context 的声明合并(agentCtx.systemPrompt / agentCtx.tools)。\r\nimport type {} from '@deepseek-ai/dsh-system-prompt'\r\nimport type {} from '@deepseek-ai/dsh-tools'\r\nimport { scopeOf } from '@deepseek-ai/dsh-scope'\r\nimport { RUN_CODE_NAME } from '@deepseek-ai/dsh-tools'\r\nimport type { AgentHooks } from './ports.ts'\r\nimport type { ScopeJoiner } from './scope-joiner.ts'\r\n\r\n/** bot 会话角色 persona 的 scoped 段名:与全局 persona 层同名,scoped 注册即 shadow 覆盖主 Agent persona。 */\r\nexport const TOOLKIT_PERSONA_SECTION = 'prompt-stack:persona'\r\n\r\n/**\r\n * 组合 agent 作用域:先把 agent scope 父链挂到基础工具行 standing scope(工具成为\r\n * 继承面),再叠 bot 的 persona 与 tools 白名单。\r\n * 顺序敏感:restrict 必须在 join 之后——宿主 tools.restrict() 只校验并过滤继承面\r\n * (global + 祖先 scope 层),own 层(agentCtx 直接挂载)的名字既不可 restrict 也\r\n * 不受 restrict 影响,直接挂进 agentCtx 的白名单会抛 unknown global tools。\r\n */\r\nexport async function setupAgentScope(\r\n agentCtx: Context,\r\n hooks: AgentHooks,\r\n joiner: ScopeJoiner,\r\n): Promise<void> {\r\n await joiner.join(agentCtx)\r\n if (hooks.persona !== undefined) {\r\n agentCtx.systemPrompt.section({ name: TOOLKIT_PERSONA_SECTION, order: 10, text: hooks.persona })\r\n }\r\n if (hooks.sections !== undefined) {\r\n for (const section of hooks.sections) {\r\n agentCtx.systemPrompt.section({ name: section.name, order: section.order, text: section.text })\r\n }\r\n }\r\n if (hooks.tools !== undefined) {\r\n // 求交:join 后的 scoped schemas = global + 祖先层(preset standing 或 BASIC_TOOLS\r\n // fallback standing),正是 restrict 的合法命名空间;未知名 warn-drop 而非抛错,\r\n // 使同一角色白名单在委派(父 preset 面)与 bot(agent-bot 面)两条路径都安全。\r\n const visible = new Set(agentCtx.tools.schemas(scopeOf(agentCtx)).map((s) => s.name)\r\n .filter((n) => n !== RUN_CODE_NAME))\r\n const effective = hooks.tools.filter((n) => visible.has(n))\r\n const dropped = hooks.tools.filter((n) => !visible.has(n))\r\n if (dropped.length > 0) {\r\n agentCtx.logger.warn(`dsh-agent-toolkit: 工具白名单含本会话不可见工具,已忽略:${dropped.join(', ')}`)\r\n }\r\n if (effective.length === 0) {\r\n throw new Error(`dsh-agent-toolkit: 工具白名单求交后为空(原 ${hooks.tools.length} 个均不可见):${hooks.tools.join(', ')}`)\r\n }\r\n agentCtx.tools.restrict({ allow: effective })\r\n }\r\n}\r\n","/** AgentsPort 真实适配器工厂(bots Router 与 schedule 执行器共用):create/resume 经 setupAgentScope 装配,\r\n * sessionId 记入 ownedSessions(插件自有会话集合,cron_* 工具注册门控据此排除 bot/schedule 会话)。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { SessionId } from '@deepseek-ai/dsh-session'\r\nimport type { AgentHandle } from '@deepseek-ai/dsh-agent'\r\nimport { setupAgentScope } from './agent-setup.ts'\r\nimport type { AgentPort, AgentsPort } from './ports.ts'\r\nimport type { ScopeJoiner } from './scope-joiner.ts'\r\n\r\nexport function createAgentsPort(ctx: Context, joiner: ScopeJoiner, ownedSessions?: Set<string>): AgentsPort {\r\n function adaptAgent(handle: AgentHandle): AgentPort {\r\n const { agent } = handle\r\n return {\r\n sessionId: String(agent.id),\r\n followup: (message) => agent.followup(message as Parameters<typeof agent.followup>[0]),\r\n cancel: () => agent.cancel({ kind: 'user' }),\r\n whenIdle: () => agent.whenIdle(),\r\n }\r\n }\r\n return {\r\n async create(input) {\r\n ownedSessions?.add(input.sessionId)\r\n const handle: AgentHandle = await ctx.agents.create({\r\n sessionId: SessionId(input.sessionId),\r\n meta: { cwd: input.cwd },\r\n ...(input.agentOptions !== undefined ? { agentOptions: input.agentOptions } : {}),\r\n setup: (agentCtx) => setupAgentScope(agentCtx, input.hooks, joiner),\r\n })\r\n return adaptAgent(handle)\r\n },\r\n async resume(input) {\r\n ownedSessions?.add(input.sessionId)\r\n const handle: AgentHandle = await ctx.agents.resume({\r\n resumeSessionId: SessionId(input.sessionId),\r\n ...(input.agentOptions !== undefined ? { agentOptions: input.agentOptions } : {}),\r\n setup: (agentCtx) => setupAgentScope(agentCtx, input.hooks, joiner),\r\n })\r\n return adaptAgent(handle)\r\n },\r\n }\r\n}\r\n","/** 飞书 OpenAPI 的结构化端口:reply/channel 只依赖本接口,SDK 类型不外泄。 */\r\nimport type * as lark from '@larksuiteoapi/node-sdk'\r\nimport type { InboundImage } from '../channel.ts'\r\n\r\nexport interface FeishuApi {\r\n createCard(cardJson: string): Promise<string>\r\n sendCardMessage(chatId: string, cardId: string): Promise<void>\r\n updateCardElement(cardId: string, elementId: string, content: string, sequence: number): Promise<void>\r\n insertElement(cardId: string, elementJson: string, targetElementId: string, sequence: number): Promise<void>\r\n setCardStreaming(cardId: string, streaming: boolean, sequence: number, summary?: string): Promise<void>\r\n replaceCard(cardId: string, cardJson: string, sequence: number): Promise<void>\r\n sendText(chatId: string, text: string): Promise<void>\r\n addReaction(messageId: string, emojiType: string): Promise<string>\r\n removeReaction(messageId: string, reactionId: string): Promise<void>\r\n /** 下载消息内图片资源(im/v1 resources,type=image);媒体类型按魔数判定、响应头兜底。 */\r\n downloadImage(messageId: string, fileKey: string): Promise<InboundImage>\r\n /** 本机器人的 open_id(bot/v3/info);群消息 @ 身份校验用。 */\r\n getBotOpenId(): Promise<string>\r\n}\r\n\r\n/** 从 lark SDK 抛出的 axios 错误提取飞书业务错误码(无则 undefined)。 */\r\nexport function feishuErrorCode(error: unknown): number | undefined {\r\n const data = (error as { response?: { data?: unknown } } | null | undefined)?.response?.data\r\n if (typeof data !== 'object' || data === null) return undefined\r\n const code = (data as { code?: unknown }).code\r\n return typeof code === 'number' ? code : undefined\r\n}\r\n\r\n/** 附件服务接受的图片媒体类型(与宿主 attachment v1 一致)。 */\r\nconst IMAGE_MEDIA_TYPES = ['image/png', 'image/jpeg', 'image/webp', 'image/gif'] as const\r\nexport type SniffedImageMediaType = (typeof IMAGE_MEDIA_TYPES)[number]\r\n\r\n/** 按魔数判定图片媒体类型;未知字节时回退响应头 content-type(限接受集合),否则 undefined。 */\r\nexport function sniffImageMediaType(data: Uint8Array, contentType?: unknown): SniffedImageMediaType | undefined {\r\n if (data.length >= 4 && data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4e && data[3] === 0x47) return 'image/png'\r\n if (data.length >= 3 && data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff) return 'image/jpeg'\r\n if (data.length >= 4 && data[0] === 0x47 && data[1] === 0x49 && data[2] === 0x46 && data[3] === 0x38) return 'image/gif'\r\n if (data.length >= 12\r\n && data[0] === 0x52 && data[1] === 0x49 && data[2] === 0x46 && data[3] === 0x46\r\n && data[8] === 0x57 && data[9] === 0x45 && data[10] === 0x42 && data[11] === 0x50) return 'image/webp'\r\n const declared = typeof contentType === 'string' ? contentType.split(';')[0]!.trim().toLowerCase() : ''\r\n return (IMAGE_MEDIA_TYPES as readonly string[]).includes(declared)\r\n ? declared as SniffedImageMediaType\r\n : undefined\r\n}\r\n\r\n/** SDK 薄封装:tenant_access_token 由 SDK 自动管理;错误带 code/msg 上下文。 */\r\nexport function createFeishuApi(client: lark.Client): FeishuApi {\r\n return {\r\n async createCard(cardJson) {\r\n const res = await client.cardkit.v1.card.create({ data: { type: 'card_json', data: cardJson } })\r\n const cardId = res.data?.card_id\r\n if (typeof cardId !== 'string' || cardId.length === 0) {\r\n throw new Error(`cardkit 建卡失败:code=${res.code} msg=${res.msg}`)\r\n }\r\n return cardId\r\n },\r\n async sendCardMessage(chatId, cardId) {\r\n await client.im.message.create({\r\n params: { receive_id_type: 'chat_id' },\r\n data: { receive_id: chatId, msg_type: 'interactive', content: JSON.stringify({ type: 'card', data: { card_id: cardId } }) },\r\n })\r\n },\r\n async updateCardElement(cardId, elementId, content, sequence) {\r\n await client.cardkit.v1.cardElement.content({ path: { card_id: cardId, element_id: elementId }, data: { content, sequence } })\r\n },\r\n async insertElement(cardId, elementJson, targetElementId, sequence) {\r\n await client.cardkit.v1.cardElement.create({\r\n path: { card_id: cardId },\r\n data: { type: 'insert_before', target_element_id: targetElementId, elements: `[${elementJson}]`, sequence },\r\n })\r\n },\r\n async setCardStreaming(cardId, streaming, sequence, summary) {\r\n await client.cardkit.v1.card.settings({\r\n path: { card_id: cardId },\r\n data: {\r\n settings: JSON.stringify({\r\n config: {\r\n streaming_mode: streaming,\r\n ...(summary !== undefined ? { summary: { content: summary } } : {}),\r\n },\r\n }),\r\n sequence,\r\n },\r\n })\r\n },\r\n async replaceCard(cardId, cardJson, sequence) {\r\n await client.cardkit.v1.card.update({ path: { card_id: cardId }, data: { card: { type: 'card_json', data: cardJson }, sequence } })\r\n },\r\n async sendText(chatId, text) {\r\n await client.im.message.create({\r\n params: { receive_id_type: 'chat_id' },\r\n data: { receive_id: chatId, msg_type: 'text', content: JSON.stringify({ text }) },\r\n })\r\n },\r\n async addReaction(messageId, emojiType) {\r\n const res = await client.im.messageReaction.create({\r\n path: { message_id: messageId },\r\n data: { reaction_type: { emoji_type: emojiType } },\r\n })\r\n const reactionId = res.data?.reaction_id\r\n if (typeof reactionId !== 'string') throw new Error(`加表情失败:code=${res.code} msg=${res.msg}`)\r\n return reactionId\r\n },\r\n async removeReaction(messageId, reactionId) {\r\n await client.im.messageReaction.delete({ path: { message_id: messageId, reaction_id: reactionId } })\r\n },\r\n async downloadImage(messageId, fileKey) {\r\n const res = await client.im.messageResource.get({\r\n params: { type: 'image' },\r\n path: { message_id: messageId, file_key: fileKey },\r\n })\r\n const chunks: Buffer[] = []\r\n await new Promise<void>((resolve, reject) => {\r\n const stream = res.getReadableStream()\r\n stream.on('data', (chunk) => { chunks.push(chunk as Buffer) })\r\n stream.on('end', () => resolve())\r\n stream.on('error', (error) => reject(error instanceof Error ? error : new Error(String(error))))\r\n })\r\n const data = new Uint8Array(Buffer.concat(chunks))\r\n const mediaType = sniffImageMediaType(data, res.headers?.['content-type'])\r\n if (mediaType === undefined) {\r\n throw new Error(`图片资源格式不受支持(file_key=${fileKey},content-type=${String(res.headers?.['content-type'] ?? '未知')})`)\r\n }\r\n return { data, mediaType }\r\n },\r\n async getBotOpenId() {\r\n // bot/v3/info 无 SDK 类型化方法,走通用 request;响应顶层挂 bot(非 data.bot)。\r\n const res = await client.request<{ code?: number; msg?: string; bot?: { open_id?: unknown } }>({\r\n method: 'GET',\r\n url: 'https://open.feishu.cn/open-apis/bot/v3/info',\r\n })\r\n const openId = res.bot?.open_id\r\n if (typeof openId !== 'string' || openId.length === 0) {\r\n throw new Error(`获取机器人信息失败:code=${res.code} msg=${res.msg}`)\r\n }\r\n return openId\r\n },\r\n }\r\n}\r\n","/** 飞书内的运维文本指令(不走模型)。 */\r\nexport type Directive = 'new' | 'stop' | 'status'\r\n\r\n/** 仅当整条消息就是一个指令时命中;带参数/前后文的按普通消息处理。 */\r\nexport function parseDirective(text: string): Directive | null {\r\n const t = text.trim().toLowerCase()\r\n if (t === '/new') return 'new'\r\n if (t === '/stop') return 'stop'\r\n if (t === '/status') return 'status'\r\n return null\r\n}\r\n\r\n/** 群消息正文中的 @ 占位符(@_user_1 等)剥掉,得到纯净指令文本。 */\r\nexport function stripMentionPlaceholders(text: string): string {\r\n return text.replace(/@_user_\\d+\\s*/g, '').trim()\r\n}\r\n","/** im.message.receive_v1 事件解析:窄化为渠道无关的 ParsedMessage;message_id 去重。 */\r\nimport { stripMentionPlaceholders } from '../directive.ts'\r\n\r\nexport interface ParsedMessage {\r\n messageId: string\r\n chatId: string\r\n chatType: 'p2p' | 'group'\r\n userId: string\r\n text: string\r\n /** 消息携带的图片 key(post 富文本节点与 image 消息),按出现顺序;文本下载经渠道懒加载。 */\r\n imageKeys: readonly string[]\r\n}\r\n\r\ninterface RawEvent {\r\n sender?: { sender_type?: unknown; sender_id?: { open_id?: unknown } }\r\n message?: {\r\n message_id?: unknown\r\n chat_id?: unknown\r\n chat_type?: unknown\r\n message_type?: unknown\r\n content?: unknown\r\n mentions?: readonly { mentioned_type?: unknown; id?: { open_id?: unknown } }[]\r\n }\r\n}\r\n\r\n/** post 富文本节点:text/a 取文本,img 收 image_key,at(@占位)与其余标签跳过。 */\r\ninterface PostNode {\r\n tag?: unknown\r\n text?: unknown\r\n image_key?: unknown\r\n}\r\n\r\n/** 从 post content(段落数组)抽取文本与图片 key;段落间以换行连接。 */\r\nfunction parsePostContent(content: string): { text: string; imageKeys: string[] } {\r\n const imageKeys: string[] = []\r\n const paragraphs: string[] = []\r\n try {\r\n const parsed = JSON.parse(content) as { content?: unknown }\r\n const list = Array.isArray(parsed.content) ? parsed.content : []\r\n for (const paragraph of list) {\r\n if (!Array.isArray(paragraph)) continue\r\n const parts: string[] = []\r\n for (const node of paragraph as PostNode[]) {\r\n if (node === null || typeof node !== 'object') continue\r\n if (node.tag === 'img') {\r\n if (typeof node.image_key === 'string' && node.image_key.length > 0) imageKeys.push(node.image_key)\r\n } else if ((node.tag === 'text' || node.tag === 'a') && typeof node.text === 'string') {\r\n parts.push(node.text)\r\n }\r\n }\r\n paragraphs.push(parts.join(''))\r\n }\r\n } catch {\r\n return { text: '', imageKeys: [] }\r\n }\r\n return { text: paragraphs.join('\\n'), imageKeys }\r\n}\r\n\r\n/**\r\n * SDK handler 收到的 data 即事件体(README 示例 `data.message` 直接解构);\r\n * 兼容包一层 { event } 的形态。过滤:机器人消息、非 text/post/image 类型、\r\n * 群内未 @机器人、无文本且无图片。\r\n * 群消息 @ 校验身份:mention 的 open_id 必须等于本机器人(应用若持全部群消息权限,\r\n * 会收到 @ 其他机器人的消息,不能误触发)。\r\n */\r\nexport function parseMessageEvent(data: unknown, botOpenId: string): ParsedMessage | null {\r\n const wrapped = data as { event?: RawEvent } & RawEvent\r\n const event: RawEvent = wrapped.event ?? wrapped\r\n if (event.sender?.sender_type !== 'user') return null\r\n const userId = event.sender.sender_id?.open_id\r\n const msg = event.message\r\n if (typeof userId !== 'string' || msg === undefined) return null\r\n if (msg.message_type !== 'text' && msg.message_type !== 'post' && msg.message_type !== 'image') return null\r\n if (typeof msg.content !== 'string') return null\r\n if (typeof msg.message_id !== 'string' || typeof msg.chat_id !== 'string') return null\r\n if (msg.chat_type !== 'p2p' && msg.chat_type !== 'group') return null\r\n if (msg.chat_type === 'group'\r\n && !(msg.mentions ?? []).some((m) => m.mentioned_type === 'bot' && m.id?.open_id === botOpenId)) return null\r\n\r\n let text = ''\r\n let imageKeys: string[] = []\r\n if (msg.message_type === 'text') {\r\n try {\r\n const parsed = JSON.parse(msg.content) as { text?: unknown }\r\n if (typeof parsed.text !== 'string') return null\r\n text = stripMentionPlaceholders(parsed.text)\r\n } catch {\r\n return null\r\n }\r\n } else if (msg.message_type === 'post') {\r\n const post = parsePostContent(msg.content)\r\n text = stripMentionPlaceholders(post.text)\r\n imageKeys = post.imageKeys\r\n } else {\r\n try {\r\n const parsed = JSON.parse(msg.content) as { image_key?: unknown }\r\n if (typeof parsed.image_key === 'string' && parsed.image_key.length > 0) imageKeys.push(parsed.image_key)\r\n } catch {\r\n return null\r\n }\r\n }\r\n if (text.length === 0 && imageKeys.length === 0) return null\r\n\r\n return { messageId: msg.message_id, chatId: msg.chat_id, chatType: msg.chat_type, userId, text, imageKeys }\r\n}\r\n\r\n/** message_id 去重(飞书会重推);FIFO 容量淘汰。 */\r\nexport class MessageDedup {\r\n private readonly seen = new Set<string>()\r\n private readonly order: string[] = []\r\n\r\n constructor(private readonly cap = 1000) {}\r\n\r\n /** true = 新消息。 */\r\n check(id: string): boolean {\r\n if (this.seen.has(id)) return false\r\n this.seen.add(id)\r\n this.order.push(id)\r\n if (this.order.length > this.cap) this.seen.delete(this.order.shift()!)\r\n return true\r\n }\r\n}\r\n","/** 飞书卡片纯函数:JSON 2.0 构建、UTF-8 字节切分、段序列流式操作规划(拆卡决策全在这里)。 */\r\nimport type { TurnSegment, TurnStatus } from '../channel.ts'\r\n\r\nexport type { TurnSegment }\r\n\r\nexport const STATUS_ELEMENT_ID = 'status'\r\n\r\n/** create 未返回真实 card_id 前的占位哨兵(executor 赋值;防并发 flush 重复建卡)。 */\r\nexport const PENDING_CARD_ID = '__pending__'\r\n\r\n/** 过程区截尾后的头部省略标记。 */\r\nexport const PROCESS_OMITTED = '…(已省略前文)\\n'\r\n\r\n/** 输出中状态行文案。 */\r\nconst STATUS_STREAMING = '⏳ 输出中…'\r\n\r\n/** 定格状态行文案。 */\r\nconst STATUS_FINAL: Record<TurnStatus, string> = {\r\n done: '✅ 输出完成',\r\n error: '❌ 输出出错',\r\n cancelled: '⏹ 已取消',\r\n}\r\n\r\n/** 拆卡定格状态行文案(旧卡内容已接续到下一张卡片)。 */\r\nexport const STATUS_CONTINUED = '📦 内容较长,已接续到下一张卡片'\r\n\r\n/** 单卡组件数安全上限(飞书硬上限 200;面板按 2 计:面板 + 内嵌 markdown)。 */\r\nconst CARD_ELEMENT_LIMIT = 190\r\n\r\n/** 按 UTF-8 字节上限截头(保留头部),不劈开多字节字符与代理对。 */\r\nexport function sliceByBytes(text: string, maxBytes: number): string {\r\n if (Buffer.byteLength(text, 'utf8') <= maxBytes) return text\r\n let lo = 0\r\n let hi = text.length\r\n while (lo < hi) {\r\n const mid = Math.ceil((lo + hi) / 2)\r\n if (Buffer.byteLength(text.slice(0, mid), 'utf8') <= maxBytes) lo = mid\r\n else hi = mid - 1\r\n }\r\n let cut = lo\r\n if (cut > 0) {\r\n const code = text.charCodeAt(cut - 1)\r\n if (code >= 0xd8_00 && code <= 0xdb_ff) cut -= 1 // 高位代理在末尾:整对移除\r\n }\r\n return text.slice(0, cut)\r\n}\r\n\r\n/** 按 UTF-8 字节上限截尾(保留尾部),不劈开多字节字符与代理对;截断时头部加省略标记。 */\r\nexport function sliceTailByBytes(text: string, maxBytes: number): string {\r\n if (Buffer.byteLength(text, 'utf8') <= maxBytes) return text\r\n const budget = maxBytes - Buffer.byteLength(PROCESS_OMITTED, 'utf8')\r\n if (budget <= 0) throw new Error(`processMaxBytes=${maxBytes} 过小,连省略标记都容纳不了`)\r\n let lo = 0\r\n let hi = text.length\r\n while (lo < hi) {\r\n const mid = Math.floor((lo + hi) / 2)\r\n if (Buffer.byteLength(text.slice(mid), 'utf8') <= budget) hi = mid\r\n else lo = mid + 1\r\n }\r\n let cut = lo\r\n if (cut < text.length) {\r\n const code = text.charCodeAt(cut)\r\n if (code >= 0xdc_00 && code <= 0xdf_ff) cut += 1 // 低位代理在开头:整对移除\r\n }\r\n return PROCESS_OMITTED + text.slice(cut)\r\n}\r\n\r\n/** JSON 串内内容的转义后字节数(去首尾引号);卡片 DSL 真实字节记账用。 */\r\nexport function escapedLen(s: string): number {\r\n return Buffer.byteLength(JSON.stringify(s), 'utf8') - 2\r\n}\r\n\r\n/** 按转义后字节上限截头(保留头部),不劈开多字节字符与代理对。 */\r\nexport function sliceByEscapedBytes(text: string, maxBytes: number): string {\r\n if (escapedLen(text) <= maxBytes) return text\r\n let lo = 0\r\n let hi = text.length\r\n while (lo < hi) {\r\n const mid = Math.ceil((lo + hi) / 2)\r\n if (escapedLen(text.slice(0, mid)) <= maxBytes) lo = mid\r\n else hi = mid - 1\r\n }\r\n let cut = lo\r\n if (cut > 0) {\r\n const code = text.charCodeAt(cut - 1)\r\n if (code >= 0xd8_00 && code <= 0xdb_ff) cut -= 1\r\n }\r\n return text.slice(0, cut)\r\n}\r\n\r\n/** 新卡:仅状态行的流式卡;段后续经插入组件 API 动态加入。 */\r\nexport function buildCardJson(printStep: number): string {\r\n return JSON.stringify({\r\n schema: '2.0',\r\n config: {\r\n streaming_mode: true,\r\n summary: { content: '生成中…' },\r\n streaming_config: { print_frequency_ms: { default: 70 }, print_step: { default: printStep }, print_strategy: 'fast' },\r\n },\r\n body: { elements: [{ tag: 'markdown', content: STATUS_STREAMING, element_id: STATUS_ELEMENT_ID }] },\r\n })\r\n}\r\n\r\n/** 段元素 JSON(insert op 负载):process = 默认收起折叠面板;text = 纯 markdown。 */\r\nexport function buildSegmentJson(kind: 'text' | 'process', elementId: string, content: string): string {\r\n if (kind === 'process') {\r\n return JSON.stringify({\r\n tag: 'collapsible_panel',\r\n expanded: false,\r\n header: { title: { tag: 'plain_text', content: '思考与工具调用过程' } },\r\n elements: [{ tag: 'markdown', content, element_id: elementId }],\r\n })\r\n }\r\n return JSON.stringify({ tag: 'markdown', content, element_id: elementId })\r\n}\r\n\r\nexport interface StreamState {\r\n /** 当前卡片 id(PENDING_CARD_ID = 创建中);null = 下一张卡待创建。 */\r\n cardId: string | null\r\n /** 当前卡片已消耗的 sequence 计数(create/send 不占)。 */\r\n seq: number\r\n /** 当前卡已提交内容字节数(段内容 + 固定开销合计)。 */\r\n cardBytes: number\r\n /** 当前卡组件数(含状态行;面板按 2 计)。 */\r\n cardElements: number\r\n /** 全局段计数(element_id 生成用,跨卡递增)。 */\r\n segCounter: number\r\n /** 已在历史卡封闭、不再关注的段数(段 0..closedSegCount-1)。 */\r\n closedSegCount: number\r\n /** 当前卡上打开的段(永远是最新的有内容段);base = 元素内容在该段 content 中的 char 起始偏移(process 恒 0)。 */\r\n tail: { segIndex: number; elementId: string; base: number; shownText: string } | undefined\r\n /** text 段跨卡续写基准(char offset into 该段 content)。 */\r\n carry: { segIndex: number; base: number } | undefined\r\n}\r\n\r\nexport const initialStreamState = (): StreamState => ({\r\n cardId: null, seq: 0, cardBytes: 0, cardElements: 0, segCounter: 0,\r\n closedSegCount: 0, tail: undefined, carry: undefined,\r\n})\r\n\r\nexport type CardOp =\r\n | { type: 'create'; cardJson: string }\r\n | { type: 'send' }\r\n | { type: 'insert'; elementJson: string; sequence: number }\r\n | { type: 'update'; elementId: string; content: string; sequence: number }\r\n | { type: 'settings'; streaming: boolean; sequence: number; summary?: string }\r\n | { type: 'noop' }\r\n\r\nexport interface PlannedOp {\r\n op: CardOp\r\n /** 该 op 成功后的状态迁移(快照整体替换)。 */\r\n commit: (s: StreamState) => StreamState\r\n}\r\n\r\n/** 把段序列的新增部分同步到卡片;新段 insert 到状态行之前,尾段增长走元素 update,满卡关流开续卡。 */\r\nexport function planSync(\r\n state: StreamState,\r\n segments: readonly TurnSegment[],\r\n maxBytes: number,\r\n processMaxBytes: number,\r\n printStep: number,\r\n): { ops: PlannedOp[] } {\r\n const ops: PlannedOp[] = []\r\n let { cardId, seq, cardBytes, cardElements, segCounter, closedSegCount, tail, carry } = state\r\n\r\n /** 约定:先改规划局部变量再 push——commit 捕获该 op 完成后的状态快照。 */\r\n const push = (op: CardOp): void => {\r\n const snap = { cardId, seq, cardBytes, cardElements, segCounter, closedSegCount, tail, carry }\r\n ops.push({ op, commit: () => ({ ...snap }) })\r\n }\r\n\r\n const ensureCard = (): void => {\r\n if (cardId !== null) return\r\n const cardJson = buildCardJson(printStep)\r\n cardId = PENDING_CARD_ID\r\n seq = 0\r\n cardBytes = Buffer.byteLength(cardJson, 'utf8') // 真实 DSL 字节\r\n cardElements = 1\r\n push({ type: 'create', cardJson })\r\n push({ type: 'send' })\r\n }\r\n\r\n const closeCard = (): void => {\r\n // 先定格状态行(流式还开着,组件 content API 需要流式模式),再关流 + summary。\r\n seq += 1\r\n push({ type: 'update', elementId: STATUS_ELEMENT_ID, content: STATUS_CONTINUED, sequence: seq })\r\n seq += 1\r\n cardId = null\r\n tail = undefined\r\n push({ type: 'settings', streaming: false, sequence: seq, summary: STATUS_CONTINUED })\r\n }\r\n\r\n let i = tail?.segIndex ?? closedSegCount\r\n while (i < segments.length) {\r\n const seg = segments[i]\r\n const content = seg.kind === 'process' ? sliceTailByBytes(seg.content, processMaxBytes) : seg.content\r\n const base = tail !== undefined && tail.segIndex === i\r\n ? tail.base\r\n : carry?.segIndex === i ? carry.base : 0\r\n const elementContent = seg.kind === 'text' ? content.slice(base) : content\r\n\r\n if (tail !== undefined && tail.segIndex === i) {\r\n // 当前卡上的打开段:内容增长走 update\r\n if (elementContent !== tail.shownText) {\r\n const delta = escapedLen(elementContent) - escapedLen(tail.shownText)\r\n if (cardBytes + delta <= maxBytes) {\r\n seq += 1\r\n cardBytes += delta\r\n tail = { ...tail, shownText: elementContent }\r\n push({ type: 'update', elementId: tail.elementId, content: elementContent, sequence: seq })\r\n } else if (seg.kind === 'text') {\r\n // 部分更新到满 → 拆卡,剩余经 carry 续写(预算按转义后字节)\r\n const piece = sliceByEscapedBytes(elementContent, escapedLen(tail.shownText) + (maxBytes - cardBytes))\r\n if (piece.length > tail.shownText.length) {\r\n seq += 1\r\n cardBytes += escapedLen(piece) - escapedLen(tail.shownText)\r\n tail = { ...tail, shownText: piece }\r\n push({ type: 'update', elementId: tail.elementId, content: piece, sequence: seq })\r\n }\r\n carry = { segIndex: i, base: tail.base + tail.shownText.length }\r\n closeCard()\r\n continue\r\n } else {\r\n // process:旧卡定格,续卡整窗重放\r\n closeCard()\r\n continue\r\n }\r\n }\r\n // 已完整同步:是最新段则保活收尾;有更新段则封闭前段\r\n if (i === segments.length - 1) break\r\n tail = undefined\r\n closedSegCount = i + 1\r\n carry = undefined\r\n i += 1\r\n continue\r\n }\r\n\r\n // 当前卡上还没有该段的元素 → insert\r\n if (seg.kind === 'process') {\r\n const elementId = `seg_${segCounter + 1}`\r\n const elementJson = buildSegmentJson('process', elementId, elementContent)\r\n const elBytes = Buffer.byteLength(elementJson, 'utf8')\r\n if (cardId !== null && (cardBytes + elBytes > maxBytes || cardElements + 2 > CARD_ELEMENT_LIMIT)) {\r\n closeCard()\r\n continue\r\n }\r\n ensureCard()\r\n // 过程窗口由 processMaxBytes 兜底(sliceTailByBytes 已截尾);新卡整窗插入,不再受卡预算约束。\r\n segCounter += 1\r\n seq += 1\r\n cardBytes += elBytes\r\n cardElements += 2\r\n tail = { segIndex: i, elementId, base: 0, shownText: elementContent }\r\n push({ type: 'insert', elementJson, sequence: seq })\r\n } else {\r\n if (elementContent.length === 0) { // 空 text 段不占卡\r\n closedSegCount = i + 1\r\n carry = undefined\r\n i += 1\r\n continue\r\n }\r\n if (cardId !== null && cardElements + 1 > CARD_ELEMENT_LIMIT) {\r\n closeCard()\r\n continue\r\n }\r\n ensureCard()\r\n const elementId = `seg_${segCounter + 1}`\r\n const overhead = Buffer.byteLength(buildSegmentJson('text', elementId, ''), 'utf8')\r\n const piece = sliceByEscapedBytes(elementContent, maxBytes - cardBytes - overhead)\r\n if (piece.length === 0) {\r\n throw new Error(`cardMaxBytes=${maxBytes} 过小,扣基础卡与元素开销后连一个字符都容纳不了`)\r\n }\r\n segCounter += 1\r\n const elementJson = buildSegmentJson('text', elementId, piece)\r\n seq += 1\r\n cardBytes += Buffer.byteLength(elementJson, 'utf8')\r\n cardElements += 1\r\n tail = { segIndex: i, elementId, base, shownText: piece }\r\n push({ type: 'insert', elementJson, sequence: seq })\r\n if (piece.length < elementContent.length) {\r\n carry = { segIndex: i, base: base + piece.length }\r\n closeCard()\r\n continue\r\n }\r\n }\r\n carry = undefined\r\n if (i === segments.length - 1) break\r\n tail = undefined\r\n closedSegCount = i + 1\r\n i += 1\r\n }\r\n // 段封闭/进位等纯状态推进也要交还执行侧:无 op 或末 op 之后状态仍有差异时补一个空操作 commit。\r\n // 简单起见:恒追加一个 no-op 规划项携带末态(执行侧对 type:'noop' 直接 commit,不调 API)。\r\n const snap = { cardId, seq, cardBytes, cardElements, segCounter, closedSegCount, tail, carry }\r\n ops.push({ op: { type: 'noop' }, commit: () => ({ ...snap }) })\r\n return { ops }\r\n}\r\n\r\n/** 定格:先 update 状态行(流式还开着),再关闭 + summary。 */\r\nexport function planFinalize(state: StreamState, status: TurnStatus): { ops: CardOp[] } {\r\n if (state.cardId === null) return { ops: [] }\r\n return {\r\n ops: [\r\n { type: 'update', elementId: STATUS_ELEMENT_ID, content: STATUS_FINAL[status], sequence: state.seq + 1 },\r\n { type: 'settings', streaming: false, sequence: state.seq + 2, summary: STATUS_FINAL[status] },\r\n ],\r\n }\r\n}\r\n","/** 出站句柄:turn 级流式卡片(确认式状态机 + 失败分类治理 + 拆卡定格)。 */\r\nimport type { ChannelTunables, Disposer, ReplyHandle, TurnSegment, TurnStatus } from '../channel.ts'\r\nimport { feishuErrorCode, type FeishuApi } from './api.ts'\r\nimport {\r\n initialStreamState, PENDING_CARD_ID, STATUS_ELEMENT_ID,\r\n planFinalize, planSync, type CardOp, type PlannedOp, type StreamState,\r\n} from './cards.ts'\r\n\r\n/** 指数退避重试(默认 3 次,300ms 起)。 */\r\nexport async function withRetry<T>(fn: () => Promise<T>, attempts = 3, baseDelayMs = 300): Promise<T> {\r\n let lastError: unknown\r\n for (let i = 0; i < attempts; i++) {\r\n try {\r\n return await fn()\r\n } catch (error) {\r\n lastError = error\r\n if (i < attempts - 1) await new Promise((resolve) => setTimeout(resolve, baseDelayMs * 2 ** i))\r\n }\r\n }\r\n throw lastError\r\n}\r\n\r\n/** 卡片输出异常时的用户提示(仅真实废弃一张已发卡时发送)。 */\r\nconst ABANDON_NOTICE = '⚠️ 卡片输出异常,已在新卡片继续;如有内容缺失请重发。'\r\n\r\n/** 单次 flush 内连续废弃换卡的上限(防异常死循环;超限抛给出站链日志)。 */\r\nconst MAX_ABANDON_PER_FLUSH = 3\r\n\r\nexport class FeishuReplyHandle implements ReplyHandle {\r\n private state: StreamState = initialStreamState()\r\n private segments: readonly TurnSegment[] = []\r\n private tail: Promise<unknown> = Promise.resolve()\r\n private timer: ReturnType<typeof setTimeout> | undefined\r\n private planQueued = false\r\n private finalized = false\r\n\r\n constructor(\r\n private readonly api: FeishuApi,\r\n private readonly chatId: string,\r\n private readonly tunables: ChannelTunables,\r\n private readonly log: (message: string) => void,\r\n ) {}\r\n\r\n beginTurn(): Promise<void> {\r\n return Promise.resolve()\r\n }\r\n\r\n update(segments: readonly TurnSegment[]): Promise<void> {\r\n if (this.finalized) return Promise.resolve()\r\n this.segments = segments\r\n if (this.timer === undefined) {\r\n this.timer = setTimeout(() => {\r\n this.timer = undefined\r\n this.flush()\r\n }, this.tunables.cardUpdateThrottleMs)\r\n }\r\n return Promise.resolve()\r\n }\r\n\r\n async finalize(status: TurnStatus, detail?: string): Promise<void> {\r\n if (this.finalized) {\r\n await this.tail\r\n return\r\n }\r\n this.finalized = true\r\n if (this.timer !== undefined) {\r\n clearTimeout(this.timer)\r\n this.timer = undefined\r\n }\r\n this.flush()\r\n // 等 flush 定局(含失败恢复)后再规划定格:状态此刻是已确认态。\r\n await this.tail\r\n const hadCard = this.state.cardId !== null\r\n const { ops } = planFinalize(this.state, status)\r\n // 定格批不触发废弃重规划(卡已在收尾):遇 abandon 直接止步。\r\n this.enqueue(async () => {\r\n for (const op of ops) {\r\n const outcome = await this.execOne({ op, commit: (s: StreamState) => s })\r\n if (outcome === 'abandoned') return\r\n }\r\n })\r\n if (!hadCard && detail !== undefined) {\r\n this.enqueue(() => withRetry(() => this.api.sendText(this.chatId, detail)).then(() => undefined))\r\n }\r\n await this.tail\r\n }\r\n\r\n notice(text: string): Promise<void> {\r\n this.enqueue(() => withRetry(() => this.api.sendText(this.chatId, text)).then(() => undefined))\r\n return this.tail.then(() => undefined)\r\n }\r\n\r\n /**\r\n * 规划入串行链:planSync 在执行点读最新已确认状态与最新 segments,\r\n * 在飞期间到达的 flush 只标位不重复规划(杜绝重复建卡/重复 insert)。\r\n */\r\n private flush(): void {\r\n if (this.planQueued) return\r\n this.planQueued = true\r\n this.enqueue(async () => {\r\n this.planQueued = false\r\n const { ops } = planSync(this.state, this.segments, this.tunables.cardMaxBytes, this.tunables.processMaxBytes, this.tunables.cardPrintStep)\r\n await this.exec(ops)\r\n })\r\n }\r\n\r\n /** 逐 op 确认执行;遇废弃从已确认状态重新规划续写(上限 MAX_ABANDON_PER_FLUSH 次)。 */\r\n private async exec(ops: readonly PlannedOp[]): Promise<void> {\r\n let pending = ops\r\n for (let attempts = 0; ; attempts++) {\r\n let abandoned = false\r\n for (const planned of pending) {\r\n if ((await this.execOne(planned)) === 'abandoned') {\r\n abandoned = true\r\n break\r\n }\r\n }\r\n if (!abandoned) return\r\n if (attempts >= MAX_ABANDON_PER_FLUSH) throw new Error('卡片连续废弃超限,本批输出放弃(下一 flush 继续)')\r\n pending = planSync(this.state, this.segments, this.tunables.cardMaxBytes, this.tunables.processMaxBytes, this.tunables.cardPrintStep).ops\r\n }\r\n }\r\n\r\n /**\r\n * 单个 op:成功(或 insert 300301 视同成功)才 commit;\r\n * 失败按错误码分类:流式超时重激活重放 / 200860 废弃续写 / 未知错误 seq+2 重放一次。\r\n */\r\n private async execOne(planned: PlannedOp): Promise<'ok' | 'abandoned'> {\r\n const { op } = planned\r\n if (op.type === 'noop') {\r\n this.commit(planned)\r\n return 'ok'\r\n }\r\n const liveCard = this.state.cardId !== null && this.state.cardId !== PENDING_CARD_ID\r\n try {\r\n await this.invokeThenCommit(planned)\r\n return 'ok'\r\n } catch (error) {\r\n // 建卡链路(尚无活卡):状态未推进,抛给出站链日志,下次 flush 自然重试。\r\n if (!liveCard) throw error\r\n const code = feishuErrorCode(error)\r\n if (op.type === 'insert' && code === 300301) {\r\n // 元素重复 = 服务端已执行(此前响应丢失),视同成功。\r\n this.commit(planned)\r\n return 'ok'\r\n }\r\n if (code === 200850 || code === 200510) {\r\n // 流式被平台超时自动关闭:重激活(占一个 sequence)后以新 sequence 重放一次。\r\n if (await this.reactivate()) {\r\n try {\r\n await this.invokeThenCommit(planned, this.state.seq + 1)\r\n return 'ok'\r\n } catch {\r\n return this.abandon('流式超时重激活后重放失败', true)\r\n }\r\n }\r\n return this.abandon('流式超时且重激活失败', true)\r\n }\r\n if (code === 200860) {\r\n // 确定性超限:op 未被应用。废弃换卡,从确认点续写(不重演已显示部分)。\r\n return this.abandon('卡片超出平台大小上限', false)\r\n }\r\n // 未知/网络错误(op 可能已执行):sequence 跳过可能已消耗的序号重放一次\r\n // (update/settings 幂等;insert 重演由 300301 兜底)。跳步按本次尝试的 sequence\r\n // 计(state.seq 是最后已确认序号,未包含本次尝试,用它 +2 会差一)。\r\n try {\r\n const retrySeq = (op.type === 'insert' || op.type === 'update' || op.type === 'settings' ? op.sequence : this.state.seq) + 2\r\n await this.invokeThenCommit(planned, retrySeq)\r\n return 'ok'\r\n } catch (retryError) {\r\n if (op.type === 'insert' && feishuErrorCode(retryError) === 300301) {\r\n this.commit(planned)\r\n return 'ok'\r\n }\r\n return this.abandon('卡片操作重放失败', true)\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 执行 API 并在成功后 commit;seqOverride 用于重放(create 的真实 cardId 在此覆盖进状态)。\r\n * 带序号 op 的发送/提交序号一律取 max(本次序号, 已确认 seq+1):重放/重激活会推高已确认 seq,\r\n * 批内后续 op 的规划序号可能落后,照发会以非递增序号碰撞(平台可能视作幂等 no-op 静默丢 op →\r\n * 定格/关流 op 消失 → 卡死「输出中」)。\r\n */\r\n private async invokeThenCommit(planned: PlannedOp, seqOverride?: number): Promise<void> {\r\n const effectiveSeq = effectiveSeqOf(planned.op, seqOverride, this.state.seq)\r\n const op = withSeq(planned.op, effectiveSeq)\r\n if (op.type === 'create') {\r\n const id = await withRetry(() => this.api.createCard(op.cardJson))\r\n this.state = { ...planned.commit(this.state), cardId: id }\r\n return\r\n }\r\n if (op.type === 'send') {\r\n await withRetry(() => this.api.sendCardMessage(this.chatId, this.state.cardId!))\r\n } else if (op.type === 'insert') {\r\n await this.api.insertElement(this.state.cardId!, op.elementJson, STATUS_ELEMENT_ID, op.sequence)\r\n } else if (op.type === 'update') {\r\n await this.api.updateCardElement(this.state.cardId!, op.elementId, op.content, op.sequence)\r\n } else if (op.type === 'settings') {\r\n await this.api.setCardStreaming(this.state.cardId!, op.streaming, op.sequence, op.summary)\r\n }\r\n this.commit(planned, effectiveSeq)\r\n }\r\n\r\n private commit(planned: PlannedOp, seqOverride?: number): void {\r\n const next = planned.commit(this.state)\r\n // 建卡批次里 create 已把真实 cardId 叠入状态,后续 op 的规划快照仍带 PENDING 占位:\r\n // 占位符不得回写真实卡号,否则同批末尾的 insert/update 会对 __pending__ 发 op。\r\n const current = this.state.cardId\r\n const cardId = next.cardId === PENDING_CARD_ID && current !== null && current !== PENDING_CARD_ID\r\n ? current\r\n : next.cardId\r\n this.state = seqOverride !== undefined\r\n ? { ...next, seq: seqOverride, cardId }\r\n : { ...next, seq: Math.max(next.seq, this.state.seq), cardId }\r\n }\r\n\r\n /** 流式超时后的官方恢复路径:settings 重设 streaming_mode:true(占一个 sequence)。 */\r\n private async reactivate(): Promise<boolean> {\r\n const { cardId, seq } = this.state\r\n if (cardId === null || cardId === PENDING_CARD_ID) return false\r\n try {\r\n await this.api.setCardStreaming(cardId, true, seq + 1)\r\n this.state = { ...this.state, seq: seq + 1 }\r\n return true\r\n } catch {\r\n return false\r\n }\r\n }\r\n\r\n /**\r\n * 废弃当前卡:尽力关流 → cardId 归零、尾段回卷为 carry → 调用方重新规划续写。\r\n * reshowTail=true(未知失败,op 可能已执行)时从尾段 base 重演(少量重复优于丢失);\r\n * reshowTail=false(200860 确定性未应用)时跳过已显示部分(零重复)。\r\n */\r\n private async abandon(reason: string, reshowTail: boolean): Promise<'abandoned'> {\r\n const { cardId, tail, seq } = this.state\r\n const hadRealCard = cardId !== null && cardId !== PENDING_CARD_ID\r\n if (hadRealCard) {\r\n await this.api.setCardStreaming(cardId as string, false, seq + 1).catch(() => undefined)\r\n }\r\n if (tail !== undefined) {\r\n const kind = this.segments[tail.segIndex]?.kind\r\n const base = kind === 'process' ? 0 : reshowTail ? tail.base : tail.base + tail.shownText.length\r\n this.state = {\r\n ...this.state,\r\n cardId: null,\r\n tail: undefined,\r\n closedSegCount: tail.segIndex,\r\n carry: { segIndex: tail.segIndex, base },\r\n }\r\n } else {\r\n this.state = { ...this.state, cardId: null }\r\n }\r\n this.log(`[project-bot] 卡片输出异常(${reason}),已废弃当前卡并在新卡继续`)\r\n if (hadRealCard) {\r\n await withRetry(() => this.api.sendText(this.chatId, ABANDON_NOTICE)).catch(() => undefined)\r\n }\r\n return 'abandoned'\r\n }\r\n\r\n private enqueue(task: () => Promise<void>): void {\r\n this.tail = this.tail.then(task).catch((error) => {\r\n this.log(`[project-bot] 卡片操作失败:${error instanceof Error ? error.message : String(error)}`)\r\n })\r\n }\r\n}\r\n\r\n/** 重放用:仅带 sequence 语义的 op 替换序号(create/send 无序号)。 */\r\nfunction withSeq(op: CardOp, sequence: number | undefined): CardOp {\r\n if (sequence === undefined) return op\r\n if (op.type === 'insert') return { ...op, sequence }\r\n if (op.type === 'update') return { ...op, sequence }\r\n if (op.type === 'settings') return { ...op, sequence }\r\n return op\r\n}\r\n\r\n/**\r\n * 带序号 op 的生效 sequence(create/send 返回 undefined = 不占序号):\r\n * 重放/重激活推高已确认 seq 后,规划或重放序号落后时抬升到已确认 seq+1,保证单调不碰撞。\r\n */\r\nfunction effectiveSeqOf(op: CardOp, override: number | undefined, confirmedSeq: number): number | undefined {\r\n if (op.type !== 'insert' && op.type !== 'update' && op.type !== 'settings') return undefined\r\n return Math.max(override ?? op.sequence, confirmedSeq + 1)\r\n}\r\n\r\n/** 「处理中」表情:加上后返回删除 disposer;加/删失败都静默(表情残留无害)。 */\r\nexport function makeAck(api: FeishuApi, messageId: string, emojiType: string): () => Promise<Disposer | undefined> {\r\n return async () => {\r\n try {\r\n const reactionId = await api.addReaction(messageId, emojiType)\r\n return () => {\r\n void api.removeReaction(messageId, reactionId).catch(() => undefined)\r\n }\r\n } catch {\r\n return undefined\r\n }\r\n }\r\n}\r\n","/** 飞书审批卡片:cardkit 2.0 静态卡(非流式)+ callback 按钮;presenter 挂在渠道 ChannelHandle.approval。 */\r\nimport type { FeishuApi } from '../feishu/api.ts'\r\nimport { withRetry } from '../feishu/reply.ts'\r\nimport type { ApprovalPresentation, ApprovalPresenter, ApprovalPrompt } from './center.ts'\r\n\r\nconst STATUS_TEXT: Record<'allowed' | 'rejected' | 'cancelled', string> = {\r\n allowed: '✅ 已允许',\r\n rejected: '❌ 已拒绝',\r\n cancelled: '⏹ 已取消',\r\n}\r\n\r\nfunction bodyMarkdown(prompt: ApprovalPrompt): string {\r\n const lines = [`**Bot**:${prompt.botName}`, `**工具**:\\`${prompt.toolName}\\``]\r\n if (prompt.reason !== undefined) lines.push(`**理由**:${prompt.reason}`)\r\n return lines.join('\\n')\r\n}\r\n\r\nfunction button(text: string, type: 'primary' | 'danger', key: string, decision: 'allow' | 'reject'): Record<string, unknown> {\r\n return {\r\n tag: 'button',\r\n text: { tag: 'plain_text', content: text },\r\n type,\r\n behaviors: [{ type: 'callback', value: { key, decision } }],\r\n }\r\n}\r\n\r\n/** 审批卡(带按钮);summary 供会话列表/推送预览。 */\r\nexport function buildApprovalCardJson(prompt: ApprovalPrompt): string {\r\n return JSON.stringify({\r\n schema: '2.0',\r\n config: { summary: { content: `权限申请:${prompt.toolName}` } },\r\n header: { title: { tag: 'plain_text', content: '权限申请' }, template: 'orange' },\r\n body: {\r\n elements: [\r\n { tag: 'markdown', content: bodyMarkdown(prompt) },\r\n { tag: 'action', actions: [button('允许', 'primary', prompt.key, 'allow'), button('拒绝', 'danger', prompt.key, 'reject')] },\r\n ],\r\n },\r\n })\r\n}\r\n\r\n/** 终态卡(无按钮):定格审批结果;operatorName 仅允许/拒绝时有。 */\r\nexport function buildApprovalFinalCardJson(prompt: ApprovalPrompt, status: 'allowed' | 'rejected' | 'cancelled', operatorName?: string): string {\r\n const statusLine = STATUS_TEXT[status] + (operatorName !== undefined ? ` · ${operatorName}` : '')\r\n const template = status === 'allowed' ? 'green' : status === 'rejected' ? 'red' : 'grey'\r\n return JSON.stringify({\r\n schema: '2.0',\r\n config: { summary: { content: `权限申请${STATUS_TEXT[status].slice(2).trim()}:${prompt.toolName}` } },\r\n header: { title: { tag: 'plain_text', content: `权限申请 · ${statusLine}` }, template },\r\n body: { elements: [{ tag: 'markdown', content: bodyMarkdown(prompt) }] },\r\n })\r\n}\r\n\r\n/** 飞书审批能力:present = 建卡 + 发消息;finalize = replaceCard 定格(sequence 从 1 起,create/send 不占)。 */\r\nexport class FeishuApprovalPresenter implements ApprovalPresenter {\r\n constructor(\r\n private readonly api: FeishuApi,\r\n private readonly log: (message: string) => void,\r\n ) {}\r\n\r\n async present(prompt: ApprovalPrompt): Promise<ApprovalPresentation> {\r\n const cardId = await withRetry(() => this.api.createCard(buildApprovalCardJson(prompt)))\r\n await withRetry(() => this.api.sendCardMessage(prompt.chatId, cardId))\r\n return {\r\n finalize: async (status, operatorName) => {\r\n try {\r\n await withRetry(() => this.api.replaceCard(cardId, buildApprovalFinalCardJson(prompt, status, operatorName), 1))\r\n } catch (error) {\r\n // 定格失败不吞审批结果:卡片残留按钮但回调侧已 settle(重复点击 toast 已失效)。\r\n this.log(`[project-bot] 审批卡片定格失败(card ${cardId}):${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n },\r\n }\r\n }\r\n}\r\n","/** card.action.trigger 回调解析:SDK normalizeCardAction → 渠道无关 CardActionInput;toast 应答帧负载。 */\r\nimport * as lark from '@larksuiteoapi/node-sdk'\r\nimport type { CardActionAck, CardActionInput } from '../approval/center.ts'\r\n\r\n/** raw → CardActionInput;normalize 失败(畸形/缺字段)→ undefined。 */\r\nexport function toCardActionInput(raw: unknown): CardActionInput | undefined {\r\n // SDK normalizeCardAction 对 null 直取 event.context 会抛 TypeError;先挡掉非对象输入。\r\n if (raw === null || typeof raw !== 'object') return undefined\r\n const evt = lark.normalizeCardAction(raw as lark.RawCardActionEvent)\r\n if (evt === null) return undefined\r\n return {\r\n chatId: evt.chatId,\r\n operatorOpenId: evt.operator.openId,\r\n ...(evt.operator.name !== undefined ? { operatorName: evt.operator.name } : {}),\r\n value: evt.action.value,\r\n }\r\n}\r\n\r\n/** WS 应答帧负载:handler 返回值经 WSClient 回传(lib/index.js handleEventData:truthy result → respPayload.data)。 */\r\nexport function toastResponse(ack: CardActionAck | undefined): { toast: { type: 'info'; content: string } } | undefined {\r\n if (ack?.toast === undefined) return undefined\r\n return { toast: { type: 'info', content: ack.toast } }\r\n}\r\n","/** 飞书渠道:WSClient 长连接收事件 → 解析 → 核心;出站走 FeishuReplyHandle。 */\r\nimport * as lark from '@larksuiteoapi/node-sdk'\r\nimport type { BotChannel, ChannelHandle } from '../channel.ts'\r\nimport { createFeishuApi } from './api.ts'\r\nimport { MessageDedup, parseMessageEvent } from './parse.ts'\r\nimport { FeishuReplyHandle, makeAck } from './reply.ts'\r\nimport { FeishuApprovalPresenter } from '../approval/feishu.ts'\r\nimport { toCardActionInput, toastResponse } from './card-action.ts'\r\n\r\nexport const feishuChannel: BotChannel = {\r\n type: 'feishu',\r\n\r\n async start(bot, io, tunables, log): Promise<ChannelHandle> {\r\n // runtime 仅对已绑定记录启动渠道(reconcile 的 feishu guard),此处安全。\r\n const { appId } = bot.record.feishu!\r\n const client = new lark.Client({ appId, appSecret: bot.secret })\r\n const api = createFeishuApi(client)\r\n // 群消息 @ 身份校验依赖本机器人 open_id;取不到则启动失败(reconcile 记录原因),不降级放行。\r\n const botOpenId = await api.getBotOpenId()\r\n const dedup = new MessageDedup()\r\n\r\n const dispatcher = new lark.EventDispatcher({}).register<{ 'card.action.trigger': (raw: unknown) => unknown }>({\r\n // 已读回执无动作;显式 no-op 消掉 EventDispatcher 的 \"no ... handle\" 告警噪音。\r\n 'im.message.message_read_v1': async () => undefined,\r\n // WS 事件须 3 秒内返回:解析同步完成,业务投递 fire-and-forget(含图片懒下载)。\r\n 'im.message.receive_v1': async (data: unknown) => {\r\n const parsed = parseMessageEvent(data, botOpenId)\r\n if (parsed === null || !dedup.check(parsed.messageId)) return\r\n const reply = new FeishuReplyHandle(api, parsed.chatId, tunables, log)\r\n const loadImages = parsed.imageKeys.length > 0\r\n ? async () => Promise.all(parsed.imageKeys.map(async (key) => api.downloadImage(parsed.messageId, key)))\r\n : undefined\r\n io.onMessage({\r\n botId: bot.record.id,\r\n chatId: parsed.chatId,\r\n userId: parsed.userId,\r\n messageId: parsed.messageId,\r\n text: parsed.text,\r\n ...(loadImages !== undefined ? { loadImages } : {}),\r\n reply,\r\n ackProcessing: makeAck(api, parsed.messageId, tunables.processingReactionEmoji),\r\n })\r\n },\r\n // 卡片按钮回调(审批):同步入核,toast 经 WS 应答帧回执。\r\n 'card.action.trigger': (raw: unknown) => {\r\n if (io.onCardAction === undefined) return undefined\r\n const action = toCardActionInput(raw)\r\n if (action === undefined) return undefined\r\n return toastResponse(io.onCardAction(action)) ?? undefined\r\n },\r\n })\r\n\r\n const ws = new lark.WSClient({ appId, appSecret: bot.secret, loggerLevel: lark.LoggerLevel.warn })\r\n await ws.start({ eventDispatcher: dispatcher })\r\n\r\n return {\r\n approval: new FeishuApprovalPresenter(api, log),\r\n close: () => {\r\n ws.close({ force: true })\r\n return Promise.resolve()\r\n },\r\n status: () => ws.getConnectionStatus().state,\r\n }\r\n },\r\n}\r\n","/** project-bot 存储域声明:身份、版本、记录 zod schema 的单一来源。 */\r\nimport { z } from 'zod'\r\nimport { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'\r\n\r\n/** 飞书自建应用 appId 形态(WSClient 同款校验)。 */\r\nexport const FEISHU_APP_ID_RE = /^cli_[0-9a-fA-F]{16}$/\r\n/** CredentialRef 字符集(credentials 服务 credentialRef() 的校验规则)。 */\r\nexport const CREDENTIAL_REF_RE = /^[A-Za-z_][A-Za-z0-9_]*$/\r\n/** bot id:小写 slug。 */\r\nexport const BOT_ID_RE = /^[a-z][a-z0-9-]{0,31}$/\r\n\r\nexport const FeishuConfigSchema = z.object({\r\n appId: z.string().regex(FEISHU_APP_ID_RE),\r\n appSecretRef: z.string().regex(CREDENTIAL_REF_RE),\r\n})\r\nexport type FeishuConfig = z.infer<typeof FeishuConfigSchema>\r\n\r\nexport const BotRecordSchema = z.object({\r\n id: z.string().regex(BOT_ID_RE),\r\n name: z.string().min(1).max(64),\r\n /** 渠道类型;与 feishu 同有或同无(未绑定为双双缺省)。 */\r\n channel: z.literal('feishu').optional(),\r\n feishu: FeishuConfigSchema.optional(),\r\n /** 绑定项目(agent 的 cwd,绝对路径)。一 bot 一项目。 */\r\n project: z.string().min(1),\r\n /** 透传到 agent 创作期的 persona 提示段。 */\r\n persona: z.string().max(8000).optional(),\r\n /** 绑定的 Agent('main' 或注册表角色 id,缺省 = 'main')。 */\r\n agentRef: z.string().min(1).optional(),\r\n /** 可用工具白名单(缺省 = 不限制);空数组无意义,直接拒绝。 */\r\n tools: z.array(z.string().min(1)).min(1).optional(),\r\n agentOptions: z.object({\r\n provider: z.string().min(1).optional(),\r\n model: z.string().min(1).optional(),\r\n }).optional(),\r\n createdAt: z.number().int().nonnegative(),\r\n updatedAt: z.number().int().nonnegative(),\r\n}).refine(\r\n (r) => (r.channel === undefined) === (r.feishu === undefined),\r\n { message: 'channel 与 feishu 必须同有或同无' },\r\n)\r\nexport type BotRecord = z.infer<typeof BotRecordSchema>\r\n\r\nexport const BindingSchema = z.object({ sessionId: z.string().min(1) })\r\nexport type Binding = z.infer<typeof BindingSchema>\r\n\r\n/** domain 名受 UNIT_NAME_RE 约束(^[a-z][a-z0-9_]*$),不允许连字符。 */\r\nexport const projectBotDomain = defineDomain({\r\n name: 'project_bot',\r\n version: 1,\r\n tables: {\r\n bots: domainTable<string, BotRecord>(BotRecordSchema),\r\n bindings: domainTable<string, Binding>(BindingSchema),\r\n },\r\n})\r\n\r\n/** bindings 表 key:(botId, chatId) → sessionId。 */\r\nexport function bindingKey(botId: string, chatId: string): string {\r\n return `${botId}:${chatId}`\r\n}\r\n","/** 出站:持久会话事件 → turn 级回复驱动(per-session Promise 链保序)。 */\r\nimport type { TurnSegment, TurnStatus } from './channel.ts'\r\nimport type { SessionRuntime } from './ports.ts'\r\n\r\n/** 窄化的事件信封:核心只读 type/data。 */\r\nexport interface SessionEventLike {\r\n type: string\r\n data: Record<string, unknown>\r\n}\r\n\r\n/** 从 assistant 消息内容块提取正文纯文本(只取 text 块进正文;reasoning/tool_call 由 processOf 进过程区)。 */\r\nexport function textOf(content: readonly unknown[]): string {\r\n return (content as readonly { type?: unknown; text?: unknown }[])\r\n .filter((b): b is { type: 'text'; text: string } => b.type === 'text' && typeof b.text === 'string')\r\n .map((b) => b.text)\r\n .join('')\r\n}\r\n\r\n/** 工具调用参数摘要最大字符数。 */\r\nexport const TOOL_ARGS_MAX_CHARS = 120\r\n\r\n/** 向段序列追加内容:与尾段同类则合并,异类开新段。 */\r\nexport function appendToSegments(segments: TurnSegment[], kind: 'text' | 'process', text: string): void {\r\n const tail = segments[segments.length - 1]\r\n if (tail !== undefined && tail.kind === kind) tail.content += text\r\n else segments.push({ kind, content: text })\r\n}\r\n\r\n/** (保留供测试)从组装消息提取过程输出:reasoning 全文 + tool_call 摘要行(段落间空行分隔)。 */\r\nexport function processOf(content: readonly unknown[]): string {\r\n const parts: string[] = []\r\n for (const b of content as readonly { type?: unknown; text?: unknown; name?: unknown; arguments?: unknown }[]) {\r\n if (b.type === 'reasoning' && typeof b.text === 'string' && b.text.length > 0) {\r\n parts.push(b.text)\r\n } else if (b.type === 'tool_call' && typeof b.name === 'string') {\r\n const args = typeof b.arguments === 'string' ? b.arguments : JSON.stringify(b.arguments ?? {})\r\n parts.push(`🔧 ${b.name} — ${truncateDetail(args, TOOL_ARGS_MAX_CHARS)}`)\r\n }\r\n }\r\n return parts.length === 0 ? '' : `${parts.join('\\n\\n')}\\n\\n`\r\n}\r\n\r\n/** turn/end 的 reason 形状(宿主 TurnEndReason 的窄化视图:核心只读 kind 与 error.message)。 */\r\nexport interface TurnEndReasonLike {\r\n kind: string\r\n error?: { message?: unknown }\r\n}\r\n\r\nexport function mapTurnEnd(reason: TurnEndReasonLike): TurnStatus {\r\n if (reason.kind === 'completed') return 'done'\r\n if (reason.kind === 'aborted' || reason.kind === 'interrupted') return 'cancelled'\r\n return 'error'\r\n}\r\n\r\n/** 截断错误摘要到 max 字符,超出追加省略号。 */\r\nexport function truncateDetail(text: string, max: number): string {\r\n return text.length > max ? `${text.slice(0, max)}…` : text\r\n}\r\n\r\n/** 从 turn/end reason 提取错误摘要;非 error 或无 message 返回 undefined。 */\r\nfunction errorDetailOf(reason: TurnEndReasonLike, max: number): string | undefined {\r\n if (reason.kind !== 'error') return undefined\r\n const message = reason.error?.message\r\n const text = typeof message === 'string' && message.length > 0 ? message : '未知错误'\r\n return truncateDetail(text, max)\r\n}\r\n\r\nexport class Outbound {\r\n constructor(\r\n private readonly sessions: Map<string, SessionRuntime>,\r\n private readonly onError: (message: string) => void,\r\n /** 回传渠道的错误摘要最大字符数。 */\r\n private readonly maxErrorDetailChars = 500,\r\n ) {}\r\n\r\n handleSessionEvent(sessionId: string, event: SessionEventLike): void {\r\n const rt = this.sessions.get(sessionId)\r\n if (rt === undefined) return\r\n\r\n if (event.type === 'turn/start') {\r\n rt.turn = { n: event.data.turn as number, segments: [], began: false }\r\n return\r\n }\r\n\r\n if (event.type === 'assistant/chunk') {\r\n const turn = rt.turn\r\n if (turn === undefined || turn.n !== (event.data.turn as number)) return\r\n const chunk = event.data.chunk as { type: string; text?: string; block?: { type?: unknown } }\r\n if (chunk.type === 'text-delta' && typeof chunk.text === 'string') {\r\n appendToSegments(turn.segments, 'text', chunk.text)\r\n } else if (chunk.type === 'reasoning-delta' && typeof chunk.text === 'string') {\r\n appendToSegments(turn.segments, 'process', chunk.text)\r\n } else if (chunk.type === 'block-end' && chunk.block?.type === 'reasoning' && turn.segments[turn.segments.length - 1]?.kind === 'process') {\r\n appendToSegments(turn.segments, 'process', '\\n\\n') // 推理块段落分隔\r\n } else {\r\n return\r\n }\r\n const snapshot = turn.segments.map((s) => ({ ...s }))\r\n this.enqueue(rt, async () => {\r\n if (rt.reply === undefined) return\r\n if (!turn.began) {\r\n await rt.reply.beginTurn()\r\n turn.began = true\r\n }\r\n await rt.reply.update(snapshot)\r\n })\r\n return\r\n }\r\n\r\n if (event.type === 'tool/call') {\r\n const turn = rt.turn\r\n if (turn === undefined || turn.n !== (event.data.turn as number)) return\r\n const name = event.data.name as string\r\n const args = typeof event.data.arguments === 'string' ? event.data.arguments : JSON.stringify(event.data.arguments ?? {})\r\n appendToSegments(turn.segments, 'process', `🔧 ${name} — ${truncateDetail(args, TOOL_ARGS_MAX_CHARS)}\\n\\n`)\r\n const snapshot = turn.segments.map((s) => ({ ...s }))\r\n this.enqueue(rt, async () => {\r\n if (rt.reply === undefined) return\r\n if (!turn.began) {\r\n await rt.reply.beginTurn()\r\n turn.began = true\r\n }\r\n await rt.reply.update(snapshot)\r\n })\r\n return\r\n }\r\n\r\n if (event.type === 'turn/end') {\r\n const turn = rt.turn\r\n if (turn === undefined || turn.n !== (event.data.turn as number)) return\r\n const reason = event.data.reason as TurnEndReasonLike\r\n const status = mapTurnEnd(reason)\r\n const detail = errorDetailOf(reason, this.maxErrorDetailChars)\r\n this.enqueue(rt, async () => {\r\n // 有卡定格;无卡但有错误 detail 时也要调 finalize(渠道降级为文本送出)。\r\n if ((turn.began || detail !== undefined) && rt.reply !== undefined) await rt.reply.finalize(status, detail)\r\n const ack = rt.inflight?.ack\r\n rt.inflight = undefined\r\n if (ack !== undefined) await ack()\r\n })\r\n rt.turn = undefined\r\n }\r\n }\r\n\r\n /**\r\n * turn 外错误(agent/error:resume/驱动边界失败等没有 turn/end 的场景):\r\n * notice 错误摘要并释放 inflight 槽 + 删除表情;turn 进行中的错误由 turn/end 报告,跳过防双发。\r\n */\r\n handleAgentError(sessionId: string, errorText: string): void {\r\n const rt = this.sessions.get(sessionId)\r\n if (rt === undefined || rt.turn !== undefined) return\r\n const detail = truncateDetail(errorText, this.maxErrorDetailChars)\r\n this.enqueue(rt, async () => {\r\n if (rt.reply !== undefined) await rt.reply.notice(`出错了:${detail}`)\r\n const ack = rt.inflight?.ack\r\n rt.inflight = undefined\r\n if (ack !== undefined) await ack()\r\n })\r\n }\r\n\r\n private enqueue(rt: SessionRuntime, task: () => Promise<void>): void {\r\n rt.tail = rt.tail.then(task).catch((error) => {\r\n this.onError(`[project-bot] 出站处理失败:${error instanceof Error ? error.message : String(error)}`)\r\n })\r\n }\r\n}\r\n","/** 入站:指令分流 → 路由 → 单 in-flight 准入 → 表情回复 → 图片落附件库 → followup 投递。 */\r\nimport { createUserMessage } from '@deepseek-ai/dsh-llm'\r\nimport type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'\r\nimport type { BotRecord } from '../bots/store.ts'\r\nimport type { InboundMessage } from './channel.ts'\r\nimport { parseDirective } from './directive.ts'\r\nimport { truncateDetail } from './outbound.ts'\r\nimport type { Router } from './router.ts'\r\n\r\n/** 图片附件库端口(宿主 ctx.attachments 的窄化;缺席时图片降级为提示)。 */\r\nexport interface AttachmentsPort {\r\n saveImages(inputs: readonly { data: Uint8Array; mediaType: string; name?: string }[]): Promise<readonly ImageAttachmentRef[]>\r\n}\r\n\r\nexport interface InboundDeps {\r\n router: Router\r\n bots: { get(botId: string): BotRecord | undefined }\r\n maxErrorDetailChars: number\r\n /** 可选:宿主附件服务的惰性取用器(消息时解析;apply 期服务注册未必就绪)。 */\r\n attachments?: () => AttachmentsPort | undefined\r\n onError(message: string): void\r\n}\r\n\r\nexport class Inbound {\r\n constructor(private readonly deps: InboundDeps) {}\r\n\r\n onMessage(msg: InboundMessage): void {\r\n void this.handle(msg).catch(async (error) => {\r\n // 摘要一并回传渠道:dsh web 终端不展示插件 warn,通用文案无法定位(2026-09-03 /new 事故)。\r\n const detail = truncateDetail(error instanceof Error ? error.message : String(error), this.deps.maxErrorDetailChars)\r\n this.deps.onError(`[project-bot] 入站处理失败:${detail}`)\r\n await msg.reply.notice(`处理失败:${detail}`).catch(() => undefined)\r\n })\r\n }\r\n\r\n private async handle(msg: InboundMessage): Promise<void> {\r\n const bot = this.deps.bots.get(msg.botId)\r\n if (bot === undefined) return\r\n\r\n const directive = parseDirective(msg.text)\r\n if (directive === 'new') {\r\n await this.deps.router.reset(bot, msg.chatId, msg.reply, msg.userId)\r\n await msg.reply.notice('已开启新会话')\r\n return\r\n }\r\n if (directive === 'stop') {\r\n const rt = this.deps.router.lookup(bot.id, msg.chatId)\r\n if (rt?.inflight !== undefined) {\r\n rt.agent.cancel()\r\n await msg.reply.notice('已请求停止当前任务')\r\n } else {\r\n await msg.reply.notice('当前没有进行中的任务')\r\n }\r\n return\r\n }\r\n if (directive === 'status') {\r\n const rt = this.deps.router.lookup(bot.id, msg.chatId)\r\n await msg.reply.notice(rt === undefined\r\n ? `项目:${bot.project}\\n会话:未创建(发送消息即创建)`\r\n : `项目:${bot.project}\\n会话:${rt.sessionId}\\n状态:${rt.inflight !== undefined ? '处理中' : '空闲'}`)\r\n return\r\n }\r\n\r\n const rt = await this.deps.router.ensure(bot, msg.chatId, msg.reply, msg.userId)\r\n if (rt.inflight !== undefined) {\r\n await msg.reply.notice('上一条还在处理中,请稍候(或发送 /stop 取消)')\r\n return\r\n }\r\n // 准入:先占槽再异步;表情回复失败不阻塞处理。\r\n // reply 句柄只在准入通过后刷新——忙时消息不抢走运行中 turn 的出站。\r\n rt.inflight = { ack: undefined }\r\n rt.reply = msg.reply\r\n rt.inflight.ack = (await msg.ackProcessing().catch(() => undefined)) ?? undefined\r\n // source kind 用 'user'(与 ACP 同款):dsh sessionTitle 服务只接纳 user 消息生成会话标题。\r\n // 图片:in-flight 窗口内懒下载(不占飞书 WS 3 秒窗口)→ 落附件库 → image 内容块。\r\n const imageRefs: ImageAttachmentRef[] = []\r\n if (msg.loadImages !== undefined) {\r\n const images = await msg.loadImages()\r\n if (images.length > 0) {\r\n const attachments = this.deps.attachments?.()\r\n if (attachments === undefined) {\r\n await msg.reply.notice('当前环境暂不支持图片消息(附件服务不可用),已按文字部分处理')\r\n } else {\r\n imageRefs.push(...await attachments.saveImages(images))\r\n }\r\n }\r\n }\r\n const message = createUserMessage({\r\n content: [\r\n ...(msg.text.length > 0 ? [{ type: 'text' as const, text: msg.text }] : []),\r\n ...imageRefs.map((ref) => ({ type: 'image' as const, attachment: ref })),\r\n ],\r\n source: { kind: 'user' },\r\n })\r\n try {\r\n rt.agent.followup(message)\r\n } catch (error) {\r\n const ack = rt.inflight.ack\r\n rt.inflight = undefined\r\n await ack?.()\r\n throw error\r\n }\r\n }\r\n}\r\n","/** 核心对宿主 agents 服务 / 绑定表的结构化端口(测试用 fake 注入)。 */\r\nimport type { BotRecord } from '../bots/store.ts'\r\nimport type { Disposer, ReplyHandle, TurnSegment } from './channel.ts'\r\n\r\nexport interface AgentPort {\r\n readonly sessionId: string\r\n /** 入参须为 @deepseek-ai/dsh-llm 的 createUserMessage 产物(裸字符串缺 source,turn 管线读 source.kind 崩溃)。 */\r\n followup(message: unknown): void\r\n cancel(): void\r\n whenIdle(): Promise<void>\r\n}\r\n\r\n/** 一个创作期注册到 agent 系统提示的提示段(name/order/text 与 LayerConfig 同构)。 */\r\nexport interface AgentSection {\r\n name: string\r\n order: number\r\n text: string\r\n}\r\n\r\n/** 创作期注入(真实适配器里映射为 setup(agentCtx) 内的 mount/section/restrict)。 */\r\nexport interface AgentHooks {\r\n persona?: string\r\n tools?: readonly string[]\r\n /** 绑定角色时逐层注册的提示段(name = `dsh-agent-toolkit:agent:<layer>`)。 */\r\n sections?: readonly AgentSection[]\r\n}\r\n\r\nexport interface AgentsPort {\r\n create(input: {\r\n sessionId: string\r\n cwd: string\r\n agentOptions?: { provider?: string; model?: string }\r\n hooks: AgentHooks\r\n }): Promise<AgentPort>\r\n resume(input: {\r\n sessionId: string\r\n agentOptions?: { provider?: string; model?: string }\r\n hooks: AgentHooks\r\n }): Promise<AgentPort>\r\n}\r\n\r\n/** main 形态会话(bot 未自配 agentOptions 时)与未配置模型的角色的模型来源(取 {provider, model})。 */\r\nexport type DefaultModelAccessor = () => { provider: string; model: string }\r\n\r\n/** 会话归属:把 session 挂到 cwd 对应 workspace(宿主侧幂等;无则自动建)。 */\r\nexport interface WorkspacePort {\r\n attach(cwd: string, sessionId: string): Promise<void>\r\n}\r\n\r\nexport interface BindingStore {\r\n get(botId: string, chatId: string): string | undefined\r\n set(botId: string, chatId: string, sessionId: string): Promise<void>\r\n delete(botId: string, chatId: string): Promise<void>\r\n /** 删除某 bot 的全部绑定(bot 被删除时)。 */\r\n deleteBot(botId: string): Promise<void>\r\n}\r\n\r\n/** 一个活跃会话的运行时状态(inbound/outbound 共享)。 */\r\nexport interface SessionRuntime {\r\n readonly botId: string\r\n readonly chatId: string\r\n readonly sessionId: string\r\n /** 会话发起人的渠道 open_id(审批卡片越权校验用;ensure/reset 的 userId 落入)。 */\r\n readonly initiatorOpenId: string\r\n agent: AgentPort\r\n /** 最近一次入站消息携带的回复句柄(回复永远回到 chat)。 */\r\n reply: ReplyHandle | undefined\r\n /** 单会话单 in-flight 槽;ack = 表情回复的 disposer。 */\r\n inflight: { ack: Disposer | undefined } | undefined\r\n /** 出站操作串行化 Promise 链(保序)。 */\r\n tail: Promise<unknown>\r\n /** 当前 turn 归集状态;无进行中 turn 为 undefined。 */\r\n turn: { n: number; segments: TurnSegment[]; began: boolean } | undefined\r\n /**\r\n * retire 后仍在 sessions 中收尾(等 whenIdle + tail 落定才摘除,让旧卡 finalize)期间为 true:\r\n * ensure 不得复用收尾中的 runtime(其 agent 已 cancel),重绑窗口须 resume + adopt 重建。\r\n */\r\n retiring: boolean\r\n}\r\n\r\n/** 从 bot 记录提取创作期注入(主 Agent 绑定形态)。 */\r\nexport function hooksOf(bot: BotRecord): AgentHooks {\r\n return {\r\n ...(bot.persona !== undefined ? { persona: bot.persona } : {}),\r\n ...(bot.tools !== undefined ? { tools: bot.tools } : {}),\r\n }\r\n}\r\n","/** 角色形态会话装配(Router bot 会话与 schedule 执行器共用):persona 单 section + tools 白名单 + 模型解析。 */\r\nimport type { AgentRecord } from '../agents/store.ts'\r\nimport type { AgentHooks, DefaultModelAccessor } from './ports.ts'\r\n\r\n/** 角色 persona 的 scoped 段名(与 Router 既有产出一致,逐字段不可改)。 */\r\nexport const ROLE_PERSONA_SECTION = 'dsh-agent-toolkit:agent:persona'\r\n\r\n/** 角色形态创作期注入:persona 非空 → 单 section(order 0);tools 白名单存在 → 带上(由 setupAgentScope restrict)。 */\r\nexport function roleHooks(role: AgentRecord): AgentHooks {\r\n const sections = role.persona === undefined || role.persona.trim().length === 0\r\n ? []\r\n : [{ name: ROLE_PERSONA_SECTION, order: 0, text: role.persona }]\r\n return {\r\n ...(sections.length > 0 ? { sections } : {}),\r\n ...(role.tools !== undefined ? { tools: role.tools.allow } : {}),\r\n }\r\n}\r\n\r\n/** 角色模型:自配优先,缺省回退宿主默认模型(与 Router 语义一致)。 */\r\nexport function roleAgentOptions(\r\n role: AgentRecord,\r\n defaultModel: DefaultModelAccessor,\r\n): { provider?: string; model?: string } {\r\n return role.model ?? defaultModel()\r\n}\r\n","/** 绑定路由:(botId, chatId) → 长期会话;create / resume / reset。 */\r\nimport { randomUUID } from 'node:crypto'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport type { BotRecord } from '../bots/store.ts'\r\nimport type { ReplyHandle } from './channel.ts'\r\nimport { hooksOf, type AgentHooks, type AgentSection, type AgentsPort, type BindingStore, type DefaultModelAccessor, type SessionRuntime, type WorkspacePort } from './ports.ts'\r\nimport { roleAgentOptions, roleHooks } from './role-assembly.ts'\r\n\r\n/** 发起人提示段名:bot 会话声明来源渠道与发起人 open_id。 */\r\nexport const SENDER_SECTION_NAME = 'dsh-agent-toolkit:channel:sender'\r\n\r\n/** sender 段文本(单聊语义;channel 取 BotRecord.channel,未来新渠道零改动透传)。 */\r\nexport function senderSectionText(channel: string, userId: string): string {\r\n return `本会话由 ${channel} 渠道的单聊会话发起。发起人 ID(${channel} open_id):\\`${userId}\\`。`\r\n}\r\n\r\nexport class Router {\r\n constructor(\r\n private readonly agents: AgentsPort,\r\n private readonly bindings: BindingStore,\r\n /** sessionId → runtime(进程内活跃会话表,与 bindings 持久表互补)。 */\r\n private readonly sessions: Map<string, SessionRuntime>,\r\n /** main 形态会话(bot 未自配 agentOptions 时)与未配置模型的角色的模型来源(宿主默认模型)。 */\r\n private readonly defaultModel: DefaultModelAccessor,\r\n /** 会话归入 bot 项目 workspace(与原生 UI session.create 同款挂载)。 */\r\n private readonly workspace: WorkspacePort,\r\n private readonly onWarn: (message: string) => void,\r\n /** Agent 注册表(agentRef → main/角色),会话创建时决定 persona/工具/模型装配。 */\r\n private readonly registry: AgentRegistry,\r\n /** 开启时向 hooks.sections 末尾追加渠道发起人提示段。 */\r\n private readonly injectSender = true,\r\n ) {}\r\n\r\n /**\r\n * 取(或建/恢复)该 chat 的会话 runtime。存量活跃会话保持其 reply——运行中 turn 的出站\r\n * 必须留在原句柄收尾,reply 刷新由 Inbound 在 in-flight 准入通过后执行;\r\n * retiring(已 cancel、收尾中)的会话不可复用,重绑窗口内恢复时 resume + adopt 重建。\r\n */\r\n async ensure(bot: BotRecord, chatId: string, reply: ReplyHandle, userId: string): Promise<SessionRuntime> {\r\n const bound = this.bindings.get(bot.id, chatId)\r\n if (bound !== undefined) {\r\n const existing = this.sessions.get(bound)\r\n // 活跃会话不替换 reply:运行中 turn 的出站必须留在原句柄收尾;\r\n // reply 的刷新由 Inbound 在 in-flight 准入通过后执行。\r\n if (existing !== undefined && !existing.retiring) return existing\r\n const agent = await this.agents.resume({ sessionId: bound, ...this.resolveSession(bot, userId) })\r\n await this.attach(bot.project, bound)\r\n return this.adopt(bot.id, chatId, userId, bound, agent, reply)\r\n }\r\n const sessionId = randomUUID()\r\n const agent = await this.agents.create({ sessionId, cwd: bot.project, ...this.resolveSession(bot, userId) })\r\n await this.bindings.set(bot.id, chatId, sessionId)\r\n await this.attach(bot.project, sessionId)\r\n return this.adopt(bot.id, chatId, userId, sessionId, agent, reply)\r\n }\r\n\r\n /** attach 失败仅告警(会话降级为未分组),不阻塞消息处理。 */\r\n private async attach(cwd: string, sessionId: string): Promise<void> {\r\n try {\r\n await this.workspace.attach(cwd, sessionId)\r\n } catch (error) {\r\n this.onWarn(`[project-bot] 会话 ${sessionId} 挂载 workspace 失败:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n }\r\n\r\n /** injectSender 开启时向 hooks.sections 末尾追加 sender 段(主/角色形态通用)。 */\r\n private withSenderSection(hooks: AgentHooks, bot: BotRecord, userId: string): AgentHooks {\r\n if (!this.injectSender) return hooks\r\n const section: AgentSection = { name: SENDER_SECTION_NAME, order: 20, text: senderSectionText(bot.channel ?? 'unknown', userId) }\r\n return { ...hooks, sections: [...(hooks.sections ?? []), section] }\r\n }\r\n\r\n /**\r\n * 按 bot.agentRef 解析会话组装(agentOptions + 创作期 hooks):\r\n * - 缺省/指向 main → 主 Agent 形态:bot 自带 persona/tools + 模型(自配 agentOptions 优先,缺省回退宿主默认模型);\r\n * - 指向角色 → 角色形态:persona 单 section + tools.restrict + role.model;\r\n * - 指向不存在角色 → warn 并降级为主 Agent 形态。\r\n */\r\n private resolveSession(bot: BotRecord, userId: string): { agentOptions: { provider?: string; model?: string }; hooks: AgentHooks } {\r\n const ref = bot.agentRef ?? 'main'\r\n const role = this.registry.get(ref)\r\n if (role === undefined || ref === 'main') {\r\n if (role === undefined && ref !== 'main') {\r\n this.onWarn(`[project-bot] bot \"${bot.id}\" 的 agentRef \"${ref}\" 不存在,降级绑定主 Agent`)\r\n }\r\n return { agentOptions: bot.agentOptions ?? this.defaultModel(), hooks: this.withSenderSection(hooksOf(bot), bot, userId) }\r\n }\r\n return {\r\n agentOptions: roleAgentOptions(role, this.defaultModel),\r\n hooks: this.withSenderSection(roleHooks(role), bot, userId),\r\n }\r\n }\r\n\r\n /** /new:取消旧会话;等 turn/end 落定(旧卡在旧句柄 finalize)后再摘出 sessions。 */\r\n async reset(bot: BotRecord, chatId: string, reply: ReplyHandle, userId: string): Promise<SessionRuntime> {\r\n const bound = this.bindings.get(bot.id, chatId)\r\n if (bound !== undefined) {\r\n const old = this.sessions.get(bound)\r\n if (old !== undefined) this.retire(bound, old)\r\n await this.bindings.delete(bot.id, chatId)\r\n }\r\n return this.ensure(bot, chatId, reply, userId)\r\n }\r\n\r\n /** 取消会话并等出站链落定后摘出 sessions(让在飞 turn 的 turn/end 正常 finalize 旧卡)。 */\r\n private retire(sessionId: string, rt: SessionRuntime): void {\r\n rt.retiring = true\r\n rt.agent.cancel()\r\n void (async () => {\r\n await rt.agent.whenIdle().catch(() => undefined)\r\n await rt.tail.catch(() => undefined)\r\n if (this.sessions.get(sessionId) === rt) this.sessions.delete(sessionId)\r\n })()\r\n }\r\n\r\n lookup(botId: string, chatId: string): SessionRuntime | undefined {\r\n const bound = this.bindings.get(botId, chatId)\r\n return bound === undefined ? undefined : this.sessions.get(bound)\r\n }\r\n\r\n private adopt(botId: string, chatId: string, userId: string, sessionId: string, agent: SessionRuntime['agent'], reply: ReplyHandle): SessionRuntime {\r\n const rt: SessionRuntime = {\r\n botId, chatId, sessionId, initiatorOpenId: userId, agent, reply,\r\n inflight: undefined, tail: Promise.resolve(), turn: undefined, retiring: false,\r\n }\r\n this.sessions.set(sessionId, rt)\r\n return rt\r\n }\r\n}\r\n","/** 审批中心(渠道无关):自有 bot 会话的 approval ask → 渠道审批卡片挂起 → 卡片回调 resolve。\r\n * spec: docs/superpowers/specs/2026-09-08-feishu-approval-card-design.md(飞书独占 / 仅发起人 / 不超时)。 */\r\nimport { randomUUID } from 'node:crypto'\r\nimport type { SessionRuntime } from '../ports.ts'\r\n\r\nexport type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable'\r\n\r\n/** waterfall answerer 收到的请求结构(结构子集化,不依赖宿主包类型)。 */\r\nexport interface ApprovalRequestLike {\r\n agent: { session: { id: unknown } }\r\n toolName: string\r\n reason?: string\r\n signal?: AbortSignal\r\n}\r\n\r\n/** 发给渠道的审批卡片内容。 */\r\nexport interface ApprovalPrompt {\r\n key: string\r\n chatId: string\r\n botName: string\r\n toolName: string\r\n reason?: string\r\n}\r\n\r\n/** 一次已展示的审批:finalize 把卡片定格为终态(实现内部 fire-and-forget 友好,失败自告警)。 */\r\nexport interface ApprovalPresentation {\r\n finalize(status: 'allowed' | 'rejected' | 'cancelled', operatorName?: string): Promise<void>\r\n}\r\n\r\n/** 渠道侧审批能力:发卡 → 返回定格句柄。 */\r\nexport interface ApprovalPresenter {\r\n present(prompt: ApprovalPrompt): Promise<ApprovalPresentation>\r\n}\r\n\r\n/** channelFor 的返回:该 bot 的审批能力 + 展示名。 */\r\nexport interface ApprovalChannel {\r\n presenter: ApprovalPresenter\r\n botName: string\r\n}\r\n\r\n/** 渠道回调入核的卡片动作(渠道已解析成渠道无关形态)。 */\r\nexport interface CardActionInput {\r\n chatId: string\r\n operatorOpenId: string\r\n operatorName?: string\r\n value: unknown\r\n}\r\n\r\n/** 回调应答(飞书侧经 WS 响应帧回 toast)。 */\r\nexport interface CardActionAck {\r\n toast?: string\r\n}\r\n\r\ninterface PendingEntry {\r\n sessionId: string\r\n resolve(outcome: ApprovalOutcome): void\r\n presentation: ApprovalPresentation\r\n signal: AbortSignal | undefined\r\n onAbort: () => void\r\n}\r\n\r\nexport class ApprovalCenter {\r\n private readonly pending = new Map<string, PendingEntry>()\r\n\r\n constructor(\r\n private readonly sessions: Map<string, SessionRuntime>,\r\n private readonly channelFor: (botId: string) => ApprovalChannel | undefined,\r\n private readonly warn: (message: string) => void,\r\n private readonly newId: () => string = randomUUID,\r\n ) {}\r\n\r\n async handleRequest(req: ApprovalRequestLike): Promise<ApprovalOutcome | undefined> {\r\n const sessionId = String(req.agent.session.id)\r\n const rt = this.sessions.get(sessionId)\r\n if (rt === undefined) return undefined\r\n // 已取消的 ask 不发卡不回退:直接 cancelled(与 api-proxy 的同步 settle 对齐,\r\n // 防 abort 落在注册监听之前的 zombie 窗口)。\r\n if (req.signal?.aborted === true) return 'cancelled'\r\n const channel = this.channelFor(rt.botId)\r\n if (channel === undefined) {\r\n this.warn(`[project-bot] bot \"${rt.botId}\" 的渠道无审批能力,回退其他审批通道`)\r\n return undefined\r\n }\r\n const key = this.newId()\r\n let presentation: ApprovalPresentation\r\n try {\r\n presentation = await channel.presenter.present({\r\n key, chatId: rt.chatId, botName: channel.botName, toolName: req.toolName,\r\n ...(req.reason !== undefined ? { reason: req.reason } : {}),\r\n })\r\n } catch (error) {\r\n this.warn(`[project-bot] 审批卡片发送失败,回退其他审批通道:${error instanceof Error ? error.message : String(error)}`)\r\n return undefined\r\n }\r\n return new Promise<ApprovalOutcome>((resolve) => {\r\n const entry: PendingEntry = {\r\n sessionId, resolve, presentation, signal: req.signal,\r\n onAbort: () => this.settle(key, 'cancelled'),\r\n }\r\n this.pending.set(key, entry)\r\n req.signal?.addEventListener('abort', entry.onAbort, { once: true })\r\n })\r\n }\r\n\r\n handleCardAction(action: CardActionInput): CardActionAck | undefined {\r\n const value = action.value as { key?: unknown; decision?: unknown } | null\r\n if (value === null || typeof value !== 'object' || typeof value.key !== 'string'\r\n || (value.decision !== 'allow' && value.decision !== 'reject')) return undefined\r\n const entry = this.pending.get(value.key)\r\n if (entry === undefined) return { toast: '该申请已处理或已失效' }\r\n const rt = this.sessions.get(entry.sessionId)\r\n if (rt === undefined || rt.initiatorOpenId !== action.operatorOpenId) {\r\n return { toast: '仅会话发起人可审批' }\r\n }\r\n this.settle(value.key, value.decision === 'allow' ? 'allowed-once' : 'rejected', action.operatorName)\r\n return { toast: value.decision === 'allow' ? '已允许' : '已拒绝' }\r\n }\r\n\r\n dispose(): void {\r\n for (const key of [...this.pending.keys()]) this.settle(key, 'cancelled')\r\n }\r\n\r\n private settle(key: string, outcome: ApprovalOutcome, operatorName?: string): void {\r\n const entry = this.pending.get(key)\r\n if (entry === undefined) return\r\n this.pending.delete(key)\r\n entry.signal?.removeEventListener('abort', entry.onAbort)\r\n entry.resolve(outcome)\r\n const status = outcome === 'allowed-once' ? 'allowed' : outcome === 'rejected' ? 'rejected' : 'cancelled'\r\n void entry.presentation.finalize(status, operatorName).catch((error: unknown) => {\r\n this.warn(`[project-bot] 审批卡片定格失败:${error instanceof Error ? error.message : String(error)}`)\r\n })\r\n }\r\n}\r\n","/** BotRuntime:bot 名册 → 渠道生命周期;聚合 router/inbound/outbound。 */\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport { bindingKey, type Binding, type BotRecord } from '../bots/store.ts'\r\nimport type { BotChannel, ChannelHandle, ChannelStatus, ChannelTunables } from './channel.ts'\r\nimport { Inbound } from './inbound.ts'\r\nimport { Outbound } from './outbound.ts'\r\nimport type { AgentsPort, BindingStore, DefaultModelAccessor, SessionRuntime, WorkspacePort } from './ports.ts'\r\nimport { Router } from './router.ts'\r\nimport type { AttachmentsPort } from './inbound.ts'\r\nimport { ApprovalCenter } from './approval/center.ts'\r\n\r\nexport interface RuntimeDeps {\r\n bots: KvTable<string, BotRecord>\r\n bindings: KvTable<string, Binding>\r\n agents: AgentsPort\r\n /** Agent 注册表(agentRef → main/角色),Router 会话创建时决定 persona/工具/模型装配。 */\r\n registry: AgentRegistry\r\n /** main 形态会话(bot 未自配 agentOptions 时)与未配置模型的角色回退宿主默认模型。 */\r\n defaultModel: DefaultModelAccessor\r\n /** 会话归入 bot 项目 workspace。 */\r\n workspace: WorkspacePort\r\n channels: ReadonlyMap<string, BotChannel>\r\n tunables: ChannelTunables\r\n /** 回传渠道的错误摘要最大字符数。 */\r\n maxErrorDetailChars: number\r\n /** 可选:宿主附件服务的惰性取用器(消息时解析;返回 undefined = 图片降级提示)。 */\r\n attachments?: () => AttachmentsPort | undefined\r\n /** 发起人提示段开关(缺省 true;见 Config feishu.injectSender)。 */\r\n injectSender?: boolean\r\n resolveSecret(ref: string): Promise<string | undefined>\r\n validateProject(path: string): boolean\r\n log: { warn(message: string): void; info(message: string): void }\r\n}\r\n\r\nexport type BotStatus = ChannelStatus | 'not-running' | 'unbound'\r\n\r\nexport class BotRuntime {\r\n readonly sessions = new Map<string, SessionRuntime>()\r\n readonly router: Router\r\n readonly inbound: Inbound\r\n readonly outbound: Outbound\r\n readonly approval: ApprovalCenter\r\n private readonly handles = new Map<string, ChannelHandle>()\r\n\r\n constructor(private readonly deps: RuntimeDeps) {\r\n const bindingStore = this.bindingStore()\r\n this.router = new Router(deps.agents, bindingStore, this.sessions, deps.defaultModel, deps.workspace, (m) => deps.log.warn(m), deps.registry, deps.injectSender ?? true)\r\n this.inbound = new Inbound({\r\n router: this.router,\r\n bots: deps.bots,\r\n maxErrorDetailChars: deps.maxErrorDetailChars,\r\n ...(deps.attachments !== undefined ? { attachments: deps.attachments } : {}),\r\n onError: (m) => deps.log.warn(m),\r\n })\r\n this.outbound = new Outbound(this.sessions, (m) => deps.log.warn(m), deps.maxErrorDetailChars)\r\n this.approval = new ApprovalCenter(\r\n this.sessions,\r\n (botId) => {\r\n const presenter = this.handles.get(botId)?.approval\r\n if (presenter === undefined) return undefined\r\n return { presenter, botName: this.deps.bots.get(botId)?.name ?? botId }\r\n },\r\n (m) => deps.log.warn(m),\r\n )\r\n }\r\n\r\n async startAll(): Promise<void> {\r\n for (const botId of [...this.deps.bots.keys()]) await this.reconcile(botId)\r\n }\r\n\r\n /** 按最新记录重建该 bot 的渠道(创建/更新后调用;记录已删或未绑定则纯停止)。 */\r\n async reconcile(botId: string): Promise<void> {\r\n await this.stopChannel(botId)\r\n const record = this.deps.bots.get(botId)\r\n if (record === undefined) return\r\n // 未绑定(channel/feishu 均缺省)的 bot:停渠道即止,不启动不告警。\r\n if (record.feishu === undefined || record.channel === undefined) return\r\n if (!this.deps.validateProject(record.project)) {\r\n this.deps.log.warn(`[project-bot] bot \"${botId}\" 的项目路径不可用:${record.project}`)\r\n return\r\n }\r\n const secret = await this.deps.resolveSecret(record.feishu.appSecretRef)\r\n if (secret === undefined) {\r\n this.deps.log.warn(`[project-bot] bot \"${botId}\" 的密钥 ${record.feishu.appSecretRef} 未配置`)\r\n return\r\n }\r\n const channel = this.deps.channels.get(record.channel)\r\n if (channel === undefined) {\r\n this.deps.log.warn(`[project-bot] bot \"${botId}\" 的渠道 \"${record.channel}\" 未实现`)\r\n return\r\n }\r\n try {\r\n const handle = await channel.start(\r\n { record, secret },\r\n { onMessage: (msg) => this.inbound.onMessage(msg), onCardAction: (action) => this.approval.handleCardAction(action) },\r\n this.deps.tunables,\r\n (m) => this.deps.log.warn(m),\r\n )\r\n this.handles.set(botId, handle)\r\n } catch (error) {\r\n this.deps.log.warn(`[project-bot] bot \"${botId}\" 渠道启动失败:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n }\r\n\r\n /** 删除 bot:停渠道、取消会话、清绑定。 */\r\n async stopBot(botId: string): Promise<void> {\r\n await this.stopChannel(botId)\r\n for (const [sessionId, rt] of [...this.sessions]) {\r\n if (rt.botId === botId) this.retire(sessionId, rt)\r\n }\r\n await this.bindingStore().deleteBot(botId)\r\n }\r\n\r\n /** 解绑渠道:停渠道、取消在飞会话;绑定表与持久会话保留(重绑后 resume 接续)。 */\r\n async unbindBot(botId: string): Promise<void> {\r\n await this.stopChannel(botId)\r\n for (const [sessionId, rt] of [...this.sessions]) {\r\n if (rt.botId === botId) this.retire(sessionId, rt)\r\n }\r\n }\r\n\r\n /** 取消会话并等出站链落定后摘出 sessions(让在飞 turn 的 turn/end 正常 finalize 旧卡)。 */\r\n private retire(sessionId: string, rt: SessionRuntime): void {\r\n rt.retiring = true\r\n rt.agent.cancel()\r\n void (async () => {\r\n await rt.agent.whenIdle().catch(() => undefined)\r\n await rt.tail.catch(() => undefined)\r\n if (this.sessions.get(sessionId) === rt) this.sessions.delete(sessionId)\r\n })()\r\n }\r\n\r\n statusOf(botId: string): BotStatus {\r\n const record = this.deps.bots.get(botId)\r\n if (record !== undefined && record.feishu === undefined) return 'unbound'\r\n return this.handles.get(botId)?.status() ?? 'not-running'\r\n }\r\n\r\n /** 卸载时序:取消在飞会话 → 等 idle → drain 出站链(卡片定格)→ 断全部渠道。 */\r\n async stopAll(): Promise<void> {\r\n for (const rt of this.sessions.values()) rt.agent.cancel()\r\n await Promise.allSettled([...this.sessions.values()].map(async (rt) => {\r\n await rt.agent.whenIdle().catch(() => undefined)\r\n await rt.tail\r\n }))\r\n await Promise.allSettled([...this.handles.values()].map((h) => h.close()))\r\n this.handles.clear()\r\n this.approval.dispose()\r\n }\r\n\r\n private async stopChannel(botId: string): Promise<void> {\r\n const handle = this.handles.get(botId)\r\n if (handle === undefined) return\r\n this.handles.delete(botId)\r\n await handle.close().catch((error) => {\r\n this.deps.log.warn(`[project-bot] bot \"${botId}\" 渠道关闭异常:${error instanceof Error ? error.message : String(error)}`)\r\n })\r\n }\r\n\r\n private bindingStore(): BindingStore {\r\n const { bindings } = this.deps\r\n return {\r\n get: (b, c) => bindings.get(bindingKey(b, c))?.sessionId,\r\n set: async (b, c, s) => { await bindings.put(bindingKey(b, c), { sessionId: s }) },\r\n delete: async (b, c) => { await bindings.delete(bindingKey(b, c)) },\r\n deleteBot: async (b) => {\r\n for (const key of [...bindings.keys()]) {\r\n if (key.startsWith(`${b}:`)) await bindings.delete(key)\r\n }\r\n },\r\n }\r\n }\r\n}\r\n","/** preset 优先的 agent scope joiner:agentPresets 在场且 mount 成功 → 父链是 preset standing mount,\n * 宿主 spawn 驱动的 composeFrom 能认父(委派子会话继承同一组合);失败回退 toolsScope(bot 可用性优先)。 */\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { ToolsScope } from './tool-scope.ts'\n\n/** setupAgentScope 的作用域加入策略(ToolsScope 结构兼容:join 返回 unknown 使 Promise<ScopeKey> 可赋,\n * void 返回类型过窄——TS 严格模式 object 不可赋给 void)。 */\nexport interface ScopeJoiner {\n join(agentCtx: Context): Promise<unknown>\n}\n\n/** agentPresets 服务的挂载面结构类型(可选服务经 ctx.get 读取,team-preset.ts AgentPresetsLike 先例)。 */\ninterface PresetMountLike {\n mount(agentCtx: Context, id?: string): Promise<unknown>\n}\n\nexport function createScopeJoiner(ctx: Context, presetId: string, fallback: ToolsScope, warn: (msg: string) => void): ScopeJoiner {\n return {\n async join(agentCtx) {\n // join 时惰性解析(attachments 教训:apply 期一次性捕获会吃到未注册的 undefined)。\n const agentPresets = ctx.get('agentPresets', false) as PresetMountLike | undefined\n if (agentPresets !== undefined) {\n try {\n await agentPresets.mount(agentCtx, presetId)\n return\n } catch (error) {\n warn(`dsh-agent-toolkit: bot 会话挂载 preset \"${presetId}\" 失败,回退基础工具 standing scope(此后该会话委派子会话将看不到基础工具):${error instanceof Error ? error.message : String(error)}`)\n }\n }\n await fallback.join(agentCtx)\n },\n }\n}\n","/** 基础工具行的 standing scope:工具挂进祖先 scope 层,agent 加入后 restrict 才能过滤继承面。 */\nimport type { Context, Plugin } from '@deepseek-ai/cordis'\nimport { bindScopeParent, createScope, scopeOf, type Scope, type ScopeKey } from '@deepseek-ai/dsh-scope'\nimport { BASIC_TOOLS } from './basic-tools.ts'\n\n/** 工具行模块加载器(测试注入 fake;生产经动态 import 解析宿主 node_modules 中的插件包)。 */\nexport type ToolModuleLoader = (specifier: string) => Promise<Plugin>\n\n/** 默认加载器:复刻 preset mount 的模块解析——loader 的 unwrapExports 取 `default ?? 命名导出模块`。 */\nasync function loadToolModule(specifier: string): Promise<Plugin> {\n const mod: unknown = await import(specifier)\n return ((mod as { default?: unknown }).default ?? mod) as Plugin\n}\n\n/** 基础工具行 standing scope 的持有者:join 把 agent scope 挂到工具层下,dispose 随插件卸载。 */\nexport interface ToolsScope {\n /**\n * 把 agent scope 父链挂到 standing scope(工具成为继承面),并在返回前等首轮\n * 挂载落定(agent factory 会等 setup 完成,工具插件不会晚于首个 turn 就绪)。\n * agent scope 已有父链时抛错(bot 会话的 scope 父链由本方法独占绑定)。\n */\n join(agentCtx: Context): Promise<ScopeKey>\n /** 释放 standing scope(插件卸载时调用;此后 join 会按需重建)。 */\n dispose(): Promise<void>\n}\n\n/** 建一个 bot 会话共用的工具行 standing scope(所有 bot 会话挂同一套 BASIC_TOOLS)。 */\nexport function createToolsScope(ctx: Context, loadTool: ToolModuleLoader = loadToolModule): ToolsScope {\n let scope: Scope | undefined\n let mount: Promise<ScopeKey> | undefined\n let generation = 0\n\n function ensure(): Promise<ScopeKey> {\n mount ??= (async () => {\n // 失败重试换新 key:避免与失败代次的层残留状态纠缠。\n const key: ScopeKey = { origin: 'dsh-agent-toolkit', kind: 'bots-tools', gen: ++generation }\n const created = createScope(ctx, key)\n scope = created\n try {\n for (const tool of BASIC_TOOLS) {\n await created.ctx.plugin(await loadTool(tool.id), tool.config)\n }\n } catch (error) {\n if (scope === created) scope = undefined\n mount = undefined\n await created.dispose().catch(() => undefined)\n throw error\n }\n return key\n })()\n return mount\n }\n\n return {\n async join(agentCtx) {\n const agentKey = scopeOf(agentCtx)\n if (agentKey === undefined) {\n throw new Error('tools-scope: refusing to join an unscoped agent context; per-agent composition requires a scope key')\n }\n const standing = await ensure()\n bindScopeParent(agentKey, standing)\n return standing\n },\n async dispose() {\n mount = undefined\n const current = scope\n scope = undefined\n await current?.dispose()\n },\n }\n}\n","/** approval/request waterfall answerer 工厂:自有 bot 会话走 ApprovalCenter(飞书卡片),\r\n * 其余 next() 透传(web api-proxy / ACP 等)。prepend 注册抢在 api-proxy 前(其从不 next 让出)。 */\r\nimport type { ApprovalCenter, ApprovalOutcome, ApprovalRequestLike } from './center.ts'\r\n\r\nexport function createApprovalAnswerer(\r\n centerOf: () => ApprovalCenter | undefined,\r\n): (req: ApprovalRequestLike, next: () => Promise<ApprovalOutcome>) => Promise<ApprovalOutcome> {\r\n return async (req, next) => {\r\n const outcome = await centerOf()?.handleRequest(req)\r\n return outcome ?? next()\r\n }\r\n}\r\n","/** 浏览器半 RPC:单前缀路由 /dsh-agent-toolkit/api/bots + 内部路径分发。 */\r\nimport { randomBytes } from 'node:crypto'\r\nimport type { IncomingMessage, ServerResponse } from 'node:http'\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport { z } from 'zod'\r\nimport type { BotRuntime } from '../channels/runtime.ts'\r\nimport type { RegisterAppService } from './register-app.ts'\r\nimport { BOT_ID_RE, BotRecordSchema, CREDENTIAL_REF_RE, FEISHU_APP_ID_RE, type BotRecord } from './store.ts'\r\n\r\n/** 一个可选的 provider 路由(id = agentOptions.provider 的值)。 */\r\nexport interface ProviderOption { id: string; name: string }\r\n/** 一个可选的模型条目(id = agentOptions.model 的值)。 */\r\nexport interface ModelOption { id: string; name: string }\r\n\r\nexport interface ApiDeps {\r\n bots: KvTable<string, BotRecord>\r\n runtime: BotRuntime\r\n registerApp: RegisterAppService\r\n listTools(): string[]\r\n listProviders(): ProviderOption[]\r\n /** 失败由调用方(路由)兜底为空数组,不抛错。 */\r\n listModels(provider: string): Promise<ModelOption[]>\r\n /** 密钥入 credentials,返回 CredentialRef 字符串。 */\r\n storeSecret(key: string, secret: string): Promise<string>\r\n deleteSecret(ref: string): Promise<void>\r\n validateProject(path: string): boolean\r\n now(): number\r\n}\r\n\r\nconst MAX_BODY_BYTES = 64 * 1024\r\n\r\nconst CreateBodySchema = z.object({\r\n /** 缺省时后端自动生成(bot-<8 位随机小写字母数字>)。 */\r\n id: z.string().regex(BOT_ID_RE).optional(),\r\n name: z.string().min(1).max(64),\r\n project: z.string().min(1),\r\n persona: z.string().max(8000).optional(),\r\n /** 绑定的 Agent('main' 或注册表角色 id;缺省 = main)。 */\r\n agentRef: z.string().min(1).optional(),\r\n tools: z.array(z.string().min(1)).min(1).optional(),\r\n agentOptions: z.object({ provider: z.string().min(1).optional(), model: z.string().min(1).optional() }).optional(),\r\n feishu: z.object({\r\n appId: z.string().regex(FEISHU_APP_ID_RE),\r\n /** 手动填写路径:明文密钥(立即入 credentials,不落表)。 */\r\n appSecret: z.string().min(1).optional(),\r\n /** 扫码路径:registerApp 已入库,直接给引用。 */\r\n appSecretRef: z.string().regex(CREDENTIAL_REF_RE).optional(),\r\n }),\r\n})\r\n\r\nconst UpdateBodySchema = z.object({\r\n name: z.string().min(1).max(64).optional(),\r\n project: z.string().min(1).optional(),\r\n persona: z.string().max(8000).nullable().optional(),\r\n agentRef: z.string().min(1).nullable().optional(),\r\n tools: z.array(z.string().min(1)).min(1).nullable().optional(),\r\n agentOptions: z.object({ provider: z.string().min(1).optional(), model: z.string().min(1).optional() }).nullable().optional(),\r\n /** 重绑:明文新密钥(立即入 credentials)或扫码引用(已入库);null = 解绑渠道(删密钥、保留会话绑定)。 */\r\n feishu: z.object({\r\n appId: z.string().regex(FEISHU_APP_ID_RE),\r\n appSecret: z.string().min(1).optional(),\r\n appSecretRef: z.string().regex(CREDENTIAL_REF_RE).optional(),\r\n }).refine((f) => f.appSecret !== undefined || f.appSecretRef !== undefined, { message: '缺少 appSecret 或 appSecretRef' })\r\n .nullable().optional(),\r\n})\r\n\r\nfunction json(res: ServerResponse, code: number, body: unknown): void {\r\n res.writeHead(code, { 'content-type': 'application/json' }).end(JSON.stringify(body))\r\n}\r\n\r\nconst ID_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789'\r\n\r\n/** 生成 bot-<8 位随机小写字母数字>(符合 BOT_ID_RE);与现有 id 冲突时重试。 */\r\nfunction generateBotId(occupied: (id: string) => boolean): string {\r\n for (;;) {\r\n const bytes = randomBytes(8)\r\n let id = 'bot-'\r\n for (let i = 0; i < 8; i++) id += ID_CHARS[bytes[i] % ID_CHARS.length]\r\n if (!occupied(id)) return id\r\n }\r\n}\r\n\r\n/** 读 JSON body;超限 413 / 非法 JSON 400(已写响应时返回 undefined)。 */\r\nasync function readJsonBody(req: IncomingMessage, res: ServerResponse): Promise<unknown | undefined> {\r\n const chunks: Buffer[] = []\r\n let received = 0\r\n for await (const chunk of req) {\r\n const buffer = chunk as Buffer\r\n received += buffer.byteLength\r\n if (received > MAX_BODY_BYTES) {\r\n json(res, 413, { error: 'body too large' })\r\n req.destroy()\r\n return undefined\r\n }\r\n chunks.push(buffer)\r\n }\r\n try {\r\n return JSON.parse(Buffer.concat(chunks).toString('utf8'))\r\n } catch {\r\n json(res, 400, { error: 'invalid JSON body' })\r\n return undefined\r\n }\r\n}\r\n\r\nexport function createApiHandler(deps: ApiDeps): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\r\n return async (req, res) => {\r\n const url = new URL(req.url ?? '/', 'http://127.0.0.1')\r\n const sub = url.pathname.replace(/^\\/dsh-agent-toolkit\\/api\\/bots/, '') || '/'\r\n const method = req.method ?? 'GET'\r\n\r\n if (sub === '/bots' && method === 'GET') {\r\n const bots = [...deps.bots.entries()].map(([, record]) => ({ ...record, status: deps.runtime.statusOf(record.id) }))\r\n json(res, 200, { bots })\r\n return\r\n }\r\n\r\n if (sub === '/bots' && method === 'POST') {\r\n const body = await readJsonBody(req, res)\r\n if (body === undefined) return\r\n const parsed = CreateBodySchema.safeParse(body)\r\n if (!parsed.success) {\r\n json(res, 400, { error: parsed.error.issues[0]?.message ?? 'invalid body' })\r\n return\r\n }\r\n const input = parsed.data\r\n const id = input.id ?? generateBotId((candidate) => deps.bots.get(candidate) !== undefined)\r\n if (deps.bots.get(id) !== undefined) {\r\n json(res, 409, { error: `bot id \"${id}\" 已存在` })\r\n return\r\n }\r\n for (const [, existing] of deps.bots.entries()) {\r\n if (existing.feishu !== undefined && existing.feishu.appId === input.feishu.appId) {\r\n json(res, 409, { error: `appId 已被 bot \"${existing.id}\" 使用` })\r\n return\r\n }\r\n }\r\n if (!deps.validateProject(input.project)) {\r\n json(res, 400, { error: `项目路径不可用:${input.project}` })\r\n return\r\n }\r\n let appSecretRef = input.feishu.appSecretRef\r\n if (appSecretRef === undefined) {\r\n if (input.feishu.appSecret === undefined) {\r\n json(res, 400, { error: '缺少 appSecret 或 appSecretRef' })\r\n return\r\n }\r\n appSecretRef = await deps.storeSecret(id, input.feishu.appSecret)\r\n }\r\n const record = BotRecordSchema.parse({\r\n id, name: input.name, channel: 'feishu',\r\n feishu: { appId: input.feishu.appId, appSecretRef },\r\n project: input.project,\r\n ...(input.persona !== undefined ? { persona: input.persona } : {}),\r\n ...(input.agentRef !== undefined ? { agentRef: input.agentRef } : {}),\r\n ...(input.tools !== undefined ? { tools: input.tools } : {}),\r\n ...(input.agentOptions !== undefined ? { agentOptions: input.agentOptions } : {}),\r\n createdAt: deps.now(), updatedAt: deps.now(),\r\n } satisfies BotRecord)\r\n await deps.bots.put(record.id, record)\r\n await deps.runtime.reconcile(record.id)\r\n json(res, 200, { bot: { ...record, status: deps.runtime.statusOf(record.id) } })\r\n return\r\n }\r\n\r\n if (sub === '/bots' && method === 'PUT') {\r\n const id = url.searchParams.get('id') ?? ''\r\n const existing = deps.bots.get(id)\r\n if (existing === undefined) {\r\n json(res, 404, { error: `bot \"${id}\" 不存在` })\r\n return\r\n }\r\n const body = await readJsonBody(req, res)\r\n if (body === undefined) return\r\n const parsed = UpdateBodySchema.safeParse(body)\r\n if (!parsed.success) {\r\n json(res, 400, { error: parsed.error.issues[0]?.message ?? 'invalid body' })\r\n return\r\n }\r\n const input = parsed.data\r\n const project = input.project ?? existing.project\r\n if (!deps.validateProject(project)) {\r\n json(res, 400, { error: `项目路径不可用:${project}` })\r\n return\r\n }\r\n // 重绑路径:appId 先查冲突(未绑定 bot 不占 appId),再做任何副作用。\r\n if (input.feishu !== null && input.feishu !== undefined) {\r\n for (const [, other] of deps.bots.entries()) {\r\n if (other.id !== id && other.feishu?.appId === input.feishu.appId) {\r\n json(res, 409, { error: `appId 已被 bot \"${other.id}\" 使用` })\r\n return\r\n }\r\n }\r\n }\r\n // 渠道副作用:null 解绑(停渠道 + 删旧密钥);对象重绑(新密钥入库或引用 + 旧 ref ≠ 新 ref 时清旧密钥)。\r\n let appSecretRef: string | undefined\r\n if (input.feishu === null) {\r\n await deps.runtime.unbindBot(id)\r\n if (existing.feishu !== undefined) await deps.deleteSecret(existing.feishu.appSecretRef)\r\n } else if (input.feishu !== undefined) {\r\n if (input.feishu.appSecret !== undefined) {\r\n appSecretRef = await deps.storeSecret(id, input.feishu.appSecret)\r\n } else {\r\n appSecretRef = input.feishu.appSecretRef\r\n }\r\n if (existing.feishu !== undefined && existing.feishu.appSecretRef !== appSecretRef) {\r\n await deps.deleteSecret(existing.feishu.appSecretRef)\r\n }\r\n }\r\n const merged: Record<string, unknown> = { ...existing }\r\n if (input.name !== undefined) merged.name = input.name\r\n merged.project = project\r\n merged.updatedAt = deps.now()\r\n if (input.feishu === null) {\r\n delete merged.channel\r\n delete merged.feishu\r\n } else if (input.feishu !== undefined && appSecretRef !== undefined) {\r\n merged.channel = 'feishu'\r\n merged.feishu = { appId: input.feishu.appId, appSecretRef }\r\n }\r\n if (input.persona === null) delete merged.persona\r\n else if (input.persona !== undefined) merged.persona = input.persona\r\n if (input.agentRef === null) delete merged.agentRef\r\n else if (input.agentRef !== undefined) merged.agentRef = input.agentRef\r\n if (input.tools === null) delete merged.tools\r\n else if (input.tools !== undefined) merged.tools = input.tools\r\n if (input.agentOptions === null) delete merged.agentOptions\r\n else if (input.agentOptions !== undefined) merged.agentOptions = input.agentOptions\r\n const record = BotRecordSchema.parse(merged)\r\n await deps.bots.put(id, record)\r\n await deps.runtime.reconcile(id)\r\n json(res, 200, { bot: { ...record, status: deps.runtime.statusOf(id) } })\r\n return\r\n }\r\n\r\n if (sub === '/bots' && method === 'DELETE') {\r\n const id = url.searchParams.get('id') ?? ''\r\n const existing = deps.bots.get(id)\r\n if (existing === undefined) {\r\n json(res, 404, { error: `bot \"${id}\" 不存在` })\r\n return\r\n }\r\n await deps.runtime.stopBot(id)\r\n await deps.bots.delete(id)\r\n if (existing.feishu !== undefined) await deps.deleteSecret(existing.feishu.appSecretRef)\r\n json(res, 200, { ok: true })\r\n return\r\n }\r\n\r\n if (sub === '/register-app' && method === 'POST') {\r\n json(res, 200, { id: deps.registerApp.start() })\r\n return\r\n }\r\n\r\n if (sub === '/register-app/status' && method === 'GET') {\r\n const id = url.searchParams.get('id') ?? ''\r\n const state = deps.registerApp.get(id)\r\n if (state === undefined) {\r\n json(res, 404, { error: 'register session 不存在' })\r\n return\r\n }\r\n json(res, 200, { state })\r\n return\r\n }\r\n\r\n if (sub === '/tools' && method === 'GET') {\r\n json(res, 200, { tools: deps.listTools() })\r\n return\r\n }\r\n\r\n if (sub === '/providers' && method === 'GET') {\r\n json(res, 200, { providers: deps.listProviders() })\r\n return\r\n }\r\n\r\n if (sub === '/models' && method === 'GET') {\r\n // 模型列举可能走网络(adapter 探测),失败静默降级为空数组。\r\n let models: ModelOption[] = []\r\n try {\r\n models = await deps.listModels(url.searchParams.get('provider') ?? '')\r\n } catch {\r\n models = []\r\n }\r\n json(res, 200, { models })\r\n return\r\n }\r\n\r\n if (['/bots', '/register-app', '/register-app/status', '/tools', '/providers', '/models'].includes(sub)) {\r\n json(res, 405, { error: 'method not allowed' })\r\n return\r\n }\r\n json(res, 404, { error: 'not found' })\r\n }\r\n}\r\n","/** 扫码一键创建飞书应用:lark.registerApp(OAuth 2.0 Device Authorization Grant)的状态机封装。 */\r\nimport { randomUUID } from 'node:crypto'\r\n\r\n/** 扫码创建应用时申请的权限/事件/回调(流式卡片 + 收发消息 + 表情 + 通讯录基础信息 + 审批卡片回传)。\r\n * 故意不加 as const:readonly 元组不可赋值给 SDK AppAddons 的 mutable string[],\r\n * 否则 bots/index.ts 的 lark.registerApp(options) 透传会 typecheck 失败。 */\r\nexport const FEISHU_REGISTER_APP_ADDONS = {\r\n scopes: {\r\n tenant: [\r\n 'im:message',\r\n 'im:message:send_as_bot',\r\n 'cardkit:card:write',\r\n 'contact:user.base:readonly',\r\n ],\r\n },\r\n events: {\r\n items: { tenant: ['im.message.receive_v1'] },\r\n },\r\n callbacks: {\r\n items: ['card.action.trigger'],\r\n },\r\n}\r\n\r\nexport interface QRInfo {\r\n url: string\r\n expireIn: number\r\n}\r\n\r\n/** lark.registerApp 的结构化签名(便于 fake 注入)。 */\r\nexport type RegisterAppFn = (options: {\r\n signal: AbortSignal\r\n addons: typeof FEISHU_REGISTER_APP_ADDONS\r\n onQRCodeReady(info: QRInfo): void\r\n}) => Promise<{ client_id: string; client_secret: string }>\r\n\r\nexport type RegisterState =\r\n | { status: 'pending'; url?: string; expireIn?: number }\r\n | { status: 'done'; appId: string; credentialRef: string }\r\n | { status: 'error'; code: string; description?: string }\r\n\r\nexport interface RegisterAppDeps {\r\n registerApp: RegisterAppFn\r\n /** 把 appSecret 存进 credentials,返回 CredentialRef 字符串。 */\r\n storeSecret(appId: string, secret: string): Promise<string>\r\n timeoutMs: number\r\n newId?: () => string\r\n}\r\n\r\nexport class RegisterAppService {\r\n private readonly sessions = new Map<string, {\r\n state: RegisterState\r\n controller: AbortController\r\n timer: ReturnType<typeof setTimeout>\r\n }>()\r\n\r\n constructor(private readonly deps: RegisterAppDeps) {}\r\n\r\n /** 发起一轮扫码创建;返回轮询 id。 */\r\n start(): string {\r\n const id = (this.deps.newId ?? randomUUID)()\r\n const controller = new AbortController()\r\n const entry = {\r\n state: { status: 'pending' } as RegisterState,\r\n controller,\r\n timer: setTimeout(() => { controller.abort() }, this.deps.timeoutMs),\r\n }\r\n this.sessions.set(id, entry)\r\n void this.deps.registerApp({\r\n signal: controller.signal,\r\n addons: FEISHU_REGISTER_APP_ADDONS,\r\n onQRCodeReady: (info) => {\r\n entry.state = { status: 'pending', url: info.url, expireIn: info.expireIn }\r\n },\r\n }).then(async (result) => {\r\n const credentialRef = await this.deps.storeSecret(result.client_id, result.client_secret)\r\n entry.state = { status: 'done', appId: result.client_id, credentialRef }\r\n }).catch((error: unknown) => {\r\n const e = error as { code?: unknown; description?: unknown }\r\n entry.state = {\r\n status: 'error',\r\n code: typeof e.code === 'string' ? e.code : 'unknown',\r\n ...(typeof e.description === 'string' ? { description: e.description } : {}),\r\n }\r\n }).finally(() => {\r\n clearTimeout(entry.timer)\r\n })\r\n return id\r\n }\r\n\r\n get(id: string): RegisterState | undefined {\r\n return this.sessions.get(id)?.state\r\n }\r\n\r\n /** 卸载:中断全部进行中的轮询。 */\r\n dispose(): void {\r\n for (const entry of this.sessions.values()) {\r\n entry.controller.abort()\r\n clearTimeout(entry.timer)\r\n }\r\n this.sessions.clear()\r\n }\r\n}\r\n","/** bots 模块:项目机器人(飞书渠道)——多 bot 作为项目 agent 的交互入口(project-bot Node 半迁移,去 preset 化)。 */\r\nimport { existsSync } from 'node:fs'\r\nimport type { IncomingMessage, ServerResponse } from 'node:http'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { SessionId } from '@deepseek-ai/dsh-session'\r\nimport { credentialRef } from '@deepseek-ai/dsh-credentials'\r\nimport type { ImageAttachmentRef, ImageMediaType } from '@deepseek-ai/dsh-attachment'\r\n// type-only 导入激活各包对 cordis Context 的声明合并(inject 的服务属性)。\r\nimport type {} from '@deepseek-ai/dsh-system-prompt'\r\nimport type {} from '@deepseek-ai/dsh-tools'\r\nimport type {} from '@deepseek-ai/dsh-host-webserver'\r\nimport type {} from '@deepseek-ai/dsh-llm'\r\nimport type {} from '@deepseek-ai/dsh-agent-default-model'\r\n// Side-effect type import: declaration-merges the `approval/request` waterfall event\r\n// answered below(照 host api-proxy.ts L87-90 同款;type-only,bundle 期擦除无运行时依赖)。\r\nimport type {} from '@deepseek-ai/dsh-user-approval'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport { openDomainSafely } from '../shared/storage.ts'\r\nimport { registerOptionalRoutes } from '../shared/webserver.ts'\r\nimport { createAgentsPort } from '../channels/agents-port.ts'\r\nimport type { BotChannel, ChannelTunables } from '../channels/channel.ts'\r\nimport { feishuChannel } from '../channels/feishu/index.ts'\r\nimport type { AttachmentsPort } from '../channels/inbound.ts'\r\nimport type { WorkspacePort } from '../channels/ports.ts'\r\nimport { BotRuntime } from '../channels/runtime.ts'\r\nimport { createScopeJoiner, type ScopeJoiner } from '../channels/scope-joiner.ts'\r\nimport { createToolsScope } from '../channels/tool-scope.ts'\r\nimport { createApprovalAnswerer } from '../channels/approval/answerer.ts'\r\nimport { createApiHandler } from './api.ts'\r\nimport { RegisterAppService } from './register-app.ts'\r\nimport { projectBotDomain, type Binding, type BotRecord } from './store.ts'\r\n\r\n/** project-bot Config 的 9 个全局可调参数(字段名不变;schemastery 定义与默认值源:archive/2026-08-26-merged-plugins/project-bot/src/index.ts:38-45,由 Task 15 平移进 suite Config)。 */\r\nexport interface BotsModuleConfig {\r\n /** 卡片流式更新节流间隔(毫秒)。 */\r\n cardUpdateThrottleMs: number\r\n /** 单卡真实 DSL 字节上限(含结构与转义;平台硬上限 30KB)。 */\r\n cardMaxBytes: number\r\n /** 飞书流式打字机每次打印字符数。 */\r\n cardPrintStep: number\r\n /** 过程区(思考 + 工具调用)字节上限(截尾保留最近内容)。 */\r\n processMaxBytes: number\r\n /** 扫码创建应用的轮询超时(毫秒)。 */\r\n registerAppTimeoutMs: number\r\n /** 「处理中」表情回复的 emoji_type。 */\r\n processingReactionEmoji: string\r\n /** 回传飞书的错误摘要最大字符数。 */\r\n errorDetailMaxChars: number\r\n /** 会话创建/恢复时注入「渠道 + 发起人 open_id」提示段(dsh-agent-toolkit:channel:sender)。 */\r\n injectSender: boolean\r\n /** 飞书审批卡片:bot 会话的工具提权申请改由飞书卡片审批(仅会话发起人可点)。 */\r\n approval: boolean\r\n}\r\n\r\n/** setupBots 的宿主接线依赖(registry 供运行时委派/API 消费;prompt 无消费方,Task 13 定案不装配 persona)。 */\r\nexport interface BotsDeps {\r\n registry: AgentRegistry\r\n /** bot 会话挂载的 preset id(agentTeamPreset 开启时下达;undefined = 直接 toolsScope)。 */\r\n botPresetId?: string\r\n /** 插件自有会话 id 集(cron_* 工具门控排除用;缺省不记录)。 */\r\n ownedSessions?: Set<string>\r\n}\r\n\r\nexport function setupBots(ctx: Context, config: BotsModuleConfig, deps: BotsDeps): void {\r\n const log = { warn: (m: string) => ctx.logger.warn(m), info: (m: string) => ctx.logger.info(m) }\r\n const channels: ReadonlyMap<string, BotChannel> = new Map([['feishu', feishuChannel]])\r\n const tunables: ChannelTunables = {\r\n cardUpdateThrottleMs: config.cardUpdateThrottleMs,\r\n cardMaxBytes: config.cardMaxBytes,\r\n processMaxBytes: config.processMaxBytes,\r\n cardPrintStep: config.cardPrintStep,\r\n processingReactionEmoji: config.processingReactionEmoji,\r\n }\r\n\r\n const storeSecret = async (key: string, secret: string): Promise<string> => {\r\n const ref = `project_bot_${key.replace(/[^A-Za-z0-9_]/g, '_')}`\r\n await ctx.credentials.set(credentialRef(ref), secret)\r\n return ref\r\n }\r\n\r\n /** 创作期注入已迁至 agent-setup.ts + tool-scope.ts(基础工具行 standing scope 挂载 + persona/tools)。\r\n * preset 优先 joiner(agent-bot 组合):mount 成功后委派子会话 composeFrom 认父(spec: docs/superpowers/specs/2026-09-07-bot-delegation-preset-mount-design.md)。 */\r\n const toolsScope = createToolsScope(ctx)\r\n // preset 优先:mount 成功后委派子会话 composeFrom 认父;未下达 id 时维持 toolsScope 直挂。\r\n const scopeJoiner: ScopeJoiner = deps.botPresetId !== undefined\r\n ? createScopeJoiner(ctx, deps.botPresetId, toolsScope, log.warn)\r\n : toolsScope\r\n\r\n const agentsPort = createAgentsPort(ctx, scopeJoiner, deps.ownedSessions)\r\n\r\n // workspaceRegistry 是可选服务(ctx.get 非严格模式):缺失时 attach 抛错,\r\n // 由 Router 捕获降级为\"未分组 + 告警\",不阻塞消息处理。\r\n interface WorkspaceRegistryLike {\r\n create(path: string): Promise<{ attachSession(sessionId: SessionId): Promise<void> }>\r\n }\r\n const workspaceRegistry = ctx.get('workspaceRegistry', false) as WorkspaceRegistryLike | undefined\r\n const workspacePort: WorkspacePort = {\r\n async attach(cwd, sessionId) {\r\n if (workspaceRegistry === undefined) throw new Error('workspaceRegistry 服务不可用')\r\n const workspace = await workspaceRegistry.create(cwd)\r\n await workspace.attachSession(SessionId(sessionId))\r\n },\r\n }\r\n\r\n // attachments 是可选服务:**消息到达时惰性解析**(宿主 read-image 同款\"执行时再查\")。\r\n // apply 期一次性捕获不可靠——attachment-local 的 fiber 可能尚未注册完服务,\r\n // 启动期 ctx.get 拿到 undefined 会让图片消息永远走降级提示(2026-09-03 实测踩坑)。\r\n interface AttachmentsStoreLike {\r\n saveImages(inputs: readonly { data: Uint8Array; mediaType: string; name?: string }[]): Promise<readonly ImageAttachmentRef[]>\r\n }\r\n const attachmentsOf = (): AttachmentsPort | undefined => {\r\n const store = ctx.get('attachments', false) as AttachmentsStoreLike | undefined\r\n if (store === undefined) return undefined\r\n return {\r\n async saveImages(inputs) {\r\n // 保存时再取一次(与可用性判断同刻);mediaType 已由渠道按魔数判定为接受的\r\n // 图片类型,store.saveImages 内部按解码字节再验证。\r\n const current = ctx.get('attachments', false) as AttachmentsStoreLike | undefined\r\n if (current === undefined) throw new Error('attachments 服务不可用')\r\n return current.saveImages(inputs.map(({ data, mediaType, name }) => ({\r\n data,\r\n mediaType: mediaType as ImageMediaType,\r\n ...(name !== undefined ? { name } : {}),\r\n })))\r\n },\r\n }\r\n }\r\n\r\n // 存储域:open 失败挂 rejection handler 防次生崩溃,调用方仍感知失败(token-usage 同款)。\r\n // 卸载顺序由 openDomainSafely 的 beforeClose 保证:先等启动链落定、排空在飞会话与出站链\r\n // (stopAll 内含卡片定格 drain),再关存储域——close 一旦开始就拒绝新入队的写。\r\n let botsTable: import('@deepseek-ai/dsh-storage-domain').KvTable<string, BotRecord> | undefined\r\n let bindingsTable: import('@deepseek-ai/dsh-storage-domain').KvTable<string, Binding> | undefined\r\n let runtime: BotRuntime | undefined\r\n let started: Promise<void> = Promise.resolve()\r\n const domainReady = openDomainSafely(\r\n ctx,\r\n projectBotDomain,\r\n (msg) => log.warn(msg),\r\n async () => {\r\n await started.catch(() => undefined)\r\n await runtime?.stopAll()\r\n },\r\n ).then((domain) => {\r\n botsTable = domain.table('bots') as import('@deepseek-ai/dsh-storage-domain').KvTable<string, BotRecord>\r\n bindingsTable = domain.table('bindings') as import('@deepseek-ai/dsh-storage-domain').KvTable<string, Binding>\r\n return domain\r\n })\r\n\r\n const registerAppService = new RegisterAppService({\r\n registerApp: (options) => import('@larksuiteoapi/node-sdk').then((lark) => lark.registerApp(options)),\r\n storeSecret,\r\n timeoutMs: config.registerAppTimeoutMs,\r\n })\r\n\r\n started = domainReady.then(() => {\r\n runtime = new BotRuntime({\r\n bots: botsTable!,\r\n bindings: bindingsTable!,\r\n agents: agentsPort,\r\n registry: deps.registry,\r\n defaultModel: () => {\r\n const selection = ctx.agentDefaultModel.currentSelection()\r\n return { provider: selection.provider, model: selection.model }\r\n },\r\n workspace: workspacePort,\r\n channels,\r\n tunables,\r\n maxErrorDetailChars: config.errorDetailMaxChars,\r\n attachments: attachmentsOf,\r\n injectSender: config.injectSender,\r\n resolveSecret: async (ref) => (await ctx.credentials.resolve(credentialRef(ref)))?.value,\r\n validateProject: (path) => existsSync(path),\r\n log,\r\n })\r\n return runtime.startAll()\r\n })\r\n started.catch((error) => {\r\n log.warn(`[project-bot] 启动失败:${error instanceof Error ? error.message : String(error)}`)\r\n })\r\n\r\n // 出站:持久会话事件 → runtime.outbound(session id 匹配自有 runtime,其余忽略)。\r\n ctx.on('session/event', (session, event) => {\r\n runtime?.outbound.handleSessionEvent(String(session.header.id), event as { type: string; data: Record<string, unknown> })\r\n })\r\n\r\n // 审批 answerer:prepend 抢在 web api-proxy 全局 answerer 之前(其从不 next 让出);\r\n // runtime 未启动/非自有会话/发卡失败时 createApprovalAnswerer 内部 next() 透传,行为回到现状。\r\n if (config.approval) {\r\n ctx.on('approval/request', createApprovalAnswerer(() => runtime?.approval), { prepend: true })\r\n }\r\n\r\n // turn 外错误(无 turn/end 兜底):agent/error → notice 错误摘要 + 释放 inflight(outbound 内去重)。\r\n ctx.on('agent/error', ({ agent, error }) => {\r\n const text = error instanceof Error\r\n ? error.message\r\n : String((error as { message?: unknown } | null)?.message ?? error)\r\n runtime?.outbound.handleAgentError(String(agent.session.id), text)\r\n })\r\n\r\n // webServer 是可选能力(headless 无此服务):经 registerOptionalRoutes 子 fiber 惰性注册\r\n // (token-usage 同款);子 fiber 未激活时惰性、随父 fiber 卸载而清理。\r\n // 仅注册本模块自己的 /dsh-agent-toolkit/api/bots 前缀;agents/providers/tools 核心端点由\r\n // setupAgentsApi 恒启用注册(同前缀下 longest-prefix 匹配、路径互不重叠),本分支不涉足。\r\n registerOptionalRoutes(ctx, (webCtx) => {\r\n // bots handler 请求时才构造:runtime 在 started 落定后才赋值,注册期捕获会拿到 undefined。\r\n const botsHandler: (req: IncomingMessage, res: ServerResponse) => Promise<void> = async (req, res) => {\r\n if (runtime === undefined) throw new Error('runtime unavailable')\r\n await createApiHandler({\r\n bots: botsTable!,\r\n runtime,\r\n registerApp: registerAppService,\r\n listTools: () => ctx.tools.schemas().map((s) => s.name),\r\n listProviders: () => ctx.llm.listProviders().map(({ id, name }) => ({ id, name })),\r\n listModels: (provider) => ctx.llm.listModels(provider).then((models) => models.map(({ id, name }) => ({ id, name }))),\r\n storeSecret,\r\n deleteSecret: async (ref) => ctx.credentials.unset(credentialRef(ref)),\r\n validateProject: (path) => existsSync(path),\r\n now: () => Date.now(),\r\n })(req, res)\r\n }\r\n const dispose = webCtx.webServer.register({\r\n kind: 'prefix',\r\n path: '/dsh-agent-toolkit/api/bots',\r\n handler: async (req, res) => {\r\n try {\r\n // 请求时才等待自身启动链:避免连带失败与注册期捕获 undefined runtime。\r\n await started\r\n await botsHandler(req, res)\r\n } catch (error) {\r\n res.writeHead(500, { 'content-type': 'application/json' })\r\n .end(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }))\r\n }\r\n },\r\n })\r\n return () => dispose()\r\n })\r\n\r\n // 卸载:释放工具行 standing scope;中断扫码轮询;runtime drain(stopAll)与关存储域的\r\n // 顺序由 openDomainSafely 的 beforeClose 保证。\r\n ctx.effect(() => async () => {\r\n await toolsScope.dispose()\r\n })\r\n ctx.effect(() => async () => {\r\n registerAppService.dispose()\r\n })\r\n}\r\n","/** agent-bot preset 组合序列化:BASIC_TOOLS → preset 行(bot 会话挂载的最小组合,\n * 委派子会话 composeFrom 认父的前提;spec: docs/superpowers/specs/2026-09-07-bot-delegation-preset-mount-design.md)。 */\nimport yaml from 'js-yaml'\nimport { BASIC_TOOLS, type BasicTool } from '../channels/basic-tools.ts'\n\n/** BASIC_TOOLS 插件包名 → preset 行 id(与 standard/agent-team 的行 id 对齐)。新增 BASIC_TOOLS 行必须在此登记。 */\nconst ROW_IDS: Record<string, string> = {\n '@deepseek-ai/dsh-persona': 'persona',\n '@deepseek-ai/dsh-agent-instructions': 'agent-instructions',\n '@deepseek-ai/dsh-tool-pwsh': 'tool-pwsh',\n '@deepseek-ai/dsh-tool-bash': 'tool-bash',\n '@deepseek-ai/dsh-tool-fs': 'tool-fs',\n '@deepseek-ai/dsh-tool-fs-search': 'tool-fs-search',\n}\n\nexport const BOT_PRESET_NAME = 'Bot 会话'\nexport const BOT_PRESET_DESCRIPTION = '飞书 bot 会话组合:基础工具行(persona/instructions/shell/fs/fs-search);委派子会话经 composeFrom 继承同一组合'\n\n/** BASIC_TOOLS → preset 行对象数组(未登记映射的包名抛错,防新增工具行静默丢 id)。 */\nexport function serializeBotRows(tools: readonly BasicTool[]): Record<string, unknown>[] {\n return tools.map((tool) => {\n const rowId = ROW_IDS[tool.id]\n if (rowId === undefined) throw new Error(`bot-preset: BASIC_TOOLS 行 ${tool.id} 未登记 preset 行 id 映射`)\n return { id: rowId, name: tool.id, ...tool.config !== undefined ? { config: tool.config } : {} }\n })\n}\n\n/** agent-bot composition 文本(平台相关 shell 行已由 BASIC_TOOLS 选定,不用 !!js)。 */\nexport function botPresetComposition(): string {\n return yaml.dump(serializeBotRows(BASIC_TOOLS), { lineWidth: -1 })\n}\n","/**\r\n * Agent 团队 preset 自动生成:派生宿主当前 shipped standard composition,\r\n * 文本级禁用 subagent 工具族 4 个行,写入首个 trust=user 的 preset root。\r\n * 设计:docs/superpowers/specs/2026-09-02-agent-team-preset-design.md\r\n */\r\nimport { access, mkdir, readFile, writeFile } from 'node:fs/promises'\r\nimport { join, resolve } from 'node:path'\r\nimport yaml from 'js-yaml'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { expandHomePath } from '@deepseek-ai/dsh-home-paths'\r\nimport { botPresetComposition, BOT_PRESET_NAME, BOT_PRESET_DESCRIPTION } from './bot-preset.ts'\r\n\r\n/** 本功能的可调配置(Config schema 在 ../index.ts)。 */\r\nexport interface AgentTeamPresetConfig {\r\n /** 总开关:false 时启动不生成/刷新 preset。 */\r\n enabled: boolean\r\n /** 生成的 preset id(即目录名)。 */\r\n id: string\r\n /** 源 preset id,读其 composition 做派生。 */\r\n source: string\r\n /** preset.yml 的显示名。 */\r\n name: string\r\n /** preset.yml 的描述。 */\r\n description: string\r\n /** bot 会话挂载的最小 preset id(内容 = BASIC_TOOLS 5 行)。 */\r\n botsId: string\r\n}\r\n\r\n/** 禁用目标行:覆盖与 team_delegate 竞争/配套的 5 个模型可见工具所属的 4 个行。 */\r\nexport const TEAM_PRESET_DISABLED_ROWS = [\r\n 'tool-subagent',\r\n 'tool-subagent-fork',\r\n 'tool-subagent-control',\r\n 'tool-subagent-list-agents',\r\n] as const\r\n\r\n/**\r\n * 文本级锚点改写:对 4 个目标行各插入一行 `disabled: true`(缩进 = 锚点缩进 + 2 空格)。\r\n * 锚点是整行精确匹配 `- id: <行id>`(忽略首尾空白),防 tool-subagent 误中\r\n * tool-subagent-fork / tool-subagent-control 前缀;锚点所属块内(锚点行之后、\r\n * 首个缩进 <= 锚点缩进的非空行之前)已有 `disabled:` 键则跳过——既幂等,也避免\r\n * 与宿主已有的 `disabled: !!js ...` 撞出 YAML 重复键。锚点缺失 warn 并跳过该锚点,\r\n * 其余照常。除插入行外文本逐字节不变。\r\n */\r\nexport function disableSubagentRows(source: string, warn: (msg: string) => void): string {\r\n const lines = source.split('\\n')\r\n for (const row of TEAM_PRESET_DISABLED_ROWS) {\r\n const anchor = `- id: ${row}`\r\n const index = lines.findIndex((line) => line.trim() === anchor)\r\n if (index === -1) {\r\n warn(`dsh-agent-toolkit: agent-team preset 锚点行 \"${anchor}\" 在源 composition 中缺失,已跳过`)\r\n continue\r\n }\r\n const indent = lines[index].length - lines[index].trimStart().length\r\n let hasDisabled = false\r\n for (let i = index + 1; i < lines.length; i += 1) {\r\n const line = lines[i]\r\n if (line.trim() === '') continue\r\n if (line.length - line.trimStart().length <= indent) break\r\n if (/^\\s*disabled\\s*:/.test(line)) {\r\n hasDisabled = true\r\n break\r\n }\r\n }\r\n if (hasDisabled) continue\r\n lines.splice(index + 1, 0, `${' '.repeat(indent + 2)}disabled: true`)\r\n }\r\n return lines.join('\\n')\r\n}\r\n\r\n// 三个文件名镜像宿主 @deepseek-ai/dsh-agent-presets 的 COMPOSITION_FILE / METADATA_FILE\r\n// 契约(文件名即 discovery 协议);不 import 宿主常量,避免新增运行时耦合。\r\nconst COMPOSITION_FILE = 'agent.cordis.yml'\r\nconst METADATA_FILE = 'preset.yml'\r\n/**\r\n * 生成目录的归属标记:无此标记的同名目录视为用户手工 preset,不覆盖。\r\n * 标记必须在 mkdir 后最先写入(marker-first):这样写 composition/metadata 失败留下的是\r\n * 带标记的半成品目录,下次启动会被正常重写自愈;若最后才写标记,则半成品目录无标记、\r\n * 会被误判为用户手工 preset 而永久卡死不覆盖。\r\n */\r\nconst MARKER_FILE = '.generated-by'\r\nconst MARKER_CONTENT = 'dsh-agent-toolkit'\r\n/** 镜像宿主 PRESET_ID:preset id 即目录名,正则白名单是路径逃逸的 containment 边界。 */\r\nconst PRESET_ID = /^[a-z0-9][a-z0-9-]*$/\r\n\r\nconst GENERATED_HEADER = '# 本文件由 dsh-agent-toolkit 自动生成,勿手改(每次启动重写)。\\n'\r\n\r\n/**\r\n * agentPresets 服务的结构类型。可选服务经 ctx.get 读取(宿主约定:可选服务用\r\n * ctx.get,不进 inject),结构类型避免对 @deepseek-ai/dsh-agent-presets 的依赖\r\n *(bots/index.ts 的 WorkspaceRegistryLike 先例)。\r\n */\r\ninterface AgentPresetsLike {\r\n readonly roots: readonly { path: string; trust: 'system' | 'user' }[]\r\n read(id: string): Promise<string>\r\n}\r\n\r\n/**\r\n * 写一个生成 preset 目录:无标记的同名用户目录不覆盖(warn 返回 false);marker-first 写入。\r\n * composition / metadata 写失败(含半途失败)留下的带标记目录,下次启动会被正常重写自愈。\r\n */\r\nasync function writeGeneratedPreset(\r\n dir: string,\r\n composition: string,\r\n metadata: { name: string; description: string },\r\n warn: (msg: string) => void,\r\n): Promise<boolean> {\r\n const markerPath = join(dir, MARKER_FILE)\r\n let dirExists = true\r\n try {\r\n await access(dir)\r\n } catch {\r\n dirExists = false\r\n }\r\n if (dirExists) {\r\n let marked = false\r\n try {\r\n marked = (await readFile(markerPath, 'utf8')).trim() === MARKER_CONTENT\r\n } catch {\r\n // 无标记文件 = 用户手工同名 preset。\r\n }\r\n if (!marked) {\r\n warn(`dsh-agent-toolkit: ${dir} 已存在且非本插件生成,不覆盖,跳过生成`)\r\n return false\r\n }\r\n }\r\n await mkdir(dir, { recursive: true })\r\n await writeFile(markerPath, `${MARKER_CONTENT}\\n`, 'utf8')\r\n await writeFile(join(dir, COMPOSITION_FILE), composition, 'utf8')\r\n await writeFile(join(dir, METADATA_FILE), yaml.dump(metadata, { lineWidth: -1 }), 'utf8')\r\n return true\r\n}\r\n\r\n/**\r\n * 启动时生成/刷新 agent-team 与 agent-bot 两个 preset。所有失败路径 warn 降级,不影响插件其余功能。\r\n * 不设为默认 preset、卸载不删目录(可能有会话在用;composition 不引用 toolkit 行,残留 preset 自身\r\n * 仍可用)。每次启动重写:standing mount 按文件代际,重写只影响新会话。agent-bot 内容来自 BASIC_TOOLS,\r\n * 不依赖源 preset 读取(read 失败只跳过 agent-team);两块独立 try/catch、独立 marker 保护。\r\n */\r\nexport async function setupAgentTeamPreset(ctx: Context, config: AgentTeamPresetConfig): Promise<void> {\r\n if (!config.enabled) return\r\n const warn = (msg: string): void => { ctx.logger.warn(msg) }\r\n // rc2 等无 presets 的旧宿主:静默跳过(旧宿主无 subagent/team_delegate 工具竞争问题)。\r\n const agentPresets = ctx.get('agentPresets', false) as AgentPresetsLike | undefined\r\n if (agentPresets === undefined) return\r\n // 提前解析 trust=user root 供两块共用;缺席时两者都跳过。\r\n const root = agentPresets.roots.find((r) => r.trust === 'user')\r\n if (root === undefined) {\r\n warn('dsh-agent-toolkit: preset roots 中无 trust=user 的目录,跳过 agent-team / agent-bot 生成')\r\n return\r\n }\r\n const presetDir = (id: string): string => join(resolve(expandHomePath(root.path)), id)\r\n\r\n // agent-team:派生源 preset,文本级禁用 subagent 工具族 4 行;read 失败只跳过本块。\r\n if (!PRESET_ID.test(config.id)) {\r\n warn(`dsh-agent-toolkit: agentTeamPreset.id \"${config.id}\" 不是合法 preset id,跳过 agent-team 生成`)\r\n } else {\r\n let source: string | undefined\r\n try {\r\n source = await agentPresets.read(config.source)\r\n } catch (error) {\r\n warn(`dsh-agent-toolkit: 读取源 preset \"${config.source}\" 失败,跳过 agent-team 生成:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n if (source !== undefined) {\r\n const dir = presetDir(config.id)\r\n try {\r\n await writeGeneratedPreset(\r\n dir,\r\n GENERATED_HEADER + disableSubagentRows(source, warn),\r\n { name: config.name, description: config.description },\r\n warn,\r\n )\r\n } catch (error) {\r\n warn(`dsh-agent-toolkit: 写入 agent-team preset 失败(${dir}):${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n }\r\n }\r\n\r\n // botsId 与 id 相同:agent-bot 块会覆盖 agent-team 的 composition + preset.yml,直接跳过(agent-team 照常生成)。\r\n if (config.id === config.botsId) {\r\n warn(`dsh-agent-toolkit: agentTeamPreset.id 与 agentTeamPreset.botsId 相同(均为 \"${config.id}\"),跳过 agent-bot 生成`)\r\n } else {\r\n // agent-bot:bot 会话挂载的最小组合,内容来自 BASIC_TOOLS,不依赖源 preset 读取。\r\n if (!PRESET_ID.test(config.botsId)) {\r\n warn(`dsh-agent-toolkit: agentTeamPreset.botsId \"${config.botsId}\" 不是合法 preset id,跳过 agent-bot 生成`)\r\n } else {\r\n try {\r\n await writeGeneratedPreset(\r\n presetDir(config.botsId),\r\n GENERATED_HEADER + botPresetComposition(),\r\n { name: BOT_PRESET_NAME, description: BOT_PRESET_DESCRIPTION },\r\n warn,\r\n )\r\n } catch (error) {\r\n warn(`dsh-agent-toolkit: 写入 agent-bot preset 失败:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n }\r\n }\r\n}\r\n","/** schedule 模块存储域声明:CronTask/CronRun 记录 schema + domain 布局的单一来源。*/\r\nimport { z } from 'zod'\r\nimport { defineDomain, domainTable, type KvTable } from '@deepseek-ai/dsh-storage-domain'\r\n\r\n/** 调度规则三选一:cron(5 字段,可选 IANA 时区,省略 = 进程时区)/ at(RFC 3339 一次性)/ every(≥60s,创建时间为锚)。*/\r\nexport const CronScheduleSchema = z.discriminatedUnion('kind', [\r\n z.object({ kind: z.literal('cron'), expr: z.string().min(1), timeZone: z.string().min(1).optional() }),\r\n z.object({ kind: z.literal('at'), at: z.string().min(1) }),\r\n z.object({ kind: z.literal('every'), seconds: z.number().int().min(60) }),\r\n])\r\nexport type CronSchedule = z.infer<typeof CronScheduleSchema>\r\n\r\n/** 执行目标:主 Agent(宿主默认模型,无 persona/restrict)或注册表角色(persona/model/工具白名单随角色)。*/\r\nexport const CronTargetSchema = z.discriminatedUnion('kind', [\r\n z.object({ kind: z.literal('main') }),\r\n z.object({ kind: z.literal('role'), roleId: z.string().min(1) }),\r\n])\r\nexport type CronTarget = z.infer<typeof CronTargetSchema>\r\n\r\nexport const CronTaskSchema = z.object({\r\n id: z.string().min(1),\r\n name: z.string().min(1).max(64),\r\n prompt: z.string().min(1).max(8000),\r\n cwd: z.string().min(1),\r\n schedule: CronScheduleSchema,\r\n target: CronTargetSchema,\r\n catchup: z.boolean(),\r\n enabled: z.boolean(),\r\n /** 调度器维护的持久缓存(重启 rearm 依据),UTC ISO 串。*/\r\n nextRunAt: z.string().nullable(),\r\n createdAt: z.string(),\r\n updatedAt: z.string(),\r\n})\r\nexport type CronTask = z.infer<typeof CronTaskSchema>\r\n\r\nexport const CronRunSchema = z.object({\r\n id: z.string().min(1),\r\n taskId: z.string().min(1),\r\n triggeredAt: z.string(),\r\n finishedAt: z.string().optional(),\r\n status: z.enum(['running', 'ok', 'error', 'skipped-overlap']),\r\n /** 本次执行新建的会话 id(skipped-overlap 无会话)。*/\r\n sessionId: z.string().optional(),\r\n /** 错误摘要(截断)。*/\r\n error: z.string().optional(),\r\n})\r\nexport type CronRun = z.infer<typeof CronRunSchema>\r\n\r\n/** domain 名/表名均受 UNIT_NAME_RE 约束(^[a-z][a-z0-9_]*$),不允许连字符。*/\r\nexport const scheduleDomain = defineDomain({\r\n name: 'dsh_agent_toolkit_schedule',\r\n version: 1,\r\n tables: {\r\n tasks: domainTable<string, CronTask>(CronTaskSchema),\r\n runs: domainTable<string, CronRun>(CronRunSchema),\r\n // 一次性标记位(沿用 agents store 的 meta 模式;当前无标记消费者,保留表位)。\r\n meta: domainTable<string, { value: string }>(z.object({ value: z.string() })),\r\n },\r\n})\r\n\r\n/** 某任务的 run 列表(新 → 旧;同刻按 id 倒序稳定化)。*/\r\nexport function listRuns(runs: KvTable<string, CronRun>, taskId: string): CronRun[] {\r\n return [...runs.entries()]\r\n .map(([, run]) => run)\r\n .filter((run) => run.taskId === taskId)\r\n .sort((a, b) => b.triggeredAt.localeCompare(a.triggeredAt) || b.id.localeCompare(a.id))\r\n}\r\n\r\n/** 环形保留某任务最近 limit 条 run,超出删最旧。*/\r\nexport async function trimRuns(runs: KvTable<string, CronRun>, taskId: string, limit: number): Promise<void> {\r\n const mine = listRuns(runs, taskId)\r\n for (const run of mine.slice(limit)) await runs.delete(run.id)\r\n}\r\n\r\n/** 删除任务连带清运行历史。*/\r\nexport async function deleteRunsOf(runs: KvTable<string, CronRun>, taskId: string): Promise<void> {\r\n for (const run of listRuns(runs, taskId)) await runs.delete(run.id)\r\n}\r\n","/** 定时任务浏览器半 RPC:单前缀路由 /dsh-agent-toolkit/api/cron + 内部路径分发(bots/api.ts 同款骨架)。 */\r\nimport type { IncomingMessage, ServerResponse } from 'node:http'\r\nimport { z } from 'zod'\r\nimport { json, readJsonBody } from '../shared/http.ts'\r\nimport type { CronService, CronTaskInput } from './service.ts'\r\nimport { CronScheduleSchema, CronTargetSchema } from './store.ts'\r\n\r\nexport interface CronApiDeps {\r\n service: CronService\r\n /** 候选 cwd 列表(workspaceRegistry.list() 的 path 集;服务缺席时调用方给空数组)。 */\r\n listProjects(): string[]\r\n runHistoryLimit: number\r\n}\r\n\r\nconst CreateBodySchema = z.object({\r\n name: z.string().min(1).max(64),\r\n prompt: z.string().min(1).max(8000),\r\n cwd: z.string().min(1),\r\n schedule: CronScheduleSchema,\r\n target: CronTargetSchema,\r\n catchup: z.boolean(),\r\n enabled: z.boolean(),\r\n}) satisfies z.ZodType<CronTaskInput>\r\nconst UpdateBodySchema = CreateBodySchema.partial()\r\n\r\nexport function createCronApiHandler(deps: CronApiDeps): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\r\n return async (req, res) => {\r\n const url = new URL(req.url ?? '/', 'http://127.0.0.1')\r\n const sub = url.pathname.replace(/^\\/dsh-agent-toolkit\\/api\\/cron/, '') || '/'\r\n const method = req.method ?? 'GET'\r\n const taskMatch = /^\\/tasks\\/([^/]+)$/.exec(sub)\r\n const triggerMatch = /^\\/tasks\\/([^/]+)\\/trigger$/.exec(sub)\r\n const runsMatch = /^\\/tasks\\/([^/]+)\\/runs$/.exec(sub)\r\n\r\n if (sub === '/tasks' && method === 'GET') {\r\n json(res, 200, { tasks: deps.service.list() })\r\n return\r\n }\r\n\r\n if (sub === '/tasks' && method === 'POST') {\r\n const body = await readJsonBody(req, res)\r\n if (body === undefined) return\r\n const parsed = CreateBodySchema.safeParse(body)\r\n if (!parsed.success) {\r\n json(res, 400, { error: parsed.error.issues[0]?.message ?? 'invalid body' })\r\n return\r\n }\r\n const result = await deps.service.create(parsed.data)\r\n if (!result.ok) {\r\n json(res, 400, { error: result.error })\r\n return\r\n }\r\n json(res, 200, { task: result.value })\r\n return\r\n }\r\n\r\n if (taskMatch !== null && method === 'PUT') {\r\n const id = decodeURIComponent(taskMatch[1])\r\n if (deps.service.get(id) === undefined) {\r\n json(res, 404, { error: `定时任务 \"${id}\" 不存在` })\r\n return\r\n }\r\n const body = await readJsonBody(req, res)\r\n if (body === undefined) return\r\n const parsed = UpdateBodySchema.safeParse(body)\r\n if (!parsed.success) {\r\n json(res, 400, { error: parsed.error.issues[0]?.message ?? 'invalid body' })\r\n return\r\n }\r\n const result = await deps.service.update(id, parsed.data)\r\n if (!result.ok) {\r\n json(res, 400, { error: result.error })\r\n return\r\n }\r\n json(res, 200, { task: result.value })\r\n return\r\n }\r\n\r\n if (taskMatch !== null && method === 'DELETE') {\r\n const id = decodeURIComponent(taskMatch[1])\r\n if (deps.service.get(id) === undefined) {\r\n json(res, 404, { error: `定时任务 \"${id}\" 不存在` })\r\n return\r\n }\r\n const result = await deps.service.remove(id)\r\n if (!result.ok) {\r\n json(res, 400, { error: result.error })\r\n return\r\n }\r\n json(res, 200, { ok: true })\r\n return\r\n }\r\n\r\n if (triggerMatch !== null && method === 'POST') {\r\n const id = decodeURIComponent(triggerMatch[1])\r\n if (deps.service.get(id) === undefined) {\r\n json(res, 404, { error: `定时任务 \"${id}\" 不存在` })\r\n return\r\n }\r\n const result = await deps.service.trigger(id)\r\n if (!result.ok) {\r\n // 运行中冲突 409;其余(理论上只有不存在,已被预检拦截)400。\r\n json(res, /正在运行/.test(result.error) ? 409 : 400, { error: result.error })\r\n return\r\n }\r\n json(res, 200, { run: result.value })\r\n return\r\n }\r\n\r\n if (runsMatch !== null && method === 'GET') {\r\n const id = decodeURIComponent(runsMatch[1])\r\n if (deps.service.get(id) === undefined) {\r\n json(res, 404, { error: `定时任务 \"${id}\" 不存在` })\r\n return\r\n }\r\n json(res, 200, { runs: deps.service.runsOf(id, deps.runHistoryLimit) })\r\n return\r\n }\r\n\r\n if (sub === '/projects' && method === 'GET') {\r\n json(res, 200, { projects: deps.listProjects() })\r\n return\r\n }\r\n\r\n if (sub === '/tasks' || taskMatch !== null || triggerMatch !== null || runsMatch !== null || sub === '/projects') {\r\n json(res, 405, { error: 'method not allowed' })\r\n return\r\n }\r\n json(res, 404, { error: 'not found' })\r\n }\r\n}\r\n","/** 定时任务执行器:输入一条 task,输出一条 run 记录(建会话 → followup → whenIdle/超时 → 落库)。 */\r\nimport { createUserMessage } from '@deepseek-ai/dsh-llm'\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport { roleAgentOptions, roleHooks } from '../channels/role-assembly.ts'\r\nimport type { AgentHooks, AgentSection, AgentsPort, DefaultModelAccessor, WorkspacePort } from '../channels/ports.ts'\r\nimport { trimRuns, type CronRun, type CronTask } from './store.ts'\r\n\r\n/** 来源段名:声明本会话由定时任务触发(order 20,与渠道 sender 段同位)。 */\r\nexport const TASK_SECTION_NAME = 'dsh-agent-toolkit:schedule:task'\r\n\r\nexport function taskSectionText(task: CronTask, triggeredAt: string): string {\r\n return `本会话由定时任务「${task.name}」(id: ${task.id})于 ${triggeredAt} 触发。`\r\n}\r\n\r\n/** 错误摘要最大字符数(对齐 feishu.errorDetailMaxChars 默认 500)。 */\r\nconst ERROR_MAX_CHARS = 500\r\n\r\nexport interface ExecutorDeps {\r\n agents: AgentsPort\r\n registry: AgentRegistry\r\n /** 宿主默认模型(main 形态与未自配模型的角色的模型来源)。 */\r\n defaultModel: DefaultModelAccessor\r\n workspace: WorkspacePort\r\n runs: KvTable<string, CronRun>\r\n runHistoryLimit: number\r\n /** 单次运行 followup→whenIdle 超时(Config schedule.runTimeoutMinutes × 60_000)。 */\r\n runTimeoutMs: number\r\n warn: (msg: string) => void\r\n now(): number\r\n newSessionId(): string\r\n newRunId(): string\r\n /** 超时计时(测试注入可控 Promise;生产为 setTimeout 包装)。 */\r\n delay(ms: number): Promise<void>\r\n}\r\n\r\nexport interface Executor {\r\n /** 执行一次任务:永不抛错,结果体现在返回的 run 记录。 */\r\n trigger(task: CronTask): Promise<CronRun>\r\n}\r\n\r\nclass RunTimeoutError extends Error {\r\n constructor() { super('timeout') }\r\n}\r\n\r\nexport function createExecutor(deps: ExecutorDeps): Executor {\r\n async function persist(run: CronRun): Promise<void> {\r\n await deps.runs.put(run.id, run)\r\n await trimRuns(deps.runs, run.taskId, deps.runHistoryLimit)\r\n }\r\n\r\n return {\r\n async trigger(task) {\r\n const triggeredAt = new Date(deps.now()).toISOString()\r\n const sessionId = deps.newSessionId()\r\n const run: CronRun = { id: deps.newRunId(), taskId: task.id, triggeredAt, status: 'running', sessionId }\r\n await persist(run)\r\n const finish = async (status: CronRun['status'], error?: string): Promise<CronRun> => {\r\n const done: CronRun = {\r\n ...run,\r\n status,\r\n finishedAt: new Date(deps.now()).toISOString(),\r\n ...(error !== undefined ? { error: error.slice(0, ERROR_MAX_CHARS) } : {}),\r\n }\r\n await persist(done)\r\n return done\r\n }\r\n\r\n // 解析装配(main/role 共用序列,仅装配不同;roleId 缺失降级 main 并 warn,同 Router 语义)。\r\n const source: AgentSection = { name: TASK_SECTION_NAME, order: 20, text: taskSectionText(task, triggeredAt) }\r\n let agentOptions: { provider?: string; model?: string }\r\n let hooks: AgentHooks\r\n const roleId = task.target.kind === 'role' ? task.target.roleId : 'main'\r\n const role = roleId === 'main' ? undefined : deps.registry.get(roleId)\r\n if (roleId === 'main' || role === undefined) {\r\n if (roleId !== 'main' && role === undefined) {\r\n deps.warn(`[schedule] 定时任务 \"${task.id}\" 的角色 \"${roleId}\" 不存在,降级主 Agent 形态`)\r\n }\r\n agentOptions = deps.defaultModel()\r\n hooks = { sections: [source] }\r\n } else {\r\n const base = roleHooks(role)\r\n agentOptions = roleAgentOptions(role, deps.defaultModel)\r\n hooks = { ...base, sections: [...(base.sections ?? []), source] }\r\n }\r\n\r\n let agent\r\n try {\r\n agent = await deps.agents.create({ sessionId, cwd: task.cwd, agentOptions, hooks })\r\n } catch (error) {\r\n return finish('error', error instanceof Error ? error.message : String(error))\r\n }\r\n try {\r\n await deps.workspace.attach(task.cwd, sessionId)\r\n } catch (error) {\r\n // attach 失败仅告警(会话降级为未分组),不阻塞执行——同 Router.attach。\r\n deps.warn(`[schedule] 会话 ${sessionId} 挂载 workspace 失败:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n // 必须经 createUserMessage 包装(裸字符串会让 turn 管线读 message.source.kind 崩溃)。\r\n agent.followup(createUserMessage({\r\n content: [{ type: 'text', text: task.prompt }],\r\n source: { kind: 'user' },\r\n }))\r\n // race 落败方的迟到 rejection 不变 unhandled(先各挂 noop catch;race 自身引用不受影响)。\r\n const idle = agent.whenIdle()\r\n idle.catch(() => undefined)\r\n const timeout = deps.delay(deps.runTimeoutMs).then(() => { throw new RunTimeoutError() })\r\n timeout.catch(() => undefined)\r\n try {\r\n await Promise.race([idle, timeout])\r\n return await finish('ok')\r\n } catch (error) {\r\n if (error instanceof RunTimeoutError) {\r\n agent.cancel()\r\n return await finish('error', `timeout(超过 ${Math.round(deps.runTimeoutMs / 60_000)} 分钟未空闲,已取消)`)\r\n }\r\n return await finish('error', error instanceof Error ? error.message : String(error))\r\n }\r\n },\r\n }\r\n}\r\n","/** cron/at/every 纯时间运算:校验、下一触发点、预览、启动 rearm。全部注入 now,无隐藏时钟。*/\r\nimport { Cron } from 'croner'\r\nimport type { CronSchedule, CronTask } from './store.ts'\r\n\r\n/** croner 选项:paused 仅做解析与预测,不注册真实定时器(计时由调度器 tick 驱动)。*/\r\nfunction cronerOptions(schedule: Extract<CronSchedule, { kind: 'cron' }>): { paused: true; timezone?: string } {\r\n return { paused: true, ...(schedule.timeZone !== undefined ? { timezone: schedule.timeZone } : {}) }\r\n}\r\n\r\n/** 创建/更新即校验;合法返回 undefined,非法返回错误消息(不入库由调用方保证)。*/\r\nexport function validateSchedule(schedule: CronSchedule, nowMs: number): string | undefined {\r\n switch (schedule.kind) {\r\n case 'cron': {\r\n const fields = schedule.expr.trim().split(/\\s+/)\r\n if (fields.length !== 5) return `cron 表达式须为 5 字段(分 时 日 月 周),收到 ${fields.length} 字段;秒级/年字段暂不开放`\r\n if (schedule.timeZone !== undefined) {\r\n try {\r\n new Intl.DateTimeFormat('en-US', { timeZone: schedule.timeZone })\r\n } catch {\r\n return `未知时区:${schedule.timeZone}`\r\n }\r\n }\r\n try {\r\n new Cron(schedule.expr, cronerOptions(schedule))\r\n } catch (error) {\r\n return `非法 cron 表达式\"${schedule.expr}\":${error instanceof Error ? error.message : String(error)}`\r\n }\r\n return undefined\r\n }\r\n case 'at': {\r\n const t = Date.parse(schedule.at)\r\n if (Number.isNaN(t)) return `非法 at 时间(须 RFC 3339):${schedule.at}`\r\n if (t <= nowMs) return `at 时间须在未来:${schedule.at}`\r\n return undefined\r\n }\r\n case 'every':\r\n return undefined // seconds ≥ 60 整数由 schema 保证\r\n }\r\n}\r\n\r\n/** 下一触发点(epoch ms);无未来触发点(at 过期等)返回 null。*/\r\nexport function nextOccurrence(schedule: CronSchedule, createdAtMs: number, nowMs: number): number | null {\r\n switch (schedule.kind) {\r\n case 'cron': {\r\n const next = new Cron(schedule.expr, cronerOptions(schedule)).nextRun(new Date(nowMs))\r\n return next === null ? null : next.getTime()\r\n }\r\n case 'at': {\r\n const t = Date.parse(schedule.at)\r\n return t > nowMs ? t : null\r\n }\r\n case 'every': {\r\n const intervalMs = schedule.seconds * 1000\r\n if (nowMs < createdAtMs) return createdAtMs\r\n // 创建锚点对齐的下一间隔:跳过中间错过的,不枚举积压。\r\n const k = Math.floor((nowMs - createdAtMs) / intervalMs) + 1\r\n return createdAtMs + k * intervalMs\r\n }\r\n }\r\n}\r\n\r\n/** 「未来 count 次触发」预览(epoch ms 数组,长度 ≤ count;供 UI 表单与调试)。*/\r\nexport function previewOccurrences(schedule: CronSchedule, count: number, createdAtMs: number, nowMs: number): number[] {\r\n const out: number[] = []\r\n let cursor = nowMs\r\n for (let i = 0; i < count; i++) {\r\n const next = nextOccurrence(schedule, createdAtMs, cursor)\r\n if (next === null) break\r\n out.push(next)\r\n cursor = next + 1\r\n }\r\n return out\r\n}\r\n\r\n/**\r\n * 启动 rearm:对一条持久化任务重算 enabled/nextRunAt(无变化返回原引用,调用方按引用决定是否写回)。\r\n * - nextRunAt 仍在未来 → 保持;\r\n * - 已过期且 catchup → 设为「立即」(首个 tick 补跑一次);\r\n * - 已过期且非 catchup → 下一未来触发点;没有(at 一次性)→ enabled=false、nextRunAt=null(过期即作废)。\r\n */\r\nexport function rearmTask(task: CronTask, nowMs: number): CronTask {\r\n if (!task.enabled) return task.nextRunAt === null ? task : { ...task, nextRunAt: null }\r\n const persisted = task.nextRunAt === null ? null : Date.parse(task.nextRunAt)\r\n if (persisted !== null && persisted > nowMs) return task\r\n if (persisted !== null && task.catchup) return { ...task, nextRunAt: new Date(nowMs).toISOString() }\r\n const next = nextOccurrence(task.schedule, Date.parse(task.createdAt), nowMs)\r\n return next === null\r\n ? { ...task, enabled: false, nextRunAt: null }\r\n : { ...task, nextRunAt: new Date(next).toISOString() }\r\n}\r\n\r\n/** 创建/更新后的 fresh 重算(catchup 是停机补跑语义,不适用于编辑路径)。*/\r\nexport function recomputeTask(task: CronTask, nowMs: number): CronTask {\r\n if (!task.enabled) return { ...task, nextRunAt: null }\r\n const next = nextOccurrence(task.schedule, Date.parse(task.createdAt), nowMs)\r\n return next === null\r\n ? { ...task, enabled: false, nextRunAt: null }\r\n : { ...task, nextRunAt: new Date(next).toISOString() }\r\n}\r\n\r\n/** 触发/跳过后推进:cron/every 取 now 之后下一触发点;at 一次性作废。*/\r\nexport function advanceAfterTrigger(task: CronTask, nowMs: number): CronTask {\r\n if (task.schedule.kind === 'at') return { ...task, enabled: false, nextRunAt: null }\r\n const next = nextOccurrence(task.schedule, Date.parse(task.createdAt), nowMs)\r\n return next === null\r\n ? { ...task, enabled: false, nextRunAt: null }\r\n : { ...task, nextRunAt: new Date(next).toISOString() }\r\n}\r\n","/** 调度引擎:启动 rearm + 周期 tick + 重叠保护 + 触发后推进。计时由接线层(ctx.interval 30s)驱动。 */\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport { advanceAfterTrigger, rearmTask, recomputeTask } from './timing.ts'\r\nimport { trimRuns, type CronRun, type CronTask } from './store.ts'\r\n\r\nexport interface SchedulerDeps {\r\n tasks: KvTable<string, CronTask>\r\n runs: KvTable<string, CronRun>\r\n runHistoryLimit: number\r\n /** executor.trigger:契约上永不抛错(异常已落 run 记录);仍 catch 兜底。 */\r\n execute(task: CronTask): Promise<unknown>\r\n now(): number\r\n newRunId(): string\r\n warn(msg: string): void\r\n}\r\n\r\nexport interface Scheduler {\r\n /** 启动 rearm:全部任务按 catchup 语义重算(写回有变化的行)。 */\r\n rearmAll(): Promise<void>\r\n /** 一次 tick:触发全部到期任务(执行异步进行,不阻塞 tick 返回)。 */\r\n tick(): Promise<void>\r\n /** 创建/更新后 fresh 重算 nextRunAt(不执行、不落库——调用方负责 put)。 */\r\n recompute(task: CronTask): CronTask\r\n /** 手动触发一次(不受 enabled 影响;不存在/运行中抛错)。不改变 nextRunAt。 */\r\n triggerManual(taskId: string): Promise<CronRun>\r\n isRunning(taskId: string): boolean\r\n}\r\n\r\nexport function createScheduler(deps: SchedulerDeps): Scheduler {\r\n /** 内存重叠锁:同任务上次未结束则本次记 skipped-overlap,不并发执行。 */\r\n const running = new Set<string>()\r\n\r\n async function recordSkipped(task: CronTask): Promise<void> {\r\n const nowIso = new Date(deps.now()).toISOString()\r\n const run: CronRun = {\r\n id: deps.newRunId(), taskId: task.id,\r\n triggeredAt: nowIso, finishedAt: nowIso,\r\n status: 'skipped-overlap',\r\n }\r\n await deps.runs.put(run.id, run)\r\n await trimRuns(deps.runs, task.id, deps.runHistoryLimit)\r\n }\r\n\r\n function launch(task: CronTask): void {\r\n running.add(task.id)\r\n void deps.execute(task)\r\n .catch((error) => deps.warn(`[schedule] 任务 \"${task.id}\" 执行器异常:${error instanceof Error ? error.message : String(error)}`))\r\n .finally(() => {\r\n running.delete(task.id)\r\n // 触发后推进:任务可能已被删除/停用 → 只在仍存在且启用时写回。\r\n const current = deps.tasks.get(task.id)\r\n if (current === undefined || !current.enabled) return\r\n void deps.tasks.put(task.id, advanceAfterTrigger(current, deps.now()))\r\n })\r\n }\r\n\r\n return {\r\n async rearmAll() {\r\n for (const [id, task] of deps.tasks.entries()) {\r\n const rearmed = rearmTask(task, deps.now())\r\n if (rearmed !== task) await deps.tasks.put(id, rearmed)\r\n }\r\n },\r\n async tick() {\r\n for (const [, task] of deps.tasks.entries()) {\r\n if (!task.enabled || task.nextRunAt === null) continue\r\n if (Date.parse(task.nextRunAt) > deps.now()) continue\r\n if (running.has(task.id)) {\r\n // 重叠保护:记 skipped-overlap 并把 nextRunAt 推到未来(避免每个 tick 重复记跳过)。\r\n await recordSkipped(task)\r\n await deps.tasks.put(task.id, advanceAfterTrigger(task, deps.now()))\r\n continue\r\n }\r\n launch(task)\r\n }\r\n },\r\n recompute: (task) => recomputeTask(task, deps.now()),\r\n async triggerManual(taskId) {\r\n const task = deps.tasks.get(taskId)\r\n if (task === undefined) throw new Error(`定时任务 \"${taskId}\" 不存在`)\r\n if (running.has(taskId)) throw new Error(`定时任务 \"${task.name}\" 正在运行中,本次手动触发已跳过`)\r\n running.add(taskId)\r\n try {\r\n return await deps.execute(task) as CronRun\r\n } finally {\r\n running.delete(taskId)\r\n }\r\n },\r\n isRunning: (taskId) => running.has(taskId),\r\n }\r\n}\r\n","/** cron 任务 CRUD 服务:模型工具与 HTTP API 双入口共用(校验、落库、重算、连带清理)。 */\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport type { Scheduler } from './scheduler.ts'\r\nimport { CronTaskSchema, deleteRunsOf, listRuns, type CronRun, type CronSchedule, type CronTarget, type CronTask } from './store.ts'\r\nimport { validateSchedule } from './timing.ts'\r\n\r\n/** 创建输入(全字段必填;更新用 Partial)。 */\r\nexport interface CronTaskInput {\r\n name: string\r\n prompt: string\r\n cwd: string\r\n schedule: CronSchedule\r\n target: CronTarget\r\n catchup: boolean\r\n enabled: boolean\r\n}\r\nexport type CronTaskPatch = Partial<CronTaskInput>\r\n\r\n/** 列表视图:任务 + 最近一次运行摘要。 */\r\nexport type CronTaskView = CronTask & { lastRun?: Pick<CronRun, 'status' | 'triggeredAt'> }\r\n\r\nexport type CronResult<T> = { ok: true; value: T } | { ok: false; error: string }\r\n\r\nexport interface CronServiceDeps {\r\n tasks: KvTable<string, CronTask>\r\n runs: KvTable<string, CronRun>\r\n scheduler: Scheduler\r\n registry: AgentRegistry\r\n validateProject(path: string): boolean\r\n now(): number\r\n newTaskId(): string\r\n}\r\n\r\nexport interface CronService {\r\n list(): CronTaskView[]\r\n get(id: string): CronTask | undefined\r\n create(input: CronTaskInput): Promise<CronResult<CronTask>>\r\n update(id: string, patch: CronTaskPatch): Promise<CronResult<CronTask>>\r\n /** 删除任务并连带清运行历史。 */\r\n remove(id: string): Promise<CronResult<null>>\r\n /** 立即手动触发一次(不受 enabled 影响;不存在/运行中 ok:false)。 */\r\n trigger(id: string): Promise<CronResult<CronRun>>\r\n /** 运行历史(新 → 旧,最多 limit 条)。 */\r\n runsOf(id: string, limit: number): CronRun[]\r\n}\r\n\r\nexport function createCronService(deps: CronServiceDeps): CronService {\r\n /** 创建/更新共用校验:schedule 语法与时值 → cwd → roleId 存在性。 */\r\n const validateIO = (input: Pick<CronTaskInput, 'cwd' | 'schedule' | 'target'>): string | undefined => {\r\n const scheduleError = validateSchedule(input.schedule, deps.now())\r\n if (scheduleError !== undefined) return scheduleError\r\n if (!deps.validateProject(input.cwd)) return `项目路径不可用:${input.cwd}`\r\n if (input.target.kind === 'role' && deps.registry.get(input.target.roleId) === undefined) {\r\n return `角色 \"${input.target.roleId}\" 不存在`\r\n }\r\n return undefined\r\n }\r\n\r\n return {\r\n list() {\r\n return [...deps.tasks.entries()].map(([, task]) => {\r\n const last = listRuns(deps.runs, task.id)[0]\r\n const view: CronTaskView = last === undefined\r\n ? task\r\n : { ...task, lastRun: { status: last.status, triggeredAt: last.triggeredAt } }\r\n return view\r\n })\r\n },\r\n get: (id) => deps.tasks.get(id),\r\n async create(input) {\r\n const invalid = validateIO(input)\r\n if (invalid !== undefined) return { ok: false, error: invalid }\r\n const nowIso = new Date(deps.now()).toISOString()\r\n const parsed = CronTaskSchema.safeParse({\r\n id: deps.newTaskId(), ...input,\r\n nextRunAt: null, createdAt: nowIso, updatedAt: nowIso,\r\n })\r\n if (!parsed.success) return { ok: false, error: parsed.error.issues[0]?.message ?? 'invalid task' }\r\n const task = deps.scheduler.recompute(parsed.data)\r\n await deps.tasks.put(task.id, task)\r\n return { ok: true, value: task }\r\n },\r\n async update(id, patch) {\r\n const existing = deps.tasks.get(id)\r\n if (existing === undefined) return { ok: false, error: `定时任务 \"${id}\" 不存在` }\r\n const merged = {\r\n ...existing,\r\n ...(Object.fromEntries(Object.entries(patch).filter(([, v]) => v !== undefined))),\r\n id: existing.id,\r\n updatedAt: new Date(deps.now()).toISOString(),\r\n }\r\n const invalid = validateIO(merged)\r\n if (invalid !== undefined) return { ok: false, error: invalid }\r\n const parsed = CronTaskSchema.safeParse(merged)\r\n if (!parsed.success) return { ok: false, error: parsed.error.issues[0]?.message ?? 'invalid task' }\r\n const task = deps.scheduler.recompute(parsed.data)\r\n await deps.tasks.put(id, task)\r\n return { ok: true, value: task }\r\n },\r\n async remove(id) {\r\n if (deps.tasks.get(id) === undefined) return { ok: false, error: `定时任务 \"${id}\" 不存在` }\r\n await deps.tasks.delete(id)\r\n await deleteRunsOf(deps.runs, id)\r\n return { ok: true, value: null }\r\n },\r\n async trigger(id) {\r\n try {\r\n return { ok: true, value: await deps.scheduler.triggerManual(id) }\r\n } catch (error) {\r\n return { ok: false, error: error instanceof Error ? error.message : String(error) }\r\n }\r\n },\r\n runsOf: (id, limit) => listRuns(deps.runs, id).slice(0, limit),\r\n }\r\n}\r\n","/** cron_* 模型工具:注册在主 Agent scope(不进 subagent/插件自有会话)+ 宿主 schedule 互斥探测。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { Agent } from '@deepseek-ai/dsh-agent'\r\nimport { defineTool, type ToolDefinition } from '@deepseek-ai/dsh-tools'\r\nimport { scopeOf } from '@deepseek-ai/dsh-scope'\r\nimport type { CronService, CronTaskInput, CronTaskPatch } from './service.ts'\r\nimport type { CronSchedule, CronTarget } from './store.ts'\r\n\r\n/** 互斥探测目标:宿主 @deepseek-ai/dsh-schedule 的会话内提醒工具。 */\r\nconst HOST_SCHEDULE_TOOL = 'schedule_create'\r\n\r\n/** 扁平参数 → CronSchedule(缺 kind 对应字段抛错——模型可读的自描述消息)。 */\r\nfunction scheduleOf(args: Record<string, unknown>): CronSchedule {\r\n const kind = args.scheduleKind\r\n if (kind === 'cron') {\r\n if (typeof args.cronExpr !== 'string' || args.cronExpr.trim() === '') throw new Error('scheduleKind=cron 需要 cronExpr(5 字段 cron 表达式)')\r\n return {\r\n kind: 'cron', expr: args.cronExpr,\r\n ...(typeof args.timeZone === 'string' && args.timeZone !== '' ? { timeZone: args.timeZone } : {}),\r\n }\r\n }\r\n if (kind === 'at') {\r\n if (typeof args.atTime !== 'string' || args.atTime === '') throw new Error('scheduleKind=at 需要 atTime(RFC 3339 时间)')\r\n return { kind: 'at', at: args.atTime }\r\n }\r\n if (kind === 'every') {\r\n if (typeof args.everySeconds !== 'number') throw new Error('scheduleKind=every 需要 everySeconds(≥60 的秒数)')\r\n return { kind: 'every', seconds: args.everySeconds }\r\n }\r\n throw new Error(`未知 scheduleKind:${String(kind)}(可选 cron / at / every)`)\r\n}\r\n\r\nfunction targetOf(args: Record<string, unknown>): CronTarget {\r\n if (args.targetKind === 'role') {\r\n if (typeof args.roleId !== 'string' || args.roleId === '') throw new Error('targetKind=role 需要 roleId')\r\n return { kind: 'role', roleId: args.roleId }\r\n }\r\n return { kind: 'main' }\r\n}\r\n\r\n/** 服务结果展开:ok:false → 抛错(defineTool 约定:抛错即工具错误结果)。 */\r\nfunction unwrap<T>(result: { ok: true; value: T } | { ok: false; error: string }): T {\r\n if (!result.ok) throw new Error(result.error)\r\n return result.value\r\n}\r\n\r\nconst JSON_OUTPUT = {\r\n schema: { type: 'json' },\r\n render: (_args: unknown, value: unknown) => [{ type: 'text' as const, text: JSON.stringify(value, null, 2) }],\r\n} as const\r\n\r\nconst SCHEDULE_PARAMS_REQUIRED = {\r\n scheduleKind: { type: 'string', required: true, description: 'One of: cron / at / every' },\r\n} as const\r\n\r\nconst SCHEDULE_PARAMS_OPTIONAL = {\r\n scheduleKind: { type: 'string', description: 'Replace schedule kind: cron / at / every (provide the matching fields too)' },\r\n} as const\r\n\r\nconst SCHEDULE_FIELD_PARAMS = {\r\n cronExpr: { type: 'string', description: 'Required when scheduleKind=cron: 5-field cron expression \"minute hour day-of-month month day-of-week\" (seconds/years not supported)' },\r\n timeZone: { type: 'string', description: 'Optional IANA time zone for cron (e.g. \"Asia/Shanghai\"); default: server process time zone' },\r\n atTime: { type: 'string', description: 'Required when scheduleKind=at: one-shot RFC 3339 time (e.g. \"2026-09-08T09:00:00+08:00\")' },\r\n everySeconds: { type: 'number', description: 'Required when scheduleKind=every: interval seconds (>= 60), anchored at creation time' },\r\n} as const\r\n\r\nconst TARGET_PARAMS_REQUIRED = {\r\n targetKind: { type: 'string', required: true, description: 'One of: main (main agent, default model) / role (registry role with its persona/model/tool allowlist)' },\r\n} as const\r\n\r\nconst TARGET_PARAMS_OPTIONAL = {\r\n targetKind: { type: 'string', description: 'Replace target: main / role' },\r\n} as const\r\n\r\nconst ROLE_ID_PARAM = { roleId: { type: 'string', description: 'Required when targetKind=role: registry role id' } } as const\r\n\r\nexport function createCronTools(service: CronService): ToolDefinition[] {\r\n return [\r\n defineTool({\r\n name: 'cron_task_create',\r\n description:\r\n 'Create a scheduled task that runs a prompt in a NEW standalone session (main agent or a registry role) '\r\n + 'on a cron/at/every schedule. The task survives restarts; a run missed while stopped is caught up once '\r\n + 'when catchup=true. Use cron_task_list to see existing tasks.',\r\n parameters: {\r\n name: { type: 'string', required: true, description: 'Task name (display)' },\r\n prompt: { type: 'string', required: true, description: 'The prompt sent as the user message when the task fires. Self-contained: the session has no other context.' },\r\n cwd: { type: 'string', required: true, description: 'Working directory of the new session (must be a valid project path)' },\r\n ...SCHEDULE_PARAMS_REQUIRED,\r\n ...SCHEDULE_FIELD_PARAMS,\r\n ...TARGET_PARAMS_REQUIRED,\r\n ...ROLE_ID_PARAM,\r\n catchup: { type: 'boolean', required: true, description: 'true: run once immediately after restart if a run was missed while stopped; false: skip to the next future occurrence' },\r\n enabled: { type: 'boolean', required: true, description: 'false: create paused (nextRunAt stays null until enabled via cron_task_update)' },\r\n },\r\n output: JSON_OUTPUT,\r\n isConcurrencySafe: () => true,\r\n async execute(rawArgs) {\r\n const args = rawArgs as Record<string, unknown>\r\n const input: CronTaskInput = {\r\n name: args.name as string,\r\n prompt: args.prompt as string,\r\n cwd: args.cwd as string,\r\n schedule: scheduleOf(args),\r\n target: targetOf(args),\r\n catchup: args.catchup as boolean,\r\n enabled: args.enabled as boolean,\r\n }\r\n return unwrap(await service.create(input))\r\n },\r\n }),\r\n defineTool({\r\n name: 'cron_task_list',\r\n description: 'List all scheduled tasks with enabled flag, next run time and last run status.',\r\n parameters: {},\r\n output: JSON_OUTPUT,\r\n isConcurrencySafe: () => true,\r\n async execute() {\r\n return service.list()\r\n },\r\n }),\r\n defineTool({\r\n name: 'cron_task_update',\r\n description: 'Update any fields of a scheduled task by id. nextRunAt is recomputed.',\r\n parameters: {\r\n id: { type: 'string', required: true, description: 'Task id' },\r\n name: { type: 'string', description: 'New name' },\r\n prompt: { type: 'string', description: 'New prompt' },\r\n cwd: { type: 'string', description: 'New working directory' },\r\n ...SCHEDULE_PARAMS_OPTIONAL,\r\n ...SCHEDULE_FIELD_PARAMS,\r\n ...TARGET_PARAMS_OPTIONAL,\r\n ...ROLE_ID_PARAM,\r\n catchup: { type: 'boolean', description: 'New catchup flag' },\r\n enabled: { type: 'boolean', description: 'Enable/disable the task' },\r\n },\r\n output: JSON_OUTPUT,\r\n isConcurrencySafe: () => true,\r\n async execute(rawArgs) {\r\n const args = rawArgs as Record<string, unknown>\r\n const patch: CronTaskPatch = {}\r\n if (args.name !== undefined) patch.name = args.name as string\r\n if (args.prompt !== undefined) patch.prompt = args.prompt as string\r\n if (args.cwd !== undefined) patch.cwd = args.cwd as string\r\n if (args.scheduleKind !== undefined) patch.schedule = scheduleOf(args)\r\n if (args.targetKind !== undefined) patch.target = targetOf(args)\r\n if (args.catchup !== undefined) patch.catchup = args.catchup as boolean\r\n if (args.enabled !== undefined) patch.enabled = args.enabled as boolean\r\n return unwrap(await service.update(args.id as string, patch))\r\n },\r\n }),\r\n defineTool({\r\n name: 'cron_task_delete',\r\n description: 'Delete a scheduled task by id, including its run history.',\r\n parameters: { id: { type: 'string', required: true, description: 'Task id' } },\r\n output: JSON_OUTPUT,\r\n isConcurrencySafe: () => true,\r\n async execute(rawArgs) {\r\n return unwrap(await service.remove((rawArgs as Record<string, unknown>).id as string))\r\n },\r\n }),\r\n defineTool({\r\n name: 'cron_task_trigger',\r\n description: 'Trigger a scheduled task once right now (works even when disabled; fails with an error if the task is already running).',\r\n parameters: { id: { type: 'string', required: true, description: 'Task id' } },\r\n output: JSON_OUTPUT,\r\n isConcurrencySafe: () => true,\r\n async execute(rawArgs) {\r\n return unwrap(await service.trigger((rawArgs as Record<string, unknown>).id as string))\r\n },\r\n }),\r\n ]\r\n}\r\n\r\n/**\r\n * 注册 cron_* 工具到主 Agent scope 并探测宿主 schedule 互斥(spec §1/§5)。\r\n * 门控:跳过 subagent(session.header.origin === 'subagent')与插件自有会话(ownedSessions:\r\n * bot/schedule 会话)——dsh-schedule src/index.ts:45-49 同款 agent/created 模式,\r\n * 外加存量 roots 立即注册(HMR 重挂后当前主会话不丢工具)。\r\n * HMR 安全:镜像 dsh-schedule src/index.ts:44-76——attached 身份表防同一 agent 二次挂载,\r\n * toolkit 级 ctx.effect 卸载时 Promise.allSettled 摘下所有 agent 上挂的工具\r\n * (agent.ctx 属宿主、长于 toolkit fiber,仅靠 agent.ctx.effect 会在重挂时残留)。\r\n */\r\nexport function setupCronTools(ctx: Context, tools: ToolDefinition[], ownedSessions: ReadonlySet<string>): void {\r\n const attached = new Map<Agent, () => void>()\r\n let stopping = false\r\n\r\n ctx.effect(() => {\r\n const stopCreated = ctx.on('agent/created', ({ agent }) => {\r\n if (stopping || attached.has(agent)) return\r\n attach(agent)\r\n })\r\n for (const agent of ctx.agents.roots()) attach(agent)\r\n\r\n return async () => {\r\n stopping = true\r\n stopCreated()\r\n const cleanups = [...attached.values()]\r\n attached.clear()\r\n await Promise.allSettled(cleanups.map((cleanup) => Promise.resolve(cleanup())))\r\n }\r\n }, 'dsh-agent-toolkit.cron-tools()')\r\n\r\n function attach(agent: Agent): void {\r\n if (attached.has(agent)) return\r\n if (agent.session.header.origin === 'subagent') return\r\n if (ownedSessions.has(String(agent.session.id))) return\r\n const cleanup = agent.ctx.effect(() => {\r\n const scope = scopeOf(agent.ctx)\r\n const hostPresent = scope !== undefined\r\n ? ctx.tools.get(HOST_SCHEDULE_TOOL, scope) !== undefined\r\n : ctx.tools.get(HOST_SCHEDULE_TOOL) !== undefined\r\n if (hostPresent) {\r\n ctx.logger.warn(\r\n 'dsh-agent-toolkit: 检测到宿主 @deepseek-ai/dsh-schedule 的 schedule_create 与 cron_* 并存——'\r\n + '两套调度工具并存会显著提高模型误选率,且会话内提醒在会话冷时静默失败;'\r\n + '请从组合中移除 @deepseek-ai/dsh-schedule(二选一)',\r\n )\r\n }\r\n const disposers = tools.map((tool) => agent.ctx.tools.register(tool))\r\n return () => {\r\n for (const dispose of disposers) dispose()\r\n if (attached.get(agent) === cleanup) attached.delete(agent)\r\n }\r\n }, 'dsh-agent-toolkit.cron-tools.attach()')\r\n attached.set(agent, cleanup)\r\n }\r\n}\r\n","/** schedule 模块接线:存储域 → executor/scheduler/service → cron_* 工具 + HTTP API + 30s tick。 */\r\nimport { existsSync } from 'node:fs'\r\nimport { randomUUID } from 'node:crypto'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport { SessionId } from '@deepseek-ai/dsh-session'\r\nimport type {} from '@deepseek-ai/dsh-host-webserver'\r\nimport type {} from '@deepseek-ai/dsh-agent-default-model'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport { createAgentsPort } from '../channels/agents-port.ts'\r\nimport type { WorkspacePort } from '../channels/ports.ts'\r\nimport { createScopeJoiner, type ScopeJoiner } from '../channels/scope-joiner.ts'\r\nimport { createToolsScope } from '../channels/tool-scope.ts'\r\nimport { openDomainSafely } from '../shared/storage.ts'\r\nimport { registerOptionalRoutes } from '../shared/webserver.ts'\r\nimport { createCronApiHandler } from './api.ts'\r\nimport { createExecutor } from './executor.ts'\r\nimport { createScheduler, type Scheduler } from './scheduler.ts'\r\nimport { createCronService } from './service.ts'\r\nimport { scheduleDomain, type CronRun, type CronTask } from './store.ts'\r\nimport { createCronTools, setupCronTools } from './tools.ts'\r\n\r\nexport interface ScheduleModuleConfig {\r\n /** 单次运行 followup→whenIdle 超时(分钟),超时 cancel + run 记 error('timeout')。 */\r\n runTimeoutMinutes: number\r\n /** 每任务环形保留的最近运行数。 */\r\n runHistoryLimit: number\r\n}\r\n\r\nexport interface ScheduleDeps {\r\n registry: AgentRegistry\r\n /** 任务会话挂载的 preset id(agentTeamPreset 开启时下达;undefined = 直接 toolsScope)。 */\r\n botPresetId?: string\r\n /** 插件自有会话 id 集(与 bots 共享;cron_* 工具注册门控排除用)。 */\r\n ownedSessions: Set<string>\r\n}\r\n\r\n/** tick 间隔固定 30s(spec §8:不进 Config——YAGNI)。 */\r\nconst TICK_MS = 30_000\r\n\r\nexport function setupSchedule(ctx: Context, config: ScheduleModuleConfig, deps: ScheduleDeps): void {\r\n const warn = (m: string): void => ctx.logger.warn(m)\r\n // 与 setupBots 同款 joiner 栈:preset 优先(委派子会话 composeFrom 认父)+ toolsScope 回退。\r\n const toolsScope = createToolsScope(ctx)\r\n const joiner: ScopeJoiner = deps.botPresetId !== undefined\r\n ? createScopeJoiner(ctx, deps.botPresetId, toolsScope, warn)\r\n : toolsScope\r\n const agentsPort = createAgentsPort(ctx, joiner, deps.ownedSessions)\r\n\r\n // workspaceRegistry 可选服务,惰性解析(attachments 教训:apply 期一次性捕获会吃到未注册的 undefined)。\r\n interface WorkspaceRegistryLike {\r\n create(path: string): Promise<{ attachSession(sessionId: SessionId): Promise<void> }>\r\n list(): { path: string }[]\r\n }\r\n const workspaceRegistryOf = (): WorkspaceRegistryLike | undefined =>\r\n ctx.get('workspaceRegistry', false) as WorkspaceRegistryLike | undefined\r\n const workspacePort: WorkspacePort = {\r\n async attach(cwd, sessionId) {\r\n const registry = workspaceRegistryOf()\r\n if (registry === undefined) throw new Error('workspaceRegistry 服务不可用')\r\n const workspace = await registry.create(cwd)\r\n await workspace.attachSession(SessionId(sessionId))\r\n },\r\n }\r\n\r\n let scheduler: Scheduler | undefined\r\n const started = openDomainSafely(ctx, scheduleDomain, warn).then(async (domain) => {\r\n const tasks = domain.table('tasks') as KvTable<string, CronTask>\r\n const runs = domain.table('runs') as KvTable<string, CronRun>\r\n const executor = createExecutor({\r\n agents: agentsPort,\r\n registry: deps.registry,\r\n defaultModel: () => {\r\n const selection = ctx.agentDefaultModel.currentSelection()\r\n return { provider: selection.provider, model: selection.model }\r\n },\r\n workspace: workspacePort,\r\n runs,\r\n runHistoryLimit: config.runHistoryLimit,\r\n runTimeoutMs: config.runTimeoutMinutes * 60_000,\r\n warn,\r\n now: () => Date.now(),\r\n newSessionId: () => randomUUID(),\r\n newRunId: () => randomUUID(),\r\n delay: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),\r\n })\r\n scheduler = createScheduler({\r\n tasks, runs,\r\n runHistoryLimit: config.runHistoryLimit,\r\n execute: (task) => executor.trigger(task),\r\n now: () => Date.now(),\r\n newRunId: () => randomUUID(),\r\n warn,\r\n })\r\n const service = createCronService({\r\n tasks, runs,\r\n scheduler,\r\n registry: deps.registry,\r\n validateProject: (path) => existsSync(path),\r\n now: () => Date.now(),\r\n newTaskId: () => randomUUID(),\r\n })\r\n setupCronTools(ctx, createCronTools(service), deps.ownedSessions)\r\n // webServer 可选(headless 惰性不抛错);handler 请求时才构造(启动链落定前不捕获 service)。\r\n registerOptionalRoutes(ctx, (webCtx) => {\r\n const dispose = webCtx.webServer.register({\r\n kind: 'prefix',\r\n path: '/dsh-agent-toolkit/api/cron',\r\n handler: async (req, res) => {\r\n try {\r\n await started\r\n await createCronApiHandler({\r\n service,\r\n listProjects: () => workspaceRegistryOf()?.list().map((w) => w.path) ?? [],\r\n runHistoryLimit: config.runHistoryLimit,\r\n })(req, res)\r\n } catch (error) {\r\n res.writeHead(500, { 'content-type': 'application/json' })\r\n .end(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }))\r\n }\r\n },\r\n })\r\n return () => dispose()\r\n })\r\n await scheduler.rearmAll()\r\n })\r\n started.catch((error) => {\r\n warn(`[schedule] 启动失败:${error instanceof Error ? error.message : String(error)}`)\r\n })\r\n\r\n // 周期 tick:启动链落定后扫描到期任务。裸 setInterval 而非 ctx.interval——\r\n // timer mixin 受 cordis inject 门控,而本插件 inject 列表按约束不加新服务;\r\n // ctx.effect 卸载时自动 clearInterval,与 ctx.interval 清理语义等价。\r\n ctx.effect(() => {\r\n const timer = setInterval(() => { void started.then(() => scheduler?.tick()) }, TICK_MS)\r\n return () => clearInterval(timer)\r\n })\r\n\r\n ctx.effect(() => async () => { await toolsScope.dispose() })\r\n}\r\n","/** dsh-agent-toolkit 插件总入口:Agent 注册表 + 分层提示词 + 并行委派 + 飞书 bots + token 用量。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport z from '@deepseek-ai/schemastery'\r\nimport { createRegistry } from './agents/registry.ts'\r\nimport { createToolCatalog } from './agents/tool-catalog.ts'\r\nimport { agentToolkitDomain, type AgentRecord } from './agents/store.ts'\r\nimport { openDomainSafely } from './shared/storage.ts'\r\nimport { DEFAULT_LAYERS, DEFAULT_RULES } from './prompt/defaults.ts'\r\nimport { setupPrompt, validateConfig as validatePromptConfig } from './prompt/index.ts'\r\nimport { openLayerSource, type PromptLayersRow } from './prompt/layer-source.ts'\r\nimport { setupPromptLayersApi } from './prompt/api.ts'\r\nimport type { LayerConfig, Rule } from './prompt/types.ts'\r\nimport { setupDelegate } from './delegate/index.ts'\r\nimport { createActiveRoutes } from './delegate/active.ts'\r\nimport { delegationRoutesDomain, type DelegationRouteRecord } from './delegate/routes.ts'\r\nimport { setupDelegateApi } from './delegate/api.ts'\r\nimport { setupAgentsApi } from './agents/api.ts'\r\nimport { setupCreateAgentCommand } from './agents/create-command.ts'\r\nimport { setupBots, type BotsModuleConfig } from './bots/index.ts'\r\nimport { setupAgentTeamPreset, type AgentTeamPresetConfig } from './agents/team-preset.ts'\r\nimport { setupSchedule, type ScheduleModuleConfig } from './schedule/index.ts'\r\nimport { setupUsage } from '@dsh-agent-toolkit/token-usage'\r\n\r\nexport const name = 'dsh-agent-toolkit'\r\n\r\n// 全部硬依赖服务(merged 模块直接消费;archive token-usage/project-bot 的 inject 并集)。\r\n// storageDomain(registry/bots/usage 经 openDomainSafely 消费)、tokenMeter(usage)、\r\n// credentials(bots)不在 brief 骨架的 7 项里,但均为插件运行必需,补齐。\r\nexport const inject = [\r\n 'storageDomain',\r\n 'tools',\r\n 'subagents',\r\n 'systemPrompt',\r\n 'commands',\r\n 'llm',\r\n 'agentDefaultModel',\r\n 'agents',\r\n 'tokenMeter',\r\n 'credentials',\r\n]\r\n\r\n/** 插件配置输出型。 */\r\nexport interface Config {\r\n modules: { feishu: boolean; usage: boolean }\r\n layers: LayerConfig[]\r\n rules: Rule[]\r\n timezone: string\r\n provider: string\r\n toolName: string\r\n feishu: BotsModuleConfig\r\n agentTeamPreset: AgentTeamPresetConfig\r\n schedule: ScheduleModuleConfig\r\n}\r\n\r\n/** layers/rules 的 schemastery schema 照归档 prompt-stack/src/index.ts:21-41 逐字段平移(含 overrides transform hack)。 */\r\nexport const Config: z<unknown, Config> = z.object({\r\n modules: z.object({\r\n feishu: z.boolean().default(true),\r\n usage: z.boolean().default(true),\r\n }).default({ feishu: true, usage: true }),\r\n layers: z.array(z.object({\r\n name: z.string().required(),\r\n order: z.number().required(),\r\n text: z.string().required(),\r\n })).default(DEFAULT_LAYERS),\r\n // 元素 cast 为 z<Rule>:Rule.overrides/append 可选,而 z.object 输出键全必填,\r\n // 直接 .default(DEFAULT_RULES) 会类型不匹配。transform 丢弃空 overrides:\r\n // z.dict 隐式默认 {},会给 append-only 默认规则注入 overrides: {}(破坏\r\n // Config({}) 与 DEFAULT_RULES 的精确相等)。\r\n rules: z.array((z.object({\r\n match: z.object({\r\n provider: z.string(),\r\n model: z.string(),\r\n modelPattern: z.string(),\r\n }).required(),\r\n overrides: z.transform(z.dict(z.string()), value => Object.keys(value).length === 0 ? undefined : value),\r\n append: z.string(),\r\n }) as z<Rule>)).default(DEFAULT_RULES),\r\n timezone: z.string().default('Asia/Shanghai'),\r\n provider: z.string().default('spawn'),\r\n toolName: z.string().default('team_delegate'),\r\n // feishu 9 个全局可调参数照归档 project-bot/src/index.ts:38-45,字段名/默认值原样平移。\r\n feishu: z.object({\r\n cardUpdateThrottleMs: z.number().default(500),\r\n cardMaxBytes: z.number().default(26_000),\r\n cardPrintStep: z.number().default(5),\r\n processMaxBytes: z.number().default(8_000),\r\n registerAppTimeoutMs: z.number().default(600_000),\r\n processingReactionEmoji: z.string().default('OneSecond'),\r\n errorDetailMaxChars: z.number().default(500),\r\n injectSender: z.boolean().default(true),\r\n approval: z.boolean().default(true),\r\n }).default({\r\n cardUpdateThrottleMs: 500,\r\n cardMaxBytes: 26_000,\r\n cardPrintStep: 5,\r\n processMaxBytes: 8_000,\r\n registerAppTimeoutMs: 600_000,\r\n processingReactionEmoji: 'OneSecond',\r\n errorDetailMaxChars: 500,\r\n injectSender: true,\r\n approval: true,\r\n }),\r\n // agent-team preset 自动生成:派生 shipped standard、禁用 subagent 工具族 4 行,\r\n // 写入首个 trust=user root;另生成 bot 会话最小 preset(botsId,委派子会话 composeFrom 认父的前提)\r\n // (spec: docs/superpowers/specs/2026-09-02-agent-team-preset-design.md)。\r\n agentTeamPreset: z.object({\r\n enabled: z.boolean().default(true),\r\n id: z.string().default('agent-team'),\r\n source: z.string().default('standard'),\r\n name: z.string().default('Agent 团队'),\r\n description: z.string().default('Agent 团队模式:禁用原生 subagent 工具族,委派统一走 team_delegate 团队角色'),\r\n botsId: z.string().default('agent-bot'),\r\n }).default({\r\n enabled: true,\r\n id: 'agent-team',\r\n source: 'standard',\r\n name: 'Agent 团队',\r\n description: 'Agent 团队模式:禁用原生 subagent 工具族,委派统一走 team_delegate 团队角色',\r\n botsId: 'agent-bot',\r\n }),\r\n // 定时任务(cron):单次运行超时(分钟)与每任务运行历史环形上限(spec: docs/superpowers/specs/2026-09-07-cron-schedule-design.md §8)。\r\n // natural() = 非负整数(schemastery 无 .int(),语义等价且校验更强)。\r\n schedule: z.object({\r\n runTimeoutMinutes: z.number().min(1).default(60),\r\n runHistoryLimit: z.natural().min(1).default(20),\r\n }).default({ runTimeoutMinutes: 60, runHistoryLimit: 20 }),\r\n}) as z<unknown, Config>\r\n\r\nexport async function apply(ctx: Context, config: Config): Promise<void> {\r\n validatePromptConfig({ layers: config.layers, rules: config.rules })\r\n const warn = (msg: string): void => ctx.logger.warn(msg)\r\n const domain = await openDomainSafely(ctx, agentToolkitDomain, warn)\r\n const tables = {\r\n agents: domain.table('agents') as KvTable<string, AgentRecord>,\r\n meta: domain.table('meta') as KvTable<string, { value: string }>,\r\n promptLayers: domain.table('prompt_layers') as KvTable<string, PromptLayersRow>,\r\n }\r\n // agent-team / agent-bot preset 生成必须先于 createRegistry:preset 并入迁移要枚举\r\n // agent-team 面(standingKeyFor 按 composition 文件挂载,首启时尚未生成会枚举失败跳过)。\r\n // agentPresets 为可选服务(rc2 旧宿主缺席时内部静默跳过),不进 inject。\r\n await setupAgentTeamPreset(ctx, config.agentTeamPreset)\r\n const toolCatalog = createToolCatalog(ctx, config.agentTeamPreset.id)\r\n const registry = await createRegistry(warn, { agents: tables.agents, meta: tables.meta }, toolCatalog.listPresetTools)\r\n const layerSource = await openLayerSource({ promptLayers: tables.promptLayers, meta: tables.meta }, config.layers)\r\n setupPrompt(ctx, { source: layerSource, rules: config.rules })\r\n const routesDomain = await openDomainSafely(ctx, delegationRoutesDomain, warn)\r\n const routesTable = routesDomain.table('routes') as KvTable<string, DelegationRouteRecord>\r\n const activeRoutes = createActiveRoutes()\r\n setupDelegate(ctx, {\r\n provider: config.provider,\r\n toolName: config.toolName,\r\n rules: config.rules,\r\n }, registry, {\r\n active: activeRoutes,\r\n recordRoute: async (childSessionId, route) => {\r\n await routesTable.put(childSessionId, { provider: route.provider, model: route.model, at: Date.now() })\r\n },\r\n })\r\n setupDelegateApi(ctx, { active: activeRoutes, routes: routesTable })\r\n // agents/providers/tools RPC 为核心恒启用(Agents 面板总是挂载,端点缺失即「加载失败」),\r\n // 不随 modules.feishu 门控;仅 bots 分支受 feishu 开关控制。\r\n setupAgentsApi(ctx, {\r\n registry,\r\n listTools: toolCatalog.listGlobalTools,\r\n listPresetTools: toolCatalog.listPresetTools,\r\n listProviders: () => ctx.llm.listProviders().map(({ id, name }) => ({ id, name })),\r\n listModels: (provider) => ctx.llm.listModels(provider).then((models) => models.map(({ id, name }) => ({ id, name }))),\r\n })\r\n // /create-agent 命令恒启用(引导主 Agent 访谈并复用面板 API 落库,不新增工具/API)。\r\n setupCreateAgentCommand(ctx, { registry, listTools: toolCatalog.listGlobalTools, listPresetTools: toolCatalog.listPresetTools })\r\n setupPromptLayersApi(ctx, {\r\n source: layerSource,\r\n rules: config.rules,\r\n seedLayers: config.layers,\r\n // 裸组装探测:面板只读区展示原生 sections 与动态层 contexts 的当前快照。\r\n probe: async () => {\r\n const assembly = await ctx.systemPrompt.assemble({})\r\n return {\r\n sections: assembly.sections.map(({ name: n, text }) => ({ name: n, text })),\r\n contexts: assembly.contexts.map(({ name: n, text }) => ({ name: n, text })),\r\n }\r\n },\r\n })\r\n const ownedSessions = new Set<string>()\r\n if (config.modules.feishu) setupBots(ctx, config.feishu, { registry, botPresetId: config.agentTeamPreset.enabled ? config.agentTeamPreset.botsId : undefined, ownedSessions })\r\n if (config.modules.usage) setupUsage(ctx, { timezone: config.timezone }, name)\r\n // schedule 恒启用,不随 modules 门控(任务可独立于飞书/用量使用)。\r\n setupSchedule(ctx, config.schedule, {\r\n registry,\r\n botPresetId: config.agentTeamPreset.enabled ? config.agentTeamPreset.botsId : undefined,\r\n ownedSessions,\r\n })\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAMA,MAAa,cAAc;AAiB3B,MAAa,oBAAoBA,IAAE,OAAO;CACxC,MAAMA,IAAE,OAAO;CACf,OAAOA,IAAE,OAAO;CAChB,MAAMA,IAAE,OAAO;AACjB,CAAC;AAED,MAAa,oBAA4CA,IAAE,OAAO;CAChE,IAAIA,IAAE,OAAO,CAAC,CAAC,MAAM,WAAW;CAChC,MAAMA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACtB,aAAaA,IAAE,OAAO,CAAC,CAAC,SAAS;CACjC,SAASA,IAAE,OAAO,CAAC,CAAC,SAAS;CAC7B,cAAcA,IAAE,MAAM,iBAAiB,CAAC,CAAC,SAAS;CAClD,OAAOA,IAAE,OAAO;EAAE,UAAUA,IAAE,OAAO;EAAG,OAAOA,IAAE,OAAO;CAAE,CAAC,CAAC,CAAC,SAAS;CACtE,OAAOA,IAAE,OAAO,EAAE,OAAOA,IAAE,MAAMA,IAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;CAChE,SAASA,IAAE,QAAQ,CAAC,CAAC,SAAS;CAC9B,eAAeA,IAAE,QAAQ,CAAC,CAAC,SAAS;AACtC,CAAC;;AAGD,MAAa,qBAAqB,aAAa;CAC7C,MAAM;CACN,SAAS;CACT,QAAQ;EACN,QAAQ,YAAiC,iBAAiB;EAE1D,MAAM,YAAuCA,IAAE,OAAO,EAAE,OAAOA,IAAE,OAAO,EAAE,CAAC,CAAC;EAE5E,eAAe,YAA+CA,IAAE,OAAO,EAAE,QAAQA,IAAE,MAAM,iBAAiB,EAAE,CAAC,CAAC;CAChH;AACF,CAAC;;;;;AAMD,SAAgB,mBAAmB,QAAkC;CACnE,IAAI,OAAO,iBAAiB,KAAA,GAAW,OAAO;CAC9C,MAAM,EAAE,cAAc,GAAG,SAAS;CAClC,MAAM,SAAS,CAAC,GAAG,YAAY,CAAC,CAC7B,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CACjC,KAAK,UAAU,MAAM,IAAI,CAAC,CAC1B,QAAQ,SAAS,KAAK,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CACxC,KAAK,MAAM;CACd,MAAM,UAAU,KAAK,WAAW;CAChC,OAAO,QAAQ,SAAS,IAAI;EAAE,GAAG;EAAM;CAAQ,IAAI;AACrD;;AAGA,SAAgB,cAAc,MAAmD;CAC/E,OAAO,KAAK,kBAAkB;AAChC;;;AC1DA,MAAa,cAA2B;CACtC;EACE,IAAI;EACJ,QAAQ,EAAE,MAAM,6MAA6M;CAC/N;CACA;EACE,IAAI;EACJ,QAAQ,EAAE,UAAU,MAAM;CAC5B;CACA,GAAI,QAAQ,aAAa,UACrB,CAAC,EAAE,IAAI,6BAA6B,CAAC,IACrC,CAAC,EAAE,IAAI,6BAA6B,CAAC;CACzC,EAAE,IAAI,2BAA2B;CACjC;EACE,IAAI;EACJ,QAAQ,EAAE,0BAA0B,MAAM;CAC5C;AACF;;;;;AAMA,MAAa,oBAAuC;CAClD,QAAQ,aAAa,UAAU,SAAS;CACxC;CACA;CACA;CACA;CACA;CACA;AACF;;;;AC1CA,MAAM,aAAa,QAAQ,aAAa,UAAU,SAAS;;;;AAK3D,MAAa,wBAA2C,kBAAkB,QAAQ,MAAM,MAAM,WAAW,MAAM,MAAM;;;;;;AAOrH,MAAa,0BAA6C;CACxD,GAAG;CACH;CAAc;CAAc;CAAY;CAAc;AACxD;;;;AAKA,MAAa,gBAAmC;CAC9C;CAAY;CAAQ;CAAS;CAAQ;CAAc;CAAQ;CAC3D;CAAc;CAAc;CAAqB;CAAS;CAC1D;CAAY;CAAc;CAAY;CAAe;CAAY;CACjE;CAAS;AACX;AAEA,MAAa,iBAAyC;CACpD;EACE,IAAI;EACJ,MAAM;EACN,SAAS;CACX;CACA;EACE,IAAI;EACJ,MAAM;EACN,aAAa;EACb,SAAS;;;EAGT,SAAS;EACT,OAAO,EAAE,OAAO,CAAC,GAAG,uBAAuB,EAAE;CAC/C;CACA;EACE,IAAI;EACJ,MAAM;EACN,aAAa;EACb,SAAS;;;EAGT,SAAS;EACT,OAAO,EAAE,OAAO,CAAC,GAAG,aAAa,EAAE;CACrC;AACF;;;;;AC9CA,MAAa,0BAA0B;AAevC,MAAM,iBAAiBC,IAAE,OAAO;CAC9B,MAAMA,IAAE,OAAO,CAAC,CAAC,SAAS;CAC1B,aAAaA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CAC7B,SAASA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACzB,UAAUA,IAAE,OAAO,CAAC,CAAC,SAAS;CAC9B,OAAOA,IAAE,OAAO,CAAC,CAAC,SAAS;CAC3B,OAAOA,IAAE,OAAO,EACd,OAAOA,IAAE,MAAMA,IAAE,OAAO,CAAC,CAAC,CAAC,SAAS,EACtC,CAAC,CAAC,CAAC,SAAS;AACd,CAAC;;;;;;;;AASD,SAAgB,cAAc,MAAc,QAAgB,UAA+B;CACzF,IAAI;CACJ,IAAI;EACF,SAAS,KAAK,KAAK,IAAI;CACzB,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,2BAA2B,OAAO,aAAa,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;CACzH;CACA,MAAM,WAAW,WAAW,QAAQ,OAAO,WAAW,YAAY,WAAY;CAC9E,IAAI;CACJ,IAAI;EACF,MAAM,eAAe,MAAM,MAAM;CACnC,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,2BAA2B,OAAO,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;CACpH;CACA,MAAM,KAAK,IAAI,QAAQ;CACvB,IAAI,IAAI,SAAS,KAAA,KAAa,IAAI,SAAS,UACzC,MAAM,IAAI,MAAM,2BAA2B,OAAO,WAAW,IAAI,KAAK,UAAU,SAAS,qBAAqB;CAEhH,IAAI,CAAC,YAAY,KAAK,EAAE,GACtB,MAAM,IAAI,MAAM,6BAA6B,GAAG,OAAO,OAAO,wBAAwB;CAExF,IAAI,YAAY,IAAI,UAAU,KAAA,MAAc,IAAI,MAAM,OAAO,UAAU,OAAO,GAC5E,MAAM,IAAI,MAAM,2BAA2B,OAAO,0CAA0C;CAE9F,MAAM,QAAQ,IAAI,aAAa,KAAA,KAAa,IAAI,UAAU,KAAA,IAAY;EAAE,UAAU,IAAI;EAAU,OAAO,IAAI;CAAM,IAAI,KAAA;CACrH,MAAM,QAAQ,YAAY,IAAI,UAAU,KAAA,KAAa,IAAI,MAAM,UAAU,KAAA,KAAa,IAAI,MAAM,MAAM,SAAS,IAC3G,EAAE,OAAO,IAAI,MAAM,MAAM,IACzB,KAAA;CACJ,OAAO;EACL;EACA,MAAM;EACN,aAAa,IAAI;EACjB,SAAS,IAAI;EACb,GAAI,UAAU,KAAA,IAAY,EAAE,MAAM,IAAI,CAAC;EACvC,GAAI,UAAU,KAAA,IAAY,EAAE,MAAM,IAAI,CAAC;CACzC;AACF;;;;;;;;AAgBA,eAAe,mBAAmB,KAAqC;CACrE,IAAI;CACJ,IAAI;EACF,UAAU,MAAM,QAAQ,GAAG;CAC7B,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,UAAU,OAAO,CAAC;EAChE,MAAM,IAAI,MAAM,8BAA8B,IAAI,GAAG,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,EAAE;CAChH;CACA,OAAO,QACJ,QAAO,MAAK,EAAE,SAAS,MAAM,CAAC,CAAC,CAC/B,KAAK,CAAC,CACN,KAAI,UAAS;EAAE,MAAM;EAAM,MAAM,KAAK,KAAK,IAAI;EAAG,UAAU,KAAK,MAAM,GAAG,EAAc;CAAE,EAAE;AACjG;;;;;;;AA6BA,eAAsB,gBAAgB,KAAyB,UAA0C;CACvG,MAAM,SAAuB;EAAE,UAAU;EAAG,SAAS,CAAC;CAAE;CACxD,IAAI,IAAI,KAAK,IAAA,qBAA2B,MAAM,KAAA,GAAW,OAAO;CAChE,MAAM,MAAM,YAAY,KAAK,eAAe,GAAG,cAAc,OAAO;CACpE,IAAI;CACJ,IAAI;EACF,OAAO,MAAM,mBAAmB,GAAG;CACrC,SAAS,OAAO;EAEd,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EAC/D,MAAM,aAAa,GAAG;EACtB,OAAO;CACT;CACA,KAAK,MAAM,OAAO,MAChB,IAAI;EAEF,MAAM,SAAS,cAAc,MADV,SAAS,IAAI,MAAM,MAAM,GACT,IAAI,MAAM,IAAI,QAAQ;EACzD,MAAM,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM;EACtC,OAAO;CACT,SAAS,OAAO;EACd,OAAO,QAAQ,KAAK,IAAI,IAAI;EAC5B,IAAI,KAAK,2BAA2B,IAAI,KAAK,YAAY,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;CACnH;CAEF,MAAM,aAAa,GAAG;CACtB,OAAO;AACT;AAEA,eAAe,aAAa,KAAwC;CAClE,MAAM,IAAI,KAAK,IAAI,yBAAyB,EAAE,OAAO,IAAI,CAAC;AAC5D;;;;ACnJA,MAAa,4BAA4B;;AAGzC,MAAa,iCAAiC;;AAG9C,MAAa,4BAA4B;;AAGzC,MAAa,uCAAuC;;;;;AAMpD,eAAsB,eACpB,MACA,QAEA,iBACwB;CACxB,MAAM,EAAE,QAAQ,SAAS;CAEzB,MAAM,gBAAgB;EAAE;EAAQ;EAAM;CAAK,CAAC;CAK5C,MAAM,iBAAiB,KAAK,IAAI,yBAAyB,MAAM,KAAA;CAC/D,KAAK,MAAM,CAAC,IAAI,WAAW,OAAO,QAAQ,GAAG;EAC3C,IAAI,OAAO,mBAAmB,MAAM;EACpC,IAAI,CAAC,kBAAkB,KAAK,UAAU,KAAA,GAAW;GAC/C,MAAM,QAAQ,KAAK,MAAM;GACzB,MAAM,UAAU,kBAAkB,QAAQ,SAAS,CAAC,MAAM,SAAS,IAAI,CAAC;GACxE,IAAI,QAAQ,SAAS,GAAG,OAAO;IAAE,GAAG;IAAM,OAAO,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,OAAO,EAAE;GAAE;EACrF;EACA,IAAI,SAAS,QAAQ,MAAM,OAAO,IAAI,IAAI,IAAI;CAChD;CACA,IAAI,CAAC,gBAAgB,MAAM,KAAK,IAAI,2BAA2B,EAAE,OAAO,IAAI,CAAC;CAM7E,IAAI,KAAK,IAAA,+BAA6B,MAAM,KAAA,KAAa,oBAAoB,KAAA,GAAW;EACtF,IAAI;EACJ,IAAI;GAEF,SAAQ,MADc,gBAAgB,EAAA,CACtB,QAAQ,MAAM,CAAC,kBAAkB,SAAS,CAAC,CAAC;EAC9D,QAAQ;GACN,QAAQ,KAAA;EACV;EAGA,IAAI,UAAU,KAAA,KAAa,MAAM,SAAS,GAAG;GAC3C,KAAK,MAAM,CAAC,IAAI,WAAW,OAAO,QAAQ,GAAG;IAC3C,IAAI,OAAO,YAAY,QAAQ,OAAO,UAAU,KAAA,GAAW;IAC3D,MAAM,UAAU,MAAM,QAAQ,MAAM,CAAC,OAAO,MAAO,MAAM,SAAS,CAAC,CAAC;IACpE,IAAI,QAAQ,SAAS,GAAG,MAAM,OAAO,IAAI,IAAI;KAAE,GAAG;KAAQ,OAAO,EAAE,OAAO,CAAC,GAAG,OAAO,MAAO,OAAO,GAAG,OAAO,EAAE;IAAE,CAAC;GACpH;GACA,MAAM,KAAK,IAAI,2BAA2B,EAAE,OAAO,IAAI,CAAC;EAC1D;CACF;CAKA,IAAI,EADqB,KAAK,IAAA,4BAAkC,MAAM,KAAA,IAC/C;EACrB,MAAM,WAAW,OAAO,IAAI,UAAU;EACtC,IAAI,aAAa,KAAA,KAAa,SAAS,UAAU,KAAA,GAC/C,MAAM,OAAO,IAAI,YAAY;GAAE,GAAG;GAAU,OAAO,EAAE,OAAO,CAAC,GAAG,uBAAuB,EAAE;EAAE,CAAC;EAE9F,MAAM,KAAK,IAAI,gCAAgC,EAAE,OAAO,IAAI,CAAC;CAC/D;CAQA,IAAI,KAAK,IAAA,kCAAwC,MAAM,KAAA,GAAW;EAChE,MAAM,WAAW,OAAO,IAAI,UAAU;EACtC,MAAM,eAA+C,CAAC,uBAAuB;GAAC,GAAG;GAAuB;GAAS;EAAM,CAAC;EACxH,IAAI,UAAU,YAAY,QAAQ,SAAS,UAAU,KAAA,KAChD,aAAa,MAAM,UAAU,SAAS,MAAO,MAAM,WAAW,MAAM,UAClE,SAAS,MAAO,MAAM,OAAO,GAAG,MAAM,MAAM,MAAM,EAAE,CAAC,GAC1D,MAAM,OAAO,IAAI,YAAY;GAAE,GAAG;GAAU,OAAO,EAAE,OAAO,CAAC,GAAG,uBAAuB,EAAE;EAAE,CAAC;EAE9F,MAAM,UAAU,OAAO,IAAI,SAAS;EACpC,IAAI,SAAS,YAAY,QAAQ,QAAQ,UAAU,KAAA,GACjD,MAAM,OAAO,IAAI,WAAW;GAAE,GAAG;GAAS,OAAO,EAAE,OAAO,CAAC,GAAG,aAAa,EAAE;EAAE,CAAC;EAElF,MAAM,KAAK,IAAI,sCAAsC,EAAE,OAAO,IAAI,CAAC;CACrE;CAEA,MAAM,aAAa,MAAM;CAEzB,MAAM,wBAAQ,IAAI,IAAyB;CAC3C,KAAK,MAAM,CAAC,IAAI,WAAW,OAAO,QAAQ,GAAG,MAAM,IAAI,IAAI,MAAM;CAEjE,MAAM,4BAAY,IAAI,IAAgB;CACtC,MAAM,eAAe;EACnB,KAAK,MAAM,YAAY,CAAC,GAAG,SAAS,GAAG,SAAS;CAClD;CAEA,OAAO;EACL,OAAsB;GACpB,MAAM,OAAO,MAAM,IAAI,MAAM;GAC7B,MAAM,OAAO,CAAC,GAAG,MAAM,QAAQ,CAAC,CAAC,CAC9B,QAAQ,CAAC,QAAQ,OAAO,MAAM,CAAC,CAC/B,KAAK,GAAG,YAAY,MAAM,CAAC,CAC3B,MAAM,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,EAAE,CAAC;GAC1C,OAAO,SAAS,KAAA,IAAY,OAAO,CAAC,MAAM,GAAG,IAAI;EACnD;EACA,IAAI,IAAqC;GACvC,OAAO,MAAM,IAAI,EAAE;EACrB;EACA,MAAM,OAAO,QAAoC;GAC/C,MAAM,SAAS,kBAAkB,UAAU,MAAM;GACjD,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,MAAM,mCAAmC,OAAO,MAAM,SAAS;GAE3E,MAAM,aAAa,mBAAmB,OAAO,IAAI;GACjD,MAAM,WAAW,MAAM,IAAI,OAAO,EAAE;GACpC,IAAI,OAAO,OAAO,UAAU,aAAa,KAAA,GACnC;QAAA,SAAS,SAAS,OAAO,QAAQ,SAAS,YAAY,OAAO,SAC/D,MAAM,IAAI,MAAM,uDAAuD;GAAA;GAG3E,IAAI,UAAU,YAAY,QAAQ,OAAO,YAAY,MACnD,MAAM,IAAI,MAAM,2BAA2B,OAAO,GAAG,kBAAkB;GAEzE,MAAM,OAAO,IAAI,OAAO,IAAI,UAAU;GACtC,MAAM,IAAI,OAAO,IAAI,UAAU;GAC/B,OAAO;EACT;EACA,MAAM,OAAO,IAA2B;GACtC,IAAI,OAAO,QAAQ,MAAM,IAAI,MAAM,sCAAsC;GAEzE,IADiB,MAAM,IAAI,EAChB,CAAC,EAAE,YAAY,MACxB,MAAM,IAAI,MAAM,2BAA2B,GAAG,MAAM;GAGtD,IAAI,MADkB,OAAO,OAAO,EAAE,GACzB;IACX,MAAM,OAAO,EAAE;IACf,OAAO;GACT;EACF;EACA,UAAU,UAAkC;GAC1C,UAAU,IAAI,QAAQ;GACtB,aAAa;IAAE,UAAU,OAAO,QAAQ;GAAE;EAC5C;CACF;AACF;AAEA,eAAe,aAAa,QAAqD;CAC/E,KAAK,MAAM,WAAW,gBACpB,IAAI,OAAO,IAAI,QAAQ,EAAE,MAAM,KAAA,GAC7B,MAAM,OAAO,IAAI,QAAQ,IAAI,OAAO;AAG1C;;;AC9JA,SAAgB,kBAAkB,KAAc,UAA+B;CAC7E,OAAO;EACL,MAAM,kBAAkB;GAEtB,MAAM,UAAU,IAAI,IAAI,gBAAgB,KAAK;GAC7C,IAAI,YAAY,KAAA,GAAW,OAAO,CAAC,GAAG,iBAAiB;GACvD,IAAI;IACF,MAAM,MAAM,MAAM,QAAQ,eAAe,QAAQ;IACjD,MAAM,SAAS,IAAI,IAAI,IAAI,MAAM,QAAQ,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI,CAAC;IAC7D,OAAO,IAAI,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI,CAAC,CAC7C,QAAQ,MAAM,CAAC,OAAO,IAAI,CAAC,KAAK,MAAM,aAAa,CAAC,CACpD,KAAK;GACV,SAAS,OAAO;IACd,IAAI,OAAO,KACT,iCAAiC,SAAS,iBAAiB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAClH;IACA,OAAO,CAAC,GAAG,iBAAiB;GAC9B;EACF;EACA,kBAAkB;GAChB,OAAO,IAAI,MAAM,QAAQ,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ,MAAM,MAAM,aAAa;EACjF;CACF;AACF;;;ACxCA,SAAgB,iBACd,KACA,QACA,MACA,aACuB;CACvB,MAAM,QAAQ,IAAI,cAAc,KAAK,MAAM;CAI3C,MAAM,OAAO,UAAU;EACrB,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;CAC7D,CAAC;CAGD,IAAI,aAAa,YAAY;EAI3B,MAAM,QAAQ,QAAQ,cAAc,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;EAC5D,MAAM,MAAM,MAAM,WAAW,OAAO,MAAM,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;CACpE,CAAC;CACD,OAAO;AACT;;;;ACvBA,MAAa,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6DzB,MAAa,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;AAyB9B,MAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwD3B,MAAa,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwC1B,MAAa,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmD1B,MAAa,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyExB,MAAa,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4DzB,MAAa,kBAAkB;;;;AAK/B,MAAa,aAAa;;;;;;;;;AAU1B,MAAa,iBAAgC,CAC3C;CAAE,MAAM;CAAW,OAAO;CAAI,MAAM;AAAG,CACzC;;AAGA,MAAa,gBAAwB;CACnC;EAAE,OAAO,EAAE,cAAc,UAAU;EAAG,WAAW,EAAE,MAAM,eAAe;CAAE;CAC1E;EAAE,OAAO,EAAE,cAAc,WAAW;EAAG,WAAW,EAAE,MAAM,YAAY;CAAE;CACxE;EAAE,OAAO,EAAE,cAAc,SAAS;EAAG,WAAW,EAAE,MAAM,WAAW;CAAE;CACrE;EAAE,OAAO,EAAE,cAAc,MAAM;EAAG,WAAW,EAAE,MAAM,WAAW;CAAE;CAClE;EAAE,OAAO,EAAE,cAAc,MAAM;EAAG,WAAW,EAAE,MAAM,WAAW;CAAE;CAClE;EAAE,OAAO,EAAE,cAAc,aAAa;EAAG,WAAW,EAAE,MAAM,WAAW;CAAE;CACzE;EAAE,OAAO,EAAE,cAAc,OAAO;EAAG,WAAW,EAAE,MAAM,SAAS;CAAE;CACjE;EAAE,OAAO,EAAE,cAAc,QAAQ;EAAG,WAAW,EAAE,MAAM,UAAU;CAAE;CAEnE;EAAE,OAAO,EAAE,cAAc,MAAM;EAAG,WAAW,EAAE,MAAM,UAAU;CAAE;CACjE;EAAE,OAAO,EAAE,cAAc,MAAM;EAAG,WAAW,EAAE,MAAM,UAAU;CAAE;CACjE;EAAE,OAAO,EAAE,UAAU,aAAa;EAAG,WAAW,EAAE,MAAM,UAAU;CAAE;CACpE;EAAE,OAAO,EAAE,UAAU,gBAAgB;EAAG,WAAW,EAAE,MAAM,UAAU;CAAE;CACvE;EAAE,OAAO,EAAE,UAAU,kBAAkB;EAAG,WAAW,EAAE,MAAM,UAAU;CAAE;CACzE;EAAE,OAAO,EAAE,cAAc,YAAY;EAAG,QAAQ;CAAgB;CAChE;EAAE,OAAO,EAAE,cAAc,QAAQ;EAAG,QAAQ;CAAW;AACzD;;;;ACtZA,MAAM,cAAc;;;;;;AAOpB,SAAgB,aAAa,SAAyB;CACpD,IAAI,QAAQ,KAAK,MAAM,IACrB,MAAM,IAAI,MAAM,qDAAqD;CAEvE,MAAM,SAAS,QACZ,QAAQ,aAAa,MAAM,CAAC,CAC5B,WAAW,KAAK,IAAI,CAAC,CACrB,WAAW,KAAK,GAAG;CACtB,OAAO,IAAI,OAAO,IAAI,OAAO,EAAE;AACjC;;;;;;;;;AAUA,SAAgB,UAAU,OAAkB,UAA8B,OAAmC;CAC3G,IAAI,QAAQ;CACZ,IAAI,MAAM,aAAa,KAAA,GAAW;EAChC,IAAI,MAAM,aAAa,UAAU,OAAO;EACxC,SAAS;CACX;CACA,IAAI,MAAM,UAAU,KAAA,GAAW;EAC7B,IAAI,MAAM,UAAU,OAAO,OAAO;EAClC,SAAS;CACX;CACA,IAAI,MAAM,iBAAiB,KAAA,GAAW;EACpC,IAAI,UAAU,KAAA,KAAa,CAAC,aAAa,MAAM,YAAY,CAAC,CAAC,KAAK,KAAK,GAAG,OAAO;EACjF,SAAS;CACX;CACA,OAAO;AACT;;;;;;;;AASA,SAAgB,WAAW,OAAwB,UAA8B,OAA6C;CAC5H,IAAI;CACJ,IAAI,YAAY;CAChB,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,QAAQ,UAAU,KAAK,OAAO,UAAU,KAAK;EACnD,IAAI,QAAQ,WAAW;GACrB,OAAO;GACP,YAAY;EACd;CACF;CACA,OAAO;AACT;;;;ACrDA,MAAa,oBAAoB;;AAGjC,MAAa,aAAa;AAE1B,MAAM,eAAe,gBAAgB;;AAGrC,MAAM,mBAAmB;AACzB,MAAM,uBAAuB;;AAW7B,SAAgB,eAAe,QAA6B;CAC1D,IAAI,OAAO,WAAW,GACpB,MAAM,IAAI,MAAM,4DAA4D;CAE9E,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,MAAM,SAAA,iBAA8B,MAAM,SAAA,QAC5C,MAAM,IAAI,MAAM,6BAA6B,MAAM,KAAK,cAAc;EAExE,IAAI,MAAM,IAAI,MAAM,IAAI,GACtB,MAAM,IAAI,MAAM,uCAAuC,MAAM,KAAK,EAAE;EAEtE,MAAM,IAAI,MAAM,IAAI;CACtB;AACF;;;;;AAMA,SAAgB,eAAe,QAAuB;CACpD,eAAe,OAAO,MAAM;CAC5B,MAAM,wBAAQ,IAAI,IAAI,CAAC,YAAY,GAAG,OAAO,OAAO,KAAI,UAAS,MAAM,IAAI,CAAC,CAAC;CAC7E,KAAK,MAAM,CAAC,OAAO,SAAS,OAAO,MAAM,QAAQ,GAAG;EAClD,MAAM,EAAE,UAAU,OAAO,iBAAiB,KAAK;EAC/C,IAAI,aAAa,KAAA,KAAa,UAAU,KAAA,KAAa,iBAAiB,KAAA,GACpE,MAAM,IAAI,MAAM,uBAAuB,MAAM,+DAA+D;EAE9G,IAAI,iBAAiB,KAAA,GAAW,aAAa,YAAY;EACzD,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,aAAa,CAAC,CAAC,GAChD,IAAI,CAAC,MAAM,IAAI,GAAG,GAChB,MAAM,IAAI,MAAM,uBAAuB,MAAM,wCAAwC,IAAI,EAAE;CAGjG;AACF;;;;;;;;;AAUA,SAAgB,YAAY,KAAc,QAAoD;CAC5F,MAAM,EAAE,QAAQ,UAAU;CAC1B,MAAM,WAAW,YACf,WAAW,OAAO,QAAQ,OAAO,SAAS,UAAU,QAAQ,OAAO,SAAS,KAAK;CAGnF,MAAM,cAAc,YAClB,QAAQ,OAAO,SAAS,QAAQ,WAAW;CAI7C,IAAI,YAA+B,CAAC;CACpC,MAAM,yBAA+B;EACnC,KAAK,MAAM,WAAW,WAAW,QAAQ;EACzC,YAAY,CAAC;EACb,MAAM,SAAS,OAAO,IAAI;EAC1B,eAAe,MAAM;EACrB,MAAM,aAAa,KAAK,IAAI,GAAG,GAAG,OAAO,KAAI,UAAS,MAAM,KAAK,CAAC,IAAI;EACtE,UAAU,KAAK,IAAI,aAAa,QAAQ;GACtC,MAAM;GACN,OAAO;GACP,OAAO,YACL,WAAW,OAAO,IAAI,KAAM,QAAQ,OAAO,CAAC,EAAE,YAAA,WAA2B;EAC7E,CAAC,CAAC;EACF,KAAK,MAAM,SAAS,QAClB,UAAU,KAAK,IAAI,aAAa,QAAQ;GACtC,MAAM,gBAAgB,MAAM;GAC5B,OAAO,MAAM;GACb,OAAO,YACL,WAAW,OAAO,IAAI,KAAM,QAAQ,OAAO,CAAC,EAAE,YAAY,MAAM,SAAS,MAAM;EACnF,CAAC,CAAC;EAEJ,UAAU,KAAK,IAAI,aAAa,QAAQ;GACtC,MAAM,gBAAgB;GACtB,OAAO;GACP,OAAO,YAAY,QAAQ,OAAO,CAAC,EAAE,UAAU;EACjD,CAAC,CAAC;CACJ;CACA,iBAAiB;CACjB,IAAI,aAAa,OAAO,UAAU,gBAAgB,CAAC;CAEnD,MAAM,eAAe,gBAAgB;CAIrC,MAAM,yBAAS,IAAI,QAAgG;CACnH,IAAI,GAAG,0BAA0B,OAAO,WAAW,SAAS,SAAS;EACnE,MAAM,YAAY,MAAM,KAAK;EAC7B,IAAI,WAAW,UAAU,UAAU,YAAY,QAAQ,OAAO,SAAS;EACvE,IAAI,QAAQ,UAAU,UAAU,SAAS,QAAQ,OAAO,SAAS;EACjE,MAAM,QAAQ,QAAQ;EACtB,IAAI,UAAU,KAAA,GAAW;GACvB,MAAM,SAAS,OAAO,IAAI,KAAK;GAC/B,IAAI,WAAW,KAAA,KAAa,OAAO,cAAc,MAAM,QAAQ,IAAI;IACjE,WAAW,OAAO;IAClB,QAAQ,OAAO;GACjB,OAAO,IAAI,aAAa,KAAA,KAAa,UAAU,KAAA,GAC7C,OAAO,IAAI,OAAO;IAAE,WAAW,MAAM,QAAQ;IAAI;IAAU;GAAM,CAAC;EAEtE;EACA,MAAM,OAAO,WAAW,OAAO,UAAU,KAAK;EAC9C,MAAM,SAAS,OAAO,IAAI;EAI1B,MAAM,cAAc,YAAkD;GACpE,IAAI,QAAQ,SAAS,cACnB,OAAO,WAAW,OAAO,IAAI,KAAM,QAAQ,OAAO,CAAC,EAAE,YAAA,WAA2B;GAElF,MAAM,QAAQ,OAAO,MAAK,MAAK,QAAQ,SAAS,gBAAgB,EAAE,MAAM;GACxE,IAAI,UAAU,KAAA,GAAW,OAAO,KAAA;GAChC,OAAO,WAAW,OAAO,IAAI,KAAM,QAAQ,OAAO,CAAC,EAAE,YAAY,MAAM,SAAS,MAAM;EACxF;EACA,MAAM,WAAW,UAAU,SAAS,KAAK,YAAY;GAGnD,IAAI,QAAQ,SAAS,kBAAkB;IACrC,MAAM,WAAW,OAAO,YAAY;IACpC,IAAI,aAAa,MAAM,WAAW,OAAO,KAAK,QAAQ,SAAS,sBAAsB,OAAO;IAC5F,OAAO;KAAE,GAAG;KAAS,MAAM;IAAS;GACtC;GACA,IAAI,QAAQ,SAAS,cACnB,OAAO;IAAE,GAAG;IAAS,MAAM,MAAM,UAAU;GAAG;GAEhD,MAAM,MAAM,WAAW,OAAO;GAC9B,IAAI,QAAQ,KAAA,KAAa,QAAQ,SAAS,KAAK,OAAO;GACtD,IAAI,QAAQ,SAAS,cACnB,OAAO;IAAE,GAAG;IAAS,MAAM,WAAW,OAAO,IAAI,KAAM,MAAM,YAAA,WAA2B;GAAW;GAErG,MAAM,QAAQ,OAAO,MAAK,MAAK,QAAQ,SAAS,gBAAgB,EAAE,MAAM;GACxE,OAAO;IAAE,GAAG;IAAS,MAAM,WAAW,OAAO,IAAI,KAAM,MAAM,YAAY,MAAM,SAAS,MAAM;GAAM;EACtG,CAAC;EACD,OAAO;GAAE,GAAG;GAAW;EAAS;CAClC,CAAC;AACH;;;;ACrKA,MAAa,oBAAoB;;AAEjC,MAAa,2BAA2B;;AAwBxC,SAAS,IAAI,QAAuB,UAAmC;CACrE,OAAO,aAAa,KAAK,EAAE,OAAO,IAAI;EAAE;EAAQ;CAAS;AAC3D;;AAGA,SAAgB,oBAAoB,QAAuB,YAAiC;CAC1F,MAAM,OAAO,UAA+B,GAAG,MAAM,KAAK,GAAG,OAAO,MAAM,KAAK;CAC/E,MAAM,OAAO,WAAW,IAAI,GAAG,CAAC,CAAC,KAAK;CACtC,MAAM,SAAS,OAAO,IAAI,GAAG,CAAC,CAAC,KAAK;CACpC,IAAI,OAAO,WAAW,KAAK,UAAU,OAAO,MAAM,GAAG,MAAM,MAAM,KAAK,EAAE,GACtE,MAAM,IAAI,MAAM,2CAA2C,WAAW,KAAI,MAAK,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,+BAA+B;AAErI;;AAGA,SAAgB,gBAAgB,QAAuB,YAA0C;CAC/F,OAAO,WAAW,KAAI,UAAS;EAC7B,GAAG;EACH,MAAM,OAAO,MAAK,UAAS,MAAM,SAAS,KAAK,IAAI,CAAC,EAAE,QAAQ,KAAK;CACrE,EAAE;AACJ;;;;;;AAOA,eAAsB,gBAAgB,QAA2B,YAAiD;CAChH,MAAM,EAAE,cAAc,SAAS;CAC/B,eAAe,UAAU;CACzB,IAAI;CACJ,IAAI;CACJ,MAAM,WAAW,aAAa,IAAI,iBAAiB;CACnD,IAAI,aAAa,KAAA,GAAW;EAG1B,QAAQ,gBAAgB,SAAS,QAAQ,UAAU;EACnD,eAAe,KAAK;EACpB,WAAW,SAAS,YAAY;EAChC,MAAM,aAAa,IAAI,mBAAmB,IAAI,OAAO,QAAQ,CAAC;CAChE,OAAO;EACL,QAAQ;EACR,WAAW;EACX,MAAM,aAAa,IAAI,mBAAmB,EAAE,QAAQ,MAAM,CAAC;CAC7D;CACA,IAAI,KAAK,IAAA,sBAA4B,MAAM,KAAA,GACzC,MAAM,KAAK,IAAI,0BAA0B,EAAE,OAAO,IAAI,CAAC;CAGzD,MAAM,4BAAY,IAAI,IAAgB;CACtC,MAAM,eAAqB;EAAE,KAAK,MAAM,YAAY,CAAC,GAAG,SAAS,GAAG,SAAS;CAAE;CAE/E,OAAO;EACL,WAAW;EACX,mBAAmB;EACnB,MAAM,IAAI,QAAsC;GAC9C,eAAe,MAAM;GACrB,oBAAoB,QAAQ,UAAU;GACtC,MAAM,aAAa,IAAI,mBAAmB,IAAI,QAAQ,QAAQ,CAAC;GAC/D,QAAQ;GACR,OAAO;EACT;EACA,MAAM,YAAY,MAA6B;GAC7C,MAAM,aAAa,IAAI,mBAAmB,IAAI,OAAO,IAAI,CAAC;GAC1D,WAAW;GACX,OAAO;EACT;EACA,MAAM,QAAuB;GAC3B,MAAM,aAAa,OAAO,iBAAiB;GAC3C,MAAM,KAAK,OAAO,wBAAwB;GAC1C,MAAM,aAAa,IAAI,mBAAmB,EAAE,QAAQ,WAAW,CAAC;GAChE,MAAM,KAAK,IAAI,0BAA0B,EAAE,OAAO,IAAI,CAAC;GACvD,QAAQ;GACR,WAAW;GACX,OAAO;EACT;EACA,UAAU,UAAkC;GAC1C,UAAU,IAAI,QAAQ;GACtB,aAAa;IAAE,UAAU,OAAO,QAAQ;GAAE;EAC5C;CACF;AACF;;;AC9GA,SAAgB,uBACd,KACA,UACM;CAKN,IAAI,OAAO,CAAC,WAAW,IAAI,WAAW;EACpC,OAAO,aAAa,SAAS,MAAM,CAAC;CACtC,CAAC;AACH;ACVA,SAAgBE,OAAK,KAAqB,MAAc,MAAqB;CAC3E,IAAI,UAAU,MAAM,EAAE,gBAAgB,mBAAmB,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC;AACtF;;AAGA,eAAsBC,eAAa,KAAsB,KAAmD;CAC1G,MAAM,SAAmB,CAAC;CAC1B,IAAI,WAAW;CACf,WAAW,MAAM,SAAS,KAAK;EAC7B,MAAM,SAAS;EACf,YAAY,OAAO;EACnB,IAAI,WAAA,OAA2B;GAC7B,OAAK,KAAK,KAAK,EAAE,OAAO,iBAAiB,CAAC;GAC1C,IAAI,QAAQ;GACZ;EACF;EACA,OAAO,KAAK,MAAM;CACpB;CACA,IAAI;EACF,OAAO,KAAK,MAAM,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC;CAC1D,QAAQ;EACN,OAAK,KAAK,KAAK,EAAE,OAAO,oBAAoB,CAAC;EAC7C;CACF;AACF;;;ACFA,MAAM,mBAAmBC,IAAE,OAAO;CAAE,QAAQA,IAAE,MAAM,iBAAiB;CAAG,kBAAkBA,IAAE,OAAO,CAAC,CAAC,SAAS;AAAE,CAAC;AAEjH,SAAgB,6BAA6B,MAAyF;CACpI,OAAO,OAAO,KAAK,QAAQ;EAEzB,MAAM,MAAM,IADI,IAAI,IAAI,OAAO,KAAK,kBACtB,CAAC,CAAC,SAAS,QAAQ,4CAA4C,EAAE,KAAK;EACpF,MAAM,SAAS,IAAI,UAAU;EAE7B,IAAI,QAAQ,OAAO,WAAW,OAAO;GACnC,IAAI,SAAsB;IAAE,UAAU,CAAC;IAAG,UAAU,CAAC;GAAE;GACvD,IAAI;IACF,SAAS,MAAM,KAAK,MAAM;GAC5B,QAAQ,CAAiD;GACzD,OAAK,KAAK,KAAK;IAAE,QAAQ,KAAK,OAAO,IAAI;IAAG,OAAO,KAAK;IAAO,YAAY,KAAK;IAAY;IAAQ,mBAAmB;IAAW,kBAAkB,KAAK,OAAO,YAAY;GAAE,CAAC;GAC/K;EACF;EAEA,IAAI,QAAQ,OAAO,WAAW,OAAO;GACnC,MAAM,OAAO,MAAMC,eAAa,KAAK,GAAG;GACxC,IAAI,SAAS,KAAA,GAAW;GACxB,MAAM,SAAS,iBAAiB,UAAU,IAAI;GAC9C,IAAI,CAAC,OAAO,SAAS;IACnB,OAAK,KAAK,KAAK,EAAE,OAAO,OAAO,MAAM,OAAO,EAAE,EAAE,WAAW,sBAAsB,CAAC;IAClF;GACF;GACA,IAAI;IACF,eAAe,OAAO,KAAK,MAAM;IACjC,oBAAoB,OAAO,KAAK,QAAQ,KAAK,UAAU;GACzD,SAAS,OAAO;IACd,OAAK,KAAK,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,CAAC;IAChF;GACF;GACA,IAAI;IACF,MAAM,KAAK,OAAO,IAAI,OAAO,KAAK,MAAM;IACxC,IAAI,OAAO,KAAK,qBAAqB,KAAA,GACnC,MAAM,KAAK,OAAO,YAAY,OAAO,KAAK,gBAAgB;GAE9D,SAAS,OAAO;IACd,OAAK,KAAK,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,CAAC;IAChF;GACF;GACA,OAAK,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;GAC3B;EACF;EAEA,IAAI,QAAQ,YAAY,WAAW,QAAQ;GACzC,IAAI;IACF,MAAM,KAAK,OAAO,MAAM;GAC1B,SAAS,OAAO;IACd,OAAK,KAAK,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,CAAC;IAChF;GACF;GACA,OAAK,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;GAC3B;EACF;EAEA,IAAI,QAAQ,YAAY,QAAQ,KAAK;GACnC,OAAK,KAAK,KAAK,EAAE,OAAO,qBAAqB,CAAC;GAC9C;EACF;EACA,OAAK,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;CACvC;AACF;;AAGA,SAAgB,qBAAqB,KAAc,MAAiC;CAClF,MAAM,UAAU,6BAA6B,IAAI;CACjD,uBAAuB,MAAM,WAAW;EACtC,MAAM,UAAU,OAAO,UAAU,SAAS;GAAE,MAAM;GAAU,MAAM;GAAwC;EAAQ,CAAC;EACnH,aAAa,QAAQ;CACvB,CAAC;AACH;;;;AC5FA,MAAM,aAAa,aAA6B,iBAAiB,SAAS;;;;AAK1E,MAAM,YAAY;;;;;;;;;AAUlB,SAAgB,kBACd,QACA,MACA,OACQ;CACR,MAAM,OAAO,WAAW,OAAO,OAAO,OAAO,UAAU,OAAO,KAAK;CACnE,MAAM,QAAQ,CAAC,MAAM,WAAW,QAAQ,SAAS;CACjD,IAAI,KAAK,YAAY,KAAA,KAAa,KAAK,QAAQ,KAAK,CAAC,CAAC,SAAS,GAAG,MAAM,KAAK,KAAK,OAAO;CACzF,IAAI,MAAM,WAAW,KAAA,GAAW,MAAM,KAAK,KAAK,MAAM;CACtD,OAAO;EAAC,UAAU,KAAK,IAAI;EAAG;EAAW,GAAG;CAAK,CAAC,CAAC,KAAK,MAAM;AAChE;;;;ACAA,SAAS,gBAAgB,QAA4C;CACnE,QAAQ,OAAO,YAAf;EACE,KAAK,aAAa;EAClB,KAAK,WAAW,OAAO;EACvB,KAAK,SAAS,OAAO;EACrB,KAAK,cAAc,OAAO;EAC1B,KAAK,WAAW,OAAO;EACvB,SAAS,OAAO,YAAY,OAAO,OAAO,UAAU,EAAE;CACxD;AACF;;AAGA,SAAS,gBAAgB,OAAe,QAAgC;CACtE,MAAM,OAAO,OACV,QAAQ,UAA4D,MAAM,SAAS,MAAM,CAAC,CAC1F,KAAI,UAAS,MAAM,IAAI,CAAC,CACxB,KAAK,EAAE;CACV,OAAO,KAAK,WAAW,IAAI,QAAQ,GAAG,MAAM,iBAAiB;AAC/D;;AAGA,eAAe,oBAAoB,KAAkB,QAAgB,OAAuB;CAE1F,MAAM,iBAAiB,OAAO,IAAI,EAAE;CACpC,MAAM,CAAC,aAAa,MAAM,QAAQ,WAAW,CAC3C,IAAI,OAAO,MAAM,WAAW;EAC1B,MAAM,QAAQ,gBAAgB,MAAM;EACpC,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,gBAAgB,OAAO,OAAO,MAAM,CAAC;EAC9E,OAAO;GACL,MAAM;GACN,MAAM;GACN,OAAO,OAAO,IAAI,EAAE;GACpB;GACA,QAAQ,OAAO;GACf,GAAG,UAAU,KAAA,IAAY;IAAE,UAAU,MAAM;IAAU,OAAO,MAAM;GAAM,IAAI,CAAC;EAC/E;CACF,CAAC,CACH,CAAC;CACD,MAAM,CAAC,YAAY,MAAM,QAAQ,WAAW,CAAC,QAAQ,QAAQ,CAAC,CAAC,WAAW,IAAI,QAAQ,CAAC,CAAC,CAAC;CACzF,IAAI,UAAU,WAAW,YAAY;EACnC,IAAI,SAAS,WAAW,YACtB,MAAM,IAAI,eAAe,CAAC,UAAU,QAAQ,SAAS,MAAM,GACzD,UAAU,OAAO,UAAU,MAAM,EAAE,cAAc,OAAO,SAAS,MAAM,GAAG;EAE9E,MAAM,UAAU;CAClB;CACA,IAAI,SAAS,WAAW,YAAY,MAAM,SAAS;CACnD,OAAO,UAAU;AACnB;;;;;;;;;;AAWA,SAAgB,mBAAmB,UAAkB,MAAwB;CAsH3E,OArHa,WAAW;EACtB,MAAM;EACN,aACE;EAIF,YAAY;GACV,MAAM;IAAE,MAAM;IAAU,UAAU;IAAM,aAAa;GAA8D;GACnH,aAAa;IAAE,MAAM;IAAU,UAAU;IAAM,aAAa;GAAqE;GACjI,QAAQ;IAAE,MAAM;IAAU,UAAU;IAAM,aAAa;GAAoI;EAC7L;EACA,QAAQ;GACN,QAAQ;IACN,MAAM;IACN,sBAAsB;IACtB,YAAY;KACV,MAAM;MAAE,MAAM;MAAU,UAAU;MAAM,OAAO;KAAa;KAC5D,MAAM;MAAE,MAAM;MAAU,UAAU;KAAK;KACvC,OAAO;MAAE,MAAM;MAAU,UAAU;KAAK;KACxC,gBAAgB;MAAE,MAAM;MAAU,UAAU;KAAK;KACjD,QAAQ;MAAE,MAAM;MAAS,UAAU;MAAM,OAAO,EAAE,MAAM,OAAO;KAAE;KACjE,UAAU,EAAE,MAAM,SAAS;KAC3B,OAAO,EAAE,MAAM,SAAS;IAC1B;GACF;GACA,SAAS,OAAO,UAAU,CAAC;IACzB,MAAM;IACN,MAAO,MAAM,OACV,QAAO,UAAS,MAAM,SAAS,UAAU,OAAO,MAAM,SAAS,QAAQ,CAAC,CACxE,KAAI,UAAS,MAAM,IAAI,CAAC,CAAC,KAAK,EAAE;GACrC,CAAC;GAED,mBAAmB,OAAO,WAAW;IACnC,MAAM,MAAM;IACZ,OAAO,MAAM;IACb,gBAAgB,MAAM;IACtB,GAAG,OAAO,MAAM,aAAa,YAAY,OAAO,MAAM,UAAU,WAC5D;KAAE,UAAU,MAAM;KAAU,OAAO,MAAM;IAAM,IAC/C,CAAC;GACP;EACF;EAEA,yBAAyB;EAGzB,cAAc,UAAU;GACtB,MAAM;GACN,OAAO,QAAQ,KAAK,KAAK,IAAI,KAAK;GAClC,UAAU,KAAK;EACjB;EACA,gBAAgB,OAAO,WAAY,OAAO,UAAU,KAAA,IAAY,EAAE,MAAM,UAAmB;EAC3F,MAAM,QAAQ,MAAM,MAAM;GACxB,MAAM,SAA4B,KAAK;GACvC,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,0CAA0C;GAEvE,MAAM,SAAS,KAAK,OAAO,CAAC,CAAC,QAAO,MAAK,EAAE,OAAO,UAAU,cAAc,CAAC,CAAC;GAC5E,MAAM,OAAO,OAAO,MAAK,MAAK,EAAE,OAAO,KAAK,IAAI;GAChD,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,SAAS,KAAK,KAAK,SAAS,OAAO,KAAI,MAAK,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,GAAG;GAEhF,MAAM,UAAU,KAAK,aAAa,IAAI;GAKtC,IAAI;GACJ,IAAI,KAAK,UAAU,KAAA,GAAW;IAC5B,MAAM,UAAU,IAAI,IAAI,KAAK,eAAe,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAM,aAAa,CAAC;IACtF,MAAM,YAAY,KAAK,MAAM,MAAM,QAAQ,MAAM,QAAQ,IAAI,CAAC,CAAC;IAC/D,MAAM,UAAU,KAAK,MAAM,MAAM,QAAQ,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;IAC9D,IAAI,QAAQ,SAAS,GACnB,KAAK,KAAK,yBAAyB,KAAK,GAAG,sBAAsB,QAAQ,KAAK,IAAI,GAAG;IAEvF,IAAI,UAAU,WAAW,GACvB,MAAM,IAAI,MAAM,yBAAyB,KAAK,GAAG,gBAAgB,KAAK,MAAM,MAAM,OAAO,UAAU,KAAK,MAAM,MAAM,KAAK,IAAI,GAAG;IAElI,aAAa,EAAE,OAAO,UAAU;GAClC;GACA,MAAM,UAAgC;IACpC,OAAO,QAAQ,KAAK,GAAG,IAAI,KAAK;IAChC,QAAQ,CAAC;KAAE,MAAM;KAAQ,MAAM,KAAK;IAAO,CAAiB;IAC5D;IACA;IACA,UAAU;IACV,QAAQ,KAAK;IACb,GAAG,KAAK,UAAU,KAAA,IACd,EAAE,cAAc;KAAE,UAAU,KAAK,MAAM;KAAU,OAAO,KAAK,MAAM;IAAM,EAAE,IAC3E,CAAC;IACL,GAAG,eAAe,KAAA,IACd,EAAE,WAAW,IACb,CAAC;GACP;GAGA,MAAM,SACH,KAAK,UAAU,KAAA,KAAa,KAAK,MAAM,aAAa,MAAM,KAAK,MAAM,UAAU,KAC5E,KAAK,QACL,KAAA,OACA,OAAO,OAAO,QAAQ,aAAa,YAAY,OAAO,QAAQ,aAAa,MACxE,OAAO,OAAO,QAAQ,UAAU,YAAY,OAAO,QAAQ,UAAU,KACxE;IAAE,UAAU,OAAO,QAAQ;IAAU,OAAO,OAAO,QAAQ;GAAM,IACjE,KAAA;GACN,MAAM,kBAAkB,OAAO,OAAO,QAAQ,EAAE;GAChD,IAAI,UAAU,KAAA,GAAW,KAAK,OAAO,IAAI,iBAAiB,KAAK,IAAI,KAAK;GACxE,IAAI;IACF,MAAM,MAAM,MAAM,KAAK,SAAS,KAAK,UAAU,OAAO;IACtD,IAAI,UAAU,KAAA,GAEZ,MAAM,KAAK,YAAY,OAAO,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;IAErE,OAAO,MAAM,oBAAoB,KAAK,KAAK,IAAI,KAAK;GACtD,UAAU;IACR,IAAI,UAAU,KAAA,GAAW,KAAK,OAAO,OAAO,iBAAiB,KAAK,EAAE;GACtE;EACF;CACF,CACU;AACZ;;;;ACjMA,MAAM,qBAAqB;;;;;;AAO3B,SAAgB,gBACd,UACA,OACA,aACQ;CACR,IAAI,CAAC,aAAa,OAAO;CAKzB,OAAO,gBAAgB,SAAS,+CAJb,MAChB,QAAO,MAAK,EAAE,OAAO,UAAU,cAAc,CAAC,CAAC,CAAC,CAChD,KAAI,MAAK,GAAG,EAAE,GAAG,IAAI,EAAE,eAAe,EAAE,MAAM,CAAC,CAC/C,KAAK,IACgF;AAC1F;;;;;;;AAuBA,SAAgB,cAAc,KAAc,QAAwB,UAAyB,UAAkC;CAC7H,MAAM,EAAE,UAAU,aAAa;CAC/B,IAAI;CACJ,IAAI,iBAAiB;CACrB,MAAM,aAAa,MAA8B;EAC/C,MAAM,UAAoB,CAAC;EAC3B,IAAI,CAAC,EAAE,aAAa,SAAS,QAAQ,KAAK,SAAS;EACnD,IAAI,CAAC,EAAE,aAAa,YAAY,QAAQ,KAAK,YAAY;EACzD,IAAI,QAAQ,SAAS,GACnB,MAAM,IAAI,MACR,gCAAgC,EAAE,KAAK,4BAA4B,QAAQ,KAAK,GAAG,EAAE,mFACvF;EAEF,IAAI,gBAAgB,KAAA,GAClB,cAAc,IAAI,MAAM,SAAS,mBAAmB,UAAU;GAC5D,cAAc,SAAS,KAAK;GAC5B;GACA,eAAe,SACb,kBAAkB,EAAE,OAAO,OAAO,MAAM,GAAG,MAAM,KAAK,KAAK;GAC7D,WAAW,IAAI,YAAY,IAAI,UAAU,MAAM,IAAI,OAAO;GAC1D,QAAQ,SAAS;GACjB,aAAa,SAAS;GAItB,iBAAiB,UAAU,MAAM,IAAI,MAAM,QAAQ,QAAQ,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI;GACxF,OAAO,QAAQ;IAAE,IAAI,OAAO,KAAK,GAAG;GAAE;EACxC,CAAC,CAAC;CAEN;CACA,IAAI,GAAG,4BAA4B,MAAM;EACvC,IAAI,EAAE,SAAS,YAAY,gBAAgB;EAC3C,IAAI;GACF,UAAU,CAAC;EACb,SAAS,OAAO;GACd,iBAAiB;GACjB,IAAI,OAAO,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EACzE;CACF,CAAC;CACD,IAAI,GAAG,8BAA8B,YAAY;EAC/C,IAAI,YAAY,UAAU;EAC1B,iBAAiB;EACjB,IAAI,gBAAgB,KAAA,GAAW;GAC7B,YAAY;GACZ,cAAc,KAAA;EAChB;CACF,CAAC;CACD,MAAM,UAAU,IAAI,UAAU,YAAY,QAAQ;CAClD,IAAI,YAAY,KAAA,GACd,UAAU,OAAO;MAEjB,IAAI,OAAO,KAAK,yCAAyC,SAAS,8BAA8B;CAElG,IAAI,aAAa,QAAQ;EACvB,MAAM;EACN,OAAO;EACP,OAAO,YAAY,gBACjB,OAAO,UACP,SAAS,KAAK,GAId,IAAI,MAAM,IAAI,OAAO,UAAU,QAAQ,KAAK,MAAM,KAAA,CACpD;CACF,CAAC;AACH;;;ACxGA,SAAgB,qBAAmC;CACjD,MAAM,sBAAM,IAAI,IAA2B;CAC3C,MAAM,OAAO,WAAmB,WAA2B,GAAG,UAAU,GAAG;CAC3E,OAAO;EACL,MAAM,WAAW,QAAQ,UAAU;GAAE,IAAI,IAAI,IAAI,WAAW,MAAM,GAAG,KAAK;EAAE;EAC5E,MAAM,WAAW,WAAW,IAAI,IAAI,IAAI,WAAW,MAAM,CAAC;EAC1D,SAAS,WAAW,WAAW;GAAE,IAAI,OAAO,IAAI,WAAW,MAAM,CAAC;EAAE;CACtE;AACF;;;;ACdA,MAAa,8BAA8BC,IAAE,OAAO;CAClD,UAAUA,IAAE,OAAO;CACnB,OAAOA,IAAE,OAAO;CAChB,IAAIA,IAAE,OAAO;AACf,CAAC;AAID,MAAa,yBAAyB,aAAa;CACjD,MAAM;CACN,SAAS;CACT,QAAQ,EAEN,QAAQ,YAA2C,2BAA2B,EAChF;AACF,CAAC;;;ACZD,SAAgB,yBAAyB,MAAqF;CAC5H,OAAO,OAAO,KAAK,QAAQ;EACzB,MAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB;EACtD,MAAM,MAAM,IAAI,SAAS,QAAQ,6BAA6B,EAAE,KAAK;EACrE,IAAI,IAAI,WAAW,OAAO;GACxB,OAAK,KAAK,KAAK,EAAE,OAAO,qBAAqB,CAAC;GAC9C;EACF;EACA,IAAI,QAAQ,oBAAoB;GAC9B,MAAM,QAAQ,KAAK,OAAO,IAAI,IAAI,aAAa,IAAI,SAAS,KAAK,IAAI,IAAI,aAAa,IAAI,MAAM,KAAK,EAAE;GACvG,IAAI,UAAU,KAAA,GAAW;IACvB,OAAK,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;IACrC;GACF;GACA,OAAK,KAAK,KAAK;IAAE,UAAU,MAAM;IAAU,OAAO,MAAM;GAAM,CAAC;GAC/D;EACF;EACA,IAAI,QAAQ,mBAAmB;GAC7B,MAAM,SAAS,KAAK,OAAO,IAAI,IAAI,aAAa,IAAI,SAAS,KAAK,EAAE;GACpE,IAAI,WAAW,KAAA,GAAW;IACxB,OAAK,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;IACrC;GACF;GACA,OAAK,KAAK,KAAK;IAAE,UAAU,OAAO;IAAU,OAAO,OAAO;GAAM,CAAC;GACjE;EACF;EACA,OAAK,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;CACvC;AACF;;;;;AAMA,SAAgB,iBAAiB,KAAc,MAA6B;CAC1E,MAAM,UAAU,yBAAyB,IAAI;CAC7C,uBAAuB,MAAM,WAAW;EACtC,MAAM,aAAa,OAAO,UAAU,SAAS;GAAE,MAAM;GAAU,MAAM;GAAmC;EAAQ,CAAC;EACjH,aAAa,WAAW;CAC1B,CAAC;AACH;;;AC/BA,SAAgB,uBAAuB,MAAmF;CACxH,OAAO,OAAO,KAAK,QAAQ;EAEzB,MAAM,MAAM,IADI,IAAI,IAAI,OAAO,KAAK,kBACtB,CAAC,CAAC,SAAS,QAAQ,6BAA6B,EAAE,KAAK;EACrE,MAAM,SAAS,IAAI,UAAU;EAE7B,IAAI,QAAQ,aAAa,WAAW,OAAO;GACzC,OAAK,KAAK,KAAK,KAAK,SAAS,KAAK,CAAC;GACnC;EACF;EAEA,IAAI,QAAQ,YAAY,WAAW,OAAO;GAExC,OAAK,KAAK,KAAK;IAAE,QAAQ,MAAM,KAAK,gBAAgB;IAAG,QAAQ,KAAK,UAAU;GAAE,CAAC;GACjF;EACF;EAEA,IAAI,QAAQ,gBAAgB,WAAW,OAAO;GAC5C,OAAK,KAAK,KAAK,KAAK,cAAc,CAAC;GACnC;EACF;EAEA,MAAM,cAAc,iCAAiC,KAAK,GAAG;EAC7D,IAAI,gBAAgB,QAAQ,WAAW,OAAO;GAE5C,IAAI,SAAwB,CAAC;GAC7B,IAAI;IACF,SAAS,MAAM,KAAK,WAAW,mBAAmB,YAAY,EAAE,CAAC;GACnE,QAAQ;IACN,SAAS,CAAC;GACZ;GACA,OAAK,KAAK,KAAK,MAAM;GACrB;EACF;EAEA,MAAM,aAAa,sBAAsB,KAAK,GAAG;EACjD,IAAI,eAAe,MAAM;GACvB,MAAM,KAAK,mBAAmB,WAAW,EAAE;GAE3C,IAAI,WAAW,OAAO;IACpB,MAAM,OAAO,MAAMC,eAAa,KAAK,GAAG;IACxC,IAAI,SAAS,KAAA,GAAW;IAGxB,MAAM,aAAsC,EAAE,GAAI,KAAiC;IACnF,OAAO,WAAW;IAClB,MAAM,YAAqC;KAAE,GAAG;KAAY;IAAG;IAI/D,IADiB,KAAK,SAAS,IAAI,EACxB,CAAC,EAAE,YAAY,MAAM,UAAU,UAAU;IACpD,MAAM,SAAS,kBAAkB,UAAU,SAAS;IACpD,IAAI,CAAC,OAAO,SAAS;KACnB,OAAK,KAAK,KAAK,EAAE,OAAO,OAAO,MAAM,OAAO,EAAE,EAAE,WAAW,uBAAuB,CAAC;KACnF;IACF;IACA,IAAI;KACF,MAAM,KAAK,SAAS,OAAO,OAAO,IAAI;IACxC,SAAS,OAAO;KACd,OAAK,KAAK,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,CAAC;KAChF;IACF;IACA,OAAK,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;IAC3B;GACF;GAEA,IAAI,WAAW,UAAU;IACvB,IAAI,KAAK,SAAS,IAAI,EAAE,MAAM,KAAA,GAAW;KACvC,OAAK,KAAK,KAAK,EAAE,OAAO,UAAU,GAAG,OAAO,CAAC;KAC7C;IACF;IACA,IAAI;KACF,MAAM,KAAK,SAAS,OAAO,EAAE;IAC/B,SAAS,OAAO;KACd,OAAK,KAAK,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,CAAC;KAChF;IACF;IACA,OAAK,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;IAC3B;GACF;GAEA,OAAK,KAAK,KAAK,EAAE,OAAO,qBAAqB,CAAC;GAC9C;EACF;EAEA,IAAI;GAAC;GAAW;GAAc;EAAQ,CAAC,CAAC,MAAM,MAAM,QAAQ,KAAK,IAAI,WAAW,GAAG,EAAE,EAAE,CAAC,GAAG;GACzF,OAAK,KAAK,KAAK,EAAE,OAAO,qBAAqB,CAAC;GAC9C;EACF;EACA,OAAK,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;CACvC;AACF;;;;;;;;;;;;AAaA,SAAgB,eAAe,KAAc,MAA2B;CACtE,MAAM,UAAU,uBAAuB,IAAI;CAC3C,uBAAuB,MAAM,WAAW;EACtC,MAAM,UAAU;GACd,OAAO,UAAU,SAAS;IAAE,MAAM;IAAU,MAAM;IAAiC;GAAQ,CAAC;GAC5F,OAAO,UAAU,SAAS;IAAE,MAAM;IAAU,MAAM;IAAoC;GAAQ,CAAC;GAC/F,OAAO,UAAU,SAAS;IAAE,MAAM;IAAS,MAAM;IAAgC;GAAQ,CAAC;GAC1F,OAAO,UAAU,SAAS;IAAE,MAAM;IAAU,MAAM;IAA0B;GAAQ,CAAC;EACvF;EACA,aAAa,QAAQ,SAAS,eAAe,WAAW,CAAC;CAC3D,CAAC;AACH;;;;AClHA,SAAgB,yBAAyB,OAAyC;CAChF,MAAM,QAAkB;EACtB;EACA;EACA;EACA;EACA;EACA;CACF;CACA,IAAI,MAAM,gBAAgB,IACxB,MAAM,KACJ,IACA,aACA,kBAAkB,MAAM,YAAY,uBACtC;CAEF,MAAM,KACJ,IACA,wBACA,MAAM,SAAS,KAAK,IAAI,GACxB,mDACA,IACA,aACA,gBAAgB,MAAM,YAAY,KAAK,IAAI,KAC3C,QAAQ,MAAM,YAAY,KAAK,IAAI,KACnC,iJACF;CACA,IAAI,MAAM,WAAW,KAAA,GACnB,MAAM,KACJ,IACA,SACA,sEACF;MAEA,MAAM,KACJ,IACA,oBACA,2CACA,YAAY,MAAM,OAAO,+CACzB,YAAY,MAAM,OAAO,8EACzB,qGACA,sDACA,2CACA,0BAA0B,MAAM,OAAO,sGACvC,sBAAsB,MAAM,OAAO,sGACnC,8EACF;CAEF,OAAO,MAAM,KAAK,IAAI;AACxB;;;;;;;;AAgBA,SAAgB,wBAAwB,KAAc,MAAoC;CACxF,IAAI,SAAS,SAAS;EACpB,MAAM;EACN,aAAa;EACb,OAAO,EAAE,MAAM,YAAY;EAC3B,SAAS,OAAO,EAAE,UAAU,YAA+E;GACzG,MAAM,YAAY,IAAI,IAAI,WAAW;GACrC,MAAM,SAAS,cAAc,KAAA,IAAY,KAAA,IAAY,oBAAoB,UAAU;GACnF,MAAM,OAAO,yBAAyB;IACpC,aAAa,SAAS,KAAK;IAC3B,UAAU,KAAK,SAAS,KAAK,CAAC,CAAC,KAAK,UAAU,MAAM,EAAE;IACtD,aAAa,MAAM,KAAK,gBAAgB;IACxC,aAAa,KAAK,UAAU;IAC5B;GACF,CAAC;GAED,MAAM,SAAS,kBAAkB;IAC/B,SAAS,CAAC;KAAE,MAAM;KAAQ;IAAK,CAAC;IAChC,QAAQ,EAAE,MAAM,OAAO;GACzB,CAAC,CAAC;GACF,OAAO;IAAE,MAAM;IAAW,MAAM;GAAwC;EAC1E;CACF,CAAC;AACH;;;;ACnGA,MAAa,0BAA0B;;;;;;;;AASvC,eAAsB,gBACpB,UACA,OACA,QACe;CACf,MAAM,OAAO,KAAK,QAAQ;CAC1B,IAAI,MAAM,YAAY,KAAA,GACpB,SAAS,aAAa,QAAQ;EAAE,MAAM;EAAyB,OAAO;EAAI,MAAM,MAAM;CAAQ,CAAC;CAEjG,IAAI,MAAM,aAAa,KAAA,GACrB,KAAK,MAAM,WAAW,MAAM,UAC1B,SAAS,aAAa,QAAQ;EAAE,MAAM,QAAQ;EAAM,OAAO,QAAQ;EAAO,MAAM,QAAQ;CAAK,CAAC;CAGlG,IAAI,MAAM,UAAU,KAAA,GAAW;EAI7B,MAAM,UAAU,IAAI,IAAI,SAAS,MAAM,QAAQ,QAAQ,QAAQ,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI,CAAC,CACjF,QAAQ,MAAM,MAAM,aAAa,CAAC;EACrC,MAAM,YAAY,MAAM,MAAM,QAAQ,MAAM,QAAQ,IAAI,CAAC,CAAC;EAC1D,MAAM,UAAU,MAAM,MAAM,QAAQ,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;EACzD,IAAI,QAAQ,SAAS,GACnB,SAAS,OAAO,KAAK,yCAAyC,QAAQ,KAAK,IAAI,GAAG;EAEpF,IAAI,UAAU,WAAW,GACvB,MAAM,IAAI,MAAM,mCAAmC,MAAM,MAAM,OAAO,UAAU,MAAM,MAAM,KAAK,IAAI,GAAG;EAE1G,SAAS,MAAM,SAAS,EAAE,OAAO,UAAU,CAAC;CAC9C;AACF;;;AC3CA,SAAgB,iBAAiB,KAAc,QAAqB,eAAyC;CAC3G,SAAS,WAAW,QAAgC;EAClD,MAAM,EAAE,UAAU;EAClB,OAAO;GACL,WAAW,OAAO,MAAM,EAAE;GAC1B,WAAW,YAAY,MAAM,SAAS,OAA+C;GACrF,cAAc,MAAM,OAAO,EAAE,MAAM,OAAO,CAAC;GAC3C,gBAAgB,MAAM,SAAS;EACjC;CACF;CACA,OAAO;EACL,MAAM,OAAO,OAAO;GAClB,eAAe,IAAI,MAAM,SAAS;GAOlC,OAAO,WAAW,MANgB,IAAI,OAAO,OAAO;IAClD,WAAW,UAAU,MAAM,SAAS;IACpC,MAAM,EAAE,KAAK,MAAM,IAAI;IACvB,GAAI,MAAM,iBAAiB,KAAA,IAAY,EAAE,cAAc,MAAM,aAAa,IAAI,CAAC;IAC/E,QAAQ,aAAa,gBAAgB,UAAU,MAAM,OAAO,MAAM;GACpE,CAAC,CACuB;EAC1B;EACA,MAAM,OAAO,OAAO;GAClB,eAAe,IAAI,MAAM,SAAS;GAMlC,OAAO,WAAW,MALgB,IAAI,OAAO,OAAO;IAClD,iBAAiB,UAAU,MAAM,SAAS;IAC1C,GAAI,MAAM,iBAAiB,KAAA,IAAY,EAAE,cAAc,MAAM,aAAa,IAAI,CAAC;IAC/E,QAAQ,aAAa,gBAAgB,UAAU,MAAM,OAAO,MAAM;GACpE,CAAC,CACuB;EAC1B;CACF;AACF;;;;ACnBA,SAAgB,gBAAgB,OAAoC;CAClE,MAAM,OAAQ,OAAgE,UAAU;CACxF,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM,OAAO,KAAA;CACtD,MAAM,OAAQ,KAA4B;CAC1C,OAAO,OAAO,SAAS,WAAW,OAAO,KAAA;AAC3C;;AAGA,MAAM,oBAAoB;CAAC;CAAa;CAAc;CAAc;AAAW;;AAI/E,SAAgB,oBAAoB,MAAkB,aAA0D;CAC9G,IAAI,KAAK,UAAU,KAAK,KAAK,OAAO,OAAQ,KAAK,OAAO,MAAQ,KAAK,OAAO,MAAQ,KAAK,OAAO,IAAM,OAAO;CAC7G,IAAI,KAAK,UAAU,KAAK,KAAK,OAAO,OAAQ,KAAK,OAAO,OAAQ,KAAK,OAAO,KAAM,OAAO;CACzF,IAAI,KAAK,UAAU,KAAK,KAAK,OAAO,MAAQ,KAAK,OAAO,MAAQ,KAAK,OAAO,MAAQ,KAAK,OAAO,IAAM,OAAO;CAC7G,IAAI,KAAK,UAAU,MACd,KAAK,OAAO,MAAQ,KAAK,OAAO,MAAQ,KAAK,OAAO,MAAQ,KAAK,OAAO,MACxE,KAAK,OAAO,MAAQ,KAAK,OAAO,MAAQ,KAAK,QAAQ,MAAQ,KAAK,QAAQ,IAAM,OAAO;CAC5F,MAAM,WAAW,OAAO,gBAAgB,WAAW,YAAY,MAAM,GAAG,CAAC,CAAC,EAAE,CAAE,KAAK,CAAC,CAAC,YAAY,IAAI;CACrG,OAAQ,kBAAwC,SAAS,QAAQ,IAC7D,WACA,KAAA;AACN;;AAGA,SAAgB,gBAAgB,QAAgC;CAC9D,OAAO;EACL,MAAM,WAAW,UAAU;GACzB,MAAM,MAAM,MAAM,OAAO,QAAQ,GAAG,KAAK,OAAO,EAAE,MAAM;IAAE,MAAM;IAAa,MAAM;GAAS,EAAE,CAAC;GAC/F,MAAM,SAAS,IAAI,MAAM;GACzB,IAAI,OAAO,WAAW,YAAY,OAAO,WAAW,GAClD,MAAM,IAAI,MAAM,qBAAqB,IAAI,KAAK,OAAO,IAAI,KAAK;GAEhE,OAAO;EACT;EACA,MAAM,gBAAgB,QAAQ,QAAQ;GACpC,MAAM,OAAO,GAAG,QAAQ,OAAO;IAC7B,QAAQ,EAAE,iBAAiB,UAAU;IACrC,MAAM;KAAE,YAAY;KAAQ,UAAU;KAAe,SAAS,KAAK,UAAU;MAAE,MAAM;MAAQ,MAAM,EAAE,SAAS,OAAO;KAAE,CAAC;IAAE;GAC5H,CAAC;EACH;EACA,MAAM,kBAAkB,QAAQ,WAAW,SAAS,UAAU;GAC5D,MAAM,OAAO,QAAQ,GAAG,YAAY,QAAQ;IAAE,MAAM;KAAE,SAAS;KAAQ,YAAY;IAAU;IAAG,MAAM;KAAE;KAAS;IAAS;GAAE,CAAC;EAC/H;EACA,MAAM,cAAc,QAAQ,aAAa,iBAAiB,UAAU;GAClE,MAAM,OAAO,QAAQ,GAAG,YAAY,OAAO;IACzC,MAAM,EAAE,SAAS,OAAO;IACxB,MAAM;KAAE,MAAM;KAAiB,mBAAmB;KAAiB,UAAU,IAAI,YAAY;KAAI;IAAS;GAC5G,CAAC;EACH;EACA,MAAM,iBAAiB,QAAQ,WAAW,UAAU,SAAS;GAC3D,MAAM,OAAO,QAAQ,GAAG,KAAK,SAAS;IACpC,MAAM,EAAE,SAAS,OAAO;IACxB,MAAM;KACJ,UAAU,KAAK,UAAU,EACvB,QAAQ;MACN,gBAAgB;MAChB,GAAI,YAAY,KAAA,IAAY,EAAE,SAAS,EAAE,SAAS,QAAQ,EAAE,IAAI,CAAC;KACnE,EACF,CAAC;KACD;IACF;GACF,CAAC;EACH;EACA,MAAM,YAAY,QAAQ,UAAU,UAAU;GAC5C,MAAM,OAAO,QAAQ,GAAG,KAAK,OAAO;IAAE,MAAM,EAAE,SAAS,OAAO;IAAG,MAAM;KAAE,MAAM;MAAE,MAAM;MAAa,MAAM;KAAS;KAAG;IAAS;GAAE,CAAC;EACpI;EACA,MAAM,SAAS,QAAQ,MAAM;GAC3B,MAAM,OAAO,GAAG,QAAQ,OAAO;IAC7B,QAAQ,EAAE,iBAAiB,UAAU;IACrC,MAAM;KAAE,YAAY;KAAQ,UAAU;KAAQ,SAAS,KAAK,UAAU,EAAE,KAAK,CAAC;IAAE;GAClF,CAAC;EACH;EACA,MAAM,YAAY,WAAW,WAAW;GACtC,MAAM,MAAM,MAAM,OAAO,GAAG,gBAAgB,OAAO;IACjD,MAAM,EAAE,YAAY,UAAU;IAC9B,MAAM,EAAE,eAAe,EAAE,YAAY,UAAU,EAAE;GACnD,CAAC;GACD,MAAM,aAAa,IAAI,MAAM;GAC7B,IAAI,OAAO,eAAe,UAAU,MAAM,IAAI,MAAM,cAAc,IAAI,KAAK,OAAO,IAAI,KAAK;GAC3F,OAAO;EACT;EACA,MAAM,eAAe,WAAW,YAAY;GAC1C,MAAM,OAAO,GAAG,gBAAgB,OAAO,EAAE,MAAM;IAAE,YAAY;IAAW,aAAa;GAAW,EAAE,CAAC;EACrG;EACA,MAAM,cAAc,WAAW,SAAS;GACtC,MAAM,MAAM,MAAM,OAAO,GAAG,gBAAgB,IAAI;IAC9C,QAAQ,EAAE,MAAM,QAAQ;IACxB,MAAM;KAAE,YAAY;KAAW,UAAU;IAAQ;GACnD,CAAC;GACD,MAAM,SAAmB,CAAC;GAC1B,MAAM,IAAI,SAAe,SAAS,WAAW;IAC3C,MAAM,SAAS,IAAI,kBAAkB;IACrC,OAAO,GAAG,SAAS,UAAU;KAAE,OAAO,KAAK,KAAe;IAAE,CAAC;IAC7D,OAAO,GAAG,aAAa,QAAQ,CAAC;IAChC,OAAO,GAAG,UAAU,UAAU,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC,CAAC;GACjG,CAAC;GACD,MAAM,OAAO,IAAI,WAAW,OAAO,OAAO,MAAM,CAAC;GACjD,MAAM,YAAY,oBAAoB,MAAM,IAAI,UAAU,eAAe;GACzE,IAAI,cAAc,KAAA,GAChB,MAAM,IAAI,MAAM,uBAAuB,QAAQ,gBAAgB,OAAO,IAAI,UAAU,mBAAmB,IAAI,EAAE,EAAE;GAEjH,OAAO;IAAE;IAAM;GAAU;EAC3B;EACA,MAAM,eAAe;GAEnB,MAAM,MAAM,MAAM,OAAO,QAAsE;IAC7F,QAAQ;IACR,KAAK;GACP,CAAC;GACD,MAAM,SAAS,IAAI,KAAK;GACxB,IAAI,OAAO,WAAW,YAAY,OAAO,WAAW,GAClD,MAAM,IAAI,MAAM,kBAAkB,IAAI,KAAK,OAAO,IAAI,KAAK;GAE7D,OAAO;EACT;CACF;AACF;;;;ACvIA,SAAgB,eAAe,MAAgC;CAC7D,MAAM,IAAI,KAAK,KAAK,CAAC,CAAC,YAAY;CAClC,IAAI,MAAM,QAAQ,OAAO;CACzB,IAAI,MAAM,SAAS,OAAO;CAC1B,IAAI,MAAM,WAAW,OAAO;CAC5B,OAAO;AACT;;AAGA,SAAgB,yBAAyB,MAAsB;CAC7D,OAAO,KAAK,QAAQ,kBAAkB,EAAE,CAAC,CAAC,KAAK;AACjD;;;;;ACkBA,SAAS,iBAAiB,SAAwD;CAChF,MAAM,YAAsB,CAAC;CAC7B,MAAM,aAAuB,CAAC;CAC9B,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,OAAO;EACjC,MAAM,OAAO,MAAM,QAAQ,OAAO,OAAO,IAAI,OAAO,UAAU,CAAC;EAC/D,KAAK,MAAM,aAAa,MAAM;GAC5B,IAAI,CAAC,MAAM,QAAQ,SAAS,GAAG;GAC/B,MAAM,QAAkB,CAAC;GACzB,KAAK,MAAM,QAAQ,WAAyB;IAC1C,IAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;IAC/C,IAAI,KAAK,QAAQ,OACX;SAAA,OAAO,KAAK,cAAc,YAAY,KAAK,UAAU,SAAS,GAAG,UAAU,KAAK,KAAK,SAAS;IAAA,OAC7F,KAAK,KAAK,QAAQ,UAAU,KAAK,QAAQ,QAAQ,OAAO,KAAK,SAAS,UAC3E,MAAM,KAAK,KAAK,IAAI;GAExB;GACA,WAAW,KAAK,MAAM,KAAK,EAAE,CAAC;EAChC;CACF,QAAQ;EACN,OAAO;GAAE,MAAM;GAAI,WAAW,CAAC;EAAE;CACnC;CACA,OAAO;EAAE,MAAM,WAAW,KAAK,IAAI;EAAG;CAAU;AAClD;;;;;;;;AASA,SAAgB,kBAAkB,MAAe,WAAyC;CACxF,MAAM,UAAU;CAChB,MAAM,QAAkB,QAAQ,SAAS;CACzC,IAAI,MAAM,QAAQ,gBAAgB,QAAQ,OAAO;CACjD,MAAM,SAAS,MAAM,OAAO,WAAW;CACvC,MAAM,MAAM,MAAM;CAClB,IAAI,OAAO,WAAW,YAAY,QAAQ,KAAA,GAAW,OAAO;CAC5D,IAAI,IAAI,iBAAiB,UAAU,IAAI,iBAAiB,UAAU,IAAI,iBAAiB,SAAS,OAAO;CACvG,IAAI,OAAO,IAAI,YAAY,UAAU,OAAO;CAC5C,IAAI,OAAO,IAAI,eAAe,YAAY,OAAO,IAAI,YAAY,UAAU,OAAO;CAClF,IAAI,IAAI,cAAc,SAAS,IAAI,cAAc,SAAS,OAAO;CACjE,IAAI,IAAI,cAAc,WACjB,EAAE,IAAI,YAAY,CAAC,EAAA,CAAG,MAAM,MAAM,EAAE,mBAAmB,SAAS,EAAE,IAAI,YAAY,SAAS,GAAG,OAAO;CAE1G,IAAI,OAAO;CACX,IAAI,YAAsB,CAAC;CAC3B,IAAI,IAAI,iBAAiB,QACvB,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,IAAI,OAAO;EACrC,IAAI,OAAO,OAAO,SAAS,UAAU,OAAO;EAC5C,OAAO,yBAAyB,OAAO,IAAI;CAC7C,QAAQ;EACN,OAAO;CACT;MACK,IAAI,IAAI,iBAAiB,QAAQ;EACtC,MAAM,OAAO,iBAAiB,IAAI,OAAO;EACzC,OAAO,yBAAyB,KAAK,IAAI;EACzC,YAAY,KAAK;CACnB,OACE,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,IAAI,OAAO;EACrC,IAAI,OAAO,OAAO,cAAc,YAAY,OAAO,UAAU,SAAS,GAAG,UAAU,KAAK,OAAO,SAAS;CAC1G,QAAQ;EACN,OAAO;CACT;CAEF,IAAI,KAAK,WAAW,KAAK,UAAU,WAAW,GAAG,OAAO;CAExD,OAAO;EAAE,WAAW,IAAI;EAAY,QAAQ,IAAI;EAAS,UAAU,IAAI;EAAW;EAAQ;EAAM;CAAU;AAC5G;;AAGA,IAAa,eAAb,MAA0B;CAIK;CAH7B,uBAAwB,IAAI,IAAY;CACxC,QAAmC,CAAC;CAEpC,YAAY,MAAuB,KAAM;EAAZ,KAAA,MAAA;CAAa;;CAG1C,MAAM,IAAqB;EACzB,IAAI,KAAK,KAAK,IAAI,EAAE,GAAG,OAAO;EAC9B,KAAK,KAAK,IAAI,EAAE;EAChB,KAAK,MAAM,KAAK,EAAE;EAClB,IAAI,KAAK,MAAM,SAAS,KAAK,KAAK,KAAK,KAAK,OAAO,KAAK,MAAM,MAAM,CAAE;EACtE,OAAO;CACT;AACF;;;ACpHA,MAAa,oBAAoB;;AAGjC,MAAa,kBAAkB;;AAG/B,MAAa,kBAAkB;;AAG/B,MAAM,mBAAmB;;AAGzB,MAAM,eAA2C;CAC/C,MAAM;CACN,OAAO;CACP,WAAW;AACb;;AAGA,MAAa,mBAAmB;;AAGhC,MAAM,qBAAqB;;AAqB3B,SAAgB,iBAAiB,MAAc,UAA0B;CACvE,IAAI,OAAO,WAAW,MAAM,MAAM,KAAK,UAAU,OAAO;CACxD,MAAM,SAAS,WAAW,OAAO,WAAW,iBAAiB,MAAM;CACnE,IAAI,UAAU,GAAG,MAAM,IAAI,MAAM,mBAAmB,SAAS,eAAe;CAC5E,IAAI,KAAK;CACT,IAAI,KAAK,KAAK;CACd,OAAO,KAAK,IAAI;EACd,MAAM,MAAM,KAAK,OAAO,KAAK,MAAM,CAAC;EACpC,IAAI,OAAO,WAAW,KAAK,MAAM,GAAG,GAAG,MAAM,KAAK,QAAQ,KAAK;OAC1D,KAAK,MAAM;CAClB;CACA,IAAI,MAAM;CACV,IAAI,MAAM,KAAK,QAAQ;EACrB,MAAM,OAAO,KAAK,WAAW,GAAG;EAChC,IAAI,QAAQ,SAAW,QAAQ,OAAS,OAAO;CACjD;CACA,OAAO,kBAAkB,KAAK,MAAM,GAAG;AACzC;;AAGA,SAAgB,WAAW,GAAmB;CAC5C,OAAO,OAAO,WAAW,KAAK,UAAU,CAAC,GAAG,MAAM,IAAI;AACxD;;AAGA,SAAgB,oBAAoB,MAAc,UAA0B;CAC1E,IAAI,WAAW,IAAI,KAAK,UAAU,OAAO;CACzC,IAAI,KAAK;CACT,IAAI,KAAK,KAAK;CACd,OAAO,KAAK,IAAI;EACd,MAAM,MAAM,KAAK,MAAM,KAAK,MAAM,CAAC;EACnC,IAAI,WAAW,KAAK,MAAM,GAAG,GAAG,CAAC,KAAK,UAAU,KAAK;OAChD,KAAK,MAAM;CAClB;CACA,IAAI,MAAM;CACV,IAAI,MAAM,GAAG;EACX,MAAM,OAAO,KAAK,WAAW,MAAM,CAAC;EACpC,IAAI,QAAQ,SAAW,QAAQ,OAAS,OAAO;CACjD;CACA,OAAO,KAAK,MAAM,GAAG,GAAG;AAC1B;;AAGA,SAAgB,cAAc,WAA2B;CACvD,OAAO,KAAK,UAAU;EACpB,QAAQ;EACR,QAAQ;GACN,gBAAgB;GAChB,SAAS,EAAE,SAAS,OAAO;GAC3B,kBAAkB;IAAE,oBAAoB,EAAE,SAAS,GAAG;IAAG,YAAY,EAAE,SAAS,UAAU;IAAG,gBAAgB;GAAO;EACtH;EACA,MAAM,EAAE,UAAU,CAAC;GAAE,KAAK;GAAY,SAAS;GAAkB,YAAY;EAAkB,CAAC,EAAE;CACpG,CAAC;AACH;;AAGA,SAAgB,iBAAiB,MAA0B,WAAmB,SAAyB;CACrG,IAAI,SAAS,WACX,OAAO,KAAK,UAAU;EACpB,KAAK;EACL,UAAU;EACV,QAAQ,EAAE,OAAO;GAAE,KAAK;GAAc,SAAS;EAAY,EAAE;EAC7D,UAAU,CAAC;GAAE,KAAK;GAAY;GAAS,YAAY;EAAU,CAAC;CAChE,CAAC;CAEH,OAAO,KAAK,UAAU;EAAE,KAAK;EAAY;EAAS,YAAY;CAAU,CAAC;AAC3E;AAqBA,MAAa,4BAAyC;CACpD,QAAQ;CAAM,KAAK;CAAG,WAAW;CAAG,cAAc;CAAG,YAAY;CACjE,gBAAgB;CAAG,MAAM,KAAA;CAAW,OAAO,KAAA;AAC7C;;AAiBA,SAAgB,SACd,OACA,UACA,UACA,iBACA,WACsB;CACtB,MAAM,MAAmB,CAAC;CAC1B,IAAI,EAAE,QAAQ,KAAK,WAAW,cAAc,YAAY,gBAAgB,MAAM,UAAU;;CAGxF,MAAM,QAAQ,OAAqB;EACjC,MAAM,OAAO;GAAE;GAAQ;GAAK;GAAW;GAAc;GAAY;GAAgB;GAAM;EAAM;EAC7F,IAAI,KAAK;GAAE;GAAI,eAAe,EAAE,GAAG,KAAK;EAAG,CAAC;CAC9C;CAEA,MAAM,mBAAyB;EAC7B,IAAI,WAAW,MAAM;EACrB,MAAM,WAAW,cAAc,SAAS;EACxC,SAAS;EACT,MAAM;EACN,YAAY,OAAO,WAAW,UAAU,MAAM;EAC9C,eAAe;EACf,KAAK;GAAE,MAAM;GAAU;EAAS,CAAC;EACjC,KAAK,EAAE,MAAM,OAAO,CAAC;CACvB;CAEA,MAAM,kBAAwB;EAE5B,OAAO;EACP,KAAK;GAAE,MAAM;GAAU,WAAW;GAAmB,SAAS;GAAkB,UAAU;EAAI,CAAC;EAC/F,OAAO;EACP,SAAS;EACT,OAAO,KAAA;EACP,KAAK;GAAE,MAAM;GAAY,WAAW;GAAO,UAAU;GAAK,SAAS;EAAiB,CAAC;CACvF;CAEA,IAAI,IAAI,MAAM,YAAY;CAC1B,OAAO,IAAI,SAAS,QAAQ;EAC1B,MAAM,MAAM,SAAS;EACrB,MAAM,UAAU,IAAI,SAAS,YAAY,iBAAiB,IAAI,SAAS,eAAe,IAAI,IAAI;EAC9F,MAAM,OAAO,SAAS,KAAA,KAAa,KAAK,aAAa,IACjD,KAAK,OACL,OAAO,aAAa,IAAI,MAAM,OAAO;EACzC,MAAM,iBAAiB,IAAI,SAAS,SAAS,QAAQ,MAAM,IAAI,IAAI;EAEnE,IAAI,SAAS,KAAA,KAAa,KAAK,aAAa,GAAG;GAE7C,IAAI,mBAAmB,KAAK,WAAW;IACrC,MAAM,QAAQ,WAAW,cAAc,IAAI,WAAW,KAAK,SAAS;IACpE,IAAI,YAAY,SAAS,UAAU;KACjC,OAAO;KACP,aAAa;KACb,OAAO;MAAE,GAAG;MAAM,WAAW;KAAe;KAC5C,KAAK;MAAE,MAAM;MAAU,WAAW,KAAK;MAAW,SAAS;MAAgB,UAAU;KAAI,CAAC;IAC5F,OAAO,IAAI,IAAI,SAAS,QAAQ;KAE9B,MAAM,QAAQ,oBAAoB,gBAAgB,WAAW,KAAK,SAAS,KAAK,WAAW,UAAU;KACrG,IAAI,MAAM,SAAS,KAAK,UAAU,QAAQ;MACxC,OAAO;MACP,aAAa,WAAW,KAAK,IAAI,WAAW,KAAK,SAAS;MAC1D,OAAO;OAAE,GAAG;OAAM,WAAW;MAAM;MACnC,KAAK;OAAE,MAAM;OAAU,WAAW,KAAK;OAAW,SAAS;OAAO,UAAU;MAAI,CAAC;KACnF;KACA,QAAQ;MAAE,UAAU;MAAG,MAAM,KAAK,OAAO,KAAK,UAAU;KAAO;KAC/D,UAAU;KACV;IACF,OAAO;KAEL,UAAU;KACV;IACF;GACF;GAEA,IAAI,MAAM,SAAS,SAAS,GAAG;GAC/B,OAAO,KAAA;GACP,iBAAiB,IAAI;GACrB,QAAQ,KAAA;GACR,KAAK;GACL;EACF;EAGA,IAAI,IAAI,SAAS,WAAW;GAC1B,MAAM,YAAY,OAAO,aAAa;GACtC,MAAM,cAAc,iBAAiB,WAAW,WAAW,cAAc;GACzE,MAAM,UAAU,OAAO,WAAW,aAAa,MAAM;GACrD,IAAI,WAAW,SAAS,YAAY,UAAU,YAAY,eAAe,IAAI,qBAAqB;IAChG,UAAU;IACV;GACF;GACA,WAAW;GAEX,cAAc;GACd,OAAO;GACP,aAAa;GACb,gBAAgB;GAChB,OAAO;IAAE,UAAU;IAAG;IAAW,MAAM;IAAG,WAAW;GAAe;GACpE,KAAK;IAAE,MAAM;IAAU;IAAa,UAAU;GAAI,CAAC;EACrD,OAAO;GACL,IAAI,eAAe,WAAW,GAAG;IAC/B,iBAAiB,IAAI;IACrB,QAAQ,KAAA;IACR,KAAK;IACL;GACF;GACA,IAAI,WAAW,QAAQ,eAAe,IAAI,oBAAoB;IAC5D,UAAU;IACV;GACF;GACA,WAAW;GACX,MAAM,YAAY,OAAO,aAAa;GACtC,MAAM,WAAW,OAAO,WAAW,iBAAiB,QAAQ,WAAW,EAAE,GAAG,MAAM;GAClF,MAAM,QAAQ,oBAAoB,gBAAgB,WAAW,YAAY,QAAQ;GACjF,IAAI,MAAM,WAAW,GACnB,MAAM,IAAI,MAAM,gBAAgB,SAAS,yBAAyB;GAEpE,cAAc;GACd,MAAM,cAAc,iBAAiB,QAAQ,WAAW,KAAK;GAC7D,OAAO;GACP,aAAa,OAAO,WAAW,aAAa,MAAM;GAClD,gBAAgB;GAChB,OAAO;IAAE,UAAU;IAAG;IAAW;IAAM,WAAW;GAAM;GACxD,KAAK;IAAE,MAAM;IAAU;IAAa,UAAU;GAAI,CAAC;GACnD,IAAI,MAAM,SAAS,eAAe,QAAQ;IACxC,QAAQ;KAAE,UAAU;KAAG,MAAM,OAAO,MAAM;IAAO;IACjD,UAAU;IACV;GACF;EACF;EACA,QAAQ,KAAA;EACR,IAAI,MAAM,SAAS,SAAS,GAAG;EAC/B,OAAO,KAAA;EACP,iBAAiB,IAAI;EACrB,KAAK;CACP;CAGA,MAAM,OAAO;EAAE;EAAQ;EAAK;EAAW;EAAc;EAAY;EAAgB;EAAM;CAAM;CAC7F,IAAI,KAAK;EAAE,IAAI,EAAE,MAAM,OAAO;EAAG,eAAe,EAAE,GAAG,KAAK;CAAG,CAAC;CAC9D,OAAO,EAAE,IAAI;AACf;;AAGA,SAAgB,aAAa,OAAoB,QAAuC;CACtF,IAAI,MAAM,WAAW,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE;CAC5C,OAAO,EACL,KAAK,CACH;EAAE,MAAM;EAAU,WAAW;EAAmB,SAAS,aAAa;EAAS,UAAU,MAAM,MAAM;CAAE,GACvG;EAAE,MAAM;EAAY,WAAW;EAAO,UAAU,MAAM,MAAM;EAAG,SAAS,aAAa;CAAQ,CAC/F,EACF;AACF;;;;AC1SA,eAAsB,UAAa,IAAsB,WAAW,GAAG,cAAc,KAAiB;CACpG,IAAI;CACJ,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAC5B,IAAI;EACF,OAAO,MAAM,GAAG;CAClB,SAAS,OAAO;EACd,YAAY;EACZ,IAAI,IAAI,WAAW,GAAG,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,cAAc,KAAK,CAAC,CAAC;CAChG;CAEF,MAAM;AACR;;AAGA,MAAM,iBAAiB;;AAGvB,MAAM,wBAAwB;AAE9B,IAAa,oBAAb,MAAsD;CASjC;CACA;CACA;CACA;CAXnB,QAA6B,mBAAmB;CAChD,WAA2C,CAAC;CAC5C,OAAiC,QAAQ,QAAQ;CACjD;CACA,aAAqB;CACrB,YAAoB;CAEpB,YACE,KACA,QACA,UACA,KACA;EAJiB,KAAA,MAAA;EACA,KAAA,SAAA;EACA,KAAA,WAAA;EACA,KAAA,MAAA;CAChB;CAEH,YAA2B;EACzB,OAAO,QAAQ,QAAQ;CACzB;CAEA,OAAO,UAAiD;EACtD,IAAI,KAAK,WAAW,OAAO,QAAQ,QAAQ;EAC3C,KAAK,WAAW;EAChB,IAAI,KAAK,UAAU,KAAA,GACjB,KAAK,QAAQ,iBAAiB;GAC5B,KAAK,QAAQ,KAAA;GACb,KAAK,MAAM;EACb,GAAG,KAAK,SAAS,oBAAoB;EAEvC,OAAO,QAAQ,QAAQ;CACzB;CAEA,MAAM,SAAS,QAAoB,QAAgC;EACjE,IAAI,KAAK,WAAW;GAClB,MAAM,KAAK;GACX;EACF;EACA,KAAK,YAAY;EACjB,IAAI,KAAK,UAAU,KAAA,GAAW;GAC5B,aAAa,KAAK,KAAK;GACvB,KAAK,QAAQ,KAAA;EACf;EACA,KAAK,MAAM;EAEX,MAAM,KAAK;EACX,MAAM,UAAU,KAAK,MAAM,WAAW;EACtC,MAAM,EAAE,QAAQ,aAAa,KAAK,OAAO,MAAM;EAE/C,KAAK,QAAQ,YAAY;GACvB,KAAK,MAAM,MAAM,KAEf,IAAI,MADkB,KAAK,QAAQ;IAAE;IAAI,SAAS,MAAmB;GAAE,CAAC,MACxD,aAAa;EAEjC,CAAC;EACD,IAAI,CAAC,WAAW,WAAW,KAAA,GACzB,KAAK,cAAc,gBAAgB,KAAK,IAAI,SAAS,KAAK,QAAQ,MAAM,CAAC,CAAC,CAAC,WAAW,KAAA,CAAS,CAAC;EAElG,MAAM,KAAK;CACb;CAEA,OAAO,MAA6B;EAClC,KAAK,cAAc,gBAAgB,KAAK,IAAI,SAAS,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,WAAW,KAAA,CAAS,CAAC;EAC9F,OAAO,KAAK,KAAK,WAAW,KAAA,CAAS;CACvC;;;;;CAMA,QAAsB;EACpB,IAAI,KAAK,YAAY;EACrB,KAAK,aAAa;EAClB,KAAK,QAAQ,YAAY;GACvB,KAAK,aAAa;GAClB,MAAM,EAAE,QAAQ,SAAS,KAAK,OAAO,KAAK,UAAU,KAAK,SAAS,cAAc,KAAK,SAAS,iBAAiB,KAAK,SAAS,aAAa;GAC1I,MAAM,KAAK,KAAK,GAAG;EACrB,CAAC;CACH;;CAGA,MAAc,KAAK,KAA0C;EAC3D,IAAI,UAAU;EACd,KAAK,IAAI,WAAW,IAAK,YAAY;GACnC,IAAI,YAAY;GAChB,KAAK,MAAM,WAAW,SACpB,IAAK,MAAM,KAAK,QAAQ,OAAO,MAAO,aAAa;IACjD,YAAY;IACZ;GACF;GAEF,IAAI,CAAC,WAAW;GAChB,IAAI,YAAY,uBAAuB,MAAM,IAAI,MAAM,8BAA8B;GACrF,UAAU,SAAS,KAAK,OAAO,KAAK,UAAU,KAAK,SAAS,cAAc,KAAK,SAAS,iBAAiB,KAAK,SAAS,aAAa,CAAC,CAAC;EACxI;CACF;;;;;CAMA,MAAc,QAAQ,SAAiD;EACrE,MAAM,EAAE,OAAO;EACf,IAAI,GAAG,SAAS,QAAQ;GACtB,KAAK,OAAO,OAAO;GACnB,OAAO;EACT;EACA,MAAM,WAAW,KAAK,MAAM,WAAW,QAAQ,KAAK,MAAM,WAAA;EAC1D,IAAI;GACF,MAAM,KAAK,iBAAiB,OAAO;GACnC,OAAO;EACT,SAAS,OAAO;GAEd,IAAI,CAAC,UAAU,MAAM;GACrB,MAAM,OAAO,gBAAgB,KAAK;GAClC,IAAI,GAAG,SAAS,YAAY,SAAS,QAAQ;IAE3C,KAAK,OAAO,OAAO;IACnB,OAAO;GACT;GACA,IAAI,SAAS,UAAU,SAAS,QAAQ;IAEtC,IAAI,MAAM,KAAK,WAAW,GACxB,IAAI;KACF,MAAM,KAAK,iBAAiB,SAAS,KAAK,MAAM,MAAM,CAAC;KACvD,OAAO;IACT,QAAQ;KACN,OAAO,KAAK,QAAQ,gBAAgB,IAAI;IAC1C;IAEF,OAAO,KAAK,QAAQ,cAAc,IAAI;GACxC;GACA,IAAI,SAAS,QAEX,OAAO,KAAK,QAAQ,cAAc,KAAK;GAKzC,IAAI;IACF,MAAM,YAAY,GAAG,SAAS,YAAY,GAAG,SAAS,YAAY,GAAG,SAAS,aAAa,GAAG,WAAW,KAAK,MAAM,OAAO;IAC3H,MAAM,KAAK,iBAAiB,SAAS,QAAQ;IAC7C,OAAO;GACT,SAAS,YAAY;IACnB,IAAI,GAAG,SAAS,YAAY,gBAAgB,UAAU,MAAM,QAAQ;KAClE,KAAK,OAAO,OAAO;KACnB,OAAO;IACT;IACA,OAAO,KAAK,QAAQ,YAAY,IAAI;GACtC;EACF;CACF;;;;;;;CAQA,MAAc,iBAAiB,SAAoB,aAAqC;EACtF,MAAM,eAAe,eAAe,QAAQ,IAAI,aAAa,KAAK,MAAM,GAAG;EAC3E,MAAM,KAAK,QAAQ,QAAQ,IAAI,YAAY;EAC3C,IAAI,GAAG,SAAS,UAAU;GACxB,MAAM,KAAK,MAAM,gBAAgB,KAAK,IAAI,WAAW,GAAG,QAAQ,CAAC;GACjE,KAAK,QAAQ;IAAE,GAAG,QAAQ,OAAO,KAAK,KAAK;IAAG,QAAQ;GAAG;GACzD;EACF;EACA,IAAI,GAAG,SAAS,QACd,MAAM,gBAAgB,KAAK,IAAI,gBAAgB,KAAK,QAAQ,KAAK,MAAM,MAAO,CAAC;OAC1E,IAAI,GAAG,SAAS,UACrB,MAAM,KAAK,IAAI,cAAc,KAAK,MAAM,QAAS,GAAG,aAAa,mBAAmB,GAAG,QAAQ;OAC1F,IAAI,GAAG,SAAS,UACrB,MAAM,KAAK,IAAI,kBAAkB,KAAK,MAAM,QAAS,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ;OACrF,IAAI,GAAG,SAAS,YACrB,MAAM,KAAK,IAAI,iBAAiB,KAAK,MAAM,QAAS,GAAG,WAAW,GAAG,UAAU,GAAG,OAAO;EAE3F,KAAK,OAAO,SAAS,YAAY;CACnC;CAEA,OAAe,SAAoB,aAA4B;EAC7D,MAAM,OAAO,QAAQ,OAAO,KAAK,KAAK;EAGtC,MAAM,UAAU,KAAK,MAAM;EAC3B,MAAM,SAAS,KAAK,WAAA,iBAA8B,YAAY,QAAQ,YAAA,gBAClE,UACA,KAAK;EACT,KAAK,QAAQ,gBAAgB,KAAA,IACzB;GAAE,GAAG;GAAM,KAAK;GAAa;EAAO,IACpC;GAAE,GAAG;GAAM,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,MAAM,GAAG;GAAG;EAAO;CACjE;;CAGA,MAAc,aAA+B;EAC3C,MAAM,EAAE,QAAQ,QAAQ,KAAK;EAC7B,IAAI,WAAW,QAAQ,WAAA,eAA4B,OAAO;EAC1D,IAAI;GACF,MAAM,KAAK,IAAI,iBAAiB,QAAQ,MAAM,MAAM,CAAC;GACrD,KAAK,QAAQ;IAAE,GAAG,KAAK;IAAO,KAAK,MAAM;GAAE;GAC3C,OAAO;EACT,QAAQ;GACN,OAAO;EACT;CACF;;;;;;CAOA,MAAc,QAAQ,QAAgB,YAA2C;EAC/E,MAAM,EAAE,QAAQ,MAAM,QAAQ,KAAK;EACnC,MAAM,cAAc,WAAW,QAAQ,WAAA;EACvC,IAAI,aACF,MAAM,KAAK,IAAI,iBAAiB,QAAkB,OAAO,MAAM,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;EAEzF,IAAI,SAAS,KAAA,GAAW;GAEtB,MAAM,OADO,KAAK,SAAS,KAAK,SAAS,EAAE,SACrB,YAAY,IAAI,aAAa,KAAK,OAAO,KAAK,OAAO,KAAK,UAAU;GAC1F,KAAK,QAAQ;IACX,GAAG,KAAK;IACR,QAAQ;IACR,MAAM,KAAA;IACN,gBAAgB,KAAK;IACrB,OAAO;KAAE,UAAU,KAAK;KAAU;IAAK;GACzC;EACF,OACE,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,QAAQ;EAAK;EAE7C,KAAK,IAAI,wBAAwB,OAAO,eAAe;EACvD,IAAI,aACF,MAAM,gBAAgB,KAAK,IAAI,SAAS,KAAK,QAAQ,cAAc,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;EAE7F,OAAO;CACT;CAEA,QAAgB,MAAiC;EAC/C,KAAK,OAAO,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC,OAAO,UAAU;GAChD,KAAK,IAAI,wBAAwB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;EAC3F,CAAC;CACH;AACF;;AAGA,SAAS,QAAQ,IAAY,UAAsC;CACjE,IAAI,aAAa,KAAA,GAAW,OAAO;CACnC,IAAI,GAAG,SAAS,UAAU,OAAO;EAAE,GAAG;EAAI;CAAS;CACnD,IAAI,GAAG,SAAS,UAAU,OAAO;EAAE,GAAG;EAAI;CAAS;CACnD,IAAI,GAAG,SAAS,YAAY,OAAO;EAAE,GAAG;EAAI;CAAS;CACrD,OAAO;AACT;;;;;AAMA,SAAS,eAAe,IAAY,UAA8B,cAA0C;CAC1G,IAAI,GAAG,SAAS,YAAY,GAAG,SAAS,YAAY,GAAG,SAAS,YAAY,OAAO,KAAA;CACnF,OAAO,KAAK,IAAI,YAAY,GAAG,UAAU,eAAe,CAAC;AAC3D;;AAGA,SAAgB,QAAQ,KAAgB,WAAmB,WAAwD;CACjH,OAAO,YAAY;EACjB,IAAI;GACF,MAAM,aAAa,MAAM,IAAI,YAAY,WAAW,SAAS;GAC7D,aAAa;IACX,IAAS,eAAe,WAAW,UAAU,CAAC,CAAC,YAAY,KAAA,CAAS;GACtE;EACF,QAAQ;GACN;EACF;CACF;AACF;;;ACtSA,MAAM,cAAoE;CACxE,SAAS;CACT,UAAU;CACV,WAAW;AACb;AAEA,SAAS,aAAa,QAAgC;CACpD,MAAM,QAAQ,CAAC,WAAW,OAAO,WAAW,YAAY,OAAO,SAAS,GAAG;CAC3E,IAAI,OAAO,WAAW,KAAA,GAAW,MAAM,KAAK,UAAU,OAAO,QAAQ;CACrE,OAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,OAAO,MAAc,MAA4B,KAAa,UAAuD;CAC5H,OAAO;EACL,KAAK;EACL,MAAM;GAAE,KAAK;GAAc,SAAS;EAAK;EACzC;EACA,WAAW,CAAC;GAAE,MAAM;GAAY,OAAO;IAAE;IAAK;GAAS;EAAE,CAAC;CAC5D;AACF;;AAGA,SAAgB,sBAAsB,QAAgC;CACpE,OAAO,KAAK,UAAU;EACpB,QAAQ;EACR,QAAQ,EAAE,SAAS,EAAE,SAAS,QAAQ,OAAO,WAAW,EAAE;EAC1D,QAAQ;GAAE,OAAO;IAAE,KAAK;IAAc,SAAS;GAAO;GAAG,UAAU;EAAS;EAC5E,MAAM,EACJ,UAAU,CACR;GAAE,KAAK;GAAY,SAAS,aAAa,MAAM;EAAE,GACjD;GAAE,KAAK;GAAU,SAAS,CAAC,OAAO,MAAM,WAAW,OAAO,KAAK,OAAO,GAAG,OAAO,MAAM,UAAU,OAAO,KAAK,QAAQ,CAAC;EAAE,CACzH,EACF;CACF,CAAC;AACH;;AAGA,SAAgB,2BAA2B,QAAwB,QAA8C,cAA+B;CAC9I,MAAM,aAAa,YAAY,WAAW,iBAAiB,KAAA,IAAY,MAAM,iBAAiB;CAC9F,MAAM,WAAW,WAAW,YAAY,UAAU,WAAW,aAAa,QAAQ;CAClF,OAAO,KAAK,UAAU;EACpB,QAAQ;EACR,QAAQ,EAAE,SAAS,EAAE,SAAS,OAAO,YAAY,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,OAAO,WAAW,EAAE;EAChG,QAAQ;GAAE,OAAO;IAAE,KAAK;IAAc,SAAS,UAAU;GAAa;GAAG;EAAS;EAClF,MAAM,EAAE,UAAU,CAAC;GAAE,KAAK;GAAY,SAAS,aAAa,MAAM;EAAE,CAAC,EAAE;CACzE,CAAC;AACH;;AAGA,IAAa,0BAAb,MAAkE;CAE7C;CACA;CAFnB,YACE,KACA,KACA;EAFiB,KAAA,MAAA;EACA,KAAA,MAAA;CAChB;CAEH,MAAM,QAAQ,QAAuD;EACnE,MAAM,SAAS,MAAM,gBAAgB,KAAK,IAAI,WAAW,sBAAsB,MAAM,CAAC,CAAC;EACvF,MAAM,gBAAgB,KAAK,IAAI,gBAAgB,OAAO,QAAQ,MAAM,CAAC;EACrE,OAAO,EACL,UAAU,OAAO,QAAQ,iBAAiB;GACxC,IAAI;IACF,MAAM,gBAAgB,KAAK,IAAI,YAAY,QAAQ,2BAA2B,QAAQ,QAAQ,YAAY,GAAG,CAAC,CAAC;GACjH,SAAS,OAAO;IAEd,KAAK,IAAI,+BAA+B,OAAO,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;GAC7G;EACF,EACF;CACF;AACF;;;;;ACrEA,SAAgB,kBAAkB,KAA2C;CAE3E,IAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU,OAAO,KAAA;CACpD,MAAM,MAAM,KAAK,oBAAoB,GAA8B;CACnE,IAAI,QAAQ,MAAM,OAAO,KAAA;CACzB,OAAO;EACL,QAAQ,IAAI;EACZ,gBAAgB,IAAI,SAAS;EAC7B,GAAI,IAAI,SAAS,SAAS,KAAA,IAAY,EAAE,cAAc,IAAI,SAAS,KAAK,IAAI,CAAC;EAC7E,OAAO,IAAI,OAAO;CACpB;AACF;;AAGA,SAAgB,cAAc,KAA0F;CACtH,IAAI,KAAK,UAAU,KAAA,GAAW,OAAO,KAAA;CACrC,OAAO,EAAE,OAAO;EAAE,MAAM;EAAQ,SAAS,IAAI;CAAM,EAAE;AACvD;;;;ACbA,MAAa,gBAA4B;CACvC,MAAM;CAEN,MAAM,MAAM,KAAK,IAAI,UAAU,KAA6B;EAE1D,MAAM,EAAE,UAAU,IAAI,OAAO;EAE7B,MAAM,MAAM,gBAAgB,IADT,KAAK,OAAO;GAAE;GAAO,WAAW,IAAI;EAAO,CAClC,CAAM;EAElC,MAAM,YAAY,MAAM,IAAI,aAAa;EACzC,MAAM,QAAQ,IAAI,aAAa;EAE/B,MAAM,aAAa,IAAI,KAAK,gBAAgB,CAAC,CAAC,CAAC,CAAC,SAA+D;GAE7G,8BAA8B,YAAY,KAAA;GAE1C,yBAAyB,OAAO,SAAkB;IAChD,MAAM,SAAS,kBAAkB,MAAM,SAAS;IAChD,IAAI,WAAW,QAAQ,CAAC,MAAM,MAAM,OAAO,SAAS,GAAG;IACvD,MAAM,QAAQ,IAAI,kBAAkB,KAAK,OAAO,QAAQ,UAAU,GAAG;IACrE,MAAM,aAAa,OAAO,UAAU,SAAS,IACzC,YAAY,QAAQ,IAAI,OAAO,UAAU,IAAI,OAAO,QAAQ,IAAI,cAAc,OAAO,WAAW,GAAG,CAAC,CAAC,IACrG,KAAA;IACJ,GAAG,UAAU;KACX,OAAO,IAAI,OAAO;KAClB,QAAQ,OAAO;KACf,QAAQ,OAAO;KACf,WAAW,OAAO;KAClB,MAAM,OAAO;KACb,GAAI,eAAe,KAAA,IAAY,EAAE,WAAW,IAAI,CAAC;KACjD;KACA,eAAe,QAAQ,KAAK,OAAO,WAAW,SAAS,uBAAuB;IAChF,CAAC;GACH;GAEA,wBAAwB,QAAiB;IACvC,IAAI,GAAG,iBAAiB,KAAA,GAAW,OAAO,KAAA;IAC1C,MAAM,SAAS,kBAAkB,GAAG;IACpC,IAAI,WAAW,KAAA,GAAW,OAAO,KAAA;IACjC,OAAO,cAAc,GAAG,aAAa,MAAM,CAAC,KAAK,KAAA;GACnD;EACF,CAAC;EAED,MAAM,KAAK,IAAI,KAAK,SAAS;GAAE;GAAO,WAAW,IAAI;GAAQ,aAAa,KAAK,YAAY;EAAK,CAAC;EACjG,MAAM,GAAG,MAAM,EAAE,iBAAiB,WAAW,CAAC;EAE9C,OAAO;GACL,UAAU,IAAI,wBAAwB,KAAK,GAAG;GAC9C,aAAa;IACX,GAAG,MAAM,EAAE,OAAO,KAAK,CAAC;IACxB,OAAO,QAAQ,QAAQ;GACzB;GACA,cAAc,GAAG,oBAAoB,CAAC,CAAC;EACzC;CACF;AACF;;;;;AC3DA,MAAa,mBAAmB;;AAEhC,MAAa,oBAAoB;;AAEjC,MAAa,YAAY;AAEzB,MAAa,qBAAqBC,IAAE,OAAO;CACzC,OAAOA,IAAE,OAAO,CAAC,CAAC,MAAM,gBAAgB;CACxC,cAAcA,IAAE,OAAO,CAAC,CAAC,MAAM,iBAAiB;AAClD,CAAC;AAGD,MAAa,kBAAkBA,IAAE,OAAO;CACtC,IAAIA,IAAE,OAAO,CAAC,CAAC,MAAM,SAAS;CAC9B,MAAMA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;;CAE9B,SAASA,IAAE,QAAQ,QAAQ,CAAC,CAAC,SAAS;CACtC,QAAQ,mBAAmB,SAAS;;CAEpC,SAASA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;;CAEzB,SAASA,IAAE,OAAO,CAAC,CAAC,IAAI,GAAI,CAAC,CAAC,SAAS;;CAEvC,UAAUA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;;CAErC,OAAOA,IAAE,MAAMA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CAClD,cAAcA,IAAE,OAAO;EACrB,UAAUA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;EACrC,OAAOA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CACpC,CAAC,CAAC,CAAC,SAAS;CACZ,WAAWA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY;CACxC,WAAWA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY;AAC1C,CAAC,CAAC,CAAC,QACA,MAAO,EAAE,YAAY,KAAA,OAAgB,EAAE,WAAW,KAAA,IACnD,EAAE,SAAS,2BAA2B,CACxC;AAGA,MAAa,gBAAgBA,IAAE,OAAO,EAAE,WAAWA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;;AAItE,MAAa,mBAAmB,aAAa;CAC3C,MAAM;CACN,SAAS;CACT,QAAQ;EACN,MAAM,YAA+B,eAAe;EACpD,UAAU,YAA6B,aAAa;CACtD;AACF,CAAC;;AAGD,SAAgB,WAAW,OAAe,QAAwB;CAChE,OAAO,GAAG,MAAM,GAAG;AACrB;;ACrCA,SAAgB,iBAAiB,UAAyB,MAA0B,MAAoB;CACtG,MAAM,OAAO,SAAS,SAAS,SAAS;CACxC,IAAI,SAAS,KAAA,KAAa,KAAK,SAAS,MAAM,KAAK,WAAW;MACzD,SAAS,KAAK;EAAE;EAAM,SAAS;CAAK,CAAC;AAC5C;AAsBA,SAAgB,WAAW,QAAuC;CAChE,IAAI,OAAO,SAAS,aAAa,OAAO;CACxC,IAAI,OAAO,SAAS,aAAa,OAAO,SAAS,eAAe,OAAO;CACvE,OAAO;AACT;;AAGA,SAAgB,eAAe,MAAc,KAAqB;CAChE,OAAO,KAAK,SAAS,MAAM,GAAG,KAAK,MAAM,GAAG,GAAG,EAAE,KAAK;AACxD;;AAGA,SAAS,cAAc,QAA2B,KAAiC;CACjF,IAAI,OAAO,SAAS,SAAS,OAAO,KAAA;CACpC,MAAM,UAAU,OAAO,OAAO;CAE9B,OAAO,eADM,OAAO,YAAY,YAAY,QAAQ,SAAS,IAAI,UAAU,QAC/C,GAAG;AACjC;AAEA,IAAa,WAAb,MAAsB;CAED;CACA;CAEA;CAJnB,YACE,UACA,SAEA,sBAAuC,KACvC;EAJiB,KAAA,WAAA;EACA,KAAA,UAAA;EAEA,KAAA,sBAAA;CAChB;CAEH,mBAAmB,WAAmB,OAA+B;EACnE,MAAM,KAAK,KAAK,SAAS,IAAI,SAAS;EACtC,IAAI,OAAO,KAAA,GAAW;EAEtB,IAAI,MAAM,SAAS,cAAc;GAC/B,GAAG,OAAO;IAAE,GAAG,MAAM,KAAK;IAAgB,UAAU,CAAC;IAAG,OAAO;GAAM;GACrE;EACF;EAEA,IAAI,MAAM,SAAS,mBAAmB;GACpC,MAAM,OAAO,GAAG;GAChB,IAAI,SAAS,KAAA,KAAa,KAAK,MAAO,MAAM,KAAK,MAAiB;GAClE,MAAM,QAAQ,MAAM,KAAK;GACzB,IAAI,MAAM,SAAS,gBAAgB,OAAO,MAAM,SAAS,UACvD,iBAAiB,KAAK,UAAU,QAAQ,MAAM,IAAI;QAC7C,IAAI,MAAM,SAAS,qBAAqB,OAAO,MAAM,SAAS,UACnE,iBAAiB,KAAK,UAAU,WAAW,MAAM,IAAI;QAChD,IAAI,MAAM,SAAS,eAAe,MAAM,OAAO,SAAS,eAAe,KAAK,SAAS,KAAK,SAAS,SAAS,EAAE,EAAE,SAAS,WAC9H,iBAAiB,KAAK,UAAU,WAAW,MAAM;QAEjD;GAEF,MAAM,WAAW,KAAK,SAAS,KAAK,OAAO,EAAE,GAAG,EAAE,EAAE;GACpD,KAAK,QAAQ,IAAI,YAAY;IAC3B,IAAI,GAAG,UAAU,KAAA,GAAW;IAC5B,IAAI,CAAC,KAAK,OAAO;KACf,MAAM,GAAG,MAAM,UAAU;KACzB,KAAK,QAAQ;IACf;IACA,MAAM,GAAG,MAAM,OAAO,QAAQ;GAChC,CAAC;GACD;EACF;EAEA,IAAI,MAAM,SAAS,aAAa;GAC9B,MAAM,OAAO,GAAG;GAChB,IAAI,SAAS,KAAA,KAAa,KAAK,MAAO,MAAM,KAAK,MAAiB;GAClE,MAAM,OAAO,MAAM,KAAK;GACxB,MAAM,OAAO,OAAO,MAAM,KAAK,cAAc,WAAW,MAAM,KAAK,YAAY,KAAK,UAAU,MAAM,KAAK,aAAa,CAAC,CAAC;GACxH,iBAAiB,KAAK,UAAU,WAAW,MAAM,KAAK,KAAK,eAAe,MAAA,GAAyB,EAAE,KAAK;GAC1G,MAAM,WAAW,KAAK,SAAS,KAAK,OAAO,EAAE,GAAG,EAAE,EAAE;GACpD,KAAK,QAAQ,IAAI,YAAY;IAC3B,IAAI,GAAG,UAAU,KAAA,GAAW;IAC5B,IAAI,CAAC,KAAK,OAAO;KACf,MAAM,GAAG,MAAM,UAAU;KACzB,KAAK,QAAQ;IACf;IACA,MAAM,GAAG,MAAM,OAAO,QAAQ;GAChC,CAAC;GACD;EACF;EAEA,IAAI,MAAM,SAAS,YAAY;GAC7B,MAAM,OAAO,GAAG;GAChB,IAAI,SAAS,KAAA,KAAa,KAAK,MAAO,MAAM,KAAK,MAAiB;GAClE,MAAM,SAAS,MAAM,KAAK;GAC1B,MAAM,SAAS,WAAW,MAAM;GAChC,MAAM,SAAS,cAAc,QAAQ,KAAK,mBAAmB;GAC7D,KAAK,QAAQ,IAAI,YAAY;IAE3B,KAAK,KAAK,SAAS,WAAW,KAAA,MAAc,GAAG,UAAU,KAAA,GAAW,MAAM,GAAG,MAAM,SAAS,QAAQ,MAAM;IAC1G,MAAM,MAAM,GAAG,UAAU;IACzB,GAAG,WAAW,KAAA;IACd,IAAI,QAAQ,KAAA,GAAW,MAAM,IAAI;GACnC,CAAC;GACD,GAAG,OAAO,KAAA;EACZ;CACF;;;;;CAMA,iBAAiB,WAAmB,WAAyB;EAC3D,MAAM,KAAK,KAAK,SAAS,IAAI,SAAS;EACtC,IAAI,OAAO,KAAA,KAAa,GAAG,SAAS,KAAA,GAAW;EAC/C,MAAM,SAAS,eAAe,WAAW,KAAK,mBAAmB;EACjE,KAAK,QAAQ,IAAI,YAAY;GAC3B,IAAI,GAAG,UAAU,KAAA,GAAW,MAAM,GAAG,MAAM,OAAO,OAAO,QAAQ;GACjE,MAAM,MAAM,GAAG,UAAU;GACzB,GAAG,WAAW,KAAA;GACd,IAAI,QAAQ,KAAA,GAAW,MAAM,IAAI;EACnC,CAAC;CACH;CAEA,QAAgB,IAAoB,MAAiC;EACnE,GAAG,OAAO,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,OAAO,UAAU;GAC5C,KAAK,QAAQ,wBAAwB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;EAC/F,CAAC;CACH;AACF;;;;AC9IA,IAAa,UAAb,MAAqB;CACU;CAA7B,YAAY,MAAoC;EAAnB,KAAA,OAAA;CAAoB;CAEjD,UAAU,KAA2B;EACnC,KAAU,OAAO,GAAG,CAAC,CAAC,MAAM,OAAO,UAAU;GAE3C,MAAM,SAAS,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,KAAK,KAAK,mBAAmB;GACnH,KAAK,KAAK,QAAQ,wBAAwB,QAAQ;GAClD,MAAM,IAAI,MAAM,OAAO,QAAQ,QAAQ,CAAC,CAAC,YAAY,KAAA,CAAS;EAChE,CAAC;CACH;CAEA,MAAc,OAAO,KAAoC;EACvD,MAAM,MAAM,KAAK,KAAK,KAAK,IAAI,IAAI,KAAK;EACxC,IAAI,QAAQ,KAAA,GAAW;EAEvB,MAAM,YAAY,eAAe,IAAI,IAAI;EACzC,IAAI,cAAc,OAAO;GACvB,MAAM,KAAK,KAAK,OAAO,MAAM,KAAK,IAAI,QAAQ,IAAI,OAAO,IAAI,MAAM;GACnE,MAAM,IAAI,MAAM,OAAO,QAAQ;GAC/B;EACF;EACA,IAAI,cAAc,QAAQ;GACxB,MAAM,KAAK,KAAK,KAAK,OAAO,OAAO,IAAI,IAAI,IAAI,MAAM;GACrD,IAAI,IAAI,aAAa,KAAA,GAAW;IAC9B,GAAG,MAAM,OAAO;IAChB,MAAM,IAAI,MAAM,OAAO,WAAW;GACpC,OACE,MAAM,IAAI,MAAM,OAAO,YAAY;GAErC;EACF;EACA,IAAI,cAAc,UAAU;GAC1B,MAAM,KAAK,KAAK,KAAK,OAAO,OAAO,IAAI,IAAI,IAAI,MAAM;GACrD,MAAM,IAAI,MAAM,OAAO,OAAO,KAAA,IAC1B,MAAM,IAAI,QAAQ,qBAClB,MAAM,IAAI,QAAQ,OAAO,GAAG,UAAU,OAAO,GAAG,aAAa,KAAA,IAAY,QAAQ,MAAM;GAC3F;EACF;EAEA,MAAM,KAAK,MAAM,KAAK,KAAK,OAAO,OAAO,KAAK,IAAI,QAAQ,IAAI,OAAO,IAAI,MAAM;EAC/E,IAAI,GAAG,aAAa,KAAA,GAAW;GAC7B,MAAM,IAAI,MAAM,OAAO,4BAA4B;GACnD;EACF;EAGA,GAAG,WAAW,EAAE,KAAK,KAAA,EAAU;EAC/B,GAAG,QAAQ,IAAI;EACf,GAAG,SAAS,MAAO,MAAM,IAAI,cAAc,CAAC,CAAC,YAAY,KAAA,CAAS,KAAM,KAAA;EAGxE,MAAM,YAAkC,CAAC;EACzC,IAAI,IAAI,eAAe,KAAA,GAAW;GAChC,MAAM,SAAS,MAAM,IAAI,WAAW;GACpC,IAAI,OAAO,SAAS,GAAG;IACrB,MAAM,cAAc,KAAK,KAAK,cAAc;IAC5C,IAAI,gBAAgB,KAAA,GAClB,MAAM,IAAI,MAAM,OAAO,gCAAgC;SAEvD,UAAU,KAAK,GAAG,MAAM,YAAY,WAAW,MAAM,CAAC;GAE1D;EACF;EACA,MAAM,UAAU,kBAAkB;GAChC,SAAS,CACP,GAAI,IAAI,KAAK,SAAS,IAAI,CAAC;IAAE,MAAM;IAAiB,MAAM,IAAI;GAAK,CAAC,IAAI,CAAC,GACzE,GAAG,UAAU,KAAK,SAAS;IAAE,MAAM;IAAkB,YAAY;GAAI,EAAE,CACzE;GACA,QAAQ,EAAE,MAAM,OAAO;EACzB,CAAC;EACD,IAAI;GACF,GAAG,MAAM,SAAS,OAAO;EAC3B,SAAS,OAAO;GACd,MAAM,MAAM,GAAG,SAAS;GACxB,GAAG,WAAW,KAAA;GACd,MAAM,MAAM;GACZ,MAAM;EACR;CACF;AACF;;;;ACtBA,SAAgB,QAAQ,KAA4B;CAClD,OAAO;EACL,GAAI,IAAI,YAAY,KAAA,IAAY,EAAE,SAAS,IAAI,QAAQ,IAAI,CAAC;EAC5D,GAAI,IAAI,UAAU,KAAA,IAAY,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;CACxD;AACF;;;;ACjFA,MAAa,uBAAuB;;AAGpC,SAAgB,UAAU,MAA+B;CACvD,MAAM,WAAW,KAAK,YAAY,KAAA,KAAa,KAAK,QAAQ,KAAK,CAAC,CAAC,WAAW,IAC1E,CAAC,IACD,CAAC;EAAE,MAAM;EAAsB,OAAO;EAAG,MAAM,KAAK;CAAQ,CAAC;CACjE,OAAO;EACL,GAAI,SAAS,SAAS,IAAI,EAAE,SAAS,IAAI,CAAC;EAC1C,GAAI,KAAK,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,MAAM,MAAM,IAAI,CAAC;CAChE;AACF;;AAGA,SAAgB,iBACd,MACA,cACuC;CACvC,OAAO,KAAK,SAAS,aAAa;AACpC;;;;;ACfA,MAAa,sBAAsB;;AAGnC,SAAgB,kBAAkB,SAAiB,QAAwB;CACzE,OAAO,QAAQ,QAAQ,oBAAoB,QAAQ,cAAc,OAAO;AAC1E;AAEA,IAAa,SAAb,MAAoB;CAEC;CACA;CAEA;CAEA;CAEA;CACA;CAEA;CAEA;CAbnB,YACE,QACA,UAEA,UAEA,cAEA,WACA,QAEA,UAEA,eAAgC,MAChC;EAbiB,KAAA,SAAA;EACA,KAAA,WAAA;EAEA,KAAA,WAAA;EAEA,KAAA,eAAA;EAEA,KAAA,YAAA;EACA,KAAA,SAAA;EAEA,KAAA,WAAA;EAEA,KAAA,eAAA;CAChB;;;;;;CAOH,MAAM,OAAO,KAAgB,QAAgB,OAAoB,QAAyC;EACxG,MAAM,QAAQ,KAAK,SAAS,IAAI,IAAI,IAAI,MAAM;EAC9C,IAAI,UAAU,KAAA,GAAW;GACvB,MAAM,WAAW,KAAK,SAAS,IAAI,KAAK;GAGxC,IAAI,aAAa,KAAA,KAAa,CAAC,SAAS,UAAU,OAAO;GACzD,MAAM,QAAQ,MAAM,KAAK,OAAO,OAAO;IAAE,WAAW;IAAO,GAAG,KAAK,eAAe,KAAK,MAAM;GAAE,CAAC;GAChG,MAAM,KAAK,OAAO,IAAI,SAAS,KAAK;GACpC,OAAO,KAAK,MAAM,IAAI,IAAI,QAAQ,QAAQ,OAAO,OAAO,KAAK;EAC/D;EACA,MAAM,YAAY,WAAW;EAC7B,MAAM,QAAQ,MAAM,KAAK,OAAO,OAAO;GAAE;GAAW,KAAK,IAAI;GAAS,GAAG,KAAK,eAAe,KAAK,MAAM;EAAE,CAAC;EAC3G,MAAM,KAAK,SAAS,IAAI,IAAI,IAAI,QAAQ,SAAS;EACjD,MAAM,KAAK,OAAO,IAAI,SAAS,SAAS;EACxC,OAAO,KAAK,MAAM,IAAI,IAAI,QAAQ,QAAQ,WAAW,OAAO,KAAK;CACnE;;CAGA,MAAc,OAAO,KAAa,WAAkC;EAClE,IAAI;GACF,MAAM,KAAK,UAAU,OAAO,KAAK,SAAS;EAC5C,SAAS,OAAO;GACd,KAAK,OAAO,oBAAoB,UAAU,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;EACvH;CACF;;CAGA,kBAA0B,OAAmB,KAAgB,QAA4B;EACvF,IAAI,CAAC,KAAK,cAAc,OAAO;EAC/B,MAAM,UAAwB;GAAE,MAAM;GAAqB,OAAO;GAAI,MAAM,kBAAkB,IAAI,WAAW,WAAW,MAAM;EAAE;EAChI,OAAO;GAAE,GAAG;GAAO,UAAU,CAAC,GAAI,MAAM,YAAY,CAAC,GAAI,OAAO;EAAE;CACpE;;;;;;;CAQA,eAAuB,KAAgB,QAA4F;EACjI,MAAM,MAAM,IAAI,YAAY;EAC5B,MAAM,OAAO,KAAK,SAAS,IAAI,GAAG;EAClC,IAAI,SAAS,KAAA,KAAa,QAAQ,QAAQ;GACxC,IAAI,SAAS,KAAA,KAAa,QAAQ,QAChC,KAAK,OAAO,sBAAsB,IAAI,GAAG,gBAAgB,IAAI,kBAAkB;GAEjF,OAAO;IAAE,cAAc,IAAI,gBAAgB,KAAK,aAAa;IAAG,OAAO,KAAK,kBAAkB,QAAQ,GAAG,GAAG,KAAK,MAAM;GAAE;EAC3H;EACA,OAAO;GACL,cAAc,iBAAiB,MAAM,KAAK,YAAY;GACtD,OAAO,KAAK,kBAAkB,UAAU,IAAI,GAAG,KAAK,MAAM;EAC5D;CACF;;CAGA,MAAM,MAAM,KAAgB,QAAgB,OAAoB,QAAyC;EACvG,MAAM,QAAQ,KAAK,SAAS,IAAI,IAAI,IAAI,MAAM;EAC9C,IAAI,UAAU,KAAA,GAAW;GACvB,MAAM,MAAM,KAAK,SAAS,IAAI,KAAK;GACnC,IAAI,QAAQ,KAAA,GAAW,KAAK,OAAO,OAAO,GAAG;GAC7C,MAAM,KAAK,SAAS,OAAO,IAAI,IAAI,MAAM;EAC3C;EACA,OAAO,KAAK,OAAO,KAAK,QAAQ,OAAO,MAAM;CAC/C;;CAGA,OAAe,WAAmB,IAA0B;EAC1D,GAAG,WAAW;EACd,GAAG,MAAM,OAAO;EAChB,CAAM,YAAY;GAChB,MAAM,GAAG,MAAM,SAAS,CAAC,CAAC,YAAY,KAAA,CAAS;GAC/C,MAAM,GAAG,KAAK,YAAY,KAAA,CAAS;GACnC,IAAI,KAAK,SAAS,IAAI,SAAS,MAAM,IAAI,KAAK,SAAS,OAAO,SAAS;EACzE,EAAA,CAAG;CACL;CAEA,OAAO,OAAe,QAA4C;EAChE,MAAM,QAAQ,KAAK,SAAS,IAAI,OAAO,MAAM;EAC7C,OAAO,UAAU,KAAA,IAAY,KAAA,IAAY,KAAK,SAAS,IAAI,KAAK;CAClE;CAEA,MAAc,OAAe,QAAgB,QAAgB,WAAmB,OAAgC,OAAoC;EAClJ,MAAM,KAAqB;GACzB;GAAO;GAAQ;GAAW,iBAAiB;GAAQ;GAAO;GAC1D,UAAU,KAAA;GAAW,MAAM,QAAQ,QAAQ;GAAG,MAAM,KAAA;GAAW,UAAU;EAC3E;EACA,KAAK,SAAS,IAAI,WAAW,EAAE;EAC/B,OAAO;CACT;AACF;;;;;ACnEA,IAAa,iBAAb,MAA4B;CAIP;CACA;CACA;CACA;CANnB,0BAA2B,IAAI,IAA0B;CAEzD,YACE,UACA,YACA,MACA,QAAuC,YACvC;EAJiB,KAAA,WAAA;EACA,KAAA,aAAA;EACA,KAAA,OAAA;EACA,KAAA,QAAA;CAChB;CAEH,MAAM,cAAc,KAAgE;EAClF,MAAM,YAAY,OAAO,IAAI,MAAM,QAAQ,EAAE;EAC7C,MAAM,KAAK,KAAK,SAAS,IAAI,SAAS;EACtC,IAAI,OAAO,KAAA,GAAW,OAAO,KAAA;EAG7B,IAAI,IAAI,QAAQ,YAAY,MAAM,OAAO;EACzC,MAAM,UAAU,KAAK,WAAW,GAAG,KAAK;EACxC,IAAI,YAAY,KAAA,GAAW;GACzB,KAAK,KAAK,sBAAsB,GAAG,MAAM,oBAAoB;GAC7D;EACF;EACA,MAAM,MAAM,KAAK,MAAM;EACvB,IAAI;EACJ,IAAI;GACF,eAAe,MAAM,QAAQ,UAAU,QAAQ;IAC7C;IAAK,QAAQ,GAAG;IAAQ,SAAS,QAAQ;IAAS,UAAU,IAAI;IAChE,GAAI,IAAI,WAAW,KAAA,IAAY,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;GAC3D,CAAC;EACH,SAAS,OAAO;GACd,KAAK,KAAK,mCAAmC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;GACrG;EACF;EACA,OAAO,IAAI,SAA0B,YAAY;GAC/C,MAAM,QAAsB;IAC1B;IAAW;IAAS;IAAc,QAAQ,IAAI;IAC9C,eAAe,KAAK,OAAO,KAAK,WAAW;GAC7C;GACA,KAAK,QAAQ,IAAI,KAAK,KAAK;GAC3B,IAAI,QAAQ,iBAAiB,SAAS,MAAM,SAAS,EAAE,MAAM,KAAK,CAAC;EACrE,CAAC;CACH;CAEA,iBAAiB,QAAoD;EACnE,MAAM,QAAQ,OAAO;EACrB,IAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,OAAO,MAAM,QAAQ,YAClE,MAAM,aAAa,WAAW,MAAM,aAAa,UAAW,OAAO,KAAA;EACzE,MAAM,QAAQ,KAAK,QAAQ,IAAI,MAAM,GAAG;EACxC,IAAI,UAAU,KAAA,GAAW,OAAO,EAAE,OAAO,aAAa;EACtD,MAAM,KAAK,KAAK,SAAS,IAAI,MAAM,SAAS;EAC5C,IAAI,OAAO,KAAA,KAAa,GAAG,oBAAoB,OAAO,gBACpD,OAAO,EAAE,OAAO,YAAY;EAE9B,KAAK,OAAO,MAAM,KAAK,MAAM,aAAa,UAAU,iBAAiB,YAAY,OAAO,YAAY;EACpG,OAAO,EAAE,OAAO,MAAM,aAAa,UAAU,QAAQ,MAAM;CAC7D;CAEA,UAAgB;EACd,KAAK,MAAM,OAAO,CAAC,GAAG,KAAK,QAAQ,KAAK,CAAC,GAAG,KAAK,OAAO,KAAK,WAAW;CAC1E;CAEA,OAAe,KAAa,SAA0B,cAA6B;EACjF,MAAM,QAAQ,KAAK,QAAQ,IAAI,GAAG;EAClC,IAAI,UAAU,KAAA,GAAW;EACzB,KAAK,QAAQ,OAAO,GAAG;EACvB,MAAM,QAAQ,oBAAoB,SAAS,MAAM,OAAO;EACxD,MAAM,QAAQ,OAAO;EACrB,MAAM,SAAS,YAAY,iBAAiB,YAAY,YAAY,aAAa,aAAa;EAC9F,MAAW,aAAa,SAAS,QAAQ,YAAY,CAAC,CAAC,OAAO,UAAmB;GAC/E,KAAK,KAAK,0BAA0B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;EAC9F,CAAC;CACH;AACF;;;AChGA,IAAa,aAAb,MAAwB;CAQO;CAP7B,2BAAoB,IAAI,IAA4B;CACpD;CACA;CACA;CACA;CACA,0BAA2B,IAAI,IAA2B;CAE1D,YAAY,MAAoC;EAAnB,KAAA,OAAA;EAC3B,MAAM,eAAe,KAAK,aAAa;EACvC,KAAK,SAAS,IAAI,OAAO,KAAK,QAAQ,cAAc,KAAK,UAAU,KAAK,cAAc,KAAK,YAAY,MAAM,KAAK,IAAI,KAAK,CAAC,GAAG,KAAK,UAAU,KAAK,gBAAgB,IAAI;EACvK,KAAK,UAAU,IAAI,QAAQ;GACzB,QAAQ,KAAK;GACb,MAAM,KAAK;GACX,qBAAqB,KAAK;GAC1B,GAAI,KAAK,gBAAgB,KAAA,IAAY,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;GAC1E,UAAU,MAAM,KAAK,IAAI,KAAK,CAAC;EACjC,CAAC;EACD,KAAK,WAAW,IAAI,SAAS,KAAK,WAAW,MAAM,KAAK,IAAI,KAAK,CAAC,GAAG,KAAK,mBAAmB;EAC7F,KAAK,WAAW,IAAI,eAClB,KAAK,WACJ,UAAU;GACT,MAAM,YAAY,KAAK,QAAQ,IAAI,KAAK,CAAC,EAAE;GAC3C,IAAI,cAAc,KAAA,GAAW,OAAO,KAAA;GACpC,OAAO;IAAE;IAAW,SAAS,KAAK,KAAK,KAAK,IAAI,KAAK,CAAC,EAAE,QAAQ;GAAM;EACxE,IACC,MAAM,KAAK,IAAI,KAAK,CAAC,CACxB;CACF;CAEA,MAAM,WAA0B;EAC9B,KAAK,MAAM,SAAS,CAAC,GAAG,KAAK,KAAK,KAAK,KAAK,CAAC,GAAG,MAAM,KAAK,UAAU,KAAK;CAC5E;;CAGA,MAAM,UAAU,OAA8B;EAC5C,MAAM,KAAK,YAAY,KAAK;EAC5B,MAAM,SAAS,KAAK,KAAK,KAAK,IAAI,KAAK;EACvC,IAAI,WAAW,KAAA,GAAW;EAE1B,IAAI,OAAO,WAAW,KAAA,KAAa,OAAO,YAAY,KAAA,GAAW;EACjE,IAAI,CAAC,KAAK,KAAK,gBAAgB,OAAO,OAAO,GAAG;GAC9C,KAAK,KAAK,IAAI,KAAK,sBAAsB,MAAM,aAAa,OAAO,SAAS;GAC5E;EACF;EACA,MAAM,SAAS,MAAM,KAAK,KAAK,cAAc,OAAO,OAAO,YAAY;EACvE,IAAI,WAAW,KAAA,GAAW;GACxB,KAAK,KAAK,IAAI,KAAK,sBAAsB,MAAM,QAAQ,OAAO,OAAO,aAAa,KAAK;GACvF;EACF;EACA,MAAM,UAAU,KAAK,KAAK,SAAS,IAAI,OAAO,OAAO;EACrD,IAAI,YAAY,KAAA,GAAW;GACzB,KAAK,KAAK,IAAI,KAAK,sBAAsB,MAAM,SAAS,OAAO,QAAQ,MAAM;GAC7E;EACF;EACA,IAAI;GACF,MAAM,SAAS,MAAM,QAAQ,MAC3B;IAAE;IAAQ;GAAO,GACjB;IAAE,YAAY,QAAQ,KAAK,QAAQ,UAAU,GAAG;IAAG,eAAe,WAAW,KAAK,SAAS,iBAAiB,MAAM;GAAE,GACpH,KAAK,KAAK,WACT,MAAM,KAAK,KAAK,IAAI,KAAK,CAAC,CAC7B;GACA,KAAK,QAAQ,IAAI,OAAO,MAAM;EAChC,SAAS,OAAO;GACd,KAAK,KAAK,IAAI,KAAK,sBAAsB,MAAM,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;EACpH;CACF;;CAGA,MAAM,QAAQ,OAA8B;EAC1C,MAAM,KAAK,YAAY,KAAK;EAC5B,KAAK,MAAM,CAAC,WAAW,OAAO,CAAC,GAAG,KAAK,QAAQ,GAC7C,IAAI,GAAG,UAAU,OAAO,KAAK,OAAO,WAAW,EAAE;EAEnD,MAAM,KAAK,aAAa,CAAC,CAAC,UAAU,KAAK;CAC3C;;CAGA,MAAM,UAAU,OAA8B;EAC5C,MAAM,KAAK,YAAY,KAAK;EAC5B,KAAK,MAAM,CAAC,WAAW,OAAO,CAAC,GAAG,KAAK,QAAQ,GAC7C,IAAI,GAAG,UAAU,OAAO,KAAK,OAAO,WAAW,EAAE;CAErD;;CAGA,OAAe,WAAmB,IAA0B;EAC1D,GAAG,WAAW;EACd,GAAG,MAAM,OAAO;EAChB,CAAM,YAAY;GAChB,MAAM,GAAG,MAAM,SAAS,CAAC,CAAC,YAAY,KAAA,CAAS;GAC/C,MAAM,GAAG,KAAK,YAAY,KAAA,CAAS;GACnC,IAAI,KAAK,SAAS,IAAI,SAAS,MAAM,IAAI,KAAK,SAAS,OAAO,SAAS;EACzE,EAAA,CAAG;CACL;CAEA,SAAS,OAA0B;EACjC,MAAM,SAAS,KAAK,KAAK,KAAK,IAAI,KAAK;EACvC,IAAI,WAAW,KAAA,KAAa,OAAO,WAAW,KAAA,GAAW,OAAO;EAChE,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,EAAE,OAAO,KAAK;CAC9C;;CAGA,MAAM,UAAyB;EAC7B,KAAK,MAAM,MAAM,KAAK,SAAS,OAAO,GAAG,GAAG,MAAM,OAAO;EACzD,MAAM,QAAQ,WAAW,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,OAAO;GACrE,MAAM,GAAG,MAAM,SAAS,CAAC,CAAC,YAAY,KAAA,CAAS;GAC/C,MAAM,GAAG;EACX,CAAC,CAAC;EACF,MAAM,QAAQ,WAAW,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC;EACzE,KAAK,QAAQ,MAAM;EACnB,KAAK,SAAS,QAAQ;CACxB;CAEA,MAAc,YAAY,OAA8B;EACtD,MAAM,SAAS,KAAK,QAAQ,IAAI,KAAK;EACrC,IAAI,WAAW,KAAA,GAAW;EAC1B,KAAK,QAAQ,OAAO,KAAK;EACzB,MAAM,OAAO,MAAM,CAAC,CAAC,OAAO,UAAU;GACpC,KAAK,KAAK,IAAI,KAAK,sBAAsB,MAAM,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;EACpH,CAAC;CACH;CAEA,eAAqC;EACnC,MAAM,EAAE,aAAa,KAAK;EAC1B,OAAO;GACL,MAAM,GAAG,MAAM,SAAS,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE;GAC/C,KAAK,OAAO,GAAG,GAAG,MAAM;IAAE,MAAM,SAAS,IAAI,WAAW,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,CAAC;GAAE;GACjF,QAAQ,OAAO,GAAG,MAAM;IAAE,MAAM,SAAS,OAAO,WAAW,GAAG,CAAC,CAAC;GAAE;GAClE,WAAW,OAAO,MAAM;IACtB,KAAK,MAAM,OAAO,CAAC,GAAG,SAAS,KAAK,CAAC,GACnC,IAAI,IAAI,WAAW,GAAG,EAAE,EAAE,GAAG,MAAM,SAAS,OAAO,GAAG;GAE1D;EACF;CACF;AACF;;;AC7JA,SAAgB,kBAAkB,KAAc,UAAkB,UAAsB,MAA0C;CAChI,OAAO,EACL,MAAM,KAAK,UAAU;EAEnB,MAAM,eAAe,IAAI,IAAI,gBAAgB,KAAK;EAClD,IAAI,iBAAiB,KAAA,GACnB,IAAI;GACF,MAAM,aAAa,MAAM,UAAU,QAAQ;GAC3C;EACF,SAAS,OAAO;GACd,KAAK,uCAAuC,SAAS,iDAAiD,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;EAChK;EAEF,MAAM,SAAS,KAAK,QAAQ;CAC9B,EACF;AACF;;;;ACvBA,eAAe,eAAe,WAAoC;CAChE,MAAM,MAAe,MAAM,OAAO;CAClC,OAAS,IAA8B,WAAW;AACpD;;AAeA,SAAgB,iBAAiB,KAAc,WAA6B,gBAA4B;CACtG,IAAI;CACJ,IAAI;CACJ,IAAI,aAAa;CAEjB,SAAS,SAA4B;EACnC,WAAW,YAAY;GAErB,MAAM,MAAgB;IAAE,QAAQ;IAAqB,MAAM;IAAc,KAAK,EAAE;GAAW;GAC3F,MAAM,UAAU,YAAY,KAAK,GAAG;GACpC,QAAQ;GACR,IAAI;IACF,KAAK,MAAM,QAAQ,aACjB,MAAM,QAAQ,IAAI,OAAO,MAAM,SAAS,KAAK,EAAE,GAAG,KAAK,MAAM;GAEjE,SAAS,OAAO;IACd,IAAI,UAAU,SAAS,QAAQ,KAAA;IAC/B,QAAQ,KAAA;IACR,MAAM,QAAQ,QAAQ,CAAC,CAAC,YAAY,KAAA,CAAS;IAC7C,MAAM;GACR;GACA,OAAO;EACT,EAAA,CAAG;EACH,OAAO;CACT;CAEA,OAAO;EACL,MAAM,KAAK,UAAU;GACnB,MAAM,WAAW,QAAQ,QAAQ;GACjC,IAAI,aAAa,KAAA,GACf,MAAM,IAAI,MAAM,qGAAqG;GAEvH,MAAM,WAAW,MAAM,OAAO;GAC9B,gBAAgB,UAAU,QAAQ;GAClC,OAAO;EACT;EACA,MAAM,UAAU;GACd,QAAQ,KAAA;GACR,MAAM,UAAU;GAChB,QAAQ,KAAA;GACR,MAAM,SAAS,QAAQ;EACzB;CACF;AACF;;;AClEA,SAAgB,uBACd,UAC8F;CAC9F,OAAO,OAAO,KAAK,SAAS;EAE1B,OAAO,MADe,SAAS,CAAC,EAAE,cAAc,GAAG,KACjC,KAAK;CACzB;AACF;;;;ACkBA,MAAM,iBAAiB;AAEvB,MAAMC,qBAAmBC,IAAE,OAAO;;CAEhC,IAAIA,IAAE,OAAO,CAAC,CAAC,MAAM,SAAS,CAAC,CAAC,SAAS;CACzC,MAAMA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;CAC9B,SAASA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACzB,SAASA,IAAE,OAAO,CAAC,CAAC,IAAI,GAAI,CAAC,CAAC,SAAS;;CAEvC,UAAUA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CACrC,OAAOA,IAAE,MAAMA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CAClD,cAAcA,IAAE,OAAO;EAAE,UAAUA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;EAAG,OAAOA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CAAE,CAAC,CAAC,CAAC,SAAS;CACjH,QAAQA,IAAE,OAAO;EACf,OAAOA,IAAE,OAAO,CAAC,CAAC,MAAM,gBAAgB;;EAExC,WAAWA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;;EAEtC,cAAcA,IAAE,OAAO,CAAC,CAAC,MAAM,iBAAiB,CAAC,CAAC,SAAS;CAC7D,CAAC;AACH,CAAC;AAED,MAAMC,qBAAmBD,IAAE,OAAO;CAChC,MAAMA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,SAAS;CACzC,SAASA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CACpC,SAASA,IAAE,OAAO,CAAC,CAAC,IAAI,GAAI,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAClD,UAAUA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAChD,OAAOA,IAAE,MAAMA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAC7D,cAAcA,IAAE,OAAO;EAAE,UAAUA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;EAAG,OAAOA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;;CAE5H,QAAQA,IAAE,OAAO;EACf,OAAOA,IAAE,OAAO,CAAC,CAAC,MAAM,gBAAgB;EACxC,WAAWA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;EACtC,cAAcA,IAAE,OAAO,CAAC,CAAC,MAAM,iBAAiB,CAAC,CAAC,SAAS;CAC7D,CAAC,CAAC,CAAC,QAAQ,MAAM,EAAE,cAAc,KAAA,KAAa,EAAE,iBAAiB,KAAA,GAAW,EAAE,SAAS,8BAA8B,CAAC,CAAC,CACpH,SAAS,CAAC,CAAC,SAAS;AACzB,CAAC;AAED,SAAS,KAAK,KAAqB,MAAc,MAAqB;CACpE,IAAI,UAAU,MAAM,EAAE,gBAAgB,mBAAmB,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC;AACtF;AAEA,MAAM,WAAW;;AAGjB,SAAS,cAAc,UAA2C;CAChE,SAAS;EACP,MAAM,QAAQ,YAAY,CAAC;EAC3B,IAAI,KAAK;EACT,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK,MAAM,SAAS,MAAM,KAAK;EACtD,IAAI,CAAC,SAAS,EAAE,GAAG,OAAO;CAC5B;AACF;;AAGA,eAAe,aAAa,KAAsB,KAAmD;CACnG,MAAM,SAAmB,CAAC;CAC1B,IAAI,WAAW;CACf,WAAW,MAAM,SAAS,KAAK;EAC7B,MAAM,SAAS;EACf,YAAY,OAAO;EACnB,IAAI,WAAW,gBAAgB;GAC7B,KAAK,KAAK,KAAK,EAAE,OAAO,iBAAiB,CAAC;GAC1C,IAAI,QAAQ;GACZ;EACF;EACA,OAAO,KAAK,MAAM;CACpB;CACA,IAAI;EACF,OAAO,KAAK,MAAM,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC;CAC1D,QAAQ;EACN,KAAK,KAAK,KAAK,EAAE,OAAO,oBAAoB,CAAC;EAC7C;CACF;AACF;AAEA,SAAgB,iBAAiB,MAA6E;CAC5G,OAAO,OAAO,KAAK,QAAQ;EACzB,MAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB;EACtD,MAAM,MAAM,IAAI,SAAS,QAAQ,mCAAmC,EAAE,KAAK;EAC3E,MAAM,SAAS,IAAI,UAAU;EAE7B,IAAI,QAAQ,WAAW,WAAW,OAAO;GAEvC,KAAK,KAAK,KAAK,EAAE,MADJ,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,aAAa;IAAE,GAAG;IAAQ,QAAQ,KAAK,QAAQ,SAAS,OAAO,EAAE;GAAE,EAC7F,EAAE,CAAC;GACvB;EACF;EAEA,IAAI,QAAQ,WAAW,WAAW,QAAQ;GACxC,MAAM,OAAO,MAAM,aAAa,KAAK,GAAG;GACxC,IAAI,SAAS,KAAA,GAAW;GACxB,MAAM,SAASD,mBAAiB,UAAU,IAAI;GAC9C,IAAI,CAAC,OAAO,SAAS;IACnB,KAAK,KAAK,KAAK,EAAE,OAAO,OAAO,MAAM,OAAO,EAAE,EAAE,WAAW,eAAe,CAAC;IAC3E;GACF;GACA,MAAM,QAAQ,OAAO;GACrB,MAAM,KAAK,MAAM,MAAM,eAAe,cAAc,KAAK,KAAK,IAAI,SAAS,MAAM,KAAA,CAAS;GAC1F,IAAI,KAAK,KAAK,IAAI,EAAE,MAAM,KAAA,GAAW;IACnC,KAAK,KAAK,KAAK,EAAE,OAAO,WAAW,GAAG,OAAO,CAAC;IAC9C;GACF;GACA,KAAK,MAAM,GAAG,aAAa,KAAK,KAAK,QAAQ,GAC3C,IAAI,SAAS,WAAW,KAAA,KAAa,SAAS,OAAO,UAAU,MAAM,OAAO,OAAO;IACjF,KAAK,KAAK,KAAK,EAAE,OAAO,iBAAiB,SAAS,GAAG,MAAM,CAAC;IAC5D;GACF;GAEF,IAAI,CAAC,KAAK,gBAAgB,MAAM,OAAO,GAAG;IACxC,KAAK,KAAK,KAAK,EAAE,OAAO,WAAW,MAAM,UAAU,CAAC;IACpD;GACF;GACA,IAAI,eAAe,MAAM,OAAO;GAChC,IAAI,iBAAiB,KAAA,GAAW;IAC9B,IAAI,MAAM,OAAO,cAAc,KAAA,GAAW;KACxC,KAAK,KAAK,KAAK,EAAE,OAAO,8BAA8B,CAAC;KACvD;IACF;IACA,eAAe,MAAM,KAAK,YAAY,IAAI,MAAM,OAAO,SAAS;GAClE;GACA,MAAM,SAAS,gBAAgB,MAAM;IACnC;IAAI,MAAM,MAAM;IAAM,SAAS;IAC/B,QAAQ;KAAE,OAAO,MAAM,OAAO;KAAO;IAAa;IAClD,SAAS,MAAM;IACf,GAAI,MAAM,YAAY,KAAA,IAAY,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;IAChE,GAAI,MAAM,aAAa,KAAA,IAAY,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;IACnE,GAAI,MAAM,UAAU,KAAA,IAAY,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;IAC1D,GAAI,MAAM,iBAAiB,KAAA,IAAY,EAAE,cAAc,MAAM,aAAa,IAAI,CAAC;IAC/E,WAAW,KAAK,IAAI;IAAG,WAAW,KAAK,IAAI;GAC7C,CAAqB;GACrB,MAAM,KAAK,KAAK,IAAI,OAAO,IAAI,MAAM;GACrC,MAAM,KAAK,QAAQ,UAAU,OAAO,EAAE;GACtC,KAAK,KAAK,KAAK,EAAE,KAAK;IAAE,GAAG;IAAQ,QAAQ,KAAK,QAAQ,SAAS,OAAO,EAAE;GAAE,EAAE,CAAC;GAC/E;EACF;EAEA,IAAI,QAAQ,WAAW,WAAW,OAAO;GACvC,MAAM,KAAK,IAAI,aAAa,IAAI,IAAI,KAAK;GACzC,MAAM,WAAW,KAAK,KAAK,IAAI,EAAE;GACjC,IAAI,aAAa,KAAA,GAAW;IAC1B,KAAK,KAAK,KAAK,EAAE,OAAO,QAAQ,GAAG,OAAO,CAAC;IAC3C;GACF;GACA,MAAM,OAAO,MAAM,aAAa,KAAK,GAAG;GACxC,IAAI,SAAS,KAAA,GAAW;GACxB,MAAM,SAASE,mBAAiB,UAAU,IAAI;GAC9C,IAAI,CAAC,OAAO,SAAS;IACnB,KAAK,KAAK,KAAK,EAAE,OAAO,OAAO,MAAM,OAAO,EAAE,EAAE,WAAW,eAAe,CAAC;IAC3E;GACF;GACA,MAAM,QAAQ,OAAO;GACrB,MAAM,UAAU,MAAM,WAAW,SAAS;GAC1C,IAAI,CAAC,KAAK,gBAAgB,OAAO,GAAG;IAClC,KAAK,KAAK,KAAK,EAAE,OAAO,WAAW,UAAU,CAAC;IAC9C;GACF;GAEA,IAAI,MAAM,WAAW,QAAQ,MAAM,WAAW,KAAA,GACvC;SAAA,MAAM,GAAG,UAAU,KAAK,KAAK,QAAQ,GACxC,IAAI,MAAM,OAAO,MAAM,MAAM,QAAQ,UAAU,MAAM,OAAO,OAAO;KACjE,KAAK,KAAK,KAAK,EAAE,OAAO,iBAAiB,MAAM,GAAG,MAAM,CAAC;KACzD;IACF;;GAIJ,IAAI;GACJ,IAAI,MAAM,WAAW,MAAM;IACzB,MAAM,KAAK,QAAQ,UAAU,EAAE;IAC/B,IAAI,SAAS,WAAW,KAAA,GAAW,MAAM,KAAK,aAAa,SAAS,OAAO,YAAY;GACzF,OAAO,IAAI,MAAM,WAAW,KAAA,GAAW;IACrC,IAAI,MAAM,OAAO,cAAc,KAAA,GAC7B,eAAe,MAAM,KAAK,YAAY,IAAI,MAAM,OAAO,SAAS;SAEhE,eAAe,MAAM,OAAO;IAE9B,IAAI,SAAS,WAAW,KAAA,KAAa,SAAS,OAAO,iBAAiB,cACpE,MAAM,KAAK,aAAa,SAAS,OAAO,YAAY;GAExD;GACA,MAAM,SAAkC,EAAE,GAAG,SAAS;GACtD,IAAI,MAAM,SAAS,KAAA,GAAW,OAAO,OAAO,MAAM;GAClD,OAAO,UAAU;GACjB,OAAO,YAAY,KAAK,IAAI;GAC5B,IAAI,MAAM,WAAW,MAAM;IACzB,OAAO,OAAO;IACd,OAAO,OAAO;GAChB,OAAO,IAAI,MAAM,WAAW,KAAA,KAAa,iBAAiB,KAAA,GAAW;IACnE,OAAO,UAAU;IACjB,OAAO,SAAS;KAAE,OAAO,MAAM,OAAO;KAAO;IAAa;GAC5D;GACA,IAAI,MAAM,YAAY,MAAM,OAAO,OAAO;QACrC,IAAI,MAAM,YAAY,KAAA,GAAW,OAAO,UAAU,MAAM;GAC7D,IAAI,MAAM,aAAa,MAAM,OAAO,OAAO;QACtC,IAAI,MAAM,aAAa,KAAA,GAAW,OAAO,WAAW,MAAM;GAC/D,IAAI,MAAM,UAAU,MAAM,OAAO,OAAO;QACnC,IAAI,MAAM,UAAU,KAAA,GAAW,OAAO,QAAQ,MAAM;GACzD,IAAI,MAAM,iBAAiB,MAAM,OAAO,OAAO;QAC1C,IAAI,MAAM,iBAAiB,KAAA,GAAW,OAAO,eAAe,MAAM;GACvE,MAAM,SAAS,gBAAgB,MAAM,MAAM;GAC3C,MAAM,KAAK,KAAK,IAAI,IAAI,MAAM;GAC9B,MAAM,KAAK,QAAQ,UAAU,EAAE;GAC/B,KAAK,KAAK,KAAK,EAAE,KAAK;IAAE,GAAG;IAAQ,QAAQ,KAAK,QAAQ,SAAS,EAAE;GAAE,EAAE,CAAC;GACxE;EACF;EAEA,IAAI,QAAQ,WAAW,WAAW,UAAU;GAC1C,MAAM,KAAK,IAAI,aAAa,IAAI,IAAI,KAAK;GACzC,MAAM,WAAW,KAAK,KAAK,IAAI,EAAE;GACjC,IAAI,aAAa,KAAA,GAAW;IAC1B,KAAK,KAAK,KAAK,EAAE,OAAO,QAAQ,GAAG,OAAO,CAAC;IAC3C;GACF;GACA,MAAM,KAAK,QAAQ,QAAQ,EAAE;GAC7B,MAAM,KAAK,KAAK,OAAO,EAAE;GACzB,IAAI,SAAS,WAAW,KAAA,GAAW,MAAM,KAAK,aAAa,SAAS,OAAO,YAAY;GACvF,KAAK,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;GAC3B;EACF;EAEA,IAAI,QAAQ,mBAAmB,WAAW,QAAQ;GAChD,KAAK,KAAK,KAAK,EAAE,IAAI,KAAK,YAAY,MAAM,EAAE,CAAC;GAC/C;EACF;EAEA,IAAI,QAAQ,0BAA0B,WAAW,OAAO;GACtD,MAAM,KAAK,IAAI,aAAa,IAAI,IAAI,KAAK;GACzC,MAAM,QAAQ,KAAK,YAAY,IAAI,EAAE;GACrC,IAAI,UAAU,KAAA,GAAW;IACvB,KAAK,KAAK,KAAK,EAAE,OAAO,uBAAuB,CAAC;IAChD;GACF;GACA,KAAK,KAAK,KAAK,EAAE,MAAM,CAAC;GACxB;EACF;EAEA,IAAI,QAAQ,YAAY,WAAW,OAAO;GACxC,KAAK,KAAK,KAAK,EAAE,OAAO,KAAK,UAAU,EAAE,CAAC;GAC1C;EACF;EAEA,IAAI,QAAQ,gBAAgB,WAAW,OAAO;GAC5C,KAAK,KAAK,KAAK,EAAE,WAAW,KAAK,cAAc,EAAE,CAAC;GAClD;EACF;EAEA,IAAI,QAAQ,aAAa,WAAW,OAAO;GAEzC,IAAI,SAAwB,CAAC;GAC7B,IAAI;IACF,SAAS,MAAM,KAAK,WAAW,IAAI,aAAa,IAAI,UAAU,KAAK,EAAE;GACvE,QAAQ;IACN,SAAS,CAAC;GACZ;GACA,KAAK,KAAK,KAAK,EAAE,OAAO,CAAC;GACzB;EACF;EAEA,IAAI;GAAC;GAAS;GAAiB;GAAwB;GAAU;GAAc;EAAS,CAAC,CAAC,SAAS,GAAG,GAAG;GACvG,KAAK,KAAK,KAAK,EAAE,OAAO,qBAAqB,CAAC;GAC9C;EACF;EACA,KAAK,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;CACvC;AACF;;;;;;;AC9RA,MAAa,6BAA6B;CACxC,QAAQ,EACN,QAAQ;EACN;EACA;EACA;EACA;CACF,EACF;CACA,QAAQ,EACN,OAAO,EAAE,QAAQ,CAAC,uBAAuB,EAAE,EAC7C;CACA,WAAW,EACT,OAAO,CAAC,qBAAqB,EAC/B;AACF;AA2BA,IAAa,qBAAb,MAAgC;CAOD;CAN7B,2BAA4B,IAAI,IAI7B;CAEH,YAAY,MAAwC;EAAvB,KAAA,OAAA;CAAwB;;CAGrD,QAAgB;EACd,MAAM,MAAM,KAAK,KAAK,SAAS,WAAA,CAAY;EAC3C,MAAM,aAAa,IAAI,gBAAgB;EACvC,MAAM,QAAQ;GACZ,OAAO,EAAE,QAAQ,UAAU;GAC3B;GACA,OAAO,iBAAiB;IAAE,WAAW,MAAM;GAAE,GAAG,KAAK,KAAK,SAAS;EACrE;EACA,KAAK,SAAS,IAAI,IAAI,KAAK;EAC3B,KAAU,KAAK,YAAY;GACzB,QAAQ,WAAW;GACnB,QAAQ;GACR,gBAAgB,SAAS;IACvB,MAAM,QAAQ;KAAE,QAAQ;KAAW,KAAK,KAAK;KAAK,UAAU,KAAK;IAAS;GAC5E;EACF,CAAC,CAAC,CAAC,KAAK,OAAO,WAAW;GACxB,MAAM,gBAAgB,MAAM,KAAK,KAAK,YAAY,OAAO,WAAW,OAAO,aAAa;GACxF,MAAM,QAAQ;IAAE,QAAQ;IAAQ,OAAO,OAAO;IAAW;GAAc;EACzE,CAAC,CAAC,CAAC,OAAO,UAAmB;GAC3B,MAAM,IAAI;GACV,MAAM,QAAQ;IACZ,QAAQ;IACR,MAAM,OAAO,EAAE,SAAS,WAAW,EAAE,OAAO;IAC5C,GAAI,OAAO,EAAE,gBAAgB,WAAW,EAAE,aAAa,EAAE,YAAY,IAAI,CAAC;GAC5E;EACF,CAAC,CAAC,CAAC,cAAc;GACf,aAAa,MAAM,KAAK;EAC1B,CAAC;EACD,OAAO;CACT;CAEA,IAAI,IAAuC;EACzC,OAAO,KAAK,SAAS,IAAI,EAAE,CAAC,EAAE;CAChC;;CAGA,UAAgB;EACd,KAAK,MAAM,SAAS,KAAK,SAAS,OAAO,GAAG;GAC1C,MAAM,WAAW,MAAM;GACvB,aAAa,MAAM,KAAK;EAC1B;EACA,KAAK,SAAS,MAAM;CACtB;AACF;;;;ACtCA,SAAgB,UAAU,KAAc,QAA0B,MAAsB;CACtF,MAAM,MAAM;EAAE,OAAO,MAAc,IAAI,OAAO,KAAK,CAAC;EAAG,OAAO,MAAc,IAAI,OAAO,KAAK,CAAC;CAAE;CAC/F,MAAM,2BAA4C,IAAI,IAAI,CAAC,CAAC,UAAU,aAAa,CAAC,CAAC;CACrF,MAAM,WAA4B;EAChC,sBAAsB,OAAO;EAC7B,cAAc,OAAO;EACrB,iBAAiB,OAAO;EACxB,eAAe,OAAO;EACtB,yBAAyB,OAAO;CAClC;CAEA,MAAM,cAAc,OAAO,KAAa,WAAoC;EAC1E,MAAM,MAAM,eAAe,IAAI,QAAQ,kBAAkB,GAAG;EAC5D,MAAM,IAAI,YAAY,IAAI,cAAc,GAAG,GAAG,MAAM;EACpD,OAAO;CACT;;;CAIA,MAAM,aAAa,iBAAiB,GAAG;CAMvC,MAAM,aAAa,iBAAiB,KAJH,KAAK,gBAAgB,KAAA,IAClD,kBAAkB,KAAK,KAAK,aAAa,YAAY,IAAI,IAAI,IAC7D,YAEkD,KAAK,aAAa;CAOxE,MAAM,oBAAoB,IAAI,IAAI,qBAAqB,KAAK;CAC5D,MAAM,gBAA+B,EACnC,MAAM,OAAO,KAAK,WAAW;EAC3B,IAAI,sBAAsB,KAAA,GAAW,MAAM,IAAI,MAAM,yBAAyB;EAE9E,OAAM,MADkB,kBAAkB,OAAO,GAAG,EAAA,CACpC,cAAc,UAAU,SAAS,CAAC;CACpD,EACF;CAQA,MAAM,sBAAmD;EAEvD,IADc,IAAI,IAAI,eAAe,KAC7B,MAAM,KAAA,GAAW,OAAO,KAAA;EAChC,OAAO,EACL,MAAM,WAAW,QAAQ;GAGvB,MAAM,UAAU,IAAI,IAAI,eAAe,KAAK;GAC5C,IAAI,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,mBAAmB;GAC9D,OAAO,QAAQ,WAAW,OAAO,KAAK,EAAE,MAAM,WAAW,YAAY;IACnE;IACW;IACX,GAAI,SAAS,KAAA,IAAY,EAAE,KAAK,IAAI,CAAC;GACvC,EAAE,CAAC;EACL,EACF;CACF;CAKA,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI,UAAyB,QAAQ,QAAQ;CAC7C,MAAM,cAAc,iBAClB,KACA,mBACC,QAAQ,IAAI,KAAK,GAAG,GACrB,YAAY;EACV,MAAM,QAAQ,YAAY,KAAA,CAAS;EACnC,MAAM,SAAS,QAAQ;CACzB,CACF,CAAC,CAAC,MAAM,WAAW;EACjB,YAAY,OAAO,MAAM,MAAM;EAC/B,gBAAgB,OAAO,MAAM,UAAU;EACvC,OAAO;CACT,CAAC;CAED,MAAM,qBAAqB,IAAI,mBAAmB;EAChD,cAAc,YAAY,OAAO,0BAA0B,CAAC,MAAM,SAAS,KAAK,YAAY,OAAO,CAAC;EACpG;EACA,WAAW,OAAO;CACpB,CAAC;CAED,UAAU,YAAY,WAAW;EAC/B,UAAU,IAAI,WAAW;GACvB,MAAM;GACN,UAAU;GACV,QAAQ;GACR,UAAU,KAAK;GACf,oBAAoB;IAClB,MAAM,YAAY,IAAI,kBAAkB,iBAAiB;IACzD,OAAO;KAAE,UAAU,UAAU;KAAU,OAAO,UAAU;IAAM;GAChE;GACA,WAAW;GACX;GACA;GACA,qBAAqB,OAAO;GAC5B,aAAa;GACb,cAAc,OAAO;GACrB,eAAe,OAAO,SAAS,MAAM,IAAI,YAAY,QAAQ,cAAc,GAAG,CAAC,EAAA,EAAI;GACnF,kBAAkB,SAAS,WAAW,IAAI;GAC1C;EACF,CAAC;EACD,OAAO,QAAQ,SAAS;CAC1B,CAAC;CACD,QAAQ,OAAO,UAAU;EACvB,IAAI,KAAK,sBAAsB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;CACzF,CAAC;CAGD,IAAI,GAAG,kBAAkB,SAAS,UAAU;EAC1C,SAAS,SAAS,mBAAmB,OAAO,QAAQ,OAAO,EAAE,GAAG,KAAwD;CAC1H,CAAC;CAID,IAAI,OAAO,UACT,IAAI,GAAG,oBAAoB,6BAA6B,SAAS,QAAQ,GAAG,EAAE,SAAS,KAAK,CAAC;CAI/F,IAAI,GAAG,gBAAgB,EAAE,OAAO,YAAY;EAC1C,MAAM,OAAO,iBAAiB,QAC1B,MAAM,UACN,OAAQ,OAAwC,WAAW,KAAK;EACpE,SAAS,SAAS,iBAAiB,OAAO,MAAM,QAAQ,EAAE,GAAG,IAAI;CACnE,CAAC;CAMD,uBAAuB,MAAM,WAAW;EAEtC,MAAM,cAA4E,OAAO,KAAK,QAAQ;GACpG,IAAI,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,qBAAqB;GAChE,MAAM,iBAAiB;IACrB,MAAM;IACN;IACA,aAAa;IACb,iBAAiB,IAAI,MAAM,QAAQ,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI;IACtD,qBAAqB,IAAI,IAAI,cAAc,CAAC,CAAC,KAAK,EAAE,IAAI,YAAY;KAAE;KAAI;IAAK,EAAE;IACjF,aAAa,aAAa,IAAI,IAAI,WAAW,QAAQ,CAAC,CAAC,MAAM,WAAW,OAAO,KAAK,EAAE,IAAI,YAAY;KAAE;KAAI;IAAK,EAAE,CAAC;IACpH;IACA,cAAc,OAAO,QAAQ,IAAI,YAAY,MAAM,cAAc,GAAG,CAAC;IACrE,kBAAkB,SAAS,WAAW,IAAI;IAC1C,WAAW,KAAK,IAAI;GACtB,CAAC,CAAC,CAAC,KAAK,GAAG;EACb;EACA,MAAM,UAAU,OAAO,UAAU,SAAS;GACxC,MAAM;GACN,MAAM;GACN,SAAS,OAAO,KAAK,QAAQ;IAC3B,IAAI;KAEF,MAAM;KACN,MAAM,YAAY,KAAK,GAAG;IAC5B,SAAS,OAAO;KACd,IAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC,CAAC,CACvD,IAAI,KAAK,UAAU,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,CAAC,CAAC;IAC1F;GACF;EACF,CAAC;EACD,aAAa,QAAQ;CACvB,CAAC;CAID,IAAI,aAAa,YAAY;EAC3B,MAAM,WAAW,QAAQ;CAC3B,CAAC;CACD,IAAI,aAAa,YAAY;EAC3B,mBAAmB,QAAQ;CAC7B,CAAC;AACH;;;;;;AChPA,MAAM,UAAkC;CACtC,4BAA4B;CAC5B,uCAAuC;CACvC,8BAA8B;CAC9B,8BAA8B;CAC9B,4BAA4B;CAC5B,mCAAmC;AACrC;AAEA,MAAa,kBAAkB;AAC/B,MAAa,yBAAyB;;AAGtC,SAAgB,iBAAiB,OAAwD;CACvF,OAAO,MAAM,KAAK,SAAS;EACzB,MAAM,QAAQ,QAAQ,KAAK;EAC3B,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,6BAA6B,KAAK,GAAG,oBAAoB;EAClG,OAAO;GAAE,IAAI;GAAO,MAAM,KAAK;GAAI,GAAG,KAAK,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAAE;CACjG,CAAC;AACH;;AAGA,SAAgB,uBAA+B;CAC7C,OAAO,KAAK,KAAK,iBAAiB,WAAW,GAAG,EAAE,WAAW,GAAG,CAAC;AACnE;;;;;;;;;ACDA,MAAa,4BAA4B;CACvC;CACA;CACA;CACA;AACF;;;;;;;;;AAUA,SAAgB,oBAAoB,QAAgB,MAAqC;CACvF,MAAM,QAAQ,OAAO,MAAM,IAAI;CAC/B,KAAK,MAAM,OAAO,2BAA2B;EAC3C,MAAM,SAAS,SAAS;EACxB,MAAM,QAAQ,MAAM,WAAW,SAAS,KAAK,KAAK,MAAM,MAAM;EAC9D,IAAI,UAAU,IAAI;GAChB,KAAK,6CAA6C,OAAO,yBAAyB;GAClF;EACF;EACA,MAAM,SAAS,MAAM,MAAM,CAAC,SAAS,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;EAC9D,IAAI,cAAc;EAClB,KAAK,IAAI,IAAI,QAAQ,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;GAChD,MAAM,OAAO,MAAM;GACnB,IAAI,KAAK,KAAK,MAAM,IAAI;GACxB,IAAI,KAAK,SAAS,KAAK,UAAU,CAAC,CAAC,UAAU,QAAQ;GACrD,IAAI,mBAAmB,KAAK,IAAI,GAAG;IACjC,cAAc;IACd;GACF;EACF;EACA,IAAI,aAAa;EACjB,MAAM,OAAO,QAAQ,GAAG,GAAG,GAAG,IAAI,OAAO,SAAS,CAAC,EAAE,eAAe;CACtE;CACA,OAAO,MAAM,KAAK,IAAI;AACxB;AAIA,MAAM,mBAAmB;AACzB,MAAM,gBAAgB;;;;;;;AAOtB,MAAM,cAAc;AACpB,MAAM,iBAAiB;;AAEvB,MAAM,YAAY;AAElB,MAAM,mBAAmB;;;;;AAgBzB,eAAe,qBACb,KACA,aACA,UACA,MACkB;CAClB,MAAM,aAAa,KAAK,KAAK,WAAW;CACxC,IAAI,YAAY;CAChB,IAAI;EACF,MAAM,OAAO,GAAG;CAClB,QAAQ;EACN,YAAY;CACd;CACA,IAAI,WAAW;EACb,IAAI,SAAS;EACb,IAAI;GACF,UAAU,MAAM,SAAS,YAAY,MAAM,EAAA,CAAG,KAAK,MAAM;EAC3D,QAAQ,CAER;EACA,IAAI,CAAC,QAAQ;GACX,KAAK,sBAAsB,IAAI,qBAAqB;GACpD,OAAO;EACT;CACF;CACA,MAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;CACpC,MAAM,UAAU,YAAY,GAAG,eAAe,KAAK,MAAM;CACzD,MAAM,UAAU,KAAK,KAAK,gBAAgB,GAAG,aAAa,MAAM;CAChE,MAAM,UAAU,KAAK,KAAK,aAAa,GAAG,KAAK,KAAK,UAAU,EAAE,WAAW,GAAG,CAAC,GAAG,MAAM;CACxF,OAAO;AACT;;;;;;;AAQA,eAAsB,qBAAqB,KAAc,QAA8C;CACrG,IAAI,CAAC,OAAO,SAAS;CACrB,MAAM,QAAQ,QAAsB;EAAE,IAAI,OAAO,KAAK,GAAG;CAAE;CAE3D,MAAM,eAAe,IAAI,IAAI,gBAAgB,KAAK;CAClD,IAAI,iBAAiB,KAAA,GAAW;CAEhC,MAAM,OAAO,aAAa,MAAM,MAAM,MAAM,EAAE,UAAU,MAAM;CAC9D,IAAI,SAAS,KAAA,GAAW;EACtB,KAAK,gFAAgF;EACrF;CACF;CACA,MAAM,aAAa,OAAuB,KAAK,QAAQ,eAAe,KAAK,IAAI,CAAC,GAAG,EAAE;CAGrF,IAAI,CAAC,UAAU,KAAK,OAAO,EAAE,GAC3B,KAAK,0CAA0C,OAAO,GAAG,kCAAkC;MACtF;EACL,IAAI;EACJ,IAAI;GACF,SAAS,MAAM,aAAa,KAAK,OAAO,MAAM;EAChD,SAAS,OAAO;GACd,KAAK,kCAAkC,OAAO,OAAO,wBAAwB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;EACvI;EACA,IAAI,WAAW,KAAA,GAAW;GACxB,MAAM,MAAM,UAAU,OAAO,EAAE;GAC/B,IAAI;IACF,MAAM,qBACJ,KACA,mBAAmB,oBAAoB,QAAQ,IAAI,GACnD;KAAE,MAAM,OAAO;KAAM,aAAa,OAAO;IAAY,GACrD,IACF;GACF,SAAS,OAAO;IACd,KAAK,8CAA8C,IAAI,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;GACrH;EACF;CACF;CAGA,IAAI,OAAO,OAAO,OAAO,QACvB,KAAK,yEAAyE,OAAO,GAAG,mBAAmB;MAG3G,IAAI,CAAC,UAAU,KAAK,OAAO,MAAM,GAC/B,KAAK,8CAA8C,OAAO,OAAO,iCAAiC;MAElG,IAAI;EACF,MAAM,qBACJ,UAAU,OAAO,MAAM,GACvB,mBAAmB,qBAAqB,GACxC;GAAE,MAAM;GAAiB,aAAa;EAAuB,GAC7D,IACF;CACF,SAAS,OAAO;EACd,KAAK,6CAA6C,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;CAC5G;AAGN;;;;;ACjMA,MAAa,qBAAqBC,IAAE,mBAAmB,QAAQ;CAC7DA,IAAE,OAAO;EAAE,MAAMA,IAAE,QAAQ,MAAM;EAAG,MAAMA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;EAAG,UAAUA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CAAE,CAAC;CACrGA,IAAE,OAAO;EAAE,MAAMA,IAAE,QAAQ,IAAI;EAAG,IAAIA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CAAE,CAAC;CACzDA,IAAE,OAAO;EAAE,MAAMA,IAAE,QAAQ,OAAO;EAAG,SAASA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;CAAE,CAAC;AAC1E,CAAC;;AAID,MAAa,mBAAmBA,IAAE,mBAAmB,QAAQ,CAC3DA,IAAE,OAAO,EAAE,MAAMA,IAAE,QAAQ,MAAM,EAAE,CAAC,GACpCA,IAAE,OAAO;CAAE,MAAMA,IAAE,QAAQ,MAAM;CAAG,QAAQA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;AAAE,CAAC,CACjE,CAAC;AAGD,MAAa,iBAAiBA,IAAE,OAAO;CACrC,IAAIA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACpB,MAAMA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;CAC9B,QAAQA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAI;CAClC,KAAKA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACrB,UAAU;CACV,QAAQ;CACR,SAASA,IAAE,QAAQ;CACnB,SAASA,IAAE,QAAQ;;CAEnB,WAAWA,IAAE,OAAO,CAAC,CAAC,SAAS;CAC/B,WAAWA,IAAE,OAAO;CACpB,WAAWA,IAAE,OAAO;AACtB,CAAC;AAGD,MAAa,gBAAgBA,IAAE,OAAO;CACpC,IAAIA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACpB,QAAQA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACxB,aAAaA,IAAE,OAAO;CACtB,YAAYA,IAAE,OAAO,CAAC,CAAC,SAAS;CAChC,QAAQA,IAAE,KAAK;EAAC;EAAW;EAAM;EAAS;CAAiB,CAAC;;CAE5D,WAAWA,IAAE,OAAO,CAAC,CAAC,SAAS;;CAE/B,OAAOA,IAAE,OAAO,CAAC,CAAC,SAAS;AAC7B,CAAC;;AAID,MAAa,iBAAiB,aAAa;CACzC,MAAM;CACN,SAAS;CACT,QAAQ;EACN,OAAO,YAA8B,cAAc;EACnD,MAAM,YAA6B,aAAa;EAEhD,MAAM,YAAuCA,IAAE,OAAO,EAAE,OAAOA,IAAE,OAAO,EAAE,CAAC,CAAC;CAC9E;AACF,CAAC;;AAGD,SAAgB,SAAS,MAAgC,QAA2B;CAClF,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CACvB,KAAK,GAAG,SAAS,GAAG,CAAC,CACrB,QAAQ,QAAQ,IAAI,WAAW,MAAM,CAAC,CACtC,MAAM,GAAG,MAAM,EAAE,YAAY,cAAc,EAAE,WAAW,KAAK,EAAE,GAAG,cAAc,EAAE,EAAE,CAAC;AAC1F;;AAGA,eAAsB,SAAS,MAAgC,QAAgB,OAA8B;CAC3G,MAAM,OAAO,SAAS,MAAM,MAAM;CAClC,KAAK,MAAM,OAAO,KAAK,MAAM,KAAK,GAAG,MAAM,KAAK,OAAO,IAAI,EAAE;AAC/D;;AAGA,eAAsB,aAAa,MAAgC,QAA+B;CAChG,KAAK,MAAM,OAAO,SAAS,MAAM,MAAM,GAAG,MAAM,KAAK,OAAO,IAAI,EAAE;AACpE;;;AC/DA,MAAM,mBAAmBC,IAAE,OAAO;CAChC,MAAMA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;CAC9B,QAAQA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAI;CAClC,KAAKA,IAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACrB,UAAU;CACV,QAAQ;CACR,SAASA,IAAE,QAAQ;CACnB,SAASA,IAAE,QAAQ;AACrB,CAAC;AACD,MAAM,mBAAmB,iBAAiB,QAAQ;AAElD,SAAgB,qBAAqB,MAAiF;CACpH,OAAO,OAAO,KAAK,QAAQ;EAEzB,MAAM,MAAM,IADI,IAAI,IAAI,OAAO,KAAK,kBACtB,CAAC,CAAC,SAAS,QAAQ,mCAAmC,EAAE,KAAK;EAC3E,MAAM,SAAS,IAAI,UAAU;EAC7B,MAAM,YAAY,qBAAqB,KAAK,GAAG;EAC/C,MAAM,eAAe,8BAA8B,KAAK,GAAG;EAC3D,MAAM,YAAY,2BAA2B,KAAK,GAAG;EAErD,IAAI,QAAQ,YAAY,WAAW,OAAO;GACxC,OAAK,KAAK,KAAK,EAAE,OAAO,KAAK,QAAQ,KAAK,EAAE,CAAC;GAC7C;EACF;EAEA,IAAI,QAAQ,YAAY,WAAW,QAAQ;GACzC,MAAM,OAAO,MAAMC,eAAa,KAAK,GAAG;GACxC,IAAI,SAAS,KAAA,GAAW;GACxB,MAAM,SAAS,iBAAiB,UAAU,IAAI;GAC9C,IAAI,CAAC,OAAO,SAAS;IACnB,OAAK,KAAK,KAAK,EAAE,OAAO,OAAO,MAAM,OAAO,EAAE,EAAE,WAAW,eAAe,CAAC;IAC3E;GACF;GACA,MAAM,SAAS,MAAM,KAAK,QAAQ,OAAO,OAAO,IAAI;GACpD,IAAI,CAAC,OAAO,IAAI;IACd,OAAK,KAAK,KAAK,EAAE,OAAO,OAAO,MAAM,CAAC;IACtC;GACF;GACA,OAAK,KAAK,KAAK,EAAE,MAAM,OAAO,MAAM,CAAC;GACrC;EACF;EAEA,IAAI,cAAc,QAAQ,WAAW,OAAO;GAC1C,MAAM,KAAK,mBAAmB,UAAU,EAAE;GAC1C,IAAI,KAAK,QAAQ,IAAI,EAAE,MAAM,KAAA,GAAW;IACtC,OAAK,KAAK,KAAK,EAAE,OAAO,SAAS,GAAG,OAAO,CAAC;IAC5C;GACF;GACA,MAAM,OAAO,MAAMA,eAAa,KAAK,GAAG;GACxC,IAAI,SAAS,KAAA,GAAW;GACxB,MAAM,SAAS,iBAAiB,UAAU,IAAI;GAC9C,IAAI,CAAC,OAAO,SAAS;IACnB,OAAK,KAAK,KAAK,EAAE,OAAO,OAAO,MAAM,OAAO,EAAE,EAAE,WAAW,eAAe,CAAC;IAC3E;GACF;GACA,MAAM,SAAS,MAAM,KAAK,QAAQ,OAAO,IAAI,OAAO,IAAI;GACxD,IAAI,CAAC,OAAO,IAAI;IACd,OAAK,KAAK,KAAK,EAAE,OAAO,OAAO,MAAM,CAAC;IACtC;GACF;GACA,OAAK,KAAK,KAAK,EAAE,MAAM,OAAO,MAAM,CAAC;GACrC;EACF;EAEA,IAAI,cAAc,QAAQ,WAAW,UAAU;GAC7C,MAAM,KAAK,mBAAmB,UAAU,EAAE;GAC1C,IAAI,KAAK,QAAQ,IAAI,EAAE,MAAM,KAAA,GAAW;IACtC,OAAK,KAAK,KAAK,EAAE,OAAO,SAAS,GAAG,OAAO,CAAC;IAC5C;GACF;GACA,MAAM,SAAS,MAAM,KAAK,QAAQ,OAAO,EAAE;GAC3C,IAAI,CAAC,OAAO,IAAI;IACd,OAAK,KAAK,KAAK,EAAE,OAAO,OAAO,MAAM,CAAC;IACtC;GACF;GACA,OAAK,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;GAC3B;EACF;EAEA,IAAI,iBAAiB,QAAQ,WAAW,QAAQ;GAC9C,MAAM,KAAK,mBAAmB,aAAa,EAAE;GAC7C,IAAI,KAAK,QAAQ,IAAI,EAAE,MAAM,KAAA,GAAW;IACtC,OAAK,KAAK,KAAK,EAAE,OAAO,SAAS,GAAG,OAAO,CAAC;IAC5C;GACF;GACA,MAAM,SAAS,MAAM,KAAK,QAAQ,QAAQ,EAAE;GAC5C,IAAI,CAAC,OAAO,IAAI;IAEd,OAAK,KAAK,OAAO,KAAK,OAAO,KAAK,IAAI,MAAM,KAAK,EAAE,OAAO,OAAO,MAAM,CAAC;IACxE;GACF;GACA,OAAK,KAAK,KAAK,EAAE,KAAK,OAAO,MAAM,CAAC;GACpC;EACF;EAEA,IAAI,cAAc,QAAQ,WAAW,OAAO;GAC1C,MAAM,KAAK,mBAAmB,UAAU,EAAE;GAC1C,IAAI,KAAK,QAAQ,IAAI,EAAE,MAAM,KAAA,GAAW;IACtC,OAAK,KAAK,KAAK,EAAE,OAAO,SAAS,GAAG,OAAO,CAAC;IAC5C;GACF;GACA,OAAK,KAAK,KAAK,EAAE,MAAM,KAAK,QAAQ,OAAO,IAAI,KAAK,eAAe,EAAE,CAAC;GACtE;EACF;EAEA,IAAI,QAAQ,eAAe,WAAW,OAAO;GAC3C,OAAK,KAAK,KAAK,EAAE,UAAU,KAAK,aAAa,EAAE,CAAC;GAChD;EACF;EAEA,IAAI,QAAQ,YAAY,cAAc,QAAQ,iBAAiB,QAAQ,cAAc,QAAQ,QAAQ,aAAa;GAChH,OAAK,KAAK,KAAK,EAAE,OAAO,qBAAqB,CAAC;GAC9C;EACF;EACA,OAAK,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;CACvC;AACF;;;;;ACzHA,MAAa,oBAAoB;AAEjC,SAAgB,gBAAgB,MAAgB,aAA6B;CAC3E,OAAO,YAAY,KAAK,KAAK,QAAQ,KAAK,GAAG,KAAK,YAAY;AAChE;;AAGA,MAAM,kBAAkB;AAyBxB,IAAM,kBAAN,cAA8B,MAAM;CAClC,cAAc;EAAE,MAAM,SAAS;CAAE;AACnC;AAEA,SAAgB,eAAe,MAA8B;CAC3D,eAAe,QAAQ,KAA6B;EAClD,MAAM,KAAK,KAAK,IAAI,IAAI,IAAI,GAAG;EAC/B,MAAM,SAAS,KAAK,MAAM,IAAI,QAAQ,KAAK,eAAe;CAC5D;CAEA,OAAO,EACL,MAAM,QAAQ,MAAM;EAClB,MAAM,cAAc,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY;EACrD,MAAM,YAAY,KAAK,aAAa;EACpC,MAAM,MAAe;GAAE,IAAI,KAAK,SAAS;GAAG,QAAQ,KAAK;GAAI;GAAa,QAAQ;GAAW;EAAU;EACvG,MAAM,QAAQ,GAAG;EACjB,MAAM,SAAS,OAAO,QAA2B,UAAqC;GACpF,MAAM,OAAgB;IACpB,GAAG;IACH;IACA,YAAY,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY;IAC7C,GAAI,UAAU,KAAA,IAAY,EAAE,OAAO,MAAM,MAAM,GAAG,eAAe,EAAE,IAAI,CAAC;GAC1E;GACA,MAAM,QAAQ,IAAI;GAClB,OAAO;EACT;EAGA,MAAM,SAAuB;GAAE,MAAM;GAAmB,OAAO;GAAI,MAAM,gBAAgB,MAAM,WAAW;EAAE;EAC5G,IAAI;EACJ,IAAI;EACJ,MAAM,SAAS,KAAK,OAAO,SAAS,SAAS,KAAK,OAAO,SAAS;EAClE,MAAM,OAAO,WAAW,SAAS,KAAA,IAAY,KAAK,SAAS,IAAI,MAAM;EACrE,IAAI,WAAW,UAAU,SAAS,KAAA,GAAW;GAC3C,IAAI,WAAW,UAAU,SAAS,KAAA,GAChC,KAAK,KAAK,oBAAoB,KAAK,GAAG,SAAS,OAAO,mBAAmB;GAE3E,eAAe,KAAK,aAAa;GACjC,QAAQ,EAAE,UAAU,CAAC,MAAM,EAAE;EAC/B,OAAO;GACL,MAAM,OAAO,UAAU,IAAI;GAC3B,eAAe,iBAAiB,MAAM,KAAK,YAAY;GACvD,QAAQ;IAAE,GAAG;IAAM,UAAU,CAAC,GAAI,KAAK,YAAY,CAAC,GAAI,MAAM;GAAE;EAClE;EAEA,IAAI;EACJ,IAAI;GACF,QAAQ,MAAM,KAAK,OAAO,OAAO;IAAE;IAAW,KAAK,KAAK;IAAK;IAAc;GAAM,CAAC;EACpF,SAAS,OAAO;GACd,OAAO,OAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EAC/E;EACA,IAAI;GACF,MAAM,KAAK,UAAU,OAAO,KAAK,KAAK,SAAS;EACjD,SAAS,OAAO;GAEd,KAAK,KAAK,iBAAiB,UAAU,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;EAClH;EAEA,MAAM,SAAS,kBAAkB;GAC/B,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM,KAAK;GAAO,CAAC;GAC7C,QAAQ,EAAE,MAAM,OAAO;EACzB,CAAC,CAAC;EAEF,MAAM,OAAO,MAAM,SAAS;EAC5B,KAAK,YAAY,KAAA,CAAS;EAC1B,MAAM,UAAU,KAAK,MAAM,KAAK,YAAY,CAAC,CAAC,WAAW;GAAE,MAAM,IAAI,gBAAgB;EAAE,CAAC;EACxF,QAAQ,YAAY,KAAA,CAAS;EAC7B,IAAI;GACF,MAAM,QAAQ,KAAK,CAAC,MAAM,OAAO,CAAC;GAClC,OAAO,MAAM,OAAO,IAAI;EAC1B,SAAS,OAAO;GACd,IAAI,iBAAiB,iBAAiB;IACpC,MAAM,OAAO;IACb,OAAO,MAAM,OAAO,SAAS,cAAc,KAAK,MAAM,KAAK,eAAe,GAAM,EAAE,YAAY;GAChG;GACA,OAAO,MAAM,OAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EACrF;CACF,EACF;AACF;;;;;ACnHA,SAAS,cAAc,UAAwF;CAC7G,OAAO;EAAE,QAAQ;EAAM,GAAI,SAAS,aAAa,KAAA,IAAY,EAAE,UAAU,SAAS,SAAS,IAAI,CAAC;CAAG;AACrG;;AAGA,SAAgB,iBAAiB,UAAwB,OAAmC;CAC1F,QAAQ,SAAS,MAAjB;EACE,KAAK,QAAQ;GACX,MAAM,SAAS,SAAS,KAAK,KAAK,CAAC,CAAC,MAAM,KAAK;GAC/C,IAAI,OAAO,WAAW,GAAG,OAAO,iCAAiC,OAAO,OAAO;GAC/E,IAAI,SAAS,aAAa,KAAA,GACxB,IAAI;IACF,IAAI,KAAK,eAAe,SAAS,EAAE,UAAU,SAAS,SAAS,CAAC;GAClE,QAAQ;IACN,OAAO,QAAQ,SAAS;GAC1B;GAEF,IAAI;IACF,IAAI,KAAK,SAAS,MAAM,cAAc,QAAQ,CAAC;GACjD,SAAS,OAAO;IACd,OAAO,eAAe,SAAS,KAAK,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GAC/F;GACA;EACF;EACA,KAAK,MAAM;GACT,MAAM,IAAI,KAAK,MAAM,SAAS,EAAE;GAChC,IAAI,OAAO,MAAM,CAAC,GAAG,OAAO,wBAAwB,SAAS;GAC7D,IAAI,KAAK,OAAO,OAAO,aAAa,SAAS;GAC7C;EACF;EACA,KAAK,SACH;CACJ;AACF;;AAGA,SAAgB,eAAe,UAAwB,aAAqB,OAA8B;CACxG,QAAQ,SAAS,MAAjB;EACE,KAAK,QAAQ;GACX,MAAM,OAAO,IAAI,KAAK,SAAS,MAAM,cAAc,QAAQ,CAAC,CAAC,CAAC,QAAQ,IAAI,KAAK,KAAK,CAAC;GACrF,OAAO,SAAS,OAAO,OAAO,KAAK,QAAQ;EAC7C;EACA,KAAK,MAAM;GACT,MAAM,IAAI,KAAK,MAAM,SAAS,EAAE;GAChC,OAAO,IAAI,QAAQ,IAAI;EACzB;EACA,KAAK,SAAS;GACZ,MAAM,aAAa,SAAS,UAAU;GACtC,IAAI,QAAQ,aAAa,OAAO;GAGhC,OAAO,eADG,KAAK,OAAO,QAAQ,eAAe,UAAU,IAAI,KAClC;EAC3B;CACF;AACF;;;;;;;AAqBA,SAAgB,UAAU,MAAgB,OAAyB;CACjE,IAAI,CAAC,KAAK,SAAS,OAAO,KAAK,cAAc,OAAO,OAAO;EAAE,GAAG;EAAM,WAAW;CAAK;CACtF,MAAM,YAAY,KAAK,cAAc,OAAO,OAAO,KAAK,MAAM,KAAK,SAAS;CAC5E,IAAI,cAAc,QAAQ,YAAY,OAAO,OAAO;CACpD,IAAI,cAAc,QAAQ,KAAK,SAAS,OAAO;EAAE,GAAG;EAAM,WAAW,IAAI,KAAK,KAAK,CAAC,CAAC,YAAY;CAAE;CACnG,MAAM,OAAO,eAAe,KAAK,UAAU,KAAK,MAAM,KAAK,SAAS,GAAG,KAAK;CAC5E,OAAO,SAAS,OACZ;EAAE,GAAG;EAAM,SAAS;EAAO,WAAW;CAAK,IAC3C;EAAE,GAAG;EAAM,WAAW,IAAI,KAAK,IAAI,CAAC,CAAC,YAAY;CAAE;AACzD;;AAGA,SAAgB,cAAc,MAAgB,OAAyB;CACrE,IAAI,CAAC,KAAK,SAAS,OAAO;EAAE,GAAG;EAAM,WAAW;CAAK;CACrD,MAAM,OAAO,eAAe,KAAK,UAAU,KAAK,MAAM,KAAK,SAAS,GAAG,KAAK;CAC5E,OAAO,SAAS,OACZ;EAAE,GAAG;EAAM,SAAS;EAAO,WAAW;CAAK,IAC3C;EAAE,GAAG;EAAM,WAAW,IAAI,KAAK,IAAI,CAAC,CAAC,YAAY;CAAE;AACzD;;AAGA,SAAgB,oBAAoB,MAAgB,OAAyB;CAC3E,IAAI,KAAK,SAAS,SAAS,MAAM,OAAO;EAAE,GAAG;EAAM,SAAS;EAAO,WAAW;CAAK;CACnF,MAAM,OAAO,eAAe,KAAK,UAAU,KAAK,MAAM,KAAK,SAAS,GAAG,KAAK;CAC5E,OAAO,SAAS,OACZ;EAAE,GAAG;EAAM,SAAS;EAAO,WAAW;CAAK,IAC3C;EAAE,GAAG;EAAM,WAAW,IAAI,KAAK,IAAI,CAAC,CAAC,YAAY;CAAE;AACzD;;;AC/EA,SAAgB,gBAAgB,MAAgC;;CAE9D,MAAM,0BAAU,IAAI,IAAY;CAEhC,eAAe,cAAc,MAA+B;EAC1D,MAAM,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY;EAChD,MAAM,MAAe;GACnB,IAAI,KAAK,SAAS;GAAG,QAAQ,KAAK;GAClC,aAAa;GAAQ,YAAY;GACjC,QAAQ;EACV;EACA,MAAM,KAAK,KAAK,IAAI,IAAI,IAAI,GAAG;EAC/B,MAAM,SAAS,KAAK,MAAM,KAAK,IAAI,KAAK,eAAe;CACzD;CAEA,SAAS,OAAO,MAAsB;EACpC,QAAQ,IAAI,KAAK,EAAE;EACnB,KAAU,QAAQ,IAAI,CAAC,CACpB,OAAO,UAAU,KAAK,KAAK,kBAAkB,KAAK,GAAG,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,CAAC,CAAC,CACzH,cAAc;GACb,QAAQ,OAAO,KAAK,EAAE;GAEtB,MAAM,UAAU,KAAK,MAAM,IAAI,KAAK,EAAE;GACtC,IAAI,YAAY,KAAA,KAAa,CAAC,QAAQ,SAAS;GAC/C,KAAU,MAAM,IAAI,KAAK,IAAI,oBAAoB,SAAS,KAAK,IAAI,CAAC,CAAC;EACvE,CAAC;CACL;CAEA,OAAO;EACL,MAAM,WAAW;GACf,KAAK,MAAM,CAAC,IAAI,SAAS,KAAK,MAAM,QAAQ,GAAG;IAC7C,MAAM,UAAU,UAAU,MAAM,KAAK,IAAI,CAAC;IAC1C,IAAI,YAAY,MAAM,MAAM,KAAK,MAAM,IAAI,IAAI,OAAO;GACxD;EACF;EACA,MAAM,OAAO;GACX,KAAK,MAAM,GAAG,SAAS,KAAK,MAAM,QAAQ,GAAG;IAC3C,IAAI,CAAC,KAAK,WAAW,KAAK,cAAc,MAAM;IAC9C,IAAI,KAAK,MAAM,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG;IAC7C,IAAI,QAAQ,IAAI,KAAK,EAAE,GAAG;KAExB,MAAM,cAAc,IAAI;KACxB,MAAM,KAAK,MAAM,IAAI,KAAK,IAAI,oBAAoB,MAAM,KAAK,IAAI,CAAC,CAAC;KACnE;IACF;IACA,OAAO,IAAI;GACb;EACF;EACA,YAAY,SAAS,cAAc,MAAM,KAAK,IAAI,CAAC;EACnD,MAAM,cAAc,QAAQ;GAC1B,MAAM,OAAO,KAAK,MAAM,IAAI,MAAM;GAClC,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,SAAS,OAAO,MAAM;GAC9D,IAAI,QAAQ,IAAI,MAAM,GAAG,MAAM,IAAI,MAAM,SAAS,KAAK,KAAK,kBAAkB;GAC9E,QAAQ,IAAI,MAAM;GAClB,IAAI;IACF,OAAO,MAAM,KAAK,QAAQ,IAAI;GAChC,UAAU;IACR,QAAQ,OAAO,MAAM;GACvB;EACF;EACA,YAAY,WAAW,QAAQ,IAAI,MAAM;CAC3C;AACF;;;AC3CA,SAAgB,kBAAkB,MAAoC;;CAEpE,MAAM,cAAc,UAAkF;EACpG,MAAM,gBAAgB,iBAAiB,MAAM,UAAU,KAAK,IAAI,CAAC;EACjE,IAAI,kBAAkB,KAAA,GAAW,OAAO;EACxC,IAAI,CAAC,KAAK,gBAAgB,MAAM,GAAG,GAAG,OAAO,WAAW,MAAM;EAC9D,IAAI,MAAM,OAAO,SAAS,UAAU,KAAK,SAAS,IAAI,MAAM,OAAO,MAAM,MAAM,KAAA,GAC7E,OAAO,OAAO,MAAM,OAAO,OAAO;CAGtC;CAEA,OAAO;EACL,OAAO;GACL,OAAO,CAAC,GAAG,KAAK,MAAM,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,UAAU;IACjD,MAAM,OAAO,SAAS,KAAK,MAAM,KAAK,EAAE,CAAC,CAAC;IAI1C,OAH2B,SAAS,KAAA,IAChC,OACA;KAAE,GAAG;KAAM,SAAS;MAAE,QAAQ,KAAK;MAAQ,aAAa,KAAK;KAAY;IAAE;GAEjF,CAAC;EACH;EACA,MAAM,OAAO,KAAK,MAAM,IAAI,EAAE;EAC9B,MAAM,OAAO,OAAO;GAClB,MAAM,UAAU,WAAW,KAAK;GAChC,IAAI,YAAY,KAAA,GAAW,OAAO;IAAE,IAAI;IAAO,OAAO;GAAQ;GAC9D,MAAM,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY;GAChD,MAAM,SAAS,eAAe,UAAU;IACtC,IAAI,KAAK,UAAU;IAAG,GAAG;IACzB,WAAW;IAAM,WAAW;IAAQ,WAAW;GACjD,CAAC;GACD,IAAI,CAAC,OAAO,SAAS,OAAO;IAAE,IAAI;IAAO,OAAO,OAAO,MAAM,OAAO,EAAE,EAAE,WAAW;GAAe;GAClG,MAAM,OAAO,KAAK,UAAU,UAAU,OAAO,IAAI;GACjD,MAAM,KAAK,MAAM,IAAI,KAAK,IAAI,IAAI;GAClC,OAAO;IAAE,IAAI;IAAM,OAAO;GAAK;EACjC;EACA,MAAM,OAAO,IAAI,OAAO;GACtB,MAAM,WAAW,KAAK,MAAM,IAAI,EAAE;GAClC,IAAI,aAAa,KAAA,GAAW,OAAO;IAAE,IAAI;IAAO,OAAO,SAAS,GAAG;GAAO;GAC1E,MAAM,SAAS;IACb,GAAG;IACH,GAAI,OAAO,YAAY,OAAO,QAAQ,KAAK,CAAC,CAAC,QAAQ,GAAG,OAAO,MAAM,KAAA,CAAS,CAAC;IAC/E,IAAI,SAAS;IACb,WAAW,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY;GAC9C;GACA,MAAM,UAAU,WAAW,MAAM;GACjC,IAAI,YAAY,KAAA,GAAW,OAAO;IAAE,IAAI;IAAO,OAAO;GAAQ;GAC9D,MAAM,SAAS,eAAe,UAAU,MAAM;GAC9C,IAAI,CAAC,OAAO,SAAS,OAAO;IAAE,IAAI;IAAO,OAAO,OAAO,MAAM,OAAO,EAAE,EAAE,WAAW;GAAe;GAClG,MAAM,OAAO,KAAK,UAAU,UAAU,OAAO,IAAI;GACjD,MAAM,KAAK,MAAM,IAAI,IAAI,IAAI;GAC7B,OAAO;IAAE,IAAI;IAAM,OAAO;GAAK;EACjC;EACA,MAAM,OAAO,IAAI;GACf,IAAI,KAAK,MAAM,IAAI,EAAE,MAAM,KAAA,GAAW,OAAO;IAAE,IAAI;IAAO,OAAO,SAAS,GAAG;GAAO;GACpF,MAAM,KAAK,MAAM,OAAO,EAAE;GAC1B,MAAM,aAAa,KAAK,MAAM,EAAE;GAChC,OAAO;IAAE,IAAI;IAAM,OAAO;GAAK;EACjC;EACA,MAAM,QAAQ,IAAI;GAChB,IAAI;IACF,OAAO;KAAE,IAAI;KAAM,OAAO,MAAM,KAAK,UAAU,cAAc,EAAE;IAAE;GACnE,SAAS,OAAO;IACd,OAAO;KAAE,IAAI;KAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAAE;GACpF;EACF;EACA,SAAS,IAAI,UAAU,SAAS,KAAK,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,KAAK;CAC/D;AACF;;;;AC1GA,MAAM,qBAAqB;;AAG3B,SAAS,WAAW,MAA6C;CAC/D,MAAM,OAAO,KAAK;CAClB,IAAI,SAAS,QAAQ;EACnB,IAAI,OAAO,KAAK,aAAa,YAAY,KAAK,SAAS,KAAK,MAAM,IAAI,MAAM,IAAI,MAAM,8CAA8C;EACpI,OAAO;GACL,MAAM;GAAQ,MAAM,KAAK;GACzB,GAAI,OAAO,KAAK,aAAa,YAAY,KAAK,aAAa,KAAK,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;EACjG;CACF;CACA,IAAI,SAAS,MAAM;EACjB,IAAI,OAAO,KAAK,WAAW,YAAY,KAAK,WAAW,IAAI,MAAM,IAAI,MAAM,wCAAwC;EACnH,OAAO;GAAE,MAAM;GAAM,IAAI,KAAK;EAAO;CACvC;CACA,IAAI,SAAS,SAAS;EACpB,IAAI,OAAO,KAAK,iBAAiB,UAAU,MAAM,IAAI,MAAM,6CAA6C;EACxG,OAAO;GAAE,MAAM;GAAS,SAAS,KAAK;EAAa;CACrD;CACA,MAAM,IAAI,MAAM,mBAAmB,OAAO,IAAI,EAAE,uBAAuB;AACzE;AAEA,SAAS,SAAS,MAA2C;CAC3D,IAAI,KAAK,eAAe,QAAQ;EAC9B,IAAI,OAAO,KAAK,WAAW,YAAY,KAAK,WAAW,IAAI,MAAM,IAAI,MAAM,2BAA2B;EACtG,OAAO;GAAE,MAAM;GAAQ,QAAQ,KAAK;EAAO;CAC7C;CACA,OAAO,EAAE,MAAM,OAAO;AACxB;;AAGA,SAAS,OAAU,QAAkE;CACnF,IAAI,CAAC,OAAO,IAAI,MAAM,IAAI,MAAM,OAAO,KAAK;CAC5C,OAAO,OAAO;AAChB;AAEA,MAAM,cAAc;CAClB,QAAQ,EAAE,MAAM,OAAO;CACvB,SAAS,OAAgB,UAAmB,CAAC;EAAE,MAAM;EAAiB,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC;CAAE,CAAC;AAC9G;AAEA,MAAM,2BAA2B,EAC/B,cAAc;CAAE,MAAM;CAAU,UAAU;CAAM,aAAa;AAA4B,EAC3F;AAEA,MAAM,2BAA2B,EAC/B,cAAc;CAAE,MAAM;CAAU,aAAa;AAA6E,EAC5H;AAEA,MAAM,wBAAwB;CAC5B,UAAU;EAAE,MAAM;EAAU,aAAa;CAAsI;CAC/K,UAAU;EAAE,MAAM;EAAU,aAAa;CAA6F;CACtI,QAAQ;EAAE,MAAM;EAAU,aAAa;CAA2F;CAClI,cAAc;EAAE,MAAM;EAAU,aAAa;CAAwF;AACvI;AAEA,MAAM,yBAAyB,EAC7B,YAAY;CAAE,MAAM;CAAU,UAAU;CAAM,aAAa;AAAwG,EACrK;AAEA,MAAM,yBAAyB,EAC7B,YAAY;CAAE,MAAM;CAAU,aAAa;AAA8B,EAC3E;AAEA,MAAM,gBAAgB,EAAE,QAAQ;CAAE,MAAM;CAAU,aAAa;AAAkD,EAAE;AAEnH,SAAgB,gBAAgB,SAAwC;CACtE,OAAO;EACL,WAAW;GACT,MAAM;GACN,aACE;GAGF,YAAY;IACV,MAAM;KAAE,MAAM;KAAU,UAAU;KAAM,aAAa;IAAsB;IAC3E,QAAQ;KAAE,MAAM;KAAU,UAAU;KAAM,aAAa;IAA6G;IACpK,KAAK;KAAE,MAAM;KAAU,UAAU;KAAM,aAAa;IAAsE;IAC1H,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,SAAS;KAAE,MAAM;KAAW,UAAU;KAAM,aAAa;IAAwH;IACjL,SAAS;KAAE,MAAM;KAAW,UAAU;KAAM,aAAa;IAAiF;GAC5I;GACA,QAAQ;GACR,yBAAyB;GACzB,MAAM,QAAQ,SAAS;IACrB,MAAM,OAAO;IACb,MAAM,QAAuB;KAC3B,MAAM,KAAK;KACX,QAAQ,KAAK;KACb,KAAK,KAAK;KACV,UAAU,WAAW,IAAI;KACzB,QAAQ,SAAS,IAAI;KACrB,SAAS,KAAK;KACd,SAAS,KAAK;IAChB;IACA,OAAO,OAAO,MAAM,QAAQ,OAAO,KAAK,CAAC;GAC3C;EACF,CAAC;EACD,WAAW;GACT,MAAM;GACN,aAAa;GACb,YAAY,CAAC;GACb,QAAQ;GACR,yBAAyB;GACzB,MAAM,UAAU;IACd,OAAO,QAAQ,KAAK;GACtB;EACF,CAAC;EACD,WAAW;GACT,MAAM;GACN,aAAa;GACb,YAAY;IACV,IAAI;KAAE,MAAM;KAAU,UAAU;KAAM,aAAa;IAAU;IAC7D,MAAM;KAAE,MAAM;KAAU,aAAa;IAAW;IAChD,QAAQ;KAAE,MAAM;KAAU,aAAa;IAAa;IACpD,KAAK;KAAE,MAAM;KAAU,aAAa;IAAwB;IAC5D,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,SAAS;KAAE,MAAM;KAAW,aAAa;IAAmB;IAC5D,SAAS;KAAE,MAAM;KAAW,aAAa;IAA0B;GACrE;GACA,QAAQ;GACR,yBAAyB;GACzB,MAAM,QAAQ,SAAS;IACrB,MAAM,OAAO;IACb,MAAM,QAAuB,CAAC;IAC9B,IAAI,KAAK,SAAS,KAAA,GAAW,MAAM,OAAO,KAAK;IAC/C,IAAI,KAAK,WAAW,KAAA,GAAW,MAAM,SAAS,KAAK;IACnD,IAAI,KAAK,QAAQ,KAAA,GAAW,MAAM,MAAM,KAAK;IAC7C,IAAI,KAAK,iBAAiB,KAAA,GAAW,MAAM,WAAW,WAAW,IAAI;IACrE,IAAI,KAAK,eAAe,KAAA,GAAW,MAAM,SAAS,SAAS,IAAI;IAC/D,IAAI,KAAK,YAAY,KAAA,GAAW,MAAM,UAAU,KAAK;IACrD,IAAI,KAAK,YAAY,KAAA,GAAW,MAAM,UAAU,KAAK;IACrD,OAAO,OAAO,MAAM,QAAQ,OAAO,KAAK,IAAc,KAAK,CAAC;GAC9D;EACF,CAAC;EACD,WAAW;GACT,MAAM;GACN,aAAa;GACb,YAAY,EAAE,IAAI;IAAE,MAAM;IAAU,UAAU;IAAM,aAAa;GAAU,EAAE;GAC7E,QAAQ;GACR,yBAAyB;GACzB,MAAM,QAAQ,SAAS;IACrB,OAAO,OAAO,MAAM,QAAQ,OAAQ,QAAoC,EAAY,CAAC;GACvF;EACF,CAAC;EACD,WAAW;GACT,MAAM;GACN,aAAa;GACb,YAAY,EAAE,IAAI;IAAE,MAAM;IAAU,UAAU;IAAM,aAAa;GAAU,EAAE;GAC7E,QAAQ;GACR,yBAAyB;GACzB,MAAM,QAAQ,SAAS;IACrB,OAAO,OAAO,MAAM,QAAQ,QAAS,QAAoC,EAAY,CAAC;GACxF;EACF,CAAC;CACH;AACF;;;;;;;;;;AAWA,SAAgB,eAAe,KAAc,OAAyB,eAA0C;CAC9G,MAAM,2BAAW,IAAI,IAAuB;CAC5C,IAAI,WAAW;CAEf,IAAI,aAAa;EACf,MAAM,cAAc,IAAI,GAAG,kBAAkB,EAAE,YAAY;GACzD,IAAI,YAAY,SAAS,IAAI,KAAK,GAAG;GACrC,OAAO,KAAK;EACd,CAAC;EACD,KAAK,MAAM,SAAS,IAAI,OAAO,MAAM,GAAG,OAAO,KAAK;EAEpD,OAAO,YAAY;GACjB,WAAW;GACX,YAAY;GACZ,MAAM,WAAW,CAAC,GAAG,SAAS,OAAO,CAAC;GACtC,SAAS,MAAM;GACf,MAAM,QAAQ,WAAW,SAAS,KAAK,YAAY,QAAQ,QAAQ,QAAQ,CAAC,CAAC,CAAC;EAChF;CACF,GAAG,gCAAgC;CAEnC,SAAS,OAAO,OAAoB;EAClC,IAAI,SAAS,IAAI,KAAK,GAAG;EACzB,IAAI,MAAM,QAAQ,OAAO,WAAW,YAAY;EAChD,IAAI,cAAc,IAAI,OAAO,MAAM,QAAQ,EAAE,CAAC,GAAG;EACjD,MAAM,UAAU,MAAM,IAAI,aAAa;GACrC,MAAM,QAAQ,QAAQ,MAAM,GAAG;GAI/B,IAHoB,UAAU,KAAA,IAC1B,IAAI,MAAM,IAAI,oBAAoB,KAAK,MAAM,KAAA,IAC7C,IAAI,MAAM,IAAI,kBAAkB,MAAM,KAAA,GAExC,IAAI,OAAO,KACT,6JAGF;GAEF,MAAM,YAAY,MAAM,KAAK,SAAS,MAAM,IAAI,MAAM,SAAS,IAAI,CAAC;GACpE,aAAa;IACX,KAAK,MAAM,WAAW,WAAW,QAAQ;IACzC,IAAI,SAAS,IAAI,KAAK,MAAM,SAAS,SAAS,OAAO,KAAK;GAC5D;EACF,GAAG,uCAAuC;EAC1C,SAAS,IAAI,OAAO,OAAO;CAC7B;AACF;;;;;AC7LA,MAAM,UAAU;AAEhB,SAAgB,cAAc,KAAc,QAA8B,MAA0B;CAClG,MAAM,QAAQ,MAAoB,IAAI,OAAO,KAAK,CAAC;CAEnD,MAAM,aAAa,iBAAiB,GAAG;CAIvC,MAAM,aAAa,iBAAiB,KAHR,KAAK,gBAAgB,KAAA,IAC7C,kBAAkB,KAAK,KAAK,aAAa,YAAY,IAAI,IACzD,YAC6C,KAAK,aAAa;CAOnE,MAAM,4BACJ,IAAI,IAAI,qBAAqB,KAAK;CACpC,MAAM,gBAA+B,EACnC,MAAM,OAAO,KAAK,WAAW;EAC3B,MAAM,WAAW,oBAAoB;EACrC,IAAI,aAAa,KAAA,GAAW,MAAM,IAAI,MAAM,yBAAyB;EAErE,OAAM,MADkB,SAAS,OAAO,GAAG,EAAA,CAC3B,cAAc,UAAU,SAAS,CAAC;CACpD,EACF;CAEA,IAAI;CACJ,MAAM,UAAU,iBAAiB,KAAK,gBAAgB,IAAI,CAAC,CAAC,KAAK,OAAO,WAAW;EACjF,MAAM,QAAQ,OAAO,MAAM,OAAO;EAClC,MAAM,OAAO,OAAO,MAAM,MAAM;EAChC,MAAM,WAAW,eAAe;GAC9B,QAAQ;GACR,UAAU,KAAK;GACf,oBAAoB;IAClB,MAAM,YAAY,IAAI,kBAAkB,iBAAiB;IACzD,OAAO;KAAE,UAAU,UAAU;KAAU,OAAO,UAAU;IAAM;GAChE;GACA,WAAW;GACX;GACA,iBAAiB,OAAO;GACxB,cAAc,OAAO,oBAAoB;GACzC;GACA,WAAW,KAAK,IAAI;GACpB,oBAAoB,WAAW;GAC/B,gBAAgB,WAAW;GAC3B,QAAQ,OAAO,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;EACjE,CAAC;EACD,YAAY,gBAAgB;GAC1B;GAAO;GACP,iBAAiB,OAAO;GACxB,UAAU,SAAS,SAAS,QAAQ,IAAI;GACxC,WAAW,KAAK,IAAI;GACpB,gBAAgB,WAAW;GAC3B;EACF,CAAC;EACD,MAAM,UAAU,kBAAkB;GAChC;GAAO;GACP;GACA,UAAU,KAAK;GACf,kBAAkB,SAAS,WAAW,IAAI;GAC1C,WAAW,KAAK,IAAI;GACpB,iBAAiB,WAAW;EAC9B,CAAC;EACD,eAAe,KAAK,gBAAgB,OAAO,GAAG,KAAK,aAAa;EAEhE,uBAAuB,MAAM,WAAW;GACtC,MAAM,UAAU,OAAO,UAAU,SAAS;IACxC,MAAM;IACN,MAAM;IACN,SAAS,OAAO,KAAK,QAAQ;KAC3B,IAAI;MACF,MAAM;MACN,MAAM,qBAAqB;OACzB;OACA,oBAAoB,oBAAoB,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC;OACzE,iBAAiB,OAAO;MAC1B,CAAC,CAAC,CAAC,KAAK,GAAG;KACb,SAAS,OAAO;MACd,IAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC,CAAC,CACvD,IAAI,KAAK,UAAU,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,CAAC,CAAC;KAC1F;IACF;GACF,CAAC;GACD,aAAa,QAAQ;EACvB,CAAC;EACD,MAAM,UAAU,SAAS;CAC3B,CAAC;CACD,QAAQ,OAAO,UAAU;EACvB,KAAK,mBAAmB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;CAClF,CAAC;CAKD,IAAI,aAAa;EACf,MAAM,QAAQ,kBAAkB;GAAE,QAAa,WAAW,WAAW,KAAK,CAAC;EAAE,GAAG,OAAO;EACvF,aAAa,cAAc,KAAK;CAClC,CAAC;CAED,IAAI,aAAa,YAAY;EAAE,MAAM,WAAW,QAAQ;CAAE,CAAC;AAC7D;;;ACnHA,MAAa,OAAO;AAKpB,MAAa,SAAS;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAgBA,MAAa,SAA6B,EAAE,OAAO;CACjD,SAAS,EAAE,OAAO;EAChB,QAAQ,EAAE,QAAQ,CAAC,CAAC,QAAQ,IAAI;EAChC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,IAAI;CACjC,CAAC,CAAC,CAAC,QAAQ;EAAE,QAAQ;EAAM,OAAO;CAAK,CAAC;CACxC,QAAQ,EAAE,MAAM,EAAE,OAAO;EACvB,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS;EAC1B,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;EAC3B,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS;CAC5B,CAAC,CAAC,CAAC,CAAC,QAAQ,cAAc;CAK1B,OAAO,EAAE,MAAO,EAAE,OAAO;EACvB,OAAO,EAAE,OAAO;GACd,UAAU,EAAE,OAAO;GACnB,OAAO,EAAE,OAAO;GAChB,cAAc,EAAE,OAAO;EACzB,CAAC,CAAC,CAAC,SAAS;EACZ,WAAW,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,IAAG,UAAS,OAAO,KAAK,KAAK,CAAC,CAAC,WAAW,IAAI,KAAA,IAAY,KAAK;EACvG,QAAQ,EAAE,OAAO;CACnB,CAAC,CAAa,CAAC,CAAC,QAAQ,aAAa;CACrC,UAAU,EAAE,OAAO,CAAC,CAAC,QAAQ,eAAe;CAC5C,UAAU,EAAE,OAAO,CAAC,CAAC,QAAQ,OAAO;CACpC,UAAU,EAAE,OAAO,CAAC,CAAC,QAAQ,eAAe;CAE5C,QAAQ,EAAE,OAAO;EACf,sBAAsB,EAAE,OAAO,CAAC,CAAC,QAAQ,GAAG;EAC5C,cAAc,EAAE,OAAO,CAAC,CAAC,QAAQ,IAAM;EACvC,eAAe,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC;EACnC,iBAAiB,EAAE,OAAO,CAAC,CAAC,QAAQ,GAAK;EACzC,sBAAsB,EAAE,OAAO,CAAC,CAAC,QAAQ,GAAO;EAChD,yBAAyB,EAAE,OAAO,CAAC,CAAC,QAAQ,WAAW;EACvD,qBAAqB,EAAE,OAAO,CAAC,CAAC,QAAQ,GAAG;EAC3C,cAAc,EAAE,QAAQ,CAAC,CAAC,QAAQ,IAAI;EACtC,UAAU,EAAE,QAAQ,CAAC,CAAC,QAAQ,IAAI;CACpC,CAAC,CAAC,CAAC,QAAQ;EACT,sBAAsB;EACtB,cAAc;EACd,eAAe;EACf,iBAAiB;EACjB,sBAAsB;EACtB,yBAAyB;EACzB,qBAAqB;EACrB,cAAc;EACd,UAAU;CACZ,CAAC;CAID,iBAAiB,EAAE,OAAO;EACxB,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,IAAI;EACjC,IAAI,EAAE,OAAO,CAAC,CAAC,QAAQ,YAAY;EACnC,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,UAAU;EACrC,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,UAAU;EACnC,aAAa,EAAE,OAAO,CAAC,CAAC,QAAQ,uDAAuD;EACvF,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,WAAW;CACxC,CAAC,CAAC,CAAC,QAAQ;EACT,SAAS;EACT,IAAI;EACJ,QAAQ;EACR,MAAM;EACN,aAAa;EACb,QAAQ;CACV,CAAC;CAGD,UAAU,EAAE,OAAO;EACjB,mBAAmB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE;EAC/C,iBAAiB,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE;CAChD,CAAC,CAAC,CAAC,QAAQ;EAAE,mBAAmB;EAAI,iBAAiB;CAAG,CAAC;AAC3D,CAAC;AAED,eAAsB,MAAM,KAAc,QAA+B;CACvE,eAAqB;EAAE,QAAQ,OAAO;EAAQ,OAAO,OAAO;CAAM,CAAC;CACnE,MAAM,QAAQ,QAAsB,IAAI,OAAO,KAAK,GAAG;CACvD,MAAM,SAAS,MAAM,iBAAiB,KAAK,oBAAoB,IAAI;CACnE,MAAM,SAAS;EACb,QAAQ,OAAO,MAAM,QAAQ;EAC7B,MAAM,OAAO,MAAM,MAAM;EACzB,cAAc,OAAO,MAAM,eAAe;CAC5C;CAIA,MAAM,qBAAqB,KAAK,OAAO,eAAe;CACtD,MAAM,cAAc,kBAAkB,KAAK,OAAO,gBAAgB,EAAE;CACpE,MAAM,WAAW,MAAM,eAAe,MAAM;EAAE,QAAQ,OAAO;EAAQ,MAAM,OAAO;CAAK,GAAG,YAAY,eAAe;CACrH,MAAM,cAAc,MAAM,gBAAgB;EAAE,cAAc,OAAO;EAAc,MAAM,OAAO;CAAK,GAAG,OAAO,MAAM;CACjH,YAAY,KAAK;EAAE,QAAQ;EAAa,OAAO,OAAO;CAAM,CAAC;CAE7D,MAAM,eAAc,MADO,iBAAiB,KAAK,wBAAwB,IAAI,EAAA,CAC5C,MAAM,QAAQ;CAC/C,MAAM,eAAe,mBAAmB;CACxC,cAAc,KAAK;EACjB,UAAU,OAAO;EACjB,UAAU,OAAO;EACjB,OAAO,OAAO;CAChB,GAAG,UAAU;EACX,QAAQ;EACR,aAAa,OAAO,gBAAgB,UAAU;GAC5C,MAAM,YAAY,IAAI,gBAAgB;IAAE,UAAU,MAAM;IAAU,OAAO,MAAM;IAAO,IAAI,KAAK,IAAI;GAAE,CAAC;EACxG;CACF,CAAC;CACD,iBAAiB,KAAK;EAAE,QAAQ;EAAc,QAAQ;CAAY,CAAC;CAGnE,eAAe,KAAK;EAClB;EACA,WAAW,YAAY;EACvB,iBAAiB,YAAY;EAC7B,qBAAqB,IAAI,IAAI,cAAc,CAAC,CAAC,KAAK,EAAE,IAAI,YAAY;GAAE;GAAI;EAAK,EAAE;EACjF,aAAa,aAAa,IAAI,IAAI,WAAW,QAAQ,CAAC,CAAC,MAAM,WAAW,OAAO,KAAK,EAAE,IAAI,YAAY;GAAE;GAAI;EAAK,EAAE,CAAC;CACtH,CAAC;CAED,wBAAwB,KAAK;EAAE;EAAU,WAAW,YAAY;EAAiB,iBAAiB,YAAY;CAAgB,CAAC;CAC/H,qBAAqB,KAAK;EACxB,QAAQ;EACR,OAAO,OAAO;EACd,YAAY,OAAO;EAEnB,OAAO,YAAY;GACjB,MAAM,WAAW,MAAM,IAAI,aAAa,SAAS,CAAC,CAAC;GACnD,OAAO;IACL,UAAU,SAAS,SAAS,KAAK,EAAE,MAAM,GAAG,YAAY;KAAE,MAAM;KAAG;IAAK,EAAE;IAC1E,UAAU,SAAS,SAAS,KAAK,EAAE,MAAM,GAAG,YAAY;KAAE,MAAM;KAAG;IAAK,EAAE;GAC5E;EACF;CACF,CAAC;CACD,MAAM,gCAAgB,IAAI,IAAY;CACtC,IAAI,OAAO,QAAQ,QAAQ,UAAU,KAAK,OAAO,QAAQ;EAAE;EAAU,aAAa,OAAO,gBAAgB,UAAU,OAAO,gBAAgB,SAAS,KAAA;EAAW;CAAc,CAAC;CAC7K,IAAI,OAAO,QAAQ,OAAO,WAAW,KAAK,EAAE,UAAU,OAAO,SAAS,GAAG,IAAI;CAE7E,cAAc,KAAK,OAAO,UAAU;EAClC;EACA,aAAa,OAAO,gBAAgB,UAAU,OAAO,gBAAgB,SAAS,KAAA;EAC9E;CACF,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["z","z","MAX_BODY_BYTES","json","readJsonBody","z","readJsonBody","z","readJsonBody","z","CreateBodySchema","z","UpdateBodySchema","z","z","readJsonBody"],"sources":["../src/agents/store.ts","../src/channels/basic-tools.ts","../src/agents/builtin.ts","../src/agents/import-yaml.ts","../src/agents/registry.ts","../src/agents/tool-catalog.ts","../src/shared/storage.ts","../src/prompt/defaults.ts","../src/prompt/match.ts","../src/prompt/index.ts","../src/prompt/layer-source.ts","../src/shared/webserver.ts","../src/shared/http.ts","../src/prompt/api.ts","../src/prompt/persona.ts","../src/delegate/tool.ts","../src/delegate/index.ts","../src/delegate/active.ts","../src/delegate/routes.ts","../src/delegate/api.ts","../src/agents/api.ts","../src/agents/create-command.ts","../src/channels/agent-setup.ts","../src/channels/agents-port.ts","../src/channels/feishu/api.ts","../src/channels/directive.ts","../src/channels/feishu/parse.ts","../src/channels/feishu/cards.ts","../src/channels/feishu/reply.ts","../src/channels/approval/feishu.ts","../src/channels/feishu/card-action.ts","../src/channels/feishu/index.ts","../src/bots/store.ts","../src/channels/outbound.ts","../src/channels/inbound.ts","../src/channels/ports.ts","../src/channels/role-assembly.ts","../src/channels/router.ts","../src/channels/approval/center.ts","../src/channels/runtime.ts","../src/channels/scope-joiner.ts","../src/channels/tool-scope.ts","../src/channels/approval/answerer.ts","../src/bots/api.ts","../src/bots/register-app.ts","../src/bots/index.ts","../src/agents/bot-preset.ts","../src/agents/team-preset.ts","../src/schedule/store.ts","../src/schedule/api.ts","../src/schedule/executor.ts","../src/schedule/timing.ts","../src/schedule/scheduler.ts","../src/schedule/service.ts","../src/schedule/tools.ts","../src/schedule/index.ts","../src/index.ts"],"sourcesContent":["/** agents 注册表存储域声明:记录 schema + domain 布局的单一来源。 */\r\nimport { z } from 'zod'\r\nimport { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport type { LayerConfig } from '../prompt/types.ts'\r\n\r\n/** Agent id 约束:'main' 或小写字母开头、仅 [a-z0-9-]、总长 ≤ 32。 */\r\nexport const AGENT_ID_RE = /^(?:main|[a-z][a-z0-9-]{0,31})$/\r\n\r\n/** 一条 Agent 注册表记录。tools 仅白名单。 */\r\nexport interface AgentRecord {\r\n id: string // 'main' 或 [a-z0-9-] slug\r\n name: string\r\n description?: string\r\n persona?: string // 角色唯一可自定义提示层(固定分层中的 persona 层文本)\r\n /** @deprecated 仅迁移输入:旧版多分层,createRegistry 读取时拼接进 persona 后剥离。 */\r\n promptLayers?: LayerConfig[]\r\n model?: { provider: string; model: string }\r\n tools?: { allow: string[] } // 仅白名单;空数组拒绝(min(1) 语义)\r\n builtin?: boolean\r\n /** 团队可见性:省略/true = 出现在 Agent 团队名册并可被委派;false = 隐藏。bot 绑定不受此字段影响。 */\r\n visibleInTeam?: boolean\r\n}\r\n\r\nexport const LayerConfigSchema = z.object({\r\n name: z.string(),\r\n order: z.number(),\r\n text: z.string(),\r\n})\r\n\r\nexport const AgentRecordSchema: z.ZodType<AgentRecord> = z.object({\r\n id: z.string().regex(AGENT_ID_RE),\r\n name: z.string().min(1),\r\n description: z.string().optional(),\r\n persona: z.string().optional(),\r\n promptLayers: z.array(LayerConfigSchema).optional(),\r\n model: z.object({ provider: z.string(), model: z.string() }).optional(),\r\n tools: z.object({ allow: z.array(z.string()).min(1) }).optional(),\r\n builtin: z.boolean().optional(),\r\n visibleInTeam: z.boolean().optional(),\r\n})\r\n\r\n/** domain 名/表名受 UNIT_NAME_RE 约束(^[a-z][a-z0-9_]*$),不允许连字符。 */\r\nexport const agentToolkitDomain = defineDomain({\r\n name: 'dsh_agent_toolkit',\r\n version: 1,\r\n tables: {\r\n agents: domainTable<string, AgentRecord>(AgentRecordSchema),\r\n // meta 表存一次性标记(如 roles_yaml_imported),schema 无法表达则独立成表。\r\n meta: domainTable<string, { value: string }>(z.object({ value: z.string() })),\r\n // 分层提示词层列表:单行 JSON(key 常量 'layers'),整体替换语义,与 agents 表同构校验。\r\n prompt_layers: domainTable<string, { layers: LayerConfig[] }>(z.object({ layers: z.array(LayerConfigSchema) })),\r\n },\r\n})\r\n\r\n/**\r\n * 旧记录迁移:promptLayers 按 order 升序拼接进 persona(忽略纯空白层;persona 已存在不覆盖),\r\n * 剥离 promptLayers 返回新对象;无需迁移返回原引用(调用方按引用比较决定是否写回)。\r\n */\r\nexport function migrateAgentRecord(record: AgentRecord): AgentRecord {\r\n if (record.promptLayers === undefined) return record\r\n const { promptLayers, ...rest } = record\r\n const joined = [...promptLayers]\r\n .sort((a, b) => a.order - b.order)\r\n .map((layer) => layer.text)\r\n .filter((text) => text.trim().length > 0)\r\n .join('\\n\\n')\r\n const persona = rest.persona ?? joined\r\n return persona.length > 0 ? { ...rest, persona } : rest\r\n}\r\n\r\n/** 团队可见性判定:缺省(undefined)与 true 均可见;仅显式 false 隐藏。 */\r\nexport function isTeamVisible(role: Pick<AgentRecord, 'visibleInTeam'>): boolean {\r\n return role.visibleInTeam !== false\r\n}\r\n","/** 基础工具行(与 dsh standard agent preset 同源):persona / instructions / shell / fs / fs-search。\r\n * 源:archive/2026-08-26-merged-plugins/agent-team/presets/team/agent.cordis.yml 的基础工具行,\r\n * 逐行对照 deepseek-harness/apps/cli/config/agent-presets/standard/agent.cordis.yml 核对 id 与 config。\r\n * shell 双行按平台互斥(win32 用 pwsh,其余用 bash),与两 preset 的 disabled 条件一致。\r\n * 这些行由 tool-scope.ts 一次性挂进 bot 会话共用的 standing scope(祖先层),agent 经\r\n * setupAgentScope join 加入——宿主 tools.restrict() 只能过滤继承面,挂进 agentCtx own 层\r\n * 的白名单会抛 unknown global tools(2026-09-03 事故)。 */\r\n\r\nexport interface BasicTool {\r\n /** 插件包名(preset 行的 name 字段)。 */\r\n id: string\r\n /** 插件 config(preset 行的 config 字段;无则省略)。 */\r\n config?: Record<string, unknown>\r\n}\r\n\r\nexport const BASIC_TOOLS: BasicTool[] = [\r\n {\r\n // 0.1.5-rc.1 起 dsh-persona Config 由 { text } 改为 { prefix, suffix? }(prefix 必填,\r\n // suffix 渲染在 first-party 指导之后);拆分方式对齐 standard preset 的 persona 行。\r\n id: '@deepseek-ai/dsh-persona',\r\n config: {\r\n prefix: 'You are a coding agent powered by the {{model}} model. If you need information or a decision from the user, ask directly in your reply and wait for their next message.',\r\n suffix: 'Your working directory is {{cwd}}.',\r\n },\r\n },\r\n {\r\n id: '@deepseek-ai/dsh-agent-instructions',\r\n config: { maxBytes: 65536 },\r\n },\r\n ...(process.platform === 'win32'\r\n ? [{ id: '@deepseek-ai/dsh-tool-pwsh' }]\r\n : [{ id: '@deepseek-ai/dsh-tool-bash' }]),\r\n { id: '@deepseek-ai/dsh-tool-fs' },\r\n {\r\n id: '@deepseek-ai/dsh-tool-fs-search',\r\n config: { sampleOverCapGlobResults: false },\r\n },\r\n]\r\n\r\n/** 内置工具名常量(兜底名单):agentPresets 缺席或 standing 枚举失败时,Agents 面板名册\r\n * 与存量迁移回退到这份常量。语义已降级为\"兜底\",不再承诺是完整原生工具面——完整面 =\r\n * 团队 preset 动态枚举(agents/tool-catalog.ts)。explorer 只读白名单仍从本常量派生\r\n * (刻意的最小集,不追求完整)。 */\r\nexport const NATIVE_TOOL_NAMES: readonly string[] = [\r\n process.platform === 'win32' ? 'pwsh' : 'bash',\r\n 'read',\r\n 'write',\r\n 'edit',\r\n 'read_image',\r\n 'glob',\r\n 'grep',\r\n]\r\n","/** 内置保底 Agent 记录:main + explorer(只读白名单 10 个)/ general(preset 面全量 20 个、禁二级委派)。 */\r\nimport { NATIVE_TOOL_NAMES } from '../channels/basic-tools.ts'\r\nimport type { AgentRecord } from './store.ts'\r\n\r\nconst SHELL_NAME = process.platform === 'win32' ? 'pwsh' : 'bash'\r\n\r\n/** 旧版 explorer 默认白名单(5 个):存量条件式迁移的等值比对基准。\r\n * 独立于 EXPLORER_READONLY_ALLOW 保留旧派生式——比对基准不可随新名单漂移。\r\n * shell 名平台互斥(win32=pwsh、其余=bash),必须从 NATIVE_TOOL_NAMES 派生不可写死。 */\r\nexport const LEGACY_EXPLORER_ALLOW: readonly string[] = NATIVE_TOOL_NAMES.filter((n) => n !== 'write' && n !== 'edit')\r\n\r\n/** explorer 默认白名单(10 个):只读基础五件(shell/read/read_image/glob/grep,旧派生不变)\r\n * + preset 面只读安全五件(web_search/todo_write/job_list/job_output/skill——skill 加载的是\r\n * 指令文本,本身只读,用户决策默认可用)。\r\n * 编排类(ralph/workflow)、写文件类(write/edit)、job_kill、ask_user_question、\r\n * goal 三件套、exit_plan_mode 不进只读名单。 */\r\nexport const EXPLORER_READONLY_ALLOW: readonly string[] = [\r\n ...LEGACY_EXPLORER_ALLOW,\r\n 'web_search', 'todo_write', 'job_list', 'job_output', 'skill',\r\n]\r\n\r\n/** general 默认白名单(20 个):agent-team preset standing 面全量(2026-09-08 实测枚举),\r\n * 不含 team_delegate(禁二级委派)与 run_code(宿主 Code Mode 保留名,restrict 拒收)。\r\n * 静态名单:preset 面日后新增工具不自动进入,需人工再梳理(见 spec 非目标)。 */\r\nexport const GENERAL_ALLOW: readonly string[] = [\r\n SHELL_NAME, 'read', 'write', 'edit', 'read_image', 'glob', 'grep',\r\n 'todo_write', 'web_search', 'ask_user_question', 'skill', 'exit_plan_mode',\r\n 'job_list', 'job_output', 'job_kill', 'create_goal', 'get_goal', 'update_goal',\r\n 'ralph', 'workflow',\r\n]\r\n\r\nexport const BUILTIN_AGENTS: readonly AgentRecord[] = [\r\n {\r\n id: 'main',\r\n name: '主 Agent',\r\n builtin: true,\r\n },\r\n {\r\n id: 'explorer',\r\n name: 'Explorer',\r\n description: '快速只读代码库探索:定位文件/符号、回答结构与调用关系问题,不做任何修改',\r\n persona: `你是代码库探索员。快速定位与任务相关的文件与符号,回答关于代码结构、\r\n调用关系、实现位置的问题。你只读不写:不修改任何文件、不运行有副作用的命令。\r\n输出结论清单,每条附文件路径与行号;信息不足时说明缺口,不要猜测。`,\r\n builtin: true,\r\n tools: { allow: [...EXPLORER_READONLY_ALLOW] },\r\n },\r\n {\r\n id: 'general',\r\n name: 'General',\r\n description: '通用多步骤任务执行:可读可写、可运行命令,完成实现/修复类任务',\r\n persona: `你是通用执行员。按任务书独立完成多步骤工作,可以读写文件、运行命令。\r\n动手前先阅读相关 AGENTS.md 并遵循项目约定;完成后运行与改动相关的检查\r\n(测试/类型检查)验证改动,并在最终输出中报告验证结果。`,\r\n builtin: true,\r\n tools: { allow: [...GENERAL_ALLOW] },\r\n },\r\n]\r\n","/** 首启导入:把旧 agent-team 角色名册 $DSH_HOME/agent-team/roles/*.yml 一次性并入注册表。 */\r\nimport { readdir, readFile } from 'node:fs/promises'\r\nimport { join } from 'node:path'\r\nimport { z } from 'zod'\r\nimport yaml from 'js-yaml'\r\nimport { resolveDshHome } from '@deepseek-ai/dsh-home-paths'\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport type { AgentRecord } from './store.ts'\r\nimport { AGENT_ID_RE } from './store.ts'\r\n\r\n/** 导入一次性标记在 meta 表中的键。 */\r\nexport const ROLES_YAML_IMPORTED_KEY = 'roles_yaml_imported'\r\n\r\nexport interface ImportRolesContext {\r\n agents: KvTable<string, AgentRecord>\r\n meta: KvTable<string, { value: string }>\r\n warn: (msg: string) => void\r\n}\r\n\r\nexport interface ImportResult {\r\n /** 成功导入(覆盖/新增)的条数。 */\r\n imported: number\r\n /** 解析失败被跳过的文件名列表。 */\r\n skipped: string[]\r\n}\r\n\r\nconst RoleYamlSchema = z.object({\r\n name: z.string().optional(),\r\n description: z.string().min(1),\r\n persona: z.string().min(1),\r\n provider: z.string().optional(),\r\n model: z.string().optional(),\r\n tools: z.object({\r\n allow: z.array(z.string()).optional(),\r\n }).optional(),\r\n})\r\n\r\n/**\r\n * 解析校验单个角色 YAML 文件并转成 AgentRecord。\r\n * @param text - 文件内容。\r\n * @param source - 用于错误信息的来源名(通常是文件路径)。\r\n * @param fileName - 文件名(去 .yml),name 省略时的取值;显式 name 须与它一致。\r\n * @throws YAML 语法错误、结构非法、name 与文件名不一致、id 非法、tools 空。\r\n */\r\nexport function parseRoleYaml(text: string, source: string, fileName: string): AgentRecord {\r\n let parsed: unknown\r\n try {\r\n parsed = yaml.load(text)\r\n } catch (error) {\r\n throw new Error(`dsh-agent-toolkit: 角色文件 ${source} 不是合法 YAML:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n const hasTools = parsed !== null && typeof parsed === 'object' && 'tools' in (parsed as object)\r\n let raw: z.infer<typeof RoleYamlSchema>\r\n try {\r\n raw = RoleYamlSchema.parse(parsed)\r\n } catch (error) {\r\n throw new Error(`dsh-agent-toolkit: 角色文件 ${source} 校验失败:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n const id = raw.name ?? fileName\r\n if (raw.name !== undefined && raw.name !== fileName) {\r\n throw new Error(`dsh-agent-toolkit: 角色文件 ${source} 的 name \"${raw.name}\" 与文件名 \"${fileName}\" 不一致(省略 name 即取文件名)`)\r\n }\r\n if (!AGENT_ID_RE.test(id)) {\r\n throw new Error(`dsh-agent-toolkit: 角色 id \"${id}\" 非法(${source}):只允许小写字母、数字、-,且以小写字母开头`)\r\n }\r\n if (hasTools && raw.tools !== undefined && (raw.tools.allow?.length ?? 0) === 0) {\r\n throw new Error(`dsh-agent-toolkit: 角色文件 ${source} 的 tools 为空:allow 至少配一个(不需要限制请整段省略 tools)`)\r\n }\r\n const model = raw.provider !== undefined && raw.model !== undefined ? { provider: raw.provider, model: raw.model } : undefined\r\n const tools = hasTools && raw.tools !== undefined && raw.tools.allow !== undefined && raw.tools.allow.length > 0\r\n ? { allow: raw.tools.allow }\r\n : undefined\r\n return {\r\n id,\r\n name: id,\r\n description: raw.description,\r\n persona: raw.persona,\r\n ...(model !== undefined ? { model } : {}),\r\n ...(tools !== undefined ? { tools } : {}),\r\n }\r\n}\r\n\r\n/** 一个角色 YAML 文件引用:完整文件名 + 完整路径 + 去 .yml 的文件名(name 缺省取值)。 */\r\ninterface RoleFileRef {\r\n name: string\r\n path: string\r\n fileName: string\r\n}\r\n\r\n/**\r\n * 枚举 roles 目录下全部 .yml 角色文件,按文件名字典序返回。\r\n * 共享骨架(readdir/ENOENT/过滤/排序/文件名推导)——YAML 文件命名约定只在这里维护。\r\n * @param dir - roles 目录绝对路径。\r\n * @returns 文件引用列表;目录不存在或无 .yml 文件时返回空列表(静默跳过,属正常态)。\r\n * @throws 目录存在但不可读(非 ENOENT)。读取/解析的严格与宽容由调用方自行处理。\r\n */\r\nasync function enumerateRoleFiles(dir: string): Promise<RoleFileRef[]> {\r\n let entries: string[]\r\n try {\r\n entries = await readdir(dir)\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return []\r\n throw new Error(`dsh-agent-toolkit: 角色目录不可读:${dir}(${error instanceof Error ? error.message : String(error)})`)\r\n }\r\n return entries\r\n .filter(f => f.endsWith('.yml'))\r\n .sort()\r\n .map(file => ({ name: file, path: join(dir, file), fileName: file.slice(0, -'.yml'.length) }))\r\n}\r\n\r\n/**\r\n * 读取 roles 目录下全部 .yml 角色文件,按文件名字典序返回(严格模式:任一文件非法即抛错)。\r\n * @param dir - roles 目录绝对路径。\r\n * @returns 角色记录列表;目录不存在或无 .yml 文件时返回空列表(静默跳过,属正常态)。\r\n * @throws 目录存在但不可读(非 ENOENT)、任一文件不可读/非法。\r\n */\r\nexport async function loadRolesDir(dir: string): Promise<AgentRecord[]> {\r\n const refs = await enumerateRoleFiles(dir)\r\n const records: AgentRecord[] = []\r\n for (const ref of refs) {\r\n let text: string\r\n try {\r\n text = await readFile(ref.path, 'utf8')\r\n } catch (error) {\r\n throw new Error(`dsh-agent-toolkit: 角色文件不可读:${ref.path}(${error instanceof Error ? error.message : String(error)})`)\r\n }\r\n records.push(parseRoleYaml(text, ref.path, ref.fileName))\r\n }\r\n return records\r\n}\r\n\r\n/**\r\n * 首启一次性导入:meta 表 roles_yaml_imported 标记短路;逐文件解析失败 warn 跳过(不阻塞激活);\r\n * 同名 YAML 覆盖内置保底记录。\r\n * @param ctx - agents/meta 表句柄与 warn 通道。\r\n * @param rolesDir - roles 目录;缺省为 $DSH_HOME/agent-team/roles。\r\n */\r\nexport async function importRolesYaml(ctx: ImportRolesContext, rolesDir?: string): Promise<ImportResult> {\r\n const result: ImportResult = { imported: 0, skipped: [] }\r\n if (ctx.meta.get(ROLES_YAML_IMPORTED_KEY) !== undefined) return result\r\n const dir = rolesDir ?? join(resolveDshHome(), 'agent-team', 'roles')\r\n let refs: RoleFileRef[]\r\n try {\r\n refs = await enumerateRoleFiles(dir)\r\n } catch (error) {\r\n // 目录不可读(非 ENOENT):warn 后标记完成,不阻塞激活。\r\n ctx.warn(error instanceof Error ? error.message : String(error))\r\n await markImported(ctx)\r\n return result\r\n }\r\n for (const ref of refs) {\r\n try {\r\n const text = await readFile(ref.path, 'utf8')\r\n const record = parseRoleYaml(text, ref.path, ref.fileName)\r\n await ctx.agents.put(record.id, record)\r\n result.imported++\r\n } catch (error) {\r\n result.skipped.push(ref.name)\r\n ctx.warn(`dsh-agent-toolkit: 角色文件 ${ref.path} 导入失败,已跳过:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n }\r\n await markImported(ctx)\r\n return result\r\n}\r\n\r\nasync function markImported(ctx: ImportRolesContext): Promise<void> {\r\n await ctx.meta.put(ROLES_YAML_IMPORTED_KEY, { value: '1' })\r\n}\r\n","/** Agent 注册表:内存缓存 + 持久化回写 + 订阅通知;main 置顶、内置保底不可删。 */\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport { AgentRecordSchema, migrateAgentRecord, type AgentRecord } from './store.ts'\r\nimport { BUILTIN_AGENTS, EXPLORER_READONLY_ALLOW, GENERAL_ALLOW, LEGACY_EXPLORER_ALLOW } from './builtin.ts'\r\nimport { importRolesYaml } from './import-yaml.ts'\r\nimport { NATIVE_TOOL_NAMES } from '../channels/basic-tools.ts'\r\n\r\nexport interface AgentRegistry {\r\n /** main 置顶,其余按 id 字典序。 */\r\n list(): AgentRecord[]\r\n get(id: string): AgentRecord | undefined\r\n /** main 的 name/builtin 不可改;builtin 可改配置不可删。 */\r\n upsert(record: AgentRecord): Promise<void>\r\n /** main 与 builtin 抛错。 */\r\n remove(id: string): Promise<void>\r\n /** UI/委派提示段热更新用;返回退订函数。 */\r\n subscribe(listener: () => void): () => void\r\n}\r\n\r\n/** tools.allow 一次性并入原生工具名的 meta 表标记键。 */\r\nexport const TOOLS_NATIVE_MIGRATED_KEY = 'tools_native_migrated'\r\n\r\n/** explorer 只读白名单一次性并入的 meta 表标记键。 */\r\nexport const EXPLORER_READONLY_MIGRATED_KEY = 'explorer_readonly_migrated'\r\n\r\n/** tools.allow 一次性并入「preset 面 − 原生常量」差集的 meta 表标记键。 */\r\nexport const TOOLS_PRESET_MIGRATED_KEY = 'tools_preset_catalog_migrated'\r\n\r\n/** 内置角色工具名单重选(explorer 5→10 / general 无→20)一次性迁移的 meta 表标记键。 */\r\nexport const BUILTIN_TOOLS_RECATALOG_MIGRATED_KEY = 'builtin_tools_recatalog_migrated'\r\n\r\n/**\r\n * 打开 dsh_agent_toolkit 域 → 首启 YAML 导入 → 旧记录迁移(promptLayers/原生并入/preset 差集并入/explorer 只读/内置名单重选)→\r\n * 缺 main/explorer/general 时种入内置 → 构建内存缓存。域由 apply 统一 open(storage-domain 同名单开),此处只消费表句柄。\r\n */\r\nexport async function createRegistry(\r\n warn: (msg: string) => void,\r\n tables: { agents: KvTable<string, AgentRecord>; meta: KvTable<string, { value: string }> },\r\n /** 动态 preset 工具面(tool-catalog.ts);缺席 = 跳过 preset 并入迁移(不置标记)。 */\r\n listPresetTools?: () => Promise<string[]>,\r\n): Promise<AgentRegistry> {\r\n const { agents, meta } = tables\r\n\r\n await importRolesYaml({ agents, meta, warn })\r\n\r\n // 旧记录迁移:promptLayers → persona(逐条幂等);tools.allow 一次性并入原生工具名\r\n // (meta 标记幂等——UI 从未提供原生工具勾选项,存量白名单缺原生名非用户本意;\r\n // 标记置位后用户再编辑 allow 不会被回收改)。\r\n const nativeMigrated = meta.get(TOOLS_NATIVE_MIGRATED_KEY) !== undefined\r\n for (const [id, record] of agents.entries()) {\r\n let next = migrateAgentRecord(record)\r\n if (!nativeMigrated && next.tools !== undefined) {\r\n const allow = next.tools.allow\r\n const missing = NATIVE_TOOL_NAMES.filter((name) => !allow.includes(name))\r\n if (missing.length > 0) next = { ...next, tools: { allow: [...allow, ...missing] } }\r\n }\r\n if (next !== record) await agents.put(id, next)\r\n }\r\n if (!nativeMigrated) await meta.put(TOOLS_NATIVE_MIGRATED_KEY, { value: '1' })\r\n\r\n // preset 并入:UI 从未提供 preset 工具名,存量自定义白名单缺它们非用户本意。\r\n // 并入集 = preset 面 − NATIVE_TOOL_NAMES(native 名一直在 UI 可勾,用户不勾是有意排除,\r\n // 不回收改);builtin 记录跳过(explorer 只读白名单是插件设计,不 widen)。\r\n // 枚举失败/服务缺席:跳过且不置标记,下次启动重试。\r\n if (meta.get(TOOLS_PRESET_MIGRATED_KEY) === undefined && listPresetTools !== undefined) {\r\n let extra: string[] | undefined\r\n try {\r\n const surface = await listPresetTools()\r\n extra = surface.filter((n) => !NATIVE_TOOL_NAMES.includes(n))\r\n } catch {\r\n extra = undefined\r\n }\r\n // 空差集(= 回退常量减常量,如 agentPresets 缺席/枚举失败回退后差集为空)不置标记:\r\n // 置上会永久跳过重试;下次启动重试为空差集是无害幂等 no-op。\r\n if (extra !== undefined && extra.length > 0) {\r\n for (const [id, record] of agents.entries()) {\r\n if (record.builtin === true || record.tools === undefined) continue\r\n const missing = extra.filter((n) => !record.tools!.allow.includes(n))\r\n if (missing.length > 0) await agents.put(id, { ...record, tools: { allow: [...record.tools!.allow, ...missing] } })\r\n }\r\n await meta.put(TOOLS_PRESET_MIGRATED_KEY, { value: '1' })\r\n }\r\n }\r\n\r\n // explorer 只读白名单一次性迁移:deny 语义取消后 explorer 失去硬约束,此处补派生白名单恢复。\r\n // 先于 seedBuiltins 执行:新装环境的 explorer 由种入直接携带白名单,不经过本迁移与原生并入。\r\n const explorerMigrated = meta.get(EXPLORER_READONLY_MIGRATED_KEY) !== undefined\r\n if (!explorerMigrated) {\r\n const explorer = agents.get('explorer')\r\n if (explorer !== undefined && explorer.tools === undefined) {\r\n await agents.put('explorer', { ...explorer, tools: { allow: [...EXPLORER_READONLY_ALLOW] } })\r\n }\r\n await meta.put(EXPLORER_READONLY_MIGRATED_KEY, { value: '1' })\r\n }\r\n\r\n // 内置名单重选一次性迁移(2026-09-08):explorer 旧默认 → 新 10 个;general 无 tools\r\n // → preset 面全量 20 个。条件式:仅更新仍是旧默认值的 builtin 记录(用户面板改过的 =\r\n // 自定义,跳过)。explorer 旧默认有两种形状:纯净 5 个(seed/只读迁移写入的 LEGACY 派生\r\n // 顺序)与原生并入加写后的 7 个([...LEGACY, write, edit]——0.2.x 时代 native 合并不\r\n // 跳过 builtin 记录,真实存量多为此形状);7 个形状替换后 write/edit 随之移除,只读\r\n // 约束随新名单恢复。同 id 非 builtin 记录是用户数据,不动。无外部依赖,跑完即置标记。\r\n if (meta.get(BUILTIN_TOOLS_RECATALOG_MIGRATED_KEY) === undefined) {\r\n const explorer = agents.get('explorer')\r\n const legacyShapes: readonly (readonly string[])[] = [LEGACY_EXPLORER_ALLOW, [...LEGACY_EXPLORER_ALLOW, 'write', 'edit']]\r\n if (explorer?.builtin === true && explorer.tools !== undefined\r\n && legacyShapes.some((shape) => explorer.tools!.allow.length === shape.length\r\n && explorer.tools!.allow.every((n, i) => n === shape[i]))) {\r\n await agents.put('explorer', { ...explorer, tools: { allow: [...EXPLORER_READONLY_ALLOW] } })\r\n }\r\n const general = agents.get('general')\r\n if (general?.builtin === true && general.tools === undefined) {\r\n await agents.put('general', { ...general, tools: { allow: [...GENERAL_ALLOW] } })\r\n }\r\n await meta.put(BUILTIN_TOOLS_RECATALOG_MIGRATED_KEY, { value: '1' })\r\n }\r\n\r\n await seedBuiltins(agents)\r\n\r\n const cache = new Map<string, AgentRecord>()\r\n for (const [id, record] of agents.entries()) cache.set(id, record)\r\n\r\n const listeners = new Set<() => void>()\r\n const notify = () => {\r\n for (const listener of [...listeners]) listener()\r\n }\r\n\r\n return {\r\n list(): AgentRecord[] {\r\n const main = cache.get('main')\r\n const rest = [...cache.entries()]\r\n .filter(([id]) => id !== 'main')\r\n .map(([, record]) => record)\r\n .sort((a, b) => a.id.localeCompare(b.id))\r\n return main === undefined ? rest : [main, ...rest]\r\n },\r\n get(id: string): AgentRecord | undefined {\r\n return cache.get(id)\r\n },\r\n async upsert(record: AgentRecord): Promise<void> {\r\n const parsed = AgentRecordSchema.safeParse(record)\r\n if (!parsed.success) {\r\n throw new Error(`dsh-agent-toolkit: Agent 记录校验失败:${parsed.error.message}`)\r\n }\r\n const normalized = migrateAgentRecord(parsed.data)\r\n const existing = cache.get(record.id)\r\n if (record.id === 'main' && existing !== undefined) {\r\n if (existing.name !== record.name || existing.builtin !== record.builtin) {\r\n throw new Error('dsh-agent-toolkit: 主 Agent(main)的 name/builtin 字段不可修改')\r\n }\r\n }\r\n if (existing?.builtin === true && record.builtin !== true) {\r\n throw new Error(`dsh-agent-toolkit: 内置角色 ${record.id} 的 builtin 标记不可修改`)\r\n }\r\n await agents.put(record.id, normalized)\r\n cache.set(record.id, normalized)\r\n notify()\r\n },\r\n async remove(id: string): Promise<void> {\r\n if (id === 'main') throw new Error('dsh-agent-toolkit: 主 Agent(main)不可删除')\r\n const existing = cache.get(id)\r\n if (existing?.builtin === true) {\r\n throw new Error(`dsh-agent-toolkit: 内置角色 ${id} 不可删除`)\r\n }\r\n const deleted = await agents.delete(id)\r\n if (deleted) {\r\n cache.delete(id)\r\n notify()\r\n }\r\n },\r\n subscribe(listener: () => void): () => void {\r\n listeners.add(listener)\r\n return () => { listeners.delete(listener) }\r\n },\r\n }\r\n}\r\n\r\nasync function seedBuiltins(agents: KvTable<string, AgentRecord>): Promise<void> {\r\n for (const builtin of BUILTIN_AGENTS) {\r\n if (agents.get(builtin.id) === undefined) {\r\n await agents.put(builtin.id, builtin)\r\n }\r\n }\r\n}\r\n","/** 动态工具名册:团队 preset 面经宿主 standing mount 枚举(standingKeyFor + scoped schemas),\r\n * agentPresets 缺席/枚举失败回退 NATIVE_TOOL_NAMES 常量。每次调用现算,不缓存——standing\r\n * mount 由宿主按 composition 文件代际缓存,view 遍历是纯内存操作。\r\n * 设计:docs/superpowers/specs/archive/2026-09-07-dynamic-tool-catalog-design.md */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { RUN_CODE_NAME } from '@deepseek-ai/dsh-tools'\r\nimport type { ScopeKey } from '@deepseek-ai/dsh-scope'\r\n// type-only 激活 dsh-tools 对 cordis Context 的声明合并(ctx.tools)。\r\nimport type {} from '@deepseek-ai/dsh-tools'\r\nimport { NATIVE_TOOL_NAMES } from '../channels/basic-tools.ts'\r\n\r\n/** agentPresets 服务的结构类型(可选服务经 ctx.get 读取,team-preset.ts AgentPresetsLike 先例)。*/\r\ninterface PresetStandingLike {\r\n standingKeyFor(id?: string): Promise<ScopeKey>\r\n}\r\n\r\n/** Agents 面板/迁移/创建命令共用的工具名册。*/\r\nexport interface ToolCatalog {\r\n /** 团队 preset 工具面(不含 global 名与 run_code 保留名,字典序)。*/\r\n listPresetTools(): Promise<string[]>\r\n /** 顶层注册表全局工具名(不含 run_code 保留名)。*/\r\n listGlobalTools(): string[]\r\n}\r\n\r\nexport function createToolCatalog(ctx: Context, presetId: string): ToolCatalog {\r\n return {\r\n async listPresetTools() {\r\n // 惰性解析(attachments 教训:apply 期一次性捕获会吃到未注册的 undefined)。\r\n const presets = ctx.get('agentPresets', false) as PresetStandingLike | undefined\r\n if (presets === undefined) return [...NATIVE_TOOL_NAMES]\r\n try {\r\n const key = await presets.standingKeyFor(presetId)\r\n const global = new Set(ctx.tools.schemas().map((s) => s.name))\r\n return ctx.tools.schemas(key).map((s) => s.name)\r\n .filter((n) => !global.has(n) && n !== RUN_CODE_NAME)\r\n .sort()\r\n } catch (error) {\r\n ctx.logger.warn(\r\n `dsh-agent-toolkit: 枚举 preset \"${presetId}\" 工具面失败,回退内置常量:${error instanceof Error ? error.message : String(error)}`,\r\n )\r\n return [...NATIVE_TOOL_NAMES]\r\n }\r\n },\r\n listGlobalTools() {\r\n return ctx.tools.schemas().map((s) => s.name).filter((n) => n !== RUN_CODE_NAME)\r\n },\r\n }\r\n}\r\n","/** shared storage 助手:安全打开存储域(open 失败挂 rejection handler)并在卸载时关闭。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { Domain, DomainSpec } from '@deepseek-ai/dsh-storage-domain'\r\n\r\n/** 类型擦除后的存储域句柄(跨 spec 泛型的统一承载面)。 */\r\nexport type DomainHandle = Domain<DomainSpec>\r\n\r\nexport function openDomainSafely(\r\n ctx: Context,\r\n domain: DomainSpec,\r\n warn: (msg: string) => void,\r\n beforeClose?: () => void | Promise<void>,\r\n): Promise<DomainHandle> {\r\n const ready = ctx.storageDomain.open(domain)\r\n // open 失败(version-mismatch/malformed-medium/invalid-record)时创建即挂\r\n // rejection handler:避免 unhandled rejection 崩掉宿主进程(Node 默认 throw)。\r\n // ready 仍保持 reject,调用方仍感知失败而不次生崩溃。\r\n ready.catch((error) => {\r\n warn(error instanceof Error ? error.message : String(error))\r\n })\r\n // 域句柄由本 fiber 持有:卸载时 close(消费方自己不关闭)。open 失败时\r\n // close 无从谈起,吞掉该 rejection,避免卸载路径次生崩溃。\r\n ctx.effect(() => async () => {\r\n // beforeClose 在 close 前排空消费方自己的写链(如 usage 的 tail):close 一旦\r\n // 开始(disposing=true)就拒绝新入队的写,未落队的采集会被静默丢弃。drain\r\n // 失败不阻断 close——卸载路径不因 drain 异常次生崩溃。\r\n await Promise.resolve(beforeClose?.()).catch(() => undefined)\r\n await ready.then((domain) => domain.close()).catch(() => undefined)\r\n })\r\n return ready\r\n}\r\n","// 默认文本改写自 opencode(MIT 许可,https://github.com/anomalyco/opencode,\r\n// packages/opencode/src/session/prompt/*.txt @ dev 分支):剔除 opencode 专有内容\r\n// (身份自述、具体工具名、/help /bug ctrl+p、issues URL、opencode.ai),保留模型族\r\n// 行为指导。身份首句刻意不写——dsh 原生 `harness:identity` 段(order -100)已覆盖身份。\r\nimport type { LayerConfig, Rule } from './types.ts'\r\n\r\n/** 通用基座层文本(default.txt 改写版)。 */\r\nexport const BASE_TEXT = `IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming. You may use URLs provided by the user in their messages or local files.\r\n\r\n# Tone and style\r\nYou should be concise, direct, and to the point. When you run a non-trivial shell command, explain what the command does and why you are running it, so the user understands what you are doing (this is especially important when the command changes the user's system).\r\nYour output will be displayed on a command line interface. You can use GitHub-flavored markdown for formatting; it will be rendered in a monospace font using the CommonMark specification.\r\nOutput text to communicate with the user; all text you output outside of tool use is displayed to the user. Only use tools to complete tasks. Never use tools or code comments as a means to communicate with the user during the session.\r\nIf you cannot or will not help the user with something, do not preach about why or what it could lead to. Offer helpful alternatives if possible, and otherwise keep your response to 1-2 sentences.\r\nOnly use emojis if the user explicitly requests it. Avoid using emojis in all communication unless asked.\r\nIMPORTANT: Minimize output tokens as much as possible while maintaining helpfulness, quality, and accuracy. Only address the specific query or task at hand, avoiding tangential information unless absolutely critical. If you can answer in 1-3 sentences or a short paragraph, please do.\r\nIMPORTANT: Do not answer with unnecessary preamble or postamble (such as explaining your code or summarizing your actions) unless the user asks you to.\r\nKeep responses short: answer the user's question directly, without elaboration. Avoid introductions, conclusions, and restatements such as \"The answer is ...\" or \"Here is what I will do next ...\".\r\n<example>\r\nuser: what is 2+2?\r\nassistant: 4\r\n</example>\r\n\r\n<example>\r\nuser: what files are in the directory src/?\r\nassistant: [lists files and sees foo.c, bar.c, baz.c]\r\nuser: which file contains the implementation of foo?\r\nassistant: src/foo.c\r\n</example>\r\n\r\n# Proactiveness\r\nBe proactive only when the user asks you to do something. Strike a balance between:\r\n1. Doing the right thing when asked, including follow-up actions the request implies.\r\n2. Not surprising the user with actions taken without asking.\r\nIf the user asks how to approach something, answer the question first instead of immediately jumping into action.\r\nDo not add a code-explanation summary unless requested. After working on a file, just stop.\r\n\r\n# Following conventions\r\nWhen making changes to files, first understand the file's code conventions. Mimic code style, use existing libraries and utilities, and follow existing patterns.\r\n- NEVER assume that a given library is available, even if it is well known. Whenever you write code that uses a library or framework, first check that this codebase already uses it (neighboring files, package manifests such as package.json or cargo.toml).\r\n- When you create a new component, first look at existing components: framework choice, naming conventions, typing, and other conventions.\r\n- When you edit a piece of code, read its surrounding context (especially its imports) and make the change idiomatic to it.\r\n- Always follow security best practices. Never introduce code that exposes or logs secrets and keys. Never commit secrets or keys to the repository.\r\n\r\n# Code style\r\n- IMPORTANT: DO NOT ADD ***ANY*** COMMENTS unless asked.\r\n\r\n# Doing tasks\r\nFor software engineering tasks (fixing bugs, adding features, refactoring, explaining code, and more):\r\n- Use the available search tools extensively, in parallel and sequentially, to understand the codebase and the user's query.\r\n- Implement the solution using all tools available to you.\r\n- Verify the solution with tests where possible. NEVER assume a specific test framework or test script; check the README or search the codebase to determine the testing approach.\r\n- When you have completed a task, run the project's lint and typecheck commands if they exist. If you cannot find the correct command, ask the user for it.\r\n- NEVER commit changes unless the user explicitly asks you to.\r\n\r\nTool results and user messages may include <system-reminder> tags. They contain useful information and reminders. They are NOT part of the user's provided input or the tool result.\r\n\r\n# Tool usage policy\r\n- For file or content search, prefer dedicated search tools over shell commands to reduce context usage.\r\n- You can call multiple tools in a single response. Batch independent calls together for optimal performance; run dependent calls sequentially.\r\n\r\nBefore you begin work, think about what the code you are editing is supposed to do, based on filenames and directory structure.\r\n\r\n# Code references\r\nWhen referencing specific functions or pieces of code, use the pattern \\`file_path:line_number\\` so the user can easily navigate to the source location.`\r\n\r\n/** 模型族行为指导文本(anthropic/gemini/beast/codex/gpt/kimi 改写版,\r\n * 内容按下文\"6 个模型族 TEXT 的改写契约\"逐条产出,英文,不写身份首句)。 */\r\nexport const ANTHROPIC_TEXT = `IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming. You may use URLs provided by the user in their messages or local files.\r\n\r\n# Tone and style\r\n- Only use emojis if the user explicitly requests it. Avoid using emojis in all communication unless asked.\r\n- Your output will be displayed on a command line interface. Your responses should be short and concise. You can use GitHub-flavored markdown for formatting, and it will be rendered in a monospace font using the CommonMark specification.\r\n- Output text to communicate with the user; all text you output outside of tool use is displayed to the user. Only use tools to complete tasks. Never use shell commands or code comments as a means to communicate with the user during the session.\r\n- NEVER create files unless they are absolutely necessary for achieving your goal. ALWAYS prefer editing an existing file to creating a new one.\r\n\r\n# Professional objectivity\r\nPrioritize technical accuracy and truthfulness over validating the user's beliefs. Focus on facts and problem-solving, providing direct, objective technical information without unnecessary superlatives, praise, or emotional validation. Apply the same rigorous standards to all ideas and disagree when necessary, even if it may not be what the user wants to hear. Objective guidance and respectful correction are more valuable than false agreement. Whenever there is uncertainty, investigate to find the truth first rather than instinctively confirming the user's beliefs.\r\n\r\n# Planning and tracking\r\nUse a task list frequently to plan and track your work, giving the user visibility into your progress. These lists are also helpful for breaking down larger, complex tasks into smaller steps. Mark each task as completed as soon as you are done; do not batch up multiple tasks before marking them completed.\r\n\r\n# Doing tasks\r\nThe user will primarily request software engineering tasks: fixing bugs, adding new functionality, refactoring code, explaining code, and more. Search the codebase to understand the user's query, implement the solution using all tools available to you, then verify it. Tool results and user messages may include <system-reminder> tags. They contain useful information and reminders; they are authoritative and are NOT part of the user's provided input or the tool result.\r\n\r\n# Tool usage policy\r\n- For file or content search, prefer dedicated search tools over shell commands to reduce context usage.\r\n- Prefer dedicated editing tools over shell for modifying files.\r\n- You can call multiple tools in a single response. Make all independent tool calls in parallel; run dependent calls sequentially. Never use placeholders or guess missing parameters in tool calls.\r\n\r\n# Code references\r\nWhen referencing specific functions or pieces of code, use the pattern \\`file_path:line_number\\` so the user can easily navigate to the source location.`\r\n\r\nexport const GEMINI_TEXT = `# Core Mandates\r\n\r\n- **Conventions:** Rigorously adhere to existing project conventions when reading or modifying code. Analyze surrounding code, tests, and configuration first.\r\n- **Libraries/Frameworks:** NEVER assume a library or framework is available or appropriate. Verify its established usage within the project (check imports and configuration files, or observe neighboring files) before employing it.\r\n- **Style & Structure:** Mimic the style (formatting, naming), structure, framework choices, typing, and architectural patterns of existing code in the project.\r\n- **Idiomatic Changes:** When editing, understand the local context (imports, functions, classes) to ensure your changes integrate naturally and idiomatically.\r\n- **Comments:** Add code comments sparingly. Focus on *why* something is done, especially for complex logic, rather than *what* is done. Only add high-value comments if necessary for clarity or if requested by the user. Do not edit comments that are separate from the code you are changing. *NEVER* talk to the user or describe your changes through comments.\r\n- **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions.\r\n- **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first; do not just do it.\r\n- **Explaining Changes:** After completing a code modification or file operation, do not provide summaries unless asked.\r\n- **Path Construction:** Before using any file system tool, construct the full absolute path for the file argument. Always combine the absolute path of the project root with the file's path relative to the root. If the user provides a relative path, resolve it against the root to create an absolute path.\r\n- **Do Not Revert Changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they resulted in an error or if the user has explicitly asked you to revert them.\r\n\r\n# Primary Workflows\r\n\r\n## Software Engineering Tasks\r\nWhen requested to fix bugs, add features, refactor, or explain code, follow this sequence:\r\n1. **Understand:** Think about the request and the relevant codebase context. Search extensively (in parallel if independent) to understand file structures, existing patterns, and conventions. Read to validate any assumptions.\r\n2. **Plan:** Build a coherent, grounded plan for how you intend to resolve the task. Share an extremely concise yet clear plan with the user if it would help. Use a self-verification loop by writing unit tests where relevant; use output logs or debug statements as part of this loop to arrive at a solution.\r\n3. **Implement:** Act on the plan using available tools, strictly adhering to the project's established conventions.\r\n4. **Verify (Tests):** If applicable and feasible, verify the changes using the project's testing procedures. Identify the correct test commands and frameworks by examining README files and build or package configuration; NEVER assume standard test commands.\r\n5. **Verify (Standards):** After making code changes, execute the project-specific build, lint, and type-checking commands you have identified. If unsure about these commands, ask the user.\r\n\r\n## New Applications\r\nAutonomously implement and deliver a visually appealing, substantially complete, functional prototype:\r\n1. **Understand Requirements:** Analyze the request to identify core features, desired user experience, visual aesthetic, application type and platform, and explicit constraints. If critical information for planning is missing or ambiguous, ask concise, targeted clarification questions.\r\n2. **Propose Plan:** Formulate an internal development plan and present a clear, concise summary covering the application's type and core purpose, key technologies, main features, interaction model, and the approach to a polished visual design and user experience.\r\n3. **User Approval:** Obtain user approval for the proposed plan before implementing.\r\n4. **Implementation:** Autonomously implement each feature and design element per the approved plan. Use placeholder assets only when essential for progress, intending to replace them with more refined versions or instructing the user on replacement during polishing.\r\n5. **Verify:** Review work against the original request and approved plan. Fix bugs, deviations, and placeholders where feasible. Build the application and ensure there are no compile errors.\r\n6. **Solicit Feedback:** Provide instructions on how to start the application and request user feedback.\r\n\r\n# Operational Guidelines\r\n\r\n## Tone and Style (CLI Interaction)\r\n- **Concise & Direct:** Adopt a professional, direct, and concise tone suitable for a CLI environment.\r\n- **Minimal Output:** Aim for fewer than 3 lines of text output (excluding tool use and code generation) per response whenever practical. Focus strictly on the user's query.\r\n- **Clarity over Brevity (When Needed):** While conciseness is key, prioritize clarity for essential explanations or when seeking necessary clarification.\r\n- **No Chitchat:** Avoid conversational filler, preambles, or postambles. Get straight to the action or answer.\r\n- **Formatting:** Use GitHub-flavored Markdown. Responses will be rendered in monospace.\r\n- **Tools vs. Text:** Use tools for actions; text output only for communication. Do not add explanatory comments within tool calls or code blocks unless specifically part of the required code.\r\n- **Handling Inability:** If unable or unwilling to fulfill a request, state so briefly (1-2 sentences) without excessive justification. Offer alternatives if appropriate.\r\n\r\n## Security and Safety Rules\r\n- **Explain Critical Commands:** Before executing commands that modify the file system, codebase, or system state, provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety.\r\n- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.\r\n\r\n## Tool Usage\r\n- **File Paths:** Always use absolute paths when referring to files with file tools. Relative paths are not supported; you must provide an absolute path.\r\n- **Parallelism:** Execute multiple independent tool calls in parallel when feasible.\r\n- **Command Execution:** Run shell commands for actual system commands and terminal operations, remembering to explain modifying commands first.\r\n- **Respect User Confirmations:** Tool calls will first require confirmation from the user, where they will either approve or cancel. If a user cancels a call, respect their choice and do not try to make the call again; it is okay to request it again only if the user asks on a subsequent prompt.\r\n\r\n# Final Reminder\r\nYour core function is efficient and safe assistance. Balance extreme conciseness with the crucial need for clarity, especially regarding safety and potential system modifications. Always prioritize user control and project conventions. Never make assumptions about the contents of files; instead read to ensure you are not making broad assumptions. Keep going until the user's query is completely resolved.`\r\n\r\nexport const BEAST_TEXT = `Keep going until the user's query is completely resolved, before ending your turn and yielding back to the user.\r\n\r\nYour thinking should be thorough, and it is fine if it is very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\r\n\r\nYou MUST iterate and keep going until the problem is solved. You have everything you need to resolve this problem. Fully solve it autonomously before coming back. Only terminate your turn when you are sure the problem is solved and all items have been checked off. Go through the problem step by step, verify that your changes are correct, and never end your turn without having truly and completely solved the problem. When you say you are going to make a tool call, make sure you ACTUALLY make the tool call instead of ending your turn.\r\n\r\nYour knowledge may be out of date because your training date is in the past. Use available search means to verify your understanding of third-party packages and dependencies is up to date every time you install or implement one. It is not enough to just search; you must also read the content of the pages you find and gather all relevant information until you have everything you need.\r\n\r\nAlways tell the user what you are going to do before making a tool call with a single concise sentence.\r\n\r\nTake your time and think through every step. Check your solution rigorously and watch out for boundary cases, especially with the changes you made. Your solution must be perfect; if not, continue working on it. Test your code rigorously using the tools provided, many times, to catch all edge cases. If it is not robust, iterate more. Failing to test your code rigorously is the number one failure mode; make sure you handle all edge cases and run existing tests if they are provided.\r\n\r\nPlan extensively before each function call, and reflect extensively on the outcomes of the previous calls. Do not do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully. Keep working until the problem is completely solved and all items in the todo list are checked off; do not end your turn until you have completed all steps and verified that everything is working correctly.\r\n\r\n# Workflow\r\n1. Fetch any URLs provided by the user using the search tool.\r\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Break down the problem into manageable parts, considering the expected behavior, edge cases, potential pitfalls, the larger context of the codebase, and the dependencies and interactions with other parts of the code.\r\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\r\n4. Research the problem using available search means by reading relevant articles, documentation, and forums.\r\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps and display the plan as a todo list, checking off each item as you go.\r\n6. Implement the fix incrementally. Make small, testable code changes.\r\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\r\n8. Test frequently. Run tests after each change to verify correctness.\r\n9. Iterate until the root cause is fixed and all tests pass.\r\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\r\n\r\n## Debugging\r\n- Make code changes only if you have high confidence they can solve the problem.\r\n- When debugging, determine the root cause rather than addressing symptoms. Use print statements, logs, or temporary code to inspect program state and test your hypotheses. Revisit your assumptions if unexpected behavior occurs.\r\n- Always read enough context to understand the code before editing; avoid re-reading files whose content has not changed.\r\n\r\n# Communication\r\nCommunicate clearly and concisely in a casual, friendly yet professional tone. Avoid unnecessary explanations, repetition, and filler. Always write code directly to the correct files, and do not display code to the user unless they specifically ask for it.\r\n\r\n# Memory\r\nRemember user preferences expressed across the session and apply them consistently.\r\n\r\n# Git\r\nNever stage and commit files automatically unless the user explicitly tells you to.`\r\n\r\nexport const CODEX_TEXT = `## Editing constraints\r\n- Default to ASCII when editing or creating files. Only introduce non-ASCII or other Unicode characters when there is a clear justification and the file already uses them.\r\n- Only add comments if they are necessary to make a non-obvious block easier to understand.\r\n\r\n## Tool usage\r\n- Prefer dedicated tools over shell for file operations: use an editing tool to modify files, a reading tool to view files, and search tools to find files by name or search file contents.\r\n- Use shell for terminal operations: git, builds, tests, and running scripts.\r\n- Run tool calls in parallel when neither call needs the other's output; otherwise run them sequentially.\r\n\r\n## Git and workspace hygiene\r\n- You may be in a dirty git worktree.\r\n * NEVER revert existing changes you did not make unless explicitly requested, since these changes were made by the user.\r\n * If asked to make a commit or code edits and there are unrelated changes to your work or changes you did not make in those files, do not revert those changes.\r\n * If the changes are in files you have touched recently, read them carefully and understand how you can work with the changes rather than reverting them.\r\n * If the changes are in unrelated files, just ignore them and do not revert them.\r\n- Do not amend commits unless explicitly requested.\r\n- **NEVER** use destructive commands like \\`git reset --hard\\` or \\`git checkout --\\` unless specifically requested or approved by the user.\r\n\r\n## Frontend tasks\r\nWhen doing frontend design tasks, avoid collapsing into bland, generic layouts. Aim for interfaces that feel intentional and deliberate.\r\n- Typography: Use expressive, purposeful fonts and avoid default stacks.\r\n- Color & Look: Choose a clear visual direction; define CSS variables; avoid generic defaults.\r\n- Motion: Use a few meaningful animations (page-load, staggered reveals) instead of generic micro-motions.\r\n- Background: Don't rely on flat, single-color backgrounds; use gradients, shapes, or subtle patterns to build atmosphere.\r\n- Overall: Avoid boilerplate layouts and interchangeable UI patterns. Vary themes, type families, and visual languages across outputs.\r\n- Ensure the page loads properly on both desktop and mobile.\r\nException: If working within an existing website or design system, preserve the established patterns, structure, and visual language.\r\n\r\n## Presenting your work and final message\r\n- Default: be very concise; friendly coding teammate tone.\r\n- Default: do the work without asking questions. Treat short tasks as sufficient direction; infer missing details by reading the codebase and following existing conventions.\r\n- Questions: only ask when you are truly blocked after checking relevant context AND you cannot safely pick a reasonable default. This usually means one of: the request is ambiguous in a way that materially changes the result and you cannot disambiguate by reading the repo; the action is destructive or irreversible, touches production, or changes billing or security posture; you need a secret or credential or value that cannot be inferred.\r\n- If you must ask: do all non-blocked work first, then ask exactly one targeted question, include your recommended default, and state what would change based on the answer.\r\n- Never ask permission questions like \"Should I proceed?\"; proceed with the most reasonable option and mention what you did.\r\n- For substantial work, summarize clearly and follow the final-answer formatting rules.\r\n- Skip heavy formatting for simple confirmations.\r\n- Don't dump large files you have written; reference paths only.\r\n- Offer logical next steps (tests, commits, build) briefly; add verify steps if you could not do something.\r\n- For code changes: lead with a quick explanation of the change, then give more details on the context covering where and why the change was made. If there are natural next steps, suggest them at the end of your response.\r\n\r\n## Final answer structure and style guidelines\r\n- Plain text; the CLI handles styling. Use structure only when it helps scannability.\r\n- Headers: optional; short Title Case (1-3 words); add only if they truly help.\r\n- Bullets: use -; merge related points; keep to one line when possible; keep phrasing consistent.\r\n- Monospace: use inline code for commands, paths, env vars, code ids, and inline examples; never combine with bold.\r\n- Code samples or multi-line snippets should be wrapped in fenced code blocks; include a language tag as often as possible.\r\n- Structure: group related bullets; order sections general to specific.\r\n- Tone: collaborative, concise, factual; present tense, active voice; self-contained.\r\n- Don'ts: no nested bullets or hierarchies; no ANSI codes; don't cram unrelated keywords; avoid naming formatting styles in answers.\r\n- File references: reference files with inline code so paths are clickable; each reference should have a standalone path; optionally include line/column (1-based) using the pattern \\`file_path:line_number\\`.`\r\n\r\nexport const GPT_TEXT = `Be a deeply pragmatic, effective software engineer. Take engineering quality seriously; collaboration comes through as direct, factual statements. Communicate efficiently, keeping the user clearly informed about ongoing actions without unnecessary detail. Build context by examining the codebase first without making assumptions or jumping to conclusions. Think through the nuances of the code you encounter and embody the mentality of a skilled senior software engineer.\r\n\r\n## Editing Approach\r\n\r\n- The best changes are often the smallest correct changes.\r\n- When you are weighing two correct approaches, prefer the more minimal one (less new names, helpers, tests, and so on).\r\n- Keep things in one function unless composable or reusable.\r\n- Do not add backward-compatibility code unless there is a concrete need, such as persisted data, shipped behavior, external consumers, or an explicit user requirement; if unclear, ask one short question instead of guessing.\r\n\r\n## Autonomy and persistence\r\n\r\nUnless the user explicitly asks for a plan, asks a question about the code, is brainstorming potential solutions, or some other intent makes it clear that code should not be written, assume the user wants you to make code changes or run tools to solve the user's problem. In these cases it is bad to output your proposed solution in a message; you should go ahead and actually implement the change. If you encounter challenges or blockers, attempt to resolve them yourself.\r\n\r\nPersist until the task is fully handled end-to-end within the current turn whenever feasible: do not stop at analysis or partial fixes; carry changes through implementation, verification, and a clear explanation of outcomes unless the user explicitly pauses or redirects you.\r\n\r\nIf you notice unexpected changes in the worktree or staging area that you did not make, continue with your task. NEVER revert, undo, or modify changes you did not make unless the user explicitly asks you to. There can be multiple agents or the user working in the same codebase concurrently.\r\n\r\n## Editing constraints\r\n\r\n- Default to ASCII when editing or creating files. Only introduce non-ASCII or other Unicode characters when there is a clear justification and the file already uses them.\r\n- Add succinct code comments that explain what is going on if code is not self-explanatory. Do not add comments like \"assigns the value to the variable\"; a brief comment might be useful ahead of a complex code block. Usage of these comments should be rare.\r\n- Use dedicated tools rather than scripts for reading and writing files when a simple dedicated tool call would suffice.\r\n- You may be in a dirty git worktree.\r\n * NEVER revert existing changes you did not make unless explicitly requested, since these changes were made by the user.\r\n * If asked to make a commit or code edits and there are unrelated changes to your work or changes you did not make in those files, do not revert those changes.\r\n * If the changes are in files you have touched recently, read them carefully and understand how you can work with them rather than reverting them.\r\n * If the changes are in unrelated files, just ignore them and do not revert them.\r\n- Do not amend a commit unless explicitly requested.\r\n- **NEVER** use destructive commands like \\`git reset --hard\\` or \\`git checkout --\\` unless specifically requested or approved by the user.\r\n\r\n## Special user requests\r\n\r\nIf the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command, do so.\r\n\r\nIf the user pastes an error description or a bug report, help them diagnose the root cause. You can try to reproduce it if it seems feasible with the available tools.\r\n\r\nIf the user asks for a \"review\", default to a code review mindset: prioritize identifying bugs, risks, behavioural regressions, and missing tests. Findings must be the primary focus of the response; keep summaries or overviews brief and only after enumerating the issues. Present findings first, ordered by severity with file/line references, followed by open questions or assumptions, and offer a change summary only as a secondary detail. If no findings are discovered, state that explicitly and mention any residual risks or testing gaps.\r\n\r\n## Frontend tasks\r\n\r\nWhen doing frontend design tasks, avoid collapsing into \"AI slop\" or safe, average-looking layouts.\r\n- Ensure the page loads properly on both desktop and mobile.\r\n- Overall: Avoid boilerplate layouts and interchangeable UI patterns. Vary themes, type families, and visual languages across outputs.\r\nException: If working within an existing website or design system, preserve the established patterns, structure, and visual language.\r\n\r\n# Working with the user\r\n\r\n## General\r\n\r\nDo not begin responses with conversational interjections or meta commentary. Avoid openers such as acknowledgements or framing phrases.\r\n\r\nBalance conciseness to not overwhelm the user with appropriate detail for the request. Do not narrate abstractly; explain what you are doing and why.\r\n\r\n## Formatting rules\r\n\r\nYour responses are rendered as GitHub-flavored Markdown.\r\n\r\nNever use nested bullets. Keep lists flat (single level). If you need hierarchy, split into separate lists or sections. For numbered lists, only use the \\`1. 2. 3.\\` style markers (with a period), never \\`1)\\`.\r\n\r\nHeaders are optional, only use them when you think they are necessary. If you do use them, use short Title Case (1-3 words). Don't add a blank line.\r\n\r\nUse inline code blocks for commands, paths, environment variables, function names, inline examples, and keywords.\r\n\r\nCode samples or multi-line snippets should be wrapped in fenced code blocks. Include a language tag when possible.\r\n\r\nDon't use emojis or em dashes unless explicitly instructed.\r\n\r\n## Progress and final responses\r\n\r\nKeep intermediate progress updates short and send them only when they add meaningful new information: a discovery, a tradeoff, a blocker, a substantial plan, or the start of a non-trivial edit or verification step. Do not narrate routine reads, searches, obvious next steps, or minor confirmations. Do not begin responses with conversational interjections or meta commentary. Before substantial work, send a short update describing your first step. Before editing files, send an update describing the edit.\r\n\r\nMatch the final answer to the complexity of the task. Structure it if necessary, ordering sections from general to specific to supporting. If the task is simple, answer with a one-liner. If the user asks for a code explanation, include code references. For simple tasks, just state the outcome without heavy formatting. For large or complex changes, lead with the solution, then explain what you did and why. For casual chat, just chat. If something could not be done (tests, builds, and so on), say so. Suggest next steps only when they are natural and useful; if you list options, use numbered items.`\r\n\r\nexport const KIMI_TEXT = `Your primary goal is to help users with software engineering tasks by taking action: use the tools available to you to make real changes on the user's system. You should also answer questions when asked.\r\n\r\n# Prompt and Tool Use\r\n\r\nThe user's messages may contain questions and/or task descriptions. Read them, understand them, and do what the user requested. For simple questions or greetings that do not involve any information in the working directory or on the internet, reply directly. For anything else, default to taking action with tools. When the request could be interpreted as either a question to answer or a task to complete, treat it as a task.\r\n\r\nWhen handling the user's request, if it involves creating, modifying, or running code or files, you MUST use the appropriate tools to make actual changes; do not just describe the solution in text. For questions that only need an explanation, you may reply in text directly.\r\n\r\nIf a subagent tool is available, you can use it to delegate a focused subtask to a subagent instance. When delegating, provide a complete prompt with all necessary context because a newly created subagent does not automatically see your context.\r\n\r\nYou can output any number of tool calls in a single response. If you anticipate making multiple non-interfering tool calls, make them in parallel to significantly improve efficiency. The results of the tool calls will be returned to you; determine your next action based on the results.\r\n\r\nTool results and user messages may include <system-reminder> tags. These are authoritative system directives that you MUST follow. They may override or constrain your normal behavior, and they bear no direct relation to the specific tool results or user messages in which they appear.\r\n\r\nWhen responding to the user, you MUST use the same language as the user, unless explicitly instructed to do otherwise.\r\n\r\n# General Guidelines for Coding\r\n\r\nWhen building something from scratch, you should:\r\n- Understand the user's requirements.\r\n- Ask the user for clarification if there is anything unclear.\r\n- Design the architecture and make a plan for the implementation.\r\n- Write the code in a modular and maintainable way.\r\n\r\nAlways use tools to implement your code changes: use editing tools to create or modify source files. Code that only appears in your text response is NOT saved to the file system and will not take effect. Use shell to run and test your code after writing it. Iterate: if tests fail, read the error, fix the code, and re-test.\r\n\r\nWhen working on an existing codebase, you should:\r\n- Understand the codebase by reading it with tools before making changes. Identify the ultimate goal and the most important criteria to achieve it.\r\n- For a bug fix, check error logs or failed tests, scan the codebase to find the root cause, and figure out a fix. If the user mentioned failed tests, make sure they pass after the changes.\r\n- For a feature, design the architecture and write the code with minimal intrusion into existing code. Add new tests if the project already has tests.\r\n- For a refactor, update all call sites if the interface changes. DO NOT change existing logic, especially in tests; focus only on fixing errors caused by the interface changes.\r\n- Make MINIMAL changes to achieve the goal. This is very important to your performance.\r\n- Follow the coding style of existing code in the project.\r\n\r\nDO NOT run git commit, git push, git reset, git rebase, or any other git mutations unless explicitly asked to do so. Ask for confirmation each time you need to do git mutations, even if the user has confirmed in earlier conversations.\r\n\r\n# General Guidelines for Research and Data Processing\r\n\r\nSearch on the Internet if possible, with carefully-designed search queries to improve efficiency and accuracy. Use proper tools or shell commands to process or generate files, ensuring that third-party packages are installed in a virtual or isolated environment if needed. Once you generate or edit any files, read them again before proceeding to ensure the content is as expected. Avoid installing or deleting anything outside of the current working directory; if you have to, ask the user for confirmation.\r\n\r\n# Working Environment\r\n\r\nThe operating environment is not in a sandbox. Any actions you do will immediately affect the user's system, so you MUST be extremely cautious. Unless explicitly instructed to do so, never access (read, write, or execute) files outside of the working directory. Use absolute paths for file operations.\r\n\r\n# Project Information\r\n\r\nMarkdown files named AGENTS.md usually contain the background, structure, coding styles, user preferences, and other relevant information about the project. You should read the project's AGENTS.md and README files to understand its conventions and preferences. If they are empty or insufficient, check README files or AGENTS.md files in subdirectories for more information.\r\n\r\n# Ultimate Reminders\r\n\r\nAt any time, you should be HELPFUL, CONCISE, and ACCURATE. Be thorough in your actions: test what you build and verify what you change, not in your explanations.\r\n- Never diverge from the requirements and goals of the task you work on. Stay on track.\r\n- Never give the user more than what they want.\r\n- Try your best to avoid hallucination. Do fact checking before providing any factual information.\r\n- Think about the best approach, then take action decisively.\r\n- Do not give up too early.\r\n- ALWAYS keep it stupidly simple. Do not overcomplicate things.\r\n- When the task requires creating or modifying files, always use tools to do so. Never treat displaying code in your response as a substitute for actually writing it to the file system.`\r\n\r\n/** DeepSeek 官方建议蒸馏(仅追加,不覆盖 base)。 */\r\nexport const DEEPSEEK_APPEND = `Notes for DeepSeek models:\r\n- Tool calls follow the OpenAI function-calling style; pass arguments strictly according to each tool's JSON schema.\r\n- Reasoning models (e.g. deepseek-reasoner) emit their reasoning before the final answer; do not ask them to skip the thinking process.`\r\n\r\n/** 智谱官方建议蒸馏(仅追加,不覆盖 base)。 */\r\nexport const GLM_APPEND = `Notes for GLM models:\r\n- Tool calls follow the OpenAI function-calling style; pass arguments strictly according to each tool's JSON schema.\r\n- For thinking-enabled GLM models, the reasoning_content of each message must be passed back verbatim on the next request; never drop or rewrite it.\r\n- With interleaved thinking, keep the reasoning context across tool-call rounds.`\r\n\r\n/** 默认语义层(固定层栈的唯一可编辑层):persona。\r\n * 结构固定——UI 与服务端均不允许增删层、改名、改序,仅文本可编辑。\r\n * persona 注册为普通 prompt-stack:persona(order 10),排在内置模型层\r\n * prompt-stack:base(order 0)之后;默认空串:dsh「空段不渲染」,未填写时行为零变化。\r\n * persona 是唯一可编辑存储层;base 为内置模型层(保留层名,不进存储),见 index.ts。 */\r\nexport const DEFAULT_LAYERS: LayerConfig[] = [\r\n { name: 'persona', order: 10, text: '' },\r\n]\r\n\r\n/** 默认模型规则(顺序即同分仲裁序,勿调整)。 */\r\nexport const DEFAULT_RULES: Rule[] = [\r\n { match: { modelPattern: 'claude*' }, overrides: { base: ANTHROPIC_TEXT } },\r\n { match: { modelPattern: 'gemini-*' }, overrides: { base: GEMINI_TEXT } },\r\n { match: { modelPattern: 'gpt-4*' }, overrides: { base: BEAST_TEXT } },\r\n { match: { modelPattern: 'o1*' }, overrides: { base: BEAST_TEXT } },\r\n { match: { modelPattern: 'o3*' }, overrides: { base: BEAST_TEXT } },\r\n { match: { modelPattern: 'gpt*codex*' }, overrides: { base: CODEX_TEXT } },\r\n { match: { modelPattern: 'gpt*' }, overrides: { base: GPT_TEXT } },\r\n { match: { modelPattern: 'kimi*' }, overrides: { base: KIMI_TEXT } },\r\n // kimi 官方模型 id 不带 kimi 前缀(k2、k3-256k 等),且常挂在自定义 provider 名下。\r\n { match: { modelPattern: 'k2*' }, overrides: { base: KIMI_TEXT } },\r\n { match: { modelPattern: 'k3*' }, overrides: { base: KIMI_TEXT } },\r\n { match: { provider: 'moonshotai' }, overrides: { base: KIMI_TEXT } },\r\n { match: { provider: 'moonshotai-cn' }, overrides: { base: KIMI_TEXT } },\r\n { match: { provider: 'kimi-for-coding' }, overrides: { base: KIMI_TEXT } },\r\n { match: { modelPattern: 'deepseek*' }, append: DEEPSEEK_APPEND },\r\n { match: { modelPattern: 'glm-*' }, append: GLM_APPEND },\r\n]\r\n","/** 模型规则匹配:glob 编译、AND 打分、最高分选择。 */\r\nimport type { Rule, RuleMatch } from './types.ts'\r\n\r\n/** 正则元字符(`*` 与 `?` 除外——它们是 glob 通配符,之后单独展开)。 */\r\nconst REGEXP_META = /[.+^${}()|[\\]\\\\]/g\r\n\r\n/**\r\n * 把 glob(`*` = 任意串,`?` = 单字符)编译为锚定全串的正则。\r\n * @param pattern - 非空 glob;空或全空白抛错(激活期响亮报错的调用点在 apply)。\r\n * @returns 锚定全串的正则。\r\n */\r\nexport function globToRegExp(pattern: string): RegExp {\r\n if (pattern.trim() === '') {\r\n throw new Error('prompt-stack: modelPattern must be a non-empty glob')\r\n }\r\n const source = pattern\r\n .replace(REGEXP_META, '\\\\$&')\r\n .replaceAll('*', '.*')\r\n .replaceAll('?', '.')\r\n return new RegExp(`^${source}$`)\r\n}\r\n\r\n/**\r\n * 给一条规则的 match 打分:任一指定字段不匹配则整条不命中(返回 0);\r\n * 命中分值为 model=4 / modelPattern=2 / provider=1 的累加。\r\n * @param match - 规则的匹配条件。\r\n * @param provider - 当前 agent 的 provider(创建期配置),可缺失。\r\n * @param model - 当前 agent 的模型 id,可缺失。\r\n * @returns 命中分值,0 表示不命中。\r\n */\r\nexport function scoreRule(match: RuleMatch, provider: string | undefined, model: string | undefined): number {\r\n let score = 0\r\n if (match.provider !== undefined) {\r\n if (match.provider !== provider) return 0\r\n score += 1\r\n }\r\n if (match.model !== undefined) {\r\n if (match.model !== model) return 0\r\n score += 4\r\n }\r\n if (match.modelPattern !== undefined) {\r\n if (model === undefined || !globToRegExp(match.modelPattern).test(model)) return 0\r\n score += 2\r\n }\r\n return score\r\n}\r\n\r\n/**\r\n * 选出唯一命中规则:最高分者,同分取配置序靠前者。\r\n * @param rules - 配置中的规则数组(顺序即优先级仲裁序)。\r\n * @param provider - 当前 agent 的 provider,可缺失。\r\n * @param model - 当前 agent 的模型 id,可缺失。\r\n * @returns 命中规则;无命中返回 undefined。\r\n */\r\nexport function selectRule(rules: readonly Rule[], provider: string | undefined, model: string | undefined): Rule | undefined {\r\n let best: Rule | undefined\r\n let bestScore = 0\r\n for (const rule of rules) {\r\n const score = scoreRule(rule.match, provider, model)\r\n if (score > bestScore) {\r\n best = rule\r\n bestScore = score\r\n }\r\n }\r\n return best\r\n}\r\n","/** prompt 模块:内置模型层(按模型规则整体覆盖)+ persona 可编辑层 + model-notes 自动层。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\n// type-only 导入激活声明合并:Context.systemPrompt 与 AssembleContext.agent。\r\nimport type { Agent } from '@deepseek-ai/dsh-agent'\r\nimport type { AssembleContext } from '@deepseek-ai/dsh-system-prompt'\r\nimport { BASE_TEXT } from './defaults.ts'\r\nimport { globToRegExp, selectRule } from './match.ts'\r\nimport type { Config as ConfigT, LayerConfig, Rule } from './types.ts'\r\n\r\nexport type { Config, LayerConfig, Rule, RuleMatch } from './types.ts'\r\n\r\n/** 固定追加层的层名(保留,用户层不得使用)。 */\r\nexport const MODEL_NOTES_LAYER = 'model-notes'\r\n\r\n/** 内置模型层名(保留):固定注册 prompt-stack:base 段、不进存储,仍是 rules overrides 的合法目标。 */\r\nexport const BASE_LAYER = 'base'\r\n\r\nconst BASE_SECTION = `prompt-stack:${BASE_LAYER}`\r\n\r\n/** 原生身份段名与原生文本(与 dsh system-prompt 宿主一致;覆盖判定的基准值)。 */\r\nconst IDENTITY_SECTION = 'harness:identity'\r\nconst NATIVE_IDENTITY_TEXT = 'You are an AI agent powered by DeepSeek Harness.'\r\n\r\n/** 运行时层视图:setupPrompt 只消费 get/getIdentity + subscribe,不关心存储细节(测试可注入假实现)。 */\r\nexport interface LayerView {\r\n get(): LayerConfig[]\r\n /** identity 段覆盖文本(空串 = 原生)。 */\r\n getIdentity(): string\r\n subscribe(listener: () => void): () => void\r\n}\r\n\r\n/** 层列表语义校验:空、层名重复、保留层名(base/model-notes)。 */\r\nexport function validateLayers(layers: LayerConfig[]): void {\r\n if (layers.length === 0) {\r\n throw new Error('prompt-stack: config.layers must define at least one layer')\r\n }\r\n const names = new Set<string>()\r\n for (const layer of layers) {\r\n if (layer.name === MODEL_NOTES_LAYER || layer.name === BASE_LAYER) {\r\n throw new Error(`prompt-stack: layer name \"${layer.name}\" is reserved`)\r\n }\r\n if (names.has(layer.name)) {\r\n throw new Error(`prompt-stack: duplicate layer name \"${layer.name}\"`)\r\n }\r\n names.add(layer.name)\r\n }\r\n}\r\n\r\n/**\r\n * 激活期校验(dsh「误配置响亮失败」惯例):空 layers、层名重复、保留层名、\r\n * overrides 引用未知层(内置 base 与 model-notes 之外的存储层名)、空 match、非法 glob 全部抛错。\r\n */\r\nexport function validateConfig(config: ConfigT): void {\r\n validateLayers(config.layers)\r\n const names = new Set([BASE_LAYER, ...config.layers.map(layer => layer.name)])\r\n for (const [index, rule] of config.rules.entries()) {\r\n const { provider, model, modelPattern } = rule.match\r\n if (provider === undefined && model === undefined && modelPattern === undefined) {\r\n throw new Error(`prompt-stack: rules[${index}].match must set at least one of provider, model, modelPattern`)\r\n }\r\n if (modelPattern !== undefined) globToRegExp(modelPattern)\r\n for (const key of Object.keys(rule.overrides ?? {})) {\r\n if (!names.has(key)) {\r\n throw new Error(`prompt-stack: rules[${index}].overrides references unknown layer \"${key}\"`)\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 固定注册 prompt-stack:base(模型层,order 0)+ 每个存储层一个段 + model-notes。\r\n * 文本在每次组装时按当前 agent 的 provider/model 选唯一命中规则(最高分、同分取配置序靠前),\r\n * 模型层用 overrides.base 整体替换内置 BASE_TEXT,存储层用 overrides 替换该层文本。\r\n * 裸组装(无 agent)静默用默认文本。deployment:persona 槽位还原生,本模块不触碰。\r\n *\r\n * 运行时选模型与首条消息钉住语义不变(见 waterfall 注释)。\r\n */\r\nexport function setupPrompt(ctx: Context, config: { source: LayerView; rules: Rule[] }): void {\r\n const { source, rules } = config\r\n const hitRule = (context: AssembleContext): Rule | undefined =>\r\n selectRule(rules, context.agent?.options?.provider, context.agent?.options?.model)\r\n // 子 Agent 隔离:模型层/persona 不泄漏进子 Agent 组装;model-notes 是模型层\r\n // (模型的通用使用说明),主子共用、按子的生效模型命中规则。\r\n const isSubagent = (context: AssembleContext): boolean =>\r\n context.agent?.session?.header?.origin === 'subagent'\r\n\r\n // 层文本可经 UI 修改:registerSections 先 dispose 上一轮再按当前层重注册,\r\n // source 变更时经 subscribe 触发。base 与 model-notes 恒注册,不随层集变化。\r\n let disposers: Array<() => void> = []\r\n const registerSections = (): void => {\r\n for (const dispose of disposers) dispose()\r\n disposers = []\r\n const layers = source.get()\r\n validateLayers(layers)\r\n const notesOrder = Math.max(0, ...layers.map(layer => layer.order)) + 1\r\n disposers.push(ctx.systemPrompt.section({\r\n name: BASE_SECTION,\r\n order: 0,\r\n text: (context) =>\r\n isSubagent(context) ? '' : (hitRule(context)?.overrides?.[BASE_LAYER] ?? BASE_TEXT),\r\n }))\r\n for (const layer of layers) {\r\n disposers.push(ctx.systemPrompt.section({\r\n name: `prompt-stack:${layer.name}`,\r\n order: layer.order,\r\n text: (context) =>\r\n isSubagent(context) ? '' : (hitRule(context)?.overrides?.[layer.name] ?? layer.text),\r\n }))\r\n }\r\n disposers.push(ctx.systemPrompt.section({\r\n name: `prompt-stack:${MODEL_NOTES_LAYER}`,\r\n order: notesOrder,\r\n text: (context) => hitRule(context)?.append ?? '',\r\n }))\r\n }\r\n registerSections()\r\n ctx.effect(() => source.subscribe(registerSections))\r\n\r\n const notesSection = `prompt-stack:${MODEL_NOTES_LAYER}`\r\n // 首条消息钉住:每个会话的首次组装解析出的 provider/model 缓存起来,会话中途\r\n // 切模型不再改写系统提示词(对话的行为契约保持稳定)。键带 session id:\r\n // clear/新会话(id 变化)自动重新解析。HMR 重挂载换新闭包,缓存随之重置。\r\n const pinned = new WeakMap<Agent, { sessionId: unknown; provider: string | undefined; model: string | undefined }>()\r\n ctx.on('system-prompt/assemble', async (_assembly, context, next) => {\r\n const assembled = await next()\r\n let provider = assembled.variables.provider ?? context.agent?.options?.provider\r\n let model = assembled.variables.model ?? context.agent?.options?.model\r\n const agent = context.agent\r\n if (agent !== undefined) {\r\n const cached = pinned.get(agent)\r\n if (cached !== undefined && cached.sessionId === agent.session.id) {\r\n provider = cached.provider\r\n model = cached.model\r\n } else if (provider !== undefined || model !== undefined) {\r\n pinned.set(agent, { sessionId: agent.session.id, provider, model })\r\n }\r\n }\r\n const rule = selectRule(rules, provider, model)\r\n const layers = source.get()\r\n // 本插件全局注册各段在本次组装的产出(不含钉住改写)。scoped 同名段(bot 角色\r\n // persona 等)经 dsh 原生 shadow 机制已覆盖全局段,其文本 ≠ 本插件产出,\r\n // 据此识别并跳过、不介入 shadow(spec §3「对主 Agent persona 层 waterfall 不介入」)。\r\n const ownSection = (section: { name: string }): string | undefined => {\r\n if (section.name === BASE_SECTION) {\r\n return isSubagent(context) ? '' : (hitRule(context)?.overrides?.[BASE_LAYER] ?? BASE_TEXT)\r\n }\r\n const layer = layers.find(l => section.name === `prompt-stack:${l.name}`)\r\n if (layer === undefined) return undefined\r\n return isSubagent(context) ? '' : (hitRule(context)?.overrides?.[layer.name] ?? layer.text)\r\n }\r\n const sections = assembled.sections.map((section) => {\r\n // identity 覆盖:非空覆盖文本整份替换原生身份句(空 = 还原原生;子 Agent 隔离;\r\n // 段文本 ≠ 原生常量即 scoped shadow,不介入——同下方 ownSection 守卫语义)。\r\n if (section.name === IDENTITY_SECTION) {\r\n const override = source.getIdentity()\r\n if (override === '' || isSubagent(context) || section.text !== NATIVE_IDENTITY_TEXT) return section\r\n return { ...section, text: override }\r\n }\r\n if (section.name === notesSection) {\r\n return { ...section, text: rule?.append ?? '' }\r\n }\r\n const own = ownSection(section)\r\n if (own === undefined || section.text !== own) return section\r\n if (section.name === BASE_SECTION) {\r\n return { ...section, text: isSubagent(context) ? '' : (rule?.overrides?.[BASE_LAYER] ?? BASE_TEXT) }\r\n }\r\n const layer = layers.find(l => section.name === `prompt-stack:${l.name}`)!\r\n return { ...section, text: isSubagent(context) ? '' : (rule?.overrides?.[layer.name] ?? layer.text) }\r\n })\r\n return { ...assembled, sections }\r\n })\r\n}\r\n","/** 分层提示词层源:内存缓存 + prompt_layers 表回写 + 订阅通知;Config 仅作首启种子。 */\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport type { LayerConfig } from './types.ts'\r\nimport { validateLayers, type LayerView } from './index.ts'\r\n\r\n/** prompt_layers 表单行的 key 常量。 */\r\nexport const PROMPT_LAYERS_KEY = 'layers'\r\n/** meta 表首启种子一次性标记键。 */\r\nexport const PROMPT_LAYERS_SEEDED_KEY = 'prompt_layers_seeded'\r\n\r\nexport interface PromptLayersRow {\r\n layers: LayerConfig[]\r\n /** identity 段覆盖文本(可选,仅非空时写入;空/缺省 = 原生句)。 */\r\n identity?: string\r\n}\r\n\r\n/** 层源的完整能力:setupPrompt 只消费 get/getIdentity/subscribe(LayerView),存储层消费 set/setIdentity/reset。 */\r\nexport interface LayerSource extends LayerView {\r\n /** 校验 → 写表 → 更新内存 → 通知订阅者。 */\r\n set(layers: LayerConfig[]): Promise<void>\r\n /** 写入 identity 覆盖文本(空串 = 还原原生)→ 更新内存 → 通知订阅者。 */\r\n setIdentity(text: string): Promise<void>\r\n /** 清表 + 清种子标记 → 重写种子 → 通知订阅者。连带清空 identity 覆盖。 */\r\n reset(): Promise<void>\r\n}\r\n\r\nexport interface PromptLayerTables {\r\n promptLayers: KvTable<string, PromptLayersRow>\r\n meta: KvTable<string, { value: string }>\r\n}\r\n\r\n/** 组装存储行:identity 仅非空时落字段(空串 = 还原原生,不留残字段)。 */\r\nfunction row(layers: LayerConfig[], identity: string): PromptLayersRow {\r\n return identity === '' ? { layers } : { layers, identity }\r\n}\r\n\r\n/** 固定结构校验:name+order 多重集合必须等于种子(仅 text 可变)。 */\r\nexport function validateFixedLayers(layers: LayerConfig[], seedLayers: LayerConfig[]): void {\r\n const key = (layer: LayerConfig): string => `${layer.name}@${String(layer.order)}`\r\n const seed = seedLayers.map(key).sort()\r\n const actual = layers.map(key).sort()\r\n if (actual.length !== seed.length || actual.some((k, i) => k !== seed[i])) {\r\n throw new Error(`prompt-stack: layer structure is fixed (${seedLayers.map(l => l.name).join(', ')}); only layer text is editable`)\r\n }\r\n}\r\n\r\n/** 按种子结构 reconcile 已存储层:同名层保留已存文本(order 以种子为准)、补缺失、丢多余。 */\r\nexport function reconcileLayers(stored: LayerConfig[], seedLayers: LayerConfig[]): LayerConfig[] {\r\n return seedLayers.map(seed => ({\r\n ...seed,\r\n text: stored.find(layer => layer.name === seed.name)?.text ?? seed.text,\r\n }))\r\n}\r\n\r\n/**\r\n * 打开层源。域由 apply 统一 open(storage-domain 同名单开),本函数只消费表句柄。\r\n * 首启(表无数据)种入 Config 种子并置标记;此后读存储并按种子结构 reconcile\r\n * (层栈固定化迁移:保留已编辑文本、补新层、丢多余层)。\r\n */\r\nexport async function openLayerSource(tables: PromptLayerTables, seedLayers: LayerConfig[]): Promise<LayerSource> {\r\n const { promptLayers, meta } = tables\r\n validateLayers(seedLayers)\r\n let cache: LayerConfig[]\r\n let identity: string\r\n const existing = promptLayers.get(PROMPT_LAYERS_KEY)\r\n if (existing !== undefined) {\r\n // 不再 validateLayers(existing.layers):旧存储可能含已退役的层名(如 base),\r\n // reconcile 负责对齐种子结构,校验只针对 reconcile 后的结果(恒合法,防御性保留)。\r\n cache = reconcileLayers(existing.layers, seedLayers)\r\n validateLayers(cache)\r\n identity = existing.identity ?? ''\r\n await promptLayers.put(PROMPT_LAYERS_KEY, row(cache, identity))\r\n } else {\r\n cache = seedLayers\r\n identity = ''\r\n await promptLayers.put(PROMPT_LAYERS_KEY, { layers: cache })\r\n }\r\n if (meta.get(PROMPT_LAYERS_SEEDED_KEY) === undefined) {\r\n await meta.put(PROMPT_LAYERS_SEEDED_KEY, { value: '1' })\r\n }\r\n\r\n const listeners = new Set<() => void>()\r\n const notify = (): void => { for (const listener of [...listeners]) listener() }\r\n\r\n return {\r\n get: () => cache,\r\n getIdentity: () => identity,\r\n async set(layers: LayerConfig[]): Promise<void> {\r\n validateLayers(layers)\r\n validateFixedLayers(layers, seedLayers)\r\n await promptLayers.put(PROMPT_LAYERS_KEY, row(layers, identity))\r\n cache = layers\r\n notify()\r\n },\r\n async setIdentity(text: string): Promise<void> {\r\n await promptLayers.put(PROMPT_LAYERS_KEY, row(cache, text))\r\n identity = text\r\n notify()\r\n },\r\n async reset(): Promise<void> {\r\n await promptLayers.delete(PROMPT_LAYERS_KEY)\r\n await meta.delete(PROMPT_LAYERS_SEEDED_KEY)\r\n await promptLayers.put(PROMPT_LAYERS_KEY, { layers: seedLayers })\r\n await meta.put(PROMPT_LAYERS_SEEDED_KEY, { value: '1' })\r\n cache = seedLayers\r\n identity = ''\r\n notify()\r\n },\r\n subscribe(listener: () => void): () => void {\r\n listeners.add(listener)\r\n return () => { listeners.delete(listener) }\r\n },\r\n }\r\n}\r\n","/** shared webServer 助手:可选服务模式下注册路由(headless/CLI 无 webServer 时惰性、不注册、不抛错)。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\n\r\nexport function registerOptionalRoutes(\r\n ctx: Context,\r\n register: (webCtx: Context) => () => void,\r\n): void {\r\n // 经 ctx.inject 子 fiber 等待 webServer 挂载后再注册:子 fiber 未激活时惰性、\r\n // 随父 fiber 卸载而清理;webServer 永不出现时任何分支都不注册。注册走\r\n // ctx.effect 接线 disposer(\"Registrations are effects\"),HMR 重挂不会因\r\n // 重复 exact 路径抛错。\r\n ctx.inject(['webServer'], (webCtx) => {\r\n webCtx.effect(() => register(webCtx))\r\n })\r\n}\r\n","import type { IncomingMessage, ServerResponse } from 'node:http'\r\n\r\nexport const MAX_BODY_BYTES = 64 * 1024\r\n\r\nexport function json(res: ServerResponse, code: number, body: unknown): void {\r\n res.writeHead(code, { 'content-type': 'application/json' }).end(JSON.stringify(body))\r\n}\r\n\r\n/** 读 JSON body;超限 413 / 非法 JSON 400(已写响应时返回 undefined)。 */\r\nexport async function readJsonBody(req: IncomingMessage, res: ServerResponse): Promise<unknown | undefined> {\r\n const chunks: Buffer[] = []\r\n let received = 0\r\n for await (const chunk of req) {\r\n const buffer = chunk as Buffer\r\n received += buffer.byteLength\r\n if (received > MAX_BODY_BYTES) {\r\n json(res, 413, { error: 'body too large' })\r\n req.destroy()\r\n return undefined\r\n }\r\n chunks.push(buffer)\r\n }\r\n try {\r\n return JSON.parse(Buffer.concat(chunks).toString('utf8'))\r\n } catch {\r\n json(res, 400, { error: 'invalid JSON body' })\r\n return undefined\r\n }\r\n}\r\n","/** 分层提示词 RPC 端点组:读(layers+rules+seed+native 探测)、写(PUT 全量替换)、reset。 */\r\nimport type { IncomingMessage, ServerResponse } from 'node:http'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { z } from 'zod'\r\nimport { registerOptionalRoutes } from '../shared/webserver.ts'\r\nimport { json, readJsonBody } from '../shared/http.ts'\r\nimport { LayerConfigSchema } from '../agents/store.ts'\r\nimport { BASE_TEXT } from './defaults.ts'\r\nimport { validateLayers } from './index.ts'\r\nimport { validateFixedLayers, type LayerSource } from './layer-source.ts'\r\nimport type { LayerConfig, Rule } from './types.ts'\r\n\r\n/** 裸组装探测结果:原生 sections / 动态 contexts 的名称与当前文本(只读展示用)。 */\r\nexport interface NativeProbe {\r\n sections: Array<{ name: string; text: string }>\r\n contexts: Array<{ name: string; text: string }>\r\n}\r\n\r\nexport interface PromptLayersApiDeps {\r\n source: LayerSource\r\n rules: Rule[]\r\n seedLayers: LayerConfig[]\r\n /** 裸 assemble 探测(apply 闭包注入);失败降级为空列表,不阻塞主数据。 */\r\n probe: () => Promise<NativeProbe>\r\n}\r\n\r\nconst LayersBodySchema = z.object({ layers: z.array(LayerConfigSchema), identityOverride: z.string().optional() })\r\n\r\nexport function createPromptLayersApiHandler(deps: PromptLayersApiDeps): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\r\n return async (req, res) => {\r\n const url = new URL(req.url ?? '/', 'http://127.0.0.1')\r\n const sub = url.pathname.replace(/^\\/dsh-agent-toolkit\\/api\\/prompt-layers/, '') || '/'\r\n const method = req.method ?? 'GET'\r\n\r\n if (sub === '/' && method === 'GET') {\r\n let native: NativeProbe = { sections: [], contexts: [] }\r\n try {\r\n native = await deps.probe()\r\n } catch { /* 探测失败降级为空,layers/rules/seedLayers 主数据照常返回 */ }\r\n json(res, 200, { layers: deps.source.get(), rules: deps.rules, seedLayers: deps.seedLayers, native, modelFallbackText: BASE_TEXT, identityOverride: deps.source.getIdentity() })\r\n return\r\n }\r\n\r\n if (sub === '/' && method === 'PUT') {\r\n const body = await readJsonBody(req, res)\r\n if (body === undefined) return\r\n const parsed = LayersBodySchema.safeParse(body)\r\n if (!parsed.success) {\r\n json(res, 400, { error: parsed.error.issues[0]?.message ?? 'invalid layers body' })\r\n return\r\n }\r\n try {\r\n validateLayers(parsed.data.layers)\r\n validateFixedLayers(parsed.data.layers, deps.seedLayers)\r\n } catch (error) {\r\n json(res, 400, { error: error instanceof Error ? error.message : String(error) })\r\n return\r\n }\r\n try {\r\n await deps.source.set(parsed.data.layers)\r\n if (parsed.data.identityOverride !== undefined) {\r\n await deps.source.setIdentity(parsed.data.identityOverride)\r\n }\r\n } catch (error) {\r\n json(res, 500, { error: error instanceof Error ? error.message : String(error) })\r\n return\r\n }\r\n json(res, 200, { ok: true })\r\n return\r\n }\r\n\r\n if (sub === '/reset' && method === 'POST') {\r\n try {\r\n await deps.source.reset()\r\n } catch (error) {\r\n json(res, 500, { error: error instanceof Error ? error.message : String(error) })\r\n return\r\n }\r\n json(res, 200, { ok: true })\r\n return\r\n }\r\n\r\n if (sub === '/reset' || sub === '/') {\r\n json(res, 405, { error: 'method not allowed' })\r\n return\r\n }\r\n json(res, 404, { error: 'not found' })\r\n }\r\n}\r\n\r\n/** 注册 /dsh-agent-toolkit/api/prompt-layers 前缀路由(webServer 可选服务,缺席惰性不注册)。 */\r\nexport function setupPromptLayersApi(ctx: Context, deps: PromptLayersApiDeps): void {\r\n const handler = createPromptLayersApiHandler(deps)\r\n registerOptionalRoutes(ctx, (webCtx) => {\r\n const dispose = webCtx.webServer.register({ kind: 'prefix', path: '/dsh-agent-toolkit/api/prompt-layers', handler })\r\n return () => dispose()\r\n })\r\n}\r\n","/** 委派子 Agent 的 persona 装配:契约段 + 内置模型层(按子的模型改写)+ 角色 persona。 */\r\nimport { BASE_TEXT } from './defaults.ts'\r\nimport { selectRule } from './match.ts'\r\nimport type { Rule } from './types.ts'\r\n\r\nconst SECTION_A = (roleName: string): string => `你是团队中的一名成员(角色:${roleName}),由主 Agent 委派任务。\r\n- 你看不到主对话;任务书包含你完成工作所需的全部上下文。\r\n- 你的最终输出会作为结果完整返回给主 Agent:直接给出结论与必要细节。\r\n- 你不能再次委派他人;任务需要拆分时,自己按顺序完成。`\r\n\r\nconst SECTION_B = `能力使用守则:\r\n- 你可以使用与主 Agent 相同的工具与 MCP 资源,但只在任务必需时调用。\r\n- 动手修改代码前,先阅读项目根目录及涉及目录的 AGENTS.md,并遵循其中约定。\r\n- 产生或修改文件后,运行相关检查(测试、类型检查)验证你的改动。`\r\n\r\n/**\r\n * 子 Agent 提示词 = 契约段 A/B + 模型层文本(命中规则 overrides.base 整份替换内置\r\n * BASE_TEXT)+ 角色 persona(非空时,排在模型层之后)+ 命中规则的 append(model-notes)。\r\n * 全局 persona 层是主 Agent 的人设,不进入子 Agent(子的角色由 role.persona 顶替)。\r\n */\r\nexport function buildAgentPersona(\r\n config: { rules: Rule[] },\r\n role: { name: string; persona?: string },\r\n model?: { provider?: string; model?: string },\r\n): string {\r\n const rule = selectRule(config.rules, model?.provider, model?.model)\r\n const texts = [rule?.overrides?.base ?? BASE_TEXT]\r\n if (role.persona !== undefined && role.persona.trim().length > 0) texts.push(role.persona)\r\n if (rule?.append !== undefined) texts.push(rule.append)\r\n return [SECTION_A(role.name), SECTION_B, ...texts].join('\\n\\n')\r\n}\r\n","/** team_delegate 工具:查角色 → 一次性 spawn 前台委派 → 规范 JSON 返回。 */\r\nimport type { Agent } from '@deepseek-ai/dsh-agent'\r\nimport type { ContentBlock } from '@deepseek-ai/dsh-llm'\r\nimport type { JsonValue } from '@deepseek-ai/dsh-util-values'\r\nimport { defineTool, RUN_CODE_NAME } from '@deepseek-ai/dsh-tools'\r\nimport type { SubagentResult, SubagentRun, SubagentStartRequest } from '@deepseek-ai/dsh-subagent'\r\nimport { isTeamVisible, type AgentRecord } from '../agents/store.ts'\r\nimport type { ActiveRoutes, DelegateRoute } from './active.ts'\r\n\r\n/** createDelegateTool 的外部依赖。 */\r\nexport interface DelegateToolDeps {\r\n /** 当前生效名册(闭包返回同一数组;查找与错误清单均排除 main)。 */\r\n readonly roster: () => readonly AgentRecord[]\r\n /** ctx.subagents 的 provider 名(默认 'spawn')。 */\r\n readonly provider: string\r\n /** 成员 persona 装配(生产为 buildAgentPersona,测试注入假实现)。 */\r\n readonly buildPersona: (role: AgentRecord) => string\r\n /** 委派入口:生产为 ctx.subagents.start.bind(ctx.subagents),测试注入假实现。 */\r\n readonly startRun: (provider: string, request: SubagentStartRequest) => Promise<SubagentRun>\r\n /** 在途表:运行中委派卡 chip 的数据源。 */\r\n readonly active: ActiveRoutes\r\n /** 持久路由写入(子会话头部 chip 数据源);实现方保证不抛错语义由调用处 catch 兜底。 */\r\n readonly recordRoute: (childSessionId: string, route: DelegateRoute) => Promise<void>\r\n /** 父会话真实可见工具面(生产走 scopeOf(agent.ctx) + scoped schemas;测试注入 fake)。 */\r\n readonly visibleSurface: (agent: Agent) => string[]\r\n /** 未知名 warn-drop 日志(生产 ctx.logger.warn)。 */\r\n readonly warn: (msg: string) => void\r\n}\r\n\r\n/** 非 completed 的 stopReason 意味着成员未干净完成。 */\r\nfunction stopReasonError(result: SubagentResult): string | undefined {\r\n switch (result.stopReason) {\r\n case 'completed': return undefined\r\n case 'aborted': return '成员运行被取消'\r\n case 'error': return '成员运行失败'\r\n case 'max-tokens': return '成员在结束前触及 token 上限'\r\n case 'refusal': return '成员拒绝了该任务'\r\n default: return `成员运行异常结束(${String(result.stopReason)})`\r\n }\r\n}\r\n\r\n/** 报错时附上成员已产出的部分文本,让截断/取消的真实产出仍回到主 Agent。 */\r\nfunction withPartialText(error: string, output: ContentBlock[]): string {\r\n const text = output\r\n .filter((block): block is Extract<ContentBlock, { type: 'text' }> => block.type === 'text')\r\n .map(block => block.text)\r\n .join('')\r\n return text.length === 0 ? error : `${error}\\n成员中断前的部分产出:\\n${text}`\r\n}\r\n\r\n/** 收集并释放一次前台运行;dispose 失败不掩盖独立的结果失败。 */\r\nasync function settleForegroundRun(run: SubagentRun, roleId: string, route?: DelegateRoute) {\r\n // 本地 run 的 run.id 契约上即子 session id(dsh-subagent types.ts:249-255)。\r\n const childSessionId = String(run.id)\r\n const [execution] = await Promise.allSettled([\r\n run.result.then((result) => {\r\n const error = stopReasonError(result)\r\n if (error !== undefined) throw new Error(withPartialText(error, result.output))\r\n return {\r\n kind: 'foreground' as const,\r\n role: roleId,\r\n runId: String(run.id),\r\n childSessionId,\r\n output: result.output as unknown as JsonValue[],\r\n ...route !== undefined ? { provider: route.provider, model: route.model } : {},\r\n }\r\n }),\r\n ])\r\n const [disposal] = await Promise.allSettled([Promise.resolve().then(() => run.dispose())])\r\n if (execution.status === 'rejected') {\r\n if (disposal.status === 'rejected') {\r\n throw new AggregateError([execution.reason, disposal.reason],\r\n `成员运行失败:${String(execution.reason)};dispose 失败:${String(disposal.reason)}`)\r\n }\r\n throw execution.reason\r\n }\r\n if (disposal.status === 'rejected') throw disposal.reason\r\n return execution.value\r\n}\r\n\r\n/**\r\n * 创建 team_delegate 工具。\r\n * @param toolName - 模型可见工具名(Config.toolName,默认 team_delegate)。\r\n * @param deps - 名册、provider、persona 装配与委派入口。\r\n * @returns defineTool 产物,交给 ctx.tools.register。\r\n *\r\n * 工具注册是 standing scope 的单次注册,description 无法内嵌名册;名册对模型的\r\n * 可见性走系统提示团队段(index.ts)。\r\n */\r\nexport function createDelegateTool(toolName: string, deps: DelegateToolDeps) {\r\n const tool = defineTool({\r\n name: toolName,\r\n description:\r\n 'Delegate a self-contained task to a team member (a separate agent with its own persona and '\r\n + 'optional model override). The member does NOT see this conversation — give it a complete, '\r\n + 'standalone prompt. Available members and their descriptions are listed in the team section '\r\n + 'of the system prompt. This call waits for the member and returns its result.',\r\n parameters: {\r\n role: { type: 'string', required: true, description: 'The member to delegate to. Must be one of the listed names.' },\r\n description: { type: 'string', required: true, description: 'A short (3-5 word) description of the delegated task, for display.' },\r\n prompt: { type: 'string', required: true, description: 'The complete, self-contained task for the member. It does not share this conversation\\'s context, so include everything it needs.' },\r\n },\r\n output: {\r\n schema: {\r\n type: 'object',\r\n additionalProperties: false,\r\n properties: {\r\n kind: { type: 'string', required: true, const: 'foreground' },\r\n role: { type: 'string', required: true },\r\n runId: { type: 'string', required: true },\r\n childSessionId: { type: 'string', required: true },\r\n output: { type: 'array', required: true, items: { type: 'json' } },\r\n provider: { type: 'string' },\r\n model: { type: 'string' },\r\n },\r\n },\r\n render: (_args, value) => [{\r\n type: 'text' as const,\r\n text: (value.output as { type: string; text?: string }[])\r\n .filter(block => block.type === 'text' && typeof block.text === 'string')\r\n .map(block => block.text).join(''),\r\n }],\r\n // 浏览器半委派卡经 tool/result 的持久化 meta 读子会话坐标(回放可重建)。\r\n presentationMeta: (_args, value) => ({\r\n role: value.role as string,\r\n runId: value.runId as string,\r\n childSessionId: value.childSessionId as string,\r\n ...typeof value.provider === 'string' && typeof value.model === 'string'\r\n ? { provider: value.provider, model: value.model }\r\n : {},\r\n }),\r\n },\r\n // 成员不改父会话;父方无写操作。与内置 subagent 工具同款。\r\n isConcurrencySafe: () => true,\r\n // generic 兜底(浏览器半缺席/回放旧事件时降级;generic title 在 Web 不渲染,\r\n // 供 headless 与日志使用)。\r\n presentCall: (args) => ({\r\n card: 'generic' as const,\r\n title: `委派 · ${args.role}: ${args.description}`,\r\n rawInput: args.prompt,\r\n }),\r\n presentResult: (_args, result) => (result.isError ? undefined : { card: 'generic' as const }),\r\n async execute(args, exec) {\r\n const parent: Agent | undefined = exec.agent\r\n if (!parent) throw new Error('team_delegate 需要调用方 agent(exec.agent 为空)')\r\n // 主 Agent 与团队不可见角色不可委派:查找与错误清单都排除。\r\n const roster = deps.roster().filter(r => r.id !== 'main' && isTeamVisible(r))\r\n const role = roster.find(r => r.id === args.role)\r\n if (!role) {\r\n throw new Error(`未知角色 \"${args.role}\"。可用角色:${roster.map(r => r.id).join(', ')}`)\r\n }\r\n const persona = deps.buildPersona(role)\r\n // 白名单与父会话真实可见面求交(warn-drop 未知名)——宿主 child-agent 对 toolFilter\r\n // 直接 restrict,未知名响亮失败(spawn-in-process 测试 \"an unknown toolFilter name\r\n // fails the spawn loudly\" 佐证);与 bot 会话路径(channels/agent-setup.ts)对称,\r\n // 消除两条路径的白名单有效性不对称。求交为空抛错防静默零工具子会话。\r\n let toolFilter: { allow: string[] } | undefined\r\n if (role.tools !== undefined) {\r\n const visible = new Set(deps.visibleSurface(parent).filter((n) => n !== RUN_CODE_NAME))\r\n const effective = role.tools.allow.filter((n) => visible.has(n))\r\n const dropped = role.tools.allow.filter((n) => !visible.has(n))\r\n if (dropped.length > 0) {\r\n deps.warn(`dsh-agent-toolkit: 角色 ${role.id} 白名单含本会话不可见工具,委派时忽略:${dropped.join(', ')}`)\r\n }\r\n if (effective.length === 0) {\r\n throw new Error(`dsh-agent-toolkit: 角色 ${role.id} 工具白名单求交后为空(原 ${role.tools.allow.length} 个均不可见):${role.tools.allow.join(', ')}`)\r\n }\r\n toolFilter = { allow: effective }\r\n }\r\n const request: SubagentStartRequest = {\r\n label: `role:${role.id}: ${args.description}`,\r\n prompt: [{ type: 'text', text: args.prompt } as ContentBlock],\r\n parent,\r\n persona,\r\n maxDepth: 1, // 禁止套娃:成员(深度 1)再委派时 childDepth 2 > 1,provider 响亮拒绝\r\n signal: exec.signal,\r\n ...role.model !== undefined\r\n ? { agentOptions: { provider: role.model.provider, model: role.model.model } }\r\n : {},\r\n ...toolFilter !== undefined\r\n ? { toolFilter }\r\n : {},\r\n } as SubagentStartRequest\r\n // 路由解析与 spawn driver resolveChildAgentOptions 同源:角色覆盖 ?? 父 options。\r\n // 字段为空串视为未配置;任一缺失整体省略(不猜部署默认——显示错值比不显示更糟)。\r\n const route: DelegateRoute | undefined =\r\n (role.model !== undefined && role.model.provider !== '' && role.model.model !== ''\r\n ? role.model\r\n : undefined)\r\n ?? (typeof parent.options.provider === 'string' && parent.options.provider !== ''\r\n && typeof parent.options.model === 'string' && parent.options.model !== ''\r\n ? { provider: parent.options.provider, model: parent.options.model }\r\n : undefined)\r\n const parentSessionId = String(parent.session.id)\r\n if (route !== undefined) deps.active.set(parentSessionId, role.id, route)\r\n try {\r\n const run = await deps.startRun(deps.provider, request)\r\n if (route !== undefined) {\r\n // 展示向写入失败不阻断委派(域关闭等异常吞掉)。\r\n await deps.recordRoute(String(run.id), route).catch(() => undefined)\r\n }\r\n return await settleForegroundRun(run, role.id, route)\r\n } finally {\r\n if (route !== undefined) deps.active.delete(parentSessionId, role.id)\r\n }\r\n },\r\n })\r\n return tool\r\n}\r\n","/** delegate 模块:注册表驱动的 team_delegate 委派工具 + 函数式团队提示段。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { scopeOf } from '@deepseek-ai/dsh-scope'\r\nimport type { SubagentProvider } from '@deepseek-ai/dsh-subagent'\r\nimport { isTeamVisible, type AgentRecord } from '../agents/store.ts'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport { buildAgentPersona } from '../prompt/persona.ts'\r\nimport type { Rule } from '../prompt/types.ts'\r\nimport { createDelegateTool } from './tool.ts'\r\nimport type { ActiveRoutes, DelegateRoute } from './active.ts'\r\n\r\nexport type { DelegateToolDeps } from './tool.ts'\r\nexport { createDelegateTool } from './tool.ts'\r\n\r\n/**\r\n * 团队名册段文本:仅当该 agent scope 的可见工具里确有委派工具时渲染,否则空\r\n * (空段渲染时被丢弃)。工具白名单 restrict 只作用于 tools 视图,名册段必须\r\n * 自行按 `tools.get(name, scope)` 联动,否则没勾委派的 bot 提示词仍会出现委派段落。\r\n */\r\nexport function teamSectionText(\r\n toolName: string,\r\n roles: readonly Pick<AgentRecord, 'id' | 'name' | 'description' | 'visibleInTeam'>[],\r\n toolVisible: boolean,\r\n): string {\r\n if (!toolVisible) return ''\r\n const rosterText = roles\r\n .filter(r => r.id !== 'main' && isTeamVisible(r))\r\n .map(r => `${r.id}: ${r.description ?? r.name}`)\r\n .join('\\n')\r\n return `你有一组可委派的成员:用 ${toolName} 把自包含的子任务委派给合适的成员,成员结果会作为工具返回值回到本对话。\\n可用成员:\\n${rosterText}`\r\n}\r\n\r\nexport interface DelegateConfig {\r\n /** ctx.subagents provider 名(默认 'spawn')。 */\r\n provider: string\r\n /** 模型可见工具名(默认 'team_delegate')。注意:浏览器半委派卡按 'team_delegate' key 注册,改名后卡片不生效(落 generic 兜底)。 */\r\n toolName: string\r\n /** 按模型规则(Task 7 产物)。 */\r\n rules: Rule[]\r\n}\r\n\r\n/** setupDelegate 的存储/在途通道(Task 3 DelegateToolDeps 的两个新字段)。 */\r\nexport interface DelegateChannels {\r\n readonly active: ActiveRoutes\r\n readonly recordRoute: (childSessionId: string, route: DelegateRoute) => Promise<void>\r\n}\r\n\r\n/**\r\n * 挂载 team_delegate 工具与函数式团队提示段。\r\n * provider 能力守卫与生命周期镜像同归档 tool-subagent:persona/depthLimit 缺失响亮报错,\r\n * 工具随 provider 在场与否挂载/摘除。名册来自注册表(main 排除),工具与提示段都经\r\n * 闭包读取 registry,UI 改角色后新会话即生效。\r\n */\r\nexport function setupDelegate(ctx: Context, config: DelegateConfig, registry: AgentRegistry, channels: DelegateChannels): void {\r\n const { provider, toolName } = config\r\n let disposeTool: (() => void) | undefined\r\n let providerFailed = false\r\n const mountTool = (p: SubagentProvider): void => {\r\n const missing: string[] = []\r\n if (!p.capabilities.persona) missing.push('persona')\r\n if (!p.capabilities.depthLimit) missing.push('depthLimit')\r\n if (missing.length > 0) {\r\n throw new Error(\r\n `dsh-agent-toolkit: provider \"${p.name}\" 缺少 team_delegate 委派必需能力 ${missing.join('/')}(固定发送 persona 与 maxDepth:1)——请配置具备 persona 与 depthLimit 能力的 provider(如 spawn/fork)`,\r\n )\r\n }\r\n if (disposeTool === undefined) {\r\n disposeTool = ctx.tools.register(createDelegateTool(toolName, {\r\n roster: () => registry.list(),\r\n provider,\r\n buildPersona: (role: AgentRecord) =>\r\n buildAgentPersona({ rules: config.rules }, role, role.model),\r\n startRun: (pr, request) => ctx.subagents.start(pr, request),\r\n active: channels.active,\r\n recordRoute: channels.recordRoute,\r\n // 父会话真实可见面:scoped schemas = global + 祖先层,与 bot 路径同款手段\r\n // (scopeOf 对未 scoped ctx 返回 undefined,schemas 接受 undefined 为顶层视图——\r\n // channels/agent-setup.ts:41 先例)。\r\n visibleSurface: (agent) => agent.ctx.tools.schemas(scopeOf(agent.ctx)).map((s) => s.name),\r\n warn: (msg) => { ctx.logger.warn(msg) },\r\n }))\r\n }\r\n }\r\n ctx.on('subagent/provider-added', (p) => {\r\n if (p.name !== provider || providerFailed) return\r\n try {\r\n mountTool(p)\r\n } catch (error) {\r\n providerFailed = true\r\n ctx.logger.error(error instanceof Error ? error.message : String(error))\r\n }\r\n })\r\n ctx.on('subagent/provider-removed', (removed) => {\r\n if (removed !== provider) return\r\n providerFailed = false\r\n if (disposeTool !== undefined) {\r\n disposeTool()\r\n disposeTool = undefined\r\n }\r\n })\r\n const present = ctx.subagents.getProvider(provider)\r\n if (present !== undefined) {\r\n mountTool(present)\r\n } else {\r\n ctx.logger.info(`dsh-agent-toolkit: subagent provider \"${provider}\" 尚未注册;team_delegate 将等它出现时挂载`)\r\n }\r\n ctx.systemPrompt.section({\r\n name: 'plugin:dsh-agent-toolkit:team',\r\n // 紧随内置 subagent 指导段之后:order 取宿主中央 SECTION_ORDERS 的 TOOL_SUBAGENT(0.1.5 起 2800)\r\n // + 0.1,跟随宿主重排而非硬编码(同宿主 tool-subagent 自身注册方式,systemPrompt.getSectionOrder)。\r\n order: ctx.systemPrompt.getSectionOrder('TOOL_SUBAGENT') + 0.1,\r\n text: (context) => teamSectionText(\r\n config.toolName,\r\n registry.list(),\r\n // 该 agent scope 的可见工具里确有委派工具才渲染:被白名单 restrict 掉、或\r\n // provider 未挂载(工具没注册)的会话不再出现委派段落(tools.get 对被\r\n // restrict 掉的全局工具返回 absent)。\r\n ctx.tools.get(config.toolName, context.scope) !== undefined,\r\n ),\r\n })\r\n}\r\n","/** 在途委派路由表:运行中委派卡模型 chip 的数据源(进程内,HMR/重启即清空,settle 后由 presentationMeta 兜底)。 */\r\n\r\n/** 一条已解析的委派路由(委派时确定,全程一致)。 */\r\nexport interface DelegateRoute {\r\n readonly provider: string\r\n readonly model: string\r\n}\r\n\r\nexport interface ActiveRoutes {\r\n /** startRun 前写入;同 key 并发委派后写覆盖(纯展示,可接受)。 */\r\n set(parentSessionId: string, roleId: string, route: DelegateRoute): void\r\n /** 端点读取;无条目返回 undefined。 */\r\n get(parentSessionId: string, roleId: string): DelegateRoute | undefined\r\n /** try/finally 删除(startRun 抛错、settle 成功/出错都删)。 */\r\n delete(parentSessionId: string, roleId: string): void\r\n}\r\n\r\nexport function createActiveRoutes(): ActiveRoutes {\r\n const map = new Map<string, DelegateRoute>()\r\n const key = (sessionId: string, roleId: string): string => `${sessionId}:${roleId}`\r\n return {\r\n set: (sessionId, roleId, route) => { map.set(key(sessionId, roleId), route) },\r\n get: (sessionId, roleId) => map.get(key(sessionId, roleId)),\r\n delete: (sessionId, roleId) => { map.delete(key(sessionId, roleId)) },\r\n }\r\n}\r\n","/** 委派路由持久存储域:子会话头部 chip 的数据源(schema 与 domain 布局的单一来源在本文件)。 */\r\nimport { z } from 'zod'\r\nimport { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'\r\n\r\n/** 一条持久化的委派路由记录。at = 写入时间戳(预留清理依据,暂无自动清理)。 */\r\nexport interface DelegationRouteRecord {\r\n provider: string\r\n model: string\r\n at: number\r\n}\r\n\r\nexport const DelegationRouteRecordSchema = z.object({\r\n provider: z.string(),\r\n model: z.string(),\r\n at: z.number(),\r\n})\r\n\r\n// 独立于 agentToolkitDomain(v1 布局不变):domain version 是格式版本,\r\n// 改既有域表结构会 version-mismatch 拒绝存量介质且无迁移。\r\nexport const delegationRoutesDomain = defineDomain({\r\n name: 'dsh_agent_toolkit_routes',\r\n version: 1,\r\n tables: {\r\n // key = childSessionId(本地 run 的 run.id 契约上即子 session id)\r\n routes: domainTable<string, DelegationRouteRecord>(DelegationRouteRecordSchema),\r\n },\r\n})\r\n","/** delegate RPC 端点:在途委派路由(运行中委派卡)+ 持久委派路由(子会话头部 chip)。 */\r\nimport type { IncomingMessage, ServerResponse } from 'node:http'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { json } from '../shared/http.ts'\r\nimport { registerOptionalRoutes } from '../shared/webserver.ts'\r\nimport type { ActiveRoutes } from './active.ts'\r\nimport type { DelegationRouteRecord } from './routes.ts'\r\n\r\nexport interface DelegateApiDeps {\r\n readonly active: ActiveRoutes\r\n /** 持久路由表读面(KvTable.get 同步读)。 */\r\n readonly routes: { get(childSessionId: string): DelegationRouteRecord | undefined }\r\n}\r\n\r\nexport function createDelegateApiHandler(deps: DelegateApiDeps): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\r\n return async (req, res) => {\r\n const url = new URL(req.url ?? '/', 'http://127.0.0.1')\r\n const sub = url.pathname.replace(/^\\/dsh-agent-toolkit\\/api/, '') || '/'\r\n if (req.method !== 'GET') {\r\n json(res, 405, { error: 'method not allowed' })\r\n return\r\n }\r\n if (sub === '/delegate/active') {\r\n const route = deps.active.get(url.searchParams.get('session') ?? '', url.searchParams.get('role') ?? '')\r\n if (route === undefined) {\r\n json(res, 404, { error: 'not found' })\r\n return\r\n }\r\n json(res, 200, { provider: route.provider, model: route.model })\r\n return\r\n }\r\n if (sub === '/delegate/route') {\r\n const record = deps.routes.get(url.searchParams.get('session') ?? '')\r\n if (record === undefined) {\r\n json(res, 404, { error: 'not found' })\r\n return\r\n }\r\n json(res, 200, { provider: record.provider, model: record.model })\r\n return\r\n }\r\n json(res, 404, { error: 'not found' })\r\n }\r\n}\r\n\r\n/**\r\n * 注册 delegate 路由(恒启用,与 agents 同策略)。webServer 为可选服务:\r\n * 缺席时经 registerOptionalRoutes 惰性不注册。prefix 先于 /api 兜底前缀命中。\r\n */\r\nexport function setupDelegateApi(ctx: Context, deps: DelegateApiDeps): void {\r\n const handler = createDelegateApiHandler(deps)\r\n registerOptionalRoutes(ctx, (webCtx) => {\r\n const unregister = webCtx.webServer.register({ kind: 'prefix', path: '/dsh-agent-toolkit/api/delegate', handler })\r\n return () => unregister()\r\n })\r\n}\r\n","/** Agents RPC 端点组:注册表 CRUD + providers/models 级联 + 工具名列表。核心恒启用(不随 feishu 门控)。 */\r\nimport type { IncomingMessage, ServerResponse } from 'node:http'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { json, readJsonBody } from '../shared/http.ts'\r\nimport { registerOptionalRoutes } from '../shared/webserver.ts'\r\nimport { AgentRecordSchema } from './store.ts'\r\nimport type { AgentRegistry } from './registry.ts'\r\n\r\n/** 一个可选的 provider 路由(id = agentOptions.provider 的值)。 */\r\nexport interface ProviderOption { id: string; name: string }\r\n/** 一个可选的模型条目(id = agentOptions.model 的值)。 */\r\nexport interface ModelOption { id: string; name: string }\r\n\r\nexport interface AgentsApiDeps {\r\n registry: AgentRegistry\r\n listTools(): string[]\r\n /** 团队 preset 工具面(tool-catalog 动态枚举,含回退)。 */\r\n listPresetTools(): Promise<string[]>\r\n listProviders(): ProviderOption[]\r\n /** 失败由调用方(路由)兜底为空数组,不抛错。 */\r\n listModels(provider: string): Promise<ModelOption[]>\r\n}\r\n\r\nexport function createAgentsApiHandler(deps: AgentsApiDeps): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\r\n return async (req, res) => {\r\n const url = new URL(req.url ?? '/', 'http://127.0.0.1')\r\n const sub = url.pathname.replace(/^\\/dsh-agent-toolkit\\/api/, '') || '/'\r\n const method = req.method ?? 'GET'\r\n\r\n if (sub === '/agents' && method === 'GET') {\r\n json(res, 200, deps.registry.list())\r\n return\r\n }\r\n\r\n if (sub === '/tools' && method === 'GET') {\r\n // 分组名册:preset = agent-team standing 面动态枚举(缺席回退常量),global = 顶层注册表。\r\n json(res, 200, { preset: await deps.listPresetTools(), global: deps.listTools() })\r\n return\r\n }\r\n\r\n if (sub === '/providers' && method === 'GET') {\r\n json(res, 200, deps.listProviders())\r\n return\r\n }\r\n\r\n const modelsMatch = /^\\/providers\\/([^/]+)\\/models$/.exec(sub)\r\n if (modelsMatch !== null && method === 'GET') {\r\n // 模型列举可能走网络(adapter 探测),失败静默降级为空数组。\r\n let models: ModelOption[] = []\r\n try {\r\n models = await deps.listModels(decodeURIComponent(modelsMatch[1]))\r\n } catch {\r\n models = []\r\n }\r\n json(res, 200, models)\r\n return\r\n }\r\n\r\n const agentMatch = /^\\/agents\\/([^/]+)$/.exec(sub)\r\n if (agentMatch !== null) {\r\n const id = decodeURIComponent(agentMatch[1])\r\n\r\n if (method === 'PUT') {\r\n const body = await readJsonBody(req, res)\r\n if (body === undefined) return\r\n // builtin 是服务端保留字段:剥离客户端携带值(防经 PUT 自创不可删记录),\r\n // id 以资源路径为准(覆盖 body.id),保证一致性。\r\n const bodyRecord: Record<string, unknown> = { ...(body as Record<string, unknown>) }\r\n delete bodyRecord.builtin\r\n const candidate: Record<string, unknown> = { ...bodyRecord, id }\r\n // 服务端保留字段回填:builtin 由既有记录决定(客户端不携带),否则 registry 的\r\n // \"内置标记不可修改\" 守卫会让所有内置角色/主 Agent 的配置编辑必然 409。\r\n const existing = deps.registry.get(id)\r\n if (existing?.builtin === true) candidate.builtin = true\r\n const parsed = AgentRecordSchema.safeParse(candidate)\r\n if (!parsed.success) {\r\n json(res, 400, { error: parsed.error.issues[0]?.message ?? 'invalid agent record' })\r\n return\r\n }\r\n try {\r\n await deps.registry.upsert(parsed.data)\r\n } catch (error) {\r\n json(res, 409, { error: error instanceof Error ? error.message : String(error) })\r\n return\r\n }\r\n json(res, 200, { ok: true })\r\n return\r\n }\r\n\r\n if (method === 'DELETE') {\r\n if (deps.registry.get(id) === undefined) {\r\n json(res, 404, { error: `agent \"${id}\" 不存在` })\r\n return\r\n }\r\n try {\r\n await deps.registry.remove(id)\r\n } catch (error) {\r\n json(res, 409, { error: error instanceof Error ? error.message : String(error) })\r\n return\r\n }\r\n json(res, 200, { ok: true })\r\n return\r\n }\r\n\r\n json(res, 405, { error: 'method not allowed' })\r\n return\r\n }\r\n\r\n if (['/agents', '/providers', '/tools'].some((p) => sub === p || sub.startsWith(`${p}/`))) {\r\n json(res, 405, { error: 'method not allowed' })\r\n return\r\n }\r\n json(res, 404, { error: 'not found' })\r\n }\r\n}\r\n\r\n/**\r\n * 注册 agents 核心 RPC 路由(恒启用,不随 modules.feishu 门控——Agents 面板总是挂载,\r\n * 这些端点缺失即「加载失败」)。webServer 为可选服务:缺席时经 registerOptionalRoutes\r\n * 惰性不注册。挂载点与 bots 同处 /dsh-agent-toolkit/api 前缀,但按路径空间拆成独立\r\n * prefix/exact 条目(webServer 精确先于最长前缀),互不重叠:\r\n * - prefix /dsh-agent-toolkit/api/agents → /agents 与 /agents/:id\r\n * - prefix /dsh-agent-toolkit/api/providers → /providers 与 /providers/:p/models\r\n * - exact /dsh-agent-toolkit/api/tools\r\n * - prefix /dsh-agent-toolkit/api → 兜底:api 前缀下未被更具体路由(bots/usage)\r\n * 认领的未知路径仍回 404 JSON(与旧统一分发行为字节一致)。\r\n */\r\nexport function setupAgentsApi(ctx: Context, deps: AgentsApiDeps): void {\r\n const handler = createAgentsApiHandler(deps)\r\n registerOptionalRoutes(ctx, (webCtx) => {\r\n const dispose = [\r\n webCtx.webServer.register({ kind: 'prefix', path: '/dsh-agent-toolkit/api/agents', handler }),\r\n webCtx.webServer.register({ kind: 'prefix', path: '/dsh-agent-toolkit/api/providers', handler }),\r\n webCtx.webServer.register({ kind: 'exact', path: '/dsh-agent-toolkit/api/tools', handler }),\r\n webCtx.webServer.register({ kind: 'prefix', path: '/dsh-agent-toolkit/api', handler }),\r\n ]\r\n return () => dispose.forEach((unregister) => unregister())\r\n })\r\n}\r\n","/**\r\n * /create-agent 命令:返回引导文本驱动主 Agent 完成\r\n * 「访谈澄清 → 推荐配置 → 用户确认 → 复用面板 HTTP API 落库」全流程。\r\n * 设计:docs/superpowers/specs/archive/2026-09-02-create-agent-command-design.md\r\n */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { createUserMessage } from '@deepseek-ai/dsh-llm'\r\nimport type { AgentRegistry } from './registry.ts'\r\n\r\n/** buildCreateAgentGuidance 的输入。 */\r\nexport interface CreateAgentGuidanceInput {\r\n /** 命令行内联需求(已 trim,可空串)。 */\r\n requirement: string\r\n /** 现有 Agent id 列表(含 main),不可复用。 */\r\n agentIds: string[]\r\n /** 团队 preset 工具名(动态名册)。 */\r\n presetTools: string[]\r\n /** 顶层注册表全局工具名。 */\r\n globalTools: string[]\r\n /** web 宿主回环 origin(如 http://127.0.0.1:3080);undefined = headless/CLI 降级。 */\r\n origin: string | undefined\r\n}\r\n\r\n/** 拼装 /create-agent 的引导文本(模型面契约,文案为规格锁定内容)。 */\r\nexport function buildCreateAgentGuidance(input: CreateAgentGuidanceInput): string {\r\n const lines: string[] = [\r\n '# 交互式创建 Agent 团队成员',\r\n '',\r\n '## 工作流(三步)',\r\n '1. 澄清需求:需求不明确时用 ask_user_question 向用户提问,整个流程提问总次数不超过 5 次,不重复问已确认的信息;',\r\n '2. 生成推荐并请用户确认:推荐 id / name / description / persona / tools 五个字段(id 是团队内唯一标识,name 是显示名,description 是职责一句话描述,persona 是系统提示词个性段,tools 是工具白名单);',\r\n '3. 迭代:用户有修改意见时按意见修订名称、描述、个性和工具后再次确认,直到用户明确确认。',\r\n ]\r\n if (input.requirement !== '') {\r\n lines.push(\r\n '',\r\n '## 用户初始需求',\r\n `用户已在命令中提供初始需求:「${input.requirement}」。请据此减少提问轮次,仅就不明确的点提问。`,\r\n )\r\n }\r\n lines.push(\r\n '',\r\n '## 现有 Agent id(不可复用)',\r\n input.agentIds.join(', '),\r\n 'id 规则:小写字母开头,仅含小写字母/数字/连字符([a-z0-9-]),最长 32 字符。',\r\n '',\r\n '## 可用工具清单',\r\n `团队 preset 工具:${input.presetTools.join(', ')}`,\r\n `全局工具:${input.globalTools.join(', ')}`,\r\n '省略 tools 字段表示不限制(Agent 可使用全部工具)。一旦给出白名单,该 Agent 只有列出的工具可用:通常应保留 read/glob/grep/shell 等基础工具,否则失去读文件/搜索/执行命令等基本能力(最终取舍按需求判断,如只读角色可去掉 write/edit)。',\r\n )\r\n if (input.origin === undefined) {\r\n lines.push(\r\n '',\r\n '## 落库',\r\n '当前宿主无 web 服务,无法自动落库。用户确认推荐后,请把最终配置完整输出给用户,并提示其打开 Agents 面板按推荐内容手动创建。',\r\n )\r\n } else {\r\n lines.push(\r\n '',\r\n '## 落库(用户明确确认后执行)',\r\n '用你的 shell 工具调用 Agents 面板同一 HTTP 端点完成创建:',\r\n `1. 先 GET ${input.origin}/dsh-agent-toolkit/api/agents 复核所选 id 仍未被占用;`,\r\n `2. 再 PUT ${input.origin}/dsh-agent-toolkit/api/agents/<id>,请求体为 JSON(不要在 body 中携带 id 或 builtin 字段):`,\r\n ' {\"name\":\"...\",\"description\":\"...\",\"persona\":\"...\",\"tools\":{\"allow\":[\"...\"]}}',\r\n ' (description/persona/tools 均可省略;省略 tools 表示不限制)',\r\n '3. curl 示例(Windows 的 pwsh 里用 curl.exe):',\r\n ` curl.exe -s -X PUT \"${input.origin}/dsh-agent-toolkit/api/agents/<id>\" -H \"Content-Type: application/json\" -d \"{\\\\\"name\\\\\":\\\\\"...\\\\\"}\"`,\r\n `4. 返回 200 后必须再 GET ${input.origin}/dsh-agent-toolkit/api/agents,在返回列表中找到该 id 的记录,把它的 name/description/persona/tools 关键字段展示给用户,作为落库证据;`,\r\n '5. 落库成功后告知用户可在 Agents 面板查看、并可被 team_delegate 委派;任一步返回 4xx 则把错误信息展示给用户,修正后重试。',\r\n )\r\n }\r\n return lines.join('\\n')\r\n}\r\n\r\n/** setupCreateAgentCommand 的依赖。 */\r\nexport interface CreateAgentCommandDeps {\r\n registry: AgentRegistry\r\n listTools(): string[]\r\n listPresetTools(): Promise<string[]>\r\n}\r\n\r\n/**\r\n * 注册 /create-agent。webServer 为可选服务按仓库规则经 ctx.get 读取(不进 inject),\r\n * 缺席(headless/CLI)时 origin 为 undefined,引导文本落库节降级为手动创建指引。\r\n *\r\n * 命令结果(command/done)是 log-only、不进模型:引导文本必须经 agent.followup\r\n * 投递为 user 消息驱动主 Agent(与 channels/inbound.ts 同一机制),命令卡只回执短文案。\r\n */\r\nexport function setupCreateAgentCommand(ctx: Context, deps: CreateAgentCommandDeps): void {\r\n ctx.commands.register({\r\n name: 'create-agent',\r\n description: '交互式创建 Agent 团队成员:访谈澄清需求 → 推荐配置 → 确认后经面板 API 落库',\r\n input: { hint: '初始需求描述,可空' },\r\n handler: async ({ rawInput, agent }: { rawInput: string; agent: { followup(message: unknown): void } }) => {\r\n const webServer = ctx.get('webServer') as { port: number } | undefined\r\n const origin = webServer === undefined ? undefined : `http://127.0.0.1:${webServer.port}`\r\n const text = buildCreateAgentGuidance({\r\n requirement: rawInput.trim(),\r\n agentIds: deps.registry.list().map((agent) => agent.id),\r\n presetTools: await deps.listPresetTools(),\r\n globalTools: deps.listTools(),\r\n origin,\r\n })\r\n // source 用 kind 'user'(与 ACP/inbound 先例一致):命令由用户敲入,引导消息即用户发起。\r\n agent.followup(createUserMessage({\r\n content: [{ type: 'text', text }],\r\n source: { kind: 'user' },\r\n }))\r\n return { kind: 'success', text: '已向主 Agent 发出创建 Agent 引导,请继续对话完成访谈与确认。' }\r\n },\r\n })\r\n}\r\n","/** agent 创建/恢复的作用域组合:加入作用域组合(preset 或基础工具 standing scope 回退)→ persona/tools 创作期注入。\r\n * hooks.tools 先与该会话真实可见面求交(warn-drop 未知名)——同一白名单同时喂委派 toolFilter(父 preset 面)\r\n * 与 bot 会话(agent-bot 面),求交消除两条路径的有效性不对称。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\n// type-only 激活 dsh-system-prompt / dsh-tools 对 cordis Context 的声明合并(agentCtx.systemPrompt / agentCtx.tools)。\r\nimport type {} from '@deepseek-ai/dsh-system-prompt'\r\nimport type {} from '@deepseek-ai/dsh-tools'\r\nimport { scopeOf } from '@deepseek-ai/dsh-scope'\r\nimport { RUN_CODE_NAME } from '@deepseek-ai/dsh-tools'\r\nimport type { AgentHooks } from './ports.ts'\r\nimport type { ScopeJoiner } from './scope-joiner.ts'\r\n\r\n/** bot 会话角色 persona 的 scoped 段名:与全局 persona 层同名,scoped 注册即 shadow 覆盖主 Agent persona。 */\r\nexport const TOOLKIT_PERSONA_SECTION = 'prompt-stack:persona'\r\n\r\n/**\r\n * 组合 agent 作用域:先把 agent scope 父链挂到基础工具行 standing scope(工具成为\r\n * 继承面),再叠 bot 的 persona 与 tools 白名单。\r\n * 顺序敏感:restrict 必须在 join 之后——宿主 tools.restrict() 只校验并过滤继承面\r\n * (global + 祖先 scope 层),own 层(agentCtx 直接挂载)的名字既不可 restrict 也\r\n * 不受 restrict 影响,直接挂进 agentCtx 的白名单会抛 unknown global tools。\r\n */\r\nexport async function setupAgentScope(\r\n agentCtx: Context,\r\n hooks: AgentHooks,\r\n joiner: ScopeJoiner,\r\n): Promise<void> {\r\n await joiner.join(agentCtx)\r\n if (hooks.persona !== undefined) {\r\n agentCtx.systemPrompt.section({ name: TOOLKIT_PERSONA_SECTION, order: 10, text: hooks.persona })\r\n }\r\n if (hooks.sections !== undefined) {\r\n for (const section of hooks.sections) {\r\n agentCtx.systemPrompt.section({ name: section.name, order: section.order, text: section.text })\r\n }\r\n }\r\n if (hooks.tools !== undefined) {\r\n // 求交:join 后的 scoped schemas = global + 祖先层(preset standing 或 BASIC_TOOLS\r\n // fallback standing),正是 restrict 的合法命名空间;未知名 warn-drop 而非抛错,\r\n // 使同一角色白名单在委派(父 preset 面)与 bot(agent-bot 面)两条路径都安全。\r\n const visible = new Set(agentCtx.tools.schemas(scopeOf(agentCtx)).map((s) => s.name)\r\n .filter((n) => n !== RUN_CODE_NAME))\r\n const effective = hooks.tools.filter((n) => visible.has(n))\r\n const dropped = hooks.tools.filter((n) => !visible.has(n))\r\n if (dropped.length > 0) {\r\n agentCtx.logger.warn(`dsh-agent-toolkit: 工具白名单含本会话不可见工具,已忽略:${dropped.join(', ')}`)\r\n }\r\n if (effective.length === 0) {\r\n throw new Error(`dsh-agent-toolkit: 工具白名单求交后为空(原 ${hooks.tools.length} 个均不可见):${hooks.tools.join(', ')}`)\r\n }\r\n agentCtx.tools.restrict({ allow: effective })\r\n }\r\n}\r\n","/** AgentsPort 真实适配器工厂(bots Router 与 schedule 执行器共用):create/resume 经 setupAgentScope 装配,\r\n * sessionId 记入 ownedSessions(插件自有会话集合,cron_* 工具注册门控据此排除 bot/schedule 会话)。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { SessionId } from '@deepseek-ai/dsh-session'\r\nimport type { AgentHandle } from '@deepseek-ai/dsh-agent'\r\nimport { setupAgentScope } from './agent-setup.ts'\r\nimport type { AgentPort, AgentsPort } from './ports.ts'\r\nimport type { ScopeJoiner } from './scope-joiner.ts'\r\n\r\nexport function createAgentsPort(ctx: Context, joiner: ScopeJoiner, ownedSessions?: Set<string>): AgentsPort {\r\n function adaptAgent(handle: AgentHandle): AgentPort {\r\n const { agent } = handle\r\n return {\r\n sessionId: String(agent.id),\r\n followup: (message) => agent.followup(message as Parameters<typeof agent.followup>[0]),\r\n cancel: () => agent.cancel({ kind: 'user' }),\r\n whenIdle: () => agent.whenIdle(),\r\n }\r\n }\r\n return {\r\n async create(input) {\r\n ownedSessions?.add(input.sessionId)\r\n const handle: AgentHandle = await ctx.agents.create({\r\n sessionId: SessionId(input.sessionId),\r\n meta: { cwd: input.cwd },\r\n ...(input.agentOptions !== undefined ? { agentOptions: input.agentOptions } : {}),\r\n setup: (agentCtx) => setupAgentScope(agentCtx, input.hooks, joiner),\r\n })\r\n return adaptAgent(handle)\r\n },\r\n async resume(input) {\r\n ownedSessions?.add(input.sessionId)\r\n const handle: AgentHandle = await ctx.agents.resume({\r\n resumeSessionId: SessionId(input.sessionId),\r\n ...(input.agentOptions !== undefined ? { agentOptions: input.agentOptions } : {}),\r\n setup: (agentCtx) => setupAgentScope(agentCtx, input.hooks, joiner),\r\n })\r\n return adaptAgent(handle)\r\n },\r\n }\r\n}\r\n","/** 飞书 OpenAPI 的结构化端口:reply/channel 只依赖本接口,SDK 类型不外泄。 */\r\nimport type * as lark from '@larksuiteoapi/node-sdk'\r\nimport type { InboundImage } from '../channel.ts'\r\n\r\nexport interface FeishuApi {\r\n createCard(cardJson: string): Promise<string>\r\n sendCardMessage(chatId: string, cardId: string): Promise<void>\r\n updateCardElement(cardId: string, elementId: string, content: string, sequence: number): Promise<void>\r\n insertElement(cardId: string, elementJson: string, targetElementId: string, sequence: number): Promise<void>\r\n setCardStreaming(cardId: string, streaming: boolean, sequence: number, summary?: string): Promise<void>\r\n replaceCard(cardId: string, cardJson: string, sequence: number): Promise<void>\r\n sendText(chatId: string, text: string): Promise<void>\r\n addReaction(messageId: string, emojiType: string): Promise<string>\r\n removeReaction(messageId: string, reactionId: string): Promise<void>\r\n /** 下载消息内图片资源(im/v1 resources,type=image);媒体类型按魔数判定、响应头兜底。 */\r\n downloadImage(messageId: string, fileKey: string): Promise<InboundImage>\r\n /** 本机器人的 open_id(bot/v3/info);群消息 @ 身份校验用。 */\r\n getBotOpenId(): Promise<string>\r\n}\r\n\r\n/** 从 lark SDK 抛出的 axios 错误提取飞书业务错误码(无则 undefined)。 */\r\nexport function feishuErrorCode(error: unknown): number | undefined {\r\n const data = (error as { response?: { data?: unknown } } | null | undefined)?.response?.data\r\n if (typeof data !== 'object' || data === null) return undefined\r\n const code = (data as { code?: unknown }).code\r\n return typeof code === 'number' ? code : undefined\r\n}\r\n\r\n/** 附件服务接受的图片媒体类型(与宿主 attachment v1 一致)。 */\r\nconst IMAGE_MEDIA_TYPES = ['image/png', 'image/jpeg', 'image/webp', 'image/gif'] as const\r\nexport type SniffedImageMediaType = (typeof IMAGE_MEDIA_TYPES)[number]\r\n\r\n/** 按魔数判定图片媒体类型;未知字节时回退响应头 content-type(限接受集合),否则 undefined。 */\r\nexport function sniffImageMediaType(data: Uint8Array, contentType?: unknown): SniffedImageMediaType | undefined {\r\n if (data.length >= 4 && data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4e && data[3] === 0x47) return 'image/png'\r\n if (data.length >= 3 && data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff) return 'image/jpeg'\r\n if (data.length >= 4 && data[0] === 0x47 && data[1] === 0x49 && data[2] === 0x46 && data[3] === 0x38) return 'image/gif'\r\n if (data.length >= 12\r\n && data[0] === 0x52 && data[1] === 0x49 && data[2] === 0x46 && data[3] === 0x46\r\n && data[8] === 0x57 && data[9] === 0x45 && data[10] === 0x42 && data[11] === 0x50) return 'image/webp'\r\n const declared = typeof contentType === 'string' ? contentType.split(';')[0]!.trim().toLowerCase() : ''\r\n return (IMAGE_MEDIA_TYPES as readonly string[]).includes(declared)\r\n ? declared as SniffedImageMediaType\r\n : undefined\r\n}\r\n\r\n/** SDK 薄封装:tenant_access_token 由 SDK 自动管理;错误带 code/msg 上下文。 */\r\nexport function createFeishuApi(client: lark.Client): FeishuApi {\r\n return {\r\n async createCard(cardJson) {\r\n const res = await client.cardkit.v1.card.create({ data: { type: 'card_json', data: cardJson } })\r\n const cardId = res.data?.card_id\r\n if (typeof cardId !== 'string' || cardId.length === 0) {\r\n throw new Error(`cardkit 建卡失败:code=${res.code} msg=${res.msg}`)\r\n }\r\n return cardId\r\n },\r\n async sendCardMessage(chatId, cardId) {\r\n await client.im.message.create({\r\n params: { receive_id_type: 'chat_id' },\r\n data: { receive_id: chatId, msg_type: 'interactive', content: JSON.stringify({ type: 'card', data: { card_id: cardId } }) },\r\n })\r\n },\r\n async updateCardElement(cardId, elementId, content, sequence) {\r\n await client.cardkit.v1.cardElement.content({ path: { card_id: cardId, element_id: elementId }, data: { content, sequence } })\r\n },\r\n async insertElement(cardId, elementJson, targetElementId, sequence) {\r\n await client.cardkit.v1.cardElement.create({\r\n path: { card_id: cardId },\r\n data: { type: 'insert_before', target_element_id: targetElementId, elements: `[${elementJson}]`, sequence },\r\n })\r\n },\r\n async setCardStreaming(cardId, streaming, sequence, summary) {\r\n await client.cardkit.v1.card.settings({\r\n path: { card_id: cardId },\r\n data: {\r\n settings: JSON.stringify({\r\n config: {\r\n streaming_mode: streaming,\r\n ...(summary !== undefined ? { summary: { content: summary } } : {}),\r\n },\r\n }),\r\n sequence,\r\n },\r\n })\r\n },\r\n async replaceCard(cardId, cardJson, sequence) {\r\n await client.cardkit.v1.card.update({ path: { card_id: cardId }, data: { card: { type: 'card_json', data: cardJson }, sequence } })\r\n },\r\n async sendText(chatId, text) {\r\n await client.im.message.create({\r\n params: { receive_id_type: 'chat_id' },\r\n data: { receive_id: chatId, msg_type: 'text', content: JSON.stringify({ text }) },\r\n })\r\n },\r\n async addReaction(messageId, emojiType) {\r\n const res = await client.im.messageReaction.create({\r\n path: { message_id: messageId },\r\n data: { reaction_type: { emoji_type: emojiType } },\r\n })\r\n const reactionId = res.data?.reaction_id\r\n if (typeof reactionId !== 'string') throw new Error(`加表情失败:code=${res.code} msg=${res.msg}`)\r\n return reactionId\r\n },\r\n async removeReaction(messageId, reactionId) {\r\n await client.im.messageReaction.delete({ path: { message_id: messageId, reaction_id: reactionId } })\r\n },\r\n async downloadImage(messageId, fileKey) {\r\n const res = await client.im.messageResource.get({\r\n params: { type: 'image' },\r\n path: { message_id: messageId, file_key: fileKey },\r\n })\r\n const chunks: Buffer[] = []\r\n await new Promise<void>((resolve, reject) => {\r\n const stream = res.getReadableStream()\r\n stream.on('data', (chunk) => { chunks.push(chunk as Buffer) })\r\n stream.on('end', () => resolve())\r\n stream.on('error', (error) => reject(error instanceof Error ? error : new Error(String(error))))\r\n })\r\n const data = new Uint8Array(Buffer.concat(chunks))\r\n const mediaType = sniffImageMediaType(data, res.headers?.['content-type'])\r\n if (mediaType === undefined) {\r\n throw new Error(`图片资源格式不受支持(file_key=${fileKey},content-type=${String(res.headers?.['content-type'] ?? '未知')})`)\r\n }\r\n return { data, mediaType }\r\n },\r\n async getBotOpenId() {\r\n // bot/v3/info 无 SDK 类型化方法,走通用 request;响应顶层挂 bot(非 data.bot)。\r\n const res = await client.request<{ code?: number; msg?: string; bot?: { open_id?: unknown } }>({\r\n method: 'GET',\r\n url: 'https://open.feishu.cn/open-apis/bot/v3/info',\r\n })\r\n const openId = res.bot?.open_id\r\n if (typeof openId !== 'string' || openId.length === 0) {\r\n throw new Error(`获取机器人信息失败:code=${res.code} msg=${res.msg}`)\r\n }\r\n return openId\r\n },\r\n }\r\n}\r\n","/** 飞书内的运维文本指令(不走模型)。 */\r\nexport type Directive = 'new' | 'stop' | 'status'\r\n\r\n/** 仅当整条消息就是一个指令时命中;带参数/前后文的按普通消息处理。 */\r\nexport function parseDirective(text: string): Directive | null {\r\n const t = text.trim().toLowerCase()\r\n if (t === '/new') return 'new'\r\n if (t === '/stop') return 'stop'\r\n if (t === '/status') return 'status'\r\n return null\r\n}\r\n\r\n/** 群消息正文中的 @ 占位符(@_user_1 等)剥掉,得到纯净指令文本。 */\r\nexport function stripMentionPlaceholders(text: string): string {\r\n return text.replace(/@_user_\\d+\\s*/g, '').trim()\r\n}\r\n","/** im.message.receive_v1 事件解析:窄化为渠道无关的 ParsedMessage;message_id 去重。 */\r\nimport { stripMentionPlaceholders } from '../directive.ts'\r\n\r\nexport interface ParsedMessage {\r\n messageId: string\r\n chatId: string\r\n chatType: 'p2p' | 'group'\r\n userId: string\r\n text: string\r\n /** 消息携带的图片 key(post 富文本节点与 image 消息),按出现顺序;文本下载经渠道懒加载。 */\r\n imageKeys: readonly string[]\r\n}\r\n\r\ninterface RawEvent {\r\n sender?: { sender_type?: unknown; sender_id?: { open_id?: unknown } }\r\n message?: {\r\n message_id?: unknown\r\n chat_id?: unknown\r\n chat_type?: unknown\r\n message_type?: unknown\r\n content?: unknown\r\n mentions?: readonly { mentioned_type?: unknown; id?: { open_id?: unknown } }[]\r\n }\r\n}\r\n\r\n/** post 富文本节点:text/a 取文本,img 收 image_key,at(@占位)与其余标签跳过。 */\r\ninterface PostNode {\r\n tag?: unknown\r\n text?: unknown\r\n image_key?: unknown\r\n}\r\n\r\n/** 从 post content(段落数组)抽取文本与图片 key;段落间以换行连接。 */\r\nfunction parsePostContent(content: string): { text: string; imageKeys: string[] } {\r\n const imageKeys: string[] = []\r\n const paragraphs: string[] = []\r\n try {\r\n const parsed = JSON.parse(content) as { content?: unknown }\r\n const list = Array.isArray(parsed.content) ? parsed.content : []\r\n for (const paragraph of list) {\r\n if (!Array.isArray(paragraph)) continue\r\n const parts: string[] = []\r\n for (const node of paragraph as PostNode[]) {\r\n if (node === null || typeof node !== 'object') continue\r\n if (node.tag === 'img') {\r\n if (typeof node.image_key === 'string' && node.image_key.length > 0) imageKeys.push(node.image_key)\r\n } else if ((node.tag === 'text' || node.tag === 'a') && typeof node.text === 'string') {\r\n parts.push(node.text)\r\n }\r\n }\r\n paragraphs.push(parts.join(''))\r\n }\r\n } catch {\r\n return { text: '', imageKeys: [] }\r\n }\r\n return { text: paragraphs.join('\\n'), imageKeys }\r\n}\r\n\r\n/**\r\n * SDK handler 收到的 data 即事件体(README 示例 `data.message` 直接解构);\r\n * 兼容包一层 { event } 的形态。过滤:机器人消息、非 text/post/image 类型、\r\n * 群内未 @机器人、无文本且无图片。\r\n * 群消息 @ 校验身份:mention 的 open_id 必须等于本机器人(应用若持全部群消息权限,\r\n * 会收到 @ 其他机器人的消息,不能误触发)。\r\n */\r\nexport function parseMessageEvent(data: unknown, botOpenId: string): ParsedMessage | null {\r\n const wrapped = data as { event?: RawEvent } & RawEvent\r\n const event: RawEvent = wrapped.event ?? wrapped\r\n if (event.sender?.sender_type !== 'user') return null\r\n const userId = event.sender.sender_id?.open_id\r\n const msg = event.message\r\n if (typeof userId !== 'string' || msg === undefined) return null\r\n if (msg.message_type !== 'text' && msg.message_type !== 'post' && msg.message_type !== 'image') return null\r\n if (typeof msg.content !== 'string') return null\r\n if (typeof msg.message_id !== 'string' || typeof msg.chat_id !== 'string') return null\r\n if (msg.chat_type !== 'p2p' && msg.chat_type !== 'group') return null\r\n if (msg.chat_type === 'group'\r\n && !(msg.mentions ?? []).some((m) => m.mentioned_type === 'bot' && m.id?.open_id === botOpenId)) return null\r\n\r\n let text = ''\r\n let imageKeys: string[] = []\r\n if (msg.message_type === 'text') {\r\n try {\r\n const parsed = JSON.parse(msg.content) as { text?: unknown }\r\n if (typeof parsed.text !== 'string') return null\r\n text = stripMentionPlaceholders(parsed.text)\r\n } catch {\r\n return null\r\n }\r\n } else if (msg.message_type === 'post') {\r\n const post = parsePostContent(msg.content)\r\n text = stripMentionPlaceholders(post.text)\r\n imageKeys = post.imageKeys\r\n } else {\r\n try {\r\n const parsed = JSON.parse(msg.content) as { image_key?: unknown }\r\n if (typeof parsed.image_key === 'string' && parsed.image_key.length > 0) imageKeys.push(parsed.image_key)\r\n } catch {\r\n return null\r\n }\r\n }\r\n if (text.length === 0 && imageKeys.length === 0) return null\r\n\r\n return { messageId: msg.message_id, chatId: msg.chat_id, chatType: msg.chat_type, userId, text, imageKeys }\r\n}\r\n\r\n/** message_id 去重(飞书会重推);FIFO 容量淘汰。 */\r\nexport class MessageDedup {\r\n private readonly seen = new Set<string>()\r\n private readonly order: string[] = []\r\n\r\n constructor(private readonly cap = 1000) {}\r\n\r\n /** true = 新消息。 */\r\n check(id: string): boolean {\r\n if (this.seen.has(id)) return false\r\n this.seen.add(id)\r\n this.order.push(id)\r\n if (this.order.length > this.cap) this.seen.delete(this.order.shift()!)\r\n return true\r\n }\r\n}\r\n","/** 飞书卡片纯函数:JSON 2.0 构建、UTF-8 字节切分、段序列流式操作规划(拆卡决策全在这里)。 */\r\nimport type { TurnSegment, TurnStatus } from '../channel.ts'\r\n\r\nexport type { TurnSegment }\r\n\r\nexport const STATUS_ELEMENT_ID = 'status'\r\n\r\n/** create 未返回真实 card_id 前的占位哨兵(executor 赋值;防并发 flush 重复建卡)。 */\r\nexport const PENDING_CARD_ID = '__pending__'\r\n\r\n/** 过程区截尾后的头部省略标记。 */\r\nexport const PROCESS_OMITTED = '…(已省略前文)\\n'\r\n\r\n/** 输出中状态行文案。 */\r\nconst STATUS_STREAMING = '⏳ 输出中…'\r\n\r\n/** 定格状态行文案。 */\r\nconst STATUS_FINAL: Record<TurnStatus, string> = {\r\n done: '✅ 输出完成',\r\n error: '❌ 输出出错',\r\n cancelled: '⏹ 已取消',\r\n}\r\n\r\n/** 拆卡定格状态行文案(旧卡内容已接续到下一张卡片)。 */\r\nexport const STATUS_CONTINUED = '📦 内容较长,已接续到下一张卡片'\r\n\r\n/** 单卡组件数安全上限(飞书硬上限 200;面板按 2 计:面板 + 内嵌 markdown)。 */\r\nconst CARD_ELEMENT_LIMIT = 190\r\n\r\n/** 按 UTF-8 字节上限截头(保留头部),不劈开多字节字符与代理对。 */\r\nexport function sliceByBytes(text: string, maxBytes: number): string {\r\n if (Buffer.byteLength(text, 'utf8') <= maxBytes) return text\r\n let lo = 0\r\n let hi = text.length\r\n while (lo < hi) {\r\n const mid = Math.ceil((lo + hi) / 2)\r\n if (Buffer.byteLength(text.slice(0, mid), 'utf8') <= maxBytes) lo = mid\r\n else hi = mid - 1\r\n }\r\n let cut = lo\r\n if (cut > 0) {\r\n const code = text.charCodeAt(cut - 1)\r\n if (code >= 0xd8_00 && code <= 0xdb_ff) cut -= 1 // 高位代理在末尾:整对移除\r\n }\r\n return text.slice(0, cut)\r\n}\r\n\r\n/** 按 UTF-8 字节上限截尾(保留尾部),不劈开多字节字符与代理对;截断时头部加省略标记。 */\r\nexport function sliceTailByBytes(text: string, maxBytes: number): string {\r\n if (Buffer.byteLength(text, 'utf8') <= maxBytes) return text\r\n const budget = maxBytes - Buffer.byteLength(PROCESS_OMITTED, 'utf8')\r\n if (budget <= 0) throw new Error(`processMaxBytes=${maxBytes} 过小,连省略标记都容纳不了`)\r\n let lo = 0\r\n let hi = text.length\r\n while (lo < hi) {\r\n const mid = Math.floor((lo + hi) / 2)\r\n if (Buffer.byteLength(text.slice(mid), 'utf8') <= budget) hi = mid\r\n else lo = mid + 1\r\n }\r\n let cut = lo\r\n if (cut < text.length) {\r\n const code = text.charCodeAt(cut)\r\n if (code >= 0xdc_00 && code <= 0xdf_ff) cut += 1 // 低位代理在开头:整对移除\r\n }\r\n return PROCESS_OMITTED + text.slice(cut)\r\n}\r\n\r\n/** JSON 串内内容的转义后字节数(去首尾引号);卡片 DSL 真实字节记账用。 */\r\nexport function escapedLen(s: string): number {\r\n return Buffer.byteLength(JSON.stringify(s), 'utf8') - 2\r\n}\r\n\r\n/** 按转义后字节上限截头(保留头部),不劈开多字节字符与代理对。 */\r\nexport function sliceByEscapedBytes(text: string, maxBytes: number): string {\r\n if (escapedLen(text) <= maxBytes) return text\r\n let lo = 0\r\n let hi = text.length\r\n while (lo < hi) {\r\n const mid = Math.ceil((lo + hi) / 2)\r\n if (escapedLen(text.slice(0, mid)) <= maxBytes) lo = mid\r\n else hi = mid - 1\r\n }\r\n let cut = lo\r\n if (cut > 0) {\r\n const code = text.charCodeAt(cut - 1)\r\n if (code >= 0xd8_00 && code <= 0xdb_ff) cut -= 1\r\n }\r\n return text.slice(0, cut)\r\n}\r\n\r\n/** 新卡:仅状态行的流式卡;段后续经插入组件 API 动态加入。 */\r\nexport function buildCardJson(printStep: number): string {\r\n return JSON.stringify({\r\n schema: '2.0',\r\n config: {\r\n streaming_mode: true,\r\n summary: { content: '生成中…' },\r\n streaming_config: { print_frequency_ms: { default: 70 }, print_step: { default: printStep }, print_strategy: 'fast' },\r\n },\r\n body: { elements: [{ tag: 'markdown', content: STATUS_STREAMING, element_id: STATUS_ELEMENT_ID }] },\r\n })\r\n}\r\n\r\n/** 段元素 JSON(insert op 负载):process = 默认收起折叠面板;text = 纯 markdown。 */\r\nexport function buildSegmentJson(kind: 'text' | 'process', elementId: string, content: string): string {\r\n if (kind === 'process') {\r\n return JSON.stringify({\r\n tag: 'collapsible_panel',\r\n expanded: false,\r\n header: { title: { tag: 'plain_text', content: '思考与工具调用过程' } },\r\n elements: [{ tag: 'markdown', content, element_id: elementId }],\r\n })\r\n }\r\n return JSON.stringify({ tag: 'markdown', content, element_id: elementId })\r\n}\r\n\r\nexport interface StreamState {\r\n /** 当前卡片 id(PENDING_CARD_ID = 创建中);null = 下一张卡待创建。 */\r\n cardId: string | null\r\n /** 当前卡片已消耗的 sequence 计数(create/send 不占)。 */\r\n seq: number\r\n /** 当前卡已提交内容字节数(段内容 + 固定开销合计)。 */\r\n cardBytes: number\r\n /** 当前卡组件数(含状态行;面板按 2 计)。 */\r\n cardElements: number\r\n /** 全局段计数(element_id 生成用,跨卡递增)。 */\r\n segCounter: number\r\n /** 已在历史卡封闭、不再关注的段数(段 0..closedSegCount-1)。 */\r\n closedSegCount: number\r\n /** 当前卡上打开的段(永远是最新的有内容段);base = 元素内容在该段 content 中的 char 起始偏移(process 恒 0)。 */\r\n tail: { segIndex: number; elementId: string; base: number; shownText: string } | undefined\r\n /** text 段跨卡续写基准(char offset into 该段 content)。 */\r\n carry: { segIndex: number; base: number } | undefined\r\n}\r\n\r\nexport const initialStreamState = (): StreamState => ({\r\n cardId: null, seq: 0, cardBytes: 0, cardElements: 0, segCounter: 0,\r\n closedSegCount: 0, tail: undefined, carry: undefined,\r\n})\r\n\r\nexport type CardOp =\r\n | { type: 'create'; cardJson: string }\r\n | { type: 'send' }\r\n | { type: 'insert'; elementJson: string; sequence: number }\r\n | { type: 'update'; elementId: string; content: string; sequence: number }\r\n | { type: 'settings'; streaming: boolean; sequence: number; summary?: string }\r\n | { type: 'noop' }\r\n\r\nexport interface PlannedOp {\r\n op: CardOp\r\n /** 该 op 成功后的状态迁移(快照整体替换)。 */\r\n commit: (s: StreamState) => StreamState\r\n}\r\n\r\n/** 把段序列的新增部分同步到卡片;新段 insert 到状态行之前,尾段增长走元素 update,满卡关流开续卡。 */\r\nexport function planSync(\r\n state: StreamState,\r\n segments: readonly TurnSegment[],\r\n maxBytes: number,\r\n processMaxBytes: number,\r\n printStep: number,\r\n): { ops: PlannedOp[] } {\r\n const ops: PlannedOp[] = []\r\n let { cardId, seq, cardBytes, cardElements, segCounter, closedSegCount, tail, carry } = state\r\n\r\n /** 约定:先改规划局部变量再 push——commit 捕获该 op 完成后的状态快照。 */\r\n const push = (op: CardOp): void => {\r\n const snap = { cardId, seq, cardBytes, cardElements, segCounter, closedSegCount, tail, carry }\r\n ops.push({ op, commit: () => ({ ...snap }) })\r\n }\r\n\r\n const ensureCard = (): void => {\r\n if (cardId !== null) return\r\n const cardJson = buildCardJson(printStep)\r\n cardId = PENDING_CARD_ID\r\n seq = 0\r\n cardBytes = Buffer.byteLength(cardJson, 'utf8') // 真实 DSL 字节\r\n cardElements = 1\r\n push({ type: 'create', cardJson })\r\n push({ type: 'send' })\r\n }\r\n\r\n const closeCard = (): void => {\r\n // 先定格状态行(流式还开着,组件 content API 需要流式模式),再关流 + summary。\r\n seq += 1\r\n push({ type: 'update', elementId: STATUS_ELEMENT_ID, content: STATUS_CONTINUED, sequence: seq })\r\n seq += 1\r\n cardId = null\r\n tail = undefined\r\n push({ type: 'settings', streaming: false, sequence: seq, summary: STATUS_CONTINUED })\r\n }\r\n\r\n let i = tail?.segIndex ?? closedSegCount\r\n while (i < segments.length) {\r\n const seg = segments[i]\r\n const content = seg.kind === 'process' ? sliceTailByBytes(seg.content, processMaxBytes) : seg.content\r\n const base = tail !== undefined && tail.segIndex === i\r\n ? tail.base\r\n : carry?.segIndex === i ? carry.base : 0\r\n const elementContent = seg.kind === 'text' ? content.slice(base) : content\r\n\r\n if (tail !== undefined && tail.segIndex === i) {\r\n // 当前卡上的打开段:内容增长走 update\r\n if (elementContent !== tail.shownText) {\r\n const delta = escapedLen(elementContent) - escapedLen(tail.shownText)\r\n if (cardBytes + delta <= maxBytes) {\r\n seq += 1\r\n cardBytes += delta\r\n tail = { ...tail, shownText: elementContent }\r\n push({ type: 'update', elementId: tail.elementId, content: elementContent, sequence: seq })\r\n } else if (seg.kind === 'text') {\r\n // 部分更新到满 → 拆卡,剩余经 carry 续写(预算按转义后字节)\r\n const piece = sliceByEscapedBytes(elementContent, escapedLen(tail.shownText) + (maxBytes - cardBytes))\r\n if (piece.length > tail.shownText.length) {\r\n seq += 1\r\n cardBytes += escapedLen(piece) - escapedLen(tail.shownText)\r\n tail = { ...tail, shownText: piece }\r\n push({ type: 'update', elementId: tail.elementId, content: piece, sequence: seq })\r\n }\r\n carry = { segIndex: i, base: tail.base + tail.shownText.length }\r\n closeCard()\r\n continue\r\n } else {\r\n // process:旧卡定格,续卡整窗重放\r\n closeCard()\r\n continue\r\n }\r\n }\r\n // 已完整同步:是最新段则保活收尾;有更新段则封闭前段\r\n if (i === segments.length - 1) break\r\n tail = undefined\r\n closedSegCount = i + 1\r\n carry = undefined\r\n i += 1\r\n continue\r\n }\r\n\r\n // 当前卡上还没有该段的元素 → insert\r\n if (seg.kind === 'process') {\r\n const elementId = `seg_${segCounter + 1}`\r\n const elementJson = buildSegmentJson('process', elementId, elementContent)\r\n const elBytes = Buffer.byteLength(elementJson, 'utf8')\r\n if (cardId !== null && (cardBytes + elBytes > maxBytes || cardElements + 2 > CARD_ELEMENT_LIMIT)) {\r\n closeCard()\r\n continue\r\n }\r\n ensureCard()\r\n // 过程窗口由 processMaxBytes 兜底(sliceTailByBytes 已截尾);新卡整窗插入,不再受卡预算约束。\r\n segCounter += 1\r\n seq += 1\r\n cardBytes += elBytes\r\n cardElements += 2\r\n tail = { segIndex: i, elementId, base: 0, shownText: elementContent }\r\n push({ type: 'insert', elementJson, sequence: seq })\r\n } else {\r\n if (elementContent.length === 0) { // 空 text 段不占卡\r\n closedSegCount = i + 1\r\n carry = undefined\r\n i += 1\r\n continue\r\n }\r\n if (cardId !== null && cardElements + 1 > CARD_ELEMENT_LIMIT) {\r\n closeCard()\r\n continue\r\n }\r\n ensureCard()\r\n const elementId = `seg_${segCounter + 1}`\r\n const overhead = Buffer.byteLength(buildSegmentJson('text', elementId, ''), 'utf8')\r\n const piece = sliceByEscapedBytes(elementContent, maxBytes - cardBytes - overhead)\r\n if (piece.length === 0) {\r\n throw new Error(`cardMaxBytes=${maxBytes} 过小,扣基础卡与元素开销后连一个字符都容纳不了`)\r\n }\r\n segCounter += 1\r\n const elementJson = buildSegmentJson('text', elementId, piece)\r\n seq += 1\r\n cardBytes += Buffer.byteLength(elementJson, 'utf8')\r\n cardElements += 1\r\n tail = { segIndex: i, elementId, base, shownText: piece }\r\n push({ type: 'insert', elementJson, sequence: seq })\r\n if (piece.length < elementContent.length) {\r\n carry = { segIndex: i, base: base + piece.length }\r\n closeCard()\r\n continue\r\n }\r\n }\r\n carry = undefined\r\n if (i === segments.length - 1) break\r\n tail = undefined\r\n closedSegCount = i + 1\r\n i += 1\r\n }\r\n // 段封闭/进位等纯状态推进也要交还执行侧:无 op 或末 op 之后状态仍有差异时补一个空操作 commit。\r\n // 简单起见:恒追加一个 no-op 规划项携带末态(执行侧对 type:'noop' 直接 commit,不调 API)。\r\n const snap = { cardId, seq, cardBytes, cardElements, segCounter, closedSegCount, tail, carry }\r\n ops.push({ op: { type: 'noop' }, commit: () => ({ ...snap }) })\r\n return { ops }\r\n}\r\n\r\n/** 定格:先 update 状态行(流式还开着),再关闭 + summary。 */\r\nexport function planFinalize(state: StreamState, status: TurnStatus): { ops: CardOp[] } {\r\n if (state.cardId === null) return { ops: [] }\r\n return {\r\n ops: [\r\n { type: 'update', elementId: STATUS_ELEMENT_ID, content: STATUS_FINAL[status], sequence: state.seq + 1 },\r\n { type: 'settings', streaming: false, sequence: state.seq + 2, summary: STATUS_FINAL[status] },\r\n ],\r\n }\r\n}\r\n","/** 出站句柄:turn 级流式卡片(确认式状态机 + 失败分类治理 + 拆卡定格)。 */\r\nimport type { ChannelTunables, Disposer, ReplyHandle, TurnSegment, TurnStatus } from '../channel.ts'\r\nimport { feishuErrorCode, type FeishuApi } from './api.ts'\r\nimport {\r\n initialStreamState, PENDING_CARD_ID, STATUS_ELEMENT_ID,\r\n planFinalize, planSync, type CardOp, type PlannedOp, type StreamState,\r\n} from './cards.ts'\r\n\r\n/** 指数退避重试(默认 3 次,300ms 起)。 */\r\nexport async function withRetry<T>(fn: () => Promise<T>, attempts = 3, baseDelayMs = 300): Promise<T> {\r\n let lastError: unknown\r\n for (let i = 0; i < attempts; i++) {\r\n try {\r\n return await fn()\r\n } catch (error) {\r\n lastError = error\r\n if (i < attempts - 1) await new Promise((resolve) => setTimeout(resolve, baseDelayMs * 2 ** i))\r\n }\r\n }\r\n throw lastError\r\n}\r\n\r\n/** 卡片输出异常时的用户提示(仅真实废弃一张已发卡时发送)。 */\r\nconst ABANDON_NOTICE = '⚠️ 卡片输出异常,已在新卡片继续;如有内容缺失请重发。'\r\n\r\n/** 单次 flush 内连续废弃换卡的上限(防异常死循环;超限抛给出站链日志)。 */\r\nconst MAX_ABANDON_PER_FLUSH = 3\r\n\r\nexport class FeishuReplyHandle implements ReplyHandle {\r\n private state: StreamState = initialStreamState()\r\n private segments: readonly TurnSegment[] = []\r\n private tail: Promise<unknown> = Promise.resolve()\r\n private timer: ReturnType<typeof setTimeout> | undefined\r\n private planQueued = false\r\n private finalized = false\r\n\r\n constructor(\r\n private readonly api: FeishuApi,\r\n private readonly chatId: string,\r\n private readonly tunables: ChannelTunables,\r\n private readonly log: (message: string) => void,\r\n ) {}\r\n\r\n beginTurn(): Promise<void> {\r\n return Promise.resolve()\r\n }\r\n\r\n update(segments: readonly TurnSegment[]): Promise<void> {\r\n if (this.finalized) return Promise.resolve()\r\n this.segments = segments\r\n if (this.timer === undefined) {\r\n this.timer = setTimeout(() => {\r\n this.timer = undefined\r\n this.flush()\r\n }, this.tunables.cardUpdateThrottleMs)\r\n }\r\n return Promise.resolve()\r\n }\r\n\r\n async finalize(status: TurnStatus, detail?: string): Promise<void> {\r\n if (this.finalized) {\r\n await this.tail\r\n return\r\n }\r\n this.finalized = true\r\n if (this.timer !== undefined) {\r\n clearTimeout(this.timer)\r\n this.timer = undefined\r\n }\r\n this.flush()\r\n // 等 flush 定局(含失败恢复)后再规划定格:状态此刻是已确认态。\r\n await this.tail\r\n const hadCard = this.state.cardId !== null\r\n const { ops } = planFinalize(this.state, status)\r\n // 定格批不触发废弃重规划(卡已在收尾):遇 abandon 直接止步。\r\n this.enqueue(async () => {\r\n for (const op of ops) {\r\n const outcome = await this.execOne({ op, commit: (s: StreamState) => s })\r\n if (outcome === 'abandoned') return\r\n }\r\n })\r\n if (!hadCard && detail !== undefined) {\r\n this.enqueue(() => withRetry(() => this.api.sendText(this.chatId, detail)).then(() => undefined))\r\n }\r\n await this.tail\r\n }\r\n\r\n notice(text: string): Promise<void> {\r\n this.enqueue(() => withRetry(() => this.api.sendText(this.chatId, text)).then(() => undefined))\r\n return this.tail.then(() => undefined)\r\n }\r\n\r\n /**\r\n * 规划入串行链:planSync 在执行点读最新已确认状态与最新 segments,\r\n * 在飞期间到达的 flush 只标位不重复规划(杜绝重复建卡/重复 insert)。\r\n */\r\n private flush(): void {\r\n if (this.planQueued) return\r\n this.planQueued = true\r\n this.enqueue(async () => {\r\n this.planQueued = false\r\n const { ops } = planSync(this.state, this.segments, this.tunables.cardMaxBytes, this.tunables.processMaxBytes, this.tunables.cardPrintStep)\r\n await this.exec(ops)\r\n })\r\n }\r\n\r\n /** 逐 op 确认执行;遇废弃从已确认状态重新规划续写(上限 MAX_ABANDON_PER_FLUSH 次)。 */\r\n private async exec(ops: readonly PlannedOp[]): Promise<void> {\r\n let pending = ops\r\n for (let attempts = 0; ; attempts++) {\r\n let abandoned = false\r\n for (const planned of pending) {\r\n if ((await this.execOne(planned)) === 'abandoned') {\r\n abandoned = true\r\n break\r\n }\r\n }\r\n if (!abandoned) return\r\n if (attempts >= MAX_ABANDON_PER_FLUSH) throw new Error('卡片连续废弃超限,本批输出放弃(下一 flush 继续)')\r\n pending = planSync(this.state, this.segments, this.tunables.cardMaxBytes, this.tunables.processMaxBytes, this.tunables.cardPrintStep).ops\r\n }\r\n }\r\n\r\n /**\r\n * 单个 op:成功(或 insert 300301 视同成功)才 commit;\r\n * 失败按错误码分类:流式超时重激活重放 / 200860 废弃续写 / 未知错误 seq+2 重放一次。\r\n */\r\n private async execOne(planned: PlannedOp): Promise<'ok' | 'abandoned'> {\r\n const { op } = planned\r\n if (op.type === 'noop') {\r\n this.commit(planned)\r\n return 'ok'\r\n }\r\n const liveCard = this.state.cardId !== null && this.state.cardId !== PENDING_CARD_ID\r\n try {\r\n await this.invokeThenCommit(planned)\r\n return 'ok'\r\n } catch (error) {\r\n // 建卡链路(尚无活卡):状态未推进,抛给出站链日志,下次 flush 自然重试。\r\n if (!liveCard) throw error\r\n const code = feishuErrorCode(error)\r\n if (op.type === 'insert' && code === 300301) {\r\n // 元素重复 = 服务端已执行(此前响应丢失),视同成功。\r\n this.commit(planned)\r\n return 'ok'\r\n }\r\n if (code === 200850 || code === 200510) {\r\n // 流式被平台超时自动关闭:重激活(占一个 sequence)后以新 sequence 重放一次。\r\n if (await this.reactivate()) {\r\n try {\r\n await this.invokeThenCommit(planned, this.state.seq + 1)\r\n return 'ok'\r\n } catch {\r\n return this.abandon('流式超时重激活后重放失败', true)\r\n }\r\n }\r\n return this.abandon('流式超时且重激活失败', true)\r\n }\r\n if (code === 200860) {\r\n // 确定性超限:op 未被应用。废弃换卡,从确认点续写(不重演已显示部分)。\r\n return this.abandon('卡片超出平台大小上限', false)\r\n }\r\n // 未知/网络错误(op 可能已执行):sequence 跳过可能已消耗的序号重放一次\r\n // (update/settings 幂等;insert 重演由 300301 兜底)。跳步按本次尝试的 sequence\r\n // 计(state.seq 是最后已确认序号,未包含本次尝试,用它 +2 会差一)。\r\n try {\r\n const retrySeq = (op.type === 'insert' || op.type === 'update' || op.type === 'settings' ? op.sequence : this.state.seq) + 2\r\n await this.invokeThenCommit(planned, retrySeq)\r\n return 'ok'\r\n } catch (retryError) {\r\n if (op.type === 'insert' && feishuErrorCode(retryError) === 300301) {\r\n this.commit(planned)\r\n return 'ok'\r\n }\r\n return this.abandon('卡片操作重放失败', true)\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 执行 API 并在成功后 commit;seqOverride 用于重放(create 的真实 cardId 在此覆盖进状态)。\r\n * 带序号 op 的发送/提交序号一律取 max(本次序号, 已确认 seq+1):重放/重激活会推高已确认 seq,\r\n * 批内后续 op 的规划序号可能落后,照发会以非递增序号碰撞(平台可能视作幂等 no-op 静默丢 op →\r\n * 定格/关流 op 消失 → 卡死「输出中」)。\r\n */\r\n private async invokeThenCommit(planned: PlannedOp, seqOverride?: number): Promise<void> {\r\n const effectiveSeq = effectiveSeqOf(planned.op, seqOverride, this.state.seq)\r\n const op = withSeq(planned.op, effectiveSeq)\r\n if (op.type === 'create') {\r\n const id = await withRetry(() => this.api.createCard(op.cardJson))\r\n this.state = { ...planned.commit(this.state), cardId: id }\r\n return\r\n }\r\n if (op.type === 'send') {\r\n await withRetry(() => this.api.sendCardMessage(this.chatId, this.state.cardId!))\r\n } else if (op.type === 'insert') {\r\n await this.api.insertElement(this.state.cardId!, op.elementJson, STATUS_ELEMENT_ID, op.sequence)\r\n } else if (op.type === 'update') {\r\n await this.api.updateCardElement(this.state.cardId!, op.elementId, op.content, op.sequence)\r\n } else if (op.type === 'settings') {\r\n await this.api.setCardStreaming(this.state.cardId!, op.streaming, op.sequence, op.summary)\r\n }\r\n this.commit(planned, effectiveSeq)\r\n }\r\n\r\n private commit(planned: PlannedOp, seqOverride?: number): void {\r\n const next = planned.commit(this.state)\r\n // 建卡批次里 create 已把真实 cardId 叠入状态,后续 op 的规划快照仍带 PENDING 占位:\r\n // 占位符不得回写真实卡号,否则同批末尾的 insert/update 会对 __pending__ 发 op。\r\n const current = this.state.cardId\r\n const cardId = next.cardId === PENDING_CARD_ID && current !== null && current !== PENDING_CARD_ID\r\n ? current\r\n : next.cardId\r\n this.state = seqOverride !== undefined\r\n ? { ...next, seq: seqOverride, cardId }\r\n : { ...next, seq: Math.max(next.seq, this.state.seq), cardId }\r\n }\r\n\r\n /** 流式超时后的官方恢复路径:settings 重设 streaming_mode:true(占一个 sequence)。 */\r\n private async reactivate(): Promise<boolean> {\r\n const { cardId, seq } = this.state\r\n if (cardId === null || cardId === PENDING_CARD_ID) return false\r\n try {\r\n await this.api.setCardStreaming(cardId, true, seq + 1)\r\n this.state = { ...this.state, seq: seq + 1 }\r\n return true\r\n } catch {\r\n return false\r\n }\r\n }\r\n\r\n /**\r\n * 废弃当前卡:尽力关流 → cardId 归零、尾段回卷为 carry → 调用方重新规划续写。\r\n * reshowTail=true(未知失败,op 可能已执行)时从尾段 base 重演(少量重复优于丢失);\r\n * reshowTail=false(200860 确定性未应用)时跳过已显示部分(零重复)。\r\n */\r\n private async abandon(reason: string, reshowTail: boolean): Promise<'abandoned'> {\r\n const { cardId, tail, seq } = this.state\r\n const hadRealCard = cardId !== null && cardId !== PENDING_CARD_ID\r\n if (hadRealCard) {\r\n await this.api.setCardStreaming(cardId as string, false, seq + 1).catch(() => undefined)\r\n }\r\n if (tail !== undefined) {\r\n const kind = this.segments[tail.segIndex]?.kind\r\n const base = kind === 'process' ? 0 : reshowTail ? tail.base : tail.base + tail.shownText.length\r\n this.state = {\r\n ...this.state,\r\n cardId: null,\r\n tail: undefined,\r\n closedSegCount: tail.segIndex,\r\n carry: { segIndex: tail.segIndex, base },\r\n }\r\n } else {\r\n this.state = { ...this.state, cardId: null }\r\n }\r\n this.log(`[project-bot] 卡片输出异常(${reason}),已废弃当前卡并在新卡继续`)\r\n if (hadRealCard) {\r\n await withRetry(() => this.api.sendText(this.chatId, ABANDON_NOTICE)).catch(() => undefined)\r\n }\r\n return 'abandoned'\r\n }\r\n\r\n private enqueue(task: () => Promise<void>): void {\r\n this.tail = this.tail.then(task).catch((error) => {\r\n this.log(`[project-bot] 卡片操作失败:${error instanceof Error ? error.message : String(error)}`)\r\n })\r\n }\r\n}\r\n\r\n/** 重放用:仅带 sequence 语义的 op 替换序号(create/send 无序号)。 */\r\nfunction withSeq(op: CardOp, sequence: number | undefined): CardOp {\r\n if (sequence === undefined) return op\r\n if (op.type === 'insert') return { ...op, sequence }\r\n if (op.type === 'update') return { ...op, sequence }\r\n if (op.type === 'settings') return { ...op, sequence }\r\n return op\r\n}\r\n\r\n/**\r\n * 带序号 op 的生效 sequence(create/send 返回 undefined = 不占序号):\r\n * 重放/重激活推高已确认 seq 后,规划或重放序号落后时抬升到已确认 seq+1,保证单调不碰撞。\r\n */\r\nfunction effectiveSeqOf(op: CardOp, override: number | undefined, confirmedSeq: number): number | undefined {\r\n if (op.type !== 'insert' && op.type !== 'update' && op.type !== 'settings') return undefined\r\n return Math.max(override ?? op.sequence, confirmedSeq + 1)\r\n}\r\n\r\n/** 「处理中」表情:加上后返回删除 disposer;加/删失败都静默(表情残留无害)。 */\r\nexport function makeAck(api: FeishuApi, messageId: string, emojiType: string): () => Promise<Disposer | undefined> {\r\n return async () => {\r\n try {\r\n const reactionId = await api.addReaction(messageId, emojiType)\r\n return () => {\r\n void api.removeReaction(messageId, reactionId).catch(() => undefined)\r\n }\r\n } catch {\r\n return undefined\r\n }\r\n }\r\n}\r\n","/** 飞书审批卡片:cardkit 2.0 静态卡(非流式)+ callback 按钮;presenter 挂在渠道 ChannelHandle.approval。 */\r\nimport type { FeishuApi } from '../feishu/api.ts'\r\nimport { withRetry } from '../feishu/reply.ts'\r\nimport type { ApprovalPresentation, ApprovalPresenter, ApprovalPrompt } from './center.ts'\r\n\r\nconst STATUS_TEXT: Record<'allowed' | 'rejected' | 'cancelled', string> = {\r\n allowed: '✅ 已允许',\r\n rejected: '❌ 已拒绝',\r\n cancelled: '⏹ 已取消',\r\n}\r\n\r\nfunction bodyMarkdown(prompt: ApprovalPrompt): string {\r\n const lines = [`**Bot**:${prompt.botName}`, `**工具**:\\`${prompt.toolName}\\``]\r\n if (prompt.reason !== undefined) lines.push(`**理由**:${prompt.reason}`)\r\n return lines.join('\\n')\r\n}\r\n\r\nfunction button(text: string, type: 'primary' | 'danger', key: string, decision: 'allow' | 'reject'): Record<string, unknown> {\r\n return {\r\n tag: 'button',\r\n text: { tag: 'plain_text', content: text },\r\n type,\r\n behaviors: [{ type: 'callback', value: { key, decision } }],\r\n }\r\n}\r\n\r\n/** 审批卡(带按钮);summary 供会话列表/推送预览。 */\r\nexport function buildApprovalCardJson(prompt: ApprovalPrompt): string {\r\n return JSON.stringify({\r\n schema: '2.0',\r\n config: { summary: { content: `权限申请:${prompt.toolName}` } },\r\n header: { title: { tag: 'plain_text', content: '权限申请' }, template: 'orange' },\r\n body: {\r\n elements: [\r\n { tag: 'markdown', content: bodyMarkdown(prompt) },\r\n { tag: 'action', actions: [button('允许', 'primary', prompt.key, 'allow'), button('拒绝', 'danger', prompt.key, 'reject')] },\r\n ],\r\n },\r\n })\r\n}\r\n\r\n/** 终态卡(无按钮):定格审批结果;operatorName 仅允许/拒绝时有。 */\r\nexport function buildApprovalFinalCardJson(prompt: ApprovalPrompt, status: 'allowed' | 'rejected' | 'cancelled', operatorName?: string): string {\r\n const statusLine = STATUS_TEXT[status] + (operatorName !== undefined ? ` · ${operatorName}` : '')\r\n const template = status === 'allowed' ? 'green' : status === 'rejected' ? 'red' : 'grey'\r\n return JSON.stringify({\r\n schema: '2.0',\r\n config: { summary: { content: `权限申请${STATUS_TEXT[status].slice(2).trim()}:${prompt.toolName}` } },\r\n header: { title: { tag: 'plain_text', content: `权限申请 · ${statusLine}` }, template },\r\n body: { elements: [{ tag: 'markdown', content: bodyMarkdown(prompt) }] },\r\n })\r\n}\r\n\r\n/** 飞书审批能力:present = 建卡 + 发消息;finalize = replaceCard 定格(sequence 从 1 起,create/send 不占)。 */\r\nexport class FeishuApprovalPresenter implements ApprovalPresenter {\r\n constructor(\r\n private readonly api: FeishuApi,\r\n private readonly log: (message: string) => void,\r\n ) {}\r\n\r\n async present(prompt: ApprovalPrompt): Promise<ApprovalPresentation> {\r\n const cardId = await withRetry(() => this.api.createCard(buildApprovalCardJson(prompt)))\r\n await withRetry(() => this.api.sendCardMessage(prompt.chatId, cardId))\r\n return {\r\n finalize: async (status, operatorName) => {\r\n try {\r\n await withRetry(() => this.api.replaceCard(cardId, buildApprovalFinalCardJson(prompt, status, operatorName), 1))\r\n } catch (error) {\r\n // 定格失败不吞审批结果:卡片残留按钮但回调侧已 settle(重复点击 toast 已失效)。\r\n this.log(`[project-bot] 审批卡片定格失败(card ${cardId}):${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n },\r\n }\r\n }\r\n}\r\n","/** card.action.trigger 回调解析:SDK normalizeCardAction → 渠道无关 CardActionInput;toast 应答帧负载。 */\r\nimport * as lark from '@larksuiteoapi/node-sdk'\r\nimport type { CardActionAck, CardActionInput } from '../approval/center.ts'\r\n\r\n/** raw → CardActionInput;normalize 失败(畸形/缺字段)→ undefined。 */\r\nexport function toCardActionInput(raw: unknown): CardActionInput | undefined {\r\n // SDK normalizeCardAction 对 null 直取 event.context 会抛 TypeError;先挡掉非对象输入。\r\n if (raw === null || typeof raw !== 'object') return undefined\r\n const evt = lark.normalizeCardAction(raw as lark.RawCardActionEvent)\r\n if (evt === null) return undefined\r\n return {\r\n chatId: evt.chatId,\r\n operatorOpenId: evt.operator.openId,\r\n ...(evt.operator.name !== undefined ? { operatorName: evt.operator.name } : {}),\r\n value: evt.action.value,\r\n }\r\n}\r\n\r\n/** WS 应答帧负载:handler 返回值经 WSClient 回传(lib/index.js handleEventData:truthy result → respPayload.data)。 */\r\nexport function toastResponse(ack: CardActionAck | undefined): { toast: { type: 'info'; content: string } } | undefined {\r\n if (ack?.toast === undefined) return undefined\r\n return { toast: { type: 'info', content: ack.toast } }\r\n}\r\n","/** 飞书渠道:WSClient 长连接收事件 → 解析 → 核心;出站走 FeishuReplyHandle。 */\r\nimport * as lark from '@larksuiteoapi/node-sdk'\r\nimport type { BotChannel, ChannelHandle } from '../channel.ts'\r\nimport { createFeishuApi } from './api.ts'\r\nimport { MessageDedup, parseMessageEvent } from './parse.ts'\r\nimport { FeishuReplyHandle, makeAck } from './reply.ts'\r\nimport { FeishuApprovalPresenter } from '../approval/feishu.ts'\r\nimport { toCardActionInput, toastResponse } from './card-action.ts'\r\n\r\nexport const feishuChannel: BotChannel = {\r\n type: 'feishu',\r\n\r\n async start(bot, io, tunables, log): Promise<ChannelHandle> {\r\n // runtime 仅对已绑定记录启动渠道(reconcile 的 feishu guard),此处安全。\r\n const { appId } = bot.record.feishu!\r\n const client = new lark.Client({ appId, appSecret: bot.secret })\r\n const api = createFeishuApi(client)\r\n // 群消息 @ 身份校验依赖本机器人 open_id;取不到则启动失败(reconcile 记录原因),不降级放行。\r\n const botOpenId = await api.getBotOpenId()\r\n const dedup = new MessageDedup()\r\n\r\n const dispatcher = new lark.EventDispatcher({}).register<{ 'card.action.trigger': (raw: unknown) => unknown }>({\r\n // 已读回执无动作;显式 no-op 消掉 EventDispatcher 的 \"no ... handle\" 告警噪音。\r\n 'im.message.message_read_v1': async () => undefined,\r\n // WS 事件须 3 秒内返回:解析同步完成,业务投递 fire-and-forget(含图片懒下载)。\r\n 'im.message.receive_v1': async (data: unknown) => {\r\n const parsed = parseMessageEvent(data, botOpenId)\r\n if (parsed === null || !dedup.check(parsed.messageId)) return\r\n const reply = new FeishuReplyHandle(api, parsed.chatId, tunables, log)\r\n const loadImages = parsed.imageKeys.length > 0\r\n ? async () => Promise.all(parsed.imageKeys.map(async (key) => api.downloadImage(parsed.messageId, key)))\r\n : undefined\r\n io.onMessage({\r\n botId: bot.record.id,\r\n chatId: parsed.chatId,\r\n userId: parsed.userId,\r\n messageId: parsed.messageId,\r\n text: parsed.text,\r\n ...(loadImages !== undefined ? { loadImages } : {}),\r\n reply,\r\n ackProcessing: makeAck(api, parsed.messageId, tunables.processingReactionEmoji),\r\n })\r\n },\r\n // 卡片按钮回调(审批):同步入核,toast 经 WS 应答帧回执。\r\n 'card.action.trigger': (raw: unknown) => {\r\n if (io.onCardAction === undefined) return undefined\r\n const action = toCardActionInput(raw)\r\n if (action === undefined) return undefined\r\n return toastResponse(io.onCardAction(action)) ?? undefined\r\n },\r\n })\r\n\r\n const ws = new lark.WSClient({ appId, appSecret: bot.secret, loggerLevel: lark.LoggerLevel.warn })\r\n await ws.start({ eventDispatcher: dispatcher })\r\n\r\n return {\r\n approval: new FeishuApprovalPresenter(api, log),\r\n close: () => {\r\n ws.close({ force: true })\r\n return Promise.resolve()\r\n },\r\n status: () => ws.getConnectionStatus().state,\r\n }\r\n },\r\n}\r\n","/** project-bot 存储域声明:身份、版本、记录 zod schema 的单一来源。 */\r\nimport { z } from 'zod'\r\nimport { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'\r\n\r\n/** 飞书自建应用 appId 形态(WSClient 同款校验)。 */\r\nexport const FEISHU_APP_ID_RE = /^cli_[0-9a-fA-F]{16}$/\r\n/** CredentialRef 字符集(credentials 服务 credentialRef() 的校验规则)。 */\r\nexport const CREDENTIAL_REF_RE = /^[A-Za-z_][A-Za-z0-9_]*$/\r\n/** bot id:小写 slug。 */\r\nexport const BOT_ID_RE = /^[a-z][a-z0-9-]{0,31}$/\r\n\r\nexport const FeishuConfigSchema = z.object({\r\n appId: z.string().regex(FEISHU_APP_ID_RE),\r\n appSecretRef: z.string().regex(CREDENTIAL_REF_RE),\r\n})\r\nexport type FeishuConfig = z.infer<typeof FeishuConfigSchema>\r\n\r\nexport const BotRecordSchema = z.object({\r\n id: z.string().regex(BOT_ID_RE),\r\n name: z.string().min(1).max(64),\r\n /** 渠道类型;与 feishu 同有或同无(未绑定为双双缺省)。 */\r\n channel: z.literal('feishu').optional(),\r\n feishu: FeishuConfigSchema.optional(),\r\n /** 绑定项目(agent 的 cwd,绝对路径)。一 bot 一项目。 */\r\n project: z.string().min(1),\r\n /** 透传到 agent 创作期的 persona 提示段。 */\r\n persona: z.string().max(8000).optional(),\r\n /** 绑定的 Agent('main' 或注册表角色 id,缺省 = 'main')。 */\r\n agentRef: z.string().min(1).optional(),\r\n /** 可用工具白名单(缺省 = 不限制);空数组无意义,直接拒绝。 */\r\n tools: z.array(z.string().min(1)).min(1).optional(),\r\n agentOptions: z.object({\r\n provider: z.string().min(1).optional(),\r\n model: z.string().min(1).optional(),\r\n }).optional(),\r\n createdAt: z.number().int().nonnegative(),\r\n updatedAt: z.number().int().nonnegative(),\r\n}).refine(\r\n (r) => (r.channel === undefined) === (r.feishu === undefined),\r\n { message: 'channel 与 feishu 必须同有或同无' },\r\n)\r\nexport type BotRecord = z.infer<typeof BotRecordSchema>\r\n\r\nexport const BindingSchema = z.object({ sessionId: z.string().min(1) })\r\nexport type Binding = z.infer<typeof BindingSchema>\r\n\r\n/** domain 名受 UNIT_NAME_RE 约束(^[a-z][a-z0-9_]*$),不允许连字符。 */\r\nexport const projectBotDomain = defineDomain({\r\n name: 'project_bot',\r\n version: 1,\r\n tables: {\r\n bots: domainTable<string, BotRecord>(BotRecordSchema),\r\n bindings: domainTable<string, Binding>(BindingSchema),\r\n },\r\n})\r\n\r\n/** bindings 表 key:(botId, chatId) → sessionId。 */\r\nexport function bindingKey(botId: string, chatId: string): string {\r\n return `${botId}:${chatId}`\r\n}\r\n","/** 出站:持久会话事件 + 瞬态流式帧 → turn 级回复驱动(per-session Promise 链保序)。 */\r\nimport type { AssistantStreamFrame } from '@deepseek-ai/dsh-agent'\r\nimport type { StreamChunk } from '@deepseek-ai/dsh-llm'\r\nimport type { TurnSegment, TurnStatus } from './channel.ts'\r\nimport type { SessionRuntime } from './ports.ts'\r\n\r\n/** 窄化的事件信封:核心只读 type/data。 */\r\nexport interface SessionEventLike {\r\n type: string\r\n data: Record<string, unknown>\r\n}\r\n\r\n/** 从 assistant 消息内容块提取正文纯文本(只取 text 块进正文;reasoning/tool_call 由 processOf 进过程区)。 */\r\nexport function textOf(content: readonly unknown[]): string {\r\n return (content as readonly { type?: unknown; text?: unknown }[])\r\n .filter((b): b is { type: 'text'; text: string } => b.type === 'text' && typeof b.text === 'string')\r\n .map((b) => b.text)\r\n .join('')\r\n}\r\n\r\n/** 从 assistant 消息内容块取最后一个 text 块的纯文本;无 text 块返回 ''(非 undefined)。 */\r\nexport function lastTextOf(content: readonly unknown[]): string {\r\n const texts = (content as readonly { type?: unknown; text?: unknown }[])\r\n .filter((b): b is { type: 'text'; text: string } => b.type === 'text' && typeof b.text === 'string')\r\n .map((b) => b.text)\r\n return texts.length === 0 ? '' : texts[texts.length - 1]!\r\n}\r\n\r\n/** 工具调用参数摘要最大字符数。 */\r\nexport const TOOL_ARGS_MAX_CHARS = 120\r\n\r\n/** 向段序列追加内容:与尾段同类则合并,异类开新段。 */\r\nexport function appendToSegments(segments: TurnSegment[], kind: 'text' | 'process', text: string): void {\r\n const tail = segments[segments.length - 1]\r\n if (tail !== undefined && tail.kind === kind) tail.content += text\r\n else segments.push({ kind, content: text })\r\n}\r\n\r\n/** 向段序列应用一个流式 chunk:text-delta → text、reasoning-delta → process、reasoning block-end → 过程段段落分隔;其余类型不消费返回 false。 */\r\nexport function applyStreamChunk(segments: TurnSegment[], chunk: StreamChunk): boolean {\r\n if (chunk.type === 'text-delta') {\r\n appendToSegments(segments, 'text', chunk.text)\r\n } else if (chunk.type === 'reasoning-delta') {\r\n appendToSegments(segments, 'process', chunk.text)\r\n } else if (chunk.type === 'block-end' && chunk.block?.type === 'reasoning' && segments[segments.length - 1]?.kind === 'process') {\r\n appendToSegments(segments, 'process', '\\n\\n')\r\n } else {\r\n return false\r\n }\r\n return true\r\n}\r\n\r\n/**\r\n * 对账尾 text 段:把最后一个 text 段的内容替换为权威全文(丢帧补齐)。\r\n * 前置条件:调用方已保证尾 text 段归属本结算 step(lastTextStep 命中结算 step)。\r\n * 返回是否发生替换;authoritative 为空、无 text 段或内容已相等时返回 false。\r\n */\r\nexport function reconcileTrailingText(segments: TurnSegment[], authoritative: string): boolean {\r\n if (authoritative === '') return false\r\n let tail: TurnSegment | undefined\r\n for (let i = segments.length - 1; i >= 0; i--) {\r\n if (segments[i]!.kind === 'text') {\r\n tail = segments[i]!\r\n break\r\n }\r\n }\r\n if (tail === undefined || tail.content === authoritative) return false\r\n tail.content = authoritative\r\n return true\r\n}\r\n\r\n/** (保留供测试)从组装消息提取过程输出:reasoning 全文 + tool_call 摘要行(段落间空行分隔)。 */\r\nexport function processOf(content: readonly unknown[]): string {\r\n const parts: string[] = []\r\n for (const b of content as readonly { type?: unknown; text?: unknown; name?: unknown; arguments?: unknown }[]) {\r\n if (b.type === 'reasoning' && typeof b.text === 'string' && b.text.length > 0) {\r\n parts.push(b.text)\r\n } else if (b.type === 'tool_call' && typeof b.name === 'string') {\r\n const args = typeof b.arguments === 'string' ? b.arguments : JSON.stringify(b.arguments ?? {})\r\n parts.push(`🔧 ${b.name} — ${truncateDetail(args, TOOL_ARGS_MAX_CHARS)}`)\r\n }\r\n }\r\n return parts.length === 0 ? '' : `${parts.join('\\n\\n')}\\n\\n`\r\n}\r\n\r\n/** turn/end 的 reason 形状(宿主 TurnEndReason 的窄化视图:核心只读 kind 与 error.message)。 */\r\nexport interface TurnEndReasonLike {\r\n kind: string\r\n error?: { message?: unknown }\r\n}\r\n\r\nexport function mapTurnEnd(reason: TurnEndReasonLike): TurnStatus {\r\n if (reason.kind === 'completed') return 'done'\r\n if (reason.kind === 'aborted' || reason.kind === 'interrupted') return 'cancelled'\r\n return 'error'\r\n}\r\n\r\n/** 截断错误摘要到 max 字符,超出追加省略号。 */\r\nexport function truncateDetail(text: string, max: number): string {\r\n return text.length > max ? `${text.slice(0, max)}…` : text\r\n}\r\n\r\n/** 从 turn/end reason 提取错误摘要;非 error 或无 message 返回 undefined。 */\r\nfunction errorDetailOf(reason: TurnEndReasonLike, max: number): string | undefined {\r\n if (reason.kind !== 'error') return undefined\r\n const message = reason.error?.message\r\n const text = typeof message === 'string' && message.length > 0 ? message : '未知错误'\r\n return truncateDetail(text, max)\r\n}\r\n\r\nexport class Outbound {\r\n constructor(\r\n private readonly sessions: Map<string, SessionRuntime>,\r\n private readonly onError: (message: string) => void,\r\n /** 回传渠道的错误摘要最大字符数。 */\r\n private readonly maxErrorDetailChars = 500,\r\n ) {}\r\n\r\n handleSessionEvent(sessionId: string, event: SessionEventLike): void {\r\n const rt = this.sessions.get(sessionId)\r\n if (rt === undefined) return\r\n\r\n if (event.type === 'turn/start') {\r\n rt.turn = { n: event.data.turn as number, segments: [], began: false }\r\n return\r\n }\r\n\r\n if (event.type === 'assistant/message') {\r\n const turn = rt.turn\r\n if (turn === undefined || turn.n !== (event.data.turn as number)) return\r\n // 防护(必需):仅当尾 text 段归属本结算 step(本 step 至少成功应用过一帧 text-delta)\r\n // 才用权威全文对账;否则跳过——用本 step 全文覆盖会篡改上一步已提交正文(宁缺勿错)。\r\n if (turn.lastTextStep !== (event.data.step as number)) return\r\n const content = (event.data.message as { content?: readonly unknown[] }).content ?? []\r\n const authoritative = lastTextOf(content) // 该 step 最后一个 text 块\r\n if (!reconcileTrailingText(turn.segments, authoritative)) return\r\n const snapshot = turn.segments.map((s) => ({ ...s }))\r\n this.enqueue(rt, async () => {\r\n if (rt.reply === undefined) return\r\n if (!turn.began) {\r\n await rt.reply.beginTurn()\r\n turn.began = true\r\n }\r\n await rt.reply.update(snapshot)\r\n })\r\n return\r\n }\r\n\r\n // assistant/attempt:该 attempt 无表面消息(失败/重试/取消无内容/流错误),不消费;\r\n // 已通过帧显示的过程区内容留在段里,由 turn/end 兜底定格。\r\n\r\n if (event.type === 'tool/call') {\r\n const turn = rt.turn\r\n if (turn === undefined || turn.n !== (event.data.turn as number)) return\r\n const name = event.data.name as string\r\n const args = typeof event.data.arguments === 'string' ? event.data.arguments : JSON.stringify(event.data.arguments ?? {})\r\n appendToSegments(turn.segments, 'process', `🔧 ${name} — ${truncateDetail(args, TOOL_ARGS_MAX_CHARS)}\\n\\n`)\r\n const snapshot = turn.segments.map((s) => ({ ...s }))\r\n this.enqueue(rt, async () => {\r\n if (rt.reply === undefined) return\r\n if (!turn.began) {\r\n await rt.reply.beginTurn()\r\n turn.began = true\r\n }\r\n await rt.reply.update(snapshot)\r\n })\r\n return\r\n }\r\n\r\n if (event.type === 'turn/end') {\r\n const turn = rt.turn\r\n if (turn === undefined || turn.n !== (event.data.turn as number)) return\r\n const reason = event.data.reason as TurnEndReasonLike\r\n const status = mapTurnEnd(reason)\r\n const detail = errorDetailOf(reason, this.maxErrorDetailChars)\r\n this.enqueue(rt, async () => {\r\n // 有卡定格;无卡但有错误 detail 时也要调 finalize(渠道降级为文本送出)。\r\n if ((turn.began || detail !== undefined) && rt.reply !== undefined) await rt.reply.finalize(status, detail)\r\n const ack = rt.inflight?.ack\r\n rt.inflight = undefined\r\n if (ack !== undefined) await ack()\r\n })\r\n rt.turn = undefined\r\n }\r\n }\r\n\r\n /**\r\n * 出站:瞬态流式帧 → 段构建 + 打字机。chunk 帧不携带 turn/step,由 start 帧建 attempt 基线\r\n * (turn/step,宿主 accumulator 同款取数);end 帧不消费;生命周期仍由 turn/start、turn/end 驱动。\r\n * 帧为 fire-and-forget,丢帧后无重传,正文由 assistant/message 结算对账有界恢复。\r\n */\r\n handleAssistantFrame(sessionId: string, frame: AssistantStreamFrame): void {\r\n const rt = this.sessions.get(sessionId)\r\n if (rt === undefined) return\r\n const turn = rt.turn\r\n if (turn === undefined) return\r\n if (frame.type === 'start') {\r\n if (turn.n !== frame.turn) return\r\n turn.attemptStep = frame.step\r\n return\r\n }\r\n if (frame.type !== 'chunk') return\r\n // start 帧丢失 → attemptStep 基线缺失,chunk 帧全部忽略:本 attempt 的正文+过程区同时缺席\r\n // (比对账「只缺正文」的降级更广,assistant/message 对账因 lastTextStep 不匹配同样跳过)。\r\n // 方向安全:不伪造内容,宁缺勿错(spec「防护的覆盖范围」段)。\r\n const step = turn.attemptStep\r\n if (step === undefined) return\r\n if (!applyStreamChunk(turn.segments, frame.chunk)) return\r\n if (frame.chunk.type === 'text-delta') turn.lastTextStep = step // 对账防护:尾 text 段的归属 step\r\n const snapshot = turn.segments.map((s) => ({ ...s }))\r\n this.enqueue(rt, async () => {\r\n if (rt.reply === undefined) return\r\n if (!turn.began) {\r\n await rt.reply.beginTurn()\r\n turn.began = true\r\n }\r\n await rt.reply.update(snapshot)\r\n })\r\n }\r\n\r\n /**\r\n * turn 外错误(agent/error:resume/驱动边界失败等没有 turn/end 的场景):\r\n * notice 错误摘要并释放 inflight 槽 + 删除表情;turn 进行中的错误由 turn/end 报告,跳过防双发。\r\n */\r\n handleAgentError(sessionId: string, errorText: string): void {\r\n const rt = this.sessions.get(sessionId)\r\n if (rt === undefined || rt.turn !== undefined) return\r\n const detail = truncateDetail(errorText, this.maxErrorDetailChars)\r\n this.enqueue(rt, async () => {\r\n if (rt.reply !== undefined) await rt.reply.notice(`出错了:${detail}`)\r\n const ack = rt.inflight?.ack\r\n rt.inflight = undefined\r\n if (ack !== undefined) await ack()\r\n })\r\n }\r\n\r\n private enqueue(rt: SessionRuntime, task: () => Promise<void>): void {\r\n rt.tail = rt.tail.then(task).catch((error) => {\r\n this.onError(`[project-bot] 出站处理失败:${error instanceof Error ? error.message : String(error)}`)\r\n })\r\n }\r\n}\r\n","/** 入站:指令分流 → 路由 → 单 in-flight 准入 → 表情回复 → 图片落附件库 → followup 投递。 */\r\nimport { createUserMessage } from '@deepseek-ai/dsh-llm'\r\nimport type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'\r\nimport type { BotRecord } from '../bots/store.ts'\r\nimport type { InboundMessage } from './channel.ts'\r\nimport { parseDirective } from './directive.ts'\r\nimport { truncateDetail } from './outbound.ts'\r\nimport type { Router } from './router.ts'\r\n\r\n/** 图片附件库端口(宿主 ctx.attachments 的窄化;缺席时图片降级为提示)。 */\r\nexport interface AttachmentsPort {\r\n saveImages(inputs: readonly { data: Uint8Array; mediaType: string; name?: string }[]): Promise<readonly ImageAttachmentRef[]>\r\n}\r\n\r\nexport interface InboundDeps {\r\n router: Router\r\n bots: { get(botId: string): BotRecord | undefined }\r\n maxErrorDetailChars: number\r\n /** 可选:宿主附件服务的惰性取用器(消息时解析;apply 期服务注册未必就绪)。 */\r\n attachments?: () => AttachmentsPort | undefined\r\n onError(message: string): void\r\n}\r\n\r\nexport class Inbound {\r\n constructor(private readonly deps: InboundDeps) {}\r\n\r\n onMessage(msg: InboundMessage): void {\r\n void this.handle(msg).catch(async (error) => {\r\n // 摘要一并回传渠道:dsh web 终端不展示插件 warn,通用文案无法定位(2026-09-03 /new 事故)。\r\n const detail = truncateDetail(error instanceof Error ? error.message : String(error), this.deps.maxErrorDetailChars)\r\n this.deps.onError(`[project-bot] 入站处理失败:${detail}`)\r\n await msg.reply.notice(`处理失败:${detail}`).catch(() => undefined)\r\n })\r\n }\r\n\r\n private async handle(msg: InboundMessage): Promise<void> {\r\n const bot = this.deps.bots.get(msg.botId)\r\n if (bot === undefined) return\r\n\r\n const directive = parseDirective(msg.text)\r\n if (directive === 'new') {\r\n await this.deps.router.reset(bot, msg.chatId, msg.reply, msg.userId)\r\n await msg.reply.notice('已开启新会话')\r\n return\r\n }\r\n if (directive === 'stop') {\r\n const rt = this.deps.router.lookup(bot.id, msg.chatId)\r\n if (rt?.inflight !== undefined) {\r\n rt.agent.cancel()\r\n await msg.reply.notice('已请求停止当前任务')\r\n } else {\r\n await msg.reply.notice('当前没有进行中的任务')\r\n }\r\n return\r\n }\r\n if (directive === 'status') {\r\n const rt = this.deps.router.lookup(bot.id, msg.chatId)\r\n await msg.reply.notice(rt === undefined\r\n ? `项目:${bot.project}\\n会话:未创建(发送消息即创建)`\r\n : `项目:${bot.project}\\n会话:${rt.sessionId}\\n状态:${rt.inflight !== undefined ? '处理中' : '空闲'}`)\r\n return\r\n }\r\n\r\n const rt = await this.deps.router.ensure(bot, msg.chatId, msg.reply, msg.userId)\r\n if (rt.inflight !== undefined) {\r\n await msg.reply.notice('上一条还在处理中,请稍候(或发送 /stop 取消)')\r\n return\r\n }\r\n // 准入:先占槽再异步;表情回复失败不阻塞处理。\r\n // reply 句柄只在准入通过后刷新——忙时消息不抢走运行中 turn 的出站。\r\n rt.inflight = { ack: undefined }\r\n rt.reply = msg.reply\r\n rt.inflight.ack = (await msg.ackProcessing().catch(() => undefined)) ?? undefined\r\n // source kind 用 'user'(与 ACP 同款):dsh sessionTitle 服务只接纳 user 消息生成会话标题。\r\n // 图片:in-flight 窗口内懒下载(不占飞书 WS 3 秒窗口)→ 落附件库 → image 内容块。\r\n const imageRefs: ImageAttachmentRef[] = []\r\n if (msg.loadImages !== undefined) {\r\n const images = await msg.loadImages()\r\n if (images.length > 0) {\r\n const attachments = this.deps.attachments?.()\r\n if (attachments === undefined) {\r\n await msg.reply.notice('当前环境暂不支持图片消息(附件服务不可用),已按文字部分处理')\r\n } else {\r\n imageRefs.push(...await attachments.saveImages(images))\r\n }\r\n }\r\n }\r\n const message = createUserMessage({\r\n content: [\r\n ...(msg.text.length > 0 ? [{ type: 'text' as const, text: msg.text }] : []),\r\n ...imageRefs.map((ref) => ({ type: 'image' as const, attachment: ref })),\r\n ],\r\n source: { kind: 'user' },\r\n })\r\n try {\r\n rt.agent.followup(message)\r\n } catch (error) {\r\n const ack = rt.inflight.ack\r\n rt.inflight = undefined\r\n await ack?.()\r\n throw error\r\n }\r\n }\r\n}\r\n","/** 核心对宿主 agents 服务 / 绑定表的结构化端口(测试用 fake 注入)。 */\r\nimport type { BotRecord } from '../bots/store.ts'\r\nimport type { Disposer, ReplyHandle, TurnSegment } from './channel.ts'\r\n\r\nexport interface AgentPort {\r\n readonly sessionId: string\r\n /** 入参须为 @deepseek-ai/dsh-llm 的 createUserMessage 产物(裸字符串缺 source,turn 管线读 source.kind 崩溃)。 */\r\n followup(message: unknown): void\r\n cancel(): void\r\n whenIdle(): Promise<void>\r\n}\r\n\r\n/** 一个创作期注册到 agent 系统提示的提示段(name/order/text 与 LayerConfig 同构)。 */\r\nexport interface AgentSection {\r\n name: string\r\n order: number\r\n text: string\r\n}\r\n\r\n/** 创作期注入(真实适配器里映射为 setup(agentCtx) 内的 mount/section/restrict)。 */\r\nexport interface AgentHooks {\r\n persona?: string\r\n tools?: readonly string[]\r\n /** 绑定角色时逐层注册的提示段(name = `dsh-agent-toolkit:agent:<layer>`)。 */\r\n sections?: readonly AgentSection[]\r\n}\r\n\r\nexport interface AgentsPort {\r\n create(input: {\r\n sessionId: string\r\n cwd: string\r\n agentOptions?: { provider?: string; model?: string }\r\n hooks: AgentHooks\r\n }): Promise<AgentPort>\r\n resume(input: {\r\n sessionId: string\r\n agentOptions?: { provider?: string; model?: string }\r\n hooks: AgentHooks\r\n }): Promise<AgentPort>\r\n}\r\n\r\n/** main 形态会话(bot 未自配 agentOptions 时)与未配置模型的角色的模型来源(取 {provider, model})。 */\r\nexport type DefaultModelAccessor = () => { provider: string; model: string }\r\n\r\n/** 会话归属:把 session 挂到 cwd 对应 workspace(宿主侧幂等;无则自动建)。 */\r\nexport interface WorkspacePort {\r\n attach(cwd: string, sessionId: string): Promise<void>\r\n}\r\n\r\nexport interface BindingStore {\r\n get(botId: string, chatId: string): string | undefined\r\n set(botId: string, chatId: string, sessionId: string): Promise<void>\r\n delete(botId: string, chatId: string): Promise<void>\r\n /** 删除某 bot 的全部绑定(bot 被删除时)。 */\r\n deleteBot(botId: string): Promise<void>\r\n}\r\n\r\n/** 一个活跃会话的运行时状态(inbound/outbound 共享)。 */\r\nexport interface SessionRuntime {\r\n readonly botId: string\r\n readonly chatId: string\r\n readonly sessionId: string\r\n /** 会话发起人的渠道 open_id(审批卡片越权校验用;ensure/reset 的 userId 落入)。 */\r\n readonly initiatorOpenId: string\r\n agent: AgentPort\r\n /** 最近一次入站消息携带的回复句柄(回复永远回到 chat)。 */\r\n reply: ReplyHandle | undefined\r\n /** 单会话单 in-flight 槽;ack = 表情回复的 disposer。 */\r\n inflight: { ack: Disposer | undefined } | undefined\r\n /** 出站操作串行化 Promise 链(保序)。 */\r\n tail: Promise<unknown>\r\n /** 当前 turn 归集状态;无进行中 turn 为 undefined。 */\r\n turn: { n: number; segments: TurnSegment[]; began: boolean; lastTextStep?: number; attemptStep?: number } | undefined\r\n /**\r\n * retire 后仍在 sessions 中收尾(等 whenIdle + tail 落定才摘除,让旧卡 finalize)期间为 true:\r\n * ensure 不得复用收尾中的 runtime(其 agent 已 cancel),重绑窗口须 resume + adopt 重建。\r\n */\r\n retiring: boolean\r\n}\r\n\r\n/** 从 bot 记录提取创作期注入(主 Agent 绑定形态)。 */\r\nexport function hooksOf(bot: BotRecord): AgentHooks {\r\n return {\r\n ...(bot.persona !== undefined ? { persona: bot.persona } : {}),\r\n ...(bot.tools !== undefined ? { tools: bot.tools } : {}),\r\n }\r\n}\r\n","/** 角色形态会话装配(Router bot 会话与 schedule 执行器共用):persona 单 section + tools 白名单 + 模型解析。 */\r\nimport type { AgentRecord } from '../agents/store.ts'\r\nimport type { AgentHooks, DefaultModelAccessor } from './ports.ts'\r\n\r\n/** 角色 persona 的 scoped 段名(与 Router 既有产出一致,逐字段不可改)。 */\r\nexport const ROLE_PERSONA_SECTION = 'dsh-agent-toolkit:agent:persona'\r\n\r\n/** 角色形态创作期注入:persona 非空 → 单 section(order 0);tools 白名单存在 → 带上(由 setupAgentScope restrict)。 */\r\nexport function roleHooks(role: AgentRecord): AgentHooks {\r\n const sections = role.persona === undefined || role.persona.trim().length === 0\r\n ? []\r\n : [{ name: ROLE_PERSONA_SECTION, order: 0, text: role.persona }]\r\n return {\r\n ...(sections.length > 0 ? { sections } : {}),\r\n ...(role.tools !== undefined ? { tools: role.tools.allow } : {}),\r\n }\r\n}\r\n\r\n/** 角色模型:自配优先,缺省回退宿主默认模型(与 Router 语义一致)。 */\r\nexport function roleAgentOptions(\r\n role: AgentRecord,\r\n defaultModel: DefaultModelAccessor,\r\n): { provider?: string; model?: string } {\r\n return role.model ?? defaultModel()\r\n}\r\n","/** 绑定路由:(botId, chatId) → 长期会话;create / resume / reset。 */\r\nimport { randomUUID } from 'node:crypto'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport type { BotRecord } from '../bots/store.ts'\r\nimport type { ReplyHandle } from './channel.ts'\r\nimport { hooksOf, type AgentHooks, type AgentSection, type AgentsPort, type BindingStore, type DefaultModelAccessor, type SessionRuntime, type WorkspacePort } from './ports.ts'\r\nimport { roleAgentOptions, roleHooks } from './role-assembly.ts'\r\n\r\n/** 发起人提示段名:bot 会话声明来源渠道与发起人 open_id。 */\r\nexport const SENDER_SECTION_NAME = 'dsh-agent-toolkit:channel:sender'\r\n\r\n/** sender 段文本(单聊语义;channel 取 BotRecord.channel,未来新渠道零改动透传)。 */\r\nexport function senderSectionText(channel: string, userId: string): string {\r\n return `本会话由 ${channel} 渠道的单聊会话发起。发起人 ID(${channel} open_id):\\`${userId}\\`。`\r\n}\r\n\r\nexport class Router {\r\n constructor(\r\n private readonly agents: AgentsPort,\r\n private readonly bindings: BindingStore,\r\n /** sessionId → runtime(进程内活跃会话表,与 bindings 持久表互补)。 */\r\n private readonly sessions: Map<string, SessionRuntime>,\r\n /** main 形态会话(bot 未自配 agentOptions 时)与未配置模型的角色的模型来源(宿主默认模型)。 */\r\n private readonly defaultModel: DefaultModelAccessor,\r\n /** 会话归入 bot 项目 workspace(与原生 UI session.create 同款挂载)。 */\r\n private readonly workspace: WorkspacePort,\r\n private readonly onWarn: (message: string) => void,\r\n /** Agent 注册表(agentRef → main/角色),会话创建时决定 persona/工具/模型装配。 */\r\n private readonly registry: AgentRegistry,\r\n /** 开启时向 hooks.sections 末尾追加渠道发起人提示段。 */\r\n private readonly injectSender = true,\r\n ) {}\r\n\r\n /**\r\n * 取(或建/恢复)该 chat 的会话 runtime。存量活跃会话保持其 reply——运行中 turn 的出站\r\n * 必须留在原句柄收尾,reply 刷新由 Inbound 在 in-flight 准入通过后执行;\r\n * retiring(已 cancel、收尾中)的会话不可复用,重绑窗口内恢复时 resume + adopt 重建。\r\n */\r\n async ensure(bot: BotRecord, chatId: string, reply: ReplyHandle, userId: string): Promise<SessionRuntime> {\r\n const bound = this.bindings.get(bot.id, chatId)\r\n if (bound !== undefined) {\r\n const existing = this.sessions.get(bound)\r\n // 活跃会话不替换 reply:运行中 turn 的出站必须留在原句柄收尾;\r\n // reply 的刷新由 Inbound 在 in-flight 准入通过后执行。\r\n if (existing !== undefined && !existing.retiring) return existing\r\n const agent = await this.agents.resume({ sessionId: bound, ...this.resolveSession(bot, userId) })\r\n await this.attach(bot.project, bound)\r\n return this.adopt(bot.id, chatId, userId, bound, agent, reply)\r\n }\r\n const sessionId = randomUUID()\r\n const agent = await this.agents.create({ sessionId, cwd: bot.project, ...this.resolveSession(bot, userId) })\r\n await this.bindings.set(bot.id, chatId, sessionId)\r\n await this.attach(bot.project, sessionId)\r\n return this.adopt(bot.id, chatId, userId, sessionId, agent, reply)\r\n }\r\n\r\n /** attach 失败仅告警(会话降级为未分组),不阻塞消息处理。 */\r\n private async attach(cwd: string, sessionId: string): Promise<void> {\r\n try {\r\n await this.workspace.attach(cwd, sessionId)\r\n } catch (error) {\r\n this.onWarn(`[project-bot] 会话 ${sessionId} 挂载 workspace 失败:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n }\r\n\r\n /** injectSender 开启时向 hooks.sections 末尾追加 sender 段(主/角色形态通用)。 */\r\n private withSenderSection(hooks: AgentHooks, bot: BotRecord, userId: string): AgentHooks {\r\n if (!this.injectSender) return hooks\r\n const section: AgentSection = { name: SENDER_SECTION_NAME, order: 20, text: senderSectionText(bot.channel ?? 'unknown', userId) }\r\n return { ...hooks, sections: [...(hooks.sections ?? []), section] }\r\n }\r\n\r\n /**\r\n * 按 bot.agentRef 解析会话组装(agentOptions + 创作期 hooks):\r\n * - 缺省/指向 main → 主 Agent 形态:bot 自带 persona/tools + 模型(自配 agentOptions 优先,缺省回退宿主默认模型);\r\n * - 指向角色 → 角色形态:persona 单 section + tools.restrict + role.model;\r\n * - 指向不存在角色 → warn 并降级为主 Agent 形态。\r\n */\r\n private resolveSession(bot: BotRecord, userId: string): { agentOptions: { provider?: string; model?: string }; hooks: AgentHooks } {\r\n const ref = bot.agentRef ?? 'main'\r\n const role = this.registry.get(ref)\r\n if (role === undefined || ref === 'main') {\r\n if (role === undefined && ref !== 'main') {\r\n this.onWarn(`[project-bot] bot \"${bot.id}\" 的 agentRef \"${ref}\" 不存在,降级绑定主 Agent`)\r\n }\r\n return { agentOptions: bot.agentOptions ?? this.defaultModel(), hooks: this.withSenderSection(hooksOf(bot), bot, userId) }\r\n }\r\n return {\r\n agentOptions: roleAgentOptions(role, this.defaultModel),\r\n hooks: this.withSenderSection(roleHooks(role), bot, userId),\r\n }\r\n }\r\n\r\n /** /new:取消旧会话;等 turn/end 落定(旧卡在旧句柄 finalize)后再摘出 sessions。 */\r\n async reset(bot: BotRecord, chatId: string, reply: ReplyHandle, userId: string): Promise<SessionRuntime> {\r\n const bound = this.bindings.get(bot.id, chatId)\r\n if (bound !== undefined) {\r\n const old = this.sessions.get(bound)\r\n if (old !== undefined) this.retire(bound, old)\r\n await this.bindings.delete(bot.id, chatId)\r\n }\r\n return this.ensure(bot, chatId, reply, userId)\r\n }\r\n\r\n /** 取消会话并等出站链落定后摘出 sessions(让在飞 turn 的 turn/end 正常 finalize 旧卡)。 */\r\n private retire(sessionId: string, rt: SessionRuntime): void {\r\n rt.retiring = true\r\n rt.agent.cancel()\r\n void (async () => {\r\n await rt.agent.whenIdle().catch(() => undefined)\r\n await rt.tail.catch(() => undefined)\r\n if (this.sessions.get(sessionId) === rt) this.sessions.delete(sessionId)\r\n })()\r\n }\r\n\r\n lookup(botId: string, chatId: string): SessionRuntime | undefined {\r\n const bound = this.bindings.get(botId, chatId)\r\n return bound === undefined ? undefined : this.sessions.get(bound)\r\n }\r\n\r\n private adopt(botId: string, chatId: string, userId: string, sessionId: string, agent: SessionRuntime['agent'], reply: ReplyHandle): SessionRuntime {\r\n const rt: SessionRuntime = {\r\n botId, chatId, sessionId, initiatorOpenId: userId, agent, reply,\r\n inflight: undefined, tail: Promise.resolve(), turn: undefined, retiring: false,\r\n }\r\n this.sessions.set(sessionId, rt)\r\n return rt\r\n }\r\n}\r\n","/** 审批中心(渠道无关):自有 bot 会话的 approval ask → 渠道审批卡片挂起 → 卡片回调 resolve。\r\n * spec: docs/superpowers/specs/archive/2026-09-08-feishu-approval-card-design.md(飞书独占 / 仅发起人 / 不超时)。 */\r\nimport { randomUUID } from 'node:crypto'\r\nimport type { SessionRuntime } from '../ports.ts'\r\n\r\nexport type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable'\r\n\r\n/** waterfall answerer 收到的请求结构(结构子集化,不依赖宿主包类型)。 */\r\nexport interface ApprovalRequestLike {\r\n agent: { session: { id: unknown } }\r\n toolName: string\r\n reason?: string\r\n signal?: AbortSignal\r\n}\r\n\r\n/** 发给渠道的审批卡片内容。 */\r\nexport interface ApprovalPrompt {\r\n key: string\r\n chatId: string\r\n botName: string\r\n toolName: string\r\n reason?: string\r\n}\r\n\r\n/** 一次已展示的审批:finalize 把卡片定格为终态(实现内部 fire-and-forget 友好,失败自告警)。 */\r\nexport interface ApprovalPresentation {\r\n finalize(status: 'allowed' | 'rejected' | 'cancelled', operatorName?: string): Promise<void>\r\n}\r\n\r\n/** 渠道侧审批能力:发卡 → 返回定格句柄。 */\r\nexport interface ApprovalPresenter {\r\n present(prompt: ApprovalPrompt): Promise<ApprovalPresentation>\r\n}\r\n\r\n/** channelFor 的返回:该 bot 的审批能力 + 展示名。 */\r\nexport interface ApprovalChannel {\r\n presenter: ApprovalPresenter\r\n botName: string\r\n}\r\n\r\n/** 渠道回调入核的卡片动作(渠道已解析成渠道无关形态)。 */\r\nexport interface CardActionInput {\r\n chatId: string\r\n operatorOpenId: string\r\n operatorName?: string\r\n value: unknown\r\n}\r\n\r\n/** 回调应答(飞书侧经 WS 响应帧回 toast)。 */\r\nexport interface CardActionAck {\r\n toast?: string\r\n}\r\n\r\ninterface PendingEntry {\r\n sessionId: string\r\n resolve(outcome: ApprovalOutcome): void\r\n presentation: ApprovalPresentation\r\n signal: AbortSignal | undefined\r\n onAbort: () => void\r\n}\r\n\r\nexport class ApprovalCenter {\r\n private readonly pending = new Map<string, PendingEntry>()\r\n\r\n constructor(\r\n private readonly sessions: Map<string, SessionRuntime>,\r\n private readonly channelFor: (botId: string) => ApprovalChannel | undefined,\r\n private readonly warn: (message: string) => void,\r\n private readonly newId: () => string = randomUUID,\r\n ) {}\r\n\r\n async handleRequest(req: ApprovalRequestLike): Promise<ApprovalOutcome | undefined> {\r\n const sessionId = String(req.agent.session.id)\r\n const rt = this.sessions.get(sessionId)\r\n if (rt === undefined) return undefined\r\n // 已取消的 ask 不发卡不回退:直接 cancelled(与 api-proxy 的同步 settle 对齐,\r\n // 防 abort 落在注册监听之前的 zombie 窗口)。\r\n if (req.signal?.aborted === true) return 'cancelled'\r\n const channel = this.channelFor(rt.botId)\r\n if (channel === undefined) {\r\n this.warn(`[project-bot] bot \"${rt.botId}\" 的渠道无审批能力,回退其他审批通道`)\r\n return undefined\r\n }\r\n const key = this.newId()\r\n let presentation: ApprovalPresentation\r\n try {\r\n presentation = await channel.presenter.present({\r\n key, chatId: rt.chatId, botName: channel.botName, toolName: req.toolName,\r\n ...(req.reason !== undefined ? { reason: req.reason } : {}),\r\n })\r\n } catch (error) {\r\n this.warn(`[project-bot] 审批卡片发送失败,回退其他审批通道:${error instanceof Error ? error.message : String(error)}`)\r\n return undefined\r\n }\r\n return new Promise<ApprovalOutcome>((resolve) => {\r\n const entry: PendingEntry = {\r\n sessionId, resolve, presentation, signal: req.signal,\r\n onAbort: () => this.settle(key, 'cancelled'),\r\n }\r\n this.pending.set(key, entry)\r\n req.signal?.addEventListener('abort', entry.onAbort, { once: true })\r\n })\r\n }\r\n\r\n handleCardAction(action: CardActionInput): CardActionAck | undefined {\r\n const value = action.value as { key?: unknown; decision?: unknown } | null\r\n if (value === null || typeof value !== 'object' || typeof value.key !== 'string'\r\n || (value.decision !== 'allow' && value.decision !== 'reject')) return undefined\r\n const entry = this.pending.get(value.key)\r\n if (entry === undefined) return { toast: '该申请已处理或已失效' }\r\n const rt = this.sessions.get(entry.sessionId)\r\n if (rt === undefined || rt.initiatorOpenId !== action.operatorOpenId) {\r\n return { toast: '仅会话发起人可审批' }\r\n }\r\n this.settle(value.key, value.decision === 'allow' ? 'allowed-once' : 'rejected', action.operatorName)\r\n return { toast: value.decision === 'allow' ? '已允许' : '已拒绝' }\r\n }\r\n\r\n dispose(): void {\r\n for (const key of [...this.pending.keys()]) this.settle(key, 'cancelled')\r\n }\r\n\r\n private settle(key: string, outcome: ApprovalOutcome, operatorName?: string): void {\r\n const entry = this.pending.get(key)\r\n if (entry === undefined) return\r\n this.pending.delete(key)\r\n entry.signal?.removeEventListener('abort', entry.onAbort)\r\n entry.resolve(outcome)\r\n const status = outcome === 'allowed-once' ? 'allowed' : outcome === 'rejected' ? 'rejected' : 'cancelled'\r\n void entry.presentation.finalize(status, operatorName).catch((error: unknown) => {\r\n this.warn(`[project-bot] 审批卡片定格失败:${error instanceof Error ? error.message : String(error)}`)\r\n })\r\n }\r\n}\r\n","/** BotRuntime:bot 名册 → 渠道生命周期;聚合 router/inbound/outbound。 */\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport { bindingKey, type Binding, type BotRecord } from '../bots/store.ts'\r\nimport type { BotChannel, ChannelHandle, ChannelStatus, ChannelTunables } from './channel.ts'\r\nimport { Inbound } from './inbound.ts'\r\nimport { Outbound } from './outbound.ts'\r\nimport type { AgentsPort, BindingStore, DefaultModelAccessor, SessionRuntime, WorkspacePort } from './ports.ts'\r\nimport { Router } from './router.ts'\r\nimport type { AttachmentsPort } from './inbound.ts'\r\nimport { ApprovalCenter } from './approval/center.ts'\r\n\r\nexport interface RuntimeDeps {\r\n bots: KvTable<string, BotRecord>\r\n bindings: KvTable<string, Binding>\r\n agents: AgentsPort\r\n /** Agent 注册表(agentRef → main/角色),Router 会话创建时决定 persona/工具/模型装配。 */\r\n registry: AgentRegistry\r\n /** main 形态会话(bot 未自配 agentOptions 时)与未配置模型的角色回退宿主默认模型。 */\r\n defaultModel: DefaultModelAccessor\r\n /** 会话归入 bot 项目 workspace。 */\r\n workspace: WorkspacePort\r\n channels: ReadonlyMap<string, BotChannel>\r\n tunables: ChannelTunables\r\n /** 回传渠道的错误摘要最大字符数。 */\r\n maxErrorDetailChars: number\r\n /** 可选:宿主附件服务的惰性取用器(消息时解析;返回 undefined = 图片降级提示)。 */\r\n attachments?: () => AttachmentsPort | undefined\r\n /** 发起人提示段开关(缺省 true;见 Config feishu.injectSender)。 */\r\n injectSender?: boolean\r\n resolveSecret(ref: string): Promise<string | undefined>\r\n validateProject(path: string): boolean\r\n log: { warn(message: string): void; info(message: string): void }\r\n}\r\n\r\nexport type BotStatus = ChannelStatus | 'not-running' | 'unbound'\r\n\r\nexport class BotRuntime {\r\n readonly sessions = new Map<string, SessionRuntime>()\r\n readonly router: Router\r\n readonly inbound: Inbound\r\n readonly outbound: Outbound\r\n readonly approval: ApprovalCenter\r\n private readonly handles = new Map<string, ChannelHandle>()\r\n\r\n constructor(private readonly deps: RuntimeDeps) {\r\n const bindingStore = this.bindingStore()\r\n this.router = new Router(deps.agents, bindingStore, this.sessions, deps.defaultModel, deps.workspace, (m) => deps.log.warn(m), deps.registry, deps.injectSender ?? true)\r\n this.inbound = new Inbound({\r\n router: this.router,\r\n bots: deps.bots,\r\n maxErrorDetailChars: deps.maxErrorDetailChars,\r\n ...(deps.attachments !== undefined ? { attachments: deps.attachments } : {}),\r\n onError: (m) => deps.log.warn(m),\r\n })\r\n this.outbound = new Outbound(this.sessions, (m) => deps.log.warn(m), deps.maxErrorDetailChars)\r\n this.approval = new ApprovalCenter(\r\n this.sessions,\r\n (botId) => {\r\n const presenter = this.handles.get(botId)?.approval\r\n if (presenter === undefined) return undefined\r\n return { presenter, botName: this.deps.bots.get(botId)?.name ?? botId }\r\n },\r\n (m) => deps.log.warn(m),\r\n )\r\n }\r\n\r\n async startAll(): Promise<void> {\r\n for (const botId of [...this.deps.bots.keys()]) await this.reconcile(botId)\r\n }\r\n\r\n /** 按最新记录重建该 bot 的渠道(创建/更新后调用;记录已删或未绑定则纯停止)。 */\r\n async reconcile(botId: string): Promise<void> {\r\n await this.stopChannel(botId)\r\n const record = this.deps.bots.get(botId)\r\n if (record === undefined) return\r\n // 未绑定(channel/feishu 均缺省)的 bot:停渠道即止,不启动不告警。\r\n if (record.feishu === undefined || record.channel === undefined) return\r\n if (!this.deps.validateProject(record.project)) {\r\n this.deps.log.warn(`[project-bot] bot \"${botId}\" 的项目路径不可用:${record.project}`)\r\n return\r\n }\r\n const secret = await this.deps.resolveSecret(record.feishu.appSecretRef)\r\n if (secret === undefined) {\r\n this.deps.log.warn(`[project-bot] bot \"${botId}\" 的密钥 ${record.feishu.appSecretRef} 未配置`)\r\n return\r\n }\r\n const channel = this.deps.channels.get(record.channel)\r\n if (channel === undefined) {\r\n this.deps.log.warn(`[project-bot] bot \"${botId}\" 的渠道 \"${record.channel}\" 未实现`)\r\n return\r\n }\r\n try {\r\n const handle = await channel.start(\r\n { record, secret },\r\n { onMessage: (msg) => this.inbound.onMessage(msg), onCardAction: (action) => this.approval.handleCardAction(action) },\r\n this.deps.tunables,\r\n (m) => this.deps.log.warn(m),\r\n )\r\n this.handles.set(botId, handle)\r\n } catch (error) {\r\n this.deps.log.warn(`[project-bot] bot \"${botId}\" 渠道启动失败:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n }\r\n\r\n /** 删除 bot:停渠道、取消会话、清绑定。 */\r\n async stopBot(botId: string): Promise<void> {\r\n await this.stopChannel(botId)\r\n for (const [sessionId, rt] of [...this.sessions]) {\r\n if (rt.botId === botId) this.retire(sessionId, rt)\r\n }\r\n await this.bindingStore().deleteBot(botId)\r\n }\r\n\r\n /** 解绑渠道:停渠道、取消在飞会话;绑定表与持久会话保留(重绑后 resume 接续)。 */\r\n async unbindBot(botId: string): Promise<void> {\r\n await this.stopChannel(botId)\r\n for (const [sessionId, rt] of [...this.sessions]) {\r\n if (rt.botId === botId) this.retire(sessionId, rt)\r\n }\r\n }\r\n\r\n /** 取消会话并等出站链落定后摘出 sessions(让在飞 turn 的 turn/end 正常 finalize 旧卡)。 */\r\n private retire(sessionId: string, rt: SessionRuntime): void {\r\n rt.retiring = true\r\n rt.agent.cancel()\r\n void (async () => {\r\n await rt.agent.whenIdle().catch(() => undefined)\r\n await rt.tail.catch(() => undefined)\r\n if (this.sessions.get(sessionId) === rt) this.sessions.delete(sessionId)\r\n })()\r\n }\r\n\r\n statusOf(botId: string): BotStatus {\r\n const record = this.deps.bots.get(botId)\r\n if (record !== undefined && record.feishu === undefined) return 'unbound'\r\n return this.handles.get(botId)?.status() ?? 'not-running'\r\n }\r\n\r\n /** 卸载时序:取消在飞会话 → 等 idle → drain 出站链(卡片定格)→ 断全部渠道。 */\r\n async stopAll(): Promise<void> {\r\n for (const rt of this.sessions.values()) rt.agent.cancel()\r\n await Promise.allSettled([...this.sessions.values()].map(async (rt) => {\r\n await rt.agent.whenIdle().catch(() => undefined)\r\n await rt.tail\r\n }))\r\n await Promise.allSettled([...this.handles.values()].map((h) => h.close()))\r\n this.handles.clear()\r\n this.approval.dispose()\r\n }\r\n\r\n private async stopChannel(botId: string): Promise<void> {\r\n const handle = this.handles.get(botId)\r\n if (handle === undefined) return\r\n this.handles.delete(botId)\r\n await handle.close().catch((error) => {\r\n this.deps.log.warn(`[project-bot] bot \"${botId}\" 渠道关闭异常:${error instanceof Error ? error.message : String(error)}`)\r\n })\r\n }\r\n\r\n private bindingStore(): BindingStore {\r\n const { bindings } = this.deps\r\n return {\r\n get: (b, c) => bindings.get(bindingKey(b, c))?.sessionId,\r\n set: async (b, c, s) => { await bindings.put(bindingKey(b, c), { sessionId: s }) },\r\n delete: async (b, c) => { await bindings.delete(bindingKey(b, c)) },\r\n deleteBot: async (b) => {\r\n for (const key of [...bindings.keys()]) {\r\n if (key.startsWith(`${b}:`)) await bindings.delete(key)\r\n }\r\n },\r\n }\r\n }\r\n}\r\n","/** preset 优先的 agent scope joiner:agentPresets 在场且 mount 成功 → 父链是 preset standing mount,\n * 宿主 spawn 驱动的 composeFrom 能认父(委派子会话继承同一组合);失败回退 toolsScope(bot 可用性优先)。 */\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { ToolsScope } from './tool-scope.ts'\n\n/** setupAgentScope 的作用域加入策略(ToolsScope 结构兼容:join 返回 unknown 使 Promise<ScopeKey> 可赋,\n * void 返回类型过窄——TS 严格模式 object 不可赋给 void)。 */\nexport interface ScopeJoiner {\n join(agentCtx: Context): Promise<unknown>\n}\n\n/** agentPresets 服务的挂载面结构类型(可选服务经 ctx.get 读取,team-preset.ts AgentPresetsLike 先例)。 */\ninterface PresetMountLike {\n mount(agentCtx: Context, id?: string): Promise<unknown>\n}\n\nexport function createScopeJoiner(ctx: Context, presetId: string, fallback: ToolsScope, warn: (msg: string) => void): ScopeJoiner {\n return {\n async join(agentCtx) {\n // join 时惰性解析(attachments 教训:apply 期一次性捕获会吃到未注册的 undefined)。\n const agentPresets = ctx.get('agentPresets', false) as PresetMountLike | undefined\n if (agentPresets !== undefined) {\n try {\n await agentPresets.mount(agentCtx, presetId)\n return\n } catch (error) {\n warn(`dsh-agent-toolkit: bot 会话挂载 preset \"${presetId}\" 失败,回退基础工具 standing scope(此后该会话委派子会话将看不到基础工具):${error instanceof Error ? error.message : String(error)}`)\n }\n }\n await fallback.join(agentCtx)\n },\n }\n}\n","/** 基础工具行的 standing scope:工具挂进祖先 scope 层,agent 加入后 restrict 才能过滤继承面。 */\nimport type { Context, Plugin } from '@deepseek-ai/cordis'\nimport { bindScopeParent, createScope, scopeOf, type Scope, type ScopeKey } from '@deepseek-ai/dsh-scope'\nimport { BASIC_TOOLS } from './basic-tools.ts'\n\n/** 工具行模块加载器(测试注入 fake;生产经动态 import 解析宿主 node_modules 中的插件包)。 */\nexport type ToolModuleLoader = (specifier: string) => Promise<Plugin>\n\n/** 默认加载器:复刻 preset mount 的模块解析——loader 的 unwrapExports 取 `default ?? 命名导出模块`。 */\nasync function loadToolModule(specifier: string): Promise<Plugin> {\n const mod: unknown = await import(specifier)\n return ((mod as { default?: unknown }).default ?? mod) as Plugin\n}\n\n/** 基础工具行 standing scope 的持有者:join 把 agent scope 挂到工具层下,dispose 随插件卸载。 */\nexport interface ToolsScope {\n /**\n * 把 agent scope 父链挂到 standing scope(工具成为继承面),并在返回前等首轮\n * 挂载落定(agent factory 会等 setup 完成,工具插件不会晚于首个 turn 就绪)。\n * agent scope 已有父链时抛错(bot 会话的 scope 父链由本方法独占绑定)。\n */\n join(agentCtx: Context): Promise<ScopeKey>\n /** 释放 standing scope(插件卸载时调用;此后 join 会按需重建)。 */\n dispose(): Promise<void>\n}\n\n/** 建一个 bot 会话共用的工具行 standing scope(所有 bot 会话挂同一套 BASIC_TOOLS)。 */\nexport function createToolsScope(ctx: Context, loadTool: ToolModuleLoader = loadToolModule): ToolsScope {\n let scope: Scope | undefined\n let mount: Promise<ScopeKey> | undefined\n let generation = 0\n\n function ensure(): Promise<ScopeKey> {\n mount ??= (async () => {\n // 失败重试换新 key:避免与失败代次的层残留状态纠缠。\n const key: ScopeKey = { origin: 'dsh-agent-toolkit', kind: 'bots-tools', gen: ++generation }\n const created = createScope(ctx, key)\n scope = created\n try {\n for (const tool of BASIC_TOOLS) {\n await created.ctx.plugin(await loadTool(tool.id), tool.config)\n }\n } catch (error) {\n if (scope === created) scope = undefined\n mount = undefined\n await created.dispose().catch(() => undefined)\n throw error\n }\n return key\n })()\n return mount\n }\n\n return {\n async join(agentCtx) {\n const agentKey = scopeOf(agentCtx)\n if (agentKey === undefined) {\n throw new Error('tools-scope: refusing to join an unscoped agent context; per-agent composition requires a scope key')\n }\n const standing = await ensure()\n bindScopeParent(agentKey, standing)\n return standing\n },\n async dispose() {\n mount = undefined\n const current = scope\n scope = undefined\n await current?.dispose()\n },\n }\n}\n","/** approval/request waterfall answerer 工厂:自有 bot 会话走 ApprovalCenter(飞书卡片),\r\n * 其余 next() 透传(web api-proxy / ACP 等)。prepend 注册抢在 api-proxy 前(其从不 next 让出)。 */\r\nimport type { ApprovalCenter, ApprovalOutcome, ApprovalRequestLike } from './center.ts'\r\n\r\nexport function createApprovalAnswerer(\r\n centerOf: () => ApprovalCenter | undefined,\r\n): (req: ApprovalRequestLike, next: () => Promise<ApprovalOutcome>) => Promise<ApprovalOutcome> {\r\n return async (req, next) => {\r\n const outcome = await centerOf()?.handleRequest(req)\r\n return outcome ?? next()\r\n }\r\n}\r\n","/** 浏览器半 RPC:单前缀路由 /dsh-agent-toolkit/api/bots + 内部路径分发。 */\r\nimport { randomBytes } from 'node:crypto'\r\nimport type { IncomingMessage, ServerResponse } from 'node:http'\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport { z } from 'zod'\r\nimport type { BotRuntime } from '../channels/runtime.ts'\r\nimport type { RegisterAppService } from './register-app.ts'\r\nimport { BOT_ID_RE, BotRecordSchema, CREDENTIAL_REF_RE, FEISHU_APP_ID_RE, type BotRecord } from './store.ts'\r\n\r\n/** 一个可选的 provider 路由(id = agentOptions.provider 的值)。 */\r\nexport interface ProviderOption { id: string; name: string }\r\n/** 一个可选的模型条目(id = agentOptions.model 的值)。 */\r\nexport interface ModelOption { id: string; name: string }\r\n\r\nexport interface ApiDeps {\r\n bots: KvTable<string, BotRecord>\r\n runtime: BotRuntime\r\n registerApp: RegisterAppService\r\n listTools(): string[]\r\n listProviders(): ProviderOption[]\r\n /** 失败由调用方(路由)兜底为空数组,不抛错。 */\r\n listModels(provider: string): Promise<ModelOption[]>\r\n /** 密钥入 credentials,返回 CredentialRef 字符串。 */\r\n storeSecret(key: string, secret: string): Promise<string>\r\n deleteSecret(ref: string): Promise<void>\r\n validateProject(path: string): boolean\r\n now(): number\r\n}\r\n\r\nconst MAX_BODY_BYTES = 64 * 1024\r\n\r\nconst CreateBodySchema = z.object({\r\n /** 缺省时后端自动生成(bot-<8 位随机小写字母数字>)。 */\r\n id: z.string().regex(BOT_ID_RE).optional(),\r\n name: z.string().min(1).max(64),\r\n project: z.string().min(1),\r\n persona: z.string().max(8000).optional(),\r\n /** 绑定的 Agent('main' 或注册表角色 id;缺省 = main)。 */\r\n agentRef: z.string().min(1).optional(),\r\n tools: z.array(z.string().min(1)).min(1).optional(),\r\n agentOptions: z.object({ provider: z.string().min(1).optional(), model: z.string().min(1).optional() }).optional(),\r\n feishu: z.object({\r\n appId: z.string().regex(FEISHU_APP_ID_RE),\r\n /** 手动填写路径:明文密钥(立即入 credentials,不落表)。 */\r\n appSecret: z.string().min(1).optional(),\r\n /** 扫码路径:registerApp 已入库,直接给引用。 */\r\n appSecretRef: z.string().regex(CREDENTIAL_REF_RE).optional(),\r\n }),\r\n})\r\n\r\nconst UpdateBodySchema = z.object({\r\n name: z.string().min(1).max(64).optional(),\r\n project: z.string().min(1).optional(),\r\n persona: z.string().max(8000).nullable().optional(),\r\n agentRef: z.string().min(1).nullable().optional(),\r\n tools: z.array(z.string().min(1)).min(1).nullable().optional(),\r\n agentOptions: z.object({ provider: z.string().min(1).optional(), model: z.string().min(1).optional() }).nullable().optional(),\r\n /** 重绑:明文新密钥(立即入 credentials)或扫码引用(已入库);null = 解绑渠道(删密钥、保留会话绑定)。 */\r\n feishu: z.object({\r\n appId: z.string().regex(FEISHU_APP_ID_RE),\r\n appSecret: z.string().min(1).optional(),\r\n appSecretRef: z.string().regex(CREDENTIAL_REF_RE).optional(),\r\n }).refine((f) => f.appSecret !== undefined || f.appSecretRef !== undefined, { message: '缺少 appSecret 或 appSecretRef' })\r\n .nullable().optional(),\r\n})\r\n\r\nfunction json(res: ServerResponse, code: number, body: unknown): void {\r\n res.writeHead(code, { 'content-type': 'application/json' }).end(JSON.stringify(body))\r\n}\r\n\r\nconst ID_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789'\r\n\r\n/** 生成 bot-<8 位随机小写字母数字>(符合 BOT_ID_RE);与现有 id 冲突时重试。 */\r\nfunction generateBotId(occupied: (id: string) => boolean): string {\r\n for (;;) {\r\n const bytes = randomBytes(8)\r\n let id = 'bot-'\r\n for (let i = 0; i < 8; i++) id += ID_CHARS[bytes[i] % ID_CHARS.length]\r\n if (!occupied(id)) return id\r\n }\r\n}\r\n\r\n/** 读 JSON body;超限 413 / 非法 JSON 400(已写响应时返回 undefined)。 */\r\nasync function readJsonBody(req: IncomingMessage, res: ServerResponse): Promise<unknown | undefined> {\r\n const chunks: Buffer[] = []\r\n let received = 0\r\n for await (const chunk of req) {\r\n const buffer = chunk as Buffer\r\n received += buffer.byteLength\r\n if (received > MAX_BODY_BYTES) {\r\n json(res, 413, { error: 'body too large' })\r\n req.destroy()\r\n return undefined\r\n }\r\n chunks.push(buffer)\r\n }\r\n try {\r\n return JSON.parse(Buffer.concat(chunks).toString('utf8'))\r\n } catch {\r\n json(res, 400, { error: 'invalid JSON body' })\r\n return undefined\r\n }\r\n}\r\n\r\nexport function createApiHandler(deps: ApiDeps): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\r\n return async (req, res) => {\r\n const url = new URL(req.url ?? '/', 'http://127.0.0.1')\r\n const sub = url.pathname.replace(/^\\/dsh-agent-toolkit\\/api\\/bots/, '') || '/'\r\n const method = req.method ?? 'GET'\r\n\r\n if (sub === '/bots' && method === 'GET') {\r\n const bots = [...deps.bots.entries()].map(([, record]) => ({ ...record, status: deps.runtime.statusOf(record.id) }))\r\n json(res, 200, { bots })\r\n return\r\n }\r\n\r\n if (sub === '/bots' && method === 'POST') {\r\n const body = await readJsonBody(req, res)\r\n if (body === undefined) return\r\n const parsed = CreateBodySchema.safeParse(body)\r\n if (!parsed.success) {\r\n json(res, 400, { error: parsed.error.issues[0]?.message ?? 'invalid body' })\r\n return\r\n }\r\n const input = parsed.data\r\n const id = input.id ?? generateBotId((candidate) => deps.bots.get(candidate) !== undefined)\r\n if (deps.bots.get(id) !== undefined) {\r\n json(res, 409, { error: `bot id \"${id}\" 已存在` })\r\n return\r\n }\r\n for (const [, existing] of deps.bots.entries()) {\r\n if (existing.feishu !== undefined && existing.feishu.appId === input.feishu.appId) {\r\n json(res, 409, { error: `appId 已被 bot \"${existing.id}\" 使用` })\r\n return\r\n }\r\n }\r\n if (!deps.validateProject(input.project)) {\r\n json(res, 400, { error: `项目路径不可用:${input.project}` })\r\n return\r\n }\r\n let appSecretRef = input.feishu.appSecretRef\r\n if (appSecretRef === undefined) {\r\n if (input.feishu.appSecret === undefined) {\r\n json(res, 400, { error: '缺少 appSecret 或 appSecretRef' })\r\n return\r\n }\r\n appSecretRef = await deps.storeSecret(id, input.feishu.appSecret)\r\n }\r\n const record = BotRecordSchema.parse({\r\n id, name: input.name, channel: 'feishu',\r\n feishu: { appId: input.feishu.appId, appSecretRef },\r\n project: input.project,\r\n ...(input.persona !== undefined ? { persona: input.persona } : {}),\r\n ...(input.agentRef !== undefined ? { agentRef: input.agentRef } : {}),\r\n ...(input.tools !== undefined ? { tools: input.tools } : {}),\r\n ...(input.agentOptions !== undefined ? { agentOptions: input.agentOptions } : {}),\r\n createdAt: deps.now(), updatedAt: deps.now(),\r\n } satisfies BotRecord)\r\n await deps.bots.put(record.id, record)\r\n await deps.runtime.reconcile(record.id)\r\n json(res, 200, { bot: { ...record, status: deps.runtime.statusOf(record.id) } })\r\n return\r\n }\r\n\r\n if (sub === '/bots' && method === 'PUT') {\r\n const id = url.searchParams.get('id') ?? ''\r\n const existing = deps.bots.get(id)\r\n if (existing === undefined) {\r\n json(res, 404, { error: `bot \"${id}\" 不存在` })\r\n return\r\n }\r\n const body = await readJsonBody(req, res)\r\n if (body === undefined) return\r\n const parsed = UpdateBodySchema.safeParse(body)\r\n if (!parsed.success) {\r\n json(res, 400, { error: parsed.error.issues[0]?.message ?? 'invalid body' })\r\n return\r\n }\r\n const input = parsed.data\r\n const project = input.project ?? existing.project\r\n if (!deps.validateProject(project)) {\r\n json(res, 400, { error: `项目路径不可用:${project}` })\r\n return\r\n }\r\n // 重绑路径:appId 先查冲突(未绑定 bot 不占 appId),再做任何副作用。\r\n if (input.feishu !== null && input.feishu !== undefined) {\r\n for (const [, other] of deps.bots.entries()) {\r\n if (other.id !== id && other.feishu?.appId === input.feishu.appId) {\r\n json(res, 409, { error: `appId 已被 bot \"${other.id}\" 使用` })\r\n return\r\n }\r\n }\r\n }\r\n // 渠道副作用:null 解绑(停渠道 + 删旧密钥);对象重绑(新密钥入库或引用 + 旧 ref ≠ 新 ref 时清旧密钥)。\r\n let appSecretRef: string | undefined\r\n if (input.feishu === null) {\r\n await deps.runtime.unbindBot(id)\r\n if (existing.feishu !== undefined) await deps.deleteSecret(existing.feishu.appSecretRef)\r\n } else if (input.feishu !== undefined) {\r\n if (input.feishu.appSecret !== undefined) {\r\n appSecretRef = await deps.storeSecret(id, input.feishu.appSecret)\r\n } else {\r\n appSecretRef = input.feishu.appSecretRef\r\n }\r\n if (existing.feishu !== undefined && existing.feishu.appSecretRef !== appSecretRef) {\r\n await deps.deleteSecret(existing.feishu.appSecretRef)\r\n }\r\n }\r\n const merged: Record<string, unknown> = { ...existing }\r\n if (input.name !== undefined) merged.name = input.name\r\n merged.project = project\r\n merged.updatedAt = deps.now()\r\n if (input.feishu === null) {\r\n delete merged.channel\r\n delete merged.feishu\r\n } else if (input.feishu !== undefined && appSecretRef !== undefined) {\r\n merged.channel = 'feishu'\r\n merged.feishu = { appId: input.feishu.appId, appSecretRef }\r\n }\r\n if (input.persona === null) delete merged.persona\r\n else if (input.persona !== undefined) merged.persona = input.persona\r\n if (input.agentRef === null) delete merged.agentRef\r\n else if (input.agentRef !== undefined) merged.agentRef = input.agentRef\r\n if (input.tools === null) delete merged.tools\r\n else if (input.tools !== undefined) merged.tools = input.tools\r\n if (input.agentOptions === null) delete merged.agentOptions\r\n else if (input.agentOptions !== undefined) merged.agentOptions = input.agentOptions\r\n const record = BotRecordSchema.parse(merged)\r\n await deps.bots.put(id, record)\r\n await deps.runtime.reconcile(id)\r\n json(res, 200, { bot: { ...record, status: deps.runtime.statusOf(id) } })\r\n return\r\n }\r\n\r\n if (sub === '/bots' && method === 'DELETE') {\r\n const id = url.searchParams.get('id') ?? ''\r\n const existing = deps.bots.get(id)\r\n if (existing === undefined) {\r\n json(res, 404, { error: `bot \"${id}\" 不存在` })\r\n return\r\n }\r\n await deps.runtime.stopBot(id)\r\n await deps.bots.delete(id)\r\n if (existing.feishu !== undefined) await deps.deleteSecret(existing.feishu.appSecretRef)\r\n json(res, 200, { ok: true })\r\n return\r\n }\r\n\r\n if (sub === '/register-app' && method === 'POST') {\r\n json(res, 200, { id: deps.registerApp.start() })\r\n return\r\n }\r\n\r\n if (sub === '/register-app/status' && method === 'GET') {\r\n const id = url.searchParams.get('id') ?? ''\r\n const state = deps.registerApp.get(id)\r\n if (state === undefined) {\r\n json(res, 404, { error: 'register session 不存在' })\r\n return\r\n }\r\n json(res, 200, { state })\r\n return\r\n }\r\n\r\n if (sub === '/tools' && method === 'GET') {\r\n json(res, 200, { tools: deps.listTools() })\r\n return\r\n }\r\n\r\n if (sub === '/providers' && method === 'GET') {\r\n json(res, 200, { providers: deps.listProviders() })\r\n return\r\n }\r\n\r\n if (sub === '/models' && method === 'GET') {\r\n // 模型列举可能走网络(adapter 探测),失败静默降级为空数组。\r\n let models: ModelOption[] = []\r\n try {\r\n models = await deps.listModels(url.searchParams.get('provider') ?? '')\r\n } catch {\r\n models = []\r\n }\r\n json(res, 200, { models })\r\n return\r\n }\r\n\r\n if (['/bots', '/register-app', '/register-app/status', '/tools', '/providers', '/models'].includes(sub)) {\r\n json(res, 405, { error: 'method not allowed' })\r\n return\r\n }\r\n json(res, 404, { error: 'not found' })\r\n }\r\n}\r\n","/** 扫码一键创建飞书应用:lark.registerApp(OAuth 2.0 Device Authorization Grant)的状态机封装。 */\r\nimport { randomUUID } from 'node:crypto'\r\n\r\n/** 扫码创建应用时申请的权限/事件/回调(流式卡片 + 收发消息 + 表情 + 通讯录基础信息 + 审批卡片回传)。\r\n * 故意不加 as const:readonly 元组不可赋值给 SDK AppAddons 的 mutable string[],\r\n * 否则 bots/index.ts 的 lark.registerApp(options) 透传会 typecheck 失败。 */\r\nexport const FEISHU_REGISTER_APP_ADDONS = {\r\n scopes: {\r\n tenant: [\r\n 'im:message',\r\n 'im:message:send_as_bot',\r\n 'cardkit:card:write',\r\n 'contact:user.base:readonly',\r\n ],\r\n },\r\n events: {\r\n items: { tenant: ['im.message.receive_v1'] },\r\n },\r\n callbacks: {\r\n items: ['card.action.trigger'],\r\n },\r\n}\r\n\r\nexport interface QRInfo {\r\n url: string\r\n expireIn: number\r\n}\r\n\r\n/** lark.registerApp 的结构化签名(便于 fake 注入)。 */\r\nexport type RegisterAppFn = (options: {\r\n signal: AbortSignal\r\n addons: typeof FEISHU_REGISTER_APP_ADDONS\r\n onQRCodeReady(info: QRInfo): void\r\n}) => Promise<{ client_id: string; client_secret: string }>\r\n\r\nexport type RegisterState =\r\n | { status: 'pending'; url?: string; expireIn?: number }\r\n | { status: 'done'; appId: string; credentialRef: string }\r\n | { status: 'error'; code: string; description?: string }\r\n\r\nexport interface RegisterAppDeps {\r\n registerApp: RegisterAppFn\r\n /** 把 appSecret 存进 credentials,返回 CredentialRef 字符串。 */\r\n storeSecret(appId: string, secret: string): Promise<string>\r\n timeoutMs: number\r\n newId?: () => string\r\n}\r\n\r\nexport class RegisterAppService {\r\n private readonly sessions = new Map<string, {\r\n state: RegisterState\r\n controller: AbortController\r\n timer: ReturnType<typeof setTimeout>\r\n }>()\r\n\r\n constructor(private readonly deps: RegisterAppDeps) {}\r\n\r\n /** 发起一轮扫码创建;返回轮询 id。 */\r\n start(): string {\r\n const id = (this.deps.newId ?? randomUUID)()\r\n const controller = new AbortController()\r\n const entry = {\r\n state: { status: 'pending' } as RegisterState,\r\n controller,\r\n timer: setTimeout(() => { controller.abort() }, this.deps.timeoutMs),\r\n }\r\n this.sessions.set(id, entry)\r\n void this.deps.registerApp({\r\n signal: controller.signal,\r\n addons: FEISHU_REGISTER_APP_ADDONS,\r\n onQRCodeReady: (info) => {\r\n entry.state = { status: 'pending', url: info.url, expireIn: info.expireIn }\r\n },\r\n }).then(async (result) => {\r\n const credentialRef = await this.deps.storeSecret(result.client_id, result.client_secret)\r\n entry.state = { status: 'done', appId: result.client_id, credentialRef }\r\n }).catch((error: unknown) => {\r\n const e = error as { code?: unknown; description?: unknown }\r\n entry.state = {\r\n status: 'error',\r\n code: typeof e.code === 'string' ? e.code : 'unknown',\r\n ...(typeof e.description === 'string' ? { description: e.description } : {}),\r\n }\r\n }).finally(() => {\r\n clearTimeout(entry.timer)\r\n })\r\n return id\r\n }\r\n\r\n get(id: string): RegisterState | undefined {\r\n return this.sessions.get(id)?.state\r\n }\r\n\r\n /** 卸载:中断全部进行中的轮询。 */\r\n dispose(): void {\r\n for (const entry of this.sessions.values()) {\r\n entry.controller.abort()\r\n clearTimeout(entry.timer)\r\n }\r\n this.sessions.clear()\r\n }\r\n}\r\n","/** bots 模块:项目机器人(飞书渠道)——多 bot 作为项目 agent 的交互入口(project-bot Node 半迁移,去 preset 化)。 */\r\nimport { existsSync } from 'node:fs'\r\nimport type { IncomingMessage, ServerResponse } from 'node:http'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { SessionId } from '@deepseek-ai/dsh-session'\r\nimport { credentialRef } from '@deepseek-ai/dsh-credentials'\r\nimport type { ImageAttachmentRef, ImageMediaType } from '@deepseek-ai/dsh-attachment'\r\n// type-only 导入激活各包对 cordis Context 的声明合并(inject 的服务属性)。\r\nimport type {} from '@deepseek-ai/dsh-system-prompt'\r\nimport type {} from '@deepseek-ai/dsh-tools'\r\nimport type {} from '@deepseek-ai/dsh-host-webserver'\r\nimport type {} from '@deepseek-ai/dsh-llm'\r\nimport type {} from '@deepseek-ai/dsh-agent-default-model'\r\nimport type { AssistantStreamFrame } from '@deepseek-ai/dsh-agent'\r\n// Side-effect type import: declaration-merges the `approval/request` waterfall event\r\n// answered below(照 host api-proxy.ts L87-90 同款;type-only,bundle 期擦除无运行时依赖)。\r\nimport type {} from '@deepseek-ai/dsh-user-approval'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport { openDomainSafely } from '../shared/storage.ts'\r\nimport { registerOptionalRoutes } from '../shared/webserver.ts'\r\nimport { createAgentsPort } from '../channels/agents-port.ts'\r\nimport type { BotChannel, ChannelTunables } from '../channels/channel.ts'\r\nimport { feishuChannel } from '../channels/feishu/index.ts'\r\nimport type { AttachmentsPort } from '../channels/inbound.ts'\r\nimport type { WorkspacePort } from '../channels/ports.ts'\r\nimport { BotRuntime } from '../channels/runtime.ts'\r\nimport { createScopeJoiner, type ScopeJoiner } from '../channels/scope-joiner.ts'\r\nimport { createToolsScope } from '../channels/tool-scope.ts'\r\nimport { createApprovalAnswerer } from '../channels/approval/answerer.ts'\r\nimport { createApiHandler } from './api.ts'\r\nimport { RegisterAppService } from './register-app.ts'\r\nimport { projectBotDomain, type Binding, type BotRecord } from './store.ts'\r\n\r\n/** project-bot Config 的 9 个全局可调参数(字段名不变;schemastery 定义与默认值源:archive/2026-08-26-merged-plugins/project-bot/src/index.ts:38-45,由 Task 15 平移进 suite Config)。 */\r\nexport interface BotsModuleConfig {\r\n /** 卡片流式更新节流间隔(毫秒)。 */\r\n cardUpdateThrottleMs: number\r\n /** 单卡真实 DSL 字节上限(含结构与转义;平台硬上限 30KB)。 */\r\n cardMaxBytes: number\r\n /** 飞书流式打字机每次打印字符数。 */\r\n cardPrintStep: number\r\n /** 过程区(思考 + 工具调用)字节上限(截尾保留最近内容)。 */\r\n processMaxBytes: number\r\n /** 扫码创建应用的轮询超时(毫秒)。 */\r\n registerAppTimeoutMs: number\r\n /** 「处理中」表情回复的 emoji_type。 */\r\n processingReactionEmoji: string\r\n /** 回传飞书的错误摘要最大字符数。 */\r\n errorDetailMaxChars: number\r\n /** 会话创建/恢复时注入「渠道 + 发起人 open_id」提示段(dsh-agent-toolkit:channel:sender)。 */\r\n injectSender: boolean\r\n /** 飞书审批卡片:bot 会话的工具提权申请改由飞书卡片审批(仅会话发起人可点)。 */\r\n approval: boolean\r\n}\r\n\r\n/** setupBots 的宿主接线依赖(registry 供运行时委派/API 消费;prompt 无消费方,Task 13 定案不装配 persona)。 */\r\nexport interface BotsDeps {\r\n registry: AgentRegistry\r\n /** bot 会话挂载的 preset id(agentTeamPreset 开启时下达;undefined = 直接 toolsScope)。 */\r\n botPresetId?: string\r\n /** 插件自有会话 id 集(cron_* 工具门控排除用;缺省不记录)。 */\r\n ownedSessions?: Set<string>\r\n}\r\n\r\nexport function setupBots(ctx: Context, config: BotsModuleConfig, deps: BotsDeps): void {\r\n const log = { warn: (m: string) => ctx.logger.warn(m), info: (m: string) => ctx.logger.info(m) }\r\n const channels: ReadonlyMap<string, BotChannel> = new Map([['feishu', feishuChannel]])\r\n const tunables: ChannelTunables = {\r\n cardUpdateThrottleMs: config.cardUpdateThrottleMs,\r\n cardMaxBytes: config.cardMaxBytes,\r\n processMaxBytes: config.processMaxBytes,\r\n cardPrintStep: config.cardPrintStep,\r\n processingReactionEmoji: config.processingReactionEmoji,\r\n }\r\n\r\n const storeSecret = async (key: string, secret: string): Promise<string> => {\r\n const ref = `project_bot_${key.replace(/[^A-Za-z0-9_]/g, '_')}`\r\n await ctx.credentials.set(credentialRef(ref), secret)\r\n return ref\r\n }\r\n\r\n /** 创作期注入已迁至 agent-setup.ts + tool-scope.ts(基础工具行 standing scope 挂载 + persona/tools)。\r\n * preset 优先 joiner(agent-bot 组合):mount 成功后委派子会话 composeFrom 认父(spec: docs/superpowers/specs/archive/2026-09-07-bot-delegation-preset-mount-design.md)。 */\r\n const toolsScope = createToolsScope(ctx)\r\n // preset 优先:mount 成功后委派子会话 composeFrom 认父;未下达 id 时维持 toolsScope 直挂。\r\n const scopeJoiner: ScopeJoiner = deps.botPresetId !== undefined\r\n ? createScopeJoiner(ctx, deps.botPresetId, toolsScope, log.warn)\r\n : toolsScope\r\n\r\n const agentsPort = createAgentsPort(ctx, scopeJoiner, deps.ownedSessions)\r\n\r\n // workspaceRegistry 是可选服务(ctx.get 非严格模式):缺失时 attach 抛错,\r\n // 由 Router 捕获降级为\"未分组 + 告警\",不阻塞消息处理。\r\n interface WorkspaceRegistryLike {\r\n create(path: string): Promise<{ attachSession(sessionId: SessionId): Promise<void> }>\r\n }\r\n const workspaceRegistry = ctx.get('workspaceRegistry', false) as WorkspaceRegistryLike | undefined\r\n const workspacePort: WorkspacePort = {\r\n async attach(cwd, sessionId) {\r\n if (workspaceRegistry === undefined) throw new Error('workspaceRegistry 服务不可用')\r\n const workspace = await workspaceRegistry.create(cwd)\r\n await workspace.attachSession(SessionId(sessionId))\r\n },\r\n }\r\n\r\n // attachments 是可选服务:**消息到达时惰性解析**(宿主 read-image 同款\"执行时再查\")。\r\n // apply 期一次性捕获不可靠——attachment-local 的 fiber 可能尚未注册完服务,\r\n // 启动期 ctx.get 拿到 undefined 会让图片消息永远走降级提示(2026-09-03 实测踩坑)。\r\n interface AttachmentsStoreLike {\r\n saveImages(inputs: readonly { data: Uint8Array; mediaType: string; name?: string }[]): Promise<readonly ImageAttachmentRef[]>\r\n }\r\n const attachmentsOf = (): AttachmentsPort | undefined => {\r\n const store = ctx.get('attachments', false) as AttachmentsStoreLike | undefined\r\n if (store === undefined) return undefined\r\n return {\r\n async saveImages(inputs) {\r\n // 保存时再取一次(与可用性判断同刻);mediaType 已由渠道按魔数判定为接受的\r\n // 图片类型,store.saveImages 内部按解码字节再验证。\r\n const current = ctx.get('attachments', false) as AttachmentsStoreLike | undefined\r\n if (current === undefined) throw new Error('attachments 服务不可用')\r\n return current.saveImages(inputs.map(({ data, mediaType, name }) => ({\r\n data,\r\n mediaType: mediaType as ImageMediaType,\r\n ...(name !== undefined ? { name } : {}),\r\n })))\r\n },\r\n }\r\n }\r\n\r\n // 存储域:open 失败挂 rejection handler 防次生崩溃,调用方仍感知失败(token-usage 同款)。\r\n // 卸载顺序由 openDomainSafely 的 beforeClose 保证:先等启动链落定、排空在飞会话与出站链\r\n // (stopAll 内含卡片定格 drain),再关存储域——close 一旦开始就拒绝新入队的写。\r\n let botsTable: import('@deepseek-ai/dsh-storage-domain').KvTable<string, BotRecord> | undefined\r\n let bindingsTable: import('@deepseek-ai/dsh-storage-domain').KvTable<string, Binding> | undefined\r\n let runtime: BotRuntime | undefined\r\n let started: Promise<void> = Promise.resolve()\r\n const domainReady = openDomainSafely(\r\n ctx,\r\n projectBotDomain,\r\n (msg) => log.warn(msg),\r\n async () => {\r\n await started.catch(() => undefined)\r\n await runtime?.stopAll()\r\n },\r\n ).then((domain) => {\r\n botsTable = domain.table('bots') as import('@deepseek-ai/dsh-storage-domain').KvTable<string, BotRecord>\r\n bindingsTable = domain.table('bindings') as import('@deepseek-ai/dsh-storage-domain').KvTable<string, Binding>\r\n return domain\r\n })\r\n\r\n const registerAppService = new RegisterAppService({\r\n registerApp: (options) => import('@larksuiteoapi/node-sdk').then((lark) => lark.registerApp(options)),\r\n storeSecret,\r\n timeoutMs: config.registerAppTimeoutMs,\r\n })\r\n\r\n started = domainReady.then(() => {\r\n runtime = new BotRuntime({\r\n bots: botsTable!,\r\n bindings: bindingsTable!,\r\n agents: agentsPort,\r\n registry: deps.registry,\r\n defaultModel: () => {\r\n const selection = ctx.agentDefaultModel.currentSelection()\r\n return { provider: selection.provider, model: selection.model }\r\n },\r\n workspace: workspacePort,\r\n channels,\r\n tunables,\r\n maxErrorDetailChars: config.errorDetailMaxChars,\r\n attachments: attachmentsOf,\r\n injectSender: config.injectSender,\r\n resolveSecret: async (ref) => (await ctx.credentials.resolve(credentialRef(ref)))?.value,\r\n validateProject: (path) => existsSync(path),\r\n log,\r\n })\r\n return runtime.startAll()\r\n })\r\n started.catch((error) => {\r\n log.warn(`[project-bot] 启动失败:${error instanceof Error ? error.message : String(error)}`)\r\n })\r\n\r\n // 出站:持久会话事件 → runtime.outbound(session id 匹配自有 runtime,其余忽略)。\r\n ctx.on('session/event', (session, event) => {\r\n runtime?.outbound.handleSessionEvent(String(session.header.id), event as { type: string; data: Record<string, unknown> })\r\n })\r\n\r\n // 出站:瞬态流式帧 → runtime.outbound(agent scoped emit,app 级订阅收到全部 agent,按自有 session 过滤)。\r\n ctx.on('agent/assistant-stream', ({ agent, frame }) => {\r\n runtime?.outbound.handleAssistantFrame(String(agent.session.id), frame)\r\n })\r\n\r\n // 审批 answerer:prepend 抢在 web api-proxy 全局 answerer 之前(其从不 next 让出);\r\n // runtime 未启动/非自有会话/发卡失败时 createApprovalAnswerer 内部 next() 透传,行为回到现状。\r\n if (config.approval) {\r\n ctx.on('approval/request', createApprovalAnswerer(() => runtime?.approval), { prepend: true })\r\n }\r\n\r\n // turn 外错误(无 turn/end 兜底):agent/error → notice 错误摘要 + 释放 inflight(outbound 内去重)。\r\n ctx.on('agent/error', ({ agent, error }) => {\r\n const text = error instanceof Error\r\n ? error.message\r\n : String((error as { message?: unknown } | null)?.message ?? error)\r\n runtime?.outbound.handleAgentError(String(agent.session.id), text)\r\n })\r\n\r\n // webServer 是可选能力(headless 无此服务):经 registerOptionalRoutes 子 fiber 惰性注册\r\n // (token-usage 同款);子 fiber 未激活时惰性、随父 fiber 卸载而清理。\r\n // 仅注册本模块自己的 /dsh-agent-toolkit/api/bots 前缀;agents/providers/tools 核心端点由\r\n // setupAgentsApi 恒启用注册(同前缀下 longest-prefix 匹配、路径互不重叠),本分支不涉足。\r\n registerOptionalRoutes(ctx, (webCtx) => {\r\n // bots handler 请求时才构造:runtime 在 started 落定后才赋值,注册期捕获会拿到 undefined。\r\n const botsHandler: (req: IncomingMessage, res: ServerResponse) => Promise<void> = async (req, res) => {\r\n if (runtime === undefined) throw new Error('runtime unavailable')\r\n await createApiHandler({\r\n bots: botsTable!,\r\n runtime,\r\n registerApp: registerAppService,\r\n listTools: () => ctx.tools.schemas().map((s) => s.name),\r\n listProviders: () => ctx.llm.listProviders().map(({ id, name }) => ({ id, name })),\r\n listModels: (provider) => ctx.llm.listModels(provider).then((models) => models.map(({ id, name }) => ({ id, name }))),\r\n storeSecret,\r\n deleteSecret: async (ref) => ctx.credentials.unset(credentialRef(ref)),\r\n validateProject: (path) => existsSync(path),\r\n now: () => Date.now(),\r\n })(req, res)\r\n }\r\n const dispose = webCtx.webServer.register({\r\n kind: 'prefix',\r\n path: '/dsh-agent-toolkit/api/bots',\r\n handler: async (req, res) => {\r\n try {\r\n // 请求时才等待自身启动链:避免连带失败与注册期捕获 undefined runtime。\r\n await started\r\n await botsHandler(req, res)\r\n } catch (error) {\r\n res.writeHead(500, { 'content-type': 'application/json' })\r\n .end(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }))\r\n }\r\n },\r\n })\r\n return () => dispose()\r\n })\r\n\r\n // 卸载:释放工具行 standing scope;中断扫码轮询;runtime drain(stopAll)与关存储域的\r\n // 顺序由 openDomainSafely 的 beforeClose 保证。\r\n ctx.effect(() => async () => {\r\n await toolsScope.dispose()\r\n })\r\n ctx.effect(() => async () => {\r\n registerAppService.dispose()\r\n })\r\n}\r\n","/** agent-bot preset 组合序列化:BASIC_TOOLS → preset 行(bot 会话挂载的最小组合,\n * 委派子会话 composeFrom 认父的前提;spec: docs/superpowers/specs/archive/2026-09-07-bot-delegation-preset-mount-design.md)。 */\nimport yaml from 'js-yaml'\nimport { BASIC_TOOLS, type BasicTool } from '../channels/basic-tools.ts'\n\n/** BASIC_TOOLS 插件包名 → preset 行 id(与 standard/agent-team 的行 id 对齐)。新增 BASIC_TOOLS 行必须在此登记。 */\nconst ROW_IDS: Record<string, string> = {\n '@deepseek-ai/dsh-persona': 'persona',\n '@deepseek-ai/dsh-agent-instructions': 'agent-instructions',\n '@deepseek-ai/dsh-tool-pwsh': 'tool-pwsh',\n '@deepseek-ai/dsh-tool-bash': 'tool-bash',\n '@deepseek-ai/dsh-tool-fs': 'tool-fs',\n '@deepseek-ai/dsh-tool-fs-search': 'tool-fs-search',\n}\n\nexport const BOT_PRESET_NAME = 'Bot 会话'\nexport const BOT_PRESET_DESCRIPTION = '飞书 bot 会话组合:基础工具行(persona/instructions/shell/fs/fs-search);委派子会话经 composeFrom 继承同一组合'\n\n/** BASIC_TOOLS → preset 行对象数组(未登记映射的包名抛错,防新增工具行静默丢 id)。 */\nexport function serializeBotRows(tools: readonly BasicTool[]): Record<string, unknown>[] {\n return tools.map((tool) => {\n const rowId = ROW_IDS[tool.id]\n if (rowId === undefined) throw new Error(`bot-preset: BASIC_TOOLS 行 ${tool.id} 未登记 preset 行 id 映射`)\n return { id: rowId, name: tool.id, ...tool.config !== undefined ? { config: tool.config } : {} }\n })\n}\n\n/** agent-bot composition 文本(平台相关 shell 行已由 BASIC_TOOLS 选定,不用 !!js)。 */\nexport function botPresetComposition(): string {\n return yaml.dump(serializeBotRows(BASIC_TOOLS), { lineWidth: -1 })\n}\n","/**\r\n * Agent 团队 preset 自动生成:派生宿主当前 shipped standard composition,\r\n * 文本级禁用 subagent 工具族 4 个行,写入首个 trust=user 的 preset root。\r\n * 设计:docs/superpowers/specs/archive/2026-09-02-agent-team-preset-design.md\r\n */\r\nimport { access, mkdir, readFile, writeFile } from 'node:fs/promises'\r\nimport { join, resolve } from 'node:path'\r\nimport yaml from 'js-yaml'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport { expandHomePath } from '@deepseek-ai/dsh-home-paths'\r\nimport { botPresetComposition, BOT_PRESET_NAME, BOT_PRESET_DESCRIPTION } from './bot-preset.ts'\r\n\r\n/** 本功能的可调配置(Config schema 在 ../index.ts)。 */\r\nexport interface AgentTeamPresetConfig {\r\n /** 总开关:false 时启动不生成/刷新 preset。 */\r\n enabled: boolean\r\n /** 生成的 preset id(即目录名)。 */\r\n id: string\r\n /** 源 preset id,读其 composition 做派生。 */\r\n source: string\r\n /** preset.yml 的显示名。 */\r\n name: string\r\n /** preset.yml 的描述。 */\r\n description: string\r\n /** bot 会话挂载的最小 preset id(内容 = BASIC_TOOLS 5 行)。 */\r\n botsId: string\r\n}\r\n\r\n/** 禁用目标行:覆盖与 team_delegate 竞争/配套的 5 个模型可见工具所属的 4 个行。 */\r\nexport const TEAM_PRESET_DISABLED_ROWS = [\r\n 'tool-subagent',\r\n 'tool-subagent-fork',\r\n 'tool-subagent-control',\r\n 'tool-subagent-list-agents',\r\n] as const\r\n\r\n/**\r\n * 文本级锚点改写:对 4 个目标行各插入一行 `disabled: true`(缩进 = 锚点缩进 + 2 空格)。\r\n * 锚点是整行精确匹配 `- id: <行id>`(忽略首尾空白),防 tool-subagent 误中\r\n * tool-subagent-fork / tool-subagent-control 前缀;锚点所属块内(锚点行之后、\r\n * 首个缩进 <= 锚点缩进的非空行之前)已有 `disabled:` 键则跳过——既幂等,也避免\r\n * 与宿主已有的 `disabled: !!js ...` 撞出 YAML 重复键。锚点缺失 warn 并跳过该锚点,\r\n * 其余照常。除插入行外文本逐字节不变。\r\n */\r\nexport function disableSubagentRows(source: string, warn: (msg: string) => void): string {\r\n const lines = source.split('\\n')\r\n for (const row of TEAM_PRESET_DISABLED_ROWS) {\r\n const anchor = `- id: ${row}`\r\n const index = lines.findIndex((line) => line.trim() === anchor)\r\n if (index === -1) {\r\n warn(`dsh-agent-toolkit: agent-team preset 锚点行 \"${anchor}\" 在源 composition 中缺失,已跳过`)\r\n continue\r\n }\r\n const indent = lines[index].length - lines[index].trimStart().length\r\n let hasDisabled = false\r\n for (let i = index + 1; i < lines.length; i += 1) {\r\n const line = lines[i]\r\n if (line.trim() === '') continue\r\n if (line.length - line.trimStart().length <= indent) break\r\n if (/^\\s*disabled\\s*:/.test(line)) {\r\n hasDisabled = true\r\n break\r\n }\r\n }\r\n if (hasDisabled) continue\r\n lines.splice(index + 1, 0, `${' '.repeat(indent + 2)}disabled: true`)\r\n }\r\n return lines.join('\\n')\r\n}\r\n\r\n// 三个文件名镜像宿主 @deepseek-ai/dsh-agent-presets 的 COMPOSITION_FILE / METADATA_FILE\r\n// 契约(文件名即 discovery 协议);不 import 宿主常量,避免新增运行时耦合。\r\nconst COMPOSITION_FILE = 'agent.cordis.yml'\r\nconst METADATA_FILE = 'preset.yml'\r\n/**\r\n * 生成目录的归属标记:无此标记的同名目录视为用户手工 preset,不覆盖。\r\n * 标记必须在 mkdir 后最先写入(marker-first):这样写 composition/metadata 失败留下的是\r\n * 带标记的半成品目录,下次启动会被正常重写自愈;若最后才写标记,则半成品目录无标记、\r\n * 会被误判为用户手工 preset 而永久卡死不覆盖。\r\n */\r\nconst MARKER_FILE = '.generated-by'\r\nconst MARKER_CONTENT = 'dsh-agent-toolkit'\r\n/** 镜像宿主 PRESET_ID:preset id 即目录名,正则白名单是路径逃逸的 containment 边界。 */\r\nconst PRESET_ID = /^[a-z0-9][a-z0-9-]*$/\r\n\r\nconst GENERATED_HEADER = '# 本文件由 dsh-agent-toolkit 自动生成,勿手改(每次启动重写)。\\n'\r\n\r\n/**\r\n * agentPresets 服务的结构类型。可选服务经 ctx.get 读取(宿主约定:可选服务用\r\n * ctx.get,不进 inject),结构类型避免对 @deepseek-ai/dsh-agent-presets 的依赖\r\n *(bots/index.ts 的 WorkspaceRegistryLike 先例)。\r\n */\r\ninterface AgentPresetsLike {\r\n readonly roots: readonly { path: string; trust: 'system' | 'user' }[]\r\n read(id: string): Promise<string>\r\n}\r\n\r\n/**\r\n * 写一个生成 preset 目录:无标记的同名用户目录不覆盖(warn 返回 false);marker-first 写入。\r\n * composition / metadata 写失败(含半途失败)留下的带标记目录,下次启动会被正常重写自愈。\r\n */\r\nasync function writeGeneratedPreset(\r\n dir: string,\r\n composition: string,\r\n metadata: { name: string; description: string },\r\n warn: (msg: string) => void,\r\n): Promise<boolean> {\r\n const markerPath = join(dir, MARKER_FILE)\r\n let dirExists = true\r\n try {\r\n await access(dir)\r\n } catch {\r\n dirExists = false\r\n }\r\n if (dirExists) {\r\n let marked = false\r\n try {\r\n marked = (await readFile(markerPath, 'utf8')).trim() === MARKER_CONTENT\r\n } catch {\r\n // 无标记文件 = 用户手工同名 preset。\r\n }\r\n if (!marked) {\r\n warn(`dsh-agent-toolkit: ${dir} 已存在且非本插件生成,不覆盖,跳过生成`)\r\n return false\r\n }\r\n }\r\n await mkdir(dir, { recursive: true })\r\n await writeFile(markerPath, `${MARKER_CONTENT}\\n`, 'utf8')\r\n await writeFile(join(dir, COMPOSITION_FILE), composition, 'utf8')\r\n await writeFile(join(dir, METADATA_FILE), yaml.dump(metadata, { lineWidth: -1 }), 'utf8')\r\n return true\r\n}\r\n\r\n/**\r\n * 启动时生成/刷新 agent-team 与 agent-bot 两个 preset。所有失败路径 warn 降级,不影响插件其余功能。\r\n * 不设为默认 preset、卸载不删目录(可能有会话在用;composition 不引用 toolkit 行,残留 preset 自身\r\n * 仍可用)。每次启动重写:standing mount 按文件代际,重写只影响新会话。agent-bot 内容来自 BASIC_TOOLS,\r\n * 不依赖源 preset 读取(read 失败只跳过 agent-team);两块独立 try/catch、独立 marker 保护。\r\n */\r\nexport async function setupAgentTeamPreset(ctx: Context, config: AgentTeamPresetConfig): Promise<void> {\r\n if (!config.enabled) return\r\n const warn = (msg: string): void => { ctx.logger.warn(msg) }\r\n // rc2 等无 presets 的旧宿主:静默跳过(旧宿主无 subagent/team_delegate 工具竞争问题)。\r\n const agentPresets = ctx.get('agentPresets', false) as AgentPresetsLike | undefined\r\n if (agentPresets === undefined) return\r\n // 提前解析 trust=user root 供两块共用;缺席时两者都跳过。\r\n const root = agentPresets.roots.find((r) => r.trust === 'user')\r\n if (root === undefined) {\r\n warn('dsh-agent-toolkit: preset roots 中无 trust=user 的目录,跳过 agent-team / agent-bot 生成')\r\n return\r\n }\r\n const presetDir = (id: string): string => join(resolve(expandHomePath(root.path)), id)\r\n\r\n // agent-team:派生源 preset,文本级禁用 subagent 工具族 4 行;read 失败只跳过本块。\r\n if (!PRESET_ID.test(config.id)) {\r\n warn(`dsh-agent-toolkit: agentTeamPreset.id \"${config.id}\" 不是合法 preset id,跳过 agent-team 生成`)\r\n } else {\r\n let source: string | undefined\r\n try {\r\n source = await agentPresets.read(config.source)\r\n } catch (error) {\r\n warn(`dsh-agent-toolkit: 读取源 preset \"${config.source}\" 失败,跳过 agent-team 生成:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n if (source !== undefined) {\r\n const dir = presetDir(config.id)\r\n try {\r\n await writeGeneratedPreset(\r\n dir,\r\n GENERATED_HEADER + disableSubagentRows(source, warn),\r\n { name: config.name, description: config.description },\r\n warn,\r\n )\r\n } catch (error) {\r\n warn(`dsh-agent-toolkit: 写入 agent-team preset 失败(${dir}):${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n }\r\n }\r\n\r\n // botsId 与 id 相同:agent-bot 块会覆盖 agent-team 的 composition + preset.yml,直接跳过(agent-team 照常生成)。\r\n if (config.id === config.botsId) {\r\n warn(`dsh-agent-toolkit: agentTeamPreset.id 与 agentTeamPreset.botsId 相同(均为 \"${config.id}\"),跳过 agent-bot 生成`)\r\n } else {\r\n // agent-bot:bot 会话挂载的最小组合,内容来自 BASIC_TOOLS,不依赖源 preset 读取。\r\n if (!PRESET_ID.test(config.botsId)) {\r\n warn(`dsh-agent-toolkit: agentTeamPreset.botsId \"${config.botsId}\" 不是合法 preset id,跳过 agent-bot 生成`)\r\n } else {\r\n try {\r\n await writeGeneratedPreset(\r\n presetDir(config.botsId),\r\n GENERATED_HEADER + botPresetComposition(),\r\n { name: BOT_PRESET_NAME, description: BOT_PRESET_DESCRIPTION },\r\n warn,\r\n )\r\n } catch (error) {\r\n warn(`dsh-agent-toolkit: 写入 agent-bot preset 失败:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n }\r\n }\r\n}\r\n","/** schedule 模块存储域声明:CronTask/CronRun 记录 schema + domain 布局的单一来源。*/\r\nimport { z } from 'zod'\r\nimport { defineDomain, domainTable, type KvTable } from '@deepseek-ai/dsh-storage-domain'\r\n\r\n/** 调度规则三选一:cron(5 字段,可选 IANA 时区,省略 = 进程时区)/ at(RFC 3339 一次性)/ every(≥60s,创建时间为锚)。*/\r\nexport const CronScheduleSchema = z.discriminatedUnion('kind', [\r\n z.object({ kind: z.literal('cron'), expr: z.string().min(1), timeZone: z.string().min(1).optional() }),\r\n z.object({ kind: z.literal('at'), at: z.string().min(1) }),\r\n z.object({ kind: z.literal('every'), seconds: z.number().int().min(60) }),\r\n])\r\nexport type CronSchedule = z.infer<typeof CronScheduleSchema>\r\n\r\n/** 执行目标:主 Agent(宿主默认模型,无 persona/restrict)或注册表角色(persona/model/工具白名单随角色)。*/\r\nexport const CronTargetSchema = z.discriminatedUnion('kind', [\r\n z.object({ kind: z.literal('main') }),\r\n z.object({ kind: z.literal('role'), roleId: z.string().min(1) }),\r\n])\r\nexport type CronTarget = z.infer<typeof CronTargetSchema>\r\n\r\nexport const CronTaskSchema = z.object({\r\n id: z.string().min(1),\r\n name: z.string().min(1).max(64),\r\n prompt: z.string().min(1).max(8000),\r\n cwd: z.string().min(1),\r\n schedule: CronScheduleSchema,\r\n target: CronTargetSchema,\r\n catchup: z.boolean(),\r\n enabled: z.boolean(),\r\n /** 调度器维护的持久缓存(重启 rearm 依据),UTC ISO 串。*/\r\n nextRunAt: z.string().nullable(),\r\n createdAt: z.string(),\r\n updatedAt: z.string(),\r\n})\r\nexport type CronTask = z.infer<typeof CronTaskSchema>\r\n\r\nexport const CronRunSchema = z.object({\r\n id: z.string().min(1),\r\n taskId: z.string().min(1),\r\n triggeredAt: z.string(),\r\n finishedAt: z.string().optional(),\r\n status: z.enum(['running', 'ok', 'error', 'skipped-overlap']),\r\n /** 本次执行新建的会话 id(skipped-overlap 无会话)。*/\r\n sessionId: z.string().optional(),\r\n /** 错误摘要(截断)。*/\r\n error: z.string().optional(),\r\n})\r\nexport type CronRun = z.infer<typeof CronRunSchema>\r\n\r\n/** domain 名/表名均受 UNIT_NAME_RE 约束(^[a-z][a-z0-9_]*$),不允许连字符。*/\r\nexport const scheduleDomain = defineDomain({\r\n name: 'dsh_agent_toolkit_schedule',\r\n version: 1,\r\n tables: {\r\n tasks: domainTable<string, CronTask>(CronTaskSchema),\r\n runs: domainTable<string, CronRun>(CronRunSchema),\r\n // 一次性标记位(沿用 agents store 的 meta 模式;当前无标记消费者,保留表位)。\r\n meta: domainTable<string, { value: string }>(z.object({ value: z.string() })),\r\n },\r\n})\r\n\r\n/** 某任务的 run 列表(新 → 旧;同刻按 id 倒序稳定化)。*/\r\nexport function listRuns(runs: KvTable<string, CronRun>, taskId: string): CronRun[] {\r\n return [...runs.entries()]\r\n .map(([, run]) => run)\r\n .filter((run) => run.taskId === taskId)\r\n .sort((a, b) => b.triggeredAt.localeCompare(a.triggeredAt) || b.id.localeCompare(a.id))\r\n}\r\n\r\n/** 环形保留某任务最近 limit 条 run,超出删最旧。*/\r\nexport async function trimRuns(runs: KvTable<string, CronRun>, taskId: string, limit: number): Promise<void> {\r\n const mine = listRuns(runs, taskId)\r\n for (const run of mine.slice(limit)) await runs.delete(run.id)\r\n}\r\n\r\n/** 删除任务连带清运行历史。*/\r\nexport async function deleteRunsOf(runs: KvTable<string, CronRun>, taskId: string): Promise<void> {\r\n for (const run of listRuns(runs, taskId)) await runs.delete(run.id)\r\n}\r\n","/** 定时任务浏览器半 RPC:单前缀路由 /dsh-agent-toolkit/api/cron + 内部路径分发(bots/api.ts 同款骨架)。 */\r\nimport type { IncomingMessage, ServerResponse } from 'node:http'\r\nimport { z } from 'zod'\r\nimport { json, readJsonBody } from '../shared/http.ts'\r\nimport type { CronService, CronTaskInput } from './service.ts'\r\nimport { CronScheduleSchema, CronTargetSchema } from './store.ts'\r\n\r\nexport interface CronApiDeps {\r\n service: CronService\r\n /** 候选 cwd 列表(workspaceRegistry.list() 的 path 集;服务缺席时调用方给空数组)。 */\r\n listProjects(): string[]\r\n runHistoryLimit: number\r\n}\r\n\r\nconst CreateBodySchema = z.object({\r\n name: z.string().min(1).max(64),\r\n prompt: z.string().min(1).max(8000),\r\n cwd: z.string().min(1),\r\n schedule: CronScheduleSchema,\r\n target: CronTargetSchema,\r\n catchup: z.boolean(),\r\n enabled: z.boolean(),\r\n}) satisfies z.ZodType<CronTaskInput>\r\nconst UpdateBodySchema = CreateBodySchema.partial()\r\n\r\nexport function createCronApiHandler(deps: CronApiDeps): (req: IncomingMessage, res: ServerResponse) => Promise<void> {\r\n return async (req, res) => {\r\n const url = new URL(req.url ?? '/', 'http://127.0.0.1')\r\n const sub = url.pathname.replace(/^\\/dsh-agent-toolkit\\/api\\/cron/, '') || '/'\r\n const method = req.method ?? 'GET'\r\n const taskMatch = /^\\/tasks\\/([^/]+)$/.exec(sub)\r\n const triggerMatch = /^\\/tasks\\/([^/]+)\\/trigger$/.exec(sub)\r\n const runsMatch = /^\\/tasks\\/([^/]+)\\/runs$/.exec(sub)\r\n\r\n if (sub === '/tasks' && method === 'GET') {\r\n json(res, 200, { tasks: deps.service.list() })\r\n return\r\n }\r\n\r\n if (sub === '/tasks' && method === 'POST') {\r\n const body = await readJsonBody(req, res)\r\n if (body === undefined) return\r\n const parsed = CreateBodySchema.safeParse(body)\r\n if (!parsed.success) {\r\n json(res, 400, { error: parsed.error.issues[0]?.message ?? 'invalid body' })\r\n return\r\n }\r\n const result = await deps.service.create(parsed.data)\r\n if (!result.ok) {\r\n json(res, 400, { error: result.error })\r\n return\r\n }\r\n json(res, 200, { task: result.value })\r\n return\r\n }\r\n\r\n if (taskMatch !== null && method === 'PUT') {\r\n const id = decodeURIComponent(taskMatch[1])\r\n if (deps.service.get(id) === undefined) {\r\n json(res, 404, { error: `定时任务 \"${id}\" 不存在` })\r\n return\r\n }\r\n const body = await readJsonBody(req, res)\r\n if (body === undefined) return\r\n const parsed = UpdateBodySchema.safeParse(body)\r\n if (!parsed.success) {\r\n json(res, 400, { error: parsed.error.issues[0]?.message ?? 'invalid body' })\r\n return\r\n }\r\n const result = await deps.service.update(id, parsed.data)\r\n if (!result.ok) {\r\n json(res, 400, { error: result.error })\r\n return\r\n }\r\n json(res, 200, { task: result.value })\r\n return\r\n }\r\n\r\n if (taskMatch !== null && method === 'DELETE') {\r\n const id = decodeURIComponent(taskMatch[1])\r\n if (deps.service.get(id) === undefined) {\r\n json(res, 404, { error: `定时任务 \"${id}\" 不存在` })\r\n return\r\n }\r\n const result = await deps.service.remove(id)\r\n if (!result.ok) {\r\n json(res, 400, { error: result.error })\r\n return\r\n }\r\n json(res, 200, { ok: true })\r\n return\r\n }\r\n\r\n if (triggerMatch !== null && method === 'POST') {\r\n const id = decodeURIComponent(triggerMatch[1])\r\n if (deps.service.get(id) === undefined) {\r\n json(res, 404, { error: `定时任务 \"${id}\" 不存在` })\r\n return\r\n }\r\n const result = await deps.service.trigger(id)\r\n if (!result.ok) {\r\n // 运行中冲突 409;其余(理论上只有不存在,已被预检拦截)400。\r\n json(res, /正在运行/.test(result.error) ? 409 : 400, { error: result.error })\r\n return\r\n }\r\n json(res, 200, { run: result.value })\r\n return\r\n }\r\n\r\n if (runsMatch !== null && method === 'GET') {\r\n const id = decodeURIComponent(runsMatch[1])\r\n if (deps.service.get(id) === undefined) {\r\n json(res, 404, { error: `定时任务 \"${id}\" 不存在` })\r\n return\r\n }\r\n json(res, 200, { runs: deps.service.runsOf(id, deps.runHistoryLimit) })\r\n return\r\n }\r\n\r\n if (sub === '/projects' && method === 'GET') {\r\n json(res, 200, { projects: deps.listProjects() })\r\n return\r\n }\r\n\r\n if (sub === '/tasks' || taskMatch !== null || triggerMatch !== null || runsMatch !== null || sub === '/projects') {\r\n json(res, 405, { error: 'method not allowed' })\r\n return\r\n }\r\n json(res, 404, { error: 'not found' })\r\n }\r\n}\r\n","/** 定时任务执行器:输入一条 task,输出一条 run 记录(建会话 → followup → whenIdle/超时 → 落库)。 */\r\nimport { createUserMessage } from '@deepseek-ai/dsh-llm'\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport { roleAgentOptions, roleHooks } from '../channels/role-assembly.ts'\r\nimport type { AgentHooks, AgentSection, AgentsPort, DefaultModelAccessor, WorkspacePort } from '../channels/ports.ts'\r\nimport { trimRuns, type CronRun, type CronTask } from './store.ts'\r\n\r\n/** 来源段名:声明本会话由定时任务触发(order 20,与渠道 sender 段同位)。 */\r\nexport const TASK_SECTION_NAME = 'dsh-agent-toolkit:schedule:task'\r\n\r\nexport function taskSectionText(task: CronTask, triggeredAt: string): string {\r\n return `本会话由定时任务「${task.name}」(id: ${task.id})于 ${triggeredAt} 触发。`\r\n}\r\n\r\n/** 错误摘要最大字符数(对齐 feishu.errorDetailMaxChars 默认 500)。 */\r\nconst ERROR_MAX_CHARS = 500\r\n\r\nexport interface ExecutorDeps {\r\n agents: AgentsPort\r\n registry: AgentRegistry\r\n /** 宿主默认模型(main 形态与未自配模型的角色的模型来源)。 */\r\n defaultModel: DefaultModelAccessor\r\n workspace: WorkspacePort\r\n runs: KvTable<string, CronRun>\r\n runHistoryLimit: number\r\n /** 单次运行 followup→whenIdle 超时(Config schedule.runTimeoutMinutes × 60_000)。 */\r\n runTimeoutMs: number\r\n warn: (msg: string) => void\r\n now(): number\r\n newSessionId(): string\r\n newRunId(): string\r\n /** 超时计时(测试注入可控 Promise;生产为 setTimeout 包装)。 */\r\n delay(ms: number): Promise<void>\r\n}\r\n\r\nexport interface Executor {\r\n /** 执行一次任务:永不抛错,结果体现在返回的 run 记录。 */\r\n trigger(task: CronTask): Promise<CronRun>\r\n}\r\n\r\nclass RunTimeoutError extends Error {\r\n constructor() { super('timeout') }\r\n}\r\n\r\nexport function createExecutor(deps: ExecutorDeps): Executor {\r\n async function persist(run: CronRun): Promise<void> {\r\n await deps.runs.put(run.id, run)\r\n await trimRuns(deps.runs, run.taskId, deps.runHistoryLimit)\r\n }\r\n\r\n return {\r\n async trigger(task) {\r\n const triggeredAt = new Date(deps.now()).toISOString()\r\n const sessionId = deps.newSessionId()\r\n const run: CronRun = { id: deps.newRunId(), taskId: task.id, triggeredAt, status: 'running', sessionId }\r\n await persist(run)\r\n const finish = async (status: CronRun['status'], error?: string): Promise<CronRun> => {\r\n const done: CronRun = {\r\n ...run,\r\n status,\r\n finishedAt: new Date(deps.now()).toISOString(),\r\n ...(error !== undefined ? { error: error.slice(0, ERROR_MAX_CHARS) } : {}),\r\n }\r\n await persist(done)\r\n return done\r\n }\r\n\r\n // 解析装配(main/role 共用序列,仅装配不同;roleId 缺失降级 main 并 warn,同 Router 语义)。\r\n const source: AgentSection = { name: TASK_SECTION_NAME, order: 20, text: taskSectionText(task, triggeredAt) }\r\n let agentOptions: { provider?: string; model?: string }\r\n let hooks: AgentHooks\r\n const roleId = task.target.kind === 'role' ? task.target.roleId : 'main'\r\n const role = roleId === 'main' ? undefined : deps.registry.get(roleId)\r\n if (roleId === 'main' || role === undefined) {\r\n if (roleId !== 'main' && role === undefined) {\r\n deps.warn(`[schedule] 定时任务 \"${task.id}\" 的角色 \"${roleId}\" 不存在,降级主 Agent 形态`)\r\n }\r\n agentOptions = deps.defaultModel()\r\n hooks = { sections: [source] }\r\n } else {\r\n const base = roleHooks(role)\r\n agentOptions = roleAgentOptions(role, deps.defaultModel)\r\n hooks = { ...base, sections: [...(base.sections ?? []), source] }\r\n }\r\n\r\n let agent\r\n try {\r\n agent = await deps.agents.create({ sessionId, cwd: task.cwd, agentOptions, hooks })\r\n } catch (error) {\r\n return finish('error', error instanceof Error ? error.message : String(error))\r\n }\r\n try {\r\n await deps.workspace.attach(task.cwd, sessionId)\r\n } catch (error) {\r\n // attach 失败仅告警(会话降级为未分组),不阻塞执行——同 Router.attach。\r\n deps.warn(`[schedule] 会话 ${sessionId} 挂载 workspace 失败:${error instanceof Error ? error.message : String(error)}`)\r\n }\r\n // 必须经 createUserMessage 包装(裸字符串会让 turn 管线读 message.source.kind 崩溃)。\r\n agent.followup(createUserMessage({\r\n content: [{ type: 'text', text: task.prompt }],\r\n source: { kind: 'user' },\r\n }))\r\n // race 落败方的迟到 rejection 不变 unhandled(先各挂 noop catch;race 自身引用不受影响)。\r\n const idle = agent.whenIdle()\r\n idle.catch(() => undefined)\r\n const timeout = deps.delay(deps.runTimeoutMs).then(() => { throw new RunTimeoutError() })\r\n timeout.catch(() => undefined)\r\n try {\r\n await Promise.race([idle, timeout])\r\n return await finish('ok')\r\n } catch (error) {\r\n if (error instanceof RunTimeoutError) {\r\n agent.cancel()\r\n return await finish('error', `timeout(超过 ${Math.round(deps.runTimeoutMs / 60_000)} 分钟未空闲,已取消)`)\r\n }\r\n return await finish('error', error instanceof Error ? error.message : String(error))\r\n }\r\n },\r\n }\r\n}\r\n","/** cron/at/every 纯时间运算:校验、下一触发点、预览、启动 rearm。全部注入 now,无隐藏时钟。*/\r\nimport { Cron } from 'croner'\r\nimport type { CronSchedule, CronTask } from './store.ts'\r\n\r\n/** croner 选项:paused 仅做解析与预测,不注册真实定时器(计时由调度器 tick 驱动)。*/\r\nfunction cronerOptions(schedule: Extract<CronSchedule, { kind: 'cron' }>): { paused: true; timezone?: string } {\r\n return { paused: true, ...(schedule.timeZone !== undefined ? { timezone: schedule.timeZone } : {}) }\r\n}\r\n\r\n/** 创建/更新即校验;合法返回 undefined,非法返回错误消息(不入库由调用方保证)。*/\r\nexport function validateSchedule(schedule: CronSchedule, nowMs: number): string | undefined {\r\n switch (schedule.kind) {\r\n case 'cron': {\r\n const fields = schedule.expr.trim().split(/\\s+/)\r\n if (fields.length !== 5) return `cron 表达式须为 5 字段(分 时 日 月 周),收到 ${fields.length} 字段;秒级/年字段暂不开放`\r\n if (schedule.timeZone !== undefined) {\r\n try {\r\n new Intl.DateTimeFormat('en-US', { timeZone: schedule.timeZone })\r\n } catch {\r\n return `未知时区:${schedule.timeZone}`\r\n }\r\n }\r\n try {\r\n new Cron(schedule.expr, cronerOptions(schedule))\r\n } catch (error) {\r\n return `非法 cron 表达式\"${schedule.expr}\":${error instanceof Error ? error.message : String(error)}`\r\n }\r\n return undefined\r\n }\r\n case 'at': {\r\n const t = Date.parse(schedule.at)\r\n if (Number.isNaN(t)) return `非法 at 时间(须 RFC 3339):${schedule.at}`\r\n if (t <= nowMs) return `at 时间须在未来:${schedule.at}`\r\n return undefined\r\n }\r\n case 'every':\r\n return undefined // seconds ≥ 60 整数由 schema 保证\r\n }\r\n}\r\n\r\n/** 下一触发点(epoch ms);无未来触发点(at 过期等)返回 null。*/\r\nexport function nextOccurrence(schedule: CronSchedule, createdAtMs: number, nowMs: number): number | null {\r\n switch (schedule.kind) {\r\n case 'cron': {\r\n const next = new Cron(schedule.expr, cronerOptions(schedule)).nextRun(new Date(nowMs))\r\n return next === null ? null : next.getTime()\r\n }\r\n case 'at': {\r\n const t = Date.parse(schedule.at)\r\n return t > nowMs ? t : null\r\n }\r\n case 'every': {\r\n const intervalMs = schedule.seconds * 1000\r\n if (nowMs < createdAtMs) return createdAtMs\r\n // 创建锚点对齐的下一间隔:跳过中间错过的,不枚举积压。\r\n const k = Math.floor((nowMs - createdAtMs) / intervalMs) + 1\r\n return createdAtMs + k * intervalMs\r\n }\r\n }\r\n}\r\n\r\n/** 「未来 count 次触发」预览(epoch ms 数组,长度 ≤ count;供 UI 表单与调试)。*/\r\nexport function previewOccurrences(schedule: CronSchedule, count: number, createdAtMs: number, nowMs: number): number[] {\r\n const out: number[] = []\r\n let cursor = nowMs\r\n for (let i = 0; i < count; i++) {\r\n const next = nextOccurrence(schedule, createdAtMs, cursor)\r\n if (next === null) break\r\n out.push(next)\r\n cursor = next + 1\r\n }\r\n return out\r\n}\r\n\r\n/**\r\n * 启动 rearm:对一条持久化任务重算 enabled/nextRunAt(无变化返回原引用,调用方按引用决定是否写回)。\r\n * - nextRunAt 仍在未来 → 保持;\r\n * - 已过期且 catchup → 设为「立即」(首个 tick 补跑一次);\r\n * - 已过期且非 catchup → 下一未来触发点;没有(at 一次性)→ enabled=false、nextRunAt=null(过期即作废)。\r\n */\r\nexport function rearmTask(task: CronTask, nowMs: number): CronTask {\r\n if (!task.enabled) return task.nextRunAt === null ? task : { ...task, nextRunAt: null }\r\n const persisted = task.nextRunAt === null ? null : Date.parse(task.nextRunAt)\r\n if (persisted !== null && persisted > nowMs) return task\r\n if (persisted !== null && task.catchup) return { ...task, nextRunAt: new Date(nowMs).toISOString() }\r\n const next = nextOccurrence(task.schedule, Date.parse(task.createdAt), nowMs)\r\n return next === null\r\n ? { ...task, enabled: false, nextRunAt: null }\r\n : { ...task, nextRunAt: new Date(next).toISOString() }\r\n}\r\n\r\n/** 创建/更新后的 fresh 重算(catchup 是停机补跑语义,不适用于编辑路径)。*/\r\nexport function recomputeTask(task: CronTask, nowMs: number): CronTask {\r\n if (!task.enabled) return { ...task, nextRunAt: null }\r\n const next = nextOccurrence(task.schedule, Date.parse(task.createdAt), nowMs)\r\n return next === null\r\n ? { ...task, enabled: false, nextRunAt: null }\r\n : { ...task, nextRunAt: new Date(next).toISOString() }\r\n}\r\n\r\n/** 触发/跳过后推进:cron/every 取 now 之后下一触发点;at 一次性作废。*/\r\nexport function advanceAfterTrigger(task: CronTask, nowMs: number): CronTask {\r\n if (task.schedule.kind === 'at') return { ...task, enabled: false, nextRunAt: null }\r\n const next = nextOccurrence(task.schedule, Date.parse(task.createdAt), nowMs)\r\n return next === null\r\n ? { ...task, enabled: false, nextRunAt: null }\r\n : { ...task, nextRunAt: new Date(next).toISOString() }\r\n}\r\n","/** 调度引擎:启动 rearm + 周期 tick + 重叠保护 + 触发后推进。计时由接线层(ctx.interval 30s)驱动。 */\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport { advanceAfterTrigger, rearmTask, recomputeTask } from './timing.ts'\r\nimport { trimRuns, type CronRun, type CronTask } from './store.ts'\r\n\r\nexport interface SchedulerDeps {\r\n tasks: KvTable<string, CronTask>\r\n runs: KvTable<string, CronRun>\r\n runHistoryLimit: number\r\n /** executor.trigger:契约上永不抛错(异常已落 run 记录);仍 catch 兜底。 */\r\n execute(task: CronTask): Promise<unknown>\r\n now(): number\r\n newRunId(): string\r\n warn(msg: string): void\r\n}\r\n\r\nexport interface Scheduler {\r\n /** 启动 rearm:全部任务按 catchup 语义重算(写回有变化的行)。 */\r\n rearmAll(): Promise<void>\r\n /** 一次 tick:触发全部到期任务(执行异步进行,不阻塞 tick 返回)。 */\r\n tick(): Promise<void>\r\n /** 创建/更新后 fresh 重算 nextRunAt(不执行、不落库——调用方负责 put)。 */\r\n recompute(task: CronTask): CronTask\r\n /** 手动触发一次(不受 enabled 影响;不存在/运行中抛错)。不改变 nextRunAt。 */\r\n triggerManual(taskId: string): Promise<CronRun>\r\n isRunning(taskId: string): boolean\r\n}\r\n\r\nexport function createScheduler(deps: SchedulerDeps): Scheduler {\r\n /** 内存重叠锁:同任务上次未结束则本次记 skipped-overlap,不并发执行。 */\r\n const running = new Set<string>()\r\n\r\n async function recordSkipped(task: CronTask): Promise<void> {\r\n const nowIso = new Date(deps.now()).toISOString()\r\n const run: CronRun = {\r\n id: deps.newRunId(), taskId: task.id,\r\n triggeredAt: nowIso, finishedAt: nowIso,\r\n status: 'skipped-overlap',\r\n }\r\n await deps.runs.put(run.id, run)\r\n await trimRuns(deps.runs, task.id, deps.runHistoryLimit)\r\n }\r\n\r\n function launch(task: CronTask): void {\r\n running.add(task.id)\r\n void deps.execute(task)\r\n .catch((error) => deps.warn(`[schedule] 任务 \"${task.id}\" 执行器异常:${error instanceof Error ? error.message : String(error)}`))\r\n .finally(() => {\r\n running.delete(task.id)\r\n // 触发后推进:任务可能已被删除/停用 → 只在仍存在且启用时写回。\r\n const current = deps.tasks.get(task.id)\r\n if (current === undefined || !current.enabled) return\r\n void deps.tasks.put(task.id, advanceAfterTrigger(current, deps.now()))\r\n })\r\n }\r\n\r\n return {\r\n async rearmAll() {\r\n for (const [id, task] of deps.tasks.entries()) {\r\n const rearmed = rearmTask(task, deps.now())\r\n if (rearmed !== task) await deps.tasks.put(id, rearmed)\r\n }\r\n },\r\n async tick() {\r\n for (const [, task] of deps.tasks.entries()) {\r\n if (!task.enabled || task.nextRunAt === null) continue\r\n if (Date.parse(task.nextRunAt) > deps.now()) continue\r\n if (running.has(task.id)) {\r\n // 重叠保护:记 skipped-overlap 并把 nextRunAt 推到未来(避免每个 tick 重复记跳过)。\r\n await recordSkipped(task)\r\n await deps.tasks.put(task.id, advanceAfterTrigger(task, deps.now()))\r\n continue\r\n }\r\n launch(task)\r\n }\r\n },\r\n recompute: (task) => recomputeTask(task, deps.now()),\r\n async triggerManual(taskId) {\r\n const task = deps.tasks.get(taskId)\r\n if (task === undefined) throw new Error(`定时任务 \"${taskId}\" 不存在`)\r\n if (running.has(taskId)) throw new Error(`定时任务 \"${task.name}\" 正在运行中,本次手动触发已跳过`)\r\n running.add(taskId)\r\n try {\r\n return await deps.execute(task) as CronRun\r\n } finally {\r\n running.delete(taskId)\r\n }\r\n },\r\n isRunning: (taskId) => running.has(taskId),\r\n }\r\n}\r\n","/** cron 任务 CRUD 服务:模型工具与 HTTP API 双入口共用(校验、落库、重算、连带清理)。 */\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport type { Scheduler } from './scheduler.ts'\r\nimport { CronTaskSchema, deleteRunsOf, listRuns, type CronRun, type CronSchedule, type CronTarget, type CronTask } from './store.ts'\r\nimport { validateSchedule } from './timing.ts'\r\n\r\n/** 创建输入(全字段必填;更新用 Partial)。 */\r\nexport interface CronTaskInput {\r\n name: string\r\n prompt: string\r\n cwd: string\r\n schedule: CronSchedule\r\n target: CronTarget\r\n catchup: boolean\r\n enabled: boolean\r\n}\r\nexport type CronTaskPatch = Partial<CronTaskInput>\r\n\r\n/** 列表视图:任务 + 最近一次运行摘要。 */\r\nexport type CronTaskView = CronTask & { lastRun?: Pick<CronRun, 'status' | 'triggeredAt'> }\r\n\r\nexport type CronResult<T> = { ok: true; value: T } | { ok: false; error: string }\r\n\r\nexport interface CronServiceDeps {\r\n tasks: KvTable<string, CronTask>\r\n runs: KvTable<string, CronRun>\r\n scheduler: Scheduler\r\n registry: AgentRegistry\r\n validateProject(path: string): boolean\r\n now(): number\r\n newTaskId(): string\r\n}\r\n\r\nexport interface CronService {\r\n list(): CronTaskView[]\r\n get(id: string): CronTask | undefined\r\n create(input: CronTaskInput): Promise<CronResult<CronTask>>\r\n update(id: string, patch: CronTaskPatch): Promise<CronResult<CronTask>>\r\n /** 删除任务并连带清运行历史。 */\r\n remove(id: string): Promise<CronResult<null>>\r\n /** 立即手动触发一次(不受 enabled 影响;不存在/运行中 ok:false)。 */\r\n trigger(id: string): Promise<CronResult<CronRun>>\r\n /** 运行历史(新 → 旧,最多 limit 条)。 */\r\n runsOf(id: string, limit: number): CronRun[]\r\n}\r\n\r\nexport function createCronService(deps: CronServiceDeps): CronService {\r\n /** 创建/更新共用校验:schedule 语法与时值 → cwd → roleId 存在性。 */\r\n const validateIO = (input: Pick<CronTaskInput, 'cwd' | 'schedule' | 'target'>): string | undefined => {\r\n const scheduleError = validateSchedule(input.schedule, deps.now())\r\n if (scheduleError !== undefined) return scheduleError\r\n if (!deps.validateProject(input.cwd)) return `项目路径不可用:${input.cwd}`\r\n if (input.target.kind === 'role' && deps.registry.get(input.target.roleId) === undefined) {\r\n return `角色 \"${input.target.roleId}\" 不存在`\r\n }\r\n return undefined\r\n }\r\n\r\n return {\r\n list() {\r\n return [...deps.tasks.entries()].map(([, task]) => {\r\n const last = listRuns(deps.runs, task.id)[0]\r\n const view: CronTaskView = last === undefined\r\n ? task\r\n : { ...task, lastRun: { status: last.status, triggeredAt: last.triggeredAt } }\r\n return view\r\n })\r\n },\r\n get: (id) => deps.tasks.get(id),\r\n async create(input) {\r\n const invalid = validateIO(input)\r\n if (invalid !== undefined) return { ok: false, error: invalid }\r\n const nowIso = new Date(deps.now()).toISOString()\r\n const parsed = CronTaskSchema.safeParse({\r\n id: deps.newTaskId(), ...input,\r\n nextRunAt: null, createdAt: nowIso, updatedAt: nowIso,\r\n })\r\n if (!parsed.success) return { ok: false, error: parsed.error.issues[0]?.message ?? 'invalid task' }\r\n const task = deps.scheduler.recompute(parsed.data)\r\n await deps.tasks.put(task.id, task)\r\n return { ok: true, value: task }\r\n },\r\n async update(id, patch) {\r\n const existing = deps.tasks.get(id)\r\n if (existing === undefined) return { ok: false, error: `定时任务 \"${id}\" 不存在` }\r\n const merged = {\r\n ...existing,\r\n ...(Object.fromEntries(Object.entries(patch).filter(([, v]) => v !== undefined))),\r\n id: existing.id,\r\n updatedAt: new Date(deps.now()).toISOString(),\r\n }\r\n const invalid = validateIO(merged)\r\n if (invalid !== undefined) return { ok: false, error: invalid }\r\n const parsed = CronTaskSchema.safeParse(merged)\r\n if (!parsed.success) return { ok: false, error: parsed.error.issues[0]?.message ?? 'invalid task' }\r\n const task = deps.scheduler.recompute(parsed.data)\r\n await deps.tasks.put(id, task)\r\n return { ok: true, value: task }\r\n },\r\n async remove(id) {\r\n if (deps.tasks.get(id) === undefined) return { ok: false, error: `定时任务 \"${id}\" 不存在` }\r\n await deps.tasks.delete(id)\r\n await deleteRunsOf(deps.runs, id)\r\n return { ok: true, value: null }\r\n },\r\n async trigger(id) {\r\n try {\r\n return { ok: true, value: await deps.scheduler.triggerManual(id) }\r\n } catch (error) {\r\n return { ok: false, error: error instanceof Error ? error.message : String(error) }\r\n }\r\n },\r\n runsOf: (id, limit) => listRuns(deps.runs, id).slice(0, limit),\r\n }\r\n}\r\n","/** cron_* 模型工具:注册在主 Agent scope(不进 subagent/插件自有会话)+ 宿主 schedule 互斥探测。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { Agent } from '@deepseek-ai/dsh-agent'\r\nimport { defineTool, type ToolDefinition } from '@deepseek-ai/dsh-tools'\r\nimport { scopeOf } from '@deepseek-ai/dsh-scope'\r\nimport type { CronService, CronTaskInput, CronTaskPatch } from './service.ts'\r\nimport type { CronSchedule, CronTarget } from './store.ts'\r\n\r\n/** 互斥探测目标:宿主 @deepseek-ai/dsh-schedule 的会话内提醒工具。 */\r\nconst HOST_SCHEDULE_TOOL = 'schedule_create'\r\n\r\n/** 扁平参数 → CronSchedule(缺 kind 对应字段抛错——模型可读的自描述消息)。 */\r\nfunction scheduleOf(args: Record<string, unknown>): CronSchedule {\r\n const kind = args.scheduleKind\r\n if (kind === 'cron') {\r\n if (typeof args.cronExpr !== 'string' || args.cronExpr.trim() === '') throw new Error('scheduleKind=cron 需要 cronExpr(5 字段 cron 表达式)')\r\n return {\r\n kind: 'cron', expr: args.cronExpr,\r\n ...(typeof args.timeZone === 'string' && args.timeZone !== '' ? { timeZone: args.timeZone } : {}),\r\n }\r\n }\r\n if (kind === 'at') {\r\n if (typeof args.atTime !== 'string' || args.atTime === '') throw new Error('scheduleKind=at 需要 atTime(RFC 3339 时间)')\r\n return { kind: 'at', at: args.atTime }\r\n }\r\n if (kind === 'every') {\r\n if (typeof args.everySeconds !== 'number') throw new Error('scheduleKind=every 需要 everySeconds(≥60 的秒数)')\r\n return { kind: 'every', seconds: args.everySeconds }\r\n }\r\n throw new Error(`未知 scheduleKind:${String(kind)}(可选 cron / at / every)`)\r\n}\r\n\r\nfunction targetOf(args: Record<string, unknown>): CronTarget {\r\n if (args.targetKind === 'role') {\r\n if (typeof args.roleId !== 'string' || args.roleId === '') throw new Error('targetKind=role 需要 roleId')\r\n return { kind: 'role', roleId: args.roleId }\r\n }\r\n return { kind: 'main' }\r\n}\r\n\r\n/** 服务结果展开:ok:false → 抛错(defineTool 约定:抛错即工具错误结果)。 */\r\nfunction unwrap<T>(result: { ok: true; value: T } | { ok: false; error: string }): T {\r\n if (!result.ok) throw new Error(result.error)\r\n return result.value\r\n}\r\n\r\nconst JSON_OUTPUT = {\r\n schema: { type: 'json' },\r\n render: (_args: unknown, value: unknown) => [{ type: 'text' as const, text: JSON.stringify(value, null, 2) }],\r\n} as const\r\n\r\nconst SCHEDULE_PARAMS_REQUIRED = {\r\n scheduleKind: { type: 'string', required: true, description: 'One of: cron / at / every' },\r\n} as const\r\n\r\nconst SCHEDULE_PARAMS_OPTIONAL = {\r\n scheduleKind: { type: 'string', description: 'Replace schedule kind: cron / at / every (provide the matching fields too)' },\r\n} as const\r\n\r\nconst SCHEDULE_FIELD_PARAMS = {\r\n cronExpr: { type: 'string', description: 'Required when scheduleKind=cron: 5-field cron expression \"minute hour day-of-month month day-of-week\" (seconds/years not supported)' },\r\n timeZone: { type: 'string', description: 'Optional IANA time zone for cron (e.g. \"Asia/Shanghai\"); default: server process time zone' },\r\n atTime: { type: 'string', description: 'Required when scheduleKind=at: one-shot RFC 3339 time (e.g. \"2026-09-08T09:00:00+08:00\")' },\r\n everySeconds: { type: 'number', description: 'Required when scheduleKind=every: interval seconds (>= 60), anchored at creation time' },\r\n} as const\r\n\r\nconst TARGET_PARAMS_REQUIRED = {\r\n targetKind: { type: 'string', required: true, description: 'One of: main (main agent, default model) / role (registry role with its persona/model/tool allowlist)' },\r\n} as const\r\n\r\nconst TARGET_PARAMS_OPTIONAL = {\r\n targetKind: { type: 'string', description: 'Replace target: main / role' },\r\n} as const\r\n\r\nconst ROLE_ID_PARAM = { roleId: { type: 'string', description: 'Required when targetKind=role: registry role id' } } as const\r\n\r\nexport function createCronTools(service: CronService): ToolDefinition[] {\r\n return [\r\n defineTool({\r\n name: 'cron_task_create',\r\n description:\r\n 'Create a scheduled task that runs a prompt in a NEW standalone session (main agent or a registry role) '\r\n + 'on a cron/at/every schedule. The task survives restarts; a run missed while stopped is caught up once '\r\n + 'when catchup=true. Use cron_task_list to see existing tasks.',\r\n parameters: {\r\n name: { type: 'string', required: true, description: 'Task name (display)' },\r\n prompt: { type: 'string', required: true, description: 'The prompt sent as the user message when the task fires. Self-contained: the session has no other context.' },\r\n cwd: { type: 'string', required: true, description: 'Working directory of the new session (must be a valid project path)' },\r\n ...SCHEDULE_PARAMS_REQUIRED,\r\n ...SCHEDULE_FIELD_PARAMS,\r\n ...TARGET_PARAMS_REQUIRED,\r\n ...ROLE_ID_PARAM,\r\n catchup: { type: 'boolean', required: true, description: 'true: run once immediately after restart if a run was missed while stopped; false: skip to the next future occurrence' },\r\n enabled: { type: 'boolean', required: true, description: 'false: create paused (nextRunAt stays null until enabled via cron_task_update)' },\r\n },\r\n output: JSON_OUTPUT,\r\n isConcurrencySafe: () => true,\r\n async execute(rawArgs) {\r\n const args = rawArgs as Record<string, unknown>\r\n const input: CronTaskInput = {\r\n name: args.name as string,\r\n prompt: args.prompt as string,\r\n cwd: args.cwd as string,\r\n schedule: scheduleOf(args),\r\n target: targetOf(args),\r\n catchup: args.catchup as boolean,\r\n enabled: args.enabled as boolean,\r\n }\r\n return unwrap(await service.create(input))\r\n },\r\n }),\r\n defineTool({\r\n name: 'cron_task_list',\r\n description: 'List all scheduled tasks with enabled flag, next run time and last run status.',\r\n parameters: {},\r\n output: JSON_OUTPUT,\r\n isConcurrencySafe: () => true,\r\n async execute() {\r\n return service.list()\r\n },\r\n }),\r\n defineTool({\r\n name: 'cron_task_update',\r\n description: 'Update any fields of a scheduled task by id. nextRunAt is recomputed.',\r\n parameters: {\r\n id: { type: 'string', required: true, description: 'Task id' },\r\n name: { type: 'string', description: 'New name' },\r\n prompt: { type: 'string', description: 'New prompt' },\r\n cwd: { type: 'string', description: 'New working directory' },\r\n ...SCHEDULE_PARAMS_OPTIONAL,\r\n ...SCHEDULE_FIELD_PARAMS,\r\n ...TARGET_PARAMS_OPTIONAL,\r\n ...ROLE_ID_PARAM,\r\n catchup: { type: 'boolean', description: 'New catchup flag' },\r\n enabled: { type: 'boolean', description: 'Enable/disable the task' },\r\n },\r\n output: JSON_OUTPUT,\r\n isConcurrencySafe: () => true,\r\n async execute(rawArgs) {\r\n const args = rawArgs as Record<string, unknown>\r\n const patch: CronTaskPatch = {}\r\n if (args.name !== undefined) patch.name = args.name as string\r\n if (args.prompt !== undefined) patch.prompt = args.prompt as string\r\n if (args.cwd !== undefined) patch.cwd = args.cwd as string\r\n if (args.scheduleKind !== undefined) patch.schedule = scheduleOf(args)\r\n if (args.targetKind !== undefined) patch.target = targetOf(args)\r\n if (args.catchup !== undefined) patch.catchup = args.catchup as boolean\r\n if (args.enabled !== undefined) patch.enabled = args.enabled as boolean\r\n return unwrap(await service.update(args.id as string, patch))\r\n },\r\n }),\r\n defineTool({\r\n name: 'cron_task_delete',\r\n description: 'Delete a scheduled task by id, including its run history.',\r\n parameters: { id: { type: 'string', required: true, description: 'Task id' } },\r\n output: JSON_OUTPUT,\r\n isConcurrencySafe: () => true,\r\n async execute(rawArgs) {\r\n return unwrap(await service.remove((rawArgs as Record<string, unknown>).id as string))\r\n },\r\n }),\r\n defineTool({\r\n name: 'cron_task_trigger',\r\n description: 'Trigger a scheduled task once right now (works even when disabled; fails with an error if the task is already running).',\r\n parameters: { id: { type: 'string', required: true, description: 'Task id' } },\r\n output: JSON_OUTPUT,\r\n isConcurrencySafe: () => true,\r\n async execute(rawArgs) {\r\n return unwrap(await service.trigger((rawArgs as Record<string, unknown>).id as string))\r\n },\r\n }),\r\n ]\r\n}\r\n\r\n/**\r\n * 注册 cron_* 工具到主 Agent scope 并探测宿主 schedule 互斥(spec §1/§5)。\r\n * 门控:跳过 subagent(session.header.origin === 'subagent')与插件自有会话(ownedSessions:\r\n * bot/schedule 会话)——dsh-schedule src/index.ts:45-49 同款 agent/created 模式,\r\n * 外加存量 roots 立即注册(HMR 重挂后当前主会话不丢工具)。\r\n * HMR 安全:镜像 dsh-schedule src/index.ts:44-76——attached 身份表防同一 agent 二次挂载,\r\n * toolkit 级 ctx.effect 卸载时 Promise.allSettled 摘下所有 agent 上挂的工具\r\n * (agent.ctx 属宿主、长于 toolkit fiber,仅靠 agent.ctx.effect 会在重挂时残留)。\r\n */\r\nexport function setupCronTools(ctx: Context, tools: ToolDefinition[], ownedSessions: ReadonlySet<string>): void {\r\n const attached = new Map<Agent, () => void>()\r\n let stopping = false\r\n\r\n ctx.effect(() => {\r\n const stopCreated = ctx.on('agent/created', ({ agent }) => {\r\n if (stopping || attached.has(agent)) return\r\n attach(agent)\r\n })\r\n for (const agent of ctx.agents.roots()) attach(agent)\r\n\r\n return async () => {\r\n stopping = true\r\n stopCreated()\r\n const cleanups = [...attached.values()]\r\n attached.clear()\r\n await Promise.allSettled(cleanups.map((cleanup) => Promise.resolve(cleanup())))\r\n }\r\n }, 'dsh-agent-toolkit.cron-tools()')\r\n\r\n function attach(agent: Agent): void {\r\n if (attached.has(agent)) return\r\n if (agent.session.header.origin === 'subagent') return\r\n if (ownedSessions.has(String(agent.session.id))) return\r\n const cleanup = agent.ctx.effect(() => {\r\n const scope = scopeOf(agent.ctx)\r\n const hostPresent = scope !== undefined\r\n ? ctx.tools.get(HOST_SCHEDULE_TOOL, scope) !== undefined\r\n : ctx.tools.get(HOST_SCHEDULE_TOOL) !== undefined\r\n if (hostPresent) {\r\n ctx.logger.warn(\r\n 'dsh-agent-toolkit: 检测到宿主 @deepseek-ai/dsh-schedule 的 schedule_create 与 cron_* 并存——'\r\n + '两套调度工具并存会显著提高模型误选率,且会话内提醒在会话冷时静默失败;'\r\n + '请从组合中移除 @deepseek-ai/dsh-schedule(二选一)',\r\n )\r\n }\r\n const disposers = tools.map((tool) => agent.ctx.tools.register(tool))\r\n return () => {\r\n for (const dispose of disposers) dispose()\r\n if (attached.get(agent) === cleanup) attached.delete(agent)\r\n }\r\n }, 'dsh-agent-toolkit.cron-tools.attach()')\r\n attached.set(agent, cleanup)\r\n }\r\n}\r\n","/** schedule 模块接线:存储域 → executor/scheduler/service → cron_* 工具 + HTTP API + 30s tick。 */\r\nimport { existsSync } from 'node:fs'\r\nimport { randomUUID } from 'node:crypto'\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport { SessionId } from '@deepseek-ai/dsh-session'\r\nimport type {} from '@deepseek-ai/dsh-host-webserver'\r\nimport type {} from '@deepseek-ai/dsh-agent-default-model'\r\nimport type { AgentRegistry } from '../agents/registry.ts'\r\nimport { createAgentsPort } from '../channels/agents-port.ts'\r\nimport type { WorkspacePort } from '../channels/ports.ts'\r\nimport { createScopeJoiner, type ScopeJoiner } from '../channels/scope-joiner.ts'\r\nimport { createToolsScope } from '../channels/tool-scope.ts'\r\nimport { openDomainSafely } from '../shared/storage.ts'\r\nimport { registerOptionalRoutes } from '../shared/webserver.ts'\r\nimport { createCronApiHandler } from './api.ts'\r\nimport { createExecutor } from './executor.ts'\r\nimport { createScheduler, type Scheduler } from './scheduler.ts'\r\nimport { createCronService } from './service.ts'\r\nimport { scheduleDomain, type CronRun, type CronTask } from './store.ts'\r\nimport { createCronTools, setupCronTools } from './tools.ts'\r\n\r\nexport interface ScheduleModuleConfig {\r\n /** 单次运行 followup→whenIdle 超时(分钟),超时 cancel + run 记 error('timeout')。 */\r\n runTimeoutMinutes: number\r\n /** 每任务环形保留的最近运行数。 */\r\n runHistoryLimit: number\r\n}\r\n\r\nexport interface ScheduleDeps {\r\n registry: AgentRegistry\r\n /** 任务会话挂载的 preset id(agentTeamPreset 开启时下达;undefined = 直接 toolsScope)。 */\r\n botPresetId?: string\r\n /** 插件自有会话 id 集(与 bots 共享;cron_* 工具注册门控排除用)。 */\r\n ownedSessions: Set<string>\r\n}\r\n\r\n/** tick 间隔固定 30s(spec §8:不进 Config——YAGNI)。 */\r\nconst TICK_MS = 30_000\r\n\r\nexport function setupSchedule(ctx: Context, config: ScheduleModuleConfig, deps: ScheduleDeps): void {\r\n const warn = (m: string): void => ctx.logger.warn(m)\r\n // 与 setupBots 同款 joiner 栈:preset 优先(委派子会话 composeFrom 认父)+ toolsScope 回退。\r\n const toolsScope = createToolsScope(ctx)\r\n const joiner: ScopeJoiner = deps.botPresetId !== undefined\r\n ? createScopeJoiner(ctx, deps.botPresetId, toolsScope, warn)\r\n : toolsScope\r\n const agentsPort = createAgentsPort(ctx, joiner, deps.ownedSessions)\r\n\r\n // workspaceRegistry 可选服务,惰性解析(attachments 教训:apply 期一次性捕获会吃到未注册的 undefined)。\r\n interface WorkspaceRegistryLike {\r\n create(path: string): Promise<{ attachSession(sessionId: SessionId): Promise<void> }>\r\n list(): { path: string }[]\r\n }\r\n const workspaceRegistryOf = (): WorkspaceRegistryLike | undefined =>\r\n ctx.get('workspaceRegistry', false) as WorkspaceRegistryLike | undefined\r\n const workspacePort: WorkspacePort = {\r\n async attach(cwd, sessionId) {\r\n const registry = workspaceRegistryOf()\r\n if (registry === undefined) throw new Error('workspaceRegistry 服务不可用')\r\n const workspace = await registry.create(cwd)\r\n await workspace.attachSession(SessionId(sessionId))\r\n },\r\n }\r\n\r\n let scheduler: Scheduler | undefined\r\n const started = openDomainSafely(ctx, scheduleDomain, warn).then(async (domain) => {\r\n const tasks = domain.table('tasks') as KvTable<string, CronTask>\r\n const runs = domain.table('runs') as KvTable<string, CronRun>\r\n const executor = createExecutor({\r\n agents: agentsPort,\r\n registry: deps.registry,\r\n defaultModel: () => {\r\n const selection = ctx.agentDefaultModel.currentSelection()\r\n return { provider: selection.provider, model: selection.model }\r\n },\r\n workspace: workspacePort,\r\n runs,\r\n runHistoryLimit: config.runHistoryLimit,\r\n runTimeoutMs: config.runTimeoutMinutes * 60_000,\r\n warn,\r\n now: () => Date.now(),\r\n newSessionId: () => randomUUID(),\r\n newRunId: () => randomUUID(),\r\n delay: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),\r\n })\r\n scheduler = createScheduler({\r\n tasks, runs,\r\n runHistoryLimit: config.runHistoryLimit,\r\n execute: (task) => executor.trigger(task),\r\n now: () => Date.now(),\r\n newRunId: () => randomUUID(),\r\n warn,\r\n })\r\n const service = createCronService({\r\n tasks, runs,\r\n scheduler,\r\n registry: deps.registry,\r\n validateProject: (path) => existsSync(path),\r\n now: () => Date.now(),\r\n newTaskId: () => randomUUID(),\r\n })\r\n setupCronTools(ctx, createCronTools(service), deps.ownedSessions)\r\n // webServer 可选(headless 惰性不抛错);handler 请求时才构造(启动链落定前不捕获 service)。\r\n registerOptionalRoutes(ctx, (webCtx) => {\r\n const dispose = webCtx.webServer.register({\r\n kind: 'prefix',\r\n path: '/dsh-agent-toolkit/api/cron',\r\n handler: async (req, res) => {\r\n try {\r\n await started\r\n await createCronApiHandler({\r\n service,\r\n listProjects: () => workspaceRegistryOf()?.list().map((w) => w.path) ?? [],\r\n runHistoryLimit: config.runHistoryLimit,\r\n })(req, res)\r\n } catch (error) {\r\n res.writeHead(500, { 'content-type': 'application/json' })\r\n .end(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }))\r\n }\r\n },\r\n })\r\n return () => dispose()\r\n })\r\n await scheduler.rearmAll()\r\n })\r\n started.catch((error) => {\r\n warn(`[schedule] 启动失败:${error instanceof Error ? error.message : String(error)}`)\r\n })\r\n\r\n // 周期 tick:启动链落定后扫描到期任务。裸 setInterval 而非 ctx.interval——\r\n // timer mixin 受 cordis inject 门控,而本插件 inject 列表按约束不加新服务;\r\n // ctx.effect 卸载时自动 clearInterval,与 ctx.interval 清理语义等价。\r\n ctx.effect(() => {\r\n const timer = setInterval(() => { void started.then(() => scheduler?.tick()) }, TICK_MS)\r\n return () => clearInterval(timer)\r\n })\r\n\r\n ctx.effect(() => async () => { await toolsScope.dispose() })\r\n}\r\n","/** dsh-agent-toolkit 插件总入口:Agent 注册表 + 分层提示词 + 并行委派 + 飞书 bots + token 用量。 */\r\nimport type { Context } from '@deepseek-ai/cordis'\r\nimport type { KvTable } from '@deepseek-ai/dsh-storage-domain'\r\nimport z from '@deepseek-ai/schemastery'\r\nimport { createRegistry } from './agents/registry.ts'\r\nimport { createToolCatalog } from './agents/tool-catalog.ts'\r\nimport { agentToolkitDomain, type AgentRecord } from './agents/store.ts'\r\nimport { openDomainSafely } from './shared/storage.ts'\r\nimport { DEFAULT_LAYERS, DEFAULT_RULES } from './prompt/defaults.ts'\r\nimport { setupPrompt, validateConfig as validatePromptConfig } from './prompt/index.ts'\r\nimport { openLayerSource, type PromptLayersRow } from './prompt/layer-source.ts'\r\nimport { setupPromptLayersApi } from './prompt/api.ts'\r\nimport type { LayerConfig, Rule } from './prompt/types.ts'\r\nimport { setupDelegate } from './delegate/index.ts'\r\nimport { createActiveRoutes } from './delegate/active.ts'\r\nimport { delegationRoutesDomain, type DelegationRouteRecord } from './delegate/routes.ts'\r\nimport { setupDelegateApi } from './delegate/api.ts'\r\nimport { setupAgentsApi } from './agents/api.ts'\r\nimport { setupCreateAgentCommand } from './agents/create-command.ts'\r\nimport { setupBots, type BotsModuleConfig } from './bots/index.ts'\r\nimport { setupAgentTeamPreset, type AgentTeamPresetConfig } from './agents/team-preset.ts'\r\nimport { setupSchedule, type ScheduleModuleConfig } from './schedule/index.ts'\r\nimport { setupUsage } from '@dsh-agent-toolkit/token-usage'\r\n\r\nexport const name = 'dsh-agent-toolkit'\r\n\r\n// 全部硬依赖服务(merged 模块直接消费;archive token-usage/project-bot 的 inject 并集)。\r\n// storageDomain(registry/bots/usage 经 openDomainSafely 消费)、tokenMeter(usage)、\r\n// credentials(bots)不在 brief 骨架的 7 项里,但均为插件运行必需,补齐。\r\nexport const inject = [\r\n 'storageDomain',\r\n 'tools',\r\n 'subagents',\r\n 'systemPrompt',\r\n 'commands',\r\n 'llm',\r\n 'agentDefaultModel',\r\n 'agents',\r\n 'tokenMeter',\r\n 'credentials',\r\n]\r\n\r\n/** 插件配置输出型。 */\r\nexport interface Config {\r\n modules: { feishu: boolean; usage: boolean }\r\n layers: LayerConfig[]\r\n rules: Rule[]\r\n timezone: string\r\n provider: string\r\n toolName: string\r\n feishu: BotsModuleConfig\r\n agentTeamPreset: AgentTeamPresetConfig\r\n schedule: ScheduleModuleConfig\r\n}\r\n\r\n/** layers/rules 的 schemastery schema 照归档 prompt-stack/src/index.ts:21-41 逐字段平移(含 overrides transform hack)。 */\r\nexport const Config: z<unknown, Config> = z.object({\r\n modules: z.object({\r\n feishu: z.boolean().default(true),\r\n usage: z.boolean().default(true),\r\n }).default({ feishu: true, usage: true }),\r\n layers: z.array(z.object({\r\n name: z.string().required(),\r\n order: z.number().required(),\r\n text: z.string().required(),\r\n })).default(DEFAULT_LAYERS),\r\n // 元素 cast 为 z<Rule>:Rule.overrides/append 可选,而 z.object 输出键全必填,\r\n // 直接 .default(DEFAULT_RULES) 会类型不匹配。transform 丢弃空 overrides:\r\n // z.dict 隐式默认 {},会给 append-only 默认规则注入 overrides: {}(破坏\r\n // Config({}) 与 DEFAULT_RULES 的精确相等)。\r\n rules: z.array((z.object({\r\n match: z.object({\r\n provider: z.string(),\r\n model: z.string(),\r\n modelPattern: z.string(),\r\n }).required(),\r\n overrides: z.transform(z.dict(z.string()), value => Object.keys(value).length === 0 ? undefined : value),\r\n append: z.string(),\r\n }) as z<Rule>)).default(DEFAULT_RULES),\r\n timezone: z.string().default('Asia/Shanghai'),\r\n provider: z.string().default('spawn'),\r\n toolName: z.string().default('team_delegate'),\r\n // feishu 9 个全局可调参数照归档 project-bot/src/index.ts:38-45,字段名/默认值原样平移。\r\n feishu: z.object({\r\n cardUpdateThrottleMs: z.number().default(500),\r\n cardMaxBytes: z.number().default(26_000),\r\n cardPrintStep: z.number().default(5),\r\n processMaxBytes: z.number().default(8_000),\r\n registerAppTimeoutMs: z.number().default(600_000),\r\n processingReactionEmoji: z.string().default('OneSecond'),\r\n errorDetailMaxChars: z.number().default(500),\r\n injectSender: z.boolean().default(true),\r\n approval: z.boolean().default(true),\r\n }).default({\r\n cardUpdateThrottleMs: 500,\r\n cardMaxBytes: 26_000,\r\n cardPrintStep: 5,\r\n processMaxBytes: 8_000,\r\n registerAppTimeoutMs: 600_000,\r\n processingReactionEmoji: 'OneSecond',\r\n errorDetailMaxChars: 500,\r\n injectSender: true,\r\n approval: true,\r\n }),\r\n // agent-team preset 自动生成:派生 shipped standard、禁用 subagent 工具族 4 行,\r\n // 写入首个 trust=user root;另生成 bot 会话最小 preset(botsId,委派子会话 composeFrom 认父的前提)\r\n // (spec: docs/superpowers/specs/archive/2026-09-02-agent-team-preset-design.md)。\r\n agentTeamPreset: z.object({\r\n enabled: z.boolean().default(true),\r\n id: z.string().default('agent-team'),\r\n source: z.string().default('standard'),\r\n name: z.string().default('Agent 团队'),\r\n description: z.string().default('Agent 团队模式:禁用原生 subagent 工具族,委派统一走 team_delegate 团队角色'),\r\n botsId: z.string().default('agent-bot'),\r\n }).default({\r\n enabled: true,\r\n id: 'agent-team',\r\n source: 'standard',\r\n name: 'Agent 团队',\r\n description: 'Agent 团队模式:禁用原生 subagent 工具族,委派统一走 team_delegate 团队角色',\r\n botsId: 'agent-bot',\r\n }),\r\n // 定时任务(cron):单次运行超时(分钟)与每任务运行历史环形上限(spec: docs/superpowers/specs/archive/2026-09-07-cron-schedule-design.md §8)。\r\n // natural() = 非负整数(schemastery 无 .int(),语义等价且校验更强)。\r\n schedule: z.object({\r\n runTimeoutMinutes: z.number().min(1).default(60),\r\n runHistoryLimit: z.natural().min(1).default(20),\r\n }).default({ runTimeoutMinutes: 60, runHistoryLimit: 20 }),\r\n}) as z<unknown, Config>\r\n\r\nexport async function apply(ctx: Context, config: Config): Promise<void> {\r\n validatePromptConfig({ layers: config.layers, rules: config.rules })\r\n const warn = (msg: string): void => ctx.logger.warn(msg)\r\n const domain = await openDomainSafely(ctx, agentToolkitDomain, warn)\r\n const tables = {\r\n agents: domain.table('agents') as KvTable<string, AgentRecord>,\r\n meta: domain.table('meta') as KvTable<string, { value: string }>,\r\n promptLayers: domain.table('prompt_layers') as KvTable<string, PromptLayersRow>,\r\n }\r\n // agent-team / agent-bot preset 生成必须先于 createRegistry:preset 并入迁移要枚举\r\n // agent-team 面(standingKeyFor 按 composition 文件挂载,首启时尚未生成会枚举失败跳过)。\r\n // agentPresets 为可选服务(rc2 旧宿主缺席时内部静默跳过),不进 inject。\r\n await setupAgentTeamPreset(ctx, config.agentTeamPreset)\r\n const toolCatalog = createToolCatalog(ctx, config.agentTeamPreset.id)\r\n const registry = await createRegistry(warn, { agents: tables.agents, meta: tables.meta }, toolCatalog.listPresetTools)\r\n const layerSource = await openLayerSource({ promptLayers: tables.promptLayers, meta: tables.meta }, config.layers)\r\n setupPrompt(ctx, { source: layerSource, rules: config.rules })\r\n const routesDomain = await openDomainSafely(ctx, delegationRoutesDomain, warn)\r\n const routesTable = routesDomain.table('routes') as KvTable<string, DelegationRouteRecord>\r\n const activeRoutes = createActiveRoutes()\r\n setupDelegate(ctx, {\r\n provider: config.provider,\r\n toolName: config.toolName,\r\n rules: config.rules,\r\n }, registry, {\r\n active: activeRoutes,\r\n recordRoute: async (childSessionId, route) => {\r\n await routesTable.put(childSessionId, { provider: route.provider, model: route.model, at: Date.now() })\r\n },\r\n })\r\n setupDelegateApi(ctx, { active: activeRoutes, routes: routesTable })\r\n // agents/providers/tools RPC 为核心恒启用(Agents 面板总是挂载,端点缺失即「加载失败」),\r\n // 不随 modules.feishu 门控;仅 bots 分支受 feishu 开关控制。\r\n setupAgentsApi(ctx, {\r\n registry,\r\n listTools: toolCatalog.listGlobalTools,\r\n listPresetTools: toolCatalog.listPresetTools,\r\n listProviders: () => ctx.llm.listProviders().map(({ id, name }) => ({ id, name })),\r\n listModels: (provider) => ctx.llm.listModels(provider).then((models) => models.map(({ id, name }) => ({ id, name }))),\r\n })\r\n // /create-agent 命令恒启用(引导主 Agent 访谈并复用面板 API 落库,不新增工具/API)。\r\n setupCreateAgentCommand(ctx, { registry, listTools: toolCatalog.listGlobalTools, listPresetTools: toolCatalog.listPresetTools })\r\n setupPromptLayersApi(ctx, {\r\n source: layerSource,\r\n rules: config.rules,\r\n seedLayers: config.layers,\r\n // 裸组装探测:面板只读区展示原生 sections 与动态层 contexts 的当前快照。\r\n probe: async () => {\r\n const assembly = await ctx.systemPrompt.assemble({})\r\n return {\r\n sections: assembly.sections.map(({ name: n, text }) => ({ name: n, text })),\r\n contexts: assembly.contexts.map(({ name: n, text }) => ({ name: n, text })),\r\n }\r\n },\r\n })\r\n const ownedSessions = new Set<string>()\r\n if (config.modules.feishu) setupBots(ctx, config.feishu, { registry, botPresetId: config.agentTeamPreset.enabled ? config.agentTeamPreset.botsId : undefined, ownedSessions })\r\n if (config.modules.usage) setupUsage(ctx, { timezone: config.timezone }, name)\r\n // schedule 恒启用,不随 modules 门控(任务可独立于飞书/用量使用)。\r\n setupSchedule(ctx, config.schedule, {\r\n registry,\r\n botPresetId: config.agentTeamPreset.enabled ? config.agentTeamPreset.botsId : undefined,\r\n ownedSessions,\r\n })\r\n}\r\n"],"mappings":"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"}
|