@waterwx/dsh-novel-forge 1.3.0 → 1.3.2

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/assets.ts","../src/comic-presets.ts","../src/engine.ts","../src/bookshelf.ts","../src/run.ts","../src/protocol.ts","../src/docx.ts","../src/assistant.ts","../src/routes.ts","../src/index.ts"],"sourcesContent":["/**\n * Writing assets — 题材基底库 / 推进模式库 / 反 AI 规则 / 写法引擎.\n *\n * Ported from AI-Novel-Writing-Assistant (Apache-2.0) built-in seed data:\n * - 8 preset style templates (DEFAULT_STYLE_TEMPLATES)\n * - 12 anti-AI rules with concrete detect patterns (DEFAULT_ANTI_AI_RULES)\n * - genre tree + progression mode seeds\n * Assets persist with the project (novel-project.json) and are injected into\n * generation / planning / review prompts, and available to the AI assistant.\n */\n\nimport type { AntiAiRule, GenreNode, ProgressionMode, ProjectAssets, StyleAsset, StyleTemplate } from './protocol.ts'\n\n// ------------------------------------------------------ built-in style templates\n\n/** 预置写法模板(来自 AI-Novel-Writing-Assistant 内置 DEFAULT_STYLE_TEMPLATES)。 */\nexport const BUILTIN_STYLE_TEMPLATES: StyleTemplate[] = [\n {\n key: 'power-up-escalation',\n name: '爽文递进推进流',\n description: '持续升级冲突和收益点,强化目标推进与爽点兑现。',\n category: '爽文流',\n applicableGenres: ['都市', '玄幻', '热血'],\n proseRules: [\n '围绕目标推进,尽快兑现局部收益;每段都要有目标推进或爽点兑现。',\n '保持明确因果和节奏抬升,场景单元按「目标→阻碍→压制→反转收益」推进。',\n '优先冲突和结果,少停留;段尾用钩子收束。',\n ],\n dialogueRules: [\n '角色表达直接,情绪跟随胜负切换。',\n '对话承担推进与信息功能,但保留角色自己的语气差异。',\n ],\n languageRules: [\n '句式清晰,减少无效分散信息。',\n '直接、明确,不做无谓铺垫。',\n ],\n rhythmRules: [\n '快节奏,段落密度中等,动作先于解释。',\n '尽快兑现局部收益,避免拖沓。',\n ],\n defaultAntiAiRuleKeys: ['禁止总结主题', '对话纯功能推进', '连续三段解释性叙事'],\n },\n {\n key: 'bottom-loop-reality',\n name: '底层循环现实流',\n description: '通过碎片化生活与反复落空表现人物困境。',\n category: '现实流',\n applicableGenres: ['都市', '现实', '成长'],\n proseRules: [\n '以时间推进和现实落差构成叙事张力,结尾不解决核心困境。',\n '场景单元按「行为→落差→自我合理化」推进。',\n '以碎片化生活推进,不做总括式回顾。',\n ],\n dialogueRules: [\n '人物情绪通过动作和嘴硬表达,允许短促口语化台词。',\n '对话保留生活杂音与无效信息。',\n ],\n languageRules: [\n '语言粗粝、口语化,允许生活杂音与不完整句。',\n '句子变化度高,允许无意义细节。',\n ],\n rhythmRules: [\n '段落密实,动作先于解释。',\n '中快节奏,允许碎片化流动。',\n ],\n defaultAntiAiRuleKeys: ['禁止解释型心理描写', '禁止段尾升华', '鼓励无意义小动作', '鼓励现实落差', '鼓励嘴硬补偿'],\n },\n {\n key: 'suspense-pressure',\n name: '悬疑压迫递增流',\n description: '通过信息遮蔽、细节异常和压力叠加制造不安感。',\n category: '悬疑流',\n applicableGenres: ['悬疑', '惊悚', '现实'],\n proseRules: [\n '以异常细节、信息差和节奏收束推动悬念层层加压。',\n '场景单元按「现场细节→异常→误判→新风险」推进。',\n '优先制造信息缺口和压迫氛围。',\n ],\n dialogueRules: [\n '角色反应克制,恐惧通过反应显现。',\n '对话保留克制感,不解释恐惧来源。',\n ],\n languageRules: [\n '细节精确,保留少量噪音增强现场感。',\n '克制、中等偏高句变化。',\n ],\n rhythmRules: [\n '通过节奏收束和信息延迟制造压力。',\n '中速,段落密度中等偏高。',\n ],\n defaultAntiAiRuleKeys: ['禁止解释型心理描写', '禁止总结主题', '段落长度过于整齐', '鼓励现实落差'],\n },\n {\n key: 'emotional-tension',\n name: '情绪拉扯流',\n description: '通过错位表达、停顿和误读制造关系张力。',\n category: '情感流',\n applicableGenres: ['言情', '都市', '群像'],\n proseRules: [\n '人物不直说核心情绪,靠误读、停顿和反应推动关系变化。',\n '场景单元按「动作→言外之意→误读→回避」推进。',\n '以关系错位推进,而非直接说明。',\n ],\n dialogueRules: [\n '情绪通过停顿、动作和言外之意体现。',\n '对话充满潜台词与试探。',\n ],\n languageRules: [\n '语言自然,允许留白与停顿。',\n '句子变化度高,允许无意义细节。',\n ],\n rhythmRules: [\n '给关系反应留空间,但避免空洞抒情。',\n '中慢节奏,段落密度中等。',\n ],\n defaultAntiAiRuleKeys: ['禁止直接说教', '禁止段尾升华', '对话纯功能推进', '鼓励无意义小动作'],\n },\n {\n key: 'ensemble-weave',\n name: '群像交织流',\n description: '以多人行动线和视角差异交织推进事件。',\n category: '群像流',\n applicableGenres: ['群像', '都市', '悬疑'],\n proseRules: [\n '多角色并行推进,但每个角色的表达和认知范围必须区分清楚。',\n '多线并进,但视角切换要受控。',\n ],\n dialogueRules: [\n '不同角色口吻必须拉开差异,避免所有人说话一样。',\n ],\n languageRules: [\n '保持角色差异,句式变化度高。',\n '减少无效分散信息。',\n ],\n rhythmRules: [\n '多线交织但节奏不乱,平衡推进。',\n '动作先于解释。',\n ],\n defaultAntiAiRuleKeys: ['对话纯功能推进', '句式重复率过高', '禁止总结主题'],\n },\n {\n key: 'immersive-daily',\n name: '日常浸没流',\n description: '通过生活细节和细微情绪变化建立持续沉浸感。',\n category: '日常流',\n applicableGenres: ['日常', '治愈', '都市'],\n proseRules: [\n '重场景体验和关系温度,核心情绪通过场景自然流出。',\n '允许保留生活性动作和无效信息。',\n ],\n dialogueRules: [\n '人物表达自然,不用高强度戏剧句。',\n '对话保留生活气息。',\n ],\n languageRules: [\n '保留生活细节和杂音,不追求工整。',\n '口语化,句子变化中等偏高。',\n ],\n rhythmRules: [\n '慢节奏沉浸,但避免空转。',\n '允许碎片化流动。',\n ],\n defaultAntiAiRuleKeys: ['禁止段尾升华', '段落长度过于整齐', '鼓励无意义小动作'],\n },\n {\n key: 'cold-professional',\n name: '冷峻专业流',\n description: '以专业事实和行业细节压住情绪,形成克制压力感。',\n category: '专业流',\n applicableGenres: ['职场', '现实', '悬疑'],\n proseRules: [\n '行业事实和程序细节优先,情绪不直说,信息密度高于抒情密度。',\n '场景单元按「事实→动作→专业判断→后果」推进。',\n '让专业事实承担叙事重量。',\n ],\n dialogueRules: [\n '情绪藏在专业动作和事实选择里。',\n '对话以信息性表达为主,克制。',\n ],\n languageRules: [\n '术语和事实优先,避免廉价金句。',\n '正式、克制的语言。',\n ],\n rhythmRules: [\n '信息密度高,但不铺张解释。',\n '平衡节奏,段落密度中等偏高。',\n ],\n defaultAntiAiRuleKeys: ['禁止直接说教', '禁止总结主题', '句式重复率过高'],\n },\n {\n key: 'absurd-dark-humor',\n name: '荒诞黑色幽默流',\n description: '通过反差、冷感观察和荒诞细节制造黑色幽默。',\n category: '黑色幽默',\n applicableGenres: ['都市', '黑色幽默', '现实'],\n proseRules: [\n '用反差和荒诞细节放大现实困境,笑点和压迫感同时存在。',\n '场景单元按「现实细节→荒诞偏差→冷反应」推进。',\n '依赖反差和冷感观察,而非热闹吐槽。',\n ],\n dialogueRules: [\n '情绪藏在冷反应和嘴硬里。',\n '台词冷面、口语化,允许自嘲与转移。',\n ],\n languageRules: [\n '允许夹带荒诞杂质和冷幽默节奏。',\n '口语化,句子变化度高。',\n ],\n rhythmRules: [\n '反差点要快落地,不要解释笑点。',\n '平衡节奏,段落密度中等偏高。',\n ],\n defaultAntiAiRuleKeys: ['禁止解释型心理描写', '禁止段尾升华', '鼓励现实落差', '鼓励嘴硬补偿'],\n },\n]\n\n// ---------------------------------------------------------- built-in rules\n\n/** 内置全局反 AI 规则(来自 AI-Novel-Writing-Assistant 内置 DEFAULT_ANTI_AI_RULES)。 */\nexport const BUILTIN_ANTI_AI_RULES: AntiAiRule[] = [\n {\n name: '禁止解释型心理描写',\n avoid: '直接使用\"他感到\"\"他意识到\"\"他明白了\"等句式解释人物心理。',\n fix: '把心理解释改成动作、语气、停顿、环境反应或结果。',\n detectPatterns: ['他感到', '她感到', '他意识到', '她意识到', '他明白了', '她明白了'],\n builtin: true,\n },\n {\n name: '禁止段尾升华',\n avoid: '在段尾或收尾处用总结句升华主题(如\"生活就是\"\"命运总会\"\"说到底\")。',\n fix: '删除升华句,回到具体动作、现场或悬而未决的处境。',\n detectPatterns: ['生活就是', '命运总会', '归根结底', '说到底', '这就是'],\n builtin: true,\n },\n {\n name: '禁止总结主题',\n avoid: '把段落写成总结中心思想或提炼人生道理(如\"这说明\"\"这意味着\")。',\n fix: '删掉主题总结,让信息通过事件和结果自然显现。',\n detectPatterns: ['这说明', '这意味着', '归根结底', '其实就是'],\n builtin: true,\n },\n {\n name: '禁止直接说教',\n avoid: '作者替角色或读者做直接价值判断和说教(如\"我们都应该\"\"人总要学会\")。',\n fix: '改成角色具体处境或对话,不做抽象说教。',\n detectPatterns: ['我们都应该', '人总要学会', '真正重要的是'],\n builtin: true,\n },\n {\n name: '段落长度过于整齐',\n avoid: '段落长度和节奏过于平均,产生 AI 作文感。',\n fix: '打破段落长度均衡,让句子和段落有自然起伏。',\n detectPatterns: [],\n builtin: true,\n },\n {\n name: '连续三段解释性叙事',\n avoid: '连续几段只有解释没有动作,削弱现场感。',\n fix: '插入动作、对话、环境反馈,减少连段说明。',\n detectPatterns: [],\n builtin: true,\n },\n {\n name: '对话纯功能推进',\n avoid: '对话只有信息推进,没有人物语气和生活噪音(如\"告诉你\"\"我们现在要\")。',\n fix: '补入停顿、绕弯、语气差异和无效信息。',\n detectPatterns: ['告诉你', '我们现在要', '接下来就'],\n builtin: true,\n },\n {\n name: '句式重复率过高',\n avoid: '连续句式过于整齐(如\"首先\"\"然后\"\"接着\"\"最后\"),显得机械。',\n fix: '拉开句式长度和起句方式,打散结构。',\n detectPatterns: ['首先', '然后', '接着', '最后'],\n builtin: true,\n },\n {\n name: 'AI 高频套话',\n avoid: '滥用\"不禁\"\"仿佛\"\"一时间\"\"不由得\"\"顿时\"\"然而\"\"缓缓\"\"轻轻\"\"微微\"\"似乎\"\"终于\"等模式词及套路比喻。',\n fix: '用具体、有画面感的表达替换套话;每个比喻都应当是新造的。',\n detectPatterns: ['不禁', '仿佛', '一时间', '不由得', '顿时', '缓缓', '轻轻', '微微'],\n builtin: true,\n },\n {\n name: '鼓励无意义小动作',\n avoid: '(鼓励类)全篇缺少真实但不推动主线的小动作,人物显得空洞。',\n fix: '补入挠头、点烟、抠包装、挪椅子等小动作,增加人味与生活感。',\n detectPatterns: [],\n builtin: true,\n },\n {\n name: '鼓励现实落差',\n avoid: '(鼓励类)人物预期和现实结果完全一致,缺少落差。',\n fix: '补出人物预期与实际结果之间的差距,制造张力。',\n detectPatterns: [],\n builtin: true,\n },\n {\n name: '鼓励嘴硬补偿',\n avoid: '(鼓励类)人物吃瘪后没有维持体面的反应。',\n fix: '给角色补一句嘴硬找补或自我合理化,保持人设温度。',\n detectPatterns: [],\n builtin: true,\n },\n]\n\n/** 内置题材基底库(常用网文题材树,跨书复用)。 */\nexport const BUILTIN_GENRE_LIBRARY: GenreNode[] = [\n {\n name: '仙侠修真',\n description: '以修仙境界、宗门斗争、法宝丹药为核心,读者期待从凡人到强者的成长与长生问道。',\n children: [\n { name: '凡人流', description: '资质平凡、步步为营,靠资源积累与心机博弈逆袭,强调真实感与代入感。', children: [] },\n { name: '苟道流', description: '主角苟且发育、藏锋敛芒,坐收渔利,强调生存智慧与反差爽点。', children: [] },\n { name: '争霸流', description: '宗门、王朝或大陆争锋,主角由弱到强整合势力,强调格局与权谋。', children: [] },\n ],\n },\n {\n name: '都市异能',\n description: '现代都市背景叠加超能力,读者期待隐藏身份、扮猪吃虎与日常反差。',\n children: [\n { name: '异能升级', description: '觉醒超能力后不断变强,隐藏于都市,遇敌碾压。', children: [] },\n { name: '重生复仇', description: '重生回到过去,利用先知先觉改变命运、清算仇敌。', children: [] },\n { name: '商业经营', description: '以超能力或见识经商扩张,建立商业帝国,强调经营爽感。', children: [] },\n ],\n },\n {\n name: '悬疑推理',\n description: '以谜题、案件与真相揭露为核心,读者期待线索层层展开与反转。',\n children: [\n { name: '本格推理', description: '公平线索、逻辑推演,读者可与主角一同解谜。', children: [] },\n { name: '刑侦探案', description: '警察或侦探视角连续破案,案件串联主线,强调现实与人性。', children: [] },\n { name: '无限流', description: '主角穿梭于不同副本世界解谜求生,副本之间累积成长。', children: [] },\n ],\n },\n {\n name: '玄幻奇幻',\n description: '异世界或架空大陆的冒险成长,读者期待宏大世界观、奇遇与战力突破。',\n children: [\n { name: '学院流', description: '入学修炼、同窗竞争、大赛扬名,强调青春感与阶梯式打脸。', children: [] },\n { name: '废柴逆袭', description: '开局废柴受辱,觉醒金手指后一路逆袭打脸,强调反差与爽点。', children: [] },\n { name: '诸天万界', description: '穿越诸天世界收集资源与能力,强调世界多样性与成长曲线。', children: [] },\n ],\n },\n {\n name: '历史军事',\n description: '以历史时代为背景的争霸、谋略或军旅故事,读者期待权谋博弈与时代质感。',\n children: [\n { name: '王朝争霸', description: '乱世崛起、招贤纳士、逐鹿天下,强调战略与人心。', children: [] },\n { name: '穿越种田', description: '穿越古代发展生产、经营家族,强调建设感与生活细节。', children: [] },\n ],\n },\n {\n name: '末世科幻',\n description: '末世危机或科幻设定下的生存与重建,读者期待资源管理、危机升级与人性考验。',\n children: [\n { name: '基地经营', description: '建立基地、收集资源、抵御危机,强调建设与扩张。', children: [] },\n { name: '进化觉醒', description: '末世异变中觉醒能力不断进化,强调战力成长与危机求生。', children: [] },\n ],\n },\n]\n\n/** 内置常用推进模式。 */\nexport const BUILTIN_PROGRESSION_MODES: ProgressionMode[] = [\n {\n name: '升级变强',\n driver: '主角的实力、境界或能力持续增长,读者期待每次突破带来的碾压与认可。',\n readerExpectation: '每隔几章有一次明确的实力提升或打脸兑现;大境界突破要有仪式感。',\n payoffs: ['突破境界', '学会新技能', '越级战胜强敌', '当众打脸质疑者'],\n risks: ['升级重复套路', '战力膨胀失控', '无铺垫强行突破'],\n primary: false,\n },\n {\n name: '经营扩张',\n driver: '主角的产业、势力或领地不断扩张,资源复利滚雪球。',\n readerExpectation: '经营投入有可感知的回报,扩张遇到新挑战并解决。',\n payoffs: ['新产业上线', '规模翻倍', '吞并对手', '资源闭环成型'],\n risks: ['过程枯燥', '扩张无阻力', '数值失衡'],\n primary: false,\n },\n {\n name: '解谜揭露',\n driver: '主线谜团(身世、阴谋、世界观真相)持续牵引读者,每揭开一层又引出更深一层。',\n readerExpectation: '定期有真相碎片放出,回收旧伏笔、埋设新伏笔。',\n payoffs: ['伏笔回收', '身份揭露', '阴谋浮出水面', '反转打脸'],\n risks: ['谜题拖太久', '伏笔忘记回收', '反转生硬'],\n primary: false,\n },\n {\n name: '渔翁得利',\n driver: '强敌相互厮杀,主角躲在暗处观察、收割,风险由他人承担、果实由主角获取。',\n readerExpectation: '冲突升级时主角以最小代价获取最大收益,且不暴露自身。',\n payoffs: ['坐收渔利', '捡漏宝物', '敌人两败俱伤', '信息差获利'],\n risks: ['重复套路', '收割太轻易', '主角全程无风险'],\n primary: false,\n },\n {\n name: '关系拉扯',\n driver: '人物关系(知己、对手、师徒、情感线)的张力与变化持续推动剧情。',\n readerExpectation: '关系有进有退、有误会与和解,情绪起伏带动阅读欲。',\n payoffs: ['关系升温', '信任建立', '背叛与挽回', '并肩作战'],\n risks: ['情感线停滞', '工业糖精', '为虐而虐'],\n primary: false,\n },\n]\n\n// ------------------------------------------------------------- persistence\n\n/** 默认(空)项目写作资产。 */\nexport function emptyProjectAssets(): ProjectAssets {\n return {\n auxiliaryProgressions: [],\n antiAiRules: [],\n styleAssets: [],\n }\n}\n\n/** 合并项目资产与内置库:返回「生效的反 AI 规则」(内置全局 + 项目自定义)。 */\nexport function effectiveAntiAiRules(assets: ProjectAssets | undefined): AntiAiRule[] {\n const custom = assets?.antiAiRules ?? []\n const customNames = new Set(custom.map(r => r.name))\n return [...BUILTIN_ANTI_AI_RULES.filter(r => !customNames.has(r.name)), ...custom]\n}\n\n/** 把生效规则渲染成提示词块(压缩:avoid/fix 截断,省 token)。 */\nexport function renderAntiAiRules(assets: ProjectAssets | undefined): string {\n const rules = effectiveAntiAiRules(assets)\n if (rules.length === 0) return ''\n const clip = (value: string, max: number): string => value.length > max ? value.slice(0, max) + '…' : value\n return [\n '==================== 反 AI 规则(写作时必须遵守的表达边界) ====================',\n ...rules.map(r => `- ${r.name}:避免——${clip(r.avoid, 90)}${r.fix !== '' ? `;修正——${clip(r.fix, 50)}` : ''}`),\n ].join('\\n')\n}\n\n/** 渲染题材与推进模式提示词块。 */\nexport function renderGenreAndProgression(assets: ProjectAssets | undefined): string {\n const sections: string[] = []\n if (assets?.genre !== undefined) {\n sections.push('==================== 题材基底(本书的题材定位与读者期待) ====================')\n sections.push(`题材:${assets.genre.name}`)\n if (assets.genre.description !== '') sections.push(`读者期待:${assets.genre.description}`)\n const walk = (node: GenreNode, depth: number): void => {\n for (const child of node.children) {\n sections.push(`${' '.repeat(depth)}- ${child.name}:${child.description}`)\n walk(child, depth + 1)\n }\n }\n walk(assets.genre, 1)\n }\n const modes = [\n ...(assets?.primaryProgression !== undefined ? [assets.primaryProgression] : []),\n ...(assets?.auxiliaryProgressions ?? []),\n ]\n if (modes.length > 0) {\n sections.push('==================== 推进模式(读者为什么继续看) ====================')\n for (const mode of modes) {\n const tag = mode.primary ? '(主推进)' : '(辅助)'\n sections.push(`- 模式「${mode.name}」${tag}:驱动力——${mode.driver}`)\n sections.push(` 读者期待:${mode.readerExpectation}`)\n if (mode.payoffs.length > 0) sections.push(` 常见兑现:${mode.payoffs.join('、')}`)\n if (mode.risks.length > 0) sections.push(` 节奏风险(避免):${mode.risks.join('、')}`)\n }\n }\n return sections.join('\\n')\n}\n\n/** 渲染写法资产提示词块(规则去重,省 token)。 */\nexport function renderStyleAssets(assets: ProjectAssets | undefined): string {\n const styles = assets?.styleAssets ?? []\n if (styles.length === 0) return ''\n const sections: string[] = ['==================== 写法资产(本书的叙事风格约束) ====================']\n for (const style of styles) {\n sections.push(`【${style.name}】`)\n const unique = (rules: string[]): string[] => [...new Set(rules)]\n if (style.proseRules.length > 0) sections.push('叙述与节奏:\\n' + unique(style.proseRules).map(r => `- ${r}`).join('\\n'))\n if (style.dialogueRules.length > 0) sections.push('台词风格:\\n' + unique(style.dialogueRules).map(r => `- ${r}`).join('\\n'))\n if (style.descriptionRules.length > 0) sections.push('描写与情绪:\\n' + unique(style.descriptionRules).map(r => `- ${r}`).join('\\n'))\n if (style.boundaries.length > 0) sections.push('表达边界:\\n' + unique(style.boundaries).map(r => `- ${r}`).join('\\n'))\n }\n return sections.join('\\n')\n}\n\n/** 渲染全部写作资产提示词(供生成/规划/审稿注入)。 */\nexport function renderAllAssets(assets: ProjectAssets | undefined): string {\n const parts = [\n renderGenreAndProgression(assets),\n renderStyleAssets(assets),\n renderAntiAiRules(assets),\n ].filter(part => part !== '')\n return parts.join('\\n\\n')\n}\n\n/** 预置写法模板 → 可直接绑定的 StyleAsset。 */\nexport function styleTemplateToAsset(template: StyleTemplate): StyleAsset {\n return {\n name: template.name,\n proseRules: [...template.proseRules, ...template.rhythmRules.map(r => `节奏:${r}`)],\n dialogueRules: template.dialogueRules,\n descriptionRules: template.languageRules,\n boundaries: [`模板「${template.name}」适用题材:${template.applicableGenres.join('、')}`, '不要违背模板的叙事单元结构与节奏约束'],\n createdAt: new Date().toISOString(),\n }\n}\n\n// ------------------------------------------------------- style extraction\n\n/** 写法引擎:从样本文本提取风格资产的系统提示词。 */\nexport function styleEngineSystemPrompt(): string {\n return [\n '你是一位资深网文文风分析师。你会收到一段样本文本,请提炼出可复用的叙事风格规则,供后续章节保持同一种味道。',\n '要求:',\n '1. 从样本中归纳,不要泛泛而谈;每条规则都要能落到具体写法(句式、用词、视角、节奏、对话方式、描写密度)。',\n '2. 台词风格要说明角色说话的语气特征与常用表达方式。',\n '3. 表达边界要写明这段风格「不会怎么做」(如:不用华丽辞藻、不写长段心理独白、不用成语堆砌)。',\n '4. 输出必须是合法 JSON 对象,不要输出任何其他文字。',\n 'JSON 结构:',\n '{\"proseRules\": [\"叙述视角与句式节奏规则\"], \"dialogueRules\": [\"台词风格规则\"], \"descriptionRules\": [\"描写密度与情绪表达规则\"], \"boundaries\": [\"表达边界\"]}',\n ].join('\\n')\n}\n","/** 漫画风格预设:每个预设对应一组出图提示词与排版偏好。 */\n\nexport interface ComicStylePreset {\n id: string\n label: string\n /** 注入 imagePrompt 的风格描述词。 */\n prompt: string\n /** 可选:排版偏好说明。 */\n layoutHint?: string\n}\n\nexport const COMIC_STYLE_PRESETS: ComicStylePreset[] = [\n {\n id: 'japan',\n label: '日漫 / 黑白',\n prompt: 'manga style, screentone, bold ink lines, high contrast, black and white, cel shading',\n layoutHint: '页漫优先',\n },\n {\n id: 'korea',\n label: '韩漫 / 条漫',\n prompt: 'manhwa style, soft cel shading, vibrant colors, clean lineart, webtoon vertical composition, glossy highlights',\n layoutHint: '条漫优先',\n },\n {\n id: 'china',\n label: '国漫 / 古风',\n prompt: 'chinese ink painting style, flowing brush strokes, traditional palette, ethereal atmosphere, xianxia aesthetic',\n layoutHint: '页漫/条漫均可',\n },\n {\n id: 'america',\n label: '美漫 / 超级英雄',\n prompt: 'american comic style, bold outlines, dramatic lighting, dynamic poses, vibrant colors, halftone shading',\n layoutHint: '页漫优先',\n },\n {\n id: 'chibi',\n label: 'Q版 / 搞笑',\n prompt: 'chibi style, cute proportions, big head, exaggerated expressions, simple background, bright colors',\n layoutHint: '条漫/四格优先',\n },\n {\n id: 'realistic',\n label: '写实 / 电影感',\n prompt: 'realistic cinematic style, detailed textures, natural lighting, film grain, high detail',\n layoutHint: '页漫/全彩',\n },\n {\n id: 'cyber',\n label: '赛博 / 暗黑',\n prompt: 'cyberpunk style, neon lights, dark atmosphere, high contrast, futuristic city, cool tones',\n layoutHint: '页漫/全彩',\n },\n]\n\nexport function getComicStylePrompt(styleId?: string): string {\n if (!styleId) return ''\n const preset = COMIC_STYLE_PRESETS.find(s => s.id === styleId)\n return preset?.prompt ?? ''\n}\n\nexport function getComicStyleLabel(styleId?: string): string {\n if (!styleId) return ''\n const preset = COMIC_STYLE_PRESETS.find(s => s.id === styleId)\n return preset?.label ?? styleId\n}\n","/**\n * Novel engine — the host half's core: LLM-driven story-bible extraction,\n * volume planning, chapter planning, chapter-by-chapter writing with\n * auto-review + rewrite, polish (de-AI-ify), narrative summaries, foreshadow\n * tracking, project persistence, and whole-book export. Pure Node (no\n * web-server dependencies), so routes stay thin and logic is testable.\n */\n\n/**\n * 内容合规红线(平台硬性要求):所有书籍、所有章节无条件生效,\n * 优先级高于单书大纲/圣经中的任何设定与作者自定义红线。\n * 注入点:章节生成系统提示 + 审稿系统提示(命中即 high)。\n */\nexport const COMPLIANCE_REDLINES: ReadonlyArray<string> = [\n '1. 不得出现反对宪法所确定的基本原则的内容。',\n '2. 不得出现危害国家安全、泄露国家秘密、颠覆国家政权、破坏国家统一的内容。',\n '3. 不得出现危害国家荣誉和利益的内容。',\n '4. 不得出现煽动民族仇恨、民族歧视、破坏民族团结的内容。',\n '5. 不得出现破坏国家宗教政策、宣扬邪教和愚昧迷信的内容(不得以真实宗教、邪教或迷信活动为背景进行宣扬)。',\n '6. 不得出现散布谣言、扰乱社会秩序、破坏社会稳定的内容。',\n '7. 不得出现淫秽色情、赌博、暴力、凶杀、恐怖或教唆犯罪的内容(网文语境:禁止露骨性描写、血腥暴力渲染、赌博教唆、犯罪手法详细教学)。',\n '8. 不得出现侮辱或者诽谤他人、侵害他人合法权益的内容(不得以真实人物、组织为原型进行侮辱或影射攻击)。',\n '9. 不得出现法律法规禁止的其他内容。',\n]\n\nimport { mkdirSync, readFileSync, writeFileSync, readdirSync, existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { createUserMessage, BlockAssembler, ReasoningEffortId, type GenerateOptions, type Message, type StreamChunk } from '@deepseek-ai/dsh-llm'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { emptyProjectAssets, renderAllAssets, styleEngineSystemPrompt } from './assets.ts'\nimport { getComicStylePrompt } from './comic-presets.ts'\nimport type {\n AuditIssue,\n AuthorReview,\n BreakdownResponse,\n ChapterPlan,\n Foreshadow,\n NovelConfig,\n OutlineCandidate,\n Plotline,\n PlotlineHealthReport,\n PlotlinePlan,\n ProjectState,\n ReviewReport,\n RoleRecord,\n RoleStatusCard,\n SceneCard,\n StoryBible,\n Volume,\n WorldState,\n} from './protocol.ts'\n\n/** Project state file name inside the output dir. */\nexport const PROJECT_FILE = 'novel-project.json'\n\n// ------------------------------------------------------------------ helpers\n\n/** Sanitize a file name: keep CJK/alphanumerics/space/dash/underscore. */\nfunction safeFileName(name: string): string {\n return name\n .replace(/[\\\\/:*?\"<>|]/g, '')\n .replace(/\\s+/g, ' ')\n .trim()\n .slice(0, 60)\n}\n\n/** Chapter output file name, e.g. 第001章_开篇.md */\nexport function chapterFileName(chapter: ChapterPlan): string {\n const title = safeFileName(chapter.title) || `第${chapter.no}章`\n return `第${String(chapter.no).padStart(3, '0')}章_${title}.md`\n}\n\n/** Infer a book name from the outline's first non-empty line. */\nexport function inferBookName(outline: string): string {\n const line = outline.split('\\n').map(l => l.trim()).find(l => l.length > 0)\n return (line ?? '未命名小说').replace(/^《/, '').replace(/》.*$/, '').slice(0, 40)\n}\n\n// ------------------------------------------------------------------ project\n\n/** Read the persisted project from the output dir (undefined when absent). */\nexport function loadProject(outputDir: string): ProjectState | undefined {\n const file = join(outputDir, PROJECT_FILE)\n if (!existsSync(file)) return undefined\n try {\n let rawText = readFileSync(file, 'utf8')\n // Tolerate a UTF-8 BOM (some editors / PowerShell writes add one).\n if (rawText.charCodeAt(0) === 0xFEFF) rawText = rawText.slice(1)\n const raw = JSON.parse(rawText) as ProjectState\n if (typeof raw.outline !== 'string' || !Array.isArray(raw.chapters)) return undefined\n // Normalize legacy projects (foreshadows / assets may be missing).\n if (!Array.isArray(raw.foreshadows)) raw.foreshadows = []\n if (raw.assets === undefined || typeof raw.assets !== 'object') raw.assets = emptyProjectAssets()\n if (!Array.isArray(raw.assets.antiAiRules)) raw.assets.antiAiRules = []\n if (!Array.isArray(raw.assets.auxiliaryProgressions)) raw.assets.auxiliaryProgressions = []\n if (!Array.isArray(raw.assets.styleAssets)) raw.assets.styleAssets = []\n if (!Array.isArray(raw.facts)) raw.facts = []\n if (!Array.isArray(raw.plotlines)) raw.plotlines = []\n return raw\n } catch {\n return undefined\n }\n}\n\n/** Persist the project state next to the chapters. */\nexport function saveProject(outputDir: string, project: ProjectState): void {\n mkdirSync(outputDir, { recursive: true })\n writeFileSync(join(outputDir, PROJECT_FILE), JSON.stringify(project, null, 2), 'utf8')\n}\n\n/**\n * 并发保护:长任务(章节计划生成/正文生成)在内存中持有旧快照,\n * 期间其他请求可能修改了「易变字段」(道藏/角色库/剧情线/人物志存档/简介/封面)。\n * 保存前用磁盘最新版本合并这些字段,避免旧快照覆盖新修改(曾导致角色卡丢失)。\n * 注意:调用方若自己修改了这些字段,不要使用本函数。\n */\nexport function mergeVolatileFromDisk(outputDir: string, project: ProjectState): void {\n try {\n const disk = loadProject(outputDir)\n if (disk === undefined) return\n project.bible = disk.bible\n project.roles = disk.roles\n project.plotlines = disk.plotlines\n project.roleStatus = disk.roleStatus\n project.blurb = disk.blurb\n project.coverPath = disk.coverPath\n project.facts = disk.facts\n project.assets = disk.assets\n project.world = disk.world\n project.volumes = disk.volumes\n } catch { /* 磁盘读取失败时保持原状 */ }\n}\n\n// ------------------------------------------------------------ sensitive words\n\n/**\n * 内置违禁词库(网文平台常见审查类别)。只做硬匹配提示,不代替人工判断。\n * 词语刻意保持常见写法;作者可自行判断是否修改。\n */\nconst SENSITIVE_WORDS: ReadonlyArray<{ word: string; category: string }> = [\n // 政治敏感\n { word: '共匪', category: '政治' }, { word: '独裁', category: '政治' },\n { word: '法轮', category: '政治' }, { word: '六四', category: '政治' },\n { word: '天安门事件', category: '政治' }, { word: '翻墙', category: '政治' },\n { word: '政治敏感', category: '政治' },\n // 色情擦边\n { word: '乳沟', category: '擦边' }, { word: '酥胸', category: '擦边' },\n { word: '淫荡', category: '擦边' }, { word: '做爱', category: '擦边' },\n { word: '上床', category: '擦边' }, { word: '裸体', category: '擦边' },\n { word: '一丝不挂', category: '擦边' }, { word: '胴体', category: '擦边' },\n { word: '春药', category: '擦边' }, { word: '催情', category: '擦边' },\n { word: '迷奸', category: '擦边' }, { word: '强暴', category: '擦边' },\n { word: '轮奸', category: '擦边' }, { word: '援交', category: '擦边' },\n { word: '嫖娼', category: '擦边' }, { word: '卖淫', category: '擦边' },\n { word: '色情', category: '擦边' }, { word: '情色', category: '擦边' },\n { word: '撸管', category: '擦边' }, { word: '自慰', category: '擦边' },\n { word: '口交', category: '擦边' }, { word: '打炮', category: '擦边' },\n { word: '约炮', category: '擦边' }, { word: '一夜情', category: '擦边' },\n // 暴力血腥\n { word: '碎尸', category: '暴力' }, { word: '分尸', category: '暴力' },\n { word: '凌迟', category: '暴力' }, { word: '剥皮', category: '暴力' },\n { word: '开膛', category: '暴力' }, { word: '剖腹', category: '暴力' },\n { word: '挖心', category: '暴力' }, { word: '虐杀', category: '暴力' },\n { word: '凌辱', category: '暴力' }, { word: '血腥', category: '暴力' },\n { word: '大屠杀', category: '暴力' }, { word: '灭门', category: '暴力' },\n { word: '满门抄斩', category: '暴力' }, { word: '腰斩', category: '暴力' },\n { word: '活埋', category: '暴力' }, { word: '点天灯', category: '暴力' },\n // 辱骂攻击\n { word: '傻逼', category: '辱骂' }, { word: '傻B', category: '辱骂' },\n { word: '草泥马', category: '辱骂' }, { word: '妈的', category: '辱骂' },\n { word: '尼玛', category: '辱骂' }, { word: '去死', category: '辱骂' },\n { word: '废物', category: '辱骂' }, { word: '垃圾', category: '辱骂' },\n { word: '人渣', category: '辱骂' }, { word: '贱人', category: '辱骂' },\n { word: '婊子', category: '辱骂' }, { word: '狗日的', category: '辱骂' },\n // 广告引流\n { word: '加微信', category: '广告' }, { word: '加QQ', category: '广告' },\n { word: '微信公众号', category: '广告' }, { word: '淘宝', category: '广告' },\n { word: '拼多多', category: '广告' }, { word: '刷单', category: '广告' },\n { word: '充值返利', category: '广告' }, { word: '扫码领', category: '广告' },\n { word: '加群领', category: '广告' }, { word: 'vx', category: '广告' },\n { word: '扣扣', category: '广告' },\n // 其他违禁\n { word: '赌博', category: '其他' }, { word: '赌场', category: '其他' },\n { word: '毒品', category: '其他' }, { word: '冰毒', category: '其他' },\n { word: '摇头丸', category: '其他' }, { word: '自杀方法', category: '其他' },\n { word: '邪教', category: '其他' }, { word: '传销', category: '其他' },\n { word: '军火', category: '其他' }, { word: '枪支', category: '其他' },\n { word: '管制刀具', category: '其他' },\n]\n\n/** 对一段文本做违禁词硬匹配,返回命中(词/类别/次数)。 */\nexport function checkSensitiveText(text: string): Array<{ word: string; category: string; count: number }> {\n const hits: Array<{ word: string; category: string; count: number }> = []\n for (const entry of SENSITIVE_WORDS) {\n let count = 0\n let idx = text.indexOf(entry.word)\n while (idx !== -1) {\n count++\n idx = text.indexOf(entry.word, idx + entry.word.length)\n }\n if (count > 0) hits.push({ word: entry.word, category: entry.category, count })\n }\n return hits\n}\n\n/** List generated chapter files in the output dir (sorted). */\nexport function listChapterFiles(outputDir: string): string[] {\n if (!existsSync(outputDir)) return []\n try {\n return readdirSync(outputDir)\n .filter(name => /^第\\d+章_.*\\.md$/.test(name) && !name.endsWith('.bak.md'))\n .sort((a, b) => {\n const na = Number(/^第(\\d+)章/.exec(a)?.[1] ?? 0)\n const nb = Number(/^第(\\d+)章/.exec(b)?.[1] ?? 0)\n return na - nb\n })\n } catch {\n return []\n }\n}\n\n/** Re-sync chapter status against files on disk (a file may exist without state). */\nexport function syncProjectWithDisk(project: ProjectState, outputDir: string): void {\n const files = new Map<string, string>()\n for (const file of listChapterFiles(outputDir)) {\n const no = Number(/^第(\\d+)章/.exec(file)?.[1] ?? 0)\n if (no > 0) files.set(String(no), file)\n }\n for (const chapter of project.chapters) {\n const file = files.get(String(chapter.no))\n if (file !== undefined && (chapter.status === 'pending' || chapter.status === 'generating')) {\n chapter.status = 'written'\n chapter.file = file\n }\n }\n project.updatedAt = new Date().toISOString()\n}\n\n/** Read a chapter's markdown body from disk (undefined when missing). */\nexport function readChapterFile(outputDir: string, chapter: ChapterPlan): string | undefined {\n if (chapter.file === undefined) return undefined\n const path = join(outputDir, chapter.file)\n if (!existsSync(path)) return undefined\n return readFileSync(path, 'utf8')\n}\n\n/** Create a fresh project from an outline. */\nexport function createProject(outline: string, outlinePath?: string): ProjectState {\n const now = new Date().toISOString()\n return {\n bookName: inferBookName(outline),\n outline,\n outlinePath,\n chapters: [],\n foreshadows: [],\n assets: emptyProjectAssets(),\n facts: [],\n createdAt: now,\n updatedAt: now,\n }\n}\n\n// ------------------------------------------------------------------- llm\n\n/** One complete non-streaming LLM call. */\nasync function complete(\n ctx: Context,\n config: NovelConfig,\n options: { system: string; user: string; temperature?: number; maxTokens?: number },\n): Promise<string> {\n const messages: Message[] = [createUserMessage({\n content: [{ type: 'text', text: options.user }],\n source: { kind: 'plugin', plugin: 'dsh-novel-forge' },\n })]\n const request: GenerateOptions = {\n provider: config.provider,\n model: config.model,\n messages,\n system: options.system,\n maxTokens: options.maxTokens ?? config.maxTokens,\n temperature: options.temperature ?? 0.7,\n reasoningEffort: ReasoningEffortId(config.reasoningEffort ?? 'off'),\n }\n const assembler = new BlockAssembler()\n for await (const chunk of ctx.llm.stream(request)) {\n assembler.push(chunk)\n }\n const finish = assembler.finish\n if (finish.kind === 'error' || finish.kind === 'aborted') {\n throw new Error(`LLM 调用失败(${finish.kind}): ${finish.failure.message}`)\n }\n if (finish.kind === 'max-tokens') {\n throw new Error('LLM 输出达到 maxTokens 上限,请增大配置后重试')\n }\n const blocks = assembler.blocks()\n // Diagnostics: log the assembled block shape (reasoning-only turns yield no\n // text blocks — the v4-flash model can answer entirely in the reasoning\n // channel, which the adapter surfaces as a reasoning block).\n if (process.env.DSH_NOVEL_DEBUG === '1') {\n console.error('[dsh-novel-forge] complete: finish=%j blocks=%j', JSON.stringify(finish), blocks.map(b => `${b.type}:${'text' in b ? b.text.length : '?'}`))\n }\n const textBlocks = blocks\n .filter((block): block is Extract<StreamChunk, { type: 'block-end' }>['block'] & { type: 'text' } => block.type === 'text')\n .map(block => block.text)\n let text = textBlocks.join('\\n').trim()\n // v4-flash can answer entirely in the reasoning channel (the adapter\n // surfaces that as a 'reasoning' block). Fall back to it when no text came\n // back — the reasoning content is the model's actual answer here.\n if (text === '') {\n const reasoning = blocks\n .filter((block): block is { type: 'reasoning'; text: string } => block.type === 'reasoning')\n .map(block => block.text)\n .join('\\n')\n .trim()\n if (reasoning !== '') text = reasoning\n }\n return text\n}\n\n/**\n * Parse a JSON value out of a model response. Multi-level tolerance because\n * models are sloppy: prose around the JSON, ```json fences, a truncated tail,\n * or raw newlines inside string values all defeat a single JSON.parse. We\n * walk candidates from strictest to loosest.\n */\nfunction parseJson<T>(text: string, wantArray: boolean): T {\n const candidates: string[] = []\n const push = (value: string | undefined): void => {\n if (value !== undefined && value.trim() !== '') candidates.push(value.trim())\n }\n\n // 1. Whole response, and any ```json fence body.\n push(text)\n const fenced = /```(?:json)?\\s*([\\s\\S]*?)```/.exec(text)\n push(fenced?.[1])\n // 2. From the first opener to the last closer.\n const opener = wantArray ? '[' : '{'\n const closer = wantArray ? ']' : '}'\n const start = text.indexOf(opener)\n const end = text.lastIndexOf(closer)\n if (start !== -1 && end > start) push(text.slice(start, end + 1))\n // 3. Trim trailing prose (a \"}...\" tail after the last closer).\n const trimmed = text.replace(new RegExp(`${closer}[\\\\s\\\\S]*$`), closer)\n push(trimmed)\n const start2 = trimmed.indexOf(opener)\n if (start2 !== -1) push(trimmed.slice(start2))\n\n // Repair: models love raw newlines inside string values, which JSON forbids.\n const repair = (value: string): string => {\n let out = ''\n let inString = false\n for (let i = 0; i < value.length; i++) {\n const ch = value[i]!\n if (inString) {\n if (ch === '\\\\') {\n out += ch + (value[i + 1] ?? '')\n i++\n continue\n }\n if (ch === '\"') {\n inString = false\n out += ch\n continue\n }\n if (ch === '\\n' || ch === '\\r') {\n out += '\\\\n'\n continue\n }\n out += ch\n } else {\n if (ch === '\"') inString = true\n out += ch\n }\n }\n return out\n }\n\n for (const candidate of candidates) {\n for (const attempt of [candidate, repair(candidate)]) {\n try {\n const value = JSON.parse(attempt) as unknown\n if (!wantArray || Array.isArray(value)) return value as T\n // wantArray but the model wrapped the list in an object, e.g.\n // {\"chapters\": [...]} — extract the first array-valued key.\n if (typeof value === 'object' && value !== null) {\n for (const key of Object.keys(value as Record<string, unknown>)) {\n const inner = (value as Record<string, unknown>)[key]\n if (Array.isArray(inner)) return inner as T\n }\n }\n // Not an array — keep trying the remaining candidates.\n } catch {\n // try the next candidate\n }\n }\n }\n const preview = text.length > 300 ? text.slice(0, 300) + '…' : text\n throw new Error(`模型输出中未找到 JSON 数据。模型原始输出:${preview}`)\n}\n\n/** Parse a JSON array (chapters, volumes, issues...). */\nfunction parseJsonArray<T>(text: string): T[] {\n const value = parseJson<T[]>(text, true)\n return Array.isArray(value) ? value : []\n}\n\n/** Parse a JSON object. */\nfunction parseJsonObject<T>(text: string): T {\n const value = parseJson<T>(text, false)\n if (typeof value !== 'object' || value === null) throw new Error('模型输出不是 JSON 对象')\n return value\n}\n\n// ------------------------------------------------------------------ bible\n\n/** System prompt for story-bible extraction. */\nfunction bibleSystemPrompt(): string {\n return [\n '你是一位资深网文编辑兼设定架构师。你会收到一份小说大纲,请把它提炼成结构化的「设定圣经」(Story Bible),供后续写作时严格引用。',\n '要求:',\n '1. 忠于大纲,不自行发明大纲之外的设定。',\n '2. 角色卡覆盖大纲明确出现的角色(主角必含),每个角色给出性格标签、目标、关键关系。',\n '3. 世界规则覆盖力量体系、金手指机制、势力、地理等所有硬性规则,逐条列出。',\n '4. 红线列出大纲中明确禁止的内容(如无后宫、不圣母、无无脑碾压等)。',\n '5. 风格列出叙事基调、节奏、POV 等写作风格要点。',\n '6. 角色名必须用正文/编年录中的真实姓名;若大纲只写「主角」未点名,而已写章节或编年录中有名字,则用该真实姓名;禁止输出「主角(描述)」这类把身份塞进名字的占位名。',\n '输出必须是合法 JSON 对象,不要输出任何其他文字或 Markdown 代码块标记。',\n '重要:所有字符串值内部不得包含换行符(不要用多行字符串),JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程或推理内容写在输出里。',\n 'JSON 结构:',\n '{\"genre\": \"题材与基调一句话\", \"worldRules\": [\"规则1\", \"规则2\", ...], \"characters\": [{\"name\": \"角色名\", \"role\": \"protagonist|supporting|antagonist|other\", \"traits\": [\"标签1\", ...], \"goals\": \"目标与动机\", \"relations\": \"关键关系\"}], \"redLines\": [\"红线1\", ...], \"style\": [\"风格1\", ...]}',\n ].join('\\n')\n}\n\n/** Extract the story bible from an outline. */\nexport async function extractBible(ctx: Context, config: NovelConfig, outline: string, project?: ProjectState): Promise<StoryBible> {\n // 已写章节/编年录只在「确认真实姓名与已确立设定」时参考,仍忠于大纲、不新增大纲外设定。\n const written = (project?.chapters ?? []).filter(c => c.status !== 'pending' && c.status !== 'generating' && c.file !== undefined)\n const excerpts: string[] = []\n for (const chapter of written.slice(0, 3)) {\n const body = readChapterFile(config.outputDir, chapter)\n if (body === undefined) continue\n const text = body.replace(/^#.*$/gm, '').trim()\n if (text.length > 0) excerpts.push(`第${chapter.no}章《${chapter.title}》\\n${text.slice(0, 2200)}`)\n }\n const facts = (project?.facts ?? []).slice(-40)\n const user = [\n `请为下面这部小说提炼设定圣经:\\n\\n${outline}`,\n facts.length > 0\n ? `\\n\\n【已写章节事实(编年录)】用于确认真实角色姓名与已确立设定;忠于大纲,不要新增大纲外设定:\\n${facts.map(f => `[第${f.chapterNo}章] ${f.text.slice(0, 100)}`).join('\\n')}`\n : '',\n excerpts.length > 0\n ? `\\n\\n【已写章节正文摘录】角色姓名、身份以正文为准(大纲未点名时用正文里的真实姓名,禁止用「主角(描述)」占位名):\\n${excerpts.join('\\n\\n')}`\n : '',\n ].filter(s => s !== '').join('\\n')\n const text = await complete(ctx, config, {\n system: bibleSystemPrompt(),\n user,\n temperature: 0.4,\n maxTokens: Math.max(config.maxTokens, 16000),\n })\n const raw = parseJsonObject<{\n genre?: unknown\n worldRules?: unknown\n characters?: unknown\n redLines?: unknown\n style?: unknown\n }>(text)\n const strArray = (value: unknown): string[] =>\n Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string' && v.trim() !== '') : []\n const characters: StoryBible['characters'] = Array.isArray(raw.characters)\n ? raw.characters\n .filter((v): v is Record<string, unknown> => typeof v === 'object' && v !== null)\n .map(entry => ({\n name: typeof entry.name === 'string' ? entry.name.trim() : '未命名',\n role: (['protagonist', 'supporting', 'antagonist', 'other'] as const).includes(entry.role as never)\n ? entry.role as StoryBible['characters'][number]['role']\n : 'other',\n traits: strArray(entry.traits),\n goals: typeof entry.goals === 'string' ? entry.goals : '',\n relations: typeof entry.relations === 'string' ? entry.relations : '',\n knowledge: strArray(entry.knowledge),\n }))\n .filter(card => card.name !== '')\n : []\n // 占位名修复:大纲未点名主角时模型可能输出「主角(…)」,用角色库真实主角名替换。\n const realProtagonist = (project?.roles ?? []).find(r => r.roleLabel === 'protagonist')?.name?.trim()\n if (realProtagonist !== undefined && realProtagonist !== '') {\n for (const card of characters) {\n if (card.role === 'protagonist' && /^(主角|未命名)/.test(card.name)) card.name = realProtagonist\n }\n }\n const bible: StoryBible = {\n genre: typeof raw.genre === 'string' ? raw.genre : '',\n worldRules: strArray(raw.worldRules),\n characters,\n redLines: strArray(raw.redLines),\n style: strArray(raw.style),\n generatedAt: new Date().toISOString(),\n }\n if (bible.worldRules.length === 0 && bible.characters.length === 0 && bible.redLines.length === 0) {\n throw new Error('道藏生成失败:模型没有返回有效内容')\n }\n return bible\n}\n\n// ------------------------------------------------------------------ volumes\n\n/** System prompt for volume planning. */\nfunction volumeSystemPrompt(): string {\n return [\n '你是一位资深网文总编。你会收到一份小说大纲,请把全书划分为若干「卷」(分卷),每卷有明确的剧情定位与起止章节。',\n '要求:',\n '1. 大纲已有分卷时,严格遵循大纲的分卷结构;没有时按剧情弧线合理划分(3-8 卷)。',\n '2. 卷定位一句话说明该卷的剧情重心。',\n '3. chapterStart/chapterEnd 给出该卷覆盖的章节区间(从 1 开始连续编号)。',\n '输出必须是合法 JSON 数组,不要输出任何其他文字:',\n '[{\"no\": 1, \"title\": \"卷名\", \"summary\": \"卷定位与剧情重心\", \"chapterStart\": 1, \"chapterEnd\": 80}]',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程或推理内容写在输出里。',\n ].join('\\n')\n}\n\n/** Plan volumes from an outline. */\nexport async function planVolumes(ctx: Context, config: NovelConfig, outline: string): Promise<Volume[]> {\n const user = `请为下面这部小说划分卷:\\n\\n${outline}`\n const text = await complete(ctx, config, { system: volumeSystemPrompt(), user, temperature: 0.4, maxTokens: Math.max(config.maxTokens, 12000) })\n const parsed = parseJsonArray<Record<string, unknown>>(text)\n const volumes: Volume[] = []\n for (let i = 0; i < parsed.length; i++) {\n const entry = parsed[i]\n if (typeof entry !== 'object' || entry === null) continue\n const no = typeof entry.no === 'number' ? entry.no : i + 1\n const title = typeof entry.title === 'string' ? entry.title.trim() : `第${no}卷`\n const summary = typeof entry.summary === 'string' ? entry.summary.trim() : ''\n const start = typeof entry.chapterStart === 'number' ? entry.chapterStart : undefined\n const end = typeof entry.chapterEnd === 'number' ? entry.chapterEnd : undefined\n volumes.push({\n no,\n title: title.slice(0, 40),\n summary: summary.slice(0, 300),\n chapterStart: start ?? 1,\n chapterEnd: end ?? 1,\n })\n }\n if (volumes.length === 0) throw new Error('卷计划生成失败:模型没有返回有效卷')\n return volumes\n}\n\n/** Assign a chapter to its volume by number. */\nfunction volumeOf(chapterNo: number, volumes: Volume[] | undefined): number {\n if (volumes === undefined || volumes.length === 0) return 0\n for (const volume of volumes) {\n if (chapterNo >= volume.chapterStart && chapterNo <= volume.chapterEnd) return volume.no\n }\n return volumes[volumes.length - 1]?.no ?? 0\n}\n\n// ------------------------------------------------------------------- plan\n\n/** The chapter-planning prompt template. */\nfunction planSystemPrompt(volumes: Volume[] | undefined): string {\n const volumeBlock = volumes !== undefined && volumes.length > 0\n ? ['\\n全书分卷结构(规划章节时需落在对应卷内):']\n .concat(volumes.map(v => `第${v.no}卷《${v.title}》:${v.summary}(章节 ${v.chapterStart}-${v.chapterEnd})`))\n .join('\\n')\n : ''\n return [\n '你是一位资深中文网文策划编辑,擅长把小说大纲拆解为可执行的章节计划。',\n '你会收到一份小说大纲。请根据大纲的设定、主线与节奏,规划出一份章节计划。',\n '要求:',\n '1. 每章必须有明确的核心剧情推进(不能只是过渡或凑字数)。',\n '2. 章节之间要衔接自然,前章结尾为后章埋下钩子。',\n '3. 严格遵循大纲的人设、金手指规则、战力体系与世界观设定,不得自行发明冲突设定。',\n '4. 输出必须是合法的 JSON 数组,不要输出任何其他文字或 Markdown 代码块标记。',\n '5. 数组每个元素格式:{\"title\": \"章节标题(10字以内,有网文感)\", \"beats\": \"结构化剧情要点(150-250字,必须包含四段,段间用换行分隔):\\\\n本章目标:本章要完成的核心推进;\\\\n剧情要点:主要情节的起承转合(2-4 句);\\\\n爽点/钩子:本章的爽点兑现或情绪钩子;\\\\n结尾钩子:本章结尾为下一章埋下的悬念\"}',\n '重要:beats 字段内部必须使用 \\\\n 转义表示换行(JSON 字符串内不得有真实换行符),其余字符串值也不得包含真实换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程或推理内容写在输出里。',\n volumeBlock,\n ].join('\\n')\n}\n\n/** Build the writing system prompt (bible + outline + active foreshadows). */\nfunction writeSystemPrompt(project: ProjectState): string {\n const bible = project.bible\n const sections: string[] = []\n if (bible !== undefined) {\n sections.push('==================== 设定圣经(写作时严格遵守) ====================')\n if (bible.genre !== '') sections.push(`题材基调:${bible.genre}`)\n if (bible.worldRules.length > 0) sections.push('世界规则:\\n' + bible.worldRules.map(r => `- ${r}`).join('\\n'))\n if (bible.characters.length > 0) {\n sections.push('角色卡:')\n for (const card of bible.characters) {\n const roleName = { protagonist: '主角', supporting: '配角', antagonist: '反派', other: '其他' }[card.role]\n sections.push(`- ${card.name}(${roleName}):${card.traits.join('、')}${card.goals !== '' ? `;目标:${card.goals}` : ''}${card.relations !== '' ? `;关系:${card.relations}` : ''}`)\n if (Array.isArray(card.knowledge) && card.knowledge.length > 0) {\n sections.push(` 已知信息(该角色知道的:${card.knowledge.join(';')};未列出的信息该角色一律不知道,不得写其知晓或提及)`)\n }\n }\n }\n // 角色库注入:定位 + 身份 + 关系(角色互动按定位规格写)。\n const roleLib = project.roles ?? []\n if (roleLib.length > 0) {\n const labelName = { protagonist: '主角', female_lead: '女主', female_support: '女配', support: '配角', antagonist: '反派', extra: '路人' }\n sections.push('角色库(出场角色按定位规格刻画互动):')\n for (const r of roleLib) {\n sections.push(`- ${r.name}(${labelName[r.roleLabel]}):${r.identity}${r.relations.length > 0 ? `;关系:${r.relations.join('、')}` : ''}`)\n }\n }\n if (bible.redLines.length > 0) sections.push('写作红线(违反即失败):\\n' + bible.redLines.map(r => `- ${r}`).join('\\n'))\n if (bible.style.length > 0) sections.push('风格要求:\\n' + bible.style.map(r => `- ${r}`).join('\\n'))\n }\n const worldBlock = renderWorld(project.world)\n if (worldBlock !== '') sections.push(worldBlock)\n sections.push('==================== 全书大纲 ====================')\n // 超长大纲截断保护(防止上下文超限);完整大纲在总纲页查看。\n const outlineBlock = project.outline.length > 6000\n ? project.outline.slice(0, 6000) + '\\n…(大纲过长已节选,完整内容见总纲页)'\n : project.outline\n sections.push(outlineBlock)\n sections.push('==================== 大纲结束 ====================')\n const assetsBlock = renderAllAssets(project.assets)\n if (assetsBlock !== '') sections.push(assetsBlock)\n const active = project.foreshadows.filter(f => f.status === 'planted' || f.status === 'progressing')\n if (active.length > 0) {\n sections.push('==================== 活跃伏笔(近期需推进或回收的线索) ====================')\n for (const f of active) {\n sections.push(`- [${f.status === 'planted' ? '已埋设' : '推进中'}] ${f.description}${f.targetChapter !== undefined ? `(预计 ${f.targetChapter} 章回收)` : ''}`)\n }\n }\n const lines = (project.plotlines ?? []).filter(l => l.status === 'active' || l.status === 'paused')\n if (lines.length > 0) {\n const kindName = { main: '主线', branch: '支线', character: '人物线', mystery: '悬念线' }\n sections.push('==================== 剧情线(本章应推进至少一条活跃线) ====================')\n for (const l of lines) {\n sections.push(`- [${kindName[l.kind]}${l.status === 'paused' ? '·暂停中' : ''}] ${l.name}:${l.goal}${l.progress !== '' ? `(当前进度:${l.progress})` : ''}`)\n }\n }\n sections.push('')\n sections.push('写作硬性要求:')\n sections.push('1. 每章 3000-4000 字(按中文字符计),只输出章节正文,不要输出标题、章回名、作者的话或任何 Markdown 标记。')\n sections.push('2. 以主角视角展开,动作、对话、心理描写交替推进,禁止大段设定说明。')\n sections.push('3. 尊重大纲与设定圣经:人设不崩、金手指规则不自相矛盾、战力不随意膨胀。')\n sections.push('4. 章末留一个钩子(悬念、反转或新线索),吸引读者读下一章。')\n sections.push('5. 语言流畅自然,符合中文网文语感,避免翻译腔与病句。')\n sections.push('6. 对话与冲突密度:每章至少 1 处实质对话或正面对抗/交锋场面;推理与心理活动必须用动作、环境细节、微表情、对话呈现,禁止整章纯内心独白铺陈(禁止\"解说式\"交代线索)。')\n sections.push('7. 反派与对手的行动力:本章出现的反派/对手必须有其行动、反制或压迫感(布局、试探、追索、交锋至少占其一),不得作为纯背景板存在。')\n sections.push('8. 配角辨识度:重要新登场配角应给姓名或可辨识的独有特征;禁止通篇用\"瘦高个/灰衣人/戴面具者\"等身形标签代称同一角色。')\n sections.push('9. 信息呈现方式:关键线索、设定、局势通过对话、动作、发现物呈现,禁止主角内心\"讲解\"给读者听。')\n sections.push('')\n sections.push('==================== 内容合规红线(平台硬性要求,最高优先级,违反即失败) ====================')\n sections.push(COMPLIANCE_REDLINES.join('\\n'))\n sections.push('以上九条为硬性底线,任何情况下不得以任何形式出现或影射;若剧情确需涉及(如批判、反讽),只能以明确否定、揭露、批判的立场呈现,且不得展开细节。')\n return sections.join('\\n')\n}\n\n/**\n * Plan chapters from an outline (optionally for one volume).\n */\nexport async function planChapters(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n chapterCount: number,\n volumeNo?: number,\n outputDir?: string,\n): Promise<ChapterPlan[]> {\n const volume = project.volumes?.find(v => v.no === volumeNo)\n const existing = project.chapters\n const startNo = existing.length === 0 ? 1 : Math.max(...existing.map(c => c.no)) + 1\n const NL = String.fromCharCode(10)\n const continuation = existing.length > 0\n const latestFacts = continuation && Array.isArray(project.facts)\n ? project.facts.slice(-15).map(f => `[第${f.chapterNo}章] ${f.text.slice(0, 150)}`).join('\\n')\n : ''\n // 上一章(已写章节中章号最大者)结尾原文,作为续写剧情起点。\n let prevTail = ''\n if (continuation) {\n const written = existing.filter(c => c.status !== 'pending')\n const last = written[written.length - 1]\n if (last !== undefined && last.file !== undefined && outputDir !== undefined) {\n try {\n const raw = readFileSync(join(outputDir, last.file), 'utf8')\n prevTail = raw.replace(/^#.*$/m, '').trim().slice(-600)\n } catch { /* 文件缺失时忽略,仅依赖编年录 */ }\n }\n }\n // 续写模式大纲注入:精简大纲(≤2 万字)直接全量,避免误伤「分卷收官规划」(如第五卷双结局);\n // 超大 docx 大纲才节选——截到「记忆梗」之前,保留分卷大纲与红线,去掉后续冗余。\n const outlineBlock = continuation\n ? (() => {\n if (project.outline.length <= 20000) return project.outline\n const cut = project.outline.indexOf('十、全书核心弹幕记忆梗')\n if (cut > 1500) return project.outline.slice(0, cut).trimEnd() + '\\n(大纲过长,末尾记忆梗从略)'\n return project.outline.slice(0, 8000) + '\\n…(大纲过长已节选)'\n })()\n : project.outline\n const user = [\n '请为下面这部小说规划章节。',\n volume !== undefined\n ? `本次只规划第 ${volume.no} 卷《${volume.title}》的章节:\\n${volume.summary}`\n : continuation\n ? `本书已有 ${existing.length} 章已规划/已写作(见下方「已有章节」)。请规划**后续**章节:从第 ${startNo} 章开始。`\n : '请规划全书开篇章节。',\n continuation\n ? '【续写硬性要求】已有章节的剧情不得重写或重复,章节标题也不得与已有章节重复。以下情节均已在已有章节中发生过,后续章节**绝对不得再次出现**:穿越、暴雨送餐、滴血认主/古玉认主、首次进入墟境、用废铁淬炼首件法器、绝境肉身入鼎洗炼(该机缘已用尽)、杀死白袍弟子与灰衣随从、藏尸水沟。' + NL + '若本次规划已进入大纲的收尾区间(接近全书规划总章数),最后 5-10 章必须按大纲推进到大结局(终极抉择/清算/双结局等),**禁止以悬念、逃离、未解之谜收尾**——收尾区间按大纲卷定位判断,不以当前剧情是否“感觉像结尾”为准。'\n : '',\n prevTail !== ''\n ? `【上一章(第 ${startNo - 1} 章)结尾原文】第 ${startNo} 章必须紧接此状态继续,从新的事件写起,不得回顾重述:\\n${prevTail}`\n : '',\n latestFacts !== ''\n ? `【最新剧情状态(本书编年录,第 ${startNo - 1} 章结尾的事实)】规划续写时必须以此为起点,时间线、人物状态与地点衔接一致:\\n${latestFacts}`\n : '',\n continuation\n ? '已有章节(共 ' + existing.length + ' 章;仅列最近 80 章,更早的以标题计数为准,剧情以「编年录」为权威):\\n'\n + existing.slice(-80).map(c => {\n const sm = c.summary !== undefined && c.summary !== '' ? `(${c.summary.slice(0, 120)})` : ''\n return `第${c.no}章《${c.title}》${sm}`\n }).join('\\n')\n : '',\n `全书大纲(设定参考,续写剧情不得与设定冲突):\\n${outlineBlock}`,\n '',\n `请规划 ${chapterCount} 章。输出 JSON 数组(不要输出其他文字):`,\n ].join('\\n')\n const system = planSystemPrompt(project.volumes) + (continuation\n ? '\\n重要:本次是**续写规划**——已有章节的剧情不得重写或重复,新章节标题不得与已有章节标题相同,新章节的剧情必须从上一章结尾自然接续(人物状态、时间线、地点衔接一致)。'\n : '')\n const text = await complete(ctx, config, { system, user, temperature: 0.7, maxTokens: Math.max(config.maxTokens, 40000) })\n const parsed = parseJsonArray<Record<string, unknown>>(text)\n const chapters: ChapterPlan[] = []\n const existingNos = new Set(existing.map(c => c.no))\n const existingTitles = new Set(existing.map(c => c.title))\n let cursor = startNo\n for (const item of parsed) {\n if (chapters.length >= chapterCount) break\n if (typeof item !== 'object' || item === null) continue\n const entry = item as Record<string, unknown>\n const title = typeof entry.title === 'string' ? entry.title.trim().slice(0, 30) : ''\n const beats = typeof entry.beats === 'string' ? entry.beats.trim() : ''\n if (title === '' && beats === '') continue\n // 续写模式下,标题与已有章节重复的一律丢弃(模型可能复述旧章节)。\n if (title !== '' && existingTitles.has(title)) continue\n while (existingNos.has(cursor)) cursor++\n const no = cursor++\n chapters.push({\n no,\n volume: volumeOf(no, project.volumes),\n title: title || `第${no}章`,\n beats,\n targetChars: config.chapterChars,\n status: 'pending',\n })\n }\n if (chapters.length === 0) {\n throw new Error('章节计划生成失败:模型没有返回有效章节')\n }\n return chapters\n}\n\n// ------------------------------------------------------------------ writing\n\n/** The review system prompt. */\nfunction reviewSystemPrompt(project: ProjectState): string {\n const bible = project.bible\n const sections: string[] = [\n '你是一位严格的网文审稿编辑。你会收到一章正文以及本书的设定圣经与红线。',\n '请从以下维度审查本章:',\n '1. 人设一致性:角色行为是否符合角色卡(主角不圣母、不无脑、痞坏有分寸等)。',\n '2. 设定一致性:金手指规则、战力体系、世界观是否与设定圣经冲突。',\n '3. 红线检查:是否触犯写作红线(无后宫、无擦边、无无脑碾压等)。',\n '4. 文笔质量:语病、翻译腔、AI 套话(\"不禁\"\"仿佛\"\"一时间\"等高频词滥用)、流水账。',\n '5. 节奏与爽点:本章是否有推进、有钩子,是否拖沓灌水。',\n '6. 逻辑漏洞:前后矛盾、时间线错误、对话失真。',\n '7. 反 AI 规则:逐条核对下方「反 AI 规则」清单,命中即列为问题。',\n '8. 呈现方式:整章是否纯内心推理铺陈(无对话/无对抗,推理全靠解说);反派是否纯背景板无行动;重要配角是否无名标签化(瘦高个/灰衣人全程代称)——命中即列为问题。',\n '9. 内容合规(最高优先级):逐条核对下方「内容合规红线」,任何一条命中(含影射、暗示、详细描写)必须列为 high,并给出改写建议。',\n '输出必须是合法 JSON 对象,不要输出任何其他文字:',\n '{\"score\": 0-100的整数, \"verdict\": \"一句话总评\", \"issues\": [{\"severity\": \"high|medium|low\", \"item\": \"问题描述\", \"suggestion\": \"修改建议\"}]}',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ]\n const assetsBlock = renderAllAssets(project.assets)\n if (assetsBlock !== '') sections.push('\\n' + assetsBlock)\n if (bible !== undefined) {\n sections.push('\\n==================== 设定圣经 ====================')\n if (bible.worldRules.length > 0) sections.push('世界规则:\\n' + bible.worldRules.map(r => `- ${r}`).join('\\n'))\n if (bible.characters.length > 0) {\n sections.push('角色卡:')\n for (const card of bible.characters) {\n sections.push(`- ${card.name}(${card.role}):${card.traits.join('、')}`)\n if (Array.isArray(card.knowledge) && card.knowledge.length > 0) {\n sections.push(` 该角色知道:${card.knowledge.join(';')}(未列出的信息该角色不知道)`)\n }\n }\n }\n if (bible.redLines.length > 0) sections.push('红线:\\n' + bible.redLines.map(r => `- ${r}`).join('\\n'))\n }\n sections.push('\\n==================== 内容合规红线(平台硬性要求,最高优先级) ====================')\n sections.push(COMPLIANCE_REDLINES.join('\\n'))\n sections.push('以上九条为硬性底线:正文中任何一条命中(含影射、暗示、详细展开)都必须列为 high,并给出改写建议;作者自定义红线不得豁免这九条。')\n return sections.join('\\n')\n}\n\n/** Run the AI review on one chapter. */\nexport async function reviewChapter(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): Promise<ReviewReport> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) throw new Error(`章节 ${chapterNo} 不在计划中`)\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) throw new Error(`章节 ${chapterNo} 的正文文件不存在`)\n const user = [\n `本章标题:《${chapter.title}》`,\n `本章剧情要点:${chapter.beats}`,\n '==================== 章节正文 ====================',\n body.replace(/^#\\s+.*$/m, '').trim(),\n ].join('\\n')\n const text = await complete(ctx, config, { system: reviewSystemPrompt(project), user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 16000) })\n const raw = parseJsonObject<{ score?: unknown; verdict?: unknown; issues?: unknown }>(text)\n const issues = Array.isArray(raw.issues)\n ? raw.issues\n .filter((v): v is Record<string, unknown> => typeof v === 'object' && v !== null)\n .map(entry => ({\n severity: (['high', 'medium', 'low'] as const).includes(entry.severity as never)\n ? entry.severity as 'high' | 'medium' | 'low'\n : 'medium',\n item: typeof entry.item === 'string' ? entry.item : '',\n suggestion: typeof entry.suggestion === 'string' ? entry.suggestion : '',\n }))\n .filter(issue => issue.item !== '')\n : []\n const score = typeof raw.score === 'number' ? Math.max(0, Math.min(100, Math.round(raw.score))) : 60\n // 无 high 问题且评分 ≥60 → 直接通过(medium/low 主观项记录但不阻塞,避免“72 分卡线”空转修订)\n const passed = score >= config.reviewPassScore || (issues.every(i => i.severity !== 'high') && score >= 60)\n const report: ReviewReport = {\n score,\n passed,\n verdict: typeof raw.verdict === 'string' ? raw.verdict.slice(0, 200) : '',\n issues,\n reviewedAt: new Date().toISOString(),\n }\n chapter.review = report\n chapter.status = report.passed ? 'approved' : 'rejected'\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return report\n}\n\n/**\n * 审查「任意正文文本」(作者手动编辑后的草稿,不落盘)。\n * 复用审稿提示词与红线/道藏/反AI规则;仅返回报告,不改文件不改状态。\n */\nexport async function reviewChapterText(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n text: string,\n previousReport?: ReviewReport,\n): Promise<ReviewReport> {\n const user = [\n `书名:《${project.bookName}》`,\n previousReport !== undefined\n ? '==================== 上一轮审稿意见(逐条核对是否已解决) ====================\\n'\n + previousReport.issues.map((it, i) => `${i + 1}. [${it.severity}] ${it.item}${it.suggestion !== '' ? ` → ${it.suggestion}` : ''}`).join('\\n')\n : '',\n previousReport !== undefined\n ? '==================== 修订稿(上一轮审稿后按意见修订的正文) ===================='\n : '==================== 待审查正文 ====================',\n text.slice(0, 20000),\n ].join('\\n')\n // 验证模式:携带上一轮报告时,逐条核对原意见是否解决 + 只挑新增 high,不再全新找茬。\n const system = previousReport !== undefined ? verifySystemPrompt(project) : reviewSystemPrompt(project)\n const raw = parseJsonObject<{ score?: unknown; verdict?: unknown; issues?: unknown }>(\n await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 16000) }),\n )\n const issues = Array.isArray(raw.issues)\n ? raw.issues\n .filter((v): v is Record<string, unknown> => typeof v === 'object' && v !== null)\n .map(entry => ({\n severity: (['high', 'medium', 'low'] as const).includes(entry.severity as never)\n ? entry.severity as 'high' | 'medium' | 'low'\n : 'medium',\n item: typeof entry.item === 'string' ? entry.item : '',\n suggestion: typeof entry.suggestion === 'string' ? entry.suggestion : '',\n }))\n .filter(issue => issue.item !== '')\n : []\n const score = typeof raw.score === 'number' ? Math.max(0, Math.min(100, Math.round(raw.score))) : 60\n // 非验证模式:无 high 且评分 ≥60 → 通过;验证模式判定:原 high 全部解决 + 无新增 high → 通过(主观项不再卡修订)。\n let passed = score >= config.reviewPassScore || (issues.every(i => i.severity !== 'high') && score >= 60)\n if (previousReport !== undefined) {\n const hasHigh = issues.some(i => i.severity === 'high')\n const prevHigh = previousReport.issues.filter(i => i.severity === 'high')\n const prevHighResolved = prevHigh.every(p => !issues.some(i => i.item.includes(p.item.slice(0, 12))))\n passed = !hasHigh && prevHighResolved\n }\n return {\n score,\n passed,\n verdict: typeof raw.verdict === 'string' ? raw.verdict.slice(0, 200) : '',\n issues,\n reviewedAt: new Date().toISOString(),\n }\n}\n\n/** 验证模式系统提示:修订后逐条核对原意见是否解决,只挑新增 high,不重复挑剔主观项。 */\nfunction verifySystemPrompt(project: ProjectState): string {\n return [\n '你是一位网文审稿验证员。作者已按上一轮审稿意见修订了本章,你需要验证修订效果。',\n '你的任务(严格按此执行):',\n '1. 逐条核对「上一轮意见」中的每一条是否已在修订稿中解决——已解决的不再列出;未解决或部分解决的,按原严重度列出(item 需注明\"未解决:原意见 xxx\")。',\n '2. 只挑修订【新引入】的 high 级问题(设定矛盾/逻辑硬伤/事实错误)——新引入的 medium/low 主观项(文笔/套话/节奏)不要列。',\n '3. 禁止重复挑剔上一轮已指出且本次已解决的主观项(如\"缓缓/微微\"等套话、错别字)——即使换个说法再提也不行。',\n '4. 严禁为了显得专业而新增\"换一批毛病\"式的意见;如果修订稿已解决全部 high 且无新增 high,输出 issues 为空数组。',\n 'score 评分:按修订稿整体质量给 50-90 分(解决全部 high 且无新增 high 时给 70 以上)。',\n 'verdict:一句话结论(如\"原 high 已解决,无新增高风险问题\"或\"仍有未解决的 high\")。',\n '输出必须是合法 JSON 对象:{\"score\": 数字, \"verdict\": \"一句话\", \"issues\": [{\"severity\": \"high|medium|low\", \"item\": \"问题\", \"suggestion\": \"建议\"}]}',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n `本书设定圣经(核对设定冲突用):\\n${project.bible !== undefined ? JSON.stringify(project.bible).slice(0, 3000) : '(无)'}`,\n ].join('\\n')\n}\n\n/** Build the author-review system prompt (narrative structure, not prose). */\nfunction authorReviewSystemPrompt(): string {\n return [\n '你是一位网文作者复盘助手。你会收到:本章正文、上一章结尾(钩子)、上一章作者复盘(如有)、活跃剧情线与编年录近期事实。',\n '请从叙事结构层面复盘本章(不评文笔,那是审稿的事):',\n '1. hookHonored:上一章结尾的钩子/悬念是否在本章兑现或推进(true/false)。',\n '2. hookNote:钩子兑现情况一句话;未兑现时说明并给出\"建议在第几章补\"的建议。',\n '3. endingHook:本章结尾钩子强度,0-10 的整数(低于 6 说明结尾平淡,读者可能不想看下一章)。',\n '4. plotlineProgress:本章推进了哪条剧情线(主线/支线名),或\"无实质推进\"(连续无推进要提醒)。',\n '5. advancedLines:本章实际推进的剧情线名称数组——从「活跃剧情线」清单中选出推进了的线(名称必须与清单中的线名一字不差;没推进任何线则输出空数组)。',\n '6. continuity:与上一章结尾的衔接检查(人物位置/时间/伤势/资源/对话状态),发现问题要指出。',\n '7. trend:结合上一章复盘看近期节奏趋势(是否连续拖沓、爽点密度是否下降、是否需要调整)。',\n '输出必须是合法 JSON 对象,不要输出任何其他文字:',\n '{\"hookHonored\": true或false, \"hookNote\": \"一句话\", \"endingHook\": 0-10整数, \"plotlineProgress\": \"一句话\", \"advancedLines\": [\"线名\"], \"continuity\": \"一句话\", \"trend\": \"一句话\"}',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n}\n\n/** 作者复盘:对一章做叙事结构复盘(钩子兑现/结尾钩子/推进/连续性/趋势)。 */\nexport async function authorReviewChapter(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n chapterNo: number,\n body: string,\n prevTail: string,\n): Promise<AuthorReview> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n const prevChapter = chapterNo > 1 ? project.chapters.find(c => c.no === chapterNo - 1) : undefined\n const lines = (project.plotlines ?? []).filter(l => l.status === 'active' || l.status === 'paused')\n const facts = (project.facts ?? []).slice(-10)\n const user = [\n `书名:《${project.bookName}》`,\n chapter !== undefined ? `本章:第 ${chapter.no} 章《${chapter.title}》` : `本章:第 ${chapterNo} 章`,\n prevTail !== ''\n ? `==================== 上一章(第 ${chapterNo - 1} 章)结尾(钩子) ====================\\n${prevTail}`\n : '(本书第一章,无上一章钩子;hookHonored 视为 true,hookNote 写\"开篇无前置钩子\")',\n prevChapter?.authorReview !== undefined\n ? `==================== 上一章作者复盘 ====================\\n${JSON.stringify(prevChapter.authorReview)}`\n : '',\n lines.length > 0\n ? `==================== 活跃剧情线 ====================\\n${lines.map(l => `- [${l.kind}] ${l.name}:${l.goal}${l.progress !== '' ? `(${l.progress})` : ''}`).join('\\n')}`\n : '',\n facts.length > 0\n ? `==================== 编年录近期事实 ====================\\n${facts.map(f => `[第${f.chapterNo}章] ${f.text}`).join('\\n')}`\n : '',\n '==================== 本章正文 ====================',\n body.slice(0, 16000),\n '',\n '只输出 JSON 对象。',\n ].join('\\n')\n const raw = parseJsonObject<{\n hookHonored?: unknown\n hookNote?: unknown\n endingHook?: unknown\n plotlineProgress?: unknown\n advancedLines?: unknown\n continuity?: unknown\n trend?: unknown\n }>(\n await complete(ctx, config, { system: authorReviewSystemPrompt(), user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 4000) }),\n )\n // 解析推进的线名(与项目线名精确匹配;过滤不存在的名字)。\n const knownLineNames = new Set((project.plotlines ?? []).map(l => l.name))\n const advancedLines = Array.isArray(raw.advancedLines)\n ? raw.advancedLines.filter((n): n is string => typeof n === 'string' && n.trim() !== '' && knownLineNames.has(n.trim())).map(n => n.trim())\n : []\n return {\n hookHonored: raw.hookHonored === true,\n hookNote: typeof raw.hookNote === 'string' ? raw.hookNote.slice(0, 200) : '',\n endingHook: typeof raw.endingHook === 'number' ? Math.max(0, Math.min(10, Math.round(raw.endingHook))) : 5,\n plotlineProgress: typeof raw.plotlineProgress === 'string' ? raw.plotlineProgress.slice(0, 200) : '',\n advancedLines,\n continuity: typeof raw.continuity === 'string' ? raw.continuity.slice(0, 200) : '',\n trend: typeof raw.trend === 'string' ? raw.trend.slice(0, 200) : '',\n reviewedAt: new Date().toISOString(),\n }\n}\n\n/** 复盘后自动关联:把本章号写入复盘标记推进的剧情线(按名称匹配,去重)。 */\nexport function autoLinkPlotlines(project: ProjectState, chapterNo: number, advancedLines: string[]): void {\n if (!Array.isArray(project.plotlines) || advancedLines.length === 0) return\n for (const line of project.plotlines) {\n if (advancedLines.includes(line.name) && !line.chapters.includes(chapterNo)) {\n line.chapters.push(chapterNo)\n }\n }\n}\n\n/** AI 建议剧情线:基于大纲/卷计划/已写章节/编年录,提炼候选线。 */\nexport async function suggestPlotlines(ctx: Context, config: NovelConfig, project: ProjectState): Promise<Plotline[]> {\n const system = [\n '你是一位网文剧情架构师。根据本书的大纲、卷计划、已写章节标题与编年录,为作者提炼建议的剧情线(主线/支线/人物线/悬念线)。',\n '每条线要:名称简洁有力;目标写清楚这条线最终要完成什么;progress 写当前推进到哪(没有就空字符串)。',\n '建议 4-8 条,覆盖:1 条主线、1-2 条人物线、1-2 条悬念线、1-3 条支线。避免与大纲明显重复的废话线。',\n '输出必须是合法 JSON 数组,格式:[{\"name\": \"线名\", \"kind\": \"main|branch|character|mystery\", \"goal\": \"目标\", \"progress\": \"\"}]',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending')\n const user = [\n `书名:《${project.bookName}》`,\n `大纲(节选前 4000 字):\\n${project.outline.slice(0, 4000)}`,\n project.volumes !== undefined && project.volumes.length > 0\n ? `卷计划:\\n${project.volumes.map(v => `第${v.no}卷《${v.title}》:${v.summary}`).join('\\n')}`\n : '',\n written.length > 0\n ? `已写章节:\\n${written.map(c => `第${c.no}章《${c.title}》${c.summary !== undefined && c.summary !== '' ? `:${c.summary.slice(0, 80)}` : ''}`).join('\\n')}`\n : '',\n (project.facts ?? []).length > 0\n ? `编年录近期事实(最近 15 条):\\n${(project.facts ?? []).slice(-15).map(f => `[第${f.chapterNo}章] ${f.text.slice(0, 100)}`).join('\\n')}`\n : '',\n '只输出 JSON 数组。',\n ].join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.6, maxTokens: Math.max(config.maxTokens, 4000) })\n const raw = parseJsonArray<Record<string, unknown>>(text)\n const lines: Plotline[] = []\n const kinds = new Set(['main', 'branch', 'character', 'mystery'])\n for (const entry of raw) {\n if (typeof entry !== 'object' || entry === null) continue\n const name = typeof entry.name === 'string' ? entry.name.trim().slice(0, 40) : ''\n if (name === '') continue\n lines.push({\n id: '',\n name,\n kind: kinds.has(entry.kind as string) ? entry.kind as Plotline['kind'] : 'branch',\n goal: typeof entry.goal === 'string' ? entry.goal.trim().slice(0, 300) : '',\n progress: typeof entry.progress === 'string' ? entry.progress.trim().slice(0, 300) : '',\n status: 'active',\n chapters: [],\n createdAt: new Date().toISOString(),\n })\n }\n return lines\n}\n\n/** AI 刷新单条剧情线的进度:结合编年录与各章摘要分析该线推进到哪。 */\nexport async function refreshPlotlineProgress(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n line: Plotline,\n): Promise<string> {\n const system = [\n '你是一位网文剧情线管理员。请根据「剧情线信息」与「本书已写章节摘要/编年录」,判断这条线目前推进到了哪一步。',\n '输出一句话(30-60 字):这条线当前的状态、最近一次推进发生在第几章、下一步可能的方向。如果这条线还没开始推进,明确说\"尚未推进\"。',\n '输出必须是合法 JSON 对象:{\"progress\": \"一句话\"}',\n '重要:不要输出任何其他文字。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending' && (c.summary !== undefined && c.summary !== ''))\n const user = [\n `剧情线:${line.name}(${line.kind})`,\n `目标:${line.goal}`,\n `已知进度:${line.progress !== '' ? line.progress : '(无)'}`,\n `已关联章节:${line.chapters.length > 0 ? line.chapters.map(n => `第${n}章`).join('、') : '(无)'}`,\n `章节摘要(最近 8 章):\\n${written.slice(-8).map(c => `第${c.no}章《${c.title}》:${c.summary!.slice(0, 120)}`).join('\\n')}`,\n (project.facts ?? []).length > 0\n ? `编年录近期事实(最近 15 条):\\n${(project.facts ?? []).slice(-15).map(f => `[第${f.chapterNo}章] ${f.text.slice(0, 100)}`).join('\\n')}`\n : '',\n '只输出 JSON 对象。',\n ].join('\\n\\n')\n const raw = parseJsonObject<{ progress?: unknown }>(\n await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 2000) }),\n )\n return typeof raw.progress === 'string' ? raw.progress.trim().slice(0, 300) : ''\n}\n\n/** ✨ AI 从全书提炼角色库:大纲 + 道藏 + 编年录 + 章节摘要 → 结构化角色清单。 */\nexport async function extractRoles(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n): Promise<RoleRecord[]> {\n const system = [\n '你是一位网文角色库管理员。请根据本书的大纲、设定、编年录与章节摘要,提炼完整的角色库。',\n '覆盖原则:所有在编年录/章节中实际出场或有名有姓的角色都应收录;无名的功能性人物(如\"矮胖姑娘\")用其身份简称收录并标注。',\n '数量控制:最多输出 10 个角色,宁缺毋滥;路人级一次带过的不要收录。',\n '每个角色输出:',\n '1. name:角色名(或身份简称)。主角/有名配角必须用正文中实际出现的人名(如「沈放」),禁止用「主角(38岁超市理货员)」这类把身份塞进名字的占位名;正文确实没点名时才可用身份简称(如「富商」「灰衣老人」)。',\n '2. roleLabel:定位——protagonist=主角;female_lead=女主(唯一知己/感情线核心,无后宫前提下只此一位);female_support=重要女配;support=普通配角;antagonist=反派;extra=路人/背景。',\n '3. identity:身份一句话(宗门/势力/血脉/职业)。',\n '4. traits:3-6 个性格标签。',\n '5. goals:目标与动机一句话。',\n '6. relations:关系网数组,格式[\"角色名(关系)\", ...]。',\n '7. arc:成长线数组,格式[\"阶段:说明\", ...](如\"出场:祭品身份\"/\"转折:祭祀被中断脱身\")。',\n '8. knowledge:该角色已经知道的关键信息(3-8 条),不知道的信息不要写进去。',\n '精简要求:identity 控制在 30 字内;traits 3-6 个短标签;goals 60 字内;relations 2-5 条;arc 2-4 条;knowledge 每条 40 字内。整体输出量要紧凑,避免冗长。',\n '重要:用户消息里列出的「已收录角色」绝不要再次输出——这些角色已经在角色库里,跳过它们,只提炼未收录的。',\n '输出必须是合法 JSON 数组,不要输出其他文字:[{\"name\":\"...\", \"roleLabel\":\"...\", \"identity\":\"...\", \"traits\":[...], \"goals\":\"...\", \"relations\":[...], \"arc\":[...], \"knowledge\":[...]}]',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating')\n const existingRoles = project.roles ?? []\n // 正文摘录:让提炼真正读到书的内容(角色姓名/身份/关系以正文为准)。\n const excerptParts: string[] = []\n for (const chapter of written.slice(0, 3)) {\n const body = readChapterFile(config.outputDir, chapter)\n if (body === undefined) continue\n const text = body.replace(/^#.*$/gm, '').trim()\n if (text.length > 0) excerptParts.push(`第${chapter.no}章《${chapter.title}》\\n${text.slice(0, 2400)}`)\n }\n const user = [\n `书名:《${project.bookName}》`,\n existingRoles.length > 0\n ? `已收录角色(跳过,不要输出):${existingRoles.map(r => r.name).join('、')}`\n : '',\n `大纲(节选前 3000 字):\\n${project.outline.slice(0, 3000)}`,\n excerptParts.length > 0\n ? `已写正文摘录(角色姓名/身份/关系以正文为准):\\n${excerptParts.join('\\n\\n')}`\n : '',\n project.bible !== undefined && project.bible.characters.length > 0\n ? `已有角色卡(补充信息):\\n${project.bible.characters.map(c => `- ${c.name}(${c.role}):${c.traits.join('、')}${c.goals !== '' ? `;目标:${c.goals}` : ''}`).join('\\n')}`\n : '',\n (project.facts ?? []).length > 0\n ? `编年录(最近 60 条):\\n${(project.facts ?? []).slice(-60).map(f => `[第${f.chapterNo}章] ${f.text.slice(0, 80)}`).join('\\n')}`\n : '',\n written.length > 0\n ? `已写章节标题(${written.length} 章):\\n${written.map(c => `第${c.no}章《${c.title}》`).join('、')}`\n : '',\n '只输出 JSON 数组。',\n ].join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 24000) })\n const raw = parseJsonArray<Record<string, unknown>>(text)\n const labels = new Set(['protagonist', 'female_lead', 'female_support', 'support', 'antagonist', 'extra'])\n const strArr = (v: unknown): string[] => Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string' && x.trim() !== '') : []\n const roles: RoleRecord[] = []\n for (const entry of raw) {\n if (typeof entry !== 'object' || entry === null) continue\n const name = typeof entry.name === 'string' ? entry.name.trim().slice(0, 30) : ''\n if (name === '') continue\n roles.push({\n name,\n roleLabel: labels.has(entry.roleLabel as string) ? entry.roleLabel as RoleRecord['roleLabel'] : 'support',\n identity: typeof entry.identity === 'string' ? entry.identity.slice(0, 100) : '',\n traits: strArr(entry.traits).map(t => t.slice(0, 20)).slice(0, 8),\n goals: typeof entry.goals === 'string' ? entry.goals.slice(0, 200) : '',\n relations: strArr(entry.relations).map(r => r.slice(0, 60)).slice(0, 10),\n arc: strArr(entry.arc).map(a => a.slice(0, 120)).slice(0, 10),\n knowledge: strArr(entry.knowledge).map(k => k.slice(0, 120)).slice(0, 12),\n })\n }\n return roles\n}\n\n/** ✨ AI 从全书提炼场景库:正文/编年录 → 高频重要场景的结构化视觉锚点。 */\nexport async function extractScenes(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n): Promise<SceneCard[]> {\n const system = [\n '你是一位网文漫剧场景导演。根据本书的大纲、编年录与已写章节摘录,提炼「镜头场景」——漫剧分镜/生图时每个镜头要知道\"在哪、什么时间光态、拍什么情节、人物什么状态\"。',\n '按五幕结构覆盖全书核心场景(短篇 10 章内可少于五幕,按实际剧情组织):第一幕后场/核心主场、第二幕对外卖场/营业区、第三幕禁忌区域/地下深仓、第四幕外部人间世界(短暂出逃)、第五幕回归与抉择。',\n '每个场景必须是「镜头场景」而非仅场地:给出该场景的关键情节镜头(人物动作+情绪+镜头推进)。',\n '数量控制:最多输出 8 个场景;每个场景必须能对应到正文实际出现过的地点与情节,不得凭空虚构。',\n '每个场景输出:',\n '1. name:场景名(地点+光态,如「后场通道·装卸口(雨夜)」)。',\n '2. act:幕归属(第一幕后场/第二幕卖场/第三幕深仓/第四幕外界/第五幕抉择)。',\n '3. moment:时间光态(夜间闭店后/雨夜/凌晨/频闪灯…)。',\n '4. summary:一句话定位(空间类型/功能/氛围)。',\n '5. beats:关键情节镜头 1-3 条(人物动作+情绪+镜头推进,如\"沈放佝偻站在货架过道,镜头推近,情绪从漠然过渡到压抑悲伤\")。',\n '6. characterState:主角/关键角色在该场景的状态一句话(含标志物细节如标签磨损、手腕红痕)。',\n '7. elements:环境构成数组 3-6 项(空间结构/陈设/标志物)。',\n '8. palette:色调与光影数组 2-4 项(颜色词,可附 HEX)。',\n '9. moods:氛围关键词 2-4 个(压抑/神秘/空旷/悲凉…)。',\n '10. zh:中文生图提示词(连贯一段,写实电影感,含环境/光线/氛围/人物状态)。',\n '11. en:英文生图提示词(booru 风格逗号分隔,含 photorealistic/cinematic)。',\n '12. tags:3-6 个关键标签。',\n '13. source:依据来源说明(哪几章哪些描写)。',\n '若故事存在结局抉择(如双分支),最后 1-2 个场景应为「抉择场景」,zh 里写明分支 A/B 两种画面。',\n '输出必须是合法 JSON 数组,不要输出其他文字:[{\"name\":\"...\", \"act\":\"...\", \"moment\":\"...\", \"summary\":\"...\", \"beats\":[...], \"characterState\":\"...\", \"elements\":[...], \"palette\":[...], \"moods\":[...], \"zh\":\"...\", \"en\":\"...\", \"tags\":[...], \"source\":\"...\"}]',\n '重要:所有字符串值内部不得包含换行符;直接输出 JSON 结果本身。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating')\n const excerptParts: string[] = []\n for (const chapter of written.slice(0, 4)) {\n const body = readChapterFile(config.outputDir, chapter)\n if (body === undefined) continue\n const text = body.replace(/^#.*$/gm, '').trim()\n if (text.length > 0) excerptParts.push('第' + chapter.no + '章《' + chapter.title + '》' + '\\n' + text.slice(0, 1800))\n }\n const user = [\n '书名:《' + project.bookName + '》',\n (project.facts ?? []).length > 0\n ? '编年录(最近 80 条,场景地点以这里为准):' + '\\n' + (project.facts ?? []).slice(-80).map(f => '[第' + f.chapterNo + '章] ' + f.text.slice(0, 80)).join('\\n')\n : '',\n excerptParts.length > 0\n ? '已写正文摘录(场景描写以正文为准):' + '\\n' + excerptParts.join('\\n')\n : '',\n '只输出 JSON 数组。',\n ].filter(s => s !== '').join('\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.4, maxTokens: Math.max(config.maxTokens, 12000) })\n const raw = parseJsonArray<Record<string, unknown>>(text)\n const strArr = (v: unknown): string[] => Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string' && x.trim() !== '') : []\n const str = (v: unknown): string => typeof v === 'string' ? v.trim() : ''\n const scenes: SceneCard[] = []\n for (const entry of raw) {\n if (typeof entry !== 'object' || entry === null) continue\n const name = str(entry.name).slice(0, 40)\n if (name === '') continue\n scenes.push({\n name,\n act: str(entry.act).slice(0, 40),\n moment: str(entry.moment).slice(0, 60),\n summary: str(entry.summary).slice(0, 120),\n beats: strArr(entry.beats).map(t => t.slice(0, 120)).slice(0, 3),\n characterState: str(entry.characterState).slice(0, 160),\n elements: strArr(entry.elements).map(t => t.slice(0, 60)).slice(0, 6),\n palette: strArr(entry.palette).map(t => t.slice(0, 40)).slice(0, 4),\n moods: strArr(entry.moods).map(t => t.slice(0, 20)).slice(0, 4),\n zh: str(entry.zh).slice(0, 800),\n en: str(entry.en).slice(0, 600),\n tags: strArr(entry.tags).map(t => t.slice(0, 24)).slice(0, 6),\n source: str(entry.source).slice(0, 120),\n })\n }\n return scenes\n}\n\n/** 动漫形象描述词(中文描述 + 英文 booru 标签 + 关键外貌标签)。 */\nexport interface RoleVisualPrompt {\n zh: string\n en: string\n tags: string[]\n source: string\n /** 该角色所需情绪表情清单(6-12 个,如 疲惫/麻木/压抑悲伤)。 */\n expressions?: string[]\n /** 四类精修提示词(立绘/四视图/表情/细节,一次提炼直接产出)。 */\n promptKit?: RoleRecord['promptKit']\n}\n\n/**\n * 为单个角色提炼「动漫形象描述词」:扫描该角色出场的已写章节正文,\n * 截取含外貌描写的段落,交给 LLM 提炼中文描述 + 英文绘图标签。\n */\nexport async function extractRoleVisual(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n roleName: string,\n): Promise<RoleVisualPrompt> {\n const role = (project.roles ?? []).find(r => r.name === roleName)\n if (role === undefined) throw new Error(`角色「${roleName}」不在角色库中`)\n\n // 1. 扫描正文:收集该角色出场且可能含外貌描写的段落(最近 60 章内,每章最多 2 段,共 12 段)。\n // 支持“描述型角色名”(如「灰蓝工装女人」):先精确匹配,匹配不到时用角色名拆分出的关键词兜底。\n const appearanceHints = /(发|眉|眼|眸|脸|肤|唇|身材|身高|衣|袍|裙|衫|靴|腰带|气质|模样|长相|容貌|披|束|扎|戴|佩|挂|绣|青|白|黑|红|蓝|紫|灰|银|金|少年|青年|少女|汉子|老者|中年|纤细|挺拔|瘦削|壮实|清秀|俊朗|英气|阴鸷|慈眉)/\n // 从角色名 + 身份描述中提取可检索关键词,支持“描述型角色名”(灰蓝工装女人)和“身份型角色名”(富商)。\n const roleText = `${role.name} ${role.identity ?? ''}`\n const colorWords = ['深灰', '灰蓝', '灰', '蓝', '白', '黑', '红', '青', '紫', '银', '金', '黄', '绿', '粉', '棕']\n const garmentWords = ['工装', '西装', '定制西装', '袍', '裙', '衫', '衣', '裤', '靴', '鞋', '帽', '腰带', '制服', '外套', '马甲', '夹克']\n const roleWords = ['女人', '男人', '老者', '老人', '中年', '青年', '少女', '姑娘', '男子', '女子', '工人', '路人', '购买者']\n const locationWords = ['别墅', '小区', '街区']\n const identityTokens = (role.identity ?? '').split(/[,,。\\s]+/).filter(t => t.length >= 2)\n const searchTokens = Array.from(new Set([\n roleName,\n ...identityTokens,\n ...colorWords.filter(w => roleText.includes(w)),\n ...garmentWords.filter(w => roleText.includes(w)),\n ...roleWords.filter(w => roleText.includes(w)),\n ...locationWords.filter(w => roleText.includes(w)),\n ])).filter(t => t.length >= 2)\n const matchesRole = (para: string): boolean => para.includes(roleName) || searchTokens.some(tok => para.includes(tok))\n const excerpts: Array<{ no: number; text: string }> = []\n const written = project.chapters\n .filter(c => c.status !== 'pending' && c.status !== 'generating' && c.file !== undefined)\n .slice(-60)\n for (const chapter of written) {\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) continue\n const paras = body.split(/\\n{2,}/).map(p => p.trim()).filter(p => p.length > 0)\n let perChapter = 0\n for (const para of paras) {\n if (perChapter >= 2 || excerpts.length >= 12) break\n if (!matchesRole(para)) continue\n // 优先外貌描写段(含外貌关键词),否则纯动作段也收(LLM 自己判断)。\n if (appearanceHints.test(para) || excerpts.length < 4) {\n excerpts.push({ no: chapter.no, text: para.slice(0, 220) })\n perChapter++\n }\n }\n if (excerpts.length >= 12) break\n }\n if (excerpts.length === 0) {\n throw new Error(`正文中未找到「${roleName}」的出场描写(仅搜索最近 60 章),请确认角色名与正文一致`)\n }\n\n // 2. LLM 提炼:一次输出 锚点 + 表情清单 + 四类精修提示词。\n const rules = project.visualRules ?? []\n const system = [\n '你是一位动漫角色设定师与 AI 绘图提示词工程师。根据网文正文中该角色的实际外貌描写,输出「形象锚点」与「四类生图提示词」——一次完成,用于 AI 绘图(NovelAI / Stable Diffusion / Midjourney / 豆包等)生成一致的角色立绘。',\n '硬性要求(依据优先):',\n '1. 发色/发型/瞳色/服装/气质/标志物必须来自提供的正文段落,不得凭空发明。',\n '2. 正文未明确写到的项目(如瞳色没写、身高没写),用「未定」标注或直接不写,不要编造数值。',\n '3. 服装优先取正文明确出现的(颜色+款式),多次出现取最常穿的组合;服装按分件组织(上身/下身/鞋/配饰)。',\n '4. 标志物(标签/印记/饰品)必须出现在每段提示词中——它们是一致性的命根子。',\n '【本书视觉规则】(必须内嵌进每段提示词,保证设定不跑偏):',\n ...rules.map(r => '- ' + r),\n '输出六部分:',\n '- zh:中文形象锚点,一段连贯文字(60-150 字):发色发型、瞳色、脸型气质、服装(颜色款式)、身材、标志性物件。',\n '- en:英文形象锚点,booru 风格、逗号分隔、小写,30-50 个标签:含性别(1boy/1girl)、发色、发型、瞳色、服装、气质、标志物。不要输出负面提示词。',\n '- tags:中文关键标签数组,5-10 个(如 [\"黑发\",\"束发\",\"青色道袍\",\"清秀\",\"腰悬古玉\"])。',\n '- source:说明依据(如\"第1章/第8章外貌描写;瞳色未明确\")。',\n '- expressions:该角色在本书剧情中需要的情绪表情清单数组,6-12 个(如 [\"疲惫\",\"麻木\",\"压抑悲伤\",\"皱眉\",\"紧绷\",\"放空\"]),依据正文情绪描写与角色处境推断。',\n '- promptKit:四类精修提示词(字段化+出图约束,参考示例结构):',\n ' · portrait 立绘:角色设计稿定位,纯白纯色背景,全身完整无裁切,无多余杂物;字段流:年龄感、身高(有依据才写)、发型发色、胡茬、眼眸、面部气质、上身服装分件(含磨损)、下身、鞋、标志物细节。',\n ' · sheet 四视图:同一角色的 正面/左侧面/右侧面/背面 四视图设定表(character sheet),纯白背景,全身完整,四个视角分别描述,服装与标志物细节完整展示。',\n ' · expressions 表情:每个表情一段,脸部特写(头部到锁骨),纯白背景,五官与角色定稿完全一致,只换情绪表达(眼神/嘴角/眉),皮肤纹理细节完整,无多余杂物。',\n ' · details 细节:多组局部细节集合参考图(一张图多个局部框),纯白背景;把该角色全部标志物逐项列出(如标签/印记/工牌/袖口磨损/鞋),每项一句特写描述;细节清晰锐利,角色细节参考稿,无多余杂物。',\n 'promptKit 每段 zh:连贯中文 60-150 字;en:booru 标签 30-50 个。',\n '输出必须是合法 JSON 对象:{\"zh\": \"...\", \"en\": \"...\", \"tags\": [...], \"source\": \"...\", \"expressions\": [...], \"promptKit\": {\"portrait\": {\"zh\":\"...\", \"en\":\"...\"}, \"sheet\": {\"zh\":\"...\", \"en\":\"...\"}, \"expressions\": [{\"name\":\"疲惫\",\"zh\":\"...\",\"en\":\"...\"}], \"details\": {\"zh\":\"...\", \"en\":\"...\"}}}',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n const user = [\n `书名:《${project.bookName}》`,\n `目标角色:${role.name}(${role.identity})`,\n role.traits.length > 0 ? `性格标签:${role.traits.join('、')}` : '',\n `正文出场描写(含外貌线索的段落):`,\n ...excerpts.map(e => `[第${e.no}章] ${e.text}`),\n '只输出 JSON 对象。',\n ].join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.4, maxTokens: Math.max(config.maxTokens, 12000) })\n const raw = parseJsonObject<{ zh?: unknown; en?: unknown; tags?: unknown; source?: unknown; expressions?: unknown; promptKit?: unknown }>(text)\n const zh = typeof raw.zh === 'string' ? raw.zh.trim().slice(0, 500) : ''\n const en = typeof raw.en === 'string' ? raw.en.trim().slice(0, 1500) : ''\n const tags = Array.isArray(raw.tags)\n ? raw.tags.filter((t): t is string => typeof t === 'string' && t.trim() !== '').map(t => t.trim().slice(0, 20)).slice(0, 12)\n : []\n const source = typeof raw.source === 'string' ? raw.source.trim().slice(0, 300) : ''\n const expressions = Array.isArray(raw.expressions)\n ? raw.expressions.filter((e): e is string => typeof e === 'string' && e.trim() !== '').map(e => e.trim().slice(0, 12)).slice(0, 12)\n : []\n // 四类精修提示词(一次提炼直接产出)\n const str = (v: unknown): string => typeof v === 'string' ? v.trim() : ''\n const pair = (v: unknown): { zh: string; en: string } => {\n const o = (typeof v === 'object' && v !== null) ? v as Record<string, unknown> : {}\n return { zh: str(o.zh).slice(0, 800), en: str(o.en).slice(0, 1200) }\n }\n const kitRaw = (typeof raw.promptKit === 'object' && raw.promptKit !== null) ? raw.promptKit as Record<string, unknown> : {}\n const kitExpr = Array.isArray(kitRaw.expressions) ? kitRaw.expressions.filter((e): e is Record<string, unknown> => typeof e === 'object' && e !== null) : []\n let promptKit: RoleRecord['promptKit']\n try {\n promptKit = {\n portrait: pair(kitRaw.portrait),\n sheet: pair(kitRaw.sheet),\n expressions: kitExpr.map(e => ({\n name: str(e.name).slice(0, 12) || '表情',\n zh: str(e.zh).slice(0, 800),\n en: str(e.en).slice(0, 1200),\n })).slice(0, 12),\n details: pair(kitRaw.details),\n }\n } catch {\n promptKit = undefined\n }\n if (zh === '' || en === '') {\n throw new Error('形象描述提炼失败:LLM 未返回有效 JSON')\n }\n return { zh, en, tags, source, expressions, promptKit }\n}\n\n/**\n * 角色四类生图提示词精修包(promptKit):以锚点 + 表情清单 + 视觉规则为输入,\n * LLM 产出 立绘/四视图/表情×N/细节 四套 zh+en 提示词(比前端拼装更精炼)。\n */\nexport async function generateRolePromptKit(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n roleName: string,\n): Promise<RoleRecord['promptKit']> {\n const role = (project.roles ?? []).find(r => r.name === roleName)\n if (role === undefined) throw new Error(`角色「${roleName}」不在角色库中`)\n if (role.imagePrompt === undefined) throw new Error(`角色「${roleName}」还没有形象锚点,请先生成锚点`)\n const rules = project.visualRules ?? []\n const system = [\n '你是一位 AI 绘图提示词工程师。基于给定角色的形象锚点、表情清单与本书视觉规则,输出四类生图提示词(每类 zh+en 各一段)。',\n '四类:',\n '1. portrait 立绘:全身/半身正视图,含完整服装与标志物。',\n '2. sheet 四视图:同一角色的 正面/左侧面/右侧面/背面 四视图设定表(character sheet),纯白背景,四个视角分别描述。',\n '3. expressions 表情:每个表情一段,脸部特写(头部到锁骨),纯白背景,五官与角色定稿完全一致,只换情绪表达(眼神/嘴角/眉),皮肤纹理细节完整,无多余杂物。',\n '4. details 细节:多组局部细节集合参考图(一张图多个局部框),纯白背景;把该角色全部标志物逐项列出,每项一句特写描述;细节清晰锐利,角色细节参考稿,无多余杂物。',\n '【本书视觉规则】(必须内嵌进每段提示词,保证设定不跑偏):',\n ...rules.map(r => '- ' + r),\n 'zh 要求:连贯中文,写实电影感,60-150 字/段;en 要求:booru 风格逗号分隔标签,30-50 个/段。',\n '输出必须是合法 JSON 对象:{\"portrait\": {\"zh\": \"...\", \"en\": \"...\"}, \"sheet\": {\"zh\": \"...\", \"en\": \"...\"}, \"expressions\": [{\"name\": \"疲惫\", \"zh\": \"...\", \"en\": \"...\"}], \"details\": {\"zh\": \"...\", \"en\": \"...\"}}',\n '重要:所有字符串值内部不得包含换行符;直接输出 JSON 结果本身。',\n ].join('\\n')\n const user = [\n `角色:${role.name}(${role.identity ?? ''})`,\n `中文锚点:${role.imagePrompt.zh}`,\n `英文锚点:${role.imagePrompt.en}`,\n `关键标签:${role.imagePrompt.tags.join('、')}`,\n `表情清单:${(role.expressions ?? []).join('、') || '(未提供,按角色气质推断 6 个)'}`,\n '只输出 JSON 对象。',\n ].join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.4, maxTokens: Math.max(config.maxTokens, 12000) })\n const raw = parseJsonObject<Record<string, unknown>>(text)\n const str = (v: unknown): string => typeof v === 'string' ? v.trim() : ''\n const pair = (v: unknown): { zh: string; en: string } => {\n const o = (typeof v === 'object' && v !== null) ? v as Record<string, unknown> : {}\n return { zh: str(o.zh).slice(0, 800), en: str(o.en).slice(0, 1200) }\n }\n const expressionsRaw = Array.isArray(raw.expressions) ? raw.expressions.filter((e): e is Record<string, unknown> => typeof e === 'object' && e !== null) : []\n const kit: RoleRecord['promptKit'] = {\n portrait: pair(raw.portrait),\n sheet: pair(raw.sheet),\n expressions: expressionsRaw.map(e => ({\n name: str(e.name).slice(0, 12) || '表情',\n zh: str(e.zh).slice(0, 800),\n en: str(e.en).slice(0, 1200),\n })).slice(0, 12),\n details: pair(raw.details),\n }\n if (kit.portrait.zh === '' || kit.portrait.en === '') {\n throw new Error('提示词精修失败:LLM 未返回有效 JSON')\n }\n return kit\n}\n\n/** ✨ 从道藏/红线提炼「视觉世界观规则」:生图/生视频必须遵守的设定纠偏(如\"商品=人,禁止常规超市商品\")。 */\nexport async function extractVisualRules(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n): Promise<string[]> {\n const system = [\n '你是一位 AI 绘图的视觉规则设计师。本书的设定是\"反常识\"的,生图/生视频模型默认会画成现实世界的样子,你需要提炼 3-6 条「视觉规则」钉住本书的视觉世界观。',\n '规则要求:',\n '1. 每条必须可执行:明确\"画面里必须出现什么/禁止出现什么\"(如\"货架上的一切商品都是活人,禁止画成罐头/饮料/日用品\")。',\n '2. 覆盖本书最容易被模型画错的 2-4 个核心反常识点。',\n '3. 每条 40 字内,禁止泛泛而谈。',\n '输出必须是合法 JSON 数组:[\"规则1\", \"规则2\", ...],不要输出其他文字。',\n ].join('\\n')\n const bible = project.bible\n const user = [\n `书名:《${project.bookName}》`,\n `题材:${bible?.genre ?? ''}`,\n bible !== undefined && bible.worldRules.length > 0\n ? `世界规则:\\n${bible.worldRules.map(r => '- ' + r).join('\\n')}`\n : '',\n bible !== undefined && bible.redLines.length > 0\n ? `红线:\\n${bible.redLines.map(r => '- ' + r).join('\\n')}`\n : '',\n '只输出 JSON 数组。',\n ].filter(s => s !== '').join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 4000) })\n const raw = parseJsonArray<string>(text)\n return raw.map(r => typeof r === 'string' ? r.trim().slice(0, 80) : '').filter(r => r !== '').slice(0, 8)\n}\n\n\n/**\n * 开书想法 → AI 大纲:输入一句话想法,生成 2-3 个方向不同、可直接开书的完整大纲方案。\n * @param count 本次生成几个(默认 3,最多 3)\n * @param exclude 已暂留方案的剧情方向/卖点摘要(换批时避开,防止重复)\n */\nexport async function suggestOutlines(\n ctx: Context,\n config: NovelConfig,\n idea: string,\n count = 3,\n exclude: string[] = [],\n): Promise<OutlineCandidate[]> {\n const n = Math.max(1, Math.min(3, Math.floor(count)))\n const system = [\n '你是一位资深网文策划。作者只给了一句「想法」,你需要把它扩展成 2-3 个【方向差异明显】的完整小说大纲方案,供作者挑选。',\n '每个方案必须满足:',\n '1. bookName:书名(6 字以内,抓眼球、点题)。',\n '2. genre:题材(如 仙侠修真 / 都市异能 / 玄幻 / 悬疑)。',\n '3. sellingPoint:核心卖点一句话(金手指/爽点/差异化,40 字内)。',\n '4. outline:完整大纲文本(至少 800 字,可直接作为开书大纲),结构包含:书名与题材、金手指/核心设定、主角人设与动机、主线剧情走向(至少 5 个阶段)、关键配角与势力、卖点与爽点设计、预计分卷(3-5 卷)。',\n '方向差异要求:',\n '- 方案之间的金手指/剧情走向必须明显不同(如:苟道发育流 vs 随身老爷爷流 vs 群像争霸流),不能只是换书名。',\n '- 忠实于作者想法的核心要素,但允许在不同方向上进行合理演绎。',\n '- 不输出任何与已列「需避开的方向」雷同的方案。',\n '输出必须是合法 JSON 数组,只输出数组本身:',\n '[{\"id\": \"唯一id\", \"bookName\": \"...\", \"genre\": \"...\", \"sellingPoint\": \"...\", \"outline\": \"...\"}]',\n `本次只输出 ${n} 个方案。`,\n '重要:所有字符串值内部不得包含换行符(大纲内部分段请用「。\\n」或「;」自然断句),JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n const user = [\n `作者的想法:${idea}`,\n idea.trim().length < 40\n ? '作者的想法非常简短(可能只有一句)。请基于通用网文套路合理扩展补全:为每个方案自洽地设计金手指/核心设定、主角人设与动机、主线走向,使其成为完整可开书的大纲;不同方案的方向仍须明显差异。'\n : '',\n exclude.length > 0\n ? `需避开的已暂留方案方向(新方案不得与之雷同):\\n${exclude.map((e, i) => `${i + 1}. ${e}`).join('\\n')}`\n : '',\n `请生成 ${n} 个大纲方案。`,\n '只输出 JSON 数组。',\n ].join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.85, maxTokens: Math.max(config.maxTokens, 12000) })\n const parsed = parseJsonArray<Record<string, unknown>>(text)\n const candidates: OutlineCandidate[] = []\n for (const entry of parsed) {\n if (typeof entry !== 'object' || entry === null) continue\n const bookName = typeof entry.bookName === 'string' ? entry.bookName.trim().slice(0, 30) : ''\n const outline = typeof entry.outline === 'string' ? entry.outline.trim() : ''\n if (bookName === '' || outline.length < 300) continue\n candidates.push({\n id: typeof entry.id === 'string' && entry.id !== '' ? entry.id : `oc-${Date.now().toString(36)}-${candidates.length}`,\n bookName,\n genre: typeof entry.genre === 'string' ? entry.genre.trim().slice(0, 20) : '',\n sellingPoint: typeof entry.sellingPoint === 'string' ? entry.sellingPoint.trim().slice(0, 120) : '',\n outline,\n })\n }\n if (candidates.length === 0) {\n throw new Error('大纲方案生成失败:LLM 未返回有效 JSON(可重试)')\n }\n return candidates.slice(0, n)\n}\n\n/** 拆书分析:对已写章节做结构/人物/文风/卖点四维体检。\n * 两阶段管道(借鉴 AI-Novel-Writing-Assistant):\n * ① 源片段笔记:每章抽取结构化笔记(剧情/人物/设定/写法/卖点/短板信号)\n * ② 分节分析:按维度各跑一次 LLM,输出可读分析稿 + 结构化数据 + 证据链。\n * @param scope 'recent'(默认最近20章) | 'volume:N' | 'all'\n * @param preset 'quick'(总览/剧情/人物/文风) | 'standard'(+卖点)\n * @param budgetTokens token 预算上限(超过即截断章节取样)。\n */\nexport async function breakdownBook(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n scope = 'recent',\n preset: 'quick' | 'standard' = 'quick',\n budgetTokens = 50000,\n): Promise<BreakdownResponse> {\n // 1. 选章节范围。\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating' && c.summary !== undefined && c.summary !== '')\n let selected = written\n if (scope === 'recent') selected = written.slice(-20)\n else if (/^volume:\\d+$/.test(scope)) {\n const v = Number(scope.slice(7))\n selected = written.filter(c => c.volume === v)\n }\n if (selected.length === 0) throw new Error('没有可分析的已写章节(需要已生成并带摘要)')\n\n // 2. token 预算:估算每章正文+摘要成本,超预算则只取最近的章节。\n let budget = budgetTokens\n const chunks: Array<{ no: number; title: string; summary: string; body: string }> = []\n for (const c of selected.slice().reverse()) {\n const body = readChapterFile(outputDir, c) ?? ''\n // 粗估:每 4 字符 ≈ 1 token(中文),章节正文截 4000 字上限。\n const bodySlice = body.replace(/^#\\s+.*$/m, '').trim().slice(0, 4000)\n const est = Math.ceil((bodySlice.length + (c.summary?.length ?? 0)) / 4) + 400\n if (est > budget && chunks.length > 0) break\n chunks.unshift({ no: c.no, title: c.title, summary: c.summary ?? '', body: bodySlice })\n budget -= est\n }\n\n // 3. 阶段一:源片段笔记(每章一次 LLM,串行控制 token)。\n const notes: string[] = []\n let usedTokens = 0\n const noteSystem = [\n '你是中文网文拆书助手。把单章正文整理成结构化笔记,供后续章节级分析复用。',\n '只输出 JSON 对象:',\n '{\"summary\": \"1-2句\", \"plotPoints\": [\"...\"], \"characters\": [\"...\"], \"worldbuilding\": [\"...\"], \"styleTechniques\": [\"...\"], \"marketHighlights\": [\"...\"], \"weaknessSignals\": [\"...\"]}',\n '硬规则:只提取正文明确出现的信息;每数组最多 4 项;不要补写原文外的动机/意图;evidence 不在此阶段输出。',\n '重要:直接输出 JSON,不要输出其他文字;字符串内不含换行。',\n ].join('\\n')\n for (const ch of chunks) {\n const noteUser = [`第${ch.no}章《${ch.title}》`, '正文:', ch.body.slice(0, 3000)].join('\\n')\n try {\n const text = await complete(ctx, config, { system: noteSystem, user: noteUser, temperature: 0.2, maxTokens: Math.max(config.maxTokens, 3000) })\n const raw = parseJsonObject<Record<string, unknown>>(text)\n const pick = (k: string): string[] => Array.isArray(raw[k]) ? raw[k].filter((x): x is string => typeof x === 'string' && x.trim() !== '').map(x => x.trim().slice(0, 120)).slice(0, 4) : []\n notes.push(\n `【第${ch.no}章《${ch.title}》】\\n`\n + `摘要:${typeof raw.summary === 'string' ? raw.summary.slice(0, 200) : ''}\\n`\n + `剧情:${pick('plotPoints').join(';')}\\n`\n + `人物:${pick('characters').join(';')}\\n`\n + `设定:${pick('worldbuilding').join(';')}\\n`\n + `写法:${pick('styleTechniques').join(';')}\\n`\n + `卖点:${pick('marketHighlights').join(';')}\\n`\n + `短板信号:${pick('weaknessSignals').join(';') || '(无明显短板信号)'}`,\n )\n usedTokens += 800\n } catch {\n // 单章笔记失败不致命——跳过继续。\n }\n }\n\n // 4. 阶段二:分节分析。\n const sectionsConfig: Array<{ key: string; title: string; focus: string; system: string }> = [\n {\n key: 'overview',\n title: '拆书总览',\n focus: '一句话定位、题材标签、整体优势与短板',\n system: [\n '你是资深中文网文拆书分析师,负责《拆书总览》小节。',\n '基于给定章节笔记做低风险综合判断,输出 JSON:{\"markdown\": \"可直接展示的分析稿(简体中文,先给结论再说明体现在哪、为何成立)\", \"structured\": {\"oneLinePositioning\": \"一句话定位\", \"genreTags\": [\"题材标签\"], \"sellingPointTags\": [\"卖点标签\"], \"strengths\": [\"整体优势\"], \"weaknesses\": [\"整体短板\"]}}',\n '硬规则:只基于笔记归纳;推断用「更偏向/可能」等谨慎措辞;证据不足写「材料不足」;不虚构原文细节。',\n '重要:直接输出 JSON,字符串内不含换行。',\n ].join('\\n'),\n },\n {\n key: 'plot',\n title: '剧情结构',\n focus: '主线梗概、阶段推进、冲突升级、节奏风险',\n system: [\n '你是资深中文网文拆书分析师,负责《剧情结构》小节。',\n '基于给定章节笔记分析,输出 JSON:{\"markdown\": \"分析稿(简体中文,先结论后依据)\", \"structured\": {\"mainlineSummary\": \"主线梗概\", \"phaseProgressions\": [\"阶段推进\"], \"escalationDesigns\": [\"冲突升级\"], \"paceRisks\": [\"节奏风险\"], \"reusablePatterns\": [\"可复用套路\"]}}',\n '硬规则:只基于笔记归纳;推断谨慎措辞;不虚构。',\n '重要:直接输出 JSON,字符串内不含换行。',\n ].join('\\n'),\n },\n {\n key: 'character',\n title: '人物系统',\n focus: '主角定位、配角功能、关系网络、成长弧线、辨识度风险',\n system: [\n '你是资深中文网文拆书分析师,负责《人物系统》小节。',\n '基于给定章节笔记分析,输出 JSON:{\"markdown\": \"分析稿(简体中文,先结论后依据)\", \"structured\": {\"protagonistPositioning\": \"主角定位\", \"supportingFunctions\": [\"配角功能\"], \"relationshipNetwork\": [\"关系网络\"], \"growthArcs\": [\"成长弧线\"], \"clarityRisks\": [\"辨识度风险\"]}}',\n '硬规则:只基于笔记归纳;推断谨慎措辞;不虚构。',\n '重要:直接输出 JSON,字符串内不含换行。',\n ].join('\\n'),\n },\n {\n key: 'style',\n title: '文风与技法',\n focus: '叙事视角、语言风格、描写方式、节奏控制、钩子设计、可复用写法',\n system: [\n '你是资深中文网文拆书分析师,负责《文风与技法》小节。',\n '基于给定章节笔记分析,输出 JSON:{\"markdown\": \"分析稿(简体中文,先结论后依据)\", \"structured\": {\"narrativePov\": \"叙事视角\", \"languageStyle\": \"语言风格\", \"dialoguePatterns\": [\"对话特征\"], \"rhythmControl\": [\"节奏控制\"], \"hookDesigns\": [\"钩子设计\"], \"reusableTechniques\": [\"可复用写法\"]}}',\n '硬规则:只基于笔记归纳;推断谨慎措辞;不虚构。',\n '重要:直接输出 JSON,字符串内不含换行。',\n ].join('\\n'),\n },\n ]\n if (preset === 'standard') {\n sectionsConfig.push({\n key: 'market',\n title: '商业化卖点',\n focus: '读者爽点、点击驱动、人物/题材卖点、商业化风险',\n system: [\n '你是资深中文网文拆书分析师,负责《商业化卖点》小节。',\n '基于给定章节笔记分析,输出 JSON:{\"markdown\": \"分析稿(简体中文,先结论后依据)\", \"structured\": {\"hookPoints\": [\"读者爽点\"], \"clickDrivers\": [\"点击驱动\"], \"characterSellingPoints\": [\"人物卖点\"], \"genreSellingPoints\": [\"题材卖点\"], \"commercialRisks\": [\"商业化风险\"]}}',\n '硬规则:只基于笔记归纳;推断谨慎措辞;不虚构。',\n '重要:直接输出 JSON,字符串内不含换行。',\n ].join('\\n'),\n })\n }\n\n const notesText = notes.join('\\n\\n')\n const sections: BreakdownResponse['sections'] = []\n const evidence: BreakdownResponse['evidence'] = []\n for (const sec of sectionsConfig) {\n try {\n const text = await complete(ctx, config, {\n system: sec.system,\n user: `分析范围:${selected.length} 章(${scope === 'all' ? '全书' : scope === 'recent' ? '最近 20 章' : '指定卷'})。\\n\\n章节笔记:\\n${notesText}`,\n temperature: 0.3,\n maxTokens: Math.max(config.maxTokens, 6000),\n })\n const raw = parseJsonObject<{ markdown?: unknown; structured?: unknown }>(text)\n sections.push({\n key: sec.key,\n title: sec.title,\n markdown: typeof raw.markdown === 'string' ? raw.markdown.trim() : '(生成失败)',\n structured: typeof raw.structured === 'object' && raw.structured !== null ? raw.structured as Record<string, unknown> : {},\n })\n usedTokens += 2000\n } catch {\n sections.push({ key: sec.key, title: sec.title, markdown: '(本节生成失败,可重试)', structured: {} })\n }\n }\n\n return {\n sections,\n evidence,\n chaptersScanned: chunks.length,\n usedTokens,\n }\n}\n\nexport async function generateRoleReferenceImage(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n name: string,\n style = '',\n): Promise<string> {\n const role = project.roles?.find(r => r.name === name)\n if (role === undefined) throw new Error(`角色 ${name} 不存在`)\n if (role.imagePrompt === undefined) throw new Error(`角色 ${name} 还没有形象锚点,请先生成锚点`)\n if (config.imageApiEnabled !== true) throw new Error('豆包生图未启用,请在设置中开启')\n const apiKey = config.imageApiKey\n const model = config.imageApiModel\n if (apiKey === undefined || apiKey === '' || model === undefined || model === '') {\n throw new Error('请先在设置中配置豆包 API Key 和生图模型')\n }\n const stylePrompt = getComicStylePrompt(style)\n const prompt = [\n role.imagePrompt.zh,\n role.imagePrompt.en,\n role.imagePrompt.tags.join(', '),\n stylePrompt,\n 'character reference sheet, front view, clean background, consistent design',\n ].filter(Boolean).join(', ')\n\n const res = await fetch('https://ark.cn-beijing.volces.com/api/v3/images/generations', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model,\n prompt,\n response_format: 'url',\n size: '2K',\n stream: false,\n watermark: false,\n }),\n })\n if (!res.ok) {\n const text = await res.text()\n throw new Error(`豆包生图失败(${res.status}):${text}`)\n }\n const json = (await res.json()) as { data?: Array<{ url?: string }> }\n const url = json.data?.[0]?.url\n if (url === undefined || url === '') throw new Error('豆包生图未返回图片 URL')\n\n const imgRes = await fetch(url)\n if (!imgRes.ok) throw new Error('下载豆包图片失败')\n const buf = Buffer.from(await imgRes.arrayBuffer())\n const contentType = imgRes.headers.get('content-type') || 'image/jpeg'\n const dataUrl = `data:${contentType};base64,${buf.toString('base64')}`\n role.imageUrl = dataUrl\n return dataUrl\n}\n\n/** 🩺 剧情健康检查:基于已写章节数/各线状态/编年录,判断是否需要新线及添加时机。 */\nexport async function analyzePlotlineHealth(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n): Promise<PlotlineHealthReport> {\n const system = [\n '你是一位网文剧情架构师。请对本书的「剧情线体系」做健康检查,判断当前是否需要新增剧情线、应在多少章后添加。',\n '评估维度:各线最近推进到第几章(已写章节与关联章节的差值越大越危险)、各线状态、已写章节总数、卷计划当前进度、编年录近期事实。',\n '输出规则:',\n '1. verdict:一句话结论——\"需要新增线\" / \"暂不需要\" / \"再写 N 章后需要\"(N 给出具体章数)。',\n '2. timing:说明建议添加的时机(如:第 25 章前引入新支线,因为主线预计第 22 章告一段落)。',\n '3. reasons:3-5 条依据(引用具体数据:哪条线多少章没推进、已写章节数、卷进度等)。',\n '4. lines:对每条线给健康度——ok(近期推进过)/ warning(超过 5 章未推进)/ stale(超过 10 章未推进或悬置过久)。',\n '输出必须是合法 JSON 对象:{\"verdict\": \"...\", \"timing\": \"...\", \"reasons\": [\"...\"], \"lines\": [{\"name\": \"线名\", \"health\": \"ok|warning|stale\", \"note\": \"一句说明\"}]}',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating')\n const lines = (project.plotlines ?? []).filter(l => l.status === 'active' || l.status === 'paused')\n const user = [\n `书名:《${project.bookName}》`,\n `已写章节数:${written.length}(最新章号 ${written.length > 0 ? written[written.length - 1]!.no : 0})`,\n project.volumes !== undefined && project.volumes.length > 0\n ? `卷计划:\\n${project.volumes.map(v => `第${v.no}卷《${v.title}》(${v.chapterStart}-${v.chapterEnd}):${v.summary.slice(0, 60)}`).join('\\n')}`\n : '',\n `剧情线(${lines.length} 条):\\n${lines.length > 0\n ? lines.map(l => `- [${l.kind}] ${l.name}|目标:${l.goal}|进度:${l.progress !== '' ? l.progress : '未推进'}|最近关联章节:${l.chapters.length > 0 ? '第' + Math.max(...l.chapters) + '章' : '无'}`).join('\\n')\n : '(暂无剧情线)'}`,\n (project.facts ?? []).length > 0\n ? `编年录近期事实(最近 10 条):\\n${(project.facts ?? []).slice(-10).map(f => `[第${f.chapterNo}章] ${f.text.slice(0, 80)}`).join('\\n')}`\n : '',\n '只输出 JSON 对象。',\n ].join('\\n\\n')\n const raw = parseJsonObject<{\n verdict?: unknown\n timing?: unknown\n reasons?: unknown\n lines?: unknown\n }>(await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 3000) }))\n const strArr = (v: unknown): string[] => Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string' && x.trim() !== '') : []\n const lineArr = Array.isArray(raw.lines)\n ? raw.lines\n .filter((v): v is Record<string, unknown> => typeof v === 'object' && v !== null)\n .map(entry => ({\n name: typeof entry.name === 'string' ? entry.name.slice(0, 40) : '',\n health: (['ok', 'warning', 'stale'] as const).includes(entry.health as never) ? entry.health as 'ok' | 'warning' | 'stale' : 'ok',\n note: typeof entry.note === 'string' ? entry.note.slice(0, 150) : '',\n }))\n .filter(x => x.name !== '')\n : []\n return {\n verdict: typeof raw.verdict === 'string' ? raw.verdict.slice(0, 100) : '',\n timing: typeof raw.timing === 'string' ? raw.timing.slice(0, 200) : '',\n reasons: strArr(raw.reasons).map(r => r.slice(0, 200)),\n lines: lineArr,\n }\n}\n\n/** ✨ AI 剧情方案:基于健康检查结果设计下一阶段方向与建议新线。 */\nexport async function designPlotlinePlan(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n health?: PlotlineHealthReport,\n): Promise<PlotlinePlan> {\n const system = [\n '你是一位网文剧情架构师。请为本书设计「下一阶段的剧情方案」:给出未来 5-10 章的剧情方向,并建议 2-3 条值得新增的剧情线。',\n '要求:方向必须结合本书大纲/卷计划/现有线/编年录;新线要能落地(和当前主角处境、已有伏笔、下一阶段舞台相关),不得重复已有线。',\n '输出必须是合法 JSON 对象:{\"direction\": \"下一阶段方向 60-120 字\", \"suggestions\": [{\"name\": \"线名\", \"kind\": \"main|branch|character|mystery\", \"goal\": \"目标\", \"progress\": \"初始进度(可空)\"}]}',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating')\n const user = [\n `书名:《${project.bookName}》`,\n health !== undefined\n ? `健康检查结论:\\n判定:${health.verdict}\\n时机:${health.timing}\\n依据:${health.reasons.join(';')}`\n : '',\n `大纲(节选前 3000 字):\\n${project.outline.slice(0, 3000)}`,\n project.volumes !== undefined && project.volumes.length > 0\n ? `卷计划:\\n${project.volumes.map(v => `第${v.no}卷《${v.title}》:${v.summary.slice(0, 60)}`).join('\\n')}`\n : '',\n `现有剧情线:\\n${(project.plotlines ?? []).map(l => `- [${l.kind}${l.status === 'resolved' ? '·已完结' : ''}] ${l.name}:${l.goal}`).join('\\n') || '(无)'}`,\n written.length > 0\n ? `最近写的章节:\\n${written.slice(-5).map(c => `第${c.no}章《${c.title}》`).join('、')}`\n : '',\n '只输出 JSON 对象。',\n ].join('\\n\\n')\n const raw = parseJsonObject<{ direction?: unknown; suggestions?: unknown }>(\n await complete(ctx, config, { system, user, temperature: 0.6, maxTokens: Math.max(config.maxTokens, 3000) }),\n )\n const suggestions: Plotline[] = []\n const kinds = new Set(['main', 'branch', 'character', 'mystery'])\n if (Array.isArray(raw.suggestions)) {\n for (const entry of raw.suggestions) {\n if (typeof entry !== 'object' || entry === null) continue\n const e = entry as Record<string, unknown>\n const name = typeof e.name === 'string' ? e.name.trim().slice(0, 40) : ''\n if (name === '') continue\n suggestions.push({\n id: '',\n name,\n kind: kinds.has(e.kind as string) ? e.kind as Plotline['kind'] : 'branch',\n goal: typeof e.goal === 'string' ? e.goal.trim().slice(0, 300) : '',\n progress: typeof e.progress === 'string' ? e.progress.trim().slice(0, 300) : '',\n status: 'active',\n chapters: [],\n createdAt: new Date().toISOString(),\n })\n }\n }\n return {\n direction: typeof raw.direction === 'string' ? raw.direction.slice(0, 300) : '',\n suggestions,\n }\n}\n\n/** Build the rewrite system prompt (fix review issues / instructions). */\nfunction rewriteSystemPrompt(project: ProjectState): string {\n const base = writeSystemPrompt(project)\n return base + '\\n\\n额外要求:你正在【修订】一章已写好的正文。保留原文中好的部分,只修改需要修改的地方,输出完整的新正文(不要只输出修改片段),字数与原文相当。'\n}\n\n/**\n * Stream a chapter rewrite. With `target` (a passage of the body), only that\n * passage's paragraph is rewritten and spliced back — everything else stays\n * untouched (local revision). Without `target`, the whole chapter is\n * rewritten. Yields delta text; persists when done.\n */\nexport async function* rewriteChapterStream(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n instructions: string,\n target?: string,\n): AsyncGenerator<{ frame: 'start' } | { frame: 'delta'; text: string } | { frame: 'drafted'; chars: number; draft: string }, void, unknown> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) throw new Error(`章节 ${chapterNo} 不在计划中`)\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) throw new Error(`章节 ${chapterNo} 的正文文件不存在`)\n\n const reviewBlock = chapter.review !== undefined\n ? '审稿意见:\\n' + chapter.review.issues.map(i => `[${i.severity}] ${i.item} → ${i.suggestion}`).join('\\n')\n : ''\n\n // Local revision: find the paragraph containing `target` and only rewrite it.\n const bodyText = body.replace(/^#\\s+.*$/m, '').trim()\n let localTarget: { paragraph: string; before: string; after: string } | undefined\n if (target !== undefined && target.trim() !== '') {\n const wanted = target.trim()\n // Normalize whitespace so multi-line / quoted snippets still match:\n // the assistant often copies a passage with line breaks and quotes.\n const normalize = (value: string): string => value.replace(/\\s+/g, ' ').replace(/[“”\"'‘’]/g, '')\n const wantedFlat = normalize(wanted)\n // Split into paragraphs on blank lines (or double newlines).\n const paragraphs = bodyText.split(/\\n{2,}/)\n const idx = paragraphs.findIndex(p => normalize(p).includes(wantedFlat))\n if (idx === -1) {\n throw new Error(`在正文中未找到要修改的片段:「${wanted.slice(0, 40)}…」。请从正文中复制原文片段(无需整段,取片段即可)。`)\n }\n localTarget = {\n paragraph: paragraphs[idx]!,\n before: paragraphs.slice(0, idx).join('\\n\\n'),\n after: paragraphs.slice(idx + 1).join('\\n\\n'),\n }\n }\n\n const user = localTarget === undefined\n ? [\n `请修订第 ${chapter.no} 章《${chapter.title}》。`,\n reviewBlock,\n instructions !== '' ? `本次修订重点:${instructions}` : '',\n '==================== 原正文 ====================',\n bodyText,\n ].filter(line => line !== '').join('\\n')\n : [\n `请修订第 ${chapter.no} 章《${chapter.title}》中的一个自然段。`,\n instructions !== '' ? `修改要求:${instructions}` : '',\n '==================== 需要修改的原文段落 ====================',\n localTarget.paragraph,\n '',\n '要求:',\n '1. 只输出修改后的【这一个段落】的完整新文本,不要输出任何说明、标题或 Markdown 标记。',\n '2. 保留该段的情节走向与角色口吻,只按修改要求调整。',\n '3. 段落长度与原文相当。',\n ].filter(line => line !== '').join('\\n')\n\n const system = localTarget === undefined\n ? rewriteSystemPrompt(project)\n : '你是一位中文网文润色师。你会收到一章中的一个段落,请按修改要求重写该段。只输出新段落文本。'\n\n const messages: Message[] = [createUserMessage({\n content: [{ type: 'text', text: user }],\n source: { kind: 'plugin', plugin: 'dsh-novel-forge' },\n })]\n const request: GenerateOptions = {\n provider: config.provider,\n model: config.model,\n messages,\n system,\n // Rewriting outputs a full chapter: budget generously and skip\n // reasoning (a transform task) so the whole budget goes to the body.\n maxTokens: Math.max(config.maxTokens, 20000),\n temperature: 0.7,\n reasoningEffort: ReasoningEffortId('off'),\n }\n\n yield { frame: 'start' }\n const assembler = new BlockAssembler()\n let streamError: Error | undefined\n for await (const chunk of ctx.llm.stream(request)) {\n assembler.push(chunk)\n if (chunk.type === 'text-delta') yield { frame: 'delta', text: chunk.text }\n }\n const finish = assembler.finish\n if (finish.kind === 'error' || finish.kind === 'aborted') {\n streamError = new Error(`修订失败(${finish.kind}): ${finish.failure.message}`)\n } else if (finish.kind === 'max-tokens') {\n streamError = new Error('修订输出达到 maxTokens 上限,请增大配置后重试')\n }\n const rewritten = assembler\n .blocks()\n .filter((block): block is Extract<StreamChunk, { type: 'block-end' }>['block'] & { type: 'text' } => block.type === 'text')\n .map(block => block.text)\n .join('\\n')\n .trim()\n if (streamError !== undefined) throw streamError\n if (rewritten.length < 20) throw new Error('修订结果过短,可能失败,请重试')\n\n // Splice: local -> replace the paragraph; whole -> replace the body.\n let newBody: string\n if (localTarget !== undefined) {\n newBody = [localTarget.before, rewritten, localTarget.after].filter(part => part !== '').join('\\n\\n')\n } else {\n newBody = rewritten\n }\n if (newBody.length < 100) throw new Error('修订结果过短,可能失败,请重试')\n\n // Draft mode: do NOT overwrite the file yet. Store the new body as a\n // pending draft; the user reviews the diff and decides to apply or\n // discard. File overwrite + status change happen on draft/apply.\n chapter.pendingDraft = newBody\n chapter.error = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n yield { frame: 'drafted', chars: newBody.length, draft: newBody }\n}\n\n/** The de-AI-ify polish system prompt (with project writing assets injected). */\nfunction polishSystemPrompt(project: ProjectState): string {\n const assetsBlock = renderAllAssets(project.assets)\n return [\n '你是一位中文网文润色师。你会收到一章正文,请做「去 AI 味」润色:',\n '1. 删除/替换 AI 高频套话与模式词:如\"不禁\"\"仿佛\"\"一时间\"\"不由得\"\"顿时\"\"然而\"\"缓缓\"\"轻轻\"\"微微\"\"默默\"\"似乎\"\"终于\"等滥用。',\n '2. 把书面翻译腔改成口语化的中文网文语感。',\n '3. 拆分过长的排比句与堆砌的修饰语。',\n '4. 保留全部情节、人物、对话内容不变,只改表达。',\n '5. 输出完整的新正文,不要输出任何说明文字或 Markdown 标记。',\n '6. 必须遵守下方「反 AI 规则」与「写法资产」的表达边界;写法资产要求保留的风格特征(句式、台词、节奏)不得在润色中丢失。',\n assetsBlock !== '' ? assetsBlock : '',\n ].join('\\n')\n}\n\n/** Stream a chapter polish (de-AI-ify). Draft-mode: the polished body lands\n * in `chapter.pendingDraft` and is only applied on draft/apply. */\nexport async function* polishChapterStream(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): AsyncGenerator<{ frame: 'start' } | { frame: 'delta'; text: string } | { frame: 'drafted'; chars: number; draft: string }, void, unknown> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) throw new Error(`章节 ${chapterNo} 不在计划中`)\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) throw new Error(`章节 ${chapterNo} 的正文文件不存在`)\n const messages: Message[] = [createUserMessage({\n content: [{ type: 'text', text: body.replace(/^#\\s+.*$/m, '').trim() }],\n source: { kind: 'plugin', plugin: 'dsh-novel-forge' },\n })]\n const request: GenerateOptions = {\n provider: config.provider,\n model: config.model,\n messages,\n system: polishSystemPrompt(project),\n // Polish rewrites the whole chapter: generous budget, no reasoning\n // (transform task — the entire budget should go to the body).\n maxTokens: Math.max(config.maxTokens, 20000),\n temperature: 0.5,\n reasoningEffort: ReasoningEffortId('off'),\n }\n yield { frame: 'start' }\n const assembler = new BlockAssembler()\n let streamError: Error | undefined\n for await (const chunk of ctx.llm.stream(request)) {\n assembler.push(chunk)\n if (chunk.type === 'text-delta') yield { frame: 'delta', text: chunk.text }\n }\n const finish = assembler.finish\n if (finish.kind === 'error' || finish.kind === 'aborted') {\n streamError = new Error(`润色失败(${finish.kind}): ${finish.failure.message}`)\n } else if (finish.kind === 'max-tokens') {\n streamError = new Error('润色输出达到 maxTokens 上限')\n }\n const newBody = assembler\n .blocks()\n .filter((block): block is Extract<StreamChunk, { type: 'block-end' }>['block'] & { type: 'text' } => block.type === 'text')\n .map(block => block.text)\n .join('\\n')\n .trim()\n if (streamError !== undefined) throw streamError\n if (newBody.length < 100) throw new Error('润色结果过短,可能失败,请重试')\n\n // Draft mode: keep the original file untouched until the user decides.\n chapter.pendingDraft = newBody\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n yield { frame: 'drafted', chars: newBody.length, draft: newBody }\n}\n\n/** Generate one chapter (streaming). Yields progress frames; persists when done. */\nexport async function* generateChapterStream(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): AsyncGenerator<{ frame: 'start' } | { frame: 'delta'; text: string } | { frame: 'done'; file: string; chars: number }, void, unknown> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) throw new Error(`章节 ${chapterNo} 不在计划中`)\n // Note: the route layer owns the 'generating' status + concurrency guard;\n // this function must not refuse when status is 'generating' (the route sets\n // it before calling us).\n\n // Continuity: previous chapter's ending + its summary (narrative memory).\n let continuity = ''\n const prev = project.chapters.find(c => c.no === chapterNo - 1)\n if (prev?.file !== undefined) {\n const prevPath = join(outputDir, prev.file)\n if (existsSync(prevPath)) {\n const text = readFileSync(prevPath, 'utf8')\n continuity = text.slice(-900)\n }\n }\n const prevSummary = prev?.summary\n // 事实注入:最近 20 条(近因记忆)+ 按本章剧情要点检索的「相关旧事实」。\n // 长篇后旧设定可能被挤出近期窗口,故检索覆盖全部事实库:trigram 重合度 +\n // 角色名命中加权 + 近因加权,取 top 15,与近期事实去重,保证关键状态不写飞。\n const allFacts = project.facts ?? []\n const recentFacts = allFacts.slice(-20).map(f => f.text)\n const recentSet = new Set(recentFacts)\n const beatsText = chapter.beats\n const roleNames = (project.roles ?? [])\n .map(r => r.name)\n .filter((n): n is string => typeof n === 'string' && n !== '')\n const trigrams = (s: string): Set<string> => {\n const out = new Set<string>()\n for (let i = 0; i + 3 <= s.length; i++) {\n const tri = s.slice(i, i + 3)\n if (tri.trim() !== '') out.add(tri)\n }\n return out\n }\n const beatsTri = trigrams(beatsText)\n const beatRoles = roleNames.filter(n => beatsText.includes(n))\n const relatedFacts = allFacts\n .map((f, idx) => {\n const head = f.text.slice(0, 80)\n let score = 0\n for (const tri of trigrams(head)) if (beatsTri.has(tri)) score += 1\n if (beatRoles.length > 0) {\n for (const n of beatRoles) if (head.includes(n)) score += 8\n }\n // 近因加权:越新越优先(封顶 40 章)\n score += Math.min(idx, 40) / 10\n return { f, score }\n })\n .filter(x => x.score >= 3)\n .sort((a, b) => b.score - a.score)\n .slice(0, 15)\n .map(x => `[第${x.f.chapterNo}章] ${x.f.text}`)\n .filter(t => !recentSet.has(t.slice(t.indexOf(']') + 2)))\n\n // 暗线(伏笔)埋点注入:检索「目标章在当前章附近 + 尚未回收」的 planned 伏笔,\n // 把埋点细节要求注入本次生成,保证正文按规划埋线(否则伏笔列表与正文脱节)。\n const foreshadowHints = (project.foreshadows ?? [])\n .filter(f => f.status === 'planned' && f.targetChapter !== undefined && f.targetChapter > 0)\n .filter(f => Math.abs((f.targetChapter as number) - chapterNo) <= 12)\n .map(f => `- ${f.description.slice(0, 120)}${f.targetChapter !== undefined ? `(计划回收于第 ${f.targetChapter} 章)` : ''}`)\n\n const user = [\n `现在写第 ${chapter.no} 章,标题《${chapter.title}》。`,\n `本章剧情要点:${chapter.beats}`,\n '',\n foreshadowHints.length > 0\n ? `本章附近需顺势埋下以下暗线(自然带过,不喧宾夺主,1-2 句即可,但细节要可辨识、与描述吻合):\\n${foreshadowHints.join('\\n')}`\n : '',\n recentFacts.length > 0\n ? `本书已确立的事实(新写内容不得与之矛盾):\\n${recentFacts.join('\\n')}`\n : '',\n relatedFacts.length > 0\n ? `本章相关的既往事实(同样不得违背):\\n${relatedFacts.join('\\n')}`\n : '',\n prevSummary !== undefined && prevSummary !== ''\n ? `上一章摘要:${prevSummary}`\n : '',\n continuity !== ''\n ? `上一章结尾(用于衔接,不要复述):\\n${continuity}`\n : '这是第一章,注意开篇要有吸引力。',\n '',\n `请写 ${chapter.targetChars} 字左右的正文,只输出正文。`,\n ].filter(line => line !== '').join('\\n')\n\n const messages: Message[] = [createUserMessage({\n content: [{ type: 'text', text: user }],\n source: { kind: 'plugin', plugin: 'dsh-novel-forge' },\n })]\n const request: GenerateOptions = {\n provider: config.provider,\n model: config.model,\n messages,\n system: writeSystemPrompt(project),\n // Full-chapter output: budget generously (4000 chars ≈ 8-12k tokens,\n // plus the model's reasoning channel).\n maxTokens: Math.max(config.maxTokens, 20000),\n temperature: 0.85,\n }\n\n yield { frame: 'start' }\n\n const assembler = new BlockAssembler()\n let streamError: Error | undefined\n for await (const chunk of ctx.llm.stream(request)) {\n assembler.push(chunk)\n if (chunk.type === 'text-delta') {\n yield { frame: 'delta', text: chunk.text }\n }\n }\n const finish = assembler.finish\n if (finish.kind === 'error' || finish.kind === 'aborted') {\n streamError = new Error(`生成失败(${finish.kind}): ${finish.failure.message}`)\n } else if (finish.kind === 'max-tokens') {\n streamError = new Error('达到 maxTokens 上限,正文可能不完整,请增大 maxTokens 后重试')\n }\n const body = assembler\n .blocks()\n .filter((block): block is Extract<StreamChunk, { type: 'block-end' }>['block'] & { type: 'text' } => block.type === 'text')\n .map(block => block.text)\n .join('\\n')\n .trim()\n if (streamError !== undefined) throw streamError\n if (body.length < 100) throw new Error('生成内容过短,可能失败,请重试')\n\n // Write the chapter file.\n const fileName = chapterFileName(chapter)\n mkdirSync(outputDir, { recursive: true })\n writeFileSync(join(outputDir, fileName), `# 第${chapter.no}章 ${chapter.title}\\n\\n${body}\\n`, 'utf8')\n\n chapter.status = 'written'\n chapter.chars = body.length\n chapter.file = fileName\n chapter.error = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n\n yield { frame: 'done', file: fileName, chars: body.length }\n}\n\n/** Generate a chapter summary (narrative memory). */\nexport async function summarizeChapter(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): Promise<string> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) throw new Error(`章节 ${chapterNo} 不在计划中`)\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) throw new Error(`章节 ${chapterNo} 的正文文件不存在`)\n const system = [\n '你是一位网文编辑。请为下面一章写一段 120-200 字的摘要,供后续章节写作时保持连贯性。',\n '摘要必须包含:本章发生的关键事件、主角状态变化(境界/资源/伤势/心境)、新增的伏笔或线索、角色关系变化。',\n '用客观陈述句,不要评价,不要剧透式感叹。只输出摘要正文。',\n ].join('\\n')\n const user = body.replace(/^#\\s+.*$/m, '').trim()\n const summary = await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 4000) })\n chapter.summary = summary.slice(0, 500)\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return chapter.summary\n}\n\n/**\n * 摘要 + 事实抽取合并为一次 LLM 调用(省一次调用与一次正文输入,\n * 批量生成时整体开销约省 25%)。\n * @returns 摘要与新增事实条数(失败返回空,调用方 best-effort)。\n */\nexport async function summarizeAndExtractFacts(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): Promise<{ summary: string; factCount: number }> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) return { summary: '', factCount: 0 }\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) return { summary: '', factCount: 0 }\n const system = [\n '你是一位网文编辑。请为下面一章做两件事,输出合法 JSON 对象:',\n '{\"summary\": \"120-200字摘要,含关键事件/主角状态变化(境界资源伤势心境)/新增伏笔线索/角色关系变化,客观陈述不评价\", \"facts\": [\"已确立事实1\", \"…3-6条\"]}',\n 'facts 指:本章明确写出的、对后续有约束力的事实——人物当前状态、重要关系变化、地点与时间线、已落地或新增的伏笔线索、关键道具去向。',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n ].join('\\n')\n const user = body.replace(/^#\\s+.*$/m, '').trim()\n const text = await complete(ctx, config, { system, user, temperature: 0.2, maxTokens: Math.max(config.maxTokens, 5000) })\n const raw = parseJsonObject<{ summary?: unknown; facts?: unknown }>(text)\n const summary = typeof raw.summary === 'string' ? raw.summary.trim().slice(0, 500) : ''\n const factLines = Array.isArray(raw.facts)\n ? raw.facts\n .filter((v): v is string => typeof v === 'string' && v.trim().length > 8)\n .map(v => v.trim().slice(0, 140))\n : []\n if (summary !== '') chapter.summary = summary\n const list = project.facts ?? []\n for (const line of factLines.slice(0, 8)) list.push({ chapterNo, text: line })\n project.facts = list.slice(-300)\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return { summary, factCount: factLines.length }\n}\n\n/**\n * 伏笔落地标记:检查刚生成的章节正文是否埋下了 planned 伏笔(关键词匹配),\n * 命中则将该伏笔标记为 planted 并记录 plantedChapter——保证暗线管理页与正文同步。\n * 纯关键词粗匹配,宁缺毋滥:仅处理「描述含可辨识关键词」的伏笔,无把握则不标。\n */\nexport function markForeshadowPlanted(\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): number {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) return 0\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) return 0\n let marked = 0\n for (const f of project.foreshadows ?? []) {\n if (f.status !== 'planned') continue\n if (f.plantedChapter !== undefined) continue\n // 从描述中提取关键词:书名号/引号内容优先(专有名词),否则取 2-4 字名词片段。\n const quoted = f.description.match(/[「“『《]([^」”』》]{2,12})[」”』》]/g)\n const keywords = (quoted !== null ? quoted : [])\n .map(q => q.slice(1, -1))\n .filter(k => k.length >= 2)\n // 无引号关键词时,退而求其次:用「本章附近注入过该伏笔」的信号(targetChapter 接近当前章)。\n const nearTarget = f.targetChapter !== undefined && Math.abs(f.targetChapter - chapterNo) <= 12\n if (keywords.length === 0 && !nearTarget) continue\n const hit = keywords.length === 0\n ? false\n : keywords.some(k => body.includes(k))\n if (hit || (keywords.length === 0 && nearTarget)) {\n // 命中或(无关键词但恰好在目标章附近被注入埋点要求)→ 保守起见,只有明确命中才标记。\n if (hit) {\n f.status = 'planted'\n f.plantedChapter = chapterNo\n marked++\n }\n }\n }\n if (marked > 0) {\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n }\n return marked\n}\n\n/**\n * 抽取本章「已确立事实」追加到事实库/时间线(最多 300 条,最新优先)。\n * 事实注入后续章节生成提示词,保证人物状态/境界/资源/关系长期一致。\n * @returns 新增事实条数(失败返回 0,调用方 best-effort)。\n */\nexport async function extractFacts(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): Promise<number> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) return 0\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) return 0\n const system = [\n '你是一位网文编辑。请从本章正文中抽取「已确立事实」,供后续章节保持一致。',\n '事实指:人物当前状态(境界/修为/伤势/资源/心境)、重要关系变化、地点与时间线、已落地或新增的伏笔线索、关键道具去向。',\n '要求:',\n '1. 只抽取本章明确写出的、对后续有约束力的内容;纯心理活动与无关细节不要。',\n '2. 每行一条事实,用客观陈述句,不含主观评价。',\n '3. 输出 3-6 条,每行一条,不要编号、不要前缀、不要解释。',\n ].join('\\n')\n const user = body.replace(/^#\\s+.*$/m, '').trim()\n // v4-flash 推理模型:reasoning channel 也占 maxTokens,预算给足避免截断。\n const text = await complete(ctx, config, { system, user, temperature: 0.2, maxTokens: Math.max(config.maxTokens, 4000) })\n const lines = text.split('\\n')\n .map(line => line.replace(/^[-*\\d.\\s]+/, '').trim())\n .filter(line => line.length > 8)\n .slice(0, 8)\n if (lines.length === 0) return 0\n const facts = project.facts ?? []\n for (const line of lines) facts.push({ chapterNo, text: line.slice(0, 140) })\n project.facts = facts.slice(-300)\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return lines.length\n}\n\n// ------------------------------------------------------------ book audit\n\nconst AUDIT_BATCH_SIZE = 10\n\n/** 单批质检:设定 + 事实库 + 该批章节节选 → 矛盾清单。 */\nasync function auditBatch(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n batch: ChapterPlan[],\n): Promise<AuditIssue[]> {\n const system = [\n '你是一位严谨的网文连续性审校编辑。你会收到一本小说的设定圣经、事实库和一批章节正文节选。',\n '请找出这批章节中的一致性矛盾,例如:',\n '- 人物状态冲突:境界/修为/伤势/资源在同一章内或跨章前后矛盾。',\n '- 设定违背:正文与世界观规则、金手指规则、写作红线冲突。',\n '- 时间线错乱:事件顺序、时间跨度、地点移动不合逻辑。',\n '- 细节穿帮:人名/地名/物品/数字前后不一致。',\n '要求:',\n '1. 只报告有实质证据的矛盾,不要泛泛而谈写作质量问题。',\n '2. 每条必须定位到具体章节号。',\n '3. 输出必须是合法 JSON 数组,格式:[{\"chapterNo\": 章节号, \"severity\": \"high|medium|low\", \"item\": \"矛盾描述\", \"suggestion\": \"修改建议\"}]',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n ].join('\\n')\n const factsBlock = (project.facts ?? []).slice(-60).map(f => `[第${f.chapterNo}章] ${f.text}`).join('\\n')\n const chapterBlocks = batch.map(c => {\n const body = readChapterFile(outputDir, c)\n const excerpt = (body ?? '').replace(/^#\\s+.*$/m, '').trim().slice(0, 700)\n return `【第${c.no}章《${c.title}》】\\n${excerpt}`\n }).join('\\n\\n')\n const user = [\n '请对以下小说做一致性质检。',\n project.bible !== undefined\n ? '设定圣经:\\n' + [\n project.bible.worldRules.length > 0 ? `世界规则:\\n${project.bible.worldRules.map(r => `- ${r}`).join('\\n')}` : '',\n project.bible.redLines.length > 0 ? `写作红线:\\n${project.bible.redLines.map(r => `- ${r}`).join('\\n')}` : '',\n project.bible.characters.length > 0 ? `角色:\\n${project.bible.characters.map(ch => `- ${ch.name}(${ch.traits.join('、')})`).join('\\n')}` : '',\n ].filter(s => s !== '').join('\\n')\n : '',\n factsBlock !== '' ? `已确立事实库:\\n${factsBlock}` : '',\n `正文节选(每章前 700 字):\\n${chapterBlocks}`,\n '只输出 JSON 数组。',\n ].filter(s => s !== '').join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.2, maxTokens: Math.max(config.maxTokens, 12000) })\n const parsed = parseJsonArray<Record<string, unknown>>(text)\n const issues: AuditIssue[] = []\n for (const entry of parsed) {\n const item = typeof entry.item === 'string' ? entry.item : ''\n if (item === '') continue\n issues.push({\n chapterNo: Number(entry.chapterNo) || 0,\n severity: ['high', 'medium', 'low'].includes(entry.severity as string)\n ? entry.severity as AuditIssue['severity']\n : 'medium',\n item,\n suggestion: typeof entry.suggestion === 'string' ? entry.suggestion : '',\n })\n }\n return issues\n}\n\n/** 全书一致性质检:LLM 分批扫描已生成章节 + 设定 + 事实库,聚合矛盾清单。 */\nexport async function auditBook(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n onProgress?: (completedBatches: number, totalBatches: number) => void,\n): Promise<AuditIssue[]> {\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating')\n if (written.length === 0) {\n onProgress?.(0, 0)\n return []\n }\n // 分批:每批 AUDIT_BATCH_SIZE 章,避免超长后单次爆上下文。\n const totalBatches = Math.ceil(written.length / AUDIT_BATCH_SIZE)\n const all: AuditIssue[] = []\n onProgress?.(0, totalBatches)\n for (let i = 0; i < written.length; i += AUDIT_BATCH_SIZE) {\n const batch = written.slice(i, i + AUDIT_BATCH_SIZE)\n try {\n all.push(...await auditBatch(ctx, config, project, outputDir, batch))\n } catch { /* 单批失败不阻断其余批次 */ }\n onProgress?.(Math.min(Math.ceil((i + AUDIT_BATCH_SIZE) / AUDIT_BATCH_SIZE), totalBatches), totalBatches)\n }\n return all.slice(0, 50)\n}\n\n/** 小说简介:AI 生成或按已写开头补全(面向读者的作品门面)。 */\nexport async function generateBlurb(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n partial = '',\n): Promise<string> {\n const system = [\n '你是一位网文平台编辑,擅长写抓人的作品简介。',\n '要求:',\n '1. 120-250 字,突出核心卖点(金手指/题材/爽点/人设反差),用一两句抛出开局钩子。',\n '2. 不剧透结局与关键反转;语气贴合题材(热血/悬疑/轻松/虐心)。',\n '3. 中文,直接输出简介正文,不要 Markdown、不要引号包裹、不要「简介:」前缀。',\n ].join('\\n')\n const genreBlock = project.bible?.genre !== undefined ? `题材:${project.bible.genre}` : ''\n const volumeBlock = (project.volumes ?? []).slice(0, 3).map(v => v.title).join('、')\n const user = [\n `书名:《${project.bookName}》`,\n genreBlock,\n volumeBlock !== '' ? `卷结构:${volumeBlock}` : '',\n `已写章节数:${project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating').length}`,\n '大纲节选:\\n' + project.outline.slice(0, 2500),\n partial.trim() !== ''\n ? `已有开头草稿(请保留其内容与语气,续写补全为完整简介):\\n${partial.trim()}`\n : '请全量生成一份完整简介。',\n ].filter(s => s !== '').join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.7, maxTokens: Math.max(config.maxTokens, 4000) })\n const blurb = text.replace(/^[\"'「『]|[\"'」』]$/g, '').replace(/^简介[::]\\s*/, '').trim().slice(0, 600)\n return blurb\n}\n\n// ---------------------------------------------------------------- world\n\n/**\n * 组装全书上下文包(AI 助手 book_overview 工具)。\n * 分片策略:章节要点默认只给最近 30 章(避免超长后爆上下文);\n * scope='full' 全量;scope=数字 只给该卷章节。\n */\nexport function bookOverview(project: ProjectState, scope: 'recent' | 'full' | number = 'recent'): string {\n const s: string[] = []\n s.push(`书名:${project.bookName}`)\n s.push(`【大纲全文】\\n${project.outline}`)\n if (project.bible !== undefined) {\n const bible = project.bible\n s.push('【设定圣经】')\n if (bible.genre !== '') s.push(`题材基调:${bible.genre}`)\n if (bible.worldRules.length > 0) s.push('世界规则:\\n' + bible.worldRules.map(r => `- ${r}`).join('\\n'))\n if (bible.characters.length > 0) {\n s.push('角色卡:')\n for (const card of bible.characters) {\n const roleName = { protagonist: '主角', supporting: '配角', antagonist: '反派', other: '其他' }[card.role]\n s.push(`- ${card.name}(${roleName}):${card.traits.join('、')}${card.goals !== '' ? `;目标:${card.goals}` : ''}${card.relations !== '' ? `;关系:${card.relations}` : ''}`)\n }\n }\n if (bible.redLines.length > 0) s.push('写作红线:\\n' + bible.redLines.map(r => `- ${r}`).join('\\n'))\n if (bible.style.length > 0) s.push('风格要求:\\n' + bible.style.map(r => `- ${r}`).join('\\n'))\n }\n const worldBlock = renderWorld(project.world)\n if (worldBlock !== '') s.push(worldBlock)\n if (project.volumes !== undefined && project.volumes.length > 0) {\n s.push('【卷结构】')\n for (const v of project.volumes) {\n s.push(`第${v.no}卷《${v.title}》:${v.summary}(章节 ${v.chapterStart}-${v.chapterEnd})`)\n }\n }\n if (project.chapters.length > 0) {\n // 分片:默认最近 30 章;full 全量;数字 = 指定卷。\n const maxNo = project.chapters.reduce((m, c) => Math.max(m, c.no), 0)\n const shown = project.chapters.filter(c => {\n if (scope === 'full') return true\n if (typeof scope === 'number') return c.volume === scope\n return c.no > Math.max(0, maxNo - 30)\n })\n const label = scope === 'full' ? '全部章节(标题/状态/剧情要点/摘要)' : typeof scope === 'number' ? `第 ${scope} 卷章节(标题/状态/剧情要点/摘要)` : `最近 ${shown.length} 章(标题/状态/剧情要点/摘要)`\n s.push(`【${label}】`)\n const statusText: Record<string, string> = { pending: '待生成', generating: '生成中', written: '待审稿', reviewing: '审稿中', approved: '已通过', rejected: '待修订', error: '失败' }\n for (const c of shown) {\n s.push(`第${c.no}章《${c.title}》[${statusText[c.status] ?? c.status}]${c.chars !== undefined ? ` ${c.chars}字` : ''}\\n剧情要点:${c.beats}\\n摘要:${c.summary ?? '无'}`)\n }\n if (scope !== 'full' && project.chapters.length > shown.length) {\n s.push(`(还有 ${project.chapters.length - shown.length} 章未列出,可用 scope=volume:N 查看指定卷)`)\n }\n }\n if ((project.facts ?? []).length > 0) {\n s.push('【事实库(最近 40 条;更多用 facts_query 检索)】')\n for (const f of (project.facts ?? []).slice(-40)) {\n s.push(`- [第${f.chapterNo}章] ${f.text}`)\n }\n }\n if (project.foreshadows.length > 0) {\n s.push('【伏笔】')\n for (const f of project.foreshadows) {\n s.push(`- [${f.status}] ${f.description}${f.targetChapter !== undefined ? `(预计 ${f.targetChapter} 章回收)` : ''}`)\n }\n }\n if (project.blurb !== undefined && project.blurb !== '') s.push(`【小说简介】${project.blurb}`)\n return s.join('\\n\\n')\n}\n\n/** 一条影响分析结果(改动波及处)。 */\nexport interface ImpactItem {\n /** 位置:章节号 / 大纲 / 设定圣经 / 大世界 / 事实库 / 简介。 */\n location: string\n /** 原文片段(定位用)。 */\n quote: string\n /** 修改建议。 */\n suggestion: string\n /** must = 必须同步改;optional = 建议改;note = 备注(如保留旧称作古称)。 */\n kind: 'must' | 'optional' | 'note'\n}\n\n/**\n * 影响分析:LLM 扫描全书(大纲/设定/大世界/事实库/已写章节),\n * 定位一次改动波及的所有位置。助手在修改后主动调用,做连锁维护。\n */\nexport async function analyzeImpact(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n change: string,\n): Promise<ImpactItem[]> {\n const system = [\n '你是一位网文一致性审校。作者要做一处修改,请找出这次改动会波及的所有位置(设定、大纲、已写章节正文、事实库、简介中可能因此过时或矛盾的内容)。',\n '输出必须是合法 JSON 数组,格式:[{\"location\": \"位置(第N章/大纲/设定圣经-世界规则/大世界-境界/事实库/简介)\", \"quote\": \"原文片段(20-60字)\", \"suggestion\": \"修改建议\", \"kind\": \"must|optional|note\"}]',\n 'kind 含义:must=必须同步改否则矛盾;optional=建议改(影响观感);note=备注(如旧称保留为古称、或无需改但需知晓)。',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating')\n // 轻量 base:大纲节选 + 道藏要点 + 编年录最近 40 条(替代全量 bookOverview,\n // 定位主要靠各批章节节选原文)。\n const base = [\n `要做的修改:${change}`,\n '以下为全书设定与规则要点(章节为分批节选):',\n `大纲节选:\\n${project.outline.slice(0, 2000)}`,\n project.bible !== undefined\n ? `道藏:${project.bible.worldRules.length} 条世界规则 / ${project.bible.redLines.length} 条红线 / 人物 ${project.bible.characters.map(c => c.name).join('、')}`\n : '',\n (project.facts ?? []).length > 0\n ? `编年录最近 40 条:\\n${(project.facts ?? []).slice(-40).map(f => `[第${f.chapterNo}章] ${f.text}`).join('\\n')}`\n : '',\n ].filter(s => s !== '').join('\\n\\n')\n const items: ImpactItem[] = []\n // 分批扫描章节正文(每批 8 章),聚合影响清单,避免超长后爆上下文。\n const IMPACT_BATCH_SIZE = 8\n for (let i = 0; i < written.length; i += IMPACT_BATCH_SIZE) {\n const batch = written.slice(i, i + IMPACT_BATCH_SIZE)\n const chapterBlock = batch.map(c => {\n const body = readChapterFile(outputDir, c)\n const excerpt = (body ?? '').replace(/^#\\s+.*$/m, '').trim().slice(0, 500)\n return `【第${c.no}章《${c.title}》】\\n${excerpt}`\n }).join('\\n\\n')\n const user = `${base}\\n\\n本批章节(第 ${batch[0]!.no}-${batch[batch.length - 1]!.no} 章):\\n${chapterBlock}\\n\\n只输出 JSON 数组。`\n try {\n const text = await complete(ctx, config, { system, user, temperature: 0.2, maxTokens: Math.max(config.maxTokens, 12000) })\n for (const entry of parseJsonArray<Record<string, unknown>>(text)) {\n const quote = typeof entry.quote === 'string' ? entry.quote.trim() : ''\n if (quote === '') continue\n items.push({\n location: typeof entry.location === 'string' ? entry.location : '未定位',\n quote: quote.slice(0, 120),\n suggestion: typeof entry.suggestion === 'string' ? entry.suggestion : '',\n kind: entry.kind === 'must' || entry.kind === 'optional' || entry.kind === 'note' ? entry.kind : 'optional',\n })\n }\n } catch { /* 单批失败不阻断其余批次 */ }\n }\n return items.slice(0, 30)\n}\n\n/** 把大世界结构化数据渲染成提示词块(境界体系按顺序强约束)。 */\nexport function renderWorld(world: WorldState | undefined): string {\n if (world === undefined) return ''\n const sections: string[] = ['==================== 大世界(结构化设定,写作时严格遵守) ====================']\n if (world.realms.length > 0) {\n sections.push('境界体系(由低到高,不得随意跳级或自创境界):')\n world.realms.forEach((realm, i) => {\n sections.push(`${i + 1}. ${realm.name}${realm.description !== '' ? ` — ${realm.description}` : ''}`)\n })\n }\n if (world.regions.length > 0) {\n sections.push('地理区域:')\n for (const region of world.regions) {\n sections.push(`- ${region.name}${region.description !== '' ? `:${region.description}` : ''}${region.faction !== undefined && region.faction !== '' ? `(势力:${region.faction})` : ''}`)\n }\n }\n if (world.factions.length > 0) {\n sections.push('势力分布:')\n for (const faction of world.factions) {\n sections.push(`- ${faction.name}(${faction.kind})${faction.description !== '' ? `:${faction.description}` : ''}${faction.region !== undefined && faction.region !== '' ? `(驻地:${faction.region})` : ''}`)\n }\n }\n return sections.join('\\n')\n}\n\n/** AI 提炼大世界:从大纲 + 设定圣经生成结构化境界体系/区域/势力。 */\nexport async function extractWorld(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n): Promise<WorldState> {\n const system = [\n '你是一位网文世界观架构师。请根据小说大纲与设定圣经,提炼结构化「大世界」数据。',\n '输出必须是合法 JSON 对象:',\n '{\"realms\": [{\"name\": \"境界名\", \"description\": \"突破条件/寿命/标志等\"}], \"regions\": [{\"name\": \"区域名\", \"description\": \"描述\", \"faction\": \"关联势力名或空\"}], \"factions\": [{\"name\": \"势力名\", \"kind\": \"宗门/家族/王朝/组织等\", \"description\": \"描述\", \"region\": \"驻地区域或空\"}]}',\n '要求:',\n '1. realms 按由低到高顺序排列(修仙题材必须含完整境界链;无境界设定的题材可输出空数组)。',\n '2. 数量贴合大纲:realms 3-12 个,regions 2-10 个,factions 2-10 个。',\n '3. 内容严格来自大纲与设定圣经,不要凭空发明与大纲冲突的设定。',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n ].join('\\n')\n const bibleBlock = project.bible !== undefined\n ? [\n project.bible.genre !== '' ? `题材:${project.bible.genre}` : '',\n project.bible.worldRules.length > 0 ? `世界规则:\\n${project.bible.worldRules.map(r => `- ${r}`).join('\\n')}` : '',\n ].filter(s => s !== '').join('\\n')\n : ''\n const user = [\n '请为这部小说提炼大世界数据。',\n `书名:《${project.bookName}》`,\n bibleBlock !== '' ? bibleBlock : '',\n '大纲:\\n' + project.outline.slice(0, 5000),\n '只输出 JSON 对象。',\n ].filter(s => s !== '').join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 12000) })\n const raw = parseJsonObject<{ realms?: unknown; regions?: unknown; factions?: unknown }>(text)\n const str = (value: unknown): string => typeof value === 'string' ? value.trim() : ''\n const objArray = (value: unknown): Record<string, unknown>[] =>\n Array.isArray(value) ? value.filter((v): v is Record<string, unknown> => typeof v === 'object' && v !== null) : []\n const world: WorldState = {\n realms: objArray(raw.realms).map(entry => ({\n name: str(entry.name).slice(0, 20) || '未命名境界',\n description: str(entry.description).slice(0, 200),\n })).filter(r => r.name !== '未命名境界' || r.description !== ''),\n regions: objArray(raw.regions).map(entry => ({\n name: str(entry.name).slice(0, 30) || '未命名区域',\n description: str(entry.description).slice(0, 200),\n faction: str(entry.faction).slice(0, 30),\n })).filter(r => r.name !== '未命名区域' || r.description !== ''),\n factions: objArray(raw.factions).map(entry => ({\n name: str(entry.name).slice(0, 30) || '未命名势力',\n kind: str(entry.kind).slice(0, 20) || '组织',\n description: str(entry.description).slice(0, 200),\n region: str(entry.region).slice(0, 30),\n })).filter(f => f.name !== '未命名势力' || f.description !== ''),\n }\n return world\n}\n\n/**\n * 事实库回填:对历史已生成章节批量抽取事实(无事实记录的旧章节)。\n * @returns 回填的章节数。\n */\nexport async function backfillFacts(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n): Promise<number> {\n const have = new Set((project.facts ?? []).map(f => f.chapterNo))\n let filled = 0\n for (const chapter of project.chapters) {\n if (chapter.status === 'pending' || chapter.status === 'generating') continue\n if (chapter.file === undefined || have.has(chapter.no)) continue\n try {\n const n = await extractFacts(ctx, config, project, outputDir, chapter.no)\n if (n > 0) filled++\n } catch { /* best-effort per chapter */ }\n have.add(chapter.no)\n }\n return filled\n}\n\n/**\n * 角色卡刷新:出场统计由服务端从正文精确计算(角色名出现过的章节数、\n * 最近出现章节),LLM 只负责聚合「当前状态」一句话。\n */\nexport async function refreshCharacters(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n): Promise<RoleStatusCard[]> {\n // 名单优先用角色库(主表);无角色库时退回道藏角色卡。\n const rawRoster = (((project.roles ?? []).length > 0 ? project.roles : project.bible?.characters) ?? []) as Array<{ name: string; traits?: string[]; role?: string; roleLabel?: string }>\n const roster = rawRoster.map(r => ({\n name: r.name,\n traits: r.traits ?? [],\n role: r.roleLabel !== undefined ? r.roleLabel : (r.role ?? 'other'),\n }))\n const facts = project.facts ?? []\n if (roster.length === 0 && facts.length === 0) return []\n\n // 服务端精确出场统计:遍历已写章节正文,统计每个角色名出现过的章节。\n const stat = new Map<string, { chapters: Set<number>; last: number }>()\n const known = roster.map(card => card.name)\n for (const chapter of project.chapters) {\n if (chapter.status === 'pending' || chapter.status === 'generating') continue\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) continue\n for (const name of known) {\n if (body.includes(name)) {\n const entry = stat.get(name) ?? { chapters: new Set<number>(), last: 0 }\n entry.chapters.add(chapter.no)\n if (chapter.no > entry.last) entry.last = chapter.no\n stat.set(name, entry)\n }\n }\n }\n\n // LLM 只聚合状态:名单(含 traits)+ 事实库 → [{name, status}]\n let statuses = new Map<string, string>()\n if (facts.length > 0) {\n const system = [\n '你是一位网文角色档案管理员。请根据「角色名单」与「已确立事实库」,为每个角色输出「当前状态」一句话(境界/修为/伤势/资源/心境)。',\n '输出必须是合法 JSON 数组,格式:[{\"name\": \"角色名\", \"status\": \"当前状态一句话\"}]',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n ].join('\\n')\n const rosterBlock = roster.map(ch => `- ${ch.name}(${ch.traits.join('、')})`).join('\\n')\n const factsBlock = facts.map(f => `[第${f.chapterNo}章] ${f.text}`).join('\\n')\n const user = [\n `角色名单:\\n${rosterBlock}`,\n `已确立事实库(${facts.length} 条):\\n${factsBlock.slice(-6000)}`,\n '只输出 JSON 数组。',\n ].join('\\n\\n')\n try {\n const text = await complete(ctx, config, { system, user, temperature: 0.2, maxTokens: Math.max(config.maxTokens, 8000) })\n for (const entry of parseJsonArray<Record<string, unknown>>(text)) {\n const name = typeof entry.name === 'string' ? entry.name : ''\n if (name !== '' && typeof entry.status === 'string') statuses.set(name, entry.status)\n }\n } catch { /* status 聚合失败则只给出场统计 */ }\n }\n\n // 合并:出场统计(精确)+ 状态(LLM)+ 名单角色补全。\n const cards: RoleStatusCard[] = []\n const roleOf = (name: string): string => roster.find(c => c.name === name)?.role ?? 'other'\n for (const card of roster) {\n const entry = stat.get(card.name)\n cards.push({\n name: card.name,\n role: card.role,\n status: statuses.get(card.name) ?? '',\n lastChapter: entry?.last ?? 0,\n appearances: entry?.chapters.size ?? 0,\n })\n }\n // 名单外的角色(从事实库中识别到但不在设定圣经名单)仅当有出场统计时补充。\n for (const [name, entry] of stat) {\n if (!cards.some(c => c.name === name)) {\n cards.push({\n name,\n role: roleOf(name),\n status: statuses.get(name) ?? '',\n lastChapter: entry.last,\n appearances: entry.chapters.size,\n })\n }\n }\n return cards\n}\n\n// ------------------------------------------------------------- foreshadows\n\n/** System prompt for foreshadow suggestions. */\nfunction foreshadowSystemPrompt(): string {\n return [\n '你是一位网文伏笔设计师。你会收到大纲和已写的章节信息,请为小说建议 3-8 条值得埋设的伏笔。',\n '要求:',\n '1. 伏笔必须有明确的回收价值(推动主线、人物弧光、世界观揭秘)。',\n '2. 描述要具体,指出埋设章节与预计回收章节(可空缺)。',\n '3. 优先从大纲的暗线(如记忆代价、残片收集、身世谜团)中提炼。',\n '输出必须是合法 JSON 数组:',\n '[{\"description\": \"伏笔描述\", \"plantedChapter\": 章节号或null, \"targetChapter\": 章节号或null}]',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n ].join('\\n')\n}\n\n/** Suggest foreshadows from the outline + plan. */\nexport async function suggestForeshadows(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n): Promise<Foreshadow[]> {\n const user = [\n '请为下面这部小说设计伏笔。',\n `大纲:\\n${project.outline}`,\n `已规划章节数:${project.chapters.length}`,\n ].join('\\n')\n const text = await complete(ctx, config, { system: foreshadowSystemPrompt(), user, temperature: 0.5, maxTokens: Math.max(config.maxTokens, 12000) })\n const parsed = parseJsonArray<Record<string, unknown>>(text)\n const existing = new Set(project.foreshadows.map(f => f.description))\n const created: Foreshadow[] = []\n for (const entry of parsed) {\n if (typeof entry !== 'object' || entry === null) continue\n const description = typeof entry.description === 'string' ? entry.description.trim() : ''\n if (description === '' || existing.has(description)) continue\n existing.add(description)\n created.push({\n id: `fs-${Date.now().toString(36)}-${created.length}`,\n description: description.slice(0, 200),\n plantedChapter: typeof entry.plantedChapter === 'number' ? entry.plantedChapter : undefined,\n targetChapter: typeof entry.targetChapter === 'number' ? entry.targetChapter : undefined,\n status: 'planned',\n })\n }\n project.foreshadows.push(...created)\n project.updatedAt = new Date().toISOString()\n return created\n}\n\n// -------------------------------------------------------------- style asset\n\n/**\n * 写法引擎:从样本文本提取一份写法资产(叙事风格规则)。\n * @returns 提取出的风格规则(未持久化,由调用方存入 project.assets)。\n */\nexport async function extractStyleAsset(\n ctx: Context,\n config: NovelConfig,\n sampleText: string,\n): Promise<{ proseRules: string[]; dialogueRules: string[]; descriptionRules: string[]; boundaries: string[] }> {\n const user = `请分析下面这段样本文本,提炼其叙事风格规则:\\n\\n${sampleText}`\n const text = await complete(ctx, config, { system: styleEngineSystemPrompt(), user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 12000) })\n const raw = parseJsonObject<{ proseRules?: unknown; dialogueRules?: unknown; descriptionRules?: unknown; boundaries?: unknown }>(text)\n const strArray = (value: unknown): string[] =>\n Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string' && v.trim() !== '') : []\n const result = {\n proseRules: strArray(raw.proseRules),\n dialogueRules: strArray(raw.dialogueRules),\n descriptionRules: strArray(raw.descriptionRules),\n boundaries: strArray(raw.boundaries),\n }\n if (result.proseRules.length + result.dialogueRules.length + result.descriptionRules.length + result.boundaries.length === 0) {\n throw new Error('写法提取失败:模型没有返回有效规则')\n }\n return result\n}\n\n// ------------------------------------------------------------------ export\n\n/** Export the whole book as one txt/md file. */\nexport function exportBook(outputDir: string, project: ProjectState, format: 'txt' | 'md'): { file: string; chars: number; chapters: number } {\n const parts: string[] = []\n if (format === 'md') {\n parts.push(`# ${project.bookName}\\n`)\n } else {\n parts.push(project.bookName, '')\n }\n const done = project.chapters.filter(c => c.file !== undefined)\n for (const chapter of done) {\n const body = readChapterFile(outputDir, chapter) ?? ''\n if (format === 'md') {\n parts.push(`\\n## 第${chapter.no}章 ${chapter.title}\\n`, body.trim(), '')\n } else {\n parts.push('', `第${chapter.no}章 ${chapter.title}`, '', body.trim(), '')\n }\n }\n const content = parts.join('\\n')\n const ext = format === 'md' ? 'md' : 'txt'\n const file = `《${safeFileName(project.bookName)}》全本.${ext}`\n writeFileSync(join(outputDir, file), content, 'utf8')\n return { file, chars: content.length, chapters: done.length }\n}\n","/**\n * 书架(Bookshelf)— 多书管理:一本书记录一个独立输出目录。\n * 状态持久化到 ~/.dsh/dsh-novel-forge-bookshelf.json(跟随 dsh 配置惯例)。\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { randomBytes } from 'node:crypto'\nimport type { BookEntry, BookshelfSnapshot } from './protocol.ts'\nimport { loadProject } from './engine.ts'\n\n/** 书架配置文件路径。 */\nexport function bookshelfFile(): string {\n return join(homedir(), '.dsh', 'dsh-novel-forge-bookshelf.json')\n}\n\ninterface BookshelfStore {\n books: BookEntry[]\n activeBookId: string | null\n}\n\nfunction defaultStore(): BookshelfStore {\n return { books: [], activeBookId: null }\n}\n\n/** 读取书架(无则返回空)。 */\nexport function loadBookshelf(): BookshelfStore {\n const file = bookshelfFile()\n if (!existsSync(file)) return defaultStore()\n try {\n let raw = readFileSync(file, 'utf8')\n if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1)\n const parsed = JSON.parse(raw) as BookshelfStore\n if (!Array.isArray(parsed.books)) return defaultStore()\n return { books: parsed.books, activeBookId: parsed.activeBookId ?? null }\n } catch {\n return defaultStore()\n }\n}\n\n/** 持久化书架。 */\nfunction saveBookshelf(store: BookshelfStore): void {\n const file = bookshelfFile()\n mkdirSync(join(homedir(), '.dsh'), { recursive: true })\n writeFileSync(file, JSON.stringify(store, null, 2), 'utf8')\n}\n\n/** 当前激活的书。 */\nexport function activeBook(store: BookshelfStore): BookEntry | undefined {\n return store.books.find(b => b.id === store.activeBookId)\n}\n\n/** 书架快照(含每本书的进度摘要)。 */\nexport function bookshelfSnapshot(store: BookshelfStore): BookshelfSnapshot {\n return {\n books: store.books.map(book => {\n const project = loadProject(book.outputDir)\n const done = project === undefined ? 0 : project.chapters.filter(c => c.status === 'approved' || c.status === 'written' || c.status === 'rejected').length\n const hasCover = project?.coverPath !== undefined && project.coverPath !== '' && existsSync(join(book.outputDir, project.coverPath))\n return {\n ...book,\n done,\n total: project?.chapters.length ?? 0,\n hasProject: project !== undefined,\n hasCover,\n blurb: project?.blurb,\n }\n }),\n activeBookId: store.activeBookId,\n }\n}\n\n/** 新建一本书(自动成为当前书)。 */\nexport function createBook(bookName: string, outputDir: string): BookEntry {\n const store = loadBookshelf()\n const id = `book-${Date.now().toString(36)}-${randomBytes(3).toString('hex')}`\n const now = new Date().toISOString()\n const book: BookEntry = { id, bookName, outputDir, createdAt: now, updatedAt: now }\n store.books.push(book)\n store.activeBookId = id\n saveBookshelf(store)\n return book\n}\n\n/** 更新某本书的书名(开书向导导入大纲后书名以大纲首行为准)。 */\nexport function renameBook(id: string, bookName: string): boolean {\n const store = loadBookshelf()\n const book = store.books.find(b => b.id === id)\n if (book === undefined) return false\n book.bookName = bookName\n book.updatedAt = new Date().toISOString()\n saveBookshelf(store)\n return true\n}\n\n/**\n * 播种:书架为空时,把指定输出目录下已有的项目自动登记为第一本书。\n * 兼容升级场景 —— 旧版插件直接在输出目录写项目,从未登记书架。\n * @param outputDir - 候选输出目录(通常为 settings 的默认输出目录)。\n * @returns 是否发生了播种。\n */\nexport function seedBookshelfFromOutputDir(outputDir: string): boolean {\n const store = loadBookshelf()\n if (store.books.length > 0) return false\n if (!existsSync(outputDir)) return false\n // 有项目文件,或至少有章节文件,才视为\"已有的书\"。\n const hasProject = existsSync(join(outputDir, 'novel-project.json'))\n const hasChapters = existsSync(outputDir)\n if (!hasProject && !hasChapters) return false\n const project = loadProject(outputDir)\n const bookName = project?.bookName ?? outputDir.split(/[\\\\/]/).pop() ?? '未命名小说'\n createBook(bookName, outputDir)\n return true\n}\n\n/** 激活一本书。 */\nexport function activateBook(id: string): BookEntry | undefined {\n const store = loadBookshelf()\n const book = store.books.find(b => b.id === id)\n if (book === undefined) return undefined\n store.activeBookId = id\n book.updatedAt = new Date().toISOString()\n saveBookshelf(store)\n return book\n}\n\n/** 移除一本书。 */\nexport function removeBook(id: string): boolean {\n const store = loadBookshelf()\n const idx = store.books.findIndex(b => b.id === id)\n if (idx === -1) return false\n store.books.splice(idx, 1)\n if (store.activeBookId === id) {\n store.activeBookId = store.books[0]?.id ?? null\n }\n saveBookshelf(store)\n return true\n}\n\n/** 当前书输出目录(无书架则 undefined,回退 settings)。 */\nexport function activeBookOutputDir(): string | undefined {\n const book = activeBook(loadBookshelf())\n return book?.outputDir\n}\n\n/** 默认输出目录推断:小说目录/书名。 */\nexport function defaultOutputDirFor(bookName: string): string {\n const clean = bookName.replace(/[\\\\/:*?\"<>|]/g, '').trim().slice(0, 40) || '未命名小说'\n return join('D:\\\\ryan work\\\\harness\\\\novels', clean)\n}\n","/**\n * 生产单(Production Run):批量章节生产的标准执行器。\n * 职责:计划补足 → 逐章生成(完整质量门)→ 被拒分级处理(豁免/修订+验证/待人工)→ 断点续跑。\n * 与路由层解耦:只依赖 engine 导出函数与磁盘状态,自身不碰 HTTP。\n * 串行纪律:单例执行器 + working 锁;每章重新从磁盘加载,写前合并易变字段。\n */\nimport { existsSync, mkdirSync, readFileSync, copyFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { ChapterPlan, NovelConfig, ProjectState, ReviewReport, RunState } from './protocol.ts'\nimport {\n loadProject,\n saveProject,\n mergeVolatileFromDisk,\n planChapters,\n generateChapterStream,\n summarizeAndExtractFacts,\n markForeshadowPlanted,\n reviewChapter,\n reviewChapterText,\n authorReviewChapter,\n autoLinkPlotlines,\n readChapterFile,\n rewriteChapterStream,\n chapterFileName,\n} from './engine.ts'\nimport { loadBookshelf } from './bookshelf.ts'\n\n/** 生产单 checkpoint 文件名(放在书目录下)。 */\nfunction runStateFile(outputDir: string): string {\n return join(outputDir, 'run-state.json')\n}\n\nexport class ProductionRunner {\n private state: RunState | null = null\n private working = false\n private pauseRequested = false\n private stopRequested = false\n /** 生产单绑定目录(start 时快照;所有读写固定用它,防止运行中切书导致写错目录)。 */\n private bookDir: string | null = null\n\n constructor(private deps: { ctx: Context; getConfig: () => NovelConfig }) {}\n\n /** 当前生产单状态(内存优先;web 重启后从磁盘恢复)。 */\n status(): RunState | null {\n if (this.state !== null) return this.state\n // 重启恢复:先找当前激活书目录,再扫书架所有书目录(防切书后找不到)。\n const candidates: string[] = [this.deps.getConfig().outputDir]\n const bookshelf = loadBookshelf()\n for (const b of bookshelf.books) if (!candidates.includes(b.outputDir)) candidates.push(b.outputDir)\n for (const outputDir of candidates) {\n const file = runStateFile(outputDir)\n if (!existsSync(file)) continue\n try {\n const raw = readFileSync(file, 'utf8')\n const parsed = JSON.parse(raw) as RunState\n if (parsed?.runId === undefined) continue\n // 重启恢复:若之前 running,则视为可续跑(loop 未在跑)。\n if (parsed.status === 'running') parsed.status = 'paused'\n this.state = parsed\n this.bookDir = outputDir\n return this.state\n } catch { /* 该目录 run-state 损坏则跳过 */ }\n }\n return null\n }\n\n private persist(): void {\n if (this.state === null) return\n const outputDir = this.bookDir ?? this.deps.getConfig().outputDir\n mkdirSync(outputDir, { recursive: true })\n writeFileSync(runStateFile(outputDir), JSON.stringify(this.state, null, 2), 'utf8')\n }\n\n private log(text: string): void {\n if (this.state === null) return\n this.state.log.push({ at: new Date().toISOString(), text })\n if (this.state.log.length > 300) this.state.log = this.state.log.slice(-300)\n this.state.updatedAt = new Date().toISOString()\n }\n\n /** 启动/续跑生产单:startNo..endNo 区间,endNo 超出计划时先自动补计划。 */\n async start(startNo: number, endNo: number): Promise<RunState> {\n const config = this.deps.getConfig()\n if (this.working) throw new Error('生产单正在运行中,请先暂停或停止')\n let project = loadProject(config.outputDir)\n if (project === undefined) throw new Error('输出目录中没有项目')\n\n // 计划补足:目标区间超出已有计划 → 续写规划追加。\n if (endNo > project.chapters.length) {\n const need = endNo - project.chapters.length\n this.log(`计划不足,追加 ${need} 章计划…`)\n const chapters = await planChapters(this.deps.ctx, config, project, need, undefined, config.outputDir)\n mergeVolatileFromDisk(config.outputDir, project)\n project.chapters.push(...chapters)\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n this.log(`计划已追加,全书 ${project.chapters.length} 章`)\n }\n\n this.state = {\n runId: `run-${Date.now().toString(36)}`,\n startNo,\n endNo,\n status: 'running',\n currentNo: startNo,\n stats: { generated: 0, revised: 0, exempted: 0, regenerated: 0, error: 0 },\n pendingManual: [],\n log: [],\n startedAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n }\n this.pauseRequested = false\n this.stopRequested = false\n // 绑定生产单目录(快照):运行期间切书不影响本单的读写目标。\n this.bookDir = config.outputDir\n this.working = true\n this.persist()\n void this.loop()\n return this.state\n }\n\n pause(): void { this.pauseRequested = true }\n resume(): void {\n if (this.state === null || this.state.status !== 'paused') return\n this.state.status = 'running'\n this.working = true\n this.pauseRequested = false\n this.stopRequested = false\n this.persist()\n void this.loop()\n }\n stop(): void { this.stopRequested = true }\n\n /** 主循环:从 currentNo 扫描到 endNo,逐章处理;支持暂停/停止。 */\n private async loop(): Promise<void> {\n // 全部读写固定使用生产单绑定目录(bookDir),绝不跟随当前激活书。\n const config = this.deps.getConfig()\n const outputDir = this.bookDir ?? config.outputDir\n try {\n while (this.state !== null) {\n if (this.stopRequested) {\n this.stopRequested = false\n this.state.status = 'stopped'\n this.log('生产单已停止')\n this.persist()\n break\n }\n if (this.pauseRequested) {\n this.pauseRequested = false\n this.state.status = 'paused'\n this.log('生产单已暂停(随时可继续)')\n this.persist()\n break\n }\n const project = loadProject(outputDir)\n if (project === undefined) {\n this.state.status = 'error'\n this.state.error = '项目丢失'\n this.persist()\n break\n }\n // 找下一个需要处理的章(approved 快进)。\n let next: ChapterPlan | undefined\n for (let no = this.state.currentNo; no <= this.state.endNo; no++) {\n const ch = project.chapters.find(c => c.no === no)\n if (ch === undefined) continue\n if (ch.status === 'approved') { this.state.currentNo = no; continue }\n next = ch\n break\n }\n if (next === undefined) {\n this.state.status = 'done'\n this.log(`生产单完成:${this.state.startNo}-${this.state.endNo} 章处理完毕`)\n this.persist()\n break\n }\n this.state.currentNo = next.no\n await this.processChapter(project, next)\n this.persist()\n }\n } catch (error) {\n if (this.state !== null) {\n this.state.status = 'error'\n this.state.error = (error as Error).message\n this.log(`生产单异常:${(error as Error).message}`)\n this.persist()\n }\n } finally {\n this.working = false\n }\n }\n\n private async processChapter(project: ProjectState, chapter: ChapterPlan): Promise<void> {\n if (chapter.status === 'pending' || chapter.status === 'error' || chapter.status === 'written') {\n await this.produce(project, chapter)\n } else if (chapter.status === 'rejected') {\n await this.handleRejected(project, chapter)\n } else if (chapter.status === 'generating') {\n // 中断残留:复位重生成。\n chapter.status = 'pending'\n await this.produce(project, chapter)\n }\n }\n\n /** 完整质量门:生成 → 摘要+事实 → 伏笔标记 → 审稿 → 作者复盘。 */\n private async produce(project: ProjectState, chapter: ChapterPlan): Promise<void> {\n const { ctx, getConfig } = this.deps\n const config = getConfig()\n const outputDir = this.bookDir ?? config.outputDir\n const no = chapter.no\n const wasError = chapter.status === 'error'\n chapter.status = 'generating'\n chapter.error = undefined\n chapter.generatingAt = new Date().toISOString()\n mergeVolatileFromDisk(outputDir, project)\n saveProject(outputDir, project)\n this.log(wasError ? `第${no}章《${chapter.title}》重新生成…` : `第${no}章《${chapter.title}》生成…`)\n try {\n for await (const step of generateChapterStream(ctx, config, project, outputDir, no)) { /* drain */ }\n try { await summarizeAndExtractFacts(ctx, config, project, outputDir, no) } catch (e) { console.warn('[dsh-novel-forge] run summary/facts:', (e as Error).message) }\n try { markForeshadowPlanted(project, outputDir, no) } catch (e) { console.warn('[dsh-novel-forge] run foreshadow:', (e as Error).message) }\n if (config.autoReview ?? true) {\n const report = await reviewChapter(ctx, config, project, outputDir, no)\n if (this.state !== null) this.state.stats[wasError ? 'regenerated' : 'generated']++\n this.log(`第${no}章 审稿 ${report.score}分 ${report.passed ? '✅ 通过' : '⚠️ 被拒'}`)\n } else {\n chapter.status = 'approved'\n mergeVolatileFromDisk(outputDir, project)\n saveProject(outputDir, project)\n }\n if (config.autoAuthorReview ?? true) {\n try {\n const body = readChapterFile(outputDir, chapter)\n if (body !== undefined) {\n let prevTail = ''\n if (no > 1) {\n const prev = project.chapters.find(c => c.no === no - 1)\n if (prev !== undefined) prevTail = (readChapterFile(outputDir, prev) ?? '').replace(/^#.*$/m, '').trim().slice(-600)\n }\n const review = await authorReviewChapter(ctx, config, project, no, body, prevTail)\n chapter.authorReview = review\n if (review.advancedLines !== undefined) autoLinkPlotlines(project, no, review.advancedLines)\n mergeVolatileFromDisk(outputDir, project)\n saveProject(outputDir, project)\n }\n } catch (e) { console.warn('[dsh-novel-forge] run author review:', (e as Error).message) }\n }\n } catch (error) {\n chapter.status = 'error'\n chapter.error = (error as Error).message\n mergeVolatileFromDisk(outputDir, project)\n saveProject(outputDir, project)\n if (this.state !== null) this.state.stats.error++\n this.log(`第${no}章 失败:${(error as Error).message}`)\n }\n }\n\n /** 被拒分级处理:无 high 豁免;有 high 按意见修订(最多 2 轮)+ 验证模式;仍不过 → 待人工。 */\n private async handleRejected(project: ProjectState, chapter: ChapterPlan): Promise<void> {\n const { ctx, getConfig } = this.deps\n const config = getConfig()\n const outputDir = this.bookDir ?? config.outputDir\n const no = chapter.no\n const report = chapter.review\n const highs = (report?.issues ?? []).filter(i => i.severity === 'high')\n if (highs.length === 0) {\n chapter.status = 'approved'\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n if (this.state !== null) this.state.stats.exempted++\n this.log(`第${no}章 豁免通过(无 high)`)\n return\n }\n this.log(`第${no}章 修订(${highs.length} 个 high)…`)\n for (let round = 1; round <= 2; round++) {\n const instr = '按审稿意见修订(优先处理):\\n' + highs.map(h => `[${h.severity}] ${h.item}${h.suggestion !== '' ? `\\n建议:${h.suggestion}` : ''}`).join('\\n\\n')\n try {\n for await (const step of rewriteChapterStream(ctx, config, project, outputDir, no, instr, undefined)) { /* drain */ }\n } catch (error) {\n this.log(`第${no}章 第${round}轮修订出错:${(error as Error).message}`)\n continue\n }\n // rewrite 已写盘(pendingDraft + saveProject),重载拿最新草稿。\n const fresh = loadProject(outputDir)\n const freshCh = fresh?.chapters.find(c => c.no === no)\n const draft = freshCh?.pendingDraft\n if (draft === undefined || draft.length < 50) {\n this.log(`第${no}章 第${round}轮草稿缺失,重试`)\n continue\n }\n const verify = await reviewChapterText(ctx, config, fresh!, draft, chapter.review)\n const highs2 = (verify.issues ?? []).filter(i => i.severity === 'high')\n if (verify.passed || highs2.length === 0) {\n // 应用草稿(与 draft/apply 路由同逻辑):备份原稿 → 落盘 → 定状态。\n this.applyDraft(fresh!, freshCh!, draft, verify)\n if (this.state !== null) this.state.stats.revised++\n this.log(`第${no}章 第${round}轮修订通过(${verify.score}分)`)\n return\n }\n this.log(`第${no}章 第${round}轮仍不过(${highs2.length} high)`)\n }\n if (this.state !== null) this.state.pendingManual.push(no)\n this.log(`第${no}章 ⚠️ 两轮修订仍不过 → 保留草稿待人工`)\n }\n\n private applyDraft(project: ProjectState, chapter: ChapterPlan, draft: string, report: ReviewReport): void {\n const config = this.deps.getConfig()\n const fileName = chapterFileName(chapter)\n mkdirSync(config.outputDir, { recursive: true })\n const targetPath = join(config.outputDir, fileName)\n if (existsSync(targetPath)) {\n copyFileSync(targetPath, join(config.outputDir, `${fileName.replace(/\\.md$/, '')}.bak.md`))\n }\n writeFileSync(targetPath, `# 第${chapter.no}章 ${chapter.title}\\n\\n${draft}\\n`, 'utf8')\n chapter.pendingDraft = undefined\n chapter.chars = draft.length\n chapter.file = fileName\n if (typeof report.score === 'number') {\n chapter.review = report\n chapter.status = report.passed === true ? 'approved' : 'rejected'\n } else {\n chapter.status = 'written'\n chapter.review = undefined\n }\n chapter.error = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n }\n}\n","/**\n * dsh-novel-forge — shared protocol between the host half (Node) and the\n * browser half (web GUI). Route paths, request/response shapes, the project\n * state file format, and the NDJSON generation stream frames all live here so\n * both halves spell exactly one vocabulary.\n */\n\n/** The /api/dsh-novel-forge route family (same-origin, loopback-fenced). */\nexport const NOVEL_API = {\n status: '/api/dsh-novel-forge/status',\n loadOutline: '/api/dsh-novel-forge/load-outline',\n saveOutline: '/api/dsh-novel-forge/save-outline',\n plan: '/api/dsh-novel-forge/plan',\n volumes: '/api/dsh-novel-forge/volumes',\n bible: '/api/dsh-novel-forge/bible',\n assets: '/api/dsh-novel-forge/assets',\n styleEngine: '/api/dsh-novel-forge/style-engine',\n generate: '/api/dsh-novel-forge/generate',\n review: '/api/dsh-novel-forge/review',\n rewrite: '/api/dsh-novel-forge/rewrite',\n polish: '/api/dsh-novel-forge/polish',\n /** 采纳待确认草稿(润色/重写产物)覆盖正文文件。 */\n draftApply: '/api/dsh-novel-forge/draft/apply',\n /** 放弃待确认草稿,保留原稿。 */\n draftDiscard: '/api/dsh-novel-forge/draft/discard',\n summary: '/api/dsh-novel-forge/summary',\n foreshadow: '/api/dsh-novel-forge/foreshadow',\n exportBook: '/api/dsh-novel-forge/export',\n chapter: '/api/dsh-novel-forge/chapter',\n /** 审查任意正文文本(作者手动编辑后,不落盘)。 */\n chapterCheck: '/api/dsh-novel-forge/chapter/check',\n /** 保存手动编辑的正文(自动备份 .bak)。 */\n chapterSave: '/api/dsh-novel-forge/chapter/save',\n assistant: '/api/dsh-novel-forge/assistant',\n assistantHistory: '/api/dsh-novel-forge/assistant-history',\n /** 清空助手对话记录。 */\n assistantClear: '/api/dsh-novel-forge/assistant/clear',\n bookshelf: '/api/dsh-novel-forge/bookshelf',\n /** 重置项目(可选携带新大纲):清空设定/卷/章节/伏笔/资产/事实库。 */\n reset: '/api/dsh-novel-forge/reset',\n /** 全书一致性质检:LLM 扫描已生成章节,输出矛盾问题清单。 */\n audit: '/api/dsh-novel-forge/audit',\n /** 角色卡刷新:基于事实库与各章摘要聚合角色当前状态。 */\n charactersRefresh: '/api/dsh-novel-forge/characters/refresh',\n /** 事实库回填:对历史已生成章节批量抽取事实(旧章节无事实记录时用)。 */\n factsBackfill: '/api/dsh-novel-forge/facts/backfill',\n /** 设定圣经局部修补(如世界观规则编辑)。 */\n biblePatch: '/api/dsh-novel-forge/bible/patch',\n /** 小说简介:生成(AI)/补全(AI)/保存。 */\n blurb: '/api/dsh-novel-forge/blurb',\n /** 重命名当前书(同步项目与书架条目)。 */\n rename: '/api/dsh-novel-forge/rename',\n /** 大世界:AI 提炼 / 保存结构化数据(境界/区域/势力)。 */\n world: '/api/dsh-novel-forge/world',\n /** 封面:GET 读取(dataUrl)/ POST 上传或移除。 */\n cover: '/api/dsh-novel-forge/blurb/cover',\n /** 剧情线管理:增删改 + 关联章节。 */\n plotlines: '/api/dsh-novel-forge/plotlines',\n /** 角色库:AI 提炼 / 采纳 / 更新 / 删除。 */\n roles: '/api/dsh-novel-forge/roles',\n scenes: '/api/dsh-novel-forge/scenes',\n visualRules: '/api/dsh-novel-forge/visual-rules',\n /** 作者复盘补跑:对已写章节补齐 authorReview(全书流式 / 单章 JSON)。 */\n reviewBackfill: '/api/dsh-novel-forge/review/backfill',\n /** 章节复位:generating 卡死 → pending(可重新生成)。 */\n chapterReset: '/api/dsh-novel-forge/chapter/reset',\n /** 章节直接通过:作者对 rejected/written 章节行使最终决定权。 */\n chapterApprove: '/api/dsh-novel-forge/chapter/approve',\n /** 敏感词检查:全书已写章节或指定文本。 */\n sensitiveCheck: '/api/dsh-novel-forge/sensitive-check',\n /** 开书想法 → AI 补全大纲:输入一句话想法,生成 2-3 个可选大纲方案。 */\n outlineSuggest: '/api/dsh-novel-forge/outline/suggest',\n /** 拆书分析:对已写章节做结构/人物/文风/卖点四维体检(两阶段:源笔记→分节分析)。 */\n breakdown: '/api/dsh-novel-forge/breakdown',\n /** 漫剧分镜生成:章节 → 角色锚点 + 分镜表(可适配豆包/Seedance/SD)。 */\n /** 漫剧分集计划:读一卷 → 按故事弧线分集(高潮拆集/过渡并章)。 */\n /** 漫画脚本:章节 → 分页分格漫画脚本(含角色视觉锚点)。 */\n /** 生产单:启动批量生产(计划补足 + 逐章生成 + 被拒分级处理)。 */\n runStart: '/api/dsh-novel-forge/run/start',\n /** 生产单控制:pause / resume / stop。 */\n runControl: '/api/dsh-novel-forge/run/control',\n /** 生产单状态(含进度统计与日志)。 */\n runStatus: '/api/dsh-novel-forge/run/status',\n config: '/api/dsh-novel-forge/config',\n openFolder: '/api/dsh-novel-forge/open-folder',\n} as const\n\n/** 书架:一本书的条目。 */\nexport interface BookEntry {\n /** 稳定 id。 */\n id: string\n /** 书名。 */\n bookName: string\n /** 该书输出目录(独立项目目录)。 */\n outputDir: string\n /** 创建时间。 */\n createdAt: string\n /** 最后活动时间。 */\n updatedAt: string\n}\n\n/** 书架快照(含每本书的进度摘要)。 */\nexport interface BookshelfSnapshot {\n books: Array<BookEntry & { done: number; total: number; hasProject: boolean; hasCover: boolean; blurb?: string }>\n /** 当前激活的书 id(无则 null)。 */\n activeBookId: string | null\n}\n\n/** POST /bookshelf 请求:创建新书。 */\nexport interface BookCreateRequest {\n bookName: string\n outputDir?: string\n /** 开书向导:创建时直接导入的大纲文本(提供则立即建立项目)。 */\n outline?: string\n}\n\n/** POST /reset 请求:重置项目(可选更新大纲)。 */\nexport interface ResetRequest {\n /** 新大纲文本;提供则替换 outline,否则保留原大纲。 */\n outline?: string\n}\n\n/** POST /bookshelf/activate 请求:切换当前书。 */\nexport interface BookActivateRequest {\n id: string\n}\n\n/** POST /bookshelf/remove 请求:移除书架条目。 */\nexport interface BookRemoveRequest {\n id: string\n}\n\n/** Chapter lifecycle states (the writing pipeline's state machine). */\nexport type ChapterStatus =\n | 'pending' // planned, not started\n | 'generating' // LLM writing right now\n | 'written' // body on disk, awaiting review\n | 'reviewing' // review in progress\n | 'approved' // passed review (or user-approved)\n | 'rejected' // review found problems\n | 'error' // generation failed\n\n/** One chapter in the plan. */\nexport interface ChapterPlan {\n /** 1-based chapter number (stable identity; files are named from it). */\n no: number\n /** Volume this chapter belongs to (1-based; 0 = unassigned). */\n volume: number\n /** Chapter title, decided by the LLM plan step. */\n title: string\n /** Story beats / plot points for this chapter (model-facing guidance). */\n beats: string\n /** Target character count (defaults to the configured chapter size). */\n targetChars: number\n /** Generation/review state. */\n status: ChapterStatus\n /** 进入 generating 的时间(用于超时自动复位;未在生成时无此字段)。 */\n generatingAt?: string\n /** Actual character count once generated. */\n chars?: number\n /** Failure message when status is 'error'. */\n error?: string\n /** Output file name once generated (relative to the output dir). */\n file?: string\n /** LLM summary of the chapter (narrative memory for later chapters). */\n summary?: string\n /** Latest review report (present once reviewed). */\n review?: ReviewReport\n /** 作者复盘:钩子兑现/结尾钩子/剧情线推进/连续性/节奏趋势(生成后自动)。 */\n authorReview?: AuthorReview\n /**\n * 待确认草稿:润色(去AI味)或整章重写的产物正文。生成时先存这里,\n * 用户看过对比后点「采纳」才覆盖正文文件;点「放弃」则丢弃。刷新页面不丢失。\n */\n pendingDraft?: string\n}\n\n/** 作者复盘:叙事结构层面的逐章检查(钩子/推进/连续性/趋势)。 */\nexport interface AuthorReview {\n /** 上一章结尾钩子是否在本章兑现。 */\n hookHonored: boolean\n /** 钩子兑现说明(未兑现时给出建议)。 */\n hookNote: string\n /** 本章结尾钩子强度 0-10。 */\n endingHook: number\n /** 剧情线推进情况(推进了哪条线/或未推进)。 */\n plotlineProgress: string\n /** 结构化:本章推进的剧情线名称列表(与项目剧情线 name 精确匹配,复盘后自动关联章节)。 */\n advancedLines?: string[]\n /** 连续性检查(人物位置/时间/伤势/资源是否与上章衔接)。 */\n continuity: string\n /** 近期节奏趋势提示(拖沓/爽点密度等)。 */\n trend: string\n /** 复盘时间。 */\n reviewedAt: string\n}\n\n/** One review finding. */\nexport interface ReviewIssue {\n /** Severity: high = must fix, medium = should fix, low = suggestion. */\n severity: 'high' | 'medium' | 'low'\n /** What the problem is. */\n item: string\n /** Concrete suggestion for fixing it. */\n suggestion: string\n}\n\n/** AI review report for one chapter. */\nexport interface ReviewReport {\n /** Overall score 0-100. */\n score: number\n /** Pass threshold (config; 70 default). */\n passed: boolean\n /** One-line verdict. */\n verdict: string\n /** Individual findings. */\n issues: ReviewIssue[]\n /** When the review ran. */\n reviewedAt: string\n}\n\n/** A volume of the book. */\nexport interface Volume {\n /** 1-based volume number. */\n no: number\n /** Volume title. */\n title: string\n /** Volume positioning / summary. */\n summary: string\n /** First chapter number of this volume. */\n chapterStart: number\n /** Last chapter number (inclusive). */\n chapterEnd: number\n}\n\n/** A character card from the story bible. */\nexport interface CharacterCard {\n name: string\n role: 'protagonist' | 'supporting' | 'antagonist' | 'other'\n /** Personality / traits (short lines). */\n traits: string[]\n /** Goals and motivations. */\n goals: string\n /** Key relations to other characters. */\n relations: string\n /** 知情度:该角色已经知道的事实/秘密(未列出的信息该角色不知道)。 */\n knowledge?: string[]\n}\n\n/** The structured story bible (worldbuilding extracted from the outline). */\nexport interface StoryBible {\n /** Genre + tone tags. */\n genre: string\n /** Worldbuilding rules (power system, geography, factions...). */\n worldRules: string[]\n /** Character cards. */\n characters: CharacterCard[]\n /** Writing red lines (forbidden content / must-avoid tropes). */\n redLines: string[]\n /** Style guidance (pacing, pov, tone). */\n style: string[]\n /** When the bible was generated. */\n generatedAt?: string\n}\n\n/** A planted/active/resolved foreshadowing thread. */\nexport interface Foreshadow {\n /** Stable id. */\n id: string\n /** What the foreshadow is. */\n description: string\n /** Chapter where it was planted (undefined = planned). */\n plantedChapter?: number\n /** Chapter where it should be paid off. */\n targetChapter?: number\n /** Lifecycle state. */\n status: 'planned' | 'planted' | 'progressing' | 'resolved' | 'abandoned'\n /** Resolution note when resolved. */\n resolvedNote?: string\n}\n\n/** 一条已确立的叙事事实(事实库/时间线,注入后续章节生成)。 */\nexport interface ChapterFact {\n /** 来源章节号。 */\n chapterNo: number\n /** 事实文本(人物状态/境界资源/关系变化/伏笔落地等)。 */\n text: string\n}\n\n/** 一条全书质检发现的问题(一致性矛盾,定位到章)。 */\nexport interface AuditIssue {\n /** 问题所在章节号(无法定位时 0)。 */\n chapterNo: number\n severity: 'high' | 'medium' | 'low'\n /** 矛盾描述。 */\n item: string\n /** 修改建议。 */\n suggestion: string\n}\n\n/** POST /audit 响应。 */\nexport interface AuditResponse {\n issues: AuditIssue[]\n /** 参与质检的章节数。 */\n auditedChapters: number\n /** 质检时间。 */\n auditedAt: string\n}\n\n/** 全书质检的实时状态(通过 /status 暴露给面板/外部读取)。 */\nexport interface AuditStatus {\n status: 'idle' | 'running' | 'done' | 'error'\n /** 开始时间(ISO)。 */\n startedAt?: string\n /** 结束时间(ISO)。 */\n finishedAt?: string\n /** 总批次数(0 = 尚未开始/无章节)。 */\n totalBatches: number\n /** 已完成批次数。 */\n completedBatches: number\n /** 参与质检的章节数。 */\n auditedChapters?: number\n /** 发现的问题数(done 后有效)。 */\n issuesCount?: number\n /** 最近一次质检的问题清单(done 后有效;error 时为空)。 */\n issues?: AuditIssue[]\n /** 失败信息(error 时有效)。 */\n error?: string\n}\n\n/** 一条剧情线(主线/支线/人物线/悬念线)。 */\nexport interface Plotline {\n /** 稳定 id。 */\n id: string\n /** 线名。 */\n name: string\n /** 类型:主线 / 支线 / 人物线 / 悬念线。 */\n kind: 'main' | 'branch' | 'character' | 'mystery'\n /** 目标/终点(这条线最终要完成什么)。 */\n goal: string\n /** 当前进度说明(最近推进到哪)。 */\n progress: string\n /** 生命周期状态。 */\n status: 'active' | 'paused' | 'resolved' | 'abandoned'\n /** 关联章节号(推进/落地的章节)。 */\n chapters: number[]\n /** 创建时间。 */\n createdAt: string\n}\n\n/** POST /plotlines 请求:剧情线增删改 + 关联章节 + AI 辅助。 */\nexport interface PlotlinesRequest {\n op: 'add' | 'update' | 'remove' | 'link' | 'suggest' | 'refresh' | 'health' | 'plan'\n /** add / update 时传入的完整剧情线。 */\n line?: Plotline\n /** remove / link / refresh 时的目标线 id。 */\n id?: string\n /** link 时关联的章节号。 */\n chapterNo?: number\n}\n\n/** 剧情线健康检查报告。 */\nexport interface PlotlineHealthReport {\n /** 是否需要新线(需要 / 暂不需要 / 再写 X 章后需要)。 */\n verdict: string\n /** 建议添加新线的时机说明。 */\n timing: string\n /** 依据(基于数据的理由,每条一句)。 */\n reasons: string[]\n /** 各线健康度。 */\n lines: Array<{\n name: string\n /** ok=健康 / warning=预警 / stale=搁置过久。 */\n health: 'ok' | 'warning' | 'stale'\n note: string\n }>\n}\n\n/** AI 剧情方案:下一阶段目标 + 建议新线。 */\nexport interface PlotlinePlan {\n /** 下一阶段(未来 5-10 章)剧情方向。 */\n direction: string\n /** 建议的新线(可逐条采纳)。 */\n suggestions: Plotline[]\n}\n\n/** POST /plotlines 响应。 */\nexport interface PlotlinesResponse {\n plotlines: Plotline[]\n /** op=suggest 时的 AI 建议候选线。 */\n suggestions?: Plotline[]\n /** op=health 时的健康检查报告。 */\n health?: PlotlineHealthReport\n /** op=plan 时的剧情方案。 */\n plan?: PlotlinePlan\n}\n\n/** 一条敏感词命中。 */\nexport interface SensitiveHit {\n /** 命中章节号(文本检测时为 0)。 */\n chapterNo: number\n /** 命中的违禁词。 */\n word: string\n /** 类别:政治 / 擦边 / 暴力 / 辱骂 / 广告 / 其他。 */\n category: string\n /** 出现次数。 */\n count: number\n}\n\n/** POST /sensitive-check 请求:检测指定章节/任意文本/全书。 */\nexport interface SensitiveCheckRequest {\n /** 检测该章正文。 */\n chapterNo?: number\n /** 检测任意文本(优先于 chapterNo)。 */\n text?: string\n /** 扫描全部已写章节。 */\n all?: boolean\n}\n\n/** POST /sensitive-check 响应。 */\nexport interface SensitiveCheckResponse {\n hits: SensitiveHit[]\n /** 参与扫描的章节数。 */\n scannedChapters: number\n}\n\n/** 开书想法 → AI 大纲方案(一个候选)。 */\nexport interface OutlineCandidate {\n /** 唯一 id(前端暂留/换批用)。 */\n id: string\n /** 推荐书名。 */\n bookName: string\n /** 题材(如 仙侠修真 / 都市)。 */\n genre: string\n /** 核心卖点一句话。 */\n sellingPoint: string\n /** 完整大纲文本(可直接用作项目大纲,≥800 字)。 */\n outline: string\n}\n\n/** POST /outline/suggest 请求:想法 → 2-3 个可选大纲。 */\nexport interface OutlineSuggestRequest {\n /** 作者想法(一两句话,≥50 字)。 */\n idea: string\n /** 本次要生成的候选数(默认 3,最多 3)。 */\n count?: number\n /** 已暂留方案的剧情方向摘要(换批时让 LLM 避开,防止与已留方案重复)。 */\n exclude?: string[]\n}\n\n/** POST /outline/suggest 响应。 */\nexport interface OutlineSuggestResponse {\n candidates: OutlineCandidate[]\n}\n\n/** 拆书分析:一个分析小节。 */\nexport interface BreakdownSection {\n /** 小节键:overview / plot / character / style / market。 */\n key: string\n /** 小节标题(如「拆书总览」)。 */\n title: string\n /** 可读分析稿(markdown)。 */\n markdown: string\n /** 结构化数据(程序可消费)。 */\n structured: Record<string, unknown>\n}\n\n/** 拆书分析:一条证据(结论→原文回溯)。 */\nexport interface BreakdownEvidence {\n label: string\n excerpt: string\n /** 来源章节号(0 = 未定位)。 */\n chapterNo: number\n /** 指向的结构化字段。 */\n fieldKey?: string\n}\n\n/** POST /breakdown 请求:对已写章节做拆书分析。 */\nexport interface BreakdownRequest {\n /** 分析范围:'recent'=最近 20 章 / 'volume:N'=第 N 卷 / 'all'=全书(默认 recent)。 */\n scope?: string\n /** 分析档位:'quick'=4 维(总览/剧情/人物/文风)/ 'standard'=5 维(+卖点)。 */\n preset?: 'quick' | 'standard'\n /** token 预算上限(默认 50000)。 */\n budgetTokens?: number\n}\n\n/** POST /breakdown 响应。 */\nexport interface BreakdownResponse {\n sections: BreakdownSection[]\n evidence: BreakdownEvidence[]\n /** 参与分析的章节数。 */\n chaptersScanned: number\n /** 估算消耗 token。 */\n usedTokens: number\n}\n\n/** 角色卡:角色当前状态(从事实库聚合)。 */\nexport interface RoleStatusCard {\n name: string\n /** protagonist / supporting / antagonist / other。 */\n role: string\n /** 当前状态一句话(境界/资源/伤势/心境)。 */\n status: string\n /** 最近出场章节。 */\n lastChapter: number\n /** 出场次数。 */\n appearances: number\n}\n\n/** 角色库条目(主表:作者维护 + AI 提炼 + 编年录自动聚合)。 */\nexport interface RoleRecord {\n /** 角色名(唯一键)。 */\n name: string\n /** 定位:主角 / 女主 / 女配 / 配角 / 反派 / 路人。 */\n roleLabel: 'protagonist' | 'female_lead' | 'female_support' | 'support' | 'antagonist' | 'extra'\n /** 身份一句话(如:祭族后裔、青云宗杂役)。 */\n identity: string\n /** 性格标签。 */\n traits: string[]\n /** 目标与动机。 */\n goals: string\n /** 关系网:[角色名](关系)。 */\n relations: string[]\n /** 成长线:阶段 → 说明(可含章节)。 */\n arc: string[]\n /** 知情度:该角色已经知道的信息。 */\n knowledge: string[]\n /** 首次出场章节(编年录聚合,可手动修正)。 */\n firstChapter?: number\n /** 动漫形象描述词(AI 绘图用:中文描述 + 英文标签 + 关键外貌标签)。 */\n imagePrompt?: {\n /** 中文外貌描述:连贯一段(发色/瞳色/服装/气质/标志物)。 */\n zh: string\n /** 英文绘图标签:booru 风格逗号分隔。 */\n en: string\n /** 中文关键标签(发色/瞳色/服装/气质/标志物)。 */\n tags: string[]\n /** 依据来源说明(哪几章哪些描写)。 */\n source?: string\n }\n /** 角色参考图(dataURL 或 URL)。用于漫画/漫剧出图时锁定角色一致性。 */\n imageUrl?: string\n /** 角色图集(图像锚点):立绘/四视图/表情/场景/细节等,label 标注用途。 */\n gallery?: RoleImage[]\n /** 该角色所需的情绪表情清单(提炼时 LLM 补全 6-12 个,如\"疲惫/麻木/压抑悲伤\")。 */\n expressions?: string[]\n /** LLM 精修的四类生图提示词包(前端拼装版之外的高质量版,promptKit 接口生成)。 */\n promptKit?: {\n /** 立绘:全身/半身正视图。 */\n portrait: { zh: string; en: string }\n /** 四视图:正面/侧面/背面设定表。 */\n sheet: { zh: string; en: string }\n /** 表情:同一脸部锚换情绪,每表情一段。 */\n expressions: { name: string; zh: string; en: string }[]\n /** 细节:标志物局部特写。 */\n details: { zh: string; en: string }\n }\n /** 漫画/漫剧重要性:main=必须建卡保证一致;support=有锚点即可;extra=路人随机生成不约束。 */\n importance?: 'main' | 'support' | 'extra'\n}\n\n/** 角色图集条目:一张已定型的角色图(图像锚点)。 */\nexport interface RoleImage {\n /** 用途标签:立绘 / 四视图 / 表情-疲惫 / 场景 / 细节 等。 */\n label: string\n /** dataURL 或 URL。 */\n dataUrl: string\n}\n\n/** 场景库条目:从正文提炼的「镜头场景」视觉锚点(漫剧分镜/生图用)。 */\nexport interface SceneCard {\n /** 场景名(唯一键),如「旧茶渡·地下石殿」。 */\n name: string\n /** 一句话定位:空间/氛围/功能。 */\n summary: string\n /** 幕归属:第一幕·后场 / 第二幕·卖场 / …(便于按剧情段落组织)。 */\n act?: string\n /** 时间光态:夜间闭店后 / 雨夜 / 凌晨 / 频闪灯… */\n moment?: string\n /** 关键情节镜头 1-3 条:该场景拍什么(人物动作+情绪+镜头推进)。 */\n beats?: string[]\n /** 人物在场状态:主角/关键角色在该场景的状态一句话。 */\n characterState?: string\n /** 环境构成:空间结构/陈设/标志物。 */\n elements: string[]\n /** 色调与光影(含 HEX 色板,可空)。 */\n palette: string[]\n /** 氛围关键词:压抑/神秘/空旷… */\n moods: string[]\n /** 中文生图提示词(连贯一段,写实电影感)。 */\n zh: string\n /** 英文生图提示词(逗号分隔标签)。 */\n en: string\n /** 关键标签。 */\n tags: string[]\n /** 依据来源(哪几章哪些描写)。 */\n source?: string\n /** 场景图集(图像锚点):全景/局部/氛围 等。 */\n gallery?: RoleImage[]\n}\n\n/** POST /scenes 请求:场景库提炼 / 采纳 / 更新 / 删除 / 图集。 */\nexport interface ScenesRequest {\n op: 'extract' | 'adopt' | 'update' | 'remove' | 'image' | 'removeImage'\n /** adopt / update 时传入的场景卡(adopt 可修改后采纳)。 */\n scene?: SceneCard\n /** remove / image 时的场景名。 */\n name?: string\n /** op='image' 时的图片 dataURL 与用途标签(全景/局部/氛围)。 */\n dataUrl?: string\n label?: string\n}\n\n/** POST /visual-rules 请求:视觉世界观规则提炼 / 保存。 */\nexport interface VisualRulesRequest {\n op: 'extract' | 'save'\n /** op=save 时的规则数组。 */\n rules?: string[]\n}\n\n/** POST /visual-rules 响应。 */\nexport interface VisualRulesResponse {\n rules: string[]\n}\n\n/** POST /scenes 响应。 */\nexport interface ScenesResponse {\n scenes: SceneCard[]\n /** op=extract 时的 AI 候选场景。 */\n candidates?: SceneCard[]\n}\n\n/** POST /roles 请求:角色库增删改 + AI 提炼 + 参考图上传。 */\nexport interface RolesRequest {\n op: 'extract' | 'adopt' | 'update' | 'remove' | 'visual' | 'image' | 'removeImage' | 'imageGenerate' | 'promptKit'\n /** adopt / update 时传入的角色(adopt 可修改后采纳)。 */\n role?: RoleRecord\n /** remove 时的角色名。 */\n name?: string\n /** op='image' 时的参考图 dataURL。 */\n dataUrl?: string\n /** op='image' 时的图集用途标签(立绘/四视图/表情-x/场景/细节);缺省视为角色参考图(imageUrl)。 */\n label?: string\n /** op='imageGenerate' 时的漫画风格预设 id(用于统一角色图与漫画页风格)。 */\n style?: string\n}\n\n/** POST /roles 响应。 */\nexport interface RolesResponse {\n roles: RoleRecord[]\n /** op=extract 时的 AI 候选角色。 */\n candidates?: RoleRecord[]\n /** op=visual 时的动漫形象描述词(已写入角色卡)。 */\n visual?: RoleRecord['imagePrompt']\n /** op=promptKit 时的四类提示词精修包(已写入角色卡)。 */\n promptKit?: RoleRecord['promptKit']\n /** op=image 时的角色参考图 dataURL。 */\n imageUrl?: string\n}\n\n/** POST /bible/patch 请求:局部修补设定圣经。 */\nexport interface BiblePatchRequest {\n worldRules?: string[]\n redLines?: string[]\n style?: string[]\n /** 角色卡整体替换(人物志编辑知情度等)。 */\n characters?: CharacterCard[]\n}\n\n/** POST /blurb 请求:AI 生成/补全或手动保存小说简介。 */\nexport interface BlurbRequest {\n action: 'generate' | 'save'\n /** 已写好的开头(AI 补全时使用;留空 = 全量生成)。 */\n partial?: string\n /** 手动保存的完整简介(action=save 时)。 */\n text?: string\n}\n\n/** POST /chapter/check|save 请求:审查/保存手动编辑的正文。 */\nexport interface ChapterTextRequest {\n chapterNo: number\n /** 当前编辑中的正文全文。 */\n text: string\n /** 保存时携带:已在工作区审查过的报告(沿用落盘,不重复审);缺省则保存后自动正式审稿一次。 */\n report?: ReviewReport\n /** 审查/验证时携带:上一轮审稿报告。传入后进入「验证模式」——逐条核对原意见是否解决、\n * 只挑新增 high,不再全新找茬(防止\"越修 high 越多\")。 */\n previousReport?: ReviewReport\n}\n\n/** POST /chapter/save 响应。 */\nexport interface ChapterSaveResponse {\n ok: boolean\n chars: number\n file: string\n /** 落盘的审稿报告(沿用工作区报告或保存后自动审稿)。 */\n report?: ReviewReport\n}\n\n/** POST /cover 请求:上传或移除封面。 */\nexport interface CoverRequest {\n action: 'upload' | 'remove'\n /** 上传时:data:image/...;base64,... 格式的图片数据。 */\n dataUrl?: string\n}\n\n/** POST /rename 请求:重命名当前书。 */\nexport interface RenameRequest {\n bookName: string\n}\n\n/** 大世界:一个境界等级。 */\nexport interface WorldRealm {\n /** 境界名(练气/筑基/金丹…)。 */\n name: string\n /** 描述:突破条件/寿命/标志等。 */\n description: string\n}\n\n/** 大世界:一个地理区域。 */\nexport interface WorldRegion {\n name: string\n description: string\n /** 关联势力名(可空)。 */\n faction?: string\n}\n\n/** 大世界:一方势力。 */\nexport interface WorldFaction {\n name: string\n /** 类型:宗门/家族/王朝/组织… */\n kind: string\n description: string\n /** 驻地区域(可空)。 */\n region?: string\n}\n\n/** 大世界结构化数据。 */\nexport interface WorldState {\n realms: WorldRealm[]\n regions: WorldRegion[]\n factions: WorldFaction[]\n}\n\n/** POST /world 请求:AI 提炼或手动保存。 */\nexport interface WorldRequest {\n action: 'generate' | 'save'\n /** action=save 时的完整世界数据。 */\n world?: WorldState\n}\n\n/** GET /cover 响应:封面的 dataUrl(无封面为 null)。 */\nexport interface CoverResponse {\n dataUrl: string | null\n}\n\n/** The persisted project: outline + bible + plan + progress. */\nexport interface ProjectState {\n /** Book title (first non-empty line of the outline, usually). */\n bookName: string\n /** Full outline text (docx-extracted or pasted). */\n outline: string\n /** Source outline path when loaded from a docx. */\n outlinePath?: string\n /** Structured story bible (worldbuilding), if generated. */\n bible?: StoryBible\n /** Volumes, if planned. */\n volumes?: Volume[]\n /** Chapter plan. */\n chapters: ChapterPlan[]\n /** Foreshadowing threads. */\n foreshadows: Foreshadow[]\n /** 写作资产(题材基底/推进模式/反AI规则/写法资产)。 */\n assets?: ProjectAssets\n /** 事实库/时间线:每章生成后抽取,注入后续章节保持一致性。 */\n facts?: ChapterFact[]\n /** 小说简介(面向读者的作品门面,AI 生成或手动保存)。 */\n blurb?: string\n /** 封面文件名(相对输出目录,如 cover.png)。 */\n coverPath?: string\n /** 大世界结构化数据(境界体系/区域/势力)。 */\n world?: WorldState\n /** 剧情线(主线/支线/人物线/悬念线)。 */\n plotlines?: Plotline[]\n /** 角色库(作者维护 + AI 提炼的主表)。 */\n roles?: RoleRecord[]\n /** 场景库(作者维护 + AI 提炼的主表)。 */\n scenes?: SceneCard[]\n /** 视觉世界观规则(生图/生视频必须遵守,从道藏提炼,注入所有提示词)。 */\n visualRules?: string[]\n /** 人物志:角色当前状态聚合结果(从编年录刷新后存档,打开页面直接显示)。 */\n roleStatus?: RoleStatusCard[]\n /** 漫剧分镜结果缓存:章号 → 分镜(持久化,刷新不丢)。 */\n /** 漫剧分集计划缓存:卷号/0=全书 → 分集计划(持久化,刷新不丢)。 */\n /** 漫画脚本缓存:章号 → 漫画脚本(持久化,刷新不丢)。 */\n /** ISO timestamps. */\n createdAt: string\n updatedAt: string\n}\n\n/** Runtime config surface exposed to the panel (subset of plugin Config). */\nexport interface NovelConfig {\n /** Absolute path of the default docx outline to load. */\n outlinePath: string\n /** Absolute output directory for chapters + project state. */\n outputDir: string\n /** LLM provider route (e.g. deepseek-official). */\n provider: string\n /** LLM model id (e.g. deepseek-v4-flash). */\n model: string\n /** LLM reasoning effort: off = no thinking; low/high/max = thinking intensity. */\n reasoningEffort: 'off' | 'low' | 'high' | 'max'\n /** Target characters per chapter. */\n chapterChars: number\n /** Max output tokens per chapter call. */\n maxTokens: number\n /** Review pass threshold (0-100). */\n reviewPassScore: number\n /** Whether generation auto-runs review after writing. */\n autoReview: boolean\n /** Whether generation auto-runs the author review (hook/continuity/trend) after writing. */\n autoAuthorReview: boolean\n /** 修订/润色产出草稿后是否自动附带一次 AI 审查(工作区显示新稿评分与剩余问题)。 */\n autoReviewAfterRevise: boolean\n /** 豆包/Seedream 生图 API Key(保存在服务端配置,不暴露给前端明文回显)。 */\n imageApiKey?: string\n /** 豆包/Seedream 生图模型 ID(如 doubao-seedream-5-0-pro-260628)。 */\n imageApiModel?: string\n /** 是否启用豆包生图(默认关,避免误调用付费 API)。 */\n imageApiEnabled?: boolean\n}\n\n/** GET /status response. */\nexport interface StatusResponse {\n config: NovelConfig\n /** The persisted project, when one exists in the output dir. */\n project?: ProjectState\n /** Chapter files already on disk (basenames, sorted). */\n generatedFiles: string[]\n /** 全书质检实时状态(用于面板/外部读取进度)。 */\n audit?: AuditStatus\n}\n\n/** 生产单状态(生产单 = 区间批量生产执行器:计划补足 + 逐章生成 + 被拒分级处理)。 */\nexport interface RunState {\n runId: string\n /** 区间起点(含)。 */\n startNo: number\n /** 区间终点(含)。 */\n endNo: number\n status: 'running' | 'paused' | 'done' | 'stopped' | 'error'\n /** 当前处理到的章号(已 approved 的章会快进)。 */\n currentNo: number\n stats: {\n /** 新生成(含审稿)的章数。 */\n generated: number\n /** 被拒后按意见修订并通过的章数。 */\n revised: number\n /** 被拒后豁免通过(无 high)的章数。 */\n exempted: number\n /** error 后重新生成的章数。 */\n regenerated: number\n /** 生成失败的章数。 */\n error: number\n }\n /** 两轮修订仍不过、保留草稿待人工的章号。 */\n pendingManual: number[]\n /** 运行日志(保留最近 300 条)。 */\n log: Array<{ at: string; text: string }>\n startedAt: string\n updatedAt: string\n error?: string\n}\n\n/** POST /run/start request. */\nexport interface RunStartRequest {\n /** 起始章号(默认 1)。 */\n startNo?: number\n /** 结束章号(含;超出计划时自动补计划)。 */\n endNo?: number\n /** 或指定新增章数(从当前最后一章 +1 起)。 */\n count?: number\n}\n\n/** POST /run/control request. */\nexport interface RunControlRequest {\n action: 'pause' | 'resume' | 'stop'\n}\n\n/** POST /load-outline request: either a docx path or raw text. */\nexport interface LoadOutlineRequest {\n /** Absolute docx path; defaults to the configured outline path. */\n path?: string\n /** Raw outline text (takes precedence over path when present). */\n text?: string\n}\n\n/** POST /load-outline response. */\nexport interface LoadOutlineResponse {\n outline: string\n bookName: string\n chars: number\n path?: string\n}\n\n/** POST /plan request. */\nexport interface PlanRequest {\n /** Outline to plan from; defaults to the persisted project's outline. */\n outline?: string\n /** Number of chapters to plan (default: 30). */\n chapterCount?: number\n /** Volume to plan (1-based); when given, plans only that volume's chapters. */\n volume?: number\n}\n\n/** POST /plan response. */\nexport interface PlanResponse {\n chapters: ChapterPlan[]\n volumes?: Volume[]\n}\n\n/** POST /volumes request/response. */\nexport interface VolumesRequest {\n /** Outline to split into volumes; defaults to the project outline. */\n outline?: string\n}\nexport interface VolumesResponse {\n volumes: Volume[]\n}\n\n/** POST /bible request/response. */\nexport interface BibleRequest {\n /** Outline to extract from; defaults to the project outline. */\n outline?: string\n}\nexport interface BibleResponse {\n bible: StoryBible\n}\n\n/** POST /generate request: one chapter of the current project. */\nexport interface GenerateRequest {\n chapterNo: number\n /** When true, skips the auto-review step. */\n skipReview?: boolean\n}\n\n/** One NDJSON frame of a generation/review/rewrite stream. */\nexport type JobFrame =\n | { type: 'start'; no: number; title: string }\n | { type: 'delta'; text: string }\n | { type: 'progress'; chars: number }\n | { type: 'done'; no: number; file: string; chars: number; title: string }\n | { type: 'review'; no: number; report: ReviewReport }\n | { type: 'author-review'; no: number; review: AuthorReview }\n | { type: 'author-backfill-done'; count: number }\n | { type: 'rewritten'; no: number; file: string; chars: number }\n /** 润色/重写完成,产物作为待确认草稿(尚未覆盖正文)。 */\n | { type: 'drafted'; no: number; chars: number; draft: string }\n | { type: 'error'; no: number; message: string }\n\n/** POST /review request: review one written chapter. */\nexport interface ReviewRequest {\n chapterNo: number\n}\n\n/** POST /rewrite request: rewrite one chapter (optionally per review issues). */\nexport interface RewriteRequest {\n chapterNo: number\n /** Free-form instructions; defaults to fixing the review's high issues. */\n instructions?: string\n /**\n * 局部修订:正文中的一段原文(无需完全精确,取一个自然段内的片段即可)。\n * 提供时只重写该段,其余正文保持不变;不提供时整章重写。\n */\n target?: string\n}\n\n/** POST /polish request: de-AI-ify one chapter. */\nexport interface PolishRequest {\n chapterNo: number\n}\n\n/** POST /draft/apply | /draft/discard request: 采纳或放弃待确认草稿。 */\nexport interface DraftDecisionRequest {\n chapterNo: number\n /** apply 时可携带审查报告(沿用结论定状态;不携带则置 written)。 */\n report?: ReviewReport\n}\n\n/** POST /summary request: (re)generate a chapter summary. */\nexport interface SummaryRequest {\n chapterNo: number\n}\n\n/** POST /foreshadow request: create, update, or AI-suggest foreshadows. */\nexport interface ForeshadowRequest {\n /** When true, runs the LLM suggestion pass (ignores other fields). */\n suggest?: boolean\n /** When given, updates that foreshadow instead of creating one. */\n id?: string\n description?: string\n plantedChapter?: number\n targetChapter?: number\n status?: Foreshadow['status']\n resolvedNote?: string\n}\nexport interface ForeshadowResponse {\n foreshadows: Foreshadow[]\n}\n\n/** GET /chapter response. */\nexport interface ChapterResponse {\n no: number\n title: string\n markdown: string\n}\n\n/** POST /export request/response. */\nexport interface ExportRequest {\n format: 'txt' | 'md'\n}\nexport interface ExportResponse {\n file: string\n chars: number\n chapters: number\n}\n\n/** POST /config request: patch any subset of the runtime config. */\nexport interface ConfigPatch {\n outlinePath?: string\n outputDir?: string\n provider?: string\n model?: string\n reasoningEffort?: 'off' | 'low' | 'high' | 'max'\n chapterChars?: number\n maxTokens?: number\n reviewPassScore?: number\n autoReview?: boolean\n autoAuthorReview?: boolean\n autoReviewAfterRevise?: boolean\n imageApiKey?: string\n imageApiModel?: string\n imageApiEnabled?: boolean\n}\n\n// ------------------------------------------------------------ assistant\n\n/** One assistant conversation message (persisted per project). */\nexport interface AssistantMessage {\n role: 'user' | 'assistant' | 'tool'\n /** Message text (tool messages carry the tool result). */\n content: string\n /** ISO timestamp. */\n ts: string\n /** For tool messages: which tool ran. */\n tool?: string\n}\n\n/** POST /assistant request: one user turn. */\nexport interface AssistantRequest {\n message: string\n}\n\n/** One NDJSON frame of the assistant stream. */\nexport type AssistantFrame =\n | { type: 'delta'; text: string }\n | { type: 'tool'; name: string; status: 'start' | 'done' | 'error'; detail?: string }\n /** Live output while a tool runs (e.g. chapter text being generated). */\n | { type: 'toolDelta'; name: string; text: string }\n | { type: 'done' }\n | { type: 'error'; message: string }\n\n/** GET /assistant-history response. */\nexport interface AssistantHistoryResponse {\n messages: AssistantMessage[]\n}\n\n// ---------------------------------------------------------- writing assets\n\n/** 题材基底库:一本书属于哪个阅读市场。树形(题材→子题材→下级)。 */\nexport interface GenreNode {\n /** 题材名称(标签,如「仙侠修真」「都市异能」)。 */\n name: string\n /** 题材特征、常见爽点、叙事重心或读者期待。 */\n description: string\n /** 子题材。 */\n children: GenreNode[]\n}\n\n/** 推进模式库:读者为什么继续看下一章。 */\nexport interface ProgressionMode {\n /** 模式名称(如「升级变强」「经营扩张」「解谜揭露」)。 */\n name: string\n /** 核心驱动力:靠什么制造追读动力。 */\n driver: string\n /** 读者期待:每隔几章获得什么变化或回报。 */\n readerExpectation: string\n /** 常见兑现方式(爽点如何落地)。 */\n payoffs: string[]\n /** 节奏风险:最怕什么(重复升级、冲突变弱、谜题拖太久…)。 */\n risks: string[]\n /** 主模式或辅助模式。 */\n primary: boolean\n}\n\n/** 反 AI 规则:一条「要避免的问题 + 修正方向」。 */\nexport interface AntiAiRule {\n /** 规则名(如「禁止解释型心理描写」「AI 高频套话」)。 */\n name: string\n /** 要避免的表达问题,具体可检查。 */\n avoid: string\n /** 推荐修正方向。 */\n fix: string\n /** 命中即告警的具体表达模式(用于审稿逐条核对与去 AI 味检测)。 */\n detectPatterns?: string[]\n /** 是否内置全局规则(内置规则随插件发布,项目规则为用户自定义)。 */\n builtin?: boolean\n}\n\n/** 预置写法模板(来自 AI-Novel-Writing-Assistant 内置数据,一键绑定无需样本文本)。 */\nexport interface StyleTemplate {\n /** 模板 key(如 power-up-escalation)。 */\n key: string\n /** 模板名(如「爽文递进推进流」)。 */\n name: string\n /** 模板说明。 */\n description: string\n /** 分类(如「爽文流」「悬疑流」)。 */\n category: string\n /** 适用题材。 */\n applicableGenres: string[]\n /** 叙述规则。 */\n proseRules: string[]\n /** 角色/台词规则。 */\n dialogueRules: string[]\n /** 语言规则。 */\n languageRules: string[]\n /** 节奏规则。 */\n rhythmRules: string[]\n /** 该模板默认绑定的反 AI 规则 key(内置规则名)。 */\n defaultAntiAiRuleKeys: string[]\n}\n\n/** 写法引擎:从样本文本提取的叙事风格资产。 */\nexport interface StyleAsset {\n /** 资产名(如「林越式痞坏」「冷峻猎手风」)。 */\n name: string\n /** 叙述视角与句式节奏。 */\n proseRules: string[]\n /** 角色台词风格。 */\n dialogueRules: string[]\n /** 描写密度与情绪表达。 */\n descriptionRules: string[]\n /** 表达边界(不要做什么)。 */\n boundaries: string[]\n /** 来源样本文本(可空)。 */\n sourceText?: string\n /** 创建时间。 */\n createdAt: string\n}\n\n/** 项目写作资产(题材基底 + 推进模式 + 反 AI 规则 + 写法资产)。 */\nexport interface ProjectAssets {\n /** 本书选用的题材(可以是题材基底库中某节点名)。 */\n genre?: GenreNode\n /** 主推进模式。 */\n primaryProgression?: ProgressionMode\n /** 辅助推进模式。 */\n auxiliaryProgressions: ProgressionMode[]\n /** 生效的反 AI 规则(内置 + 自定义)。 */\n antiAiRules: AntiAiRule[]\n /** 绑定的写法资产。 */\n styleAssets: StyleAsset[]\n /** 资产更新时间。 */\n updatedAt?: string\n}\n\n/** GET /assets response(含全局题材库与反 AI 规则库)。 */\nexport interface AssetsResponse {\n projectAssets: ProjectAssets\n /** 全局题材基底库(可复用资产,跨书)。 */\n genreLibrary: GenreNode[]\n /** 全局反 AI 规则库(内置默认规则)。 */\n antiAiLibrary: AntiAiRule[]\n /** 预置写法模板(一键绑定,无需样本文本)。 */\n styleTemplates: StyleTemplate[]\n /** 内置推进模式候选。 */\n progressionLibrary: ProgressionMode[]\n}\n\n/** POST /assets request:更新项目写作资产(部分字段可选)。 */\nexport interface AssetsPatch {\n genre?: GenreNode\n primaryProgression?: ProgressionMode\n auxiliaryProgressions?: ProgressionMode[]\n antiAiRules?: AntiAiRule[]\n styleAssets?: StyleAsset[]\n}\n\n/** POST /style-engine request:从样本文本提取写法资产。 */\nexport interface StyleEngineRequest {\n /** 样本文本(风格来源)。 */\n sampleText: string\n /** 资产名(可选,默认「风格资产 N」)。 */\n name?: string\n}\n","/**\n * docx outline extraction: a .docx is a zip whose word/document.xml holds the\n * body text in <w:t> runs inside <w:p> paragraphs. We unzip with fflate and\n * walk the XML with a tiny tokenizer — no heavyweight XML/DOM dependency.\n */\n\nimport { readFileSync } from 'node:fs'\nimport { unzipSync, strFromU8 } from 'fflate'\n\n/** Decode the handful of XML entities docx bodies actually use. */\nfunction decodeEntities(text: string): string {\n return text\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&apos;/g, \"'\")\n .replace(/&amp;/g, '&')\n .replace(/&nbsp;/g, ' ')\n}\n\n/**\n * Extract plain text from a docx buffer: one line per <w:p> paragraph, with\n * <w:tab>/<w:br> preserved as whitespace. Tables and nested structures are\n * flattened in document order (their paragraphs are just <w:p> too).\n * @param buffer - the raw .docx bytes.\n * @returns the body text.\n */\nexport function extractDocxText(buffer: Uint8Array): string {\n let files: ReturnType<typeof unzipSync>\n try {\n files = unzipSync(buffer)\n } catch (error) {\n throw new Error(`not a valid docx (zip open failed): ${(error as Error).message}`)\n }\n const document = files['word/document.xml']\n if (document === undefined) {\n throw new Error('not a valid docx (word/document.xml missing)')\n }\n const xml = strFromU8(document)\n\n const paragraphs: string[] = []\n // Split on paragraph boundaries; keep the segment text of each.\n const parts = xml.split(/<w:p\\b[^>]*>/)\n for (let i = 1; i < parts.length; i++) {\n const segment = parts[i]!\n // Runs <w:t ...>…</w:t>; also honor <w:tab/> and <w:br/> as spaces.\n const runs: string[] = []\n const runRe = /<w:t(?:\\s[^>]*)?>([\\s\\S]*?)<\\/w:t>|<w:tab\\b[^>]*\\/>|<w:br\\b[^>]*\\/>/g\n for (const match of segment.matchAll(runRe)) {\n if (match[0].startsWith('<w:tab')) {\n runs.push('\\t')\n } else if (match[0].startsWith('<w:br')) {\n runs.push('\\n')\n } else {\n runs.push(decodeEntities(match[1] ?? ''))\n }\n }\n const line = runs.join('').replace(/\\u00a0/g, ' ').trimEnd()\n paragraphs.push(line)\n }\n\n // Collapse 3+ blank lines and trim.\n const text = paragraphs.join('\\n').replace(/\\n{3,}/g, '\\n\\n').trim()\n if (text.length === 0) {\n throw new Error('docx contains no extractable text')\n }\n return text\n}\n\n/**\n * Read and extract a docx outline from disk.\n * @param path - absolute path to the .docx file.\n * @returns the extracted outline text.\n */\nexport function readOutlineFromDocx(path: string): string {\n let buffer: Buffer\n try {\n buffer = readFileSync(path)\n } catch (error) {\n throw new Error(`cannot read outline file \"${path}\": ${(error as Error).message}`)\n }\n return extractDocxText(new Uint8Array(buffer))\n}\n","/**\n * AI assistant engine — a conversational editor over the novel project.\n *\n * The user talks to the assistant about plot, characters, settings; the\n * assistant can reply in prose AND emit action directives that the host\n * executes (rewrite a paragraph, edit the bible, regenerate a chapter,\n * export the book, ...). Conversation history persists next to the project\n * as NDJSON, so a reload keeps the thread.\n *\n * Action protocol: the model emits a line of the form\n * <dsh-action name=\"toolName\">{jsonArgs}</dsh-action>\n * anywhere in its reply. The host strips it, executes the tool, appends the\n * result as a tool-role message, and continues the loop (bounded rounds).\n */\n\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, appendFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { createUserMessage, createAssistantMessage, BlockAssembler, type GenerateOptions, type Message, type StreamChunk, type ContentBlock } from '@deepseek-ai/dsh-llm'\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { AssistantMessage, NovelConfig, ProjectState } from './protocol.ts'\nimport { emptyProjectAssets } from './assets.ts'\nimport {\n analyzeImpact,\n bookOverview,\n chapterFileName,\n exportBook,\n generateChapterStream,\n readChapterFile,\n reviewChapter,\n saveProject,\n summarizeAndExtractFacts,\n} from './engine.ts'\nimport { rewriteChapterStream } from './engine.ts'\n\n/** History file name inside the output dir. */\nexport const ASSISTANT_HISTORY_FILE = 'novel-assistant.jsonl'\n\n/** Max tool-call rounds per user turn (safety bound). */\nconst MAX_TOOL_ROUNDS = 6\n\n/** Max history messages kept in context (older ones summarized away). */\nconst MAX_HISTORY_MESSAGES = 18\n\n// ------------------------------------------------------------------ history\n\n/** Load the persisted conversation (empty when none). */\nexport function loadAssistantHistory(outputDir: string): AssistantMessage[] {\n const file = join(outputDir, ASSISTANT_HISTORY_FILE)\n if (!existsSync(file)) return []\n const messages: AssistantMessage[] = []\n try {\n for (const line of readFileSync(file, 'utf8').split('\\n')) {\n if (line.trim() === '') continue\n try {\n const parsed = JSON.parse(line) as AssistantMessage\n if (typeof parsed.role === 'string' && typeof parsed.content === 'string') messages.push(parsed)\n } catch { /* skip malformed line */ }\n }\n } catch { /* unreadable history -> start fresh */ }\n return messages\n}\n\n/** Append one message to the persisted history. Tool payloads (e.g. full\n * outline / chapter text) are capped so the jsonl and later LLM context\n * don't grow unboundedly. */\nfunction appendHistory(outputDir: string, message: AssistantMessage): void {\n mkdirSync(outputDir, { recursive: true })\n const entry: AssistantMessage = message.role === 'tool' && message.content.length > 4000\n ? { ...message, content: message.content.slice(0, 4000) + '\\n…(已截断,如需完整内容请重新调用工具)' }\n : message\n appendFileSync(join(outputDir, ASSISTANT_HISTORY_FILE), JSON.stringify(entry) + '\\n', 'utf8')\n}\n\n/** 清空助手对话记录(删除历史文件)。 */\nexport function clearAssistantHistory(outputDir: string): void {\n const file = join(outputDir, ASSISTANT_HISTORY_FILE)\n if (existsSync(file)) rmSync(file, { force: true })\n}\n\n// ----------------------------------------------------------------- context\n\n/** Render the project snapshot the assistant sees. */\nfunction renderProjectSnapshot(project: ProjectState): string {\n const sections: string[] = []\n sections.push(`书名:${project.bookName}`)\n sections.push(`总纲节选(如需全文用 outline_text 工具):\\n${project.outline.slice(0, 2500)}`)\n // 写作资产名称化(占位小,需要详情用 assets_status)。\n const assetNames: string[] = []\n if (project.assets?.genre !== undefined) assetNames.push(`题材:${project.assets.genre.name}`)\n if (project.assets?.primaryProgression !== undefined) assetNames.push(`主推进:${project.assets.primaryProgression.name}`)\n if ((project.assets?.styleAssets?.length ?? 0) > 0) assetNames.push(`写法:${project.assets!.styleAssets!.map(s => s.name).join('、')}`)\n if ((project.assets?.antiAiRules?.length ?? 0) > 0) assetNames.push(`文戒自定义:${project.assets!.antiAiRules!.map(r => r.name).join('、')}`)\n if (assetNames.length > 0) sections.push(`【写作资产】${assetNames.join(' · ')}`)\n if (project.bible !== undefined) {\n const bible = project.bible\n sections.push('【道藏】')\n if (bible.genre !== '') sections.push(`题材基调:${bible.genre}`)\n if (bible.worldRules.length > 0) sections.push('世界规则:\\n' + bible.worldRules.map(r => `- ${r}`).join('\\n'))\n if (bible.characters.length > 0) {\n sections.push('角色卡:')\n for (const card of bible.characters) {\n const roleName = { protagonist: '主角', supporting: '配角', antagonist: '反派', other: '其他' }[card.role]\n sections.push(`- ${card.name}(${roleName}):${card.traits.join('、')}${card.goals !== '' ? `;目标:${card.goals}` : ''}`)\n }\n }\n if (bible.redLines.length > 0) sections.push('写作红线:\\n' + bible.redLines.map(r => `- ${r}`).join('\\n'))\n }\n if (project.world !== undefined) {\n const world = project.world\n sections.push('【大世界】')\n if (world.realms.length > 0) sections.push('境界体系:' + world.realms.map((r, i) => `${i + 1}.${r.name}(${r.description.slice(0, 40)})`).join(' → '))\n if (world.regions.length > 0) sections.push('区域:' + world.regions.map(r => r.name).join('、'))\n if (world.factions.length > 0) sections.push('势力:' + world.factions.map(f => `${f.name}(${f.kind})`).join('、'))\n }\n if (project.volumes !== undefined && project.volumes.length > 0) {\n sections.push('【卷结构】')\n for (const v of project.volumes) {\n sections.push(`第${v.no}卷《${v.title}》:${v.summary}(章节 ${v.chapterStart}-${v.chapterEnd})`)\n }\n }\n if (project.chapters.length > 0) {\n // 快照只列最近 30 章(长书时防止上下文膨胀;更早章节可用\n // book_overview scope=volume:N 或 chapter_text 按需查看)。\n const shown = project.chapters.slice(-30)\n sections.push(`【章节计划与进度(最近 ${shown.length} 章)】`)\n for (const c of shown) {\n const statusText = { pending: '待生成', generating: '生成中', written: '待审稿', reviewing: '审稿中', approved: '已通过', rejected: '待修订', error: '失败' }[c.status]\n sections.push(`第${c.no}章《${c.title}》[${statusText}]${c.chars !== undefined ? ` ${c.chars}字` : ''}${c.summary !== undefined && c.summary !== '' ? ` 摘要:${c.summary}` : ''}`)\n }\n if (project.chapters.length > shown.length) {\n sections.push(`(还有 ${project.chapters.length - shown.length} 章未列出,可用 book_overview scope=volume:N 查看)`)\n }\n // 最近两章正文节选(讨论细节时参考)\n const written = project.chapters.filter(c => c.status === 'approved' || c.status === 'written')\n const recent = written.slice(-2)\n if (recent.length > 0) {\n sections.push('【最近章节正文节选】')\n for (const c of recent) {\n sections.push(`第${c.no}章《${c.title}》(节选,如需全文用 chapter_text):${c.beats.slice(0, 300)}`)\n }\n }\n }\n if (project.foreshadows.length > 0) {\n sections.push('【暗线】')\n for (const f of project.foreshadows) {\n sections.push(`- [${f.status}] ${f.description}${f.targetChapter !== undefined ? `(预计 ${f.targetChapter} 章回收)` : ''}`)\n }\n }\n if ((project.facts ?? []).length > 0) {\n sections.push('【已确立编年录(最近 40 条,回答设定问题必须遵守)】')\n for (const f of (project.facts ?? []).slice(-40)) {\n sections.push(`- [第${f.chapterNo}章] ${f.text}`)\n }\n }\n if (project.blurb !== undefined && project.blurb !== '') {\n sections.push(`【卷首语】${project.blurb}`)\n }\n return sections.join('\\n')\n}\n\n/** The assistant system prompt. */\nfunction assistantSystemPrompt(project: ProjectState): string {\n return [\n '你是「编辑老师」——服务这本书作者的资深中文网文编辑。',\n '人设:二十年网文老编辑,懂套路、懂市场、懂节奏,说话直接但句句有用。',\n '座右铭:「书是你的,但坑我替你盯着。」',\n '职责边界:陪作者讨论剧情/人设/世界观/爽点节奏并落地修改、维护全书一致性;不闲聊、不彩虹屁、不无意义长篇大论。',\n '==================== 模块正式名称(回复作者时一律使用,禁止使用括号里的旧称) ====================',\n '总纲 = 总纲;道藏 = 道藏;暗线 = 暗线;卷首语 = 卷首语;编年录 = 编年录。',\n '==================== 当前项目快照 ====================',\n renderProjectSnapshot(project),\n '==================== 快照结束 ====================',\n '',\n '工作规则(严格遵守):',\n '1. 全量知情:回答和修改必须基于项目真实数据,禁止编造书中不存在的设定。需要完整信息时,先调用 book_overview 获取全书上下文(总纲全文/道藏/大世界/编年录/全部章节要点/暗线/卷首语);需要某章正文用 chapter_text。',\n '2. 修改流程:改前用一句话说明意图 → 执行工具 → 改后简要汇报。',\n '3. 连锁维护:改动可能波及其它位置(其它章节、设定、编年录、卷首语)时,执行后主动调用 impact_analysis 分析影响面,并把「必须同步」的项一并处理或明确提示作者逐项确认。',\n '4. 删除红线:删除章节、清空设定等破坏性操作必须等作者明确同意。',\n '5. 品质门槛:建议必须具体——指出问题在哪一章、哪一段、哪一句,并给出可落地的改法;禁止\"建议增强冲突\"这类空话。',\n '6. 设定忠诚:忠于总纲、道藏、大世界、编年录;发现书中已有内容与设定冲突时,主动指出并给修正方案。',\n '7. 中文回复,简洁有干货。',\n '',\n '可用工具:',\n '- book_overview:{\"scope\": \"recent|full|volume:2\"(可选,默认 recent)}。返回全书上下文包(总纲/道藏/大世界/章节要点/编年录/暗线/卷首语)。recent=最近30章;full=全部章节(书很长时慎用);volume:N=只看第N卷。',\n '- facts_query:{\"keyword\": \"关键词\"}。从编年录按关键词检索相关事实(如灵石、境界名、人物名)。',\n '- impact_analysis:{\"change\": \"要做的修改描述\"}。分析这次改动会波及哪些位置,返回影响清单(定位到章节/设定/编年录)。',\n '- outline_text:无参数。返回当前总纲全文。',\n '- outline_replace:{\"old\": \"要替换的原文片段\", \"new\": \"新文本\"}。在总纲中替换一段文字(old 必须能在总纲中找到)。',\n '- bible_set_rule:{\"index\": 序号(0起), \"text\": \"新规则文本\"} 或 {\"append\": \"追加的规则\"}。修改道藏的世界规则。',\n '- bible_set_redline:同上,修改写作红线。',\n '- chapter_text:{\"no\": 章节号}。返回该章正文。',\n '- chapter_rewrite:{\"no\": 章节号, \"instructions\": \"修改要求\", \"target\": \"原文片段(可选,留空整章)\"}。按讨论结果修订章节;给了 target 只改该自然段。',\n '- chapter_generate:{\"no\": 章节号}。重新生成该章。',\n '- chapter_review:{\"no\": 章节号}。对该章执行 AI 审稿。',\n '- foreshadow_add:{\"description\": \"暗线描述\", \"targetChapter\": 预计回收章(可选)}。新增暗线。',\n '- foreshadow_update:{\"id\": \"暗线id\", \"status\": \"planned|planted|progressing|resolved|abandoned\"}。更新暗线状态。',\n '- export_txt:无参数。导出全本 TXT。',\n '- assets_status:无参数。查看本书当前写作资产(题材/推进模式/反AI规则/写法)。',\n '- assets_set_genre:{\"name\": \"题材名\", \"description\": \"题材说明(可选)\"}。设置本书题材基底。',\n '- assets_set_progression:{\"name\": \"模式名\", \"driver\": \"驱动力\", \"primary\": true/false}。设置主/辅助推进模式。',\n '- assets_add_rule:{\"name\": \"规则名(可选)\", \"avoid\": \"要避免的表达问题\", \"fix\": \"修正方向(可选)}。新增反 AI 规则。',\n '',\n '回答质量要求(非常重要):',\n '- 具体:回答必须引用项目里的真实内容(人名、境界、章节、暗线、设定),禁止空泛套话。快照里没有的信息,先调用工具获取(chapter_text / outline_text)再回答。',\n '- 专业:给建议时说明理由,指出问题所在章节/段落,给出可直接落地的修改方案(改什么、怎么改)。',\n '- 主动:作者说\"改一下\",主动调用对应工具执行,不要只给建议不动手;执行前用一句话说明意图,执行后简短汇报结果。',\n '- 忠于设定:以总纲、道藏、编年录为准,不得自相矛盾;发现问题(如剧情与设定冲突)主动指出。',\n '- 中文回复;文字量适中,别啰嗦。',\n '',\n '使用规则(非常重要):',\n '- 写操作(chapter_generate / chapter_rewrite / chapter_review / outline_replace / bible_set_* / foreshadow_* / assets_set_* / export_txt)只有在作者明确要求时才能调用——例如作者说\"生成第 120 章\"\"把第 105 章结尾改一下\"\"帮我审一下第 88 章\"。作者只是提问、闲聊、查信息时,一律用文字回答,禁止调用任何写操作,也不要先斩后奏(如\"为了回答你,我先把第 X 章生成了\")。',\n '- 当你想执行任何工具时,你的【整个回复】必须只包含动作指令标签,格式如下(不要有任何解释文字、不要用自然语言说\"我要去改\",直接输出标签):',\n ' 正确示例:<dsh-action name=\"outline_replace\">{\"old\":\"要替换的原文\",\"new\":\"新文本\"}</dsh-action>',\n ' 正确示例:<dsh-action name=\"chapter_text\">{\"no\":1}</dsh-action>',\n ' 错误示例(绝对不要这样回复):\"好的,我先看一下总纲,马上改。\" ← 这只是文字,不会执行任何操作',\n ' 错误示例(绝对不要这样回复):\"先拉完整上下文确认改动落地情况,避免继续空转。\" ← 没有动作标签,不会执行任何操作',\n ' 错误示例(绝对不要这样回复):\"现在处理暗线库,我先看当前列表定位 id。\" ← 没有动作标签,不会执行任何操作',\n '- 铁律:只要你想执行任何操作,你的【整个回复】必须只包含一个动作标签,禁止先说话、禁止解释\"我要做什么\"、禁止铺垫——直接输出标签。',\n '- 如果你收到「格式提示」(宿主说你没有输出动作标签):你的下一条回复必须只输出动作标签,禁止再解释、禁止再道歉、禁止再描述计划。',\n '- 工具调用是自动的:你输出标签后,宿主会执行并把结果反馈给你,你再基于结果继续。',\n '- 每次回复最多调用 1 个动作;执行结果会反馈给你,你可以继续讨论或再调用。',\n '- 需要先看总纲/章节再决定怎么改?那就先输出一个 outline_text / chapter_text 的标签,等结果回来。',\n '- chapter_rewrite 的 target 参数:从章节正文中复制一小段(一句话或几句话即可),不要带换行、不要带引号,取连续文本片段。',\n '- 如果工具执行失败(例如片段未找到),根据错误信息修正参数后自动重试一次,不要直接放弃或让作者手动操作。',\n '- 修改前先向作者说明你要改什么、为什么;动作执行后简要汇报结果。',\n '- 涉及删除类操作(删除章节、清空设定)必须等作者明确同意。',\n '- 严格忠于道藏与总纲;不得自行发明与既有设定冲突的内容。',\n '- 用中文回复。',\n ].join('\\n')\n}\n\n// ------------------------------------------------------------- action exec\n\n/** Execute one action directive. Returns a text result (or throws). */\n/**\n * Execute one action directive as an async generator: yields live progress\n * text (chapter text being generated/rewritten), then yields the final result\n * string. Throws on failure.\n */\nexport async function* executeAction(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n name: string,\n args: Record<string, unknown>,\n): AsyncGenerator<string, string, unknown> {\n const str = (value: unknown): string => typeof value === 'string' ? value : ''\n const num = (value: unknown): number | undefined => typeof value === 'number' ? value : undefined\n\n /** Forward live text deltas from a streaming chapter job (text only). */\n const forward = async function* (stream: AsyncGenerator<{ frame: 'start' } | { frame: 'delta'; text: string } | { frame: 'done'; file: string; chars: number } | { frame: 'drafted'; chars: number; draft: string }, void, unknown>): AsyncGenerator<string, void, unknown> {\n for await (const step of stream) {\n if (step.frame === 'delta') yield step.text\n }\n }\n\n switch (name) {\n case 'book_overview': {\n // 全书上下文包(分片:默认最近 30 章;scope=full 全量;scope=volume:N 指定卷)。\n const scopeArg = str(args.scope)\n const scope = scopeArg === 'full'\n ? 'full' as const\n : /^volume:(\\d+)$/.test(scopeArg)\n ? Number(scopeArg.slice(7))\n : 'recent' as const\n return bookOverview(project, scope)\n }\n case 'facts_query': {\n // 从编年录按关键词检索相关事实。\n const keyword = str(args.keyword).trim()\n if (keyword === '') throw new Error('facts_query 需要 keyword')\n const hits = (project.facts ?? []).filter(f => f.text.includes(keyword)).slice(-30)\n if (hits.length === 0) return `编年录中未找到与「${keyword}」相关的事实记录。`\n return `编年录中与「${keyword}」相关的事实(${hits.length} 条):\\n` + hits.map(f => `- [第${f.chapterNo}章] ${f.text}`).join('\\n')\n }\n case 'impact_analysis': {\n const change = str(args.change)\n if (change === '') throw new Error('impact_analysis 需要 change(要做的修改描述)')\n const items = await analyzeImpact(ctx, config, project, outputDir, change)\n if (items.length === 0) return '影响分析:未发现需要同步修改的位置。'\n const lines = items.map((it, i) => `${i + 1}. [${it.location}]「${it.quote}」${it.suggestion !== '' ? ` → ${it.suggestion}` : ''}(${it.kind === 'must' ? '必须同步' : it.kind === 'optional' ? '建议' : '备注'})`)\n return `影响分析:这次改动波及 ${items.length} 处——\\n${lines.join('\\n')}\\n请据此提示作者逐项处理;章节内的修改可引导作者在工作区查看。`\n }\n case 'outline_text': {\n return project.outline\n }\n case 'outline_replace': {\n const old = str(args.old)\n const next = str(args.new)\n if (old === '' || !project.outline.includes(old)) {\n throw new Error(`总纲中未找到片段「${old.slice(0, 40)}…」`)\n }\n project.outline = project.outline.replace(old, next)\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `总纲已修改:替换了 ${old.length} 字符的片段。`\n }\n case 'bible_set_rule': {\n if (project.bible === undefined) throw new Error('尚无道藏,请先提炼')\n const index = num(args.index)\n if (index !== undefined) {\n project.bible.worldRules[index] = str(args.text)\n } else if (str(args.append) !== '') {\n project.bible.worldRules.push(str(args.append))\n } else {\n throw new Error('bible_set_rule 需要 index+text 或 append')\n }\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `世界规则已更新(当前 ${project.bible.worldRules.length} 条)。`\n }\n case 'bible_set_redline': {\n if (project.bible === undefined) throw new Error('尚无道藏,请先提炼')\n const index = num(args.index)\n if (index !== undefined) {\n project.bible.redLines[index] = str(args.text)\n } else if (str(args.append) !== '') {\n project.bible.redLines.push(str(args.append))\n } else {\n throw new Error('bible_set_redline 需要 index+text 或 append')\n }\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `写作红线已更新(当前 ${project.bible.redLines.length} 条)。`\n }\n case 'chapter_text': {\n const no = num(args.no)\n if (no === undefined) throw new Error('chapter_text 需要 no')\n const chapter = project.chapters.find(c => c.no === no)\n if (chapter === undefined) throw new Error(`章节 ${no} 不存在`)\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) throw new Error(`章节 ${no} 尚未生成`)\n return body\n }\n case 'chapter_rewrite': {\n const no = num(args.no)\n if (no === undefined) throw new Error('chapter_rewrite 需要 no')\n const instructions = str(args.instructions)\n const target = str(args.target)\n for await (const chunk of forward(rewriteChapterStream(ctx, config, project, outputDir, no, instructions, target === '' ? undefined : target))) {\n yield chunk\n }\n // Draft mode: the assistant acts on the user's explicit instruction, so\n // apply the draft immediately — summarize/review must see the new body.\n const chapter = project.chapters.find(c => c.no === no)\n const draft = chapter?.pendingDraft\n if (chapter === undefined || draft === undefined || draft === '') {\n throw new Error(`章节 ${no} 修订后没有产出草稿`)\n }\n const fileName = chapterFileName(chapter)\n mkdirSync(outputDir, { recursive: true })\n writeFileSync(join(outputDir, fileName), `# 第${chapter.no}章 ${chapter.title}\\n\\n${draft}\\n`, 'utf8')\n chapter.pendingDraft = undefined\n chapter.status = 'written'\n chapter.chars = draft.length\n chapter.file = fileName\n chapter.review = undefined\n chapter.error = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n yield '(已采纳修订稿,正在生成章节摘要与编年录…)'\n try {\n await summarizeAndExtractFacts(ctx, config, project, outputDir, no)\n } catch { /* best-effort */ }\n yield '(正在 AI 审稿…)'\n const report = await reviewChapter(ctx, config, project, outputDir, no)\n return `章节 ${no} 已${target === '' ? '整章' : '局部'}修订完成(${project.chapters.find(c => c.no === no)?.chars ?? '?'} 字)。重新审稿:${report.score} 分 — ${report.verdict}`\n }\n case 'chapter_generate': {\n const no = num(args.no)\n if (no === undefined) throw new Error('chapter_generate 需要 no')\n for await (const chunk of forward(generateChapterStream(ctx, config, project, outputDir, no))) {\n yield chunk\n }\n yield '(正在生成章节摘要与编年录…)'\n try {\n await summarizeAndExtractFacts(ctx, config, project, outputDir, no)\n } catch { /* best-effort */ }\n yield '(正在 AI 审稿…)'\n const report = await reviewChapter(ctx, config, project, outputDir, no)\n return `章节 ${no} 已生成(${project.chapters.find(c => c.no === no)?.chars ?? '?'} 字)。审稿:${report.score} 分 — ${report.verdict}`\n }\n case 'chapter_review': {\n const no = num(args.no)\n if (no === undefined) throw new Error('chapter_review 需要 no')\n const report = await reviewChapter(ctx, config, project, outputDir, no)\n const issues = report.issues.map(i => `[${i.severity}] ${i.item} → ${i.suggestion}`).join('\\n')\n return `章节 ${no} 审稿:${report.score} 分 — ${report.verdict}\\n${issues}`\n }\n case 'foreshadow_add': {\n const description = str(args.description)\n if (description === '') throw new Error('foreshadow_add 需要 description')\n const targetChapter = num(args.targetChapter)\n project.foreshadows.push({\n id: `fs-${Date.now().toString(36)}`,\n description,\n targetChapter,\n status: 'planned',\n })\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `已新增暗线:「${description.slice(0, 50)}」`\n }\n case 'foreshadow_update': {\n const id = str(args.id)\n const status = str(args.status) as 'planned' | 'planted' | 'progressing' | 'resolved' | 'abandoned'\n const target = project.foreshadows.find(f => f.id === id)\n if (target === undefined) throw new Error(`暗线 ${id} 不存在`)\n if (!['planned', 'planted', 'progressing', 'resolved', 'abandoned'].includes(status)) {\n throw new Error(`非法状态 ${status}`)\n }\n target.status = status\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `暗线已更新为 ${status}:「${target.description.slice(0, 50)}」`\n }\n case 'export_txt': {\n const result = exportBook(outputDir, project, 'txt')\n return `已导出 TXT:${result.file}(${result.chars} 字,${result.chapters} 章)`\n }\n case 'assets_status': {\n const assets = project.assets\n if (assets === undefined) return '本书尚未配置写作资产。'\n const parts: string[] = []\n if (assets.genre !== undefined) parts.push(`题材:${assets.genre.name}`)\n if (assets.primaryProgression !== undefined) parts.push(`主推进:${assets.primaryProgression.name}`)\n if (assets.auxiliaryProgressions.length > 0) parts.push(`辅助推进:${assets.auxiliaryProgressions.map(m => m.name).join('、')}`)\n if (assets.antiAiRules.length > 0) parts.push(`自定义反AI规则:${assets.antiAiRules.map(r => r.name).join('、')}`)\n if (assets.styleAssets.length > 0) parts.push(`写法资产:${assets.styleAssets.map(s => s.name).join('、')}`)\n return parts.length > 0 ? parts.join('\\n') : '本书尚未配置写作资产。'\n }\n case 'assets_set_genre': {\n const name = str(args.name)\n const description = str(args.description)\n if (name === '') throw new Error('assets_set_genre 需要 name')\n if (project.assets === undefined) project.assets = emptyProjectAssets()\n project.assets.genre = { name, description, children: [] }\n project.assets.updatedAt = new Date().toISOString()\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `题材已设为「${name}」`\n }\n case 'assets_set_progression': {\n const name = str(args.name)\n const driver = str(args.driver)\n const primary = args.primary !== false\n if (name === '') throw new Error('assets_set_progression 需要 name')\n if (project.assets === undefined) project.assets = emptyProjectAssets()\n const mode = {\n name,\n driver: driver !== '' ? driver : name,\n readerExpectation: str(args.readerExpectation),\n payoffs: Array.isArray(args.payoffs) ? args.payoffs.filter((v): v is string => typeof v === 'string') : [],\n risks: Array.isArray(args.risks) ? args.risks.filter((v): v is string => typeof v === 'string') : [],\n primary,\n }\n if (primary) project.assets.primaryProgression = mode\n else {\n if (project.assets.auxiliaryProgressions === undefined) project.assets.auxiliaryProgressions = []\n project.assets.auxiliaryProgressions.push(mode)\n }\n project.assets.updatedAt = new Date().toISOString()\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `推进模式${primary ? '(主)' : '(辅助)'}已设置:「${name}」`\n }\n case 'assets_add_rule': {\n const name = str(args.name)\n const avoid = str(args.avoid)\n if (avoid === '') throw new Error('assets_add_rule 需要 avoid(要避免的表达问题)')\n if (project.assets === undefined) project.assets = emptyProjectAssets()\n if (project.assets.antiAiRules === undefined) project.assets.antiAiRules = []\n project.assets.antiAiRules.push({\n name: name !== '' ? name : `自定义规则 ${project.assets.antiAiRules.length + 1}`,\n avoid,\n fix: str(args.fix),\n })\n project.assets.updatedAt = new Date().toISOString()\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `已新增反 AI 规则「${name !== '' ? name : avoid.slice(0, 20)}」`\n }\n default:\n throw new Error(`未知工具 ${name}`)\n }\n}\n\n// ------------------------------------------------------------------- chat\n\n/** Extract the first action directive from a reply (tolerant to common tag misspellings). */\nfunction extractAction(reply: string): { name: string; args: Record<string, unknown>; index: number } | undefined {\n // 容错:dsh-action 的常见误拼(dash-action / dsah-action / dhs-action 等)。\n const match = /<([a-z_]*d[a-z]?sh?-action)\\s+name=\"([^\"]+)\"\\s*>([\\s\\S]*?)<\\/\\1>/.exec(reply)\n if (match === null) return undefined\n const rawArgs = match[3]?.trim() ?? ''\n let args: Record<string, unknown>\n try {\n args = rawArgs === '' ? {} : JSON.parse(rawArgs) as Record<string, unknown>\n } catch {\n throw new Error(`动作参数不是合法 JSON:${rawArgs.slice(0, 80)}`)\n }\n return { name: match[2] ?? '', args, index: match.index }\n}\n\n/** Render the recent history as LLM messages (skipping tool chatter in early rounds). */\nfunction historyToMessages(history: AssistantMessage[]): Message[] {\n const recent = history.slice(-MAX_HISTORY_MESSAGES)\n const messages: Message[] = []\n for (const entry of recent) {\n if (entry.role === 'user') {\n messages.push(createUserMessage({\n content: [{ type: 'text', text: entry.content }],\n source: { kind: 'plugin', plugin: 'dsh-novel-forge' },\n }))\n } else if (entry.role === 'assistant') {\n messages.push(createAssistantMessage({\n content: [{ type: 'text', text: entry.content }],\n source: { provider: 'deepseek-official', model: 'deepseek-v4-flash' },\n }))\n } else if (entry.role === 'tool') {\n // 工具结果(book_overview/总纲全文等可能很大)截断后进上下文,\n // 避免多轮对话上下文翻倍膨胀触发「上下文到限制」。\n const body = entry.content.length > 2000\n ? entry.content.slice(0, 2000) + '\\n…(结果过长已截断,需要完整内容请重新调用工具)'\n : entry.content\n messages.push(createUserMessage({\n content: [{ type: 'text', text: `【工具 ${entry.tool ?? ''} 的执行结果】\\n${body}` }],\n source: { kind: 'plugin', plugin: 'dsh-novel-forge' },\n }))\n }\n }\n return messages\n}\n\n/** One non-streaming LLM chat turn (used inside the tool loop). */\nasync function chatOnce(\n ctx: Context,\n config: NovelConfig,\n system: string,\n history: AssistantMessage[],\n): Promise<string> {\n const messages = historyToMessages(history)\n // 纪律提醒贴在最后一条消息(当前用户输入)末尾:紧邻模型要生成回复的位置,\n // 比放在 system 里更不容易被长上下文稀释(位置效应)。\n // 注意:dsh-llm 的消息/内容块对象是只读的,必须重建新对象,不能直接改属性。\n const last = messages[messages.length - 1]\n if (last?.role === 'user' && Array.isArray(last.content)) {\n const blocks = last.content as ContentBlock[]\n const idx = blocks.findIndex(b => b.type === 'text')\n if (idx !== -1) {\n const textBlock = blocks[idx] as { type: 'text'; text: string }\n const newBlocks: ContentBlock[] = blocks.map((b, i) => i === idx\n ? { ...textBlock, text: textBlock.text + '\\n\\n(回复格式提醒:如果你需要执行任何操作,你的回复必须【只包含】一个 <dsh-action name=\"工具名\">{\"参数\":值}</dsh-action> 标签,禁止先说话、禁止解释、禁止铺垫;如果你只是在回答或讨论,正常回复即可,不要输出标签。)' }\n : b)\n messages[messages.length - 1] = { ...last, content: newBlocks }\n }\n }\n const request: GenerateOptions = {\n provider: config.provider,\n model: config.model,\n messages,\n system,\n // v4-flash 推理模型:reasoning channel 占预算,给足避免回复被截断。\n maxTokens: Math.max(config.maxTokens, 16000),\n temperature: 0.7,\n }\n const assembler = new BlockAssembler()\n for await (const chunk of ctx.llm.stream(request)) {\n assembler.push(chunk)\n }\n const finish = assembler.finish\n if (finish.kind === 'error' || finish.kind === 'aborted') {\n throw new Error(`助手调用失败(${finish.kind}): ${finish.failure.message}`)\n }\n const blocks = assembler.blocks()\n const textBlocks = blocks\n .filter((block): block is Extract<StreamChunk, { type: 'block-end' }>['block'] & { type: 'text' } => block.type === 'text')\n .map(block => block.text)\n let text = textBlocks.join('\\n').trim()\n if (text === '') {\n const reasoning = blocks\n .filter((block): block is { type: 'reasoning'; text: string } => block.type === 'reasoning')\n .map(block => block.text)\n .join('\\n')\n .trim()\n if (reasoning !== '') text = reasoning\n }\n return text\n}\n\n/** Run one user turn. Yields stream frames; persists history. */\nexport async function* runAssistantTurn(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n userMessage: string,\n): AsyncGenerator<\n | { frame: 'delta'; text: string }\n | { frame: 'tool'; name: string; status: 'start' | 'done' | 'error'; detail?: string }\n | { frame: 'toolDelta'; name: string; text: string },\n void,\n unknown\n> {\n const history = loadAssistantHistory(outputDir)\n const system = assistantSystemPrompt(project)\n\n // Persist the user message.\n const userEntry: AssistantMessage = { role: 'user', content: userMessage, ts: new Date().toISOString() }\n history.push(userEntry)\n appendHistory(outputDir, userEntry)\n\n let round = 0\n /** 已提示模型输出动作标签的次数(0 = 尚未提示;超过上限则按纯文字回复结束,防死循环)。 */\n let nudged = 0\n const MAX_NUDGES = 6\n /** 连续收到 hex 乱码回复的次数(≥2 次判定 LLM 侧异常,放弃本轮避免死循环)。 */\n let garbleCount = 0\n\n // ---- 写操作意图守卫 ------------------------------------------------\n // 写类工具会改动项目数据/正文文件:仅当用户消息(含最近一轮上下文)里\n // 出现与该工具对应的明确修改动词时才放行;否则拒绝执行,防止\"随口一问\"\n // 被模型误判成创作指令(如问角色是否登场 → 自主生成整章)。\n const WRITE_TOOL_KEYS: Record<string, RegExp> = {\n chapter_generate: /(生成|写第\\s*\\d+\\s*章|写一[章篇]|新写|续写|接着写|继续写|开始写|写正文|写书|创作)/,\n chapter_rewrite: /(重写|改写|修订|修改|改一下|调整|替换|润色|优化|修正|完善|回炉|换一种|从头)/,\n chapter_review: /(审|检查|校验|点评|评估|把关|质量|怎么样|如何)/,\n outline_replace: /(大纲|总纲|简介)/,\n bible_set_rule: /(道藏|设定|规则|红线|世界|金手指)/,\n bible_set_redline: /(道藏|设定|红线)/,\n foreshadow_add: /(暗线|伏笔|埋)/,\n foreshadow_update: /(暗线|伏笔)/,\n export_txt: /(导出|打包|下载|txt)/,\n assets_set_genre: /(题材)/,\n assets_set_progression: /(推进)/,\n assets_add_rule: /(规则|文戒|反AI)/,\n }\n /** 本轮已放行过写操作:后续写操作(生成→审稿→修订闭环)不再逐个拦截。 */\n let writeUnlocked = false\n const guardWrite = (name: string, userMessage: string): boolean => {\n if (writeUnlocked) return true\n const key = WRITE_TOOL_KEYS[name]\n if (key === undefined) return true // 只读工具 / 未登记工具一律放行\n // 近两轮用户消息合并判断(支持\"继续\"类延续指令)。\n const recentUsers = history\n .filter(m => m.role === 'user')\n .slice(-2)\n .map(m => m.content)\n .join('\\n')\n if (key.test(recentUsers)) {\n writeUnlocked = true\n return true\n }\n return false\n }\n for (;;) {\n if (round++ > 20) break\n const reply = await chatOnce(ctx, config, system, history)\n\n // 异常输出防护:全 hex/二进制乱码(模型偶发把回复编码成十六进制)——丢弃重试一次。\n const hexLike = reply.length > 120 && /^[0-9a-fA-F\\s]+$/.test(reply.slice(0, 2000))\n if (hexLike) {\n garbleCount++\n if (garbleCount >= 2) {\n const garbleEntry: AssistantMessage = { role: 'assistant', content: '(模型本次返回了异常编码内容,已忽略;请重新描述你的问题。)', ts: new Date().toISOString() }\n history.push(garbleEntry)\n appendHistory(outputDir, garbleEntry)\n yield { frame: 'delta', text: garbleEntry.content }\n return\n }\n continue\n }\n\n const action = extractAction(reply)\n\n if (action === undefined) {\n // No parseable action tag. If the reply clearly intends to modify\n // something (or contains a malformed action tag), nudge — repeatedly,\n // with escalating firmness, until the model emits a tag or gives up.\n const intendsAction = /(改|修改|修订|重写|替换|调整|生成|新增|删除|导出|看看|查看|调出|读一下|加上|加一个|去掉|删掉|把.+改成|定位|处理|转轨|检查|确认|搜索|找一下|列一下|查一下|查一遍|查一查|再查|查查|核实|核对|清点|盘点|看一下|看下|继续)/.test(reply)\n // 兜底:回复提到任何可操作对象名词(即使动词是\"看/查/说\"的变体)也视为有操作意图,\n // 避免\"先查一遍编年录\"这类措辞漏网被静默当作纯聊天。\n const mentionsTarget = /(编年录|道藏|暗线|总纲|卷首语|章节|正文|规则|红线|伏笔|简介|大纲|事实|设定|世界|角色|人物|第\\s*\\d+\\s*章)/.test(reply)\n const strayTag = /<[a-z_-]*action[^>]*>/.test(reply)\n if ((intendsAction || mentionsTarget || strayTag) && nudged < MAX_NUDGES) {\n // 用户消息本身没有写意图时,引导模型直接文字回答(不要被逼出写操作标签)。\n const userWriteIntent = Object.values(WRITE_TOOL_KEYS).some(re => re.test(userMessage))\n const nudge = nudged === 0\n ? (userWriteIntent\n ? '你的上一条回复表达了想操作项目的意图(或动作标签格式有误),因此没有执行任何操作。请直接输出动作标签来执行,格式必须为 <dsh-action name=\"工具名\">{\"参数\":值}</dsh-action>(注意拼写是 dsh-action,不是 dash-action;标签成对出现,参数为合法 JSON)。如果需要先看内容,先输出 outline_text 或 chapter_text 标签。'\n : '你刚才的回复看起来在讨论项目内容,但没有必要执行任何操作。如果用户只是在提问或闲聊,请直接以文字回答即可,不要输出动作标签,也不要自行调用任何写操作(生成/修订/删除等只有用户明确要求时才允许)。若确实需要先查看数据,最多使用只读工具(outline_text / chapter_text / book_overview / facts_query)。')\n : (userWriteIntent\n ? `你第 ${nudged + 1} 次表达了操作意图但没有输出动作标签,因此仍未执行任何操作。铁律:你的【整个回复】现在必须只包含一个 <dsh-action> 标签(例如 <dsh-action name=\"chapter_text\">{\"no\":1}</dsh-action>),禁止任何解释、铺垫或\"我这就去\"之类的文字。若你其实不打算执行任何操作,请明确回复「不执行」。`\n : `你第 ${nudged + 1} 次回复仍不需要执行操作。再次强调:用户没有要求修改,请直接给出文字回答(可以简短引用项目数据),不要输出动作标签。写操作只会在用户明确要求时被允许。`)\n nudged++\n history.push({ role: 'tool', content: nudge, tool: 'format-hint', ts: new Date().toISOString() })\n appendHistory(outputDir, { role: 'tool', content: nudge, tool: 'format-hint', ts: new Date().toISOString() })\n continue\n }\n // Plain prose reply — done.\n const assistantEntry: AssistantMessage = { role: 'assistant', content: reply, ts: new Date().toISOString() }\n history.push(assistantEntry)\n appendHistory(outputDir, assistantEntry)\n // Stream the prose (without any stray action markup).\n yield { frame: 'delta', text: reply }\n return\n }\n\n // Execute the action, then feed the result back and continue.\n const { name, args, index } = action\n const prose = reply.slice(0, index).trim()\n // 写操作意图守卫:用户没明确要求修改时,拒绝执行并提示(不写盘、不消耗生成额度)。\n if (!guardWrite(name, userMessage)) {\n const denied = `【操作被拒绝】${name} 是写操作(会修改正文/项目数据),但你当前的消息里没有明确要求执行该修改。如果需要,请明确说明(如「生成第 120 章」「把第 105 章结尾改一下」)。我不会擅自修改你的作品。`\n history.push({ role: 'tool', content: denied, tool: name, ts: new Date().toISOString() })\n appendHistory(outputDir, { role: 'tool', content: denied, tool: name, ts: new Date().toISOString() })\n yield { frame: 'tool', name, status: 'error', detail: denied }\n // 拒绝后结束本轮:等作者重新明确指令。\n const assistantEntry: AssistantMessage = { role: 'assistant', content: denied, ts: new Date().toISOString() }\n history.push(assistantEntry)\n appendHistory(outputDir, assistantEntry)\n yield { frame: 'delta', text: denied }\n return\n }\n yield { frame: 'tool', name, status: 'start' }\n let result: string\n try {\n // executeAction is an async generator: it yields live progress text\n // (chapter text being generated) and returns the final result string.\n // Iterate manually so we see both the yielded deltas and the return.\n const iterator = executeAction(ctx, config, project, outputDir, name, args)[Symbol.asyncIterator]()\n result = ''\n for (;;) {\n const step = await iterator.next()\n if (step.done === true) {\n result = typeof step.value === 'string' ? step.value : ''\n break\n }\n const chunk = step.value\n if (typeof chunk === 'string' && chunk !== '') {\n yield { frame: 'toolDelta', name, text: chunk }\n }\n }\n yield { frame: 'tool', name, status: 'done', detail: result.slice(0, 200) }\n } catch (error) {\n result = `执行失败:${(error as Error).message}`\n yield { frame: 'tool', name, status: 'error', detail: (error as Error).message }\n }\n\n // Persist assistant prose + tool result as history entries.\n if (prose !== '') {\n history.push({ role: 'assistant', content: prose, ts: new Date().toISOString() })\n appendHistory(outputDir, { role: 'assistant', content: prose, ts: new Date().toISOString() })\n }\n history.push({ role: 'tool', content: result, tool: name, ts: new Date().toISOString() })\n appendHistory(outputDir, { role: 'tool', content: result, tool: name, ts: new Date().toISOString() })\n\n round++\n if (round >= MAX_TOOL_ROUNDS) {\n const message = `(已连续执行 ${round} 次修改操作,本轮停止。如需继续请再说。)`\n history.push({ role: 'assistant', content: message, ts: new Date().toISOString() })\n appendHistory(outputDir, { role: 'assistant', content: message, ts: new Date().toISOString() })\n yield { frame: 'delta', text: message }\n return\n }\n }\n}\n\nexport { chapterFileName }\n","/**\n * The /api/dsh-novel-forge route family: status, docx outline loading, LLM\n * story-bible extraction, volume planning, chapter planning, streaming\n * generation / rewrite / polish (NDJSON frames), review, summaries,\n * foreshadows, export, chapter reading, config patching, and opening the\n * output folder. Every route carries the same loopback-only trust fence as\n * the family plugins — these endpoints invoke the LLM and write files on the\n * host machine.\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport { exec } from 'node:child_process'\nimport { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { WebRoute } from '@deepseek-ai/dsh-host-webserver'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { ProductionRunner } from './run.ts'\nimport {\n NOVEL_API,\n type AssetsPatch,\n type AssetsResponse,\n type AssistantFrame,\n type AssistantHistoryResponse,\n type AssistantRequest,\n type AuditResponse,\n type AuditStatus,\n type AuthorReview,\n type BiblePatchRequest,\n type BibleRequest,\n type BlurbRequest,\n type CoverRequest,\n type CoverResponse,\n type RenameRequest,\n type WorldRequest,\n type BibleResponse,\n type BookActivateRequest,\n type BookCreateRequest,\n type BookRemoveRequest,\n type BookshelfSnapshot,\n type ChapterResponse,\n type ChapterPlan,\n type ChapterSaveResponse,\n type ChapterTextRequest,\n type ConfigPatch,\n type DraftDecisionRequest,\n type ExportRequest,\n type ExportResponse,\n type ForeshadowRequest,\n type ForeshadowResponse,\n type JobFrame,\n type LoadOutlineRequest,\n type LoadOutlineResponse,\n type NovelConfig,\n type PlotlinesRequest,\n type PlotlinesResponse,\n type PlanRequest,\n type PlanResponse,\n type PolishRequest,\n type ResetRequest,\n type ReviewReport,\n type ReviewRequest,\n type RunControlRequest,\n type RunStartRequest,\n type RunState,\n type RewriteRequest,\n type RolesRequest,\n type RolesResponse,\n type SceneCard,\n type ScenesRequest,\n type ScenesResponse,\n type VisualRulesRequest,\n type VisualRulesResponse,\n type OutlineSuggestRequest,\n type OutlineSuggestResponse,\n type BreakdownRequest,\n type BreakdownResponse,\n type SensitiveCheckRequest,\n type SensitiveCheckResponse,\n type SensitiveHit,\n type StatusResponse,\n type StoryBible,\n type StyleEngineRequest,\n type SummaryRequest,\n type VolumesRequest,\n type VolumesResponse,\n} from './protocol.ts'\nimport { readOutlineFromDocx } from './docx.ts'\nimport { clearAssistantHistory, loadAssistantHistory, runAssistantTurn } from './assistant.ts'\nimport { activateBook, bookshelfSnapshot, createBook, defaultOutputDirFor, loadBookshelf, removeBook, renameBook, seedBookshelfFromOutputDir } from './bookshelf.ts'\nimport { BUILTIN_ANTI_AI_RULES, BUILTIN_GENRE_LIBRARY, BUILTIN_PROGRESSION_MODES, BUILTIN_STYLE_TEMPLATES, emptyProjectAssets } from './assets.ts'\nimport {\n chapterFileName,\n auditBook,\n authorReviewChapter,\n autoLinkPlotlines,\n backfillFacts,\n createProject,\n exportBook,\n extractBible,\n extractStyleAsset,\n extractWorld,\n generateBlurb,\n generateChapterStream,\n listChapterFiles,\n loadProject,\n markForeshadowPlanted,\n mergeVolatileFromDisk,\n planChapters,\n planVolumes,\n polishChapterStream,\n readChapterFile,\n refreshCharacters,\n refreshPlotlineProgress,\n reviewChapter,\n reviewChapterText,\n rewriteChapterStream,\n saveProject,\n analyzePlotlineHealth,\n designPlotlinePlan,\n extractRoles,\n extractScenes,\n generateRolePromptKit,\n extractVisualRules,\n extractRoleVisual,\n suggestOutlines,\n breakdownBook,\n generateRoleReferenceImage,\n checkSensitiveText,\n suggestForeshadows,\n suggestPlotlines,\n summarizeAndExtractFacts,\n summarizeChapter,\n syncProjectWithDisk,\n} from './engine.ts'\n\n/** Cap on JSON request bodies (generous: cover images travel as base64). */\nconst MAX_JSON_BODY_BYTES = 16 * 1024 * 1024\n\n/** Loopback-only fence (mirrors the family plugins' pairing routes). */\nfunction isLoopbackRequest(request: IncomingMessage): boolean {\n const address = request.socket.remoteAddress\n if (address !== '127.0.0.1' && address !== '::1' && address !== '::ffff:127.0.0.1') return false\n const host = request.headers.host\n if (typeof host !== 'string') return false\n let hostUrl: URL\n try {\n hostUrl = new URL(`http://${host}`)\n } catch {\n return false\n }\n if (hostUrl.hostname !== '127.0.0.1' && hostUrl.hostname !== 'localhost' && hostUrl.hostname !== '[::1]') return false\n if (request.headers['sec-fetch-site'] === 'cross-site') return false\n const origin = request.headers.origin\n if (origin === undefined) return true\n try {\n return new URL(origin).host === hostUrl.host\n } catch {\n return false\n }\n}\n\n/** One JSON response. */\nfunction writeJson(res: ServerResponse, status: number, body: unknown): void {\n const payload = JSON.stringify(body)\n res.writeHead(status, { 'content-type': 'application/json; charset=utf-8', 'referrer-policy': 'no-referrer' })\n res.end(payload)\n}\n\n/** Read a JSON request body. */\nasync function readJsonBody<T>(req: IncomingMessage): Promise<T | undefined> {\n const chunks: Buffer[] = []\n let size = 0\n for await (const chunk of req) {\n const buffer = chunk as Buffer\n size += buffer.length\n if (size > MAX_JSON_BODY_BYTES) return undefined\n chunks.push(buffer)\n }\n try {\n return JSON.parse(Buffer.concat(chunks).toString('utf8')) as T\n } catch {\n return undefined\n }\n}\n\n/** Route deps. */\nexport interface NovelRoutesDeps {\n ctx: Context\n /** Resolve the live plugin config (settings-aware). */\n getConfig: () => NovelConfig\n /** Persist a config patch through the settings seam. */\n patchConfig: (patch: ConfigPatch) => Promise<NovelConfig>\n}\n\n/** Default chapter count for planning when the request omits it. */\nconst DEFAULT_PLAN_COUNT = 30\n\n/**\n * Build every /api/dsh-novel-forge route.\n * @param deps - context, config resolver, config patcher.\n * @returns the route list.\n */\nexport function makeRoutes(deps: NovelRoutesDeps): WebRoute[] {\n const { ctx, getConfig, patchConfig } = deps\n\n /** 全书质检实时状态(内存态,重启后回到 idle;用于 /status 暴露进度)。 */\n let auditState: AuditStatus = { status: 'idle', totalBatches: 0, completedBatches: 0 }\n\n /** Guard helper: fence + method check. */\n const guard = (req: IncomingMessage, res: ServerResponse, method: string): boolean => {\n if (!isLoopbackRequest(req)) {\n writeJson(res, 403, { error: 'forbidden: loopback-only' })\n return false\n }\n if (req.method !== method) {\n writeJson(res, 405, { error: `method not allowed (expected ${method})` })\n return false\n }\n return true\n }\n\n /** Load (and sync) the project, or respond 400. */\n const requireProject = (res: ServerResponse): ReturnType<typeof loadProject> => {\n const config = getConfig()\n const project = loadProject(config.outputDir)\n if (project === undefined) {\n writeJson(res, 400, { error: '输出目录中没有项目,请先加载大纲' })\n return undefined\n }\n syncProjectWithDisk(project, config.outputDir)\n saveProject(config.outputDir, project)\n return project\n }\n\n // -------------------------------------------------------------- status\n const statusRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.status,\n handler: (req, res) => {\n if (!guard(req, res, 'GET')) return\n const config = getConfig()\n // 书架为空时播种 settings 默认输出目录里的已有项目。\n seedBookshelfFromOutputDir(config.outputDir)\n const project = loadProject(config.outputDir)\n if (project !== undefined) {\n // 自动兜底:generating 超过 10 分钟(正常一章 2-5 分钟)视为卡死/中断,\n // 复位为 pending,避免\"生成中\"状态卡死无法重新生成。\n const staleMs = 10 * 60 * 1000\n for (const c of project.chapters) {\n if (c.status === 'generating' && c.generatingAt !== undefined) {\n const started = new Date(c.generatingAt).getTime()\n if (Number.isFinite(started) && Date.now() - started > staleMs) {\n c.status = 'pending'\n c.error = undefined\n c.generatingAt = undefined\n }\n }\n }\n syncProjectWithDisk(project, config.outputDir)\n saveProject(config.outputDir, project)\n }\n const response: StatusResponse = {\n config,\n // 瘦身:facts 只回最近 80 条(客户端最多展示 60),避免长篇后\n // status 响应体随编年录无限膨胀。\n project: project !== undefined\n ? { ...project, facts: (project.facts ?? []).slice(-80) }\n : undefined,\n generatedFiles: listChapterFiles(config.outputDir),\n audit: auditState,\n }\n writeJson(res, 200, response)\n },\n }\n\n // -------------------------------------------------------- load-outline\n const loadOutlineRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.loadOutline,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<LoadOutlineRequest>(req)\n const config = getConfig()\n try {\n let outline: string\n let path: string | undefined\n if (body?.text !== undefined && body.text.trim() !== '') {\n outline = body.text.trim()\n } else {\n const target = body?.path?.trim() !== '' && body?.path !== undefined ? body.path : config.outlinePath\n outline = readOutlineFromDocx(target)\n path = target\n }\n if (outline.length < 50) {\n writeJson(res, 400, { error: '大纲内容过短(<50 字符),请检查文件或直接粘贴大纲文本' })\n return\n }\n const response: LoadOutlineResponse = {\n outline,\n bookName: createProject(outline).bookName,\n chars: outline.length,\n path,\n }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 400, { error: (error as Error).message })\n }\n },\n }\n\n // -------------------------------------------------------- save-outline\n const saveOutlineRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.saveOutline,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<LoadOutlineRequest>(req)\n const config = getConfig()\n const outline = body?.text ?? ''\n if (outline.trim().length < 50) {\n writeJson(res, 400, { error: '大纲内容过短(<50 字符)' })\n return\n }\n let project = loadProject(config.outputDir)\n const now = new Date().toISOString()\n if (project === undefined) {\n project = createProject(outline)\n } else {\n project.outline = outline\n project.bookName = createProject(outline).bookName\n project.updatedAt = now\n }\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, bookName: project.bookName })\n },\n }\n\n // --------------------------------------------------------------- bible\n const bibleRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.bible,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<BibleRequest>(req)\n const config = getConfig()\n const project = loadProject(config.outputDir)\n const outline = body?.outline?.trim() !== '' && body?.outline !== undefined\n ? body.outline\n : project?.outline\n if (outline === undefined || outline.length < 50) {\n writeJson(res, 400, { error: '请先加载大纲' })\n return\n }\n try {\n const bible = await extractBible(ctx, config, outline, project)\n const now = new Date().toISOString()\n const next = project ?? createProject(outline)\n next.bible = bible\n next.updatedAt = now\n saveProject(config.outputDir, next)\n const response: BibleResponse = { bible }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ------------------------------------------------------------- volumes\n const volumesRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.volumes,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<VolumesRequest>(req)\n const config = getConfig()\n const project = loadProject(config.outputDir)\n const outline = body?.outline?.trim() !== '' && body?.outline !== undefined\n ? body.outline\n : project?.outline\n if (outline === undefined || outline.length < 50) {\n writeJson(res, 400, { error: '请先加载大纲' })\n return\n }\n try {\n const volumes = await planVolumes(ctx, config, outline)\n const now = new Date().toISOString()\n const next = project ?? createProject(outline)\n next.volumes = volumes\n next.updatedAt = now\n saveProject(config.outputDir, next)\n const response: VolumesResponse = { volumes }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ----------------------------------------------------------------- plan\n const planRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.plan,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<PlanRequest>(req)\n const config = getConfig()\n const project = loadProject(config.outputDir)\n const outline = body?.outline?.trim() !== '' && body?.outline !== undefined\n ? body.outline\n : project?.outline\n if (outline === undefined || outline.length < 50) {\n writeJson(res, 400, { error: '请先加载大纲(或粘贴大纲文本)' })\n return\n }\n const count = body?.chapterCount ?? DEFAULT_PLAN_COUNT\n if (!Number.isInteger(count) || count < 1 || count > 200) {\n writeJson(res, 400, { error: 'chapterCount 须为 1-200 的整数' })\n return\n }\n try {\n const next = project ?? createProject(outline)\n const chapters: ChapterPlan[] = await planChapters(ctx, config, next, count, body?.volume, config.outputDir)\n // 并发保护:长 LLM 调用期间磁盘可能已被其他请求更新(角色库/剧情线等),\n // 保存前合并磁盘最新易变字段,避免旧快照覆盖新修改。\n mergeVolatileFromDisk(config.outputDir, next)\n next.chapters.push(...chapters)\n next.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, next)\n const response: PlanResponse = { chapters, volumes: next.volumes }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ------------------------------------------------------------- generate\n const generateRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.generate,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<{ chapterNo?: number; skipReview?: boolean }>(req)\n const rawNo = body?.chapterNo\n if (!Number.isInteger(rawNo) || rawNo === undefined || rawNo < 1) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const no: number = rawNo\n const chapter = project.chapters.find(c => c.no === no)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${no} 不在计划中` })\n return\n }\n if (chapter.status === 'generating') {\n writeJson(res, 409, { error: `章节 ${no} 正在生成中` })\n return\n }\n\n // NDJSON stream.\n res.writeHead(200, {\n 'content-type': 'application/x-ndjson; charset=utf-8',\n 'cache-control': 'no-cache',\n 'x-accel-buffering': 'no',\n 'referrer-policy': 'no-referrer',\n })\n chapter.status = 'generating'\n chapter.error = undefined\n chapter.generatingAt = new Date().toISOString()\n // 并发保护:合并磁盘最新易变字段后保存,避免本请求覆盖并发修改(角色库/剧情线等)。\n mergeVolatileFromDisk(config.outputDir, project)\n saveProject(config.outputDir, project)\n\n const send = (frame: JobFrame): void => {\n res.write(JSON.stringify(frame) + '\\n')\n }\n\n try {\n send({ type: 'start', no, title: chapter.title })\n for await (const step of generateChapterStream(ctx, config, project, config.outputDir, no)) {\n if (step.frame === 'delta') {\n send({ type: 'delta', text: step.text })\n } else if (step.frame === 'done') {\n send({ type: 'done', no, file: step.file, chars: step.chars, title: chapter.title })\n }\n }\n // Auto pipeline: summary + facts(一次调用)-> review(unless skipped)。\n try {\n await summarizeAndExtractFacts(ctx, config, project, config.outputDir, no)\n } catch (error) {\n console.warn('[dsh-novel-forge] summary/facts failed:', (error as Error).message)\n }\n // 伏笔落地标记:正文中命中 planned 伏笔关键词 → 自动标为 planted(暗线管理页与正文同步)。\n try {\n const marked = markForeshadowPlanted(project, config.outputDir, no)\n if (marked > 0) {\n console.log(`[dsh-novel-forge] 第${no}章已埋伏笔 ${marked} 条`)\n }\n } catch (error) {\n console.warn('[dsh-novel-forge] markForeshadowPlanted failed:', (error as Error).message)\n }\n if (!(body?.skipReview === true) && (config.autoReview ?? true)) {\n const report = await reviewChapter(ctx, config, project, config.outputDir, no)\n send({ type: 'review', no, report })\n } else {\n chapter.status = 'approved'\n mergeVolatileFromDisk(config.outputDir, project)\n saveProject(config.outputDir, project)\n }\n // 作者复盘:叙事结构检查(钩子兑现/结尾钩子/推进/连续性/趋势;不改变章节状态)。\n if (config.autoAuthorReview ?? true) {\n try {\n const currentBody = readChapterFile(config.outputDir, chapter)\n let prevTail = ''\n if (no > 1) {\n const prev = project.chapters.find(c => c.no === no - 1)\n if (prev !== undefined) {\n prevTail = (readChapterFile(config.outputDir, prev) ?? '').replace(/^#.*$/m, '').trim().slice(-600)\n }\n }\n if (currentBody !== undefined) {\n const review = await authorReviewChapter(ctx, config, project, no, currentBody, prevTail)\n chapter.authorReview = review\n // 复盘标记推进的剧情线 → 自动关联本章。\n if (review.advancedLines !== undefined) {\n autoLinkPlotlines(project, no, review.advancedLines)\n }\n mergeVolatileFromDisk(config.outputDir, project)\n saveProject(config.outputDir, project)\n send({ type: 'author-review', no, review })\n }\n } catch (error) {\n console.warn('[dsh-novel-forge] author review failed:', (error as Error).message)\n }\n }\n res.end()\n } catch (error) {\n chapter.status = 'error'\n chapter.error = (error as Error).message\n mergeVolatileFromDisk(config.outputDir, project)\n saveProject(config.outputDir, project)\n if (!res.writableEnded) {\n send({ type: 'error', no, message: (error as Error).message })\n res.end()\n }\n }\n },\n }\n\n // --------------------------------------------------------------- review\n const reviewRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.review,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<ReviewRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const no = body!.chapterNo!\n try {\n const report = await reviewChapter(ctx, config, project, config.outputDir, no)\n writeJson(res, 200, { report })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // -------------------------------------------------------------- rewrite\n const rewriteRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.rewrite,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<RewriteRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const no = body!.chapterNo!\n res.writeHead(200, {\n 'content-type': 'application/x-ndjson; charset=utf-8',\n 'cache-control': 'no-cache',\n 'x-accel-buffering': 'no',\n 'referrer-policy': 'no-referrer',\n })\n const send = (frame: JobFrame): void => { res.write(JSON.stringify(frame) + '\\n') }\n try {\n for await (const step of rewriteChapterStream(ctx, config, project, config.outputDir, no, body?.instructions ?? '', body?.target)) {\n if (step.frame === 'delta') send({ type: 'delta', text: step.text })\n else if (step.frame === 'drafted') send({ type: 'drafted', no, chars: step.chars, draft: step.draft })\n }\n // Draft mode: no auto re-review — the user reviews the diff and\n // decides; re-run review after applying if wanted.\n res.end()\n } catch (error) {\n if (!res.writableEnded) {\n send({ type: 'error', no, message: (error as Error).message })\n res.end()\n }\n }\n },\n }\n\n // --------------------------------------------------------------- polish\n const polishRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.polish,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<PolishRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const no = body!.chapterNo!\n res.writeHead(200, {\n 'content-type': 'application/x-ndjson; charset=utf-8',\n 'cache-control': 'no-cache',\n 'x-accel-buffering': 'no',\n 'referrer-policy': 'no-referrer',\n })\n const send = (frame: JobFrame): void => { res.write(JSON.stringify(frame) + '\\n') }\n try {\n for await (const step of polishChapterStream(ctx, config, project, config.outputDir, no)) {\n if (step.frame === 'delta') send({ type: 'delta', text: step.text })\n else if (step.frame === 'drafted') send({ type: 'drafted', no, chars: step.chars, draft: step.draft })\n }\n res.end()\n } catch (error) {\n if (!res.writableEnded) {\n send({ type: 'error', no, message: (error as Error).message })\n res.end()\n }\n }\n },\n }\n\n // ---------------------------------------------------- draft apply/discard\n /** 采纳待确认草稿:覆盖正文文件 + 状态回 written + 清空草稿。 */\n const draftApplyRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.draftApply,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<DraftDecisionRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const chapter = project.chapters.find(c => c.no === body!.chapterNo!)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${body!.chapterNo} 不在计划中` })\n return\n }\n if (chapter.pendingDraft === undefined || chapter.pendingDraft === '') {\n writeJson(res, 400, { error: `章节 ${chapter.no} 没有待确认的草稿` })\n return\n }\n const draft = chapter.pendingDraft\n const fileName = chapterFileName(chapter)\n mkdirSync(config.outputDir, { recursive: true })\n const targetPath = join(config.outputDir, fileName)\n // 采纳前自动备份当前原稿为 .bak.md(每次应用都刷新为最新原稿),可随时回退。\n if (existsSync(targetPath)) {\n copyFileSync(targetPath, join(config.outputDir, `${fileName.replace(/\\.md$/, '')}.bak.md`))\n }\n writeFileSync(targetPath, `# 第${chapter.no}章 ${chapter.title}\\n\\n${draft}\\n`, 'utf8')\n chapter.pendingDraft = undefined\n chapter.chars = draft.length\n chapter.file = fileName\n // 携带审查报告则沿用结论定状态(修订后审查通过 → approved);否则置 written 待审。\n const carried = body?.report\n if (carried !== undefined && typeof carried.score === 'number') {\n chapter.review = carried\n chapter.status = carried.passed ? 'approved' : 'rejected'\n } else {\n chapter.status = 'written'\n chapter.review = undefined\n }\n chapter.error = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, chars: draft.length, file: fileName, markdown: draft })\n },\n }\n\n /** 放弃待确认草稿:保留原稿,仅清空草稿字段。 */\n const draftDiscardRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.draftDiscard,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<DraftDecisionRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const chapter = project.chapters.find(c => c.no === body!.chapterNo!)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${body!.chapterNo} 不在计划中` })\n return\n }\n if (chapter.pendingDraft !== undefined) {\n chapter.pendingDraft = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n }\n writeJson(res, 200, { ok: true })\n },\n }\n\n // -------------------------------------------------------------- summary\n const summaryRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.summary,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<SummaryRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n try {\n const summary = await summarizeChapter(ctx, config, project, config.outputDir, body!.chapterNo!)\n writeJson(res, 200, { summary })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ---------------------------------------------------------- foreshadow\n const foreshadowRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.foreshadow,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<ForeshadowRequest>(req)\n try {\n if (body?.suggest === true) {\n // AI suggestion pass: create several foreshadows from the outline.\n const created = await suggestForeshadows(ctx, config, project)\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n const response: ForeshadowResponse = { foreshadows: created }\n writeJson(res, 200, response)\n return\n }\n if (body?.id !== undefined) {\n // Update an existing foreshadow.\n const target = project.foreshadows.find(f => f.id === body.id)\n if (target === undefined) {\n writeJson(res, 404, { error: `伏笔 ${body.id} 不存在` })\n return\n }\n if (body.description !== undefined) target.description = body.description\n if (body.plantedChapter !== undefined) target.plantedChapter = body.plantedChapter\n if (body.targetChapter !== undefined) target.targetChapter = body.targetChapter\n if (body.status !== undefined) target.status = body.status\n if (body.resolvedNote !== undefined) target.resolvedNote = body.resolvedNote\n } else {\n // Create one manually.\n const description = body?.description?.trim()\n if (description === undefined || description === '') {\n writeJson(res, 400, { error: 'description 必填' })\n return\n }\n project.foreshadows.push({\n id: `fs-${Date.now().toString(36)}`,\n description,\n plantedChapter: body?.plantedChapter,\n targetChapter: body?.targetChapter,\n status: body?.status ?? 'planned',\n })\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n const response: ForeshadowResponse = { foreshadows: project.foreshadows }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // -------------------------------------------------------------- export\n const exportRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.exportBook,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<ExportRequest>(req)\n const format = body?.format === 'md' ? 'md' : 'txt'\n try {\n const result = exportBook(config.outputDir, project, format)\n const response: ExportResponse = { ...result }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // -------------------------------------------------------------- chapter\n const chapterRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.chapter,\n handler: async (req, res) => {\n if (!guard(req, res, 'GET')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const url = new URL(req.url ?? '/', 'http://localhost')\n const rawNo = Number(url.searchParams.get('no') ?? '0')\n if (!Number.isInteger(rawNo) || rawNo < 1) {\n writeJson(res, 400, { error: 'no 须为正整数' })\n return\n }\n const chapter = project.chapters.find(c => c.no === rawNo)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${rawNo} 不在计划中` })\n return\n }\n const markdown = readChapterFile(config.outputDir, chapter)\n if (markdown === undefined) {\n writeJson(res, 404, { error: `章节 ${rawNo} 尚未生成` })\n return\n }\n const response: ChapterResponse = { no: chapter.no, title: chapter.title, markdown }\n writeJson(res, 200, response)\n },\n }\n\n // ------------------------------------------------------ chapter check/save\n /** 审查手动编辑的正文(不落盘,返回审稿报告)。 */\n const chapterCheckRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.chapterCheck,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<ChapterTextRequest>(req)\n const text = body?.text?.trim() ?? ''\n if (text.length < 50) {\n writeJson(res, 400, { error: '正文过短(<50 字),请先编辑内容' })\n return\n }\n try {\n // 携带上一轮报告 → 验证模式(逐条核对原意见解决情况 + 只挑新增 high)。\n const report = await reviewChapterText(ctx, config, project, text, body?.previousReport)\n writeJson(res, 200, { report })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n /** 保存手动编辑的正文(自动备份 .bak,状态回 written)。 */\n const chapterSaveRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.chapterSave,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<ChapterTextRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const chapter = project.chapters.find(c => c.no === body!.chapterNo!)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${body!.chapterNo} 不在计划中` })\n return\n }\n const text = body?.text?.trim() ?? ''\n if (text.length < 50) {\n writeJson(res, 400, { error: '正文过短(<50 字),未保存' })\n return\n }\n const fileName = chapterFileName(chapter)\n mkdirSync(config.outputDir, { recursive: true })\n const targetPath = join(config.outputDir, fileName)\n if (existsSync(targetPath)) {\n copyFileSync(targetPath, join(config.outputDir, `${fileName.replace(/\\.md$/, '')}.bak.md`))\n }\n writeFileSync(targetPath, `# 第${chapter.no}章 ${chapter.title}\\n\\n${text}\\n`, 'utf8')\n chapter.status = 'written'\n chapter.chars = text.length\n chapter.file = fileName\n chapter.pendingDraft = undefined\n // 保存即审稿:携带工作区审查报告则沿用(不重复审);否则自动正式审稿一次。\n let report: ReviewReport | undefined\n const carried = body?.report\n if (carried !== undefined && typeof carried.score === 'number') {\n report = carried\n chapter.review = report\n chapter.status = report.passed ? 'approved' : 'rejected'\n } else {\n report = await reviewChapter(ctx, config, project, config.outputDir, chapter.no)\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n const response: ChapterSaveResponse = { ok: true, chars: text.length, file: fileName, report }\n writeJson(res, 200, response)\n },\n }\n\n // ----------------------------------------------------------- assistant\n const assistantRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.assistant,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<AssistantRequest>(req)\n const message = body?.message?.trim()\n if (message === undefined || message === '') {\n writeJson(res, 400, { error: '消息不能为空' })\n return\n }\n res.writeHead(200, {\n 'content-type': 'application/x-ndjson; charset=utf-8',\n 'cache-control': 'no-cache',\n 'x-accel-buffering': 'no',\n 'referrer-policy': 'no-referrer',\n })\n const send = (frame: AssistantFrame): void => { res.write(JSON.stringify(frame) + '\\n') }\n try {\n for await (const step of runAssistantTurn(ctx, config, project, config.outputDir, message)) {\n if (step.frame === 'delta') send({ type: 'delta', text: step.text })\n else if (step.frame === 'tool') send({ type: 'tool', name: step.name, status: step.status, detail: step.detail })\n else if (step.frame === 'toolDelta') send({ type: 'toolDelta', name: step.name, text: step.text })\n }\n send({ type: 'done' })\n res.end()\n } catch (error) {\n if (!res.writableEnded) {\n send({ type: 'error', message: (error as Error).message })\n res.end()\n }\n }\n },\n }\n\n // -------------------------------------------------- assistant-history\n const assistantHistoryRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.assistantHistory,\n handler: (req, res) => {\n if (!guard(req, res, 'GET')) return\n const config = getConfig()\n const response: AssistantHistoryResponse = { messages: loadAssistantHistory(config.outputDir) }\n writeJson(res, 200, response)\n },\n }\n\n // --------------------------------------------------- assistant-clear\n /** 清空助手对话记录。 */\n const assistantClearRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.assistantClear,\n handler: (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n clearAssistantHistory(config.outputDir)\n writeJson(res, 200, { ok: true })\n },\n }\n\n // --------------------------------------------------------------- assets\n const assetsRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.assets,\n handler: async (req, res) => {\n // GET (read) and POST (patch) are both allowed — check methods first,\n // then the loopback fence (guard() would 405 on POST, which is wrong).\n if (req.method !== 'GET' && req.method !== 'POST') {\n writeJson(res, 405, { error: 'method not allowed (expected GET or POST)' })\n return\n }\n if (!isLoopbackRequest(req)) {\n writeJson(res, 403, { error: 'forbidden: loopback-only' })\n return\n }\n const config = getConfig()\n const project = loadProject(config.outputDir)\n const projectAssets = project?.assets ?? emptyProjectAssets()\n if (req.method === 'POST') {\n const body = await readJsonBody<AssetsPatch>(req)\n if (body === undefined) {\n writeJson(res, 400, { error: '无效的 JSON' })\n return\n }\n if (project === undefined) {\n writeJson(res, 400, { error: '请先加载大纲创建项目' })\n return\n }\n if (body.genre !== undefined) projectAssets.genre = body.genre\n if (body.primaryProgression !== undefined) projectAssets.primaryProgression = body.primaryProgression\n if (body.auxiliaryProgressions !== undefined) projectAssets.auxiliaryProgressions = body.auxiliaryProgressions\n if (body.antiAiRules !== undefined) projectAssets.antiAiRules = body.antiAiRules\n if (body.styleAssets !== undefined) projectAssets.styleAssets = body.styleAssets\n projectAssets.updatedAt = new Date().toISOString()\n project.assets = projectAssets\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n }\n const response: AssetsResponse = {\n projectAssets,\n genreLibrary: BUILTIN_GENRE_LIBRARY,\n antiAiLibrary: BUILTIN_ANTI_AI_RULES,\n styleTemplates: BUILTIN_STYLE_TEMPLATES,\n progressionLibrary: BUILTIN_PROGRESSION_MODES,\n }\n writeJson(res, 200, response)\n },\n }\n\n // ----------------------------------------------------------- style-engine\n const styleEngineRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.styleEngine,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = loadProject(config.outputDir)\n const body = await readJsonBody<StyleEngineRequest>(req)\n const sample = body?.sampleText?.trim()\n if (sample === undefined || sample.length < 50) {\n writeJson(res, 400, { error: '样本文本过短(<50 字符),请粘贴一段能代表目标风格的文字' })\n return\n }\n try {\n const rules = await extractStyleAsset(ctx, config, sample)\n const name = body?.name?.trim() !== '' && body?.name !== undefined ? body.name : `风格资产 ${Date.now().toString(36)}`\n const styleAsset = {\n name: name.slice(0, 40),\n ...rules,\n sourceText: sample.slice(0, 3000),\n createdAt: new Date().toISOString(),\n }\n if (project !== undefined) {\n project.assets ??= emptyProjectAssets()\n project.assets.styleAssets ??= []\n project.assets.styleAssets.push(styleAsset)\n project.assets.updatedAt = new Date().toISOString()\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n }\n writeJson(res, 200, { styleAsset })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ------------------------------------------------------------- bookshelf\n const bookshelfRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.bookshelf,\n handler: async (req, res) => {\n // GET = snapshot; POST = create book.\n if (req.method === 'GET') {\n if (!isLoopbackRequest(req)) {\n writeJson(res, 403, { error: 'forbidden: loopback-only' })\n return\n }\n // 书架为空时,把 settings 默认输出目录里已有的项目播种为第一本书。\n seedBookshelfFromOutputDir(getConfig().outputDir)\n const snapshot: BookshelfSnapshot = bookshelfSnapshot(loadBookshelf())\n writeJson(res, 200, snapshot)\n return\n }\n if (req.method === 'POST') {\n if (!isLoopbackRequest(req)) {\n writeJson(res, 403, { error: 'forbidden: loopback-only' })\n return\n }\n const body = await readJsonBody<BookCreateRequest>(req)\n const bookName = body?.bookName?.trim()\n if (bookName === undefined || bookName === '') {\n writeJson(res, 400, { error: 'bookName 不能为空' })\n return\n }\n const outputDir = body?.outputDir?.trim() !== '' && body?.outputDir !== undefined\n ? body.outputDir\n : defaultOutputDirFor(bookName)\n const book = createBook(bookName, outputDir)\n // 开书向导:创建时带大纲 → 立即建立项目(书名以大纲首行为准)。\n const outline = body?.outline?.trim()\n if (outline !== undefined && outline.length >= 50) {\n const project = createProject(outline)\n saveProject(outputDir, project)\n renameBook(book.id, project.bookName)\n }\n writeJson(res, 200, bookshelfSnapshot(loadBookshelf()))\n return\n }\n writeJson(res, 405, { error: 'method not allowed (expected GET or POST)' })\n },\n }\n\n // --------------------------------------------------------------- reset\n /** 重置项目:清空设定/卷/章节计划/正文/伏笔/资产/事实库(可携带新大纲)。 */\n const resetRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.reset,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = loadProject(config.outputDir)\n if (project === undefined) {\n writeJson(res, 400, { error: '输出目录中没有项目,无需重置' })\n return\n }\n const body = await readJsonBody<ResetRequest>(req)\n const outline = body?.outline?.trim()\n if (outline !== undefined && outline.length >= 50) {\n project.outline = outline\n project.bookName = createProject(outline).bookName\n }\n project.bible = undefined\n project.volumes = undefined\n project.chapters = []\n project.foreshadows = []\n project.assets = emptyProjectAssets()\n project.facts = []\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, bookName: project.bookName })\n },\n }\n\n // --------------------------------------------------- bookshelf activate\n const bookshelfActivateRoute: WebRoute = {\n kind: 'exact',\n path: '/api/dsh-novel-forge/bookshelf/activate',\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<BookActivateRequest>(req)\n if (body?.id === undefined || body.id === '') {\n writeJson(res, 400, { error: 'id 不能为空' })\n return\n }\n const book = activateBook(body.id)\n if (book === undefined) {\n writeJson(res, 404, { error: `书 ${body.id} 不存在` })\n return\n }\n writeJson(res, 200, bookshelfSnapshot(loadBookshelf()))\n },\n }\n\n // ---------------------------------------------------- bookshelf remove\n const bookshelfRemoveRoute: WebRoute = {\n kind: 'exact',\n path: '/api/dsh-novel-forge/bookshelf/remove',\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<BookRemoveRequest>(req)\n if (body?.id === undefined || body.id === '') {\n writeJson(res, 400, { error: 'id 不能为空' })\n return\n }\n const removed = removeBook(body.id)\n if (!removed) {\n writeJson(res, 404, { error: `书 ${body.id} 不存在` })\n return\n }\n writeJson(res, 200, bookshelfSnapshot(loadBookshelf()))\n },\n }\n\n // ---------------------------------------------------------------- audit\n /** 全书一致性质检。 */\n const auditRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.audit,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const startedAt = new Date().toISOString()\n auditState = { status: 'running', startedAt, totalBatches: 0, completedBatches: 0 }\n try {\n const issues = await auditBook(ctx, config, project, config.outputDir, (completed, total) => {\n auditState.totalBatches = total\n auditState.completedBatches = completed\n })\n const auditedChapters = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating').length\n auditState = {\n status: 'done',\n startedAt,\n finishedAt: new Date().toISOString(),\n totalBatches: auditState.totalBatches,\n completedBatches: auditState.totalBatches,\n auditedChapters,\n issuesCount: issues.length,\n issues,\n }\n const response: AuditResponse = {\n issues,\n auditedChapters,\n auditedAt: auditState.finishedAt!,\n }\n writeJson(res, 200, response)\n } catch (error) {\n auditState = {\n ...auditState,\n status: 'error',\n finishedAt: new Date().toISOString(),\n error: (error as Error).message,\n }\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ----------------------------------------------------- characters refresh\n /** 角色卡刷新(出场统计精确化 + LLM 聚合状态)。 */\n const charactersRefreshRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.charactersRefresh,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n try {\n const cards = await refreshCharacters(ctx, config, project, config.outputDir)\n // 存档:人物志聚合结果落盘,下次打开直接显示,无需重新计算。\n project.roleStatus = cards\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { cards })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ------------------------------------------------------- facts backfill\n /** 事实库回填:对历史已生成章节批量抽取事实。 */\n const factsBackfillRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.factsBackfill,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n try {\n const filled = await backfillFacts(ctx, config, project, config.outputDir)\n writeJson(res, 200, { ok: true, filled })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ---------------------------------------------------------- bible patch\n /** 设定圣经局部修补(世界观规则/红线/风格)。 */\n const biblePatchRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.biblePatch,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n if (project.bible === undefined) {\n writeJson(res, 400, { error: '尚未生成道藏,请先生成' })\n return\n }\n const body = await readJsonBody<BiblePatchRequest>(req)\n if (Array.isArray(body?.worldRules)) project.bible.worldRules = body.worldRules.filter(r => r.trim() !== '')\n if (Array.isArray(body?.redLines)) project.bible.redLines = body.redLines.filter(r => r.trim() !== '')\n if (Array.isArray(body?.style)) project.bible.style = body.style.filter(r => r.trim() !== '')\n if (Array.isArray(body?.characters)) {\n project.bible.characters = body.characters\n .filter(c => c !== undefined && c !== null && typeof c.name === 'string' && c.name.trim() !== '')\n .map(c => ({\n name: c.name.trim(),\n role: (['protagonist', 'supporting', 'antagonist', 'other'] as const).includes(c.role as never)\n ? c.role as StoryBible['characters'][number]['role']\n : 'other',\n traits: Array.isArray(c.traits) ? c.traits.filter((t): t is string => typeof t === 'string' && t.trim() !== '') : [],\n goals: typeof c.goals === 'string' ? c.goals : '',\n relations: typeof c.relations === 'string' ? c.relations : '',\n knowledge: Array.isArray(c.knowledge)\n ? c.knowledge.filter((k): k is string => typeof k === 'string' && k.trim() !== '')\n : undefined,\n }))\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { bible: project.bible })\n },\n }\n\n // ---------------------------------------------------------------- blurb\n /** 小说简介:AI 生成/补全,或手动保存。 */\n const blurbRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.blurb,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<BlurbRequest>(req)\n try {\n if (body?.action === 'save') {\n const text = body.text?.trim() ?? ''\n project.blurb = text\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { blurb: text })\n return\n }\n const partial = body?.partial?.trim() ?? ''\n const blurb = await generateBlurb(ctx, config, project, partial)\n project.blurb = blurb\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { blurb })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ---------------------------------------------------------------- cover\n /** 封面:GET 读取(dataUrl);POST 上传(base64)或移除。 */\n const coverRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.cover,\n handler: async (req, res) => {\n const config = getConfig()\n if (req.method === 'GET') {\n if (!isLoopbackRequest(req)) {\n writeJson(res, 403, { error: 'forbidden: loopback-only' })\n return\n }\n // 书架页按书读取:?dir=<输出目录>;省略时用当前激活书目录。\n const url = new URL(req.url ?? '/', 'http://localhost')\n const dirParam = url.searchParams.get('dir')\n const targetDir = dirParam !== null && dirParam !== '' ? dirParam : config.outputDir\n const project = loadProject(targetDir)\n const coverPath = project?.coverPath\n if (coverPath === undefined || coverPath === '') {\n writeJson(res, 200, { dataUrl: null } satisfies CoverResponse)\n return\n }\n const file = join(targetDir, coverPath)\n if (!existsSync(file)) {\n writeJson(res, 200, { dataUrl: null } satisfies CoverResponse)\n return\n }\n const mime = coverPath.toLowerCase().endsWith('.png') ? 'image/png'\n : coverPath.toLowerCase().endsWith('.jpg') || coverPath.toLowerCase().endsWith('.jpeg') ? 'image/jpeg'\n : coverPath.toLowerCase().endsWith('.webp') ? 'image/webp'\n : 'image/png'\n const dataUrl = `data:${mime};base64,${readFileSync(file).toString('base64')}`\n writeJson(res, 200, { dataUrl } satisfies CoverResponse)\n return\n }\n if (req.method === 'POST') {\n if (!guard(req, res, 'POST')) return\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<CoverRequest>(req)\n try {\n if (body?.action === 'remove') {\n if (project.coverPath !== undefined && project.coverPath !== '') {\n const oldFile = join(config.outputDir, project.coverPath)\n if (existsSync(oldFile)) rmSync(oldFile, { force: true })\n }\n project.coverPath = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, coverPath: null })\n return\n }\n const dataUrl = body?.dataUrl ?? ''\n const match = /^data:(image\\/(?:png|jpeg|jpg|webp));base64,(.+)$/s.exec(dataUrl)\n if (match === null) {\n writeJson(res, 400, { error: '封面须为 PNG/JPEG/WebP 的 base64 data URL' })\n return\n }\n const mime = match[1]!\n const ext = mime === 'image/png' ? 'png' : mime === 'image/webp' ? 'webp' : 'jpg'\n const fileName = `cover.${ext}`\n const targetPath = join(config.outputDir, fileName)\n const oldPath = project.coverPath\n mkdirSync(config.outputDir, { recursive: true })\n writeFileSync(targetPath, Buffer.from(match[2]!, 'base64'))\n if (oldPath !== undefined && oldPath !== '' && oldPath !== fileName) {\n const oldFile = join(config.outputDir, oldPath)\n if (existsSync(oldFile)) rmSync(oldFile, { force: true })\n }\n project.coverPath = fileName\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, coverPath: fileName })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n return\n }\n writeJson(res, 405, { error: 'method not allowed (expected GET or POST)' })\n },\n }\n\n // ---------------------------------------------------------------- world\n /** 大世界:AI 提炼或手动保存(境界体系/区域/势力)。 */\n const worldRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.world,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<WorldRequest>(req)\n try {\n if (body?.action === 'save' && body.world !== undefined) {\n project.world = {\n realms: Array.isArray(body.world.realms) ? body.world.realms : [],\n regions: Array.isArray(body.world.regions) ? body.world.regions : [],\n factions: Array.isArray(body.world.factions) ? body.world.factions : [],\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { world: project.world })\n return\n }\n const world = await extractWorld(ctx, config, project)\n project.world = world\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { world })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // --------------------------------------------------------------- rename\n /** 重命名当前书:同步项目 bookName 与书架条目。 */\n const renameRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.rename,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<RenameRequest>(req)\n const bookName = body?.bookName?.trim()\n if (bookName === undefined || bookName === '') {\n writeJson(res, 400, { error: '书名不能为空' })\n return\n }\n project.bookName = bookName.slice(0, 60)\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n const store = loadBookshelf()\n if (store.activeBookId !== null) renameBook(store.activeBookId, project.bookName)\n writeJson(res, 200, { bookName: project.bookName })\n },\n }\n\n // ------------------------------------------------------------- plotlines\n /** 剧情线管理:增删改 + 关联章节(主线/支线/人物线/悬念线)。 */\n const plotlinesRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.plotlines,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<PlotlinesRequest>(req)\n if (project.plotlines === undefined) project.plotlines = []\n const op = body?.op\n if (op === 'add' && body?.line !== undefined) {\n const line = body.line\n project.plotlines.push({\n id: line.id !== '' ? line.id : `pl-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,\n name: line.name.slice(0, 40),\n kind: line.kind,\n goal: line.goal.slice(0, 300),\n progress: line.progress.slice(0, 300),\n status: line.status,\n chapters: Array.isArray(line.chapters) ? line.chapters.filter((n): n is number => typeof n === 'number') : [],\n createdAt: line.createdAt !== '' ? line.createdAt : new Date().toISOString(),\n })\n } else if (op === 'update' && body?.line !== undefined && body.line.id !== '') {\n const idx = project.plotlines.findIndex(l => l.id === body.line!.id)\n if (idx !== -1) {\n const line = body.line\n project.plotlines[idx] = {\n ...project.plotlines[idx]!,\n name: line.name.slice(0, 40),\n kind: line.kind,\n goal: line.goal.slice(0, 300),\n progress: line.progress.slice(0, 300),\n status: line.status,\n }\n }\n } else if (op === 'remove' && body?.id !== undefined) {\n project.plotlines = project.plotlines.filter(l => l.id !== body.id)\n } else if (op === 'link' && body?.id !== undefined && typeof body.chapterNo === 'number' && body.chapterNo > 0) {\n const line = project.plotlines.find(l => l.id === body.id)\n if (line !== undefined && !line.chapters.includes(body.chapterNo)) {\n line.chapters.push(body.chapterNo)\n if (line.status === 'active' && line.progress === '') {\n line.progress = `推进至第 ${body.chapterNo} 章`\n }\n }\n } else if (op === 'suggest') {\n try {\n const suggestions = await suggestPlotlines(ctx, config, project)\n writeJson(res, 200, { plotlines: project.plotlines, suggestions } satisfies PlotlinesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `AI 建议失败:${(error as Error).message}` })\n return\n }\n } else if (op === 'refresh' && body?.id !== undefined) {\n const line = project.plotlines.find(l => l.id === body.id)\n if (line === undefined) {\n writeJson(res, 404, { error: '剧情线不存在' })\n return\n }\n try {\n const progress = await refreshPlotlineProgress(ctx, config, project, line)\n line.progress = progress\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { plotlines: project.plotlines } satisfies PlotlinesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `刷新进度失败:${(error as Error).message}` })\n return\n }\n } else if (op === 'health') {\n try {\n const health = await analyzePlotlineHealth(ctx, config, project)\n writeJson(res, 200, { plotlines: project.plotlines, health } satisfies PlotlinesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `健康检查失败:${(error as Error).message}` })\n return\n }\n } else if (op === 'plan') {\n try {\n const health = await analyzePlotlineHealth(ctx, config, project)\n const plan = await designPlotlinePlan(ctx, config, project, health)\n writeJson(res, 200, { plotlines: project.plotlines, health, plan } satisfies PlotlinesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `剧情方案生成失败:${(error as Error).message}` })\n return\n }\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n const response: PlotlinesResponse = { plotlines: project.plotlines }\n writeJson(res, 200, response)\n },\n }\n\n // --------------------------------------------------------- sensitive\n /** 敏感词检查:指定章节 / 任意文本 / 全书已写章节。 */\n const sensitiveRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.sensitiveCheck,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<SensitiveCheckRequest>(req)\n const hits: SensitiveHit[] = []\n let scanned = 0\n if (body?.text !== undefined) {\n for (const hit of checkSensitiveText(body.text)) {\n hits.push({ chapterNo: 0, word: hit.word, category: hit.category, count: hit.count })\n }\n } else if (typeof body?.chapterNo === 'number') {\n const chapter = project.chapters.find(c => c.no === body.chapterNo)\n if (chapter !== undefined) {\n const text = readChapterFile(config.outputDir, chapter)\n if (text !== undefined) {\n scanned = 1\n for (const hit of checkSensitiveText(text)) {\n hits.push({ chapterNo: chapter.no, word: hit.word, category: hit.category, count: hit.count })\n }\n }\n }\n } else if (body?.all === true) {\n for (const chapter of project.chapters) {\n if (chapter.status === 'pending' || chapter.status === 'generating') continue\n const text = readChapterFile(config.outputDir, chapter)\n if (text === undefined) continue\n scanned++\n for (const hit of checkSensitiveText(text)) {\n hits.push({ chapterNo: chapter.no, word: hit.word, category: hit.category, count: hit.count })\n }\n }\n } else {\n writeJson(res, 400, { error: '请提供 chapterNo / text / all 之一' })\n return\n }\n const response: SensitiveCheckResponse = { hits, scannedChapters: scanned }\n writeJson(res, 200, response)\n },\n }\n\n // ---------------------------------------------------------------- roles\n /** 角色库:AI 提炼 / 采纳 / 更新 / 删除。 */\n const rolesRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.roles,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<RolesRequest>(req)\n if (project.roles === undefined) project.roles = []\n const op = body?.op\n if (op === 'extract') {\n try {\n const candidates = await extractRoles(ctx, config, project)\n writeJson(res, 200, { roles: project.roles, candidates } satisfies RolesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `角色提炼失败:${(error as Error).message}` })\n return\n }\n } else if ((op === 'adopt' || op === 'update') && body?.role !== undefined) {\n const r = body.role\n const idx = project.roles.findIndex(x => x.name === r.name)\n if (idx === -1) project.roles.push(r)\n else project.roles[idx] = r\n } else if (op === 'remove' && body?.name !== undefined) {\n project.roles = project.roles.filter(x => x.name !== body.name)\n } else if (op === 'image') {\n const name = body?.name?.trim()\n const dataUrl = body?.dataUrl?.trim()\n if (name === undefined || name === '') {\n writeJson(res, 400, { error: 'name(角色名)必填' })\n return\n }\n if (dataUrl === undefined || dataUrl === '') {\n writeJson(res, 400, { error: 'dataUrl(参考图)必填' })\n return\n }\n const role = project.roles.find(r => r.name === name)\n if (role === undefined) {\n writeJson(res, 404, { error: `角色 ${name} 不存在` })\n return\n }\n const label = body?.label?.trim() ?? ''\n if (label !== '') {\n // 图集上传:带用途标签。标签「立绘」时同步为角色参考图(imageUrl)。\n role.gallery ??= []\n role.gallery = role.gallery.filter(g => g.label !== label)\n role.gallery.push({ label, dataUrl })\n if (label === '立绘' || label.includes('立绘')) role.imageUrl = dataUrl\n } else {\n // 兼容旧行为:不带标签 = 角色参考图。\n role.imageUrl = dataUrl\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { roles: project.roles, imageUrl: role.imageUrl } satisfies RolesResponse)\n return\n } else if (op === 'removeImage') {\n const name = body?.name?.trim()\n const label = body?.label?.trim() ?? ''\n const role = project.roles.find(r => r.name === name)\n if (role !== undefined) {\n if (label !== '') {\n role.gallery = (role.gallery ?? []).filter(g => g.label !== label)\n if (label === '立绘' || label.includes('立绘')) role.imageUrl = undefined\n } else {\n role.imageUrl = undefined\n }\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { roles: project.roles } satisfies RolesResponse)\n return\n } else if (op === 'imageGenerate') {\n const name = body?.name?.trim()\n if (name === undefined || name === '') {\n writeJson(res, 400, { error: 'name(角色名)必填' })\n return\n }\n try {\n const imageUrl = await generateRoleReferenceImage(ctx, config, project, config.outputDir, name, body?.style ?? '')\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { roles: project.roles, imageUrl } satisfies RolesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `角色参考图生成失败:${(error as Error).message}` })\n return\n }\n } else if (op === 'visual') {\n // 动漫形象描述词提炼:扫描正文外貌描写 → LLM 提炼 → 写入角色卡。\n const name = body?.name?.trim()\n if (name === undefined || name === '') {\n writeJson(res, 400, { error: 'name(角色名)必填' })\n return\n }\n try {\n const visual = await extractRoleVisual(ctx, config, project, config.outputDir, name)\n const role = project.roles.find(r => r.name === name)\n if (role !== undefined) {\n role.imagePrompt = visual\n if ((visual.expressions ?? []).length > 0) role.expressions = visual.expressions\n if (visual.promptKit !== undefined) role.promptKit = visual.promptKit\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { roles: project.roles, visual } satisfies RolesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `形象提炼失败:${(error as Error).message}` })\n return\n }\n } else if (op === 'promptKit') {\n // 角色四类提示词精修包(立绘/四视图/表情/细节)\n const name = body?.name?.trim()\n if (name === undefined || name === '') {\n writeJson(res, 400, { error: 'name(角色名)必填' })\n return\n }\n try {\n const kit = await generateRolePromptKit(ctx, config, project, name)\n const role = project.roles.find(r => r.name === name)\n if (role !== undefined) role.promptKit = kit\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { roles: project.roles, promptKit: kit } satisfies RolesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `提示词精修失败:${(error as Error).message}` })\n return\n }\n } else {\n writeJson(res, 400, { error: '未知的 roles op' })\n return\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n const response: RolesResponse = { roles: project.roles }\n writeJson(res, 200, response)\n },\n }\n\n // ------------------------------------------------------- chapter reset\n /** 章节复位:generating 卡死 → pending(可重新生成)。 */\n const chapterResetRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.chapterReset,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<{ chapterNo?: number }>(req)\n const no = body?.chapterNo\n if (!Number.isInteger(no) || no === undefined || no < 1) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const chapter = project.chapters.find(c => c.no === no)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${no} 不在计划中` })\n return\n }\n chapter.status = 'pending'\n chapter.error = undefined\n chapter.generatingAt = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, no })\n },\n }\n\n // ------------------------------------------------------ chapter approve\n /** 章节直接通过:作者行使最终决定权(不重审,保留审稿记录)。 */\n const chapterApproveRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.chapterApprove,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<{ chapterNo?: number }>(req)\n const no = body?.chapterNo\n if (!Number.isInteger(no) || no === undefined || no < 1) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const chapter = project.chapters.find(c => c.no === no)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${no} 不在计划中` })\n return\n }\n chapter.status = 'approved'\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, no })\n },\n }\n\n // ------------------------------------------------------ author review backfill\n /** 作者复盘补跑:对已写章节补齐 authorReview(body.chapterNo=单章 JSON,缺省=全书 NDJSON 流)。 */\n const reviewBackfillRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.reviewBackfill,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<{ chapterNo?: number }>(req)\n\n /** 对一章执行作者复盘(读取已落盘正文,不改变章节状态/正文)。 */\n const runOne = async (chapter: ChapterPlan): Promise<AuthorReview> => {\n const currentBody = readChapterFile(config.outputDir, chapter)\n if (currentBody === undefined) throw new Error(`章节 ${chapter.no} 的正文文件不存在`)\n let prevTail = ''\n if (chapter.no > 1) {\n const prev = project.chapters.find(c => c.no === chapter.no - 1)\n if (prev !== undefined) {\n prevTail = (readChapterFile(config.outputDir, prev) ?? '').replace(/^#.*$/m, '').trim().slice(-600)\n }\n }\n return authorReviewChapter(ctx, config, project, chapter.no, currentBody, prevTail)\n }\n\n // 单章:JSON 响应。\n if (typeof body?.chapterNo === 'number' && body.chapterNo > 0) {\n const chapter = project.chapters.find(c => c.no === body.chapterNo)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${body.chapterNo} 不在计划中` })\n return\n }\n if (chapter.status === 'pending') {\n writeJson(res, 400, { error: '该章尚未生成正文,无法复盘' })\n return\n }\n try {\n const review = await runOne(chapter)\n chapter.authorReview = review\n if (review.advancedLines !== undefined) {\n autoLinkPlotlines(project, chapter.no, review.advancedLines)\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { no: chapter.no, review } satisfies { no: number; review: AuthorReview })\n return\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n return\n }\n }\n\n // 全书:NDJSON 流式补跑缺失复盘的已写章节。\n const missing = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating' && c.status !== 'error' && c.authorReview === undefined)\n if (missing.length === 0) {\n writeJson(res, 200, { count: 0 })\n return\n }\n res.writeHead(200, {\n 'content-type': 'application/x-ndjson; charset=utf-8',\n 'cache-control': 'no-cache',\n 'referrer-policy': 'no-referrer',\n })\n const send = (frame: JobFrame): void => {\n res.write(JSON.stringify(frame) + '\\n')\n }\n let done = 0\n for (const chapter of missing) {\n try {\n const review = await runOne(chapter)\n chapter.authorReview = review\n if (review.advancedLines !== undefined) {\n autoLinkPlotlines(project, chapter.no, review.advancedLines)\n }\n done++\n saveProject(config.outputDir, project)\n send({ type: 'author-review', no: chapter.no, review })\n } catch (error) {\n console.warn(`[dsh-novel-forge] author backfill ch.${chapter.no} failed:`, (error as Error).message)\n }\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n send({ type: 'author-backfill-done', count: done })\n res.end()\n },\n }\n\n // --------------------------------------------------------------- config\n const configRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.config,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<ConfigPatch>(req)\n if (body === undefined) {\n writeJson(res, 400, { error: '无效的配置 JSON' })\n return\n }\n try {\n const next = await patchConfig(body)\n writeJson(res, 200, { config: next })\n } catch (error) {\n writeJson(res, 400, { error: (error as Error).message })\n }\n },\n }\n\n // ---------------------------------------------------------- open-folder\n const openFolderRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.openFolder,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const dir = config.outputDir\n exec(`explorer \"${dir.replace(/\"/g, '')}\"`, (error) => {\n if (error) {\n writeJson(res, 500, { ok: false, error: error.message })\n } else {\n writeJson(res, 200, { ok: true })\n }\n })\n },\n }\n\n // ------------------------------------------------------- outline suggest\n /** 开书想法 → AI 大纲:2-3 个可选方案(支持暂留换批:count 只补空槽 + exclude 避开已留方向)。 */\n const outlineSuggestRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.outlineSuggest,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const body = await readJsonBody<OutlineSuggestRequest>(req)\n const idea = body?.idea?.trim() ?? ''\n if (idea.length < 50) {\n writeJson(res, 400, { error: '想法太短(<50 字),请多写一两句:主角是谁、什么世界、想要什么爽点' })\n return\n }\n const count = body?.count !== undefined ? Math.max(1, Math.min(3, Math.floor(body.count))) : 3\n const exclude = Array.isArray(body?.exclude) ? body.exclude.filter((e): e is string => typeof e === 'string' && e.trim() !== '').map(e => e.trim().slice(0, 200)) : []\n try {\n const candidates = await suggestOutlines(ctx, config, idea, count, exclude)\n const response: OutlineSuggestResponse = { candidates }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 500, { error: `大纲方案生成失败:${(error as Error).message}` })\n }\n },\n }\n\n // ----------------------------------------------------------- breakdown\n /** 拆书分析:对已写章节做结构/人物/文风/卖点体检(两阶段:源笔记→分节分析)。 */\n const breakdownRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.breakdown,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<BreakdownRequest>(req)\n try {\n const result = await breakdownBook(\n ctx,\n config,\n project,\n config.outputDir,\n body?.scope ?? 'recent',\n body?.preset ?? 'quick',\n body?.budgetTokens ?? 50000,\n )\n writeJson(res, 200, result satisfies BreakdownResponse)\n } catch (error) {\n writeJson(res, 500, { error: `拆书分析失败:${(error as Error).message}` })\n }\n },\n }\n\n // --------------------------------------------------------------- scenes\n /** 场景库:AI 提炼 / 采纳 / 更新 / 删除 / 图集。 */\n const scenesRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.scenes,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<ScenesRequest>(req)\n if (project.scenes === undefined) project.scenes = []\n const op = body?.op\n if (op === 'extract') {\n try {\n const candidates = await extractScenes(ctx, config, project)\n writeJson(res, 200, { scenes: project.scenes, candidates } satisfies ScenesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `场景提炼失败:${(error as Error).message}` })\n return\n }\n } else if ((op === 'adopt' || op === 'update') && body?.scene !== undefined) {\n const s = body.scene\n const idx = project.scenes.findIndex(x => x.name === s.name)\n if (idx === -1) project.scenes.push(s)\n else project.scenes[idx] = s\n } else if (op === 'remove' && body?.name !== undefined) {\n project.scenes = project.scenes.filter(x => x.name !== body.name)\n } else if (op === 'image') {\n const name = body?.name?.trim()\n const dataUrl = body?.dataUrl?.trim()\n if (name === undefined || name === '' || dataUrl === undefined || dataUrl === '') {\n writeJson(res, 400, { error: 'name(场景名)与 dataUrl 必填' })\n return\n }\n const scene = project.scenes.find(x => x.name === name)\n if (scene === undefined) {\n writeJson(res, 404, { error: `场景 ${name} 不存在` })\n return\n }\n const label = body?.label?.trim() ?? '全景'\n scene.gallery ??= []\n scene.gallery = scene.gallery.filter(g => g.label !== label)\n scene.gallery.push({ label, dataUrl })\n } else if (op === 'removeImage') {\n const name = body?.name?.trim()\n const label = body?.label?.trim() ?? ''\n const scene = project.scenes.find(x => x.name === name)\n if (scene !== undefined && label !== '') {\n scene.gallery = (scene.gallery ?? []).filter(g => g.label !== label)\n }\n } else {\n writeJson(res, 400, { error: `未知操作 ${op}` })\n return\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { scenes: project.scenes } satisfies ScenesResponse)\n },\n }\n\n // ----------------------------------------------------------- visual rules\n /** 视觉世界观规则:从道藏提炼(生图/生视频纠偏),或手动保存。 */\n const visualRulesRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.visualRules,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<VisualRulesRequest>(req)\n if (body?.op === 'extract') {\n try {\n const rules = await extractVisualRules(ctx, config, project)\n project.visualRules = rules\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { rules } satisfies VisualRulesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `视觉规则提炼失败:${(error as Error).message}` })\n return\n }\n } else if (body?.op === 'save' && Array.isArray(body.rules)) {\n project.visualRules = body.rules.filter(r => typeof r === 'string' && r.trim() !== '').map(r => r.trim().slice(0, 80)).slice(0, 12)\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { rules: project.visualRules } satisfies VisualRulesResponse)\n return\n }\n writeJson(res, 400, { error: 'op 须为 extract 或 save' })\n },\n }\n\n // ----------------------------------------------------------- production run\n /** 生产单执行器(单例):计划补足 → 逐章生成 → 被拒分级处理 → 断点续跑。 */\n const runner = new ProductionRunner({ ctx, getConfig })\n\n const runStartRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.runStart,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<RunStartRequest>(req)\n const config = getConfig()\n const project = loadProject(config.outputDir)\n if (project === undefined) {\n writeJson(res, 400, { error: '输出目录中没有项目' })\n return\n }\n const startNo = Number.isInteger(body?.startNo) && (body!.startNo! >= 1) ? body!.startNo! : 1\n let endNo: number\n if (Number.isInteger(body?.endNo) && (body!.endNo! >= startNo)) {\n endNo = body!.endNo!\n } else if (Number.isInteger(body?.count) && (body!.count! >= 1) && (body!.count! <= 200)) {\n const last = Math.max(0, ...project.chapters.map(c => c.no))\n endNo = last + body!.count!\n } else {\n writeJson(res, 400, { error: '请提供 endNo 或 count(1-200)' })\n return\n }\n try {\n const state = await runner.start(startNo, endNo)\n writeJson(res, 200, state satisfies RunState)\n } catch (error) {\n writeJson(res, 409, { error: (error as Error).message })\n }\n },\n }\n\n const runControlRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.runControl,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<RunControlRequest>(req)\n const state = runner.status()\n if (state === null) {\n writeJson(res, 400, { error: '没有生产单' })\n return\n }\n if (body?.action === 'pause') runner.pause()\n else if (body?.action === 'resume') runner.resume()\n else if (body?.action === 'stop') runner.stop()\n else {\n writeJson(res, 400, { error: 'action 须为 pause / resume / stop' })\n return\n }\n writeJson(res, 200, runner.status())\n },\n }\n\n const runStatusRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.runStatus,\n handler: (req, res) => {\n if (!guard(req, res, 'GET')) return\n writeJson(res, 200, runner.status())\n },\n }\n\n return [\n statusRoute,\n loadOutlineRoute,\n saveOutlineRoute,\n bibleRoute,\n volumesRoute,\n planRoute,\n generateRoute,\n reviewRoute,\n rewriteRoute,\n polishRoute,\n draftApplyRoute,\n draftDiscardRoute,\n summaryRoute,\n foreshadowRoute,\n exportRoute,\n chapterRoute,\n chapterCheckRoute,\n chapterSaveRoute,\n assetsRoute,\n styleEngineRoute,\n assistantRoute,\n assistantHistoryRoute,\n assistantClearRoute,\n bookshelfRoute,\n bookshelfActivateRoute,\n bookshelfRemoveRoute,\n resetRoute,\n auditRoute,\n charactersRefreshRoute,\n factsBackfillRoute,\n biblePatchRoute,\n blurbRoute,\n coverRoute,\n worldRoute,\n renameRoute,\n plotlinesRoute,\n rolesRoute,\n scenesRoute,\n visualRulesRoute,\n sensitiveRoute,\n reviewBackfillRoute,\n chapterResetRoute,\n chapterApproveRoute,\n configRoute,\n openFolderRoute,\n outlineSuggestRoute,\n breakdownRoute,\n runStartRoute,\n runControlRoute,\n runStatusRoute,\n ]\n}\n\n// Re-export for tests / type consumers.\nexport type {\n ConfigPatch,\n NovelConfig,\n StatusResponse,\n PlanResponse,\n LoadOutlineResponse,\n BibleResponse,\n VolumesResponse,\n ExportResponse,\n}\nexport { chapterFileName }\n","/**\n * dsh-novel-forge — host half. Mounts the AI novel-forge workbench: docx\n * outline import, LLM chapter planning, chapter-by-chapter generation\n * (3000-4000 chars each), Markdown output into your chosen folder, and the\n * /api/dsh-novel-forge route family. The browser half (./client) renders the\n * workbench panel. Everything rides official NPM SDK packages — no dsh source\n * changes.\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport { installSettingsSection, settingsNamespace } from '@deepseek-ai/dsh-settings'\nimport z from 'schemastery'\nimport type {} from '@deepseek-ai/dsh-host-webserver'\nimport type {} from '@deepseek-ai/dsh-llm'\nimport type {} from '@deepseek-ai/dsh-system-prompt'\nimport type { ConfigPatch, NovelConfig } from './protocol.ts'\nimport { makeRoutes } from './routes.ts'\nimport { activeBookOutputDir } from './bookshelf.ts'\n\n/** Stable cordis plugin name. */\nexport const name = 'novel-forge'\n\n/** Services required before the novel-forge surfaces can mount. */\nexport const inject = ['webServer', 'llm', 'systemPrompt']\n\n/**\n * Settings namespace of the novel-forge capability — the section the web\n * settings surface edits. Spelled here rather than imported: the browser half\n * spells the same value and must not depend on a Host package.\n */\nexport const NOVEL_SETTINGS_NAMESPACE = settingsNamespace('dsh-novel-forge')\n\n/** Plugin config, validated by the same-named schemastery schema. */\nexport interface Config {\n /** When true (default), a system-prompt section announces the plugin to every agent. */\n announceToAgent?: boolean\n /** Master switch for the plugin (routes, prompt section). */\n enabled?: boolean\n /** Absolute path of the default docx outline to load. */\n outlinePath?: string\n /** Absolute output directory for chapters + project state. */\n outputDir?: string\n /** LLM provider route. */\n provider?: string\n /** LLM model id. */\n model?: string\n /** LLM reasoning effort (off/low/high/max). */\n reasoningEffort?: 'off' | 'low' | 'high' | 'max'\n /** Target characters per chapter. */\n chapterChars?: number\n /** Max output tokens per chapter call. */\n maxTokens?: number\n /** Review pass threshold (0-100). */\n reviewPassScore?: number\n /** Whether generation auto-runs review after writing. */\n autoReview?: boolean\n /** Whether generation auto-runs the author review (hook/continuity/trend). */\n autoAuthorReview?: boolean\n /** 修订/润色产出草稿后自动附带一次 AI 审查(默认开,可在设置页关闭省 token)。 */\n autoReviewAfterRevise?: boolean\n /** 豆包/Seedream 生图 API Key。 */\n imageApiKey?: string\n /** 豆包/Seedream 生图模型 ID。 */\n imageApiModel?: string\n /** 是否启用豆包生图(默认关)。 */\n imageApiEnabled?: boolean\n}\n\nexport const Config: z<Config> = z.object({\n announceToAgent: z.boolean().default(true),\n enabled: z.boolean().default(true),\n outlinePath: z.string().default('D:\\\\ryan work\\\\harness\\\\novels\\\\归墟玉主\\\\《归墟玉主》全书大纲_重新排版版.docx'),\n outputDir: z.string().default('D:\\\\ryan work\\\\harness\\\\novels\\\\归墟玉主'),\n provider: z.string().default('deepseek-official'),\n model: z.string().default('deepseek-v4-flash'),\n reasoningEffort: z.union(['off', 'low', 'high', 'max']).default('off'),\n chapterChars: z.number().default(3500),\n maxTokens: z.number().default(12000),\n reviewPassScore: z.number().default(70),\n autoReview: z.boolean().default(true),\n autoAuthorReview: z.boolean().default(true),\n autoReviewAfterRevise: z.boolean().default(true),\n imageApiKey: z.string().default(''),\n imageApiModel: z.string().default(''),\n imageApiEnabled: z.boolean().default(false),\n})\n\n/** Schema defaults, re-read for hand-built test contexts. */\nconst DEFAULT_ANNOUNCE = true\nconst DEFAULT_OUTLINE_PATH = 'D:\\\\ryan work\\\\harness\\\\novels\\\\归墟玉主\\\\《归墟玉主》全书大纲_重新排版版.docx'\nconst DEFAULT_OUTPUT_DIR = 'D:\\\\ryan work\\\\harness\\\\novels\\\\归墟玉主'\nconst DEFAULT_PROVIDER = 'deepseek-official'\nconst DEFAULT_MODEL = 'deepseek-v4-flash'\nconst DEFAULT_REASONING_EFFORT = 'off' as const\nconst DEFAULT_CHAPTER_CHARS = 3500\nconst DEFAULT_MAX_TOKENS = 12000\nconst DEFAULT_REVIEW_PASS_SCORE = 70\nconst DEFAULT_AUTO_REVIEW = true\nconst DEFAULT_AUTO_AUTHOR_REVIEW = true\nconst DEFAULT_AUTO_REVIEW_AFTER_REVISE = true\n\n/** Order of the announcement section within the tool-guidance band. */\nconst SECTION_ORDER = 160\n\n/** Model-facing announcement: plugin presence, capabilities, and limits. */\nexport const NOVEL_GUIDANCE = '本机已安装 dsh-novel-forge 插件(AI 编译小说工作台):侧边栏「小说工坊」入口。能力:读取 docx 大纲(默认 D:\\\\ryan work\\\\harness\\\\novels\\\\归墟玉主 大纲)或粘贴大纲文本;用 LLM 提炼道藏(人设/世界观/金手指规则/写作红线,即设定圣经);生成卷计划与章节计划;逐章调用 LLM 生成 3000-4000 字正文并保存为 Markdown(默认输出到 D:\\\\ryan work\\\\harness\\\\novels\\\\归墟玉主);每章自动生成摘要(叙事记忆)、自动 AI 审稿(人设/设定/红线/文笔/爽点/逻辑),支持按审稿意见重写、去 AI 味润色、暗线(伏笔)管理、批量连写与全本导出(txt/md)。限制:生成消耗 LLM API 额度;输出目录与模型可在插件设置中修改;章节正文质量取决于大纲完整度。用户提到「小说 / 大纲 / 写小说 / 章节 / 审稿 / 润色 / 归墟玉主」时即指本插件,请据此协作。'\n\n/** Resolve a config-like value into the full runtime config. */\nexport function resolveConfig(value: Partial<Config> | undefined): NovelConfig {\n return {\n outlinePath: value?.outlinePath ?? DEFAULT_OUTLINE_PATH,\n outputDir: value?.outputDir ?? DEFAULT_OUTPUT_DIR,\n provider: value?.provider ?? DEFAULT_PROVIDER,\n model: value?.model ?? DEFAULT_MODEL,\n reasoningEffort: value?.reasoningEffort ?? DEFAULT_REASONING_EFFORT,\n chapterChars: value?.chapterChars ?? DEFAULT_CHAPTER_CHARS,\n maxTokens: value?.maxTokens ?? DEFAULT_MAX_TOKENS,\n reviewPassScore: value?.reviewPassScore ?? DEFAULT_REVIEW_PASS_SCORE,\n autoReview: value?.autoReview ?? DEFAULT_AUTO_REVIEW,\n autoAuthorReview: value?.autoAuthorReview ?? DEFAULT_AUTO_AUTHOR_REVIEW,\n autoReviewAfterRevise: value?.autoReviewAfterRevise ?? DEFAULT_AUTO_REVIEW_AFTER_REVISE,\n imageApiKey: value?.imageApiKey,\n imageApiModel: value?.imageApiModel,\n imageApiEnabled: value?.imageApiEnabled ?? false,\n }\n}\n\n/**\n * Mount the routes and announcement.\n * @param ctx - host plugin context carrying webServer/llm/systemPrompt.\n * @param config - resolved plugin config (schema defaults applied by the loader).\n */\nexport function apply(ctx: Context, config?: Config): void {\n // The live source the routes read: the settings section once the web\n // settings surface is served, the composition entry otherwise.\n let current: () => Config = () => config ?? {}\n const resolve = (): NovelConfig => {\n const resolved = resolveConfig(current())\n // 书架激活的书优先决定输出目录(settings 仍可改默认值)。\n const shelfDir = activeBookOutputDir()\n if (shelfDir !== undefined) {\n return { ...resolved, outputDir: shelfDir }\n }\n return resolved\n }\n\n const patchConfig = async (patch: ConfigPatch): Promise<NovelConfig> => {\n const next: ConfigPatch = {}\n if (patch.outlinePath !== undefined) next.outlinePath = patch.outlinePath\n if (patch.outputDir !== undefined) next.outputDir = patch.outputDir\n if (patch.provider !== undefined) next.provider = patch.provider\n if (patch.model !== undefined) next.model = patch.model\n if (patch.reasoningEffort !== undefined) next.reasoningEffort = patch.reasoningEffort\n if (patch.chapterChars !== undefined) next.chapterChars = patch.chapterChars\n if (patch.maxTokens !== undefined) next.maxTokens = patch.maxTokens\n if (patch.reviewPassScore !== undefined) next.reviewPassScore = patch.reviewPassScore\n if (patch.autoReview !== undefined) next.autoReview = patch.autoReview\n if (patch.autoAuthorReview !== undefined) next.autoAuthorReview = patch.autoAuthorReview\n if (patch.autoReviewAfterRevise !== undefined) next.autoReviewAfterRevise = patch.autoReviewAfterRevise\n if (patch.imageApiKey !== undefined) next.imageApiKey = patch.imageApiKey\n if (patch.imageApiModel !== undefined) next.imageApiModel = patch.imageApiModel\n if (patch.imageApiEnabled !== undefined) next.imageApiEnabled = patch.imageApiEnabled\n // Persist through the settings seam when available; otherwise keep in memory.\n // (ctx.get is the non-strict service access — no inject requirement, same\n // pattern installSettingsSection itself uses.)\n const settings = ctx.get('settings')\n if (settings !== undefined) {\n await settings.update(NOVEL_SETTINGS_NAMESPACE, next as Record<string, unknown>)\n } else {\n current = () => ({ ...current(), ...next })\n }\n return resolve()\n }\n\n let disposeSection: (() => void) | undefined\n let disposeRoutes: (() => void) | undefined\n\n const sync = (): void => {\n if (disposeSection !== undefined) {\n disposeSection()\n disposeSection = undefined\n }\n if (disposeRoutes !== undefined) {\n disposeRoutes()\n disposeRoutes = undefined\n }\n const value = resolve()\n if (!(current().enabled ?? true)) return\n if (current().announceToAgent ?? DEFAULT_ANNOUNCE) {\n disposeSection = ctx.systemPrompt.section({\n name: 'plugin:dsh-novel-forge',\n order: SECTION_ORDER,\n text: NOVEL_GUIDANCE,\n })\n }\n const routes = makeRoutes({ ctx, getConfig: resolve, patchConfig })\n disposeRoutes = ctx.effect(\n () => {\n const disposers = routes.map(route => ctx.webServer.register(route))\n return () => { for (const dispose of disposers) dispose() }\n },\n 'dsh-novel-forge: routes',\n )\n void value\n }\n\n installSettingsSection(ctx, NOVEL_SETTINGS_NAMESPACE, Config, config ?? {}, {\n setSource: (source) => {\n current = source\n sync()\n },\n onChange: sync,\n })\n\n // 运行时 skill:章节批量生产与值守处理(只在本插件环境可用)。\n // 通过 ctx.get('skills') 获取注册表(服务存在时注册,缺失则跳过,不影响其他能力)。\n const skillsService = ctx.get('skills') as { register?: (skill: { name: string; description: string; content: string }) => () => void } | undefined\n if (skillsService?.register !== undefined) {\n const disposeSkill = skillsService.register({\n name: 'novel-forge-chapter-batch',\n description: '批量生成小说章节并值守处理审稿未过的章节(豁免/按意见修订/验证模式/重新生成),依赖 dsh-novel-forge 的 /api/dsh-novel-forge/* 路由。',\n content: [\n '# 小说章节批量生产与值守处理',\n '',\n '## 0. 值守纪律(最高优先级,违反即空转)',\n '1. 启动后台任务后立即停下,不轮询、不连续 wait、不做无意义动作——后台任务完成时运行时自动通知。',\n '2. 只有收到「任务完成」通知或用户新消息时,才继续下一步(读结果→处理未过→汇报)。',\n '3. 等待期间可做与当前任务无关的其他有用工作,但不得为等任务而空转。',\n '4. 任务因 web 重启中断时:待 3080 恢复后,复位卡死章节(generating/error → reset)再续跑,并向用户说明中断原因。',\n '',\n '## 1. 前置检查',\n '1. `GET /api/dsh-novel-forge/status` 确认服务在跑,读项目章节数。',\n '2. 列出目标区间 pending 章节号,避免重复生成已处理章节。',\n '3. **串行执行,禁止并行写 project.json**(并发会互相覆盖状态,实测教训)。',\n '',\n '## 2. 批量生成',\n '逐章串行调用 `POST /generate` `{ chapterNo, skipReview: false }`(走完整质量门:生成→摘要+编年录→审稿→复盘)。',\n '响应为 NDJSON,找 review 帧取 score/passed。每章 2-5 分钟;失败重试 1 次;后台跑并告知预计时长。',\n '用 Node 脚本(fetch 逐章循环),避免 PowerShell 转义坑,用完删除。',\n '',\n '## 3. 未过章节分级处理',\n '### A. 无 high → 豁免通过:`POST /chapter/approve`(主观项不磨)',\n '### B. 有 high 且明确 → 按意见修订 + 验证模式:',\n '1. 拼指令 `按审稿意见修订(优先处理):\\n[severity] item → suggestion`(high 优先,无 high 取前 3 medium)',\n '2. `POST /rewrite` 产草稿;3. `POST /chapter/check` 带 `previousReport` 走验证模式(只核对原意见解决+只挑新增 high)',\n '4. 判定 `passed || 无 high` 可接受;5. `POST /draft/apply` 带 passed 报告落盘 approved',\n '6. 不可接受 → 第二轮修订(指令更精确)→ 再验证;每章最多修 2 轮,仍不过保留草稿待人工',\n '### C. 结构性 high(修订改不好)→ `POST /draft/discard` 后 `POST /generate` 重写,剩主观项再走 A',\n '### D. error 状态 → `POST /chapter/reset` 后 `POST /generate`',\n '注意:approved 但 review 有 high 的保留不动;修订指令越精确越有效(具体数字/行为一次就过)。',\n '',\n '## 4. 收尾',\n '`GET /status` 验证目标区间全 approved;可选刷新剧情线(`POST /plotlines` op=refresh,注意只读最近 8 章摘要);汇报通过/未过/失败与遗留项。',\n '',\n '## 5. 已知陷阱',\n '- 并发写 project.json 互相覆盖 → 必须串行',\n '- rewrite 草稿可能偶发不落盘 → 应用前检查 pendingDraft,不存在则重跑',\n '- PowerShell 调 API 引号/中文转义是坑 → 用 Node 脚本',\n '- 验证模式 500 偶发 → 重试一次',\n ].join('\\n'),\n })\n ctx.effect(() => disposeSkill, 'dsh-novel-forge: skill')\n }\n\n // Initial registration from the composition entry.\n sync()\n}\n"],"mappings":";;;;;;;;;;;AAgBA,MAAa,0BAA2C;CACtD;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAM;EAAI;EACnC,YAAY;GACV;GACA;GACA;EACF;EACA,eAAe,CACb,oBACA,2BACF;EACA,eAAe,CACb,kBACA,eACF;EACA,aAAa,CACX,sBACA,gBACF;EACA,uBAAuB;GAAC;GAAU;GAAW;EAAW;CAC1D;CACA;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAM;EAAI;EACnC,YAAY;GACV;GACA;GACA;EACF;EACA,eAAe,CACb,4BACA,gBACF;EACA,eAAe,CACb,yBACA,iBACF;EACA,aAAa,CACX,gBACA,eACF;EACA,uBAAuB;GAAC;GAAa;GAAU;GAAY;GAAU;EAAQ;CAC/E;CACA;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAM;EAAI;EACnC,YAAY;GACV;GACA;GACA;EACF;EACA,eAAe,CACb,oBACA,kBACF;EACA,eAAe,CACb,qBACA,aACF;EACA,aAAa,CACX,oBACA,cACF;EACA,uBAAuB;GAAC;GAAa;GAAU;GAAY;EAAQ;CACrE;CACA;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAM;EAAI;EACnC,YAAY;GACV;GACA;GACA;EACF;EACA,eAAe,CACb,qBACA,aACF;EACA,eAAe,CACb,iBACA,iBACF;EACA,aAAa,CACX,qBACA,cACF;EACA,uBAAuB;GAAC;GAAU;GAAU;GAAW;EAAU;CACnE;CACA;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAM;EAAI;EACnC,YAAY,CACV,gCACA,gBACF;EACA,eAAe,CACb,yBACF;EACA,eAAe,CACb,kBACA,WACF;EACA,aAAa,CACX,mBACA,SACF;EACA,uBAAuB;GAAC;GAAW;GAAW;EAAQ;CACxD;CACA;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAM;EAAI;EACnC,YAAY,CACV,4BACA,iBACF;EACA,eAAe,CACb,oBACA,WACF;EACA,eAAe,CACb,oBACA,eACF;EACA,aAAa,CACX,gBACA,UACF;EACA,uBAAuB;GAAC;GAAU;GAAY;EAAU;CAC1D;CACA;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAM;EAAI;EACnC,YAAY;GACV;GACA;GACA;EACF;EACA,eAAe,CACb,mBACA,gBACF;EACA,eAAe,CACb,mBACA,WACF;EACA,aAAa,CACX,iBACA,gBACF;EACA,uBAAuB;GAAC;GAAU;GAAU;EAAS;CACvD;CACA;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAQ;EAAI;EACrC,YAAY;GACV;GACA;GACA;EACF;EACA,eAAe,CACb,gBACA,mBACF;EACA,eAAe,CACb,mBACA,aACF;EACA,aAAa,CACX,mBACA,gBACF;EACA,uBAAuB;GAAC;GAAa;GAAU;GAAU;EAAQ;CACnE;AACF;;AAKA,MAAa,wBAAsC;CACjD;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,gBAAgB;GAAC;GAAO;GAAO;GAAQ;GAAQ;GAAQ;EAAM;EAC7D,SAAS;CACX;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,gBAAgB;GAAC;GAAQ;GAAQ;GAAQ;GAAO;EAAK;EACrD,SAAS;CACX;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,gBAAgB;GAAC;GAAO;GAAQ;GAAQ;EAAM;EAC9C,SAAS;CACX;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,gBAAgB;GAAC;GAAS;GAAS;EAAQ;EAC3C,SAAS;CACX;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,gBAAgB,CAAC;EACjB,SAAS;CACX;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,gBAAgB,CAAC;EACjB,SAAS;CACX;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,gBAAgB;GAAC;GAAO;GAAS;EAAM;EACvC,SAAS;CACX;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,gBAAgB;GAAC;GAAM;GAAM;GAAM;EAAI;EACvC,SAAS;CACX;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,gBAAgB;GAAC;GAAM;GAAM;GAAO;GAAO;GAAM;GAAM;GAAM;EAAI;EACjE,SAAS;CACX;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,gBAAgB,CAAC;EACjB,SAAS;CACX;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,gBAAgB,CAAC;EACjB,SAAS;CACX;CACA;EACE,MAAM;EACN,OAAO;EACP,KAAK;EACL,gBAAgB,CAAC;EACjB,SAAS;CACX;AACF;;AAGA,MAAa,wBAAqC;CAChD;EACE,MAAM;EACN,aAAa;EACb,UAAU;GACR;IAAE,MAAM;IAAO,aAAa;IAAqC,UAAU,CAAC;GAAE;GAC9E;IAAE,MAAM;IAAO,aAAa;IAAiC,UAAU,CAAC;GAAE;GAC1E;IAAE,MAAM;IAAO,aAAa;IAAkC,UAAU,CAAC;GAAE;EAC7E;CACF;CACA;EACE,MAAM;EACN,aAAa;EACb,UAAU;GACR;IAAE,MAAM;IAAQ,aAAa;IAA0B,UAAU,CAAC;GAAE;GACpE;IAAE,MAAM;IAAQ,aAAa;IAA2B,UAAU,CAAC;GAAE;GACrE;IAAE,MAAM;IAAQ,aAAa;IAA8B,UAAU,CAAC;GAAE;EAC1E;CACF;CACA;EACE,MAAM;EACN,aAAa;EACb,UAAU;GACR;IAAE,MAAM;IAAQ,aAAa;IAAyB,UAAU,CAAC;GAAE;GACnE;IAAE,MAAM;IAAQ,aAAa;IAA+B,UAAU,CAAC;GAAE;GACzE;IAAE,MAAM;IAAO,aAAa;IAA6B,UAAU,CAAC;GAAE;EACxE;CACF;CACA;EACE,MAAM;EACN,aAAa;EACb,UAAU;GACR;IAAE,MAAM;IAAO,aAAa;IAA+B,UAAU,CAAC;GAAE;GACxE;IAAE,MAAM;IAAQ,aAAa;IAAgC,UAAU,CAAC;GAAE;GAC1E;IAAE,MAAM;IAAQ,aAAa;IAA+B,UAAU,CAAC;GAAE;EAC3E;CACF;CACA;EACE,MAAM;EACN,aAAa;EACb,UAAU,CACR;GAAE,MAAM;GAAQ,aAAa;GAA2B,UAAU,CAAC;EAAE,GACrE;GAAE,MAAM;GAAQ,aAAa;GAA6B,UAAU,CAAC;EAAE,CACzE;CACF;CACA;EACE,MAAM;EACN,aAAa;EACb,UAAU,CACR;GAAE,MAAM;GAAQ,aAAa;GAA2B,UAAU,CAAC;EAAE,GACrE;GAAE,MAAM;GAAQ,aAAa;GAA8B,UAAU,CAAC;EAAE,CAC1E;CACF;AACF;;AAGA,MAAa,4BAA+C;CAC1D;EACE,MAAM;EACN,QAAQ;EACR,mBAAmB;EACnB,SAAS;GAAC;GAAQ;GAAS;GAAU;EAAS;EAC9C,OAAO;GAAC;GAAU;GAAU;EAAS;EACrC,SAAS;CACX;CACA;EACE,MAAM;EACN,QAAQ;EACR,mBAAmB;EACnB,SAAS;GAAC;GAAS;GAAQ;GAAQ;EAAQ;EAC3C,OAAO;GAAC;GAAQ;GAAS;EAAM;EAC/B,SAAS;CACX;CACA;EACE,MAAM;EACN,QAAQ;EACR,mBAAmB;EACnB,SAAS;GAAC;GAAQ;GAAQ;GAAU;EAAM;EAC1C,OAAO;GAAC;GAAS;GAAU;EAAM;EACjC,SAAS;CACX;CACA;EACE,MAAM;EACN,QAAQ;EACR,mBAAmB;EACnB,SAAS;GAAC;GAAQ;GAAQ;GAAU;EAAO;EAC3C,OAAO;GAAC;GAAQ;GAAS;EAAS;EAClC,SAAS;CACX;CACA;EACE,MAAM;EACN,QAAQ;EACR,mBAAmB;EACnB,SAAS;GAAC;GAAQ;GAAQ;GAAS;EAAM;EACzC,OAAO;GAAC;GAAS;GAAQ;EAAM;EAC/B,SAAS;CACX;AACF;;AAKA,SAAgB,qBAAoC;CAClD,OAAO;EACL,uBAAuB,CAAC;EACxB,aAAa,CAAC;EACd,aAAa,CAAC;CAChB;AACF;;AAGA,SAAgB,qBAAqB,QAAiD;CACpF,MAAM,SAAS,QAAQ,eAAe,CAAC;CACvC,MAAM,cAAc,IAAI,IAAI,OAAO,KAAI,MAAK,EAAE,IAAI,CAAC;CACnD,OAAO,CAAC,GAAG,sBAAsB,QAAO,MAAK,CAAC,YAAY,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,MAAM;AACnF;;AAGA,SAAgB,kBAAkB,QAA2C;CAC3E,MAAM,QAAQ,qBAAqB,MAAM;CACzC,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,MAAM,QAAQ,OAAe,QAAwB,MAAM,SAAS,MAAM,MAAM,MAAM,GAAG,GAAG,IAAI,MAAM;CACtG,OAAO,CACL,mEACA,GAAG,MAAM,KAAI,MAAK,KAAK,EAAE,KAAK,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,KAAK,QAAQ,KAAK,EAAE,KAAK,EAAE,MAAM,IAAI,CAC1G,CAAC,CAAC,KAAK,IAAI;AACb;;AAGA,SAAgB,0BAA0B,QAA2C;CACnF,MAAM,WAAqB,CAAC;CAC5B,IAAI,QAAQ,UAAU,KAAA,GAAW;EAC/B,SAAS,KAAK,8DAA8D;EAC5E,SAAS,KAAK,MAAM,OAAO,MAAM,MAAM;EACvC,IAAI,OAAO,MAAM,gBAAgB,IAAI,SAAS,KAAK,QAAQ,OAAO,MAAM,aAAa;EACrF,MAAM,QAAQ,MAAiB,UAAwB;GACrD,KAAK,MAAM,SAAS,KAAK,UAAU;IACjC,SAAS,KAAK,GAAG,KAAK,OAAO,KAAK,EAAE,IAAI,MAAM,KAAK,GAAG,MAAM,aAAa;IACzE,KAAK,OAAO,QAAQ,CAAC;GACvB;EACF;EACA,KAAK,OAAO,OAAO,CAAC;CACtB;CACA,MAAM,QAAQ,CACZ,GAAI,QAAQ,uBAAuB,KAAA,IAAY,CAAC,OAAO,kBAAkB,IAAI,CAAC,GAC9E,GAAI,QAAQ,yBAAyB,CAAC,CACxC;CACA,IAAI,MAAM,SAAS,GAAG;EACpB,SAAS,KAAK,0DAA0D;EACxE,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,MAAM,KAAK,UAAU,UAAU;GACrC,SAAS,KAAK,QAAQ,KAAK,KAAK,GAAG,IAAI,QAAQ,KAAK,QAAQ;GAC5D,SAAS,KAAK,UAAU,KAAK,mBAAmB;GAChD,IAAI,KAAK,QAAQ,SAAS,GAAG,SAAS,KAAK,UAAU,KAAK,QAAQ,KAAK,GAAG,GAAG;GAC7E,IAAI,KAAK,MAAM,SAAS,GAAG,SAAS,KAAK,cAAc,KAAK,MAAM,KAAK,GAAG,GAAG;EAC/E;CACF;CACA,OAAO,SAAS,KAAK,IAAI;AAC3B;;AAGA,SAAgB,kBAAkB,QAA2C;CAC3E,MAAM,SAAS,QAAQ,eAAe,CAAC;CACvC,IAAI,OAAO,WAAW,GAAG,OAAO;CAChC,MAAM,WAAqB,CAAC,2DAA2D;CACvF,KAAK,MAAM,SAAS,QAAQ;EAC1B,SAAS,KAAK,IAAI,MAAM,KAAK,EAAE;EAC/B,MAAM,UAAU,UAA8B,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC;EAChE,IAAI,MAAM,WAAW,SAAS,GAAG,SAAS,KAAK,aAAa,OAAO,MAAM,UAAU,CAAC,CAAC,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;EAClH,IAAI,MAAM,cAAc,SAAS,GAAG,SAAS,KAAK,YAAY,OAAO,MAAM,aAAa,CAAC,CAAC,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;EACvH,IAAI,MAAM,iBAAiB,SAAS,GAAG,SAAS,KAAK,aAAa,OAAO,MAAM,gBAAgB,CAAC,CAAC,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;EAC9H,IAAI,MAAM,WAAW,SAAS,GAAG,SAAS,KAAK,YAAY,OAAO,MAAM,UAAU,CAAC,CAAC,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;CACnH;CACA,OAAO,SAAS,KAAK,IAAI;AAC3B;;AAGA,SAAgB,gBAAgB,QAA2C;CAMzE,OALc;EACZ,0BAA0B,MAAM;EAChC,kBAAkB,MAAM;EACxB,kBAAkB,MAAM;CAC1B,CAAC,CAAC,QAAO,SAAQ,SAAS,EACf,CAAC,CAAC,KAAK,MAAM;AAC1B;;AAiBA,SAAgB,0BAAkC;CAChD,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;;AC5fA,MAAa,sBAA0C;CACrD;EACE,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,YAAY;CACd;CACA;EACE,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,YAAY;CACd;CACA;EACE,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,YAAY;CACd;CACA;EACE,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,YAAY;CACd;CACA;EACE,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,YAAY;CACd;CACA;EACE,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,YAAY;CACd;CACA;EACE,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,YAAY;CACd;AACF;AAEA,SAAgB,oBAAoB,SAA0B;CAC5D,IAAI,CAAC,SAAS,OAAO;CAErB,OADe,oBAAoB,MAAK,MAAK,EAAE,OAAO,OAC1C,CAAC,EAAE,UAAU;AAC3B;;;;;;;;;;;;;;;AC/CA,MAAa,sBAA6C;CACxD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AA8BA,MAAa,eAAe;;AAK5B,SAAS,aAAa,MAAsB;CAC1C,OAAO,KACJ,QAAQ,iBAAiB,EAAE,CAAC,CAC5B,QAAQ,QAAQ,GAAG,CAAC,CACpB,KAAK,CAAC,CACN,MAAM,GAAG,EAAE;AAChB;;AAGA,SAAgB,gBAAgB,SAA8B;CAC5D,MAAM,QAAQ,aAAa,QAAQ,KAAK,KAAK,IAAI,QAAQ,GAAG;CAC5D,OAAO,IAAI,OAAO,QAAQ,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE,IAAI,MAAM;AAC3D;;AAGA,SAAgB,cAAc,SAAyB;CAErD,QADa,QAAQ,MAAM,IAAI,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,CAAC,CAAC,MAAK,MAAK,EAAE,SAAS,CAC9D,KAAK,QAAA,CAAS,QAAQ,MAAM,EAAE,CAAC,CAAC,QAAQ,QAAQ,EAAE,CAAC,CAAC,MAAM,GAAG,EAAE;AAC5E;;AAKA,SAAgB,YAAY,WAA6C;CACvE,MAAM,OAAO,KAAK,WAAW,YAAY;CACzC,IAAI,CAAC,WAAW,IAAI,GAAG,OAAO,KAAA;CAC9B,IAAI;EACF,IAAI,UAAU,aAAa,MAAM,MAAM;EAEvC,IAAI,QAAQ,WAAW,CAAC,MAAM,OAAQ,UAAU,QAAQ,MAAM,CAAC;EAC/D,MAAM,MAAM,KAAK,MAAM,OAAO;EAC9B,IAAI,OAAO,IAAI,YAAY,YAAY,CAAC,MAAM,QAAQ,IAAI,QAAQ,GAAG,OAAO,KAAA;EAE5E,IAAI,CAAC,MAAM,QAAQ,IAAI,WAAW,GAAG,IAAI,cAAc,CAAC;EACxD,IAAI,IAAI,WAAW,KAAA,KAAa,OAAO,IAAI,WAAW,UAAU,IAAI,SAAS,mBAAmB;EAChG,IAAI,CAAC,MAAM,QAAQ,IAAI,OAAO,WAAW,GAAG,IAAI,OAAO,cAAc,CAAC;EACtE,IAAI,CAAC,MAAM,QAAQ,IAAI,OAAO,qBAAqB,GAAG,IAAI,OAAO,wBAAwB,CAAC;EAC1F,IAAI,CAAC,MAAM,QAAQ,IAAI,OAAO,WAAW,GAAG,IAAI,OAAO,cAAc,CAAC;EACtE,IAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,GAAG,IAAI,QAAQ,CAAC;EAC5C,IAAI,CAAC,MAAM,QAAQ,IAAI,SAAS,GAAG,IAAI,YAAY,CAAC;EACpD,OAAO;CACT,QAAQ;EACN;CACF;AACF;;AAGA,SAAgB,YAAY,WAAmB,SAA6B;CAC1E,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;CACxC,cAAc,KAAK,WAAW,YAAY,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,GAAG,MAAM;AACvF;;;;;;;AAQA,SAAgB,sBAAsB,WAAmB,SAA6B;CACpF,IAAI;EACF,MAAM,OAAO,YAAY,SAAS;EAClC,IAAI,SAAS,KAAA,GAAW;EACxB,QAAQ,QAAQ,KAAK;EACrB,QAAQ,QAAQ,KAAK;EACrB,QAAQ,YAAY,KAAK;EACzB,QAAQ,aAAa,KAAK;EAC1B,QAAQ,QAAQ,KAAK;EACrB,QAAQ,YAAY,KAAK;EACzB,QAAQ,QAAQ,KAAK;EACrB,QAAQ,SAAS,KAAK;EACtB,QAAQ,QAAQ,KAAK;EACrB,QAAQ,UAAU,KAAK;CACzB,QAAQ,CAAoB;AAC9B;;;;;AAQA,MAAM,kBAAqE;CAEzE;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAS,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAChE;EAAE,MAAM;EAAQ,UAAU;CAAK;CAE/B;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAQ,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC/D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAO,UAAU;CAAK;CAE9D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAO,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC9D;EAAE,MAAM;EAAQ,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC/D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAO,UAAU;CAAK;CAE9D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAO,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC9D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAO,UAAU;CAAK;CAE9D;EAAE,MAAM;EAAO,UAAU;CAAK;CAAG;EAAE,MAAM;EAAO,UAAU;CAAK;CAC/D;EAAE,MAAM;EAAS,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAChE;EAAE,MAAM;EAAO,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC9D;EAAE,MAAM;EAAQ,UAAU;CAAK;CAAG;EAAE,MAAM;EAAO,UAAU;CAAK;CAChE;EAAE,MAAM;EAAO,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC9D;EAAE,MAAM;EAAM,UAAU;CAAK;CAE7B;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAO,UAAU;CAAK;CAAG;EAAE,MAAM;EAAQ,UAAU;CAAK;CAChE;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAM,UAAU;CAAK;CAAG;EAAE,MAAM;EAAM,UAAU;CAAK;CAC7D;EAAE,MAAM;EAAQ,UAAU;CAAK;AACjC;;AAGA,SAAgB,mBAAmB,MAAwE;CACzG,MAAM,OAAiE,CAAC;CACxE,KAAK,MAAM,SAAS,iBAAiB;EACnC,IAAI,QAAQ;EACZ,IAAI,MAAM,KAAK,QAAQ,MAAM,IAAI;EACjC,OAAO,QAAQ,IAAI;GACjB;GACA,MAAM,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM,KAAK,MAAM;EACxD;EACA,IAAI,QAAQ,GAAG,KAAK,KAAK;GAAE,MAAM,MAAM;GAAM,UAAU,MAAM;GAAU;EAAM,CAAC;CAChF;CACA,OAAO;AACT;;AAGA,SAAgB,iBAAiB,WAA6B;CAC5D,IAAI,CAAC,WAAW,SAAS,GAAG,OAAO,CAAC;CACpC,IAAI;EACF,OAAO,YAAY,SAAS,CAAC,CAC1B,QAAO,SAAQ,iBAAiB,KAAK,IAAI,KAAK,CAAC,KAAK,SAAS,SAAS,CAAC,CAAC,CACxE,MAAM,GAAG,MAAM;GAGd,OAFW,OAAO,WAAW,KAAK,CAAC,CAAC,GAAG,MAAM,CAErC,IADG,OAAO,WAAW,KAAK,CAAC,CAAC,GAAG,MAAM,CAChC;EACf,CAAC;CACL,QAAQ;EACN,OAAO,CAAC;CACV;AACF;;AAGA,SAAgB,oBAAoB,SAAuB,WAAyB;CAClF,MAAM,wBAAQ,IAAI,IAAoB;CACtC,KAAK,MAAM,QAAQ,iBAAiB,SAAS,GAAG;EAC9C,MAAM,KAAK,OAAO,WAAW,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC;EACjD,IAAI,KAAK,GAAG,MAAM,IAAI,OAAO,EAAE,GAAG,IAAI;CACxC;CACA,KAAK,MAAM,WAAW,QAAQ,UAAU;EACtC,MAAM,OAAO,MAAM,IAAI,OAAO,QAAQ,EAAE,CAAC;EACzC,IAAI,SAAS,KAAA,MAAc,QAAQ,WAAW,aAAa,QAAQ,WAAW,eAAe;GAC3F,QAAQ,SAAS;GACjB,QAAQ,OAAO;EACjB;CACF;CACA,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;AAC7C;;AAGA,SAAgB,gBAAgB,WAAmB,SAA0C;CAC3F,IAAI,QAAQ,SAAS,KAAA,GAAW,OAAO,KAAA;CACvC,MAAM,OAAO,KAAK,WAAW,QAAQ,IAAI;CACzC,IAAI,CAAC,WAAW,IAAI,GAAG,OAAO,KAAA;CAC9B,OAAO,aAAa,MAAM,MAAM;AAClC;;AAGA,SAAgB,cAAc,SAAiB,aAAoC;CACjF,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;CACnC,OAAO;EACL,UAAU,cAAc,OAAO;EAC/B;EACA;EACA,UAAU,CAAC;EACX,aAAa,CAAC;EACd,QAAQ,mBAAmB;EAC3B,OAAO,CAAC;EACR,WAAW;EACX,WAAW;CACb;AACF;;AAKA,eAAe,SACb,KACA,QACA,SACiB;CACjB,MAAM,WAAsB,CAAC,kBAAkB;EAC7C,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM,QAAQ;EAAK,CAAC;EAC9C,QAAQ;GAAE,MAAM;GAAU,QAAQ;EAAkB;CACtD,CAAC,CAAC;CACF,MAAM,UAA2B;EAC/B,UAAU,OAAO;EACjB,OAAO,OAAO;EACd;EACA,QAAQ,QAAQ;EAChB,WAAW,QAAQ,aAAa,OAAO;EACvC,aAAa,QAAQ,eAAe;EACpC,iBAAiB,kBAAkB,OAAO,mBAAmB,KAAK;CACpE;CACA,MAAM,YAAY,IAAI,eAAe;CACrC,WAAW,MAAM,SAAS,IAAI,IAAI,OAAO,OAAO,GAC9C,UAAU,KAAK,KAAK;CAEtB,MAAM,SAAS,UAAU;CACzB,IAAI,OAAO,SAAS,WAAW,OAAO,SAAS,WAC7C,MAAM,IAAI,MAAM,YAAY,OAAO,KAAK,KAAK,OAAO,QAAQ,SAAS;CAEvE,IAAI,OAAO,SAAS,cAClB,MAAM,IAAI,MAAM,gCAAgC;CAElD,MAAM,SAAS,UAAU,OAAO;CAIhC,IAAI,QAAQ,IAAI,oBAAoB,KAClC,QAAQ,MAAM,mDAAmD,KAAK,UAAU,MAAM,GAAG,OAAO,KAAI,MAAK,GAAG,EAAE,KAAK,GAAG,UAAU,IAAI,EAAE,KAAK,SAAS,KAAK,CAAC;CAK5J,IAAI,OAHe,OAChB,QAAQ,UAA4F,MAAM,SAAS,MAAM,CAAC,CAC1H,KAAI,UAAS,MAAM,IACF,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK;CAItC,IAAI,SAAS,IAAI;EACf,MAAM,YAAY,OACf,QAAQ,UAAwD,MAAM,SAAS,WAAW,CAAC,CAC3F,KAAI,UAAS,MAAM,IAAI,CAAC,CACxB,KAAK,IAAI,CAAC,CACV,KAAK;EACR,IAAI,cAAc,IAAI,OAAO;CAC/B;CACA,OAAO;AACT;;;;;;;AAQA,SAAS,UAAa,MAAc,WAAuB;CACzD,MAAM,aAAuB,CAAC;CAC9B,MAAM,QAAQ,UAAoC;EAChD,IAAI,UAAU,KAAA,KAAa,MAAM,KAAK,MAAM,IAAI,WAAW,KAAK,MAAM,KAAK,CAAC;CAC9E;CAGA,KAAK,IAAI;CAET,KADe,+BAA+B,KAAK,IACzC,CAAC,GAAG,EAAE;CAEhB,MAAM,SAAS,YAAY,MAAM;CACjC,MAAM,SAAS,YAAY,MAAM;CACjC,MAAM,QAAQ,KAAK,QAAQ,MAAM;CACjC,MAAM,MAAM,KAAK,YAAY,MAAM;CACnC,IAAI,UAAU,MAAM,MAAM,OAAO,KAAK,KAAK,MAAM,OAAO,MAAM,CAAC,CAAC;CAEhE,MAAM,UAAU,KAAK,QAAQ,IAAI,OAAO,GAAG,OAAO,WAAW,GAAG,MAAM;CACtE,KAAK,OAAO;CACZ,MAAM,SAAS,QAAQ,QAAQ,MAAM;CACrC,IAAI,WAAW,IAAI,KAAK,QAAQ,MAAM,MAAM,CAAC;CAG7C,MAAM,UAAU,UAA0B;EACxC,IAAI,MAAM;EACV,IAAI,WAAW;EACf,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,KAAK,MAAM;GACjB,IAAI,UAAU;IACZ,IAAI,OAAO,MAAM;KACf,OAAO,MAAM,MAAM,IAAI,MAAM;KAC7B;KACA;IACF;IACA,IAAI,OAAO,MAAK;KACd,WAAW;KACX,OAAO;KACP;IACF;IACA,IAAI,OAAO,QAAQ,OAAO,MAAM;KAC9B,OAAO;KACP;IACF;IACA,OAAO;GACT,OAAO;IACL,IAAI,OAAO,MAAK,WAAW;IAC3B,OAAO;GACT;EACF;EACA,OAAO;CACT;CAEA,KAAK,MAAM,aAAa,YACtB,KAAK,MAAM,WAAW,CAAC,WAAW,OAAO,SAAS,CAAC,GACjD,IAAI;EACF,MAAM,QAAQ,KAAK,MAAM,OAAO;EAChC,IAAI,CAAC,aAAa,MAAM,QAAQ,KAAK,GAAG,OAAO;EAG/C,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,KAAK,MAAM,OAAO,OAAO,KAAK,KAAgC,GAAG;GAC/D,MAAM,QAAS,MAAkC;GACjD,IAAI,MAAM,QAAQ,KAAK,GAAG,OAAO;EACnC;CAGJ,QAAQ,CAER;CAGJ,MAAM,UAAU,KAAK,SAAS,MAAM,KAAK,MAAM,GAAG,GAAG,IAAI,MAAM;CAC/D,MAAM,IAAI,MAAM,2BAA2B,SAAS;AACtD;;AAGA,SAAS,eAAkB,MAAmB;CAC5C,MAAM,QAAQ,UAAe,MAAM,IAAI;CACvC,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;AACzC;;AAGA,SAAS,gBAAmB,MAAiB;CAC3C,MAAM,QAAQ,UAAa,MAAM,KAAK;CACtC,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,MAAM,IAAI,MAAM,gBAAgB;CACjF,OAAO;AACT;;AAKA,SAAS,oBAA4B;CACnC,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;AAGA,eAAsB,aAAa,KAAc,QAAqB,SAAiB,SAA6C;CAElI,MAAM,WAAW,SAAS,YAAY,CAAC,EAAA,CAAG,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,gBAAgB,EAAE,SAAS,KAAA,CAAS;CACjI,MAAM,WAAqB,CAAC;CAC5B,KAAK,MAAM,WAAW,QAAQ,MAAM,GAAG,CAAC,GAAG;EACzC,MAAM,OAAO,gBAAgB,OAAO,WAAW,OAAO;EACtD,IAAI,SAAS,KAAA,GAAW;EACxB,MAAM,OAAO,KAAK,QAAQ,WAAW,EAAE,CAAC,CAAC,KAAK;EAC9C,IAAI,KAAK,SAAS,GAAG,SAAS,KAAK,IAAI,QAAQ,GAAG,IAAI,QAAQ,MAAM,KAAK,KAAK,MAAM,GAAG,IAAI,GAAG;CAChG;CACA,MAAM,SAAS,SAAS,SAAS,CAAC,EAAA,CAAG,MAAM,GAAG;CAC9C,MAAM,OAAO;EACX,sBAAsB;EACtB,MAAM,SAAS,IACX,sDAAsD,MAAM,KAAI,MAAK,KAAK,EAAE,UAAU,KAAK,EAAE,KAAK,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,IAAI,MAC5H;EACJ,SAAS,SAAS,IACd,gEAAgE,SAAS,KAAK,MAAM,MACpF;CACN,CAAC,CAAC,QAAO,MAAK,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI;CAOjC,MAAM,MAAM,gBAMT,MAZgB,SAAS,KAAK,QAAQ;EACvC,QAAQ,kBAAkB;EAC1B;EACA,aAAa;EACb,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAC7C,CAAC,CAOM;CACP,MAAM,YAAY,UAChB,MAAM,QAAQ,KAAK,IAAI,MAAM,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE,IAAI,CAAC;CACvG,MAAM,aAAuC,MAAM,QAAQ,IAAI,UAAU,IACrE,IAAI,WACD,QAAQ,MAAoC,OAAO,MAAM,YAAY,MAAM,IAAI,CAAC,CAChF,KAAI,WAAU;EACb,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,KAAK,KAAK,IAAI;EAC3D,MAAO;GAAC;GAAe;GAAc;GAAc;EAAO,CAAC,CAAW,SAAS,MAAM,IAAa,IAC9F,MAAM,OACN;EACJ,QAAQ,SAAS,MAAM,MAAM;EAC7B,OAAO,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;EACvD,WAAW,OAAO,MAAM,cAAc,WAAW,MAAM,YAAY;EACnE,WAAW,SAAS,MAAM,SAAS;CACrC,EAAE,CAAC,CACF,QAAO,SAAQ,KAAK,SAAS,EAAE,IAClC,CAAC;CAEL,MAAM,mBAAmB,SAAS,SAAS,CAAC,EAAA,CAAG,MAAK,MAAK,EAAE,cAAc,aAAa,CAAC,EAAE,MAAM,KAAK;CACpG,IAAI,oBAAoB,KAAA,KAAa,oBAAoB;OAClD,MAAM,QAAQ,YACjB,IAAI,KAAK,SAAS,iBAAiB,YAAY,KAAK,KAAK,IAAI,GAAG,KAAK,OAAO;CAAA;CAGhF,MAAM,QAAoB;EACxB,OAAO,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ;EACnD,YAAY,SAAS,IAAI,UAAU;EACnC;EACA,UAAU,SAAS,IAAI,QAAQ;EAC/B,OAAO,SAAS,IAAI,KAAK;EACzB,8BAAa,IAAI,KAAK,EAAA,CAAE,YAAY;CACtC;CACA,IAAI,MAAM,WAAW,WAAW,KAAK,MAAM,WAAW,WAAW,KAAK,MAAM,SAAS,WAAW,GAC9F,MAAM,IAAI,MAAM,mBAAmB;CAErC,OAAO;AACT;;AAKA,SAAS,qBAA6B;CACpC,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;AAGA,eAAsB,YAAY,KAAc,QAAqB,SAAoC;CACvG,MAAM,OAAO,mBAAmB;CAEhC,MAAM,SAAS,eAAwC,MADpC,SAAS,KAAK,QAAQ;EAAE,QAAQ,mBAAmB;EAAG;EAAM,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAAE,CAAC,CACpF;CAC3D,MAAM,UAAoB,CAAC;CAC3B,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,QAAQ,OAAO;EACrB,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EACjD,MAAM,KAAK,OAAO,MAAM,OAAO,WAAW,MAAM,KAAK,IAAI;EACzD,MAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,KAAK,IAAI,IAAI,GAAG;EAC5E,MAAM,UAAU,OAAO,MAAM,YAAY,WAAW,MAAM,QAAQ,KAAK,IAAI;EAC3E,MAAM,QAAQ,OAAO,MAAM,iBAAiB,WAAW,MAAM,eAAe,KAAA;EAC5E,MAAM,MAAM,OAAO,MAAM,eAAe,WAAW,MAAM,aAAa,KAAA;EACtE,QAAQ,KAAK;GACX;GACA,OAAO,MAAM,MAAM,GAAG,EAAE;GACxB,SAAS,QAAQ,MAAM,GAAG,GAAG;GAC7B,cAAc,SAAS;GACvB,YAAY,OAAO;EACrB,CAAC;CACH;CACA,IAAI,QAAQ,WAAW,GAAG,MAAM,IAAI,MAAM,mBAAmB;CAC7D,OAAO;AACT;;AAGA,SAAS,SAAS,WAAmB,SAAuC;CAC1E,IAAI,YAAY,KAAA,KAAa,QAAQ,WAAW,GAAG,OAAO;CAC1D,KAAK,MAAM,UAAU,SACnB,IAAI,aAAa,OAAO,gBAAgB,aAAa,OAAO,YAAY,OAAO,OAAO;CAExF,OAAO,QAAQ,QAAQ,SAAS,EAAE,EAAE,MAAM;AAC5C;;AAKA,SAAS,iBAAiB,SAAuC;CAM/D,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAfkB,YAAY,KAAA,KAAa,QAAQ,SAAS,IAC1D,CAAC,yBAAyB,CAAC,CAC1B,OAAO,QAAQ,KAAI,MAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,IAAI,EAAE,QAAQ,MAAM,EAAE,aAAa,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC,CACpG,KAAK,IAAI,IACV;CAaJ,CAAC,CAAC,KAAK,IAAI;AACb;;AAGA,SAAS,kBAAkB,SAA+B;CACxD,MAAM,QAAQ,QAAQ;CACtB,MAAM,WAAqB,CAAC;CAC5B,IAAI,UAAU,KAAA,GAAW;EACvB,SAAS,KAAK,yDAAyD;EACvE,IAAI,MAAM,UAAU,IAAI,SAAS,KAAK,QAAQ,MAAM,OAAO;EAC3D,IAAI,MAAM,WAAW,SAAS,GAAG,SAAS,KAAK,YAAY,MAAM,WAAW,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;EACzG,IAAI,MAAM,WAAW,SAAS,GAAG;GAC/B,SAAS,KAAK,MAAM;GACpB,KAAK,MAAM,QAAQ,MAAM,YAAY;IACnC,MAAM,WAAW;KAAE,aAAa;KAAM,YAAY;KAAM,YAAY;KAAM,OAAO;IAAK,EAAE,KAAK;IAC7F,SAAS,KAAK,KAAK,KAAK,KAAK,GAAG,SAAS,IAAI,KAAK,OAAO,KAAK,GAAG,IAAI,KAAK,UAAU,KAAK,OAAO,KAAK,UAAU,KAAK,KAAK,cAAc,KAAK,OAAO,KAAK,cAAc,IAAI;IAC1K,IAAI,MAAM,QAAQ,KAAK,SAAS,KAAK,KAAK,UAAU,SAAS,GAC3D,SAAS,KAAK,iBAAiB,KAAK,UAAU,KAAK,GAAG,EAAE,2BAA2B;GAEvF;EACF;EAEA,MAAM,UAAU,QAAQ,SAAS,CAAC;EAClC,IAAI,QAAQ,SAAS,GAAG;GACtB,MAAM,YAAY;IAAE,aAAa;IAAM,aAAa;IAAM,gBAAgB;IAAM,SAAS;IAAM,YAAY;IAAM,OAAO;GAAK;GAC7H,SAAS,KAAK,qBAAqB;GACnC,KAAK,MAAM,KAAK,SACd,SAAS,KAAK,KAAK,EAAE,KAAK,GAAG,UAAU,EAAE,WAAW,IAAI,EAAE,WAAW,EAAE,UAAU,SAAS,IAAI,OAAO,EAAE,UAAU,KAAK,GAAG,MAAM,IAAI;EAEvI;EACA,IAAI,MAAM,SAAS,SAAS,GAAG,SAAS,KAAK,mBAAmB,MAAM,SAAS,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;EAC5G,IAAI,MAAM,MAAM,SAAS,GAAG,SAAS,KAAK,YAAY,MAAM,MAAM,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;CACjG;CACA,MAAM,aAAa,YAAY,QAAQ,KAAK;CAC5C,IAAI,eAAe,IAAI,SAAS,KAAK,UAAU;CAC/C,SAAS,KAAK,gDAAgD;CAE9D,MAAM,eAAe,QAAQ,QAAQ,SAAS,MAC1C,QAAQ,QAAQ,MAAM,GAAG,GAAI,IAAI,0BACjC,QAAQ;CACZ,SAAS,KAAK,YAAY;CAC1B,SAAS,KAAK,gDAAgD;CAC9D,MAAM,cAAc,gBAAgB,QAAQ,MAAM;CAClD,IAAI,gBAAgB,IAAI,SAAS,KAAK,WAAW;CACjD,MAAM,SAAS,QAAQ,YAAY,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,aAAa;CACnG,IAAI,OAAO,SAAS,GAAG;EACrB,SAAS,KAAK,6DAA6D;EAC3E,KAAK,MAAM,KAAK,QACd,SAAS,KAAK,MAAM,EAAE,WAAW,YAAY,QAAQ,MAAM,IAAI,EAAE,cAAc,EAAE,kBAAkB,KAAA,IAAY,OAAO,EAAE,cAAc,SAAS,IAAI;CAEvJ;CACA,MAAM,SAAS,QAAQ,aAAa,CAAC,EAAA,CAAG,QAAO,MAAK,EAAE,WAAW,YAAY,EAAE,WAAW,QAAQ;CAClG,IAAI,MAAM,SAAS,GAAG;EACpB,MAAM,WAAW;GAAE,MAAM;GAAM,QAAQ;GAAM,WAAW;GAAO,SAAS;EAAM;EAC9E,SAAS,KAAK,6DAA6D;EAC3E,KAAK,MAAM,KAAK,OACd,SAAS,KAAK,MAAM,SAAS,EAAE,QAAQ,EAAE,WAAW,WAAW,SAAS,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,OAAO,EAAE,aAAa,KAAK,SAAS,EAAE,SAAS,KAAK,IAAI;CAEvJ;CACA,SAAS,KAAK,EAAE;CAChB,SAAS,KAAK,SAAS;CACvB,SAAS,KAAK,mEAAmE;CACjF,SAAS,KAAK,qCAAqC;CACnD,SAAS,KAAK,uCAAuC;CACrD,SAAS,KAAK,iCAAiC;CAC/C,SAAS,KAAK,8BAA8B;CAC5C,SAAS,KAAK,0FAAwF;CACtG,SAAS,KAAK,oEAAoE;CAClF,SAAS,KAAK,iEAA+D;CAC7E,SAAS,KAAK,qDAAmD;CACjE,SAAS,KAAK,EAAE;CAChB,SAAS,KAAK,sEAAsE;CACpF,SAAS,KAAK,oBAAoB,KAAK,IAAI,CAAC;CAC5C,SAAS,KAAK,yEAAyE;CACvF,OAAO,SAAS,KAAK,IAAI;AAC3B;;;;AAKA,eAAsB,aACpB,KACA,QACA,SACA,cACA,UACA,WACwB;CACxB,MAAM,SAAS,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,QAAQ;CAC3D,MAAM,WAAW,QAAQ;CACzB,MAAM,UAAU,SAAS,WAAW,IAAI,IAAI,KAAK,IAAI,GAAG,SAAS,KAAI,MAAK,EAAE,EAAE,CAAC,IAAI;CAEnF,MAAM,eAAe,SAAS,SAAS;CACvC,MAAM,cAAc,gBAAgB,MAAM,QAAQ,QAAQ,KAAK,IAC3D,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK,KAAK,EAAE,UAAU,KAAK,EAAE,KAAK,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,IAAI,IACzF;CAEJ,IAAI,WAAW;CACf,IAAI,cAAc;EAChB,MAAM,UAAU,SAAS,QAAO,MAAK,EAAE,WAAW,SAAS;EAC3D,MAAM,OAAO,QAAQ,QAAQ,SAAS;EACtC,IAAI,SAAS,KAAA,KAAa,KAAK,SAAS,KAAA,KAAa,cAAc,KAAA,GACjE,IAAI;GAEF,WADY,aAAa,KAAK,WAAW,KAAK,IAAI,GAAG,MACxC,CAAC,CAAC,QAAQ,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI;EACxD,QAAQ,CAAuB;CAEnC;CAGA,MAAM,eAAe,sBACV;EACL,IAAI,QAAQ,QAAQ,UAAU,KAAO,OAAO,QAAQ;EACpD,MAAM,MAAM,QAAQ,QAAQ,QAAQ,aAAa;EACjD,IAAI,MAAM,MAAM,OAAO,QAAQ,QAAQ,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,IAAI;EACjE,OAAO,QAAQ,QAAQ,MAAM,GAAG,GAAI,IAAI;CAC1C,EAAA,CAAG,IACH,QAAQ;CACZ,MAAM,OAAO;EACX;EACA,WAAW,KAAA,IACP,UAAU,OAAO,GAAG,KAAK,OAAO,MAAM,SAAS,OAAO,YACtD,eACE,QAAQ,SAAS,OAAO,sCAAsC,QAAQ,SACtE;EACN,eACI,qQACA;EACJ,aAAa,KACT,UAAU,UAAU,EAAE,YAAY,QAAQ,+BAA+B,aACzE;EACJ,gBAAgB,KACZ,mBAAmB,UAAU,EAAE,0CAA0C,gBACzE;EACJ,eACI,YAAY,SAAS,SAAS,4CAC5B,SAAS,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK;GAC3B,MAAM,KAAK,EAAE,YAAY,KAAA,KAAa,EAAE,YAAY,KAAK,IAAI,EAAE,QAAQ,MAAM,GAAG,GAAG,EAAE,KAAK;GAC1F,OAAO,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,GAAG;EACjC,CAAC,CAAC,CAAC,KAAK,IAAI,IACd;EACJ,4BAA4B;EAC5B;EACA,OAAO,aAAa;CACtB,CAAC,CAAC,KAAK,IAAI;CAKX,MAAM,SAAS,eAAwC,MADpC,SAAS,KAAK,QAAQ;EAAE,QAH5B,iBAAiB,QAAQ,OAAO,KAAK,eAChD,2FACA;EAC+C;EAAM,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAK;CAAE,CAAC,CAC9D;CAC3D,MAAM,WAA0B,CAAC;CACjC,MAAM,cAAc,IAAI,IAAI,SAAS,KAAI,MAAK,EAAE,EAAE,CAAC;CACnD,MAAM,iBAAiB,IAAI,IAAI,SAAS,KAAI,MAAK,EAAE,KAAK,CAAC;CACzD,IAAI,SAAS;CACb,KAAK,MAAM,QAAQ,QAAQ;EACzB,IAAI,SAAS,UAAU,cAAc;EACrC,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM;EAC/C,MAAM,QAAQ;EACd,MAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE,IAAI;EAClF,MAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,KAAK,IAAI;EACrE,IAAI,UAAU,MAAM,UAAU,IAAI;EAElC,IAAI,UAAU,MAAM,eAAe,IAAI,KAAK,GAAG;EAC/C,OAAO,YAAY,IAAI,MAAM,GAAG;EAChC,MAAM,KAAK;EACX,SAAS,KAAK;GACZ;GACA,QAAQ,SAAS,IAAI,QAAQ,OAAO;GACpC,OAAO,SAAS,IAAI,GAAG;GACvB;GACA,aAAa,OAAO;GACpB,QAAQ;EACV,CAAC;CACH;CACA,IAAI,SAAS,WAAW,GACtB,MAAM,IAAI,MAAM,qBAAqB;CAEvC,OAAO;AACT;;AAKA,SAAS,mBAAmB,SAA+B;CACzD,MAAM,QAAQ,QAAQ;CACtB,MAAM,WAAqB;EACzB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,MAAM,cAAc,gBAAgB,QAAQ,MAAM;CAClD,IAAI,gBAAgB,IAAI,SAAS,KAAK,OAAO,WAAW;CACxD,IAAI,UAAU,KAAA,GAAW;EACvB,SAAS,KAAK,kDAAkD;EAChE,IAAI,MAAM,WAAW,SAAS,GAAG,SAAS,KAAK,YAAY,MAAM,WAAW,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;EACzG,IAAI,MAAM,WAAW,SAAS,GAAG;GAC/B,SAAS,KAAK,MAAM;GACpB,KAAK,MAAM,QAAQ,MAAM,YAAY;IACnC,SAAS,KAAK,KAAK,KAAK,KAAK,GAAG,KAAK,KAAK,IAAI,KAAK,OAAO,KAAK,GAAG,GAAG;IACrE,IAAI,MAAM,QAAQ,KAAK,SAAS,KAAK,KAAK,UAAU,SAAS,GAC3D,SAAS,KAAK,WAAW,KAAK,UAAU,KAAK,GAAG,EAAE,eAAe;GAErE;EACF;EACA,IAAI,MAAM,SAAS,SAAS,GAAG,SAAS,KAAK,UAAU,MAAM,SAAS,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;CACrG;CACA,SAAS,KAAK,kEAAkE;CAChF,SAAS,KAAK,oBAAoB,KAAK,IAAI,CAAC;CAC5C,SAAS,KAAK,oEAAoE;CAClF,OAAO,SAAS,KAAK,IAAI;AAC3B;;AAGA,eAAsB,cACpB,KACA,QACA,SACA,WACA,WACuB;CACvB,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,SAAS;CAC7D,IAAI,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,UAAU,OAAO;CAClE,MAAM,OAAO,gBAAgB,WAAW,OAAO;CAC/C,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,UAAU,UAAU;CAClE,MAAM,OAAO;EACX,SAAS,QAAQ,MAAM;EACvB,UAAU,QAAQ;EAClB;EACA,KAAK,QAAQ,aAAa,EAAE,CAAC,CAAC,KAAK;CACrC,CAAC,CAAC,KAAK,IAAI;CAEX,MAAM,MAAM,gBAA0E,MADnE,SAAS,KAAK,QAAQ;EAAE,QAAQ,mBAAmB,OAAO;EAAG;EAAM,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAAE,CAAC,CAC5D;CAC1F,MAAM,SAAS,MAAM,QAAQ,IAAI,MAAM,IACnC,IAAI,OACD,QAAQ,MAAoC,OAAO,MAAM,YAAY,MAAM,IAAI,CAAC,CAChF,KAAI,WAAU;EACb,UAAW;GAAC;GAAQ;GAAU;EAAK,CAAC,CAAW,SAAS,MAAM,QAAiB,IAC3E,MAAM,WACN;EACJ,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;EACpD,YAAY,OAAO,MAAM,eAAe,WAAW,MAAM,aAAa;CACxE,EAAE,CAAC,CACF,QAAO,UAAS,MAAM,SAAS,EAAE,IACpC,CAAC;CACL,MAAM,QAAQ,OAAO,IAAI,UAAU,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC,CAAC,IAAI;CAGlG,MAAM,SAAuB;EAC3B;EACA,QAHa,SAAS,OAAO,mBAAoB,OAAO,OAAM,MAAK,EAAE,aAAa,MAAM,KAAK,SAAS;EAItG,SAAS,OAAO,IAAI,YAAY,WAAW,IAAI,QAAQ,MAAM,GAAG,GAAG,IAAI;EACvE;EACA,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CACrC;CACA,QAAQ,SAAS;CACjB,QAAQ,SAAS,OAAO,SAAS,aAAa;CAC9C,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CAC3C,YAAY,WAAW,OAAO;CAC9B,OAAO;AACT;;;;;AAMA,eAAsB,kBACpB,KACA,QACA,SACA,MACA,gBACuB;CACvB,MAAM,OAAO;EACX,OAAO,QAAQ,SAAS;EACxB,mBAAmB,KAAA,IACf,mEACE,eAAe,OAAO,KAAK,IAAI,MAAM,GAAG,IAAI,EAAE,KAAK,GAAG,SAAS,IAAI,GAAG,OAAO,GAAG,eAAe,KAAK,MAAM,GAAG,eAAe,IAAI,CAAC,CAAC,KAAK,IAAI,IAC7I;EACJ,mBAAmB,KAAA,IACf,kEACA;EACJ,KAAK,MAAM,GAAG,GAAK;CACrB,CAAC,CAAC,KAAK,IAAI;CAGX,MAAM,MAAM,gBACV,MAAM,SAAS,KAAK,QAAQ;EAAE,QAFjB,mBAAmB,KAAA,IAAY,mBAAmB,OAAO,IAAI,mBAAmB,OAAO;EAE9D;EAAM,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAAE,CAAC,CAC9G;CACA,MAAM,SAAS,MAAM,QAAQ,IAAI,MAAM,IACnC,IAAI,OACD,QAAQ,MAAoC,OAAO,MAAM,YAAY,MAAM,IAAI,CAAC,CAChF,KAAI,WAAU;EACb,UAAW;GAAC;GAAQ;GAAU;EAAK,CAAC,CAAW,SAAS,MAAM,QAAiB,IAC3E,MAAM,WACN;EACJ,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;EACpD,YAAY,OAAO,MAAM,eAAe,WAAW,MAAM,aAAa;CACxE,EAAE,CAAC,CACF,QAAO,UAAS,MAAM,SAAS,EAAE,IACpC,CAAC;CACL,MAAM,QAAQ,OAAO,IAAI,UAAU,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC,CAAC,IAAI;CAElG,IAAI,SAAS,SAAS,OAAO,mBAAoB,OAAO,OAAM,MAAK,EAAE,aAAa,MAAM,KAAK,SAAS;CACtG,IAAI,mBAAmB,KAAA,GAAW;EAChC,MAAM,UAAU,OAAO,MAAK,MAAK,EAAE,aAAa,MAAM;EAEtD,MAAM,mBADW,eAAe,OAAO,QAAO,MAAK,EAAE,aAAa,MAClC,CAAC,CAAC,OAAM,MAAK,CAAC,OAAO,MAAK,MAAK,EAAE,KAAK,SAAS,EAAE,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;EACpG,SAAS,CAAC,WAAW;CACvB;CACA,OAAO;EACL;EACA;EACA,SAAS,OAAO,IAAI,YAAY,WAAW,IAAI,QAAQ,MAAM,GAAG,GAAG,IAAI;EACvE;EACA,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CACrC;AACF;;AAGA,SAAS,mBAAmB,SAA+B;CACzD,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,qBAAqB,QAAQ,UAAU,KAAA,IAAY,KAAK,UAAU,QAAQ,KAAK,CAAC,CAAC,MAAM,GAAG,GAAI,IAAI;CACpG,CAAC,CAAC,KAAK,IAAI;AACb;;AAGA,SAAS,2BAAmC;CAC1C,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;AAGA,eAAsB,oBACpB,KACA,QACA,SACA,WACA,MACA,UACuB;CACvB,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,SAAS;CAC7D,MAAM,cAAc,YAAY,IAAI,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,YAAY,CAAC,IAAI,KAAA;CACzF,MAAM,SAAS,QAAQ,aAAa,CAAC,EAAA,CAAG,QAAO,MAAK,EAAE,WAAW,YAAY,EAAE,WAAW,QAAQ;CAClG,MAAM,SAAS,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAM,GAAG;CAC7C,MAAM,OAAO;EACX,OAAO,QAAQ,SAAS;EACxB,YAAY,KAAA,IAAY,QAAQ,QAAQ,GAAG,KAAK,QAAQ,MAAM,KAAK,QAAQ,UAAU;EACrF,aAAa,KACT,8BAA8B,YAAY,EAAE,kCAAkC,aAC9E;EACJ,aAAa,iBAAiB,KAAA,IAC1B,sDAAsD,KAAK,UAAU,YAAY,YAAY,MAC7F;EACJ,MAAM,SAAS,IACX,oDAAoD,MAAM,KAAI,MAAK,MAAM,EAAE,KAAK,IAAI,EAAE,KAAK,GAAG,EAAE,OAAO,EAAE,aAAa,KAAK,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI,MAC9J;EACJ,MAAM,SAAS,IACX,sDAAsD,MAAM,KAAI,MAAK,KAAK,EAAE,UAAU,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,IAAI,MAC9G;EACJ;EACA,KAAK,MAAM,GAAG,IAAK;EACnB;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,MAAM,gBASV,MAAM,SAAS,KAAK,QAAQ;EAAE,QAAQ,yBAAyB;EAAG;EAAM,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;CAAE,CAAC,CACzI;CAEA,MAAM,iBAAiB,IAAI,KAAK,QAAQ,aAAa,CAAC,EAAA,CAAG,KAAI,MAAK,EAAE,IAAI,CAAC;CACzE,MAAM,gBAAgB,MAAM,QAAQ,IAAI,aAAa,IACjD,IAAI,cAAc,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,MAAM,eAAe,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,IACxI,CAAC;CACL,OAAO;EACL,aAAa,IAAI,gBAAgB;EACjC,UAAU,OAAO,IAAI,aAAa,WAAW,IAAI,SAAS,MAAM,GAAG,GAAG,IAAI;EAC1E,YAAY,OAAO,IAAI,eAAe,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,UAAU,CAAC,CAAC,IAAI;EACzG,kBAAkB,OAAO,IAAI,qBAAqB,WAAW,IAAI,iBAAiB,MAAM,GAAG,GAAG,IAAI;EAClG;EACA,YAAY,OAAO,IAAI,eAAe,WAAW,IAAI,WAAW,MAAM,GAAG,GAAG,IAAI;EAChF,OAAO,OAAO,IAAI,UAAU,WAAW,IAAI,MAAM,MAAM,GAAG,GAAG,IAAI;EACjE,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CACrC;AACF;;AAGA,SAAgB,kBAAkB,SAAuB,WAAmB,eAA+B;CACzG,IAAI,CAAC,MAAM,QAAQ,QAAQ,SAAS,KAAK,cAAc,WAAW,GAAG;CACrE,KAAK,MAAM,QAAQ,QAAQ,WACzB,IAAI,cAAc,SAAS,KAAK,IAAI,KAAK,CAAC,KAAK,SAAS,SAAS,SAAS,GACxE,KAAK,SAAS,KAAK,SAAS;AAGlC;;AAGA,eAAsB,iBAAiB,KAAc,QAAqB,SAA4C;CACpH,MAAM,SAAS;EACb;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,UAAU,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,SAAS;CAgBnE,MAAM,MAAM,eAAwC,MADjC,SAAS,KAAK,QAAQ;EAAE;EAAQ,MAdtC;GACX,OAAO,QAAQ,SAAS;GACxB,oBAAoB,QAAQ,QAAQ,MAAM,GAAG,GAAI;GACjD,QAAQ,YAAY,KAAA,KAAa,QAAQ,QAAQ,SAAS,IACtD,SAAS,QAAQ,QAAQ,KAAI,MAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,IAAI,EAAE,SAAS,CAAC,CAAC,KAAK,IAAI,MACjF;GACJ,QAAQ,SAAS,IACb,UAAU,QAAQ,KAAI,MAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,GAAG,EAAE,YAAY,KAAA,KAAa,EAAE,YAAY,KAAK,IAAI,EAAE,QAAQ,MAAM,GAAG,EAAE,MAAM,IAAI,CAAC,CAAC,KAAK,IAAI,MAC/I;IACH,QAAQ,SAAS,CAAC,EAAA,CAAG,SAAS,IAC3B,uBAAuB,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK,KAAK,EAAE,UAAU,KAAK,EAAE,KAAK,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,IAAI,MACvH;GACJ;EACF,CAAC,CAAC,KAAK,MAC+C;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;CAAE,CAAC,CAChE;CACxD,MAAM,QAAoB,CAAC;CAC3B,MAAM,wBAAQ,IAAI,IAAI;EAAC;EAAQ;EAAU;EAAa;CAAS,CAAC;CAChE,KAAK,MAAM,SAAS,KAAK;EACvB,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EACjD,MAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,KAAK,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE,IAAI;EAC/E,IAAI,SAAS,IAAI;EACjB,MAAM,KAAK;GACT,IAAI;GACJ;GACA,MAAM,MAAM,IAAI,MAAM,IAAc,IAAI,MAAM,OAA2B;GACzE,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,KAAK,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,IAAI;GACzE,UAAU,OAAO,MAAM,aAAa,WAAW,MAAM,SAAS,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,IAAI;GACrF,QAAQ;GACR,UAAU,CAAC;GACX,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EACpC,CAAC;CACH;CACA,OAAO;AACT;;AAGA,eAAsB,wBACpB,KACA,QACA,SACA,MACiB;CACjB,MAAM,SAAS;EACb;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,UAAU,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,aAAc,EAAE,YAAY,KAAA,KAAa,EAAE,YAAY,EAAG;CAYpH,MAAM,MAAM,gBACV,MAAM,SAAS,KAAK,QAAQ;EAAE;EAAQ,MAZ3B;GACX,OAAO,KAAK,KAAK,GAAG,KAAK,KAAK;GAC9B,MAAM,KAAK;GACX,QAAQ,KAAK,aAAa,KAAK,KAAK,WAAW;GAC/C,SAAS,KAAK,SAAS,SAAS,IAAI,KAAK,SAAS,KAAI,MAAK,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,IAAI;GACjF,kBAAkB,QAAQ,MAAM,EAAE,CAAC,CAAC,KAAI,MAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,IAAI,EAAE,QAAS,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,IAAI;IAC1G,QAAQ,SAAS,CAAC,EAAA,CAAG,SAAS,IAC3B,uBAAuB,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK,KAAK,EAAE,UAAU,KAAK,EAAE,KAAK,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,IAAI,MACvH;GACJ;EACF,CAAC,CAAC,KAAK,MAEoC;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;CAAE,CAAC,CAC7G;CACA,OAAO,OAAO,IAAI,aAAa,WAAW,IAAI,SAAS,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,IAAI;AAChF;;AAGA,eAAsB,aACpB,KACA,QACA,SACuB;CACvB,MAAM,SAAS;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,UAAU,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,YAAY;CAChG,MAAM,gBAAgB,QAAQ,SAAS,CAAC;CAExC,MAAM,eAAyB,CAAC;CAChC,KAAK,MAAM,WAAW,QAAQ,MAAM,GAAG,CAAC,GAAG;EACzC,MAAM,OAAO,gBAAgB,OAAO,WAAW,OAAO;EACtD,IAAI,SAAS,KAAA,GAAW;EACxB,MAAM,OAAO,KAAK,QAAQ,WAAW,EAAE,CAAC,CAAC,KAAK;EAC9C,IAAI,KAAK,SAAS,GAAG,aAAa,KAAK,IAAI,QAAQ,GAAG,IAAI,QAAQ,MAAM,KAAK,KAAK,MAAM,GAAG,IAAI,GAAG;CACpG;CAsBA,MAAM,MAAM,eAAwC,MADjC,SAAS,KAAK,QAAQ;EAAE;EAAQ,MApBtC;GACX,OAAO,QAAQ,SAAS;GACxB,cAAc,SAAS,IACnB,kBAAkB,cAAc,KAAI,MAAK,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,MACzD;GACJ,oBAAoB,QAAQ,QAAQ,MAAM,GAAG,GAAI;GACjD,aAAa,SAAS,IAClB,6BAA6B,aAAa,KAAK,MAAM,MACrD;GACJ,QAAQ,UAAU,KAAA,KAAa,QAAQ,MAAM,WAAW,SAAS,IAC7D,iBAAiB,QAAQ,MAAM,WAAW,KAAI,MAAK,KAAK,EAAE,KAAK,GAAG,EAAE,KAAK,IAAI,EAAE,OAAO,KAAK,GAAG,IAAI,EAAE,UAAU,KAAK,OAAO,EAAE,UAAU,IAAI,CAAC,CAAC,KAAK,IAAI,MACrJ;IACH,QAAQ,SAAS,CAAC,EAAA,CAAG,SAAS,IAC3B,mBAAmB,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK,KAAK,EAAE,UAAU,KAAK,EAAE,KAAK,MAAM,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,MAClH;GACJ,QAAQ,SAAS,IACb,UAAU,QAAQ,OAAO,QAAQ,QAAQ,KAAI,MAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,GAAG,MACnF;GACJ;EACF,CAAC,CAAC,KAAK,MAC+C;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAAE,CAAC,CACjE;CACxD,MAAM,yBAAS,IAAI,IAAI;EAAC;EAAe;EAAe;EAAkB;EAAW;EAAc;CAAO,CAAC;CACzG,MAAM,UAAU,MAAyB,MAAM,QAAQ,CAAC,IAAI,EAAE,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE,IAAI,CAAC;CACtI,MAAM,QAAsB,CAAC;CAC7B,KAAK,MAAM,SAAS,KAAK;EACvB,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EACjD,MAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,KAAK,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE,IAAI;EAC/E,IAAI,SAAS,IAAI;EACjB,MAAM,KAAK;GACT;GACA,WAAW,OAAO,IAAI,MAAM,SAAmB,IAAI,MAAM,YAAuC;GAChG,UAAU,OAAO,MAAM,aAAa,WAAW,MAAM,SAAS,MAAM,GAAG,GAAG,IAAI;GAC9E,QAAQ,OAAO,MAAM,MAAM,CAAC,CAAC,KAAI,MAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC;GAChE,OAAO,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,MAAM,GAAG,GAAG,IAAI;GACrE,WAAW,OAAO,MAAM,SAAS,CAAC,CAAC,KAAI,MAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE;GACvE,KAAK,OAAO,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK,EAAE,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE;GAC5D,WAAW,OAAO,MAAM,SAAS,CAAC,CAAC,KAAI,MAAK,EAAE,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE;EAC1E,CAAC;CACH;CACA,OAAO;AACT;;AAGA,eAAsB,cACpB,KACA,QACA,SACsB;CACtB,MAAM,SAAS;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,UAAU,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,YAAY;CAChG,MAAM,eAAyB,CAAC;CAChC,KAAK,MAAM,WAAW,QAAQ,MAAM,GAAG,CAAC,GAAG;EACzC,MAAM,OAAO,gBAAgB,OAAO,WAAW,OAAO;EACtD,IAAI,SAAS,KAAA,GAAW;EACxB,MAAM,OAAO,KAAK,QAAQ,WAAW,EAAE,CAAC,CAAC,KAAK;EAC9C,IAAI,KAAK,SAAS,GAAG,aAAa,KAAK,MAAM,QAAQ,KAAK,OAAO,QAAQ,QAAQ,QAAa,KAAK,MAAM,GAAG,IAAI,CAAC;CACnH;CAYA,MAAM,MAAM,eAAwC,MADjC,SAAS,KAAK,QAAQ;EAAE;EAAQ,MAVtC;GACX,SAAS,QAAQ,WAAW;IAC3B,QAAQ,SAAS,CAAC,EAAA,CAAG,SAAS,IAC3B,+BAAoC,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK,OAAO,EAAE,YAAY,QAAQ,EAAE,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,IACxI;GACJ,aAAa,SAAS,IAClB,yBAA8B,aAAa,KAAK,IAAI,IACpD;GACJ;EACF,CAAC,CAAC,QAAO,MAAK,MAAM,EAAE,CAAC,CAAC,KAAK,IACyB;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAAE,CAAC,CACjE;CACxD,MAAM,UAAU,MAAyB,MAAM,QAAQ,CAAC,IAAI,EAAE,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE,IAAI,CAAC;CACtI,MAAM,OAAO,MAAuB,OAAO,MAAM,WAAW,EAAE,KAAK,IAAI;CACvE,MAAM,SAAsB,CAAC;CAC7B,KAAK,MAAM,SAAS,KAAK;EACvB,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EACjD,MAAM,OAAO,IAAI,MAAM,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE;EACxC,IAAI,SAAS,IAAI;EACjB,OAAO,KAAK;GACV;GACA,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,EAAE;GAC/B,QAAQ,IAAI,MAAM,MAAM,CAAC,CAAC,MAAM,GAAG,EAAE;GACrC,SAAS,IAAI,MAAM,OAAO,CAAC,CAAC,MAAM,GAAG,GAAG;GACxC,OAAO,OAAO,MAAM,KAAK,CAAC,CAAC,KAAI,MAAK,EAAE,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC;GAC/D,gBAAgB,IAAI,MAAM,cAAc,CAAC,CAAC,MAAM,GAAG,GAAG;GACtD,UAAU,OAAO,MAAM,QAAQ,CAAC,CAAC,KAAI,MAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC;GACpE,SAAS,OAAO,MAAM,OAAO,CAAC,CAAC,KAAI,MAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC;GAClE,OAAO,OAAO,MAAM,KAAK,CAAC,CAAC,KAAI,MAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC;GAC9D,IAAI,IAAI,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,GAAG;GAC9B,IAAI,IAAI,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,GAAG;GAC9B,MAAM,OAAO,MAAM,IAAI,CAAC,CAAC,KAAI,MAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC;GAC5D,QAAQ,IAAI,MAAM,MAAM,CAAC,CAAC,MAAM,GAAG,GAAG;EACxC,CAAC;CACH;CACA,OAAO;AACT;;;;;AAkBA,eAAsB,kBACpB,KACA,QACA,SACA,WACA,UAC2B;CAC3B,MAAM,QAAQ,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAK,MAAK,EAAE,SAAS,QAAQ;CAChE,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,SAAS,QAAQ;CAI/D,MAAM,kBAAkB;CAExB,MAAM,WAAW,GAAG,KAAK,KAAK,GAAG,KAAK,YAAY;CAClD,MAAM,aAAa;EAAC;EAAM;EAAM;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;CAAG;CAC/F,MAAM,eAAe;EAAC;EAAM;EAAM;EAAQ;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAM;EAAM;EAAM;EAAM;CAAI;CAC9G,MAAM,YAAY;EAAC;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;CAAK;CAChG,MAAM,gBAAgB;EAAC;EAAM;EAAM;CAAI;CACvC,MAAM,kBAAkB,KAAK,YAAY,GAAA,CAAI,MAAM,UAAU,CAAC,CAAC,QAAO,MAAK,EAAE,UAAU,CAAC;CACxF,MAAM,eAAe,MAAM,qBAAK,IAAI,IAAI;EACtC;EACA,GAAG;EACH,GAAG,WAAW,QAAO,MAAK,SAAS,SAAS,CAAC,CAAC;EAC9C,GAAG,aAAa,QAAO,MAAK,SAAS,SAAS,CAAC,CAAC;EAChD,GAAG,UAAU,QAAO,MAAK,SAAS,SAAS,CAAC,CAAC;EAC7C,GAAG,cAAc,QAAO,MAAK,SAAS,SAAS,CAAC,CAAC;CACnD,CAAC,CAAC,CAAC,CAAC,QAAO,MAAK,EAAE,UAAU,CAAC;CAC7B,MAAM,eAAe,SAA0B,KAAK,SAAS,QAAQ,KAAK,aAAa,MAAK,QAAO,KAAK,SAAS,GAAG,CAAC;CACrH,MAAM,WAAgD,CAAC;CACvD,MAAM,UAAU,QAAQ,SACrB,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,gBAAgB,EAAE,SAAS,KAAA,CAAS,CAAC,CACxF,MAAM,GAAG;CACZ,KAAK,MAAM,WAAW,SAAS;EAC7B,MAAM,OAAO,gBAAgB,WAAW,OAAO;EAC/C,IAAI,SAAS,KAAA,GAAW;EACxB,MAAM,QAAQ,KAAK,MAAM,QAAQ,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,CAAC,CAAC,QAAO,MAAK,EAAE,SAAS,CAAC;EAC9E,IAAI,aAAa;EACjB,KAAK,MAAM,QAAQ,OAAO;GACxB,IAAI,cAAc,KAAK,SAAS,UAAU,IAAI;GAC9C,IAAI,CAAC,YAAY,IAAI,GAAG;GAExB,IAAI,gBAAgB,KAAK,IAAI,KAAK,SAAS,SAAS,GAAG;IACrD,SAAS,KAAK;KAAE,IAAI,QAAQ;KAAI,MAAM,KAAK,MAAM,GAAG,GAAG;IAAE,CAAC;IAC1D;GACF;EACF;EACA,IAAI,SAAS,UAAU,IAAI;CAC7B;CACA,IAAI,SAAS,WAAW,GACtB,MAAM,IAAI,MAAM,UAAU,SAAS,+BAA+B;CAuCpE,MAAM,MAAM,gBAA8H,MADvH,SAAS,KAAK,QAAQ;EAAE,QAjC5B;GACb;GACA;GACA;GACA;GACA;GACA;GACA;GACA,IATY,QAAQ,eAAe,CAAC,EAAA,CAS3B,KAAI,MAAK,OAAO,CAAC;GAC1B;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF,CAAC,CAAC,KAAK,IASyC;EAAG,MARtC;GACX,OAAO,QAAQ,SAAS;GACxB,QAAQ,KAAK,KAAK,GAAG,KAAK,SAAS;GACnC,KAAK,OAAO,SAAS,IAAI,QAAQ,KAAK,OAAO,KAAK,GAAG,MAAM;GAC3D;GACA,GAAG,SAAS,KAAI,MAAK,KAAK,EAAE,GAAG,KAAK,EAAE,MAAM;GAC5C;EACF,CAAC,CAAC,KAAK,MAC+C;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAAE,CAAC,CACqB;CAC9I,MAAM,KAAK,OAAO,IAAI,OAAO,WAAW,IAAI,GAAG,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,IAAI;CACtE,MAAM,KAAK,OAAO,IAAI,OAAO,WAAW,IAAI,GAAG,KAAK,CAAC,CAAC,MAAM,GAAG,IAAI,IAAI;CACvE,MAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,IAC/B,IAAI,KAAK,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,IACzH,CAAC;CACL,MAAM,SAAS,OAAO,IAAI,WAAW,WAAW,IAAI,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,IAAI;CAClF,MAAM,cAAc,MAAM,QAAQ,IAAI,WAAW,IAC7C,IAAI,YAAY,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,IAChI,CAAC;CAEL,MAAM,OAAO,MAAuB,OAAO,MAAM,WAAW,EAAE,KAAK,IAAI;CACvE,MAAM,QAAQ,MAA2C;EACvD,MAAM,IAAK,OAAO,MAAM,YAAY,MAAM,OAAQ,IAA+B,CAAC;EAClF,OAAO;GAAE,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,GAAG;GAAG,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,IAAI;EAAE;CACrE;CACA,MAAM,SAAU,OAAO,IAAI,cAAc,YAAY,IAAI,cAAc,OAAQ,IAAI,YAAuC,CAAC;CAC3H,MAAM,UAAU,MAAM,QAAQ,OAAO,WAAW,IAAI,OAAO,YAAY,QAAQ,MAAoC,OAAO,MAAM,YAAY,MAAM,IAAI,IAAI,CAAC;CAC3J,IAAI;CACJ,IAAI;EACF,YAAY;GACV,UAAU,KAAK,OAAO,QAAQ;GAC9B,OAAO,KAAK,OAAO,KAAK;GACxB,aAAa,QAAQ,KAAI,OAAM;IAC7B,MAAM,IAAI,EAAE,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE,KAAK;IAClC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,GAAG;IAC1B,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,IAAI;GAC7B,EAAE,CAAC,CAAC,MAAM,GAAG,EAAE;GACf,SAAS,KAAK,OAAO,OAAO;EAC9B;CACF,QAAQ;EACN,YAAY,KAAA;CACd;CACA,IAAI,OAAO,MAAM,OAAO,IACtB,MAAM,IAAI,MAAM,yBAAyB;CAE3C,OAAO;EAAE;EAAI;EAAI;EAAM;EAAQ;EAAa;CAAU;AACxD;;;;;AAMA,eAAsB,sBACpB,KACA,QACA,SACA,UACkC;CAClC,MAAM,QAAQ,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAK,MAAK,EAAE,SAAS,QAAQ;CAChE,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,SAAS,QAAQ;CAC/D,IAAI,KAAK,gBAAgB,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,SAAS,gBAAgB;CAwBnF,MAAM,MAAM,gBAAyC,MADlC,SAAS,KAAK,QAAQ;EAAE,QArB5B;GACb;GACA;GACA;GACA;GACA;GACA;GACA;GACA,IATY,QAAQ,eAAe,CAAC,EAAA,CAS3B,KAAI,MAAK,OAAO,CAAC;GAC1B;GACA;GACA;EACF,CAAC,CAAC,KAAK,IASyC;EAAG,MARtC;GACX,MAAM,KAAK,KAAK,GAAG,KAAK,YAAY,GAAG;GACvC,QAAQ,KAAK,YAAY;GACzB,QAAQ,KAAK,YAAY;GACzB,QAAQ,KAAK,YAAY,KAAK,KAAK,GAAG;GACtC,SAAS,KAAK,eAAe,CAAC,EAAA,CAAG,KAAK,GAAG,KAAK;GAC9C;EACF,CAAC,CAAC,KAAK,MAC+C;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAAE,CAAC,CAChE;CACzD,MAAM,OAAO,MAAuB,OAAO,MAAM,WAAW,EAAE,KAAK,IAAI;CACvE,MAAM,QAAQ,MAA2C;EACvD,MAAM,IAAK,OAAO,MAAM,YAAY,MAAM,OAAQ,IAA+B,CAAC;EAClF,OAAO;GAAE,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,GAAG;GAAG,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,IAAI;EAAE;CACrE;CACA,MAAM,iBAAiB,MAAM,QAAQ,IAAI,WAAW,IAAI,IAAI,YAAY,QAAQ,MAAoC,OAAO,MAAM,YAAY,MAAM,IAAI,IAAI,CAAC;CAC5J,MAAM,MAA+B;EACnC,UAAU,KAAK,IAAI,QAAQ;EAC3B,OAAO,KAAK,IAAI,KAAK;EACrB,aAAa,eAAe,KAAI,OAAM;GACpC,MAAM,IAAI,EAAE,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE,KAAK;GAClC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,GAAG;GAC1B,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,IAAI;EAC7B,EAAE,CAAC,CAAC,MAAM,GAAG,EAAE;EACf,SAAS,KAAK,IAAI,OAAO;CAC3B;CACA,IAAI,IAAI,SAAS,OAAO,MAAM,IAAI,SAAS,OAAO,IAChD,MAAM,IAAI,MAAM,wBAAwB;CAE1C,OAAO;AACT;;AAGA,eAAsB,mBACpB,KACA,QACA,SACmB;CACnB,MAAM,SAAS;EACb;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,QAAQ,QAAQ;CActB,OADY,eAAuB,MADhB,SAAS,KAAK,QAAQ;EAAE;EAAQ,MAXtC;GACX,OAAO,QAAQ,SAAS;GACxB,MAAM,OAAO,SAAS;GACtB,UAAU,KAAA,KAAa,MAAM,WAAW,SAAS,IAC7C,UAAU,MAAM,WAAW,KAAI,MAAK,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,MACvD;GACJ,UAAU,KAAA,KAAa,MAAM,SAAS,SAAS,IAC3C,QAAQ,MAAM,SAAS,KAAI,MAAK,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,MACnD;GACJ;EACF,CAAC,CAAC,QAAO,MAAK,MAAM,EAAE,CAAC,CAAC,KAAK,MACyB;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;CAAE,CAAC,CAE/G,CAAC,CAAC,KAAI,MAAK,OAAO,MAAM,WAAW,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,QAAO,MAAK,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;AAC1G;;;;;;AAQA,eAAsB,gBACpB,KACA,QACA,MACA,QAAQ,GACR,UAAoB,CAAC,GACQ;CAC7B,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC,CAAC;CA8BpD,MAAM,SAAS,eAAwC,MADpC,SAAS,KAAK,QAAQ;EAAE,QA5B5B;GACb;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,SAAS,EAAE;GACX;GACA;EACF,CAAC,CAAC,KAAK,IAYyC;EAAG,MAXtC;GACX,SAAS;GACT,KAAK,KAAK,CAAC,CAAC,SAAS,KACjB,kGACA;GACJ,QAAQ,SAAS,IACb,4BAA4B,QAAQ,KAAK,GAAG,MAAM,GAAG,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,KAAK,IAAI,MAC7E;GACJ,OAAO,EAAE;GACT;EACF,CAAC,CAAC,KAAK,MAC+C;EAAG,aAAa;EAAM,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAAE,CAAC,CAC/D;CAC3D,MAAM,aAAiC,CAAC;CACxC,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EACjD,MAAM,WAAW,OAAO,MAAM,aAAa,WAAW,MAAM,SAAS,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE,IAAI;EAC3F,MAAM,UAAU,OAAO,MAAM,YAAY,WAAW,MAAM,QAAQ,KAAK,IAAI;EAC3E,IAAI,aAAa,MAAM,QAAQ,SAAS,KAAK;EAC7C,WAAW,KAAK;GACd,IAAI,OAAO,MAAM,OAAO,YAAY,MAAM,OAAO,KAAK,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,GAAG,WAAW;GAC7G;GACA,OAAO,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE,IAAI;GAC3E,cAAc,OAAO,MAAM,iBAAiB,WAAW,MAAM,aAAa,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,IAAI;GACjG;EACF,CAAC;CACH;CACA,IAAI,WAAW,WAAW,GACxB,MAAM,IAAI,MAAM,8BAA8B;CAEhD,OAAO,WAAW,MAAM,GAAG,CAAC;AAC9B;;;;;;;;;AAUA,eAAsB,cACpB,KACA,QACA,SACA,WACA,QAAQ,UACR,SAA+B,SAC/B,eAAe,KACa;CAE5B,MAAM,UAAU,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,gBAAgB,EAAE,YAAY,KAAA,KAAa,EAAE,YAAY,EAAE;CAC/I,IAAI,WAAW;CACf,IAAI,UAAU,UAAU,WAAW,QAAQ,MAAM,GAAG;MAC/C,IAAI,eAAe,KAAK,KAAK,GAAG;EACnC,MAAM,IAAI,OAAO,MAAM,MAAM,CAAC,CAAC;EAC/B,WAAW,QAAQ,QAAO,MAAK,EAAE,WAAW,CAAC;CAC/C;CACA,IAAI,SAAS,WAAW,GAAG,MAAM,IAAI,MAAM,uBAAuB;CAGlE,IAAI,SAAS;CACb,MAAM,SAA8E,CAAC;CACrF,KAAK,MAAM,KAAK,SAAS,MAAM,CAAC,CAAC,QAAQ,GAAG;EAG1C,MAAM,aAFO,gBAAgB,WAAW,CAAC,KAAK,GAAA,CAEvB,QAAQ,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,GAAI;EACpE,MAAM,MAAM,KAAK,MAAM,UAAU,UAAU,EAAE,SAAS,UAAU,MAAM,CAAC,IAAI;EAC3E,IAAI,MAAM,UAAU,OAAO,SAAS,GAAG;EACvC,OAAO,QAAQ;GAAE,IAAI,EAAE;GAAI,OAAO,EAAE;GAAO,SAAS,EAAE,WAAW;GAAI,MAAM;EAAU,CAAC;EACtF,UAAU;CACZ;CAGA,MAAM,QAAkB,CAAC;CACzB,IAAI,aAAa;CACjB,MAAM,aAAa;EACjB;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,KAAK,MAAM,MAAM,QAAQ;EACvB,MAAM,WAAW;GAAC,IAAI,GAAG,GAAG,IAAI,GAAG,MAAM;GAAI;GAAO,GAAG,KAAK,MAAM,GAAG,GAAI;EAAC,CAAC,CAAC,KAAK,IAAI;EACrF,IAAI;GAEF,MAAM,MAAM,gBAAyC,MADlC,SAAS,KAAK,QAAQ;IAAE,QAAQ;IAAY,MAAM;IAAU,aAAa;IAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;GAAE,CAAC,CACrF;GACzD,MAAM,QAAQ,MAAwB,MAAM,QAAQ,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC;GAC1L,MAAM,KACJ,KAAK,GAAG,GAAG,IAAI,GAAG,MAAM,SAChB,OAAO,IAAI,YAAY,WAAW,IAAI,QAAQ,MAAM,GAAG,GAAG,IAAI,GAAG,OACjE,KAAK,YAAY,CAAC,CAAC,KAAK,GAAG,EAAE,OAC7B,KAAK,YAAY,CAAC,CAAC,KAAK,GAAG,EAAE,OAC7B,KAAK,eAAe,CAAC,CAAC,KAAK,GAAG,EAAE,OAChC,KAAK,iBAAiB,CAAC,CAAC,KAAK,GAAG,EAAE,OAClC,KAAK,kBAAkB,CAAC,CAAC,KAAK,GAAG,EAAE,SACjC,KAAK,iBAAiB,CAAC,CAAC,KAAK,GAAG,KAAK,aACjD;GACA,cAAc;EAChB,QAAQ,CAER;CACF;CAGA,MAAM,iBAAuF;EAC3F;GACE,KAAK;GACL,OAAO;GACP,OAAO;GACP,QAAQ;IACN;IACA;IACA;IACA;GACF,CAAC,CAAC,KAAK,IAAI;EACb;EACA;GACE,KAAK;GACL,OAAO;GACP,OAAO;GACP,QAAQ;IACN;IACA;IACA;IACA;GACF,CAAC,CAAC,KAAK,IAAI;EACb;EACA;GACE,KAAK;GACL,OAAO;GACP,OAAO;GACP,QAAQ;IACN;IACA;IACA;IACA;GACF,CAAC,CAAC,KAAK,IAAI;EACb;EACA;GACE,KAAK;GACL,OAAO;GACP,OAAO;GACP,QAAQ;IACN;IACA;IACA;IACA;GACF,CAAC,CAAC,KAAK,IAAI;EACb;CACF;CACA,IAAI,WAAW,YACb,eAAe,KAAK;EAClB,KAAK;EACL,OAAO;EACP,OAAO;EACP,QAAQ;GACN;GACA;GACA;GACA;EACF,CAAC,CAAC,KAAK,IAAI;CACb,CAAC;CAGH,MAAM,YAAY,MAAM,KAAK,MAAM;CACnC,MAAM,WAA0C,CAAC;CACjD,MAAM,WAA0C,CAAC;CACjD,KAAK,MAAM,OAAO,gBAChB,IAAI;EAOF,MAAM,MAAM,gBAA8D,MANvD,SAAS,KAAK,QAAQ;GACvC,QAAQ,IAAI;GACZ,MAAM,QAAQ,SAAS,OAAO,KAAK,UAAU,QAAQ,OAAO,UAAU,WAAW,YAAY,MAAM,eAAe;GAClH,aAAa;GACb,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;EAC5C,CAAC,CAC6E;EAC9E,SAAS,KAAK;GACZ,KAAK,IAAI;GACT,OAAO,IAAI;GACX,UAAU,OAAO,IAAI,aAAa,WAAW,IAAI,SAAS,KAAK,IAAI;GACnE,YAAY,OAAO,IAAI,eAAe,YAAY,IAAI,eAAe,OAAO,IAAI,aAAwC,CAAC;EAC3H,CAAC;EACD,cAAc;CAChB,QAAQ;EACN,SAAS,KAAK;GAAE,KAAK,IAAI;GAAK,OAAO,IAAI;GAAO,UAAU;GAAgB,YAAY,CAAC;EAAE,CAAC;CAC5F;CAGF,OAAO;EACL;EACA;EACA,iBAAiB,OAAO;EACxB;CACF;AACF;AAEA,eAAsB,2BACpB,KACA,QACA,SACA,WACA,MACA,QAAQ,IACS;CACjB,MAAM,OAAO,QAAQ,OAAO,MAAK,MAAK,EAAE,SAAS,IAAI;CACrD,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,KAAK,KAAK;CACxD,IAAI,KAAK,gBAAgB,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,KAAK,gBAAgB;CAC/E,IAAI,OAAO,oBAAoB,MAAM,MAAM,IAAI,MAAM,iBAAiB;CACtE,MAAM,SAAS,OAAO;CACtB,MAAM,QAAQ,OAAO;CACrB,IAAI,WAAW,KAAA,KAAa,WAAW,MAAM,UAAU,KAAA,KAAa,UAAU,IAC5E,MAAM,IAAI,MAAM,0BAA0B;CAE5C,MAAM,cAAc,oBAAoB,KAAK;CAC7C,MAAM,SAAS;EACb,KAAK,YAAY;EACjB,KAAK,YAAY;EACjB,KAAK,YAAY,KAAK,KAAK,IAAI;EAC/B;EACA;CACF,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,IAAI;CAE3B,MAAM,MAAM,MAAM,MAAM,+DAA+D;EACrF,QAAQ;EACR,SAAS;GACP,gBAAgB;GAChB,eAAe,UAAU;EAC3B;EACA,MAAM,KAAK,UAAU;GACnB;GACA;GACA,iBAAiB;GACjB,MAAM;GACN,QAAQ;GACR,WAAW;EACb,CAAC;CACH,CAAC;CACD,IAAI,CAAC,IAAI,IAAI;EACX,MAAM,OAAO,MAAM,IAAI,KAAK;EAC5B,MAAM,IAAI,MAAM,UAAU,IAAI,OAAO,IAAI,MAAM;CACjD;CAEA,MAAM,OAAM,MADQ,IAAI,KAAK,EAAA,CACZ,OAAO,EAAE,EAAE;CAC5B,IAAI,QAAQ,KAAA,KAAa,QAAQ,IAAI,MAAM,IAAI,MAAM,eAAe;CAEpE,MAAM,SAAS,MAAM,MAAM,GAAG;CAC9B,IAAI,CAAC,OAAO,IAAI,MAAM,IAAI,MAAM,UAAU;CAC1C,MAAM,MAAM,OAAO,KAAK,MAAM,OAAO,YAAY,CAAC;CAElD,MAAM,UAAU,QADI,OAAO,QAAQ,IAAI,cAAc,KAAK,aACtB,UAAU,IAAI,SAAS,QAAQ;CACnE,KAAK,WAAW;CAChB,OAAO;AACT;;AAGA,eAAsB,sBACpB,KACA,QACA,SAC+B;CAC/B,MAAM,SAAS;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,UAAU,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,YAAY;CAChG,MAAM,SAAS,QAAQ,aAAa,CAAC,EAAA,CAAG,QAAO,MAAK,EAAE,WAAW,YAAY,EAAE,WAAW,QAAQ;CAelG,MAAM,MAAM,gBAKT,MAAM,SAAS,KAAK,QAAQ;EAAE;EAAQ,MAnB5B;GACX,OAAO,QAAQ,SAAS;GACxB,SAAS,QAAQ,OAAO,QAAQ,QAAQ,SAAS,IAAI,QAAQ,QAAQ,SAAS,EAAE,CAAE,KAAK,EAAE;GACzF,QAAQ,YAAY,KAAA,KAAa,QAAQ,QAAQ,SAAS,IACtD,SAAS,QAAQ,QAAQ,KAAI,MAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,IAAI,EAAE,aAAa,GAAG,EAAE,WAAW,IAAI,EAAE,QAAQ,MAAM,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,MACjI;GACJ,OAAO,MAAM,OAAO,QAAQ,MAAM,SAAS,IACvC,MAAM,KAAI,MAAK,MAAM,EAAE,KAAK,IAAI,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,aAAa,KAAK,EAAE,WAAW,MAAM,UAAU,EAAE,SAAS,SAAS,IAAI,MAAM,KAAK,IAAI,GAAG,EAAE,QAAQ,IAAI,MAAM,KAAK,CAAC,CAAC,KAAK,IAAI,IACzL;IACH,QAAQ,SAAS,CAAC,EAAA,CAAG,SAAS,IAC3B,uBAAuB,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK,KAAK,EAAE,UAAU,KAAK,EAAE,KAAK,MAAM,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,MACtH;GACJ;EACF,CAAC,CAAC,KAAK,MAMqC;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;CAAE,CAAC,CAAC;CAC/G,MAAM,UAAU,MAAyB,MAAM,QAAQ,CAAC,IAAI,EAAE,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE,IAAI,CAAC;CACtI,MAAM,UAAU,MAAM,QAAQ,IAAI,KAAK,IACnC,IAAI,MACD,QAAQ,MAAoC,OAAO,MAAM,YAAY,MAAM,IAAI,CAAC,CAChF,KAAI,WAAU;EACb,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,KAAK,MAAM,GAAG,EAAE,IAAI;EACjE,QAAS;GAAC;GAAM;GAAW;EAAO,CAAC,CAAW,SAAS,MAAM,MAAe,IAAI,MAAM,SAAuC;EAC7H,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,KAAK,MAAM,GAAG,GAAG,IAAI;CACpE,EAAE,CAAC,CACF,QAAO,MAAK,EAAE,SAAS,EAAE,IAC5B,CAAC;CACL,OAAO;EACL,SAAS,OAAO,IAAI,YAAY,WAAW,IAAI,QAAQ,MAAM,GAAG,GAAG,IAAI;EACvE,QAAQ,OAAO,IAAI,WAAW,WAAW,IAAI,OAAO,MAAM,GAAG,GAAG,IAAI;EACpE,SAAS,OAAO,IAAI,OAAO,CAAC,CAAC,KAAI,MAAK,EAAE,MAAM,GAAG,GAAG,CAAC;EACrD,OAAO;CACT;AACF;;AAGA,eAAsB,mBACpB,KACA,QACA,SACA,QACuB;CACvB,MAAM,SAAS;EACb;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,UAAU,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,YAAY;CAgBhG,MAAM,MAAM,gBACV,MAAM,SAAS,KAAK,QAAQ;EAAE;EAAQ,MAhB3B;GACX,OAAO,QAAQ,SAAS;GACxB,WAAW,KAAA,IACP,eAAe,OAAO,QAAQ,OAAO,OAAO,OAAO,OAAO,OAAO,QAAQ,KAAK,GAAG,MACjF;GACJ,oBAAoB,QAAQ,QAAQ,MAAM,GAAG,GAAI;GACjD,QAAQ,YAAY,KAAA,KAAa,QAAQ,QAAQ,SAAS,IACtD,SAAS,QAAQ,QAAQ,KAAI,MAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,IAAI,EAAE,QAAQ,MAAM,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,MAC9F;GACJ,YAAY,QAAQ,aAAa,CAAC,EAAA,CAAG,KAAI,MAAK,MAAM,EAAE,OAAO,EAAE,WAAW,aAAa,SAAS,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,MAAM,CAAC,CAAC,KAAK,IAAI,KAAK;GACzI,QAAQ,SAAS,IACb,YAAY,QAAQ,MAAM,EAAE,CAAC,CAAC,KAAI,MAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,GAAG,MACxE;GACJ;EACF,CAAC,CAAC,KAAK,MAEoC;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;CAAE,CAAC,CAC7G;CACA,MAAM,cAA0B,CAAC;CACjC,MAAM,wBAAQ,IAAI,IAAI;EAAC;EAAQ;EAAU;EAAa;CAAS,CAAC;CAChE,IAAI,MAAM,QAAQ,IAAI,WAAW,GAC/B,KAAK,MAAM,SAAS,IAAI,aAAa;EACnC,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EACjD,MAAM,IAAI;EACV,MAAM,OAAO,OAAO,EAAE,SAAS,WAAW,EAAE,KAAK,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE,IAAI;EACvE,IAAI,SAAS,IAAI;EACjB,YAAY,KAAK;GACf,IAAI;GACJ;GACA,MAAM,MAAM,IAAI,EAAE,IAAc,IAAI,EAAE,OAA2B;GACjE,MAAM,OAAO,EAAE,SAAS,WAAW,EAAE,KAAK,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,IAAI;GACjE,UAAU,OAAO,EAAE,aAAa,WAAW,EAAE,SAAS,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,IAAI;GAC7E,QAAQ;GACR,UAAU,CAAC;GACX,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EACpC,CAAC;CACH;CAEF,OAAO;EACL,WAAW,OAAO,IAAI,cAAc,WAAW,IAAI,UAAU,MAAM,GAAG,GAAG,IAAI;EAC7E;CACF;AACF;;AAGA,SAAS,oBAAoB,SAA+B;CAE1D,OADa,kBAAkB,OACrB,IAAI;AAChB;;;;;;;AAQA,gBAAuB,qBACrB,KACA,QACA,SACA,WACA,WACA,cACA,QAC2I;CAC3I,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,SAAS;CAC7D,IAAI,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,UAAU,OAAO;CAClE,MAAM,OAAO,gBAAgB,WAAW,OAAO;CAC/C,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,UAAU,UAAU;CAElE,MAAM,cAAc,QAAQ,WAAW,KAAA,IACnC,YAAY,QAAQ,OAAO,OAAO,KAAI,MAAK,IAAI,EAAE,SAAS,IAAI,EAAE,KAAK,KAAK,EAAE,YAAY,CAAC,CAAC,KAAK,IAAI,IACnG;CAGJ,MAAM,WAAW,KAAK,QAAQ,aAAa,EAAE,CAAC,CAAC,KAAK;CACpD,IAAI;CACJ,IAAI,WAAW,KAAA,KAAa,OAAO,KAAK,MAAM,IAAI;EAChD,MAAM,SAAS,OAAO,KAAK;EAG3B,MAAM,aAAa,UAA0B,MAAM,QAAQ,QAAQ,GAAG,CAAC,CAAC,QAAQ,aAAa,EAAE;EAC/F,MAAM,aAAa,UAAU,MAAM;EAEnC,MAAM,aAAa,SAAS,MAAM,QAAQ;EAC1C,MAAM,MAAM,WAAW,WAAU,MAAK,UAAU,CAAC,CAAC,CAAC,SAAS,UAAU,CAAC;EACvE,IAAI,QAAQ,IACV,MAAM,IAAI,MAAM,kBAAkB,OAAO,MAAM,GAAG,EAAE,EAAE,4BAA4B;EAEpF,cAAc;GACZ,WAAW,WAAW;GACtB,QAAQ,WAAW,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,MAAM;GAC5C,OAAO,WAAW,MAAM,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM;EAC9C;CACF;CAEA,MAAM,OAAO,gBAAgB,KAAA,IACzB;EACE,QAAQ,QAAQ,GAAG,KAAK,QAAQ,MAAM;EACtC;EACA,iBAAiB,KAAK,UAAU,iBAAiB;EACjD;EACA;CACF,CAAC,CAAC,QAAO,SAAQ,SAAS,EAAE,CAAC,CAAC,KAAK,IAAI,IACvC;EACE,QAAQ,QAAQ,GAAG,KAAK,QAAQ,MAAM;EACtC,iBAAiB,KAAK,QAAQ,iBAAiB;EAC/C;EACA,YAAY;EACZ;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,QAAO,SAAQ,SAAS,EAAE,CAAC,CAAC,KAAK,IAAI;CAE3C,MAAM,SAAS,gBAAgB,KAAA,IAC3B,oBAAoB,OAAO,IAC3B;CAEJ,MAAM,WAAsB,CAAC,kBAAkB;EAC7C,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM;EAAK,CAAC;EACtC,QAAQ;GAAE,MAAM;GAAU,QAAQ;EAAkB;CACtD,CAAC,CAAC;CACF,MAAM,UAA2B;EAC/B,UAAU,OAAO;EACjB,OAAO,OAAO;EACd;EACA;EAGA,WAAW,KAAK,IAAI,OAAO,WAAW,GAAK;EAC3C,aAAa;EACb,iBAAiB,kBAAkB,KAAK;CAC1C;CAEA,MAAM,EAAE,OAAO,QAAQ;CACvB,MAAM,YAAY,IAAI,eAAe;CACrC,IAAI;CACJ,WAAW,MAAM,SAAS,IAAI,IAAI,OAAO,OAAO,GAAG;EACjD,UAAU,KAAK,KAAK;EACpB,IAAI,MAAM,SAAS,cAAc,MAAM;GAAE,OAAO;GAAS,MAAM,MAAM;EAAK;CAC5E;CACA,MAAM,SAAS,UAAU;CACzB,IAAI,OAAO,SAAS,WAAW,OAAO,SAAS,WAC7C,8BAAc,IAAI,MAAM,QAAQ,OAAO,KAAK,KAAK,OAAO,QAAQ,SAAS;MACpE,IAAI,OAAO,SAAS,cACzB,8BAAc,IAAI,MAAM,8BAA8B;CAExD,MAAM,YAAY,UACf,OAAO,CAAC,CACR,QAAQ,UAA4F,MAAM,SAAS,MAAM,CAAC,CAC1H,KAAI,UAAS,MAAM,IAAI,CAAC,CACxB,KAAK,IAAI,CAAC,CACV,KAAK;CACR,IAAI,gBAAgB,KAAA,GAAW,MAAM;CACrC,IAAI,UAAU,SAAS,IAAI,MAAM,IAAI,MAAM,iBAAiB;CAG5D,IAAI;CACJ,IAAI,gBAAgB,KAAA,GAClB,UAAU;EAAC,YAAY;EAAQ;EAAW,YAAY;CAAK,CAAC,CAAC,QAAO,SAAQ,SAAS,EAAE,CAAC,CAAC,KAAK,MAAM;MAEpG,UAAU;CAEZ,IAAI,QAAQ,SAAS,KAAK,MAAM,IAAI,MAAM,iBAAiB;CAK3D,QAAQ,eAAe;CACvB,QAAQ,QAAQ,KAAA;CAChB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CAC3C,YAAY,WAAW,OAAO;CAC9B,MAAM;EAAE,OAAO;EAAW,OAAO,QAAQ;EAAQ,OAAO;CAAQ;AAClE;;AAGA,SAAS,mBAAmB,SAA+B;CACzD,MAAM,cAAc,gBAAgB,QAAQ,MAAM;CAClD,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA,gBAAgB,KAAK,cAAc;CACrC,CAAC,CAAC,KAAK,IAAI;AACb;;;AAIA,gBAAuB,oBACrB,KACA,QACA,SACA,WACA,WAC2I;CAC3I,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,SAAS;CAC7D,IAAI,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,UAAU,OAAO;CAClE,MAAM,OAAO,gBAAgB,WAAW,OAAO;CAC/C,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,UAAU,UAAU;CAClE,MAAM,WAAsB,CAAC,kBAAkB;EAC7C,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM,KAAK,QAAQ,aAAa,EAAE,CAAC,CAAC,KAAK;EAAE,CAAC;EACtE,QAAQ;GAAE,MAAM;GAAU,QAAQ;EAAkB;CACtD,CAAC,CAAC;CACF,MAAM,UAA2B;EAC/B,UAAU,OAAO;EACjB,OAAO,OAAO;EACd;EACA,QAAQ,mBAAmB,OAAO;EAGlC,WAAW,KAAK,IAAI,OAAO,WAAW,GAAK;EAC3C,aAAa;EACb,iBAAiB,kBAAkB,KAAK;CAC1C;CACA,MAAM,EAAE,OAAO,QAAQ;CACvB,MAAM,YAAY,IAAI,eAAe;CACrC,IAAI;CACJ,WAAW,MAAM,SAAS,IAAI,IAAI,OAAO,OAAO,GAAG;EACjD,UAAU,KAAK,KAAK;EACpB,IAAI,MAAM,SAAS,cAAc,MAAM;GAAE,OAAO;GAAS,MAAM,MAAM;EAAK;CAC5E;CACA,MAAM,SAAS,UAAU;CACzB,IAAI,OAAO,SAAS,WAAW,OAAO,SAAS,WAC7C,8BAAc,IAAI,MAAM,QAAQ,OAAO,KAAK,KAAK,OAAO,QAAQ,SAAS;MACpE,IAAI,OAAO,SAAS,cACzB,8BAAc,IAAI,MAAM,qBAAqB;CAE/C,MAAM,UAAU,UACb,OAAO,CAAC,CACR,QAAQ,UAA4F,MAAM,SAAS,MAAM,CAAC,CAC1H,KAAI,UAAS,MAAM,IAAI,CAAC,CACxB,KAAK,IAAI,CAAC,CACV,KAAK;CACR,IAAI,gBAAgB,KAAA,GAAW,MAAM;CACrC,IAAI,QAAQ,SAAS,KAAK,MAAM,IAAI,MAAM,iBAAiB;CAG3D,QAAQ,eAAe;CACvB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CAC3C,YAAY,WAAW,OAAO;CAC9B,MAAM;EAAE,OAAO;EAAW,OAAO,QAAQ;EAAQ,OAAO;CAAQ;AAClE;;AAGA,gBAAuB,sBACrB,KACA,QACA,SACA,WACA,WACuI;CACvI,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,SAAS;CAC7D,IAAI,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,UAAU,OAAO;CAMlE,IAAI,aAAa;CACjB,MAAM,OAAO,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,YAAY,CAAC;CAC9D,IAAI,MAAM,SAAS,KAAA,GAAW;EAC5B,MAAM,WAAW,KAAK,WAAW,KAAK,IAAI;EAC1C,IAAI,WAAW,QAAQ,GAErB,aADa,aAAa,UAAU,MACpB,CAAC,CAAC,MAAM,IAAI;CAEhC;CACA,MAAM,cAAc,MAAM;CAI1B,MAAM,WAAW,QAAQ,SAAS,CAAC;CACnC,MAAM,cAAc,SAAS,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK,EAAE,IAAI;CACvD,MAAM,YAAY,IAAI,IAAI,WAAW;CACrC,MAAM,YAAY,QAAQ;CAC1B,MAAM,aAAa,QAAQ,SAAS,CAAC,EAAA,CAClC,KAAI,MAAK,EAAE,IAAI,CAAC,CAChB,QAAQ,MAAmB,OAAO,MAAM,YAAY,MAAM,EAAE;CAC/D,MAAM,YAAY,MAA2B;EAC3C,MAAM,sBAAM,IAAI,IAAY;EAC5B,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,EAAE,QAAQ,KAAK;GACtC,MAAM,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;GAC5B,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,IAAI,GAAG;EACpC;EACA,OAAO;CACT;CACA,MAAM,WAAW,SAAS,SAAS;CACnC,MAAM,YAAY,UAAU,QAAO,MAAK,UAAU,SAAS,CAAC,CAAC;CAC7D,MAAM,eAAe,SAClB,KAAK,GAAG,QAAQ;EACf,MAAM,OAAO,EAAE,KAAK,MAAM,GAAG,EAAE;EAC/B,IAAI,QAAQ;EACZ,KAAK,MAAM,OAAO,SAAS,IAAI,GAAG,IAAI,SAAS,IAAI,GAAG,GAAG,SAAS;EAClE,IAAI,UAAU,SAAS;QAChB,MAAM,KAAK,WAAW,IAAI,KAAK,SAAS,CAAC,GAAG,SAAS;EAAA;EAG5D,SAAS,KAAK,IAAI,KAAK,EAAE,IAAI;EAC7B,OAAO;GAAE;GAAG;EAAM;CACpB,CAAC,CAAC,CACD,QAAO,MAAK,EAAE,SAAS,CAAC,CAAC,CACzB,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CACjC,MAAM,GAAG,EAAE,CAAC,CACZ,KAAI,MAAK,KAAK,EAAE,EAAE,UAAU,KAAK,EAAE,EAAE,MAAM,CAAC,CAC5C,QAAO,MAAK,CAAC,UAAU,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC;CAI1D,MAAM,mBAAmB,QAAQ,eAAe,CAAC,EAAA,CAC9C,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,kBAAkB,KAAA,KAAa,EAAE,gBAAgB,CAAC,CAAC,CAC3F,QAAO,MAAK,KAAK,IAAK,EAAE,gBAA2B,SAAS,KAAK,EAAE,CAAC,CACpE,KAAI,MAAK,KAAK,EAAE,YAAY,MAAM,GAAG,GAAG,IAAI,EAAE,kBAAkB,KAAA,IAAY,WAAW,EAAE,cAAc,OAAO,IAAI;CAyBrH,MAAM,WAAsB,CAAC,kBAAkB;EAC7C,SAAS,CAAC;GAAE,MAAM;GAAQ,MAxBf;IACX,QAAQ,QAAQ,GAAG,QAAQ,QAAQ,MAAM;IACzC,UAAU,QAAQ;IAClB;IACA,gBAAgB,SAAS,IACrB,qDAAqD,gBAAgB,KAAK,IAAI,MAC9E;IACJ,YAAY,SAAS,IACjB,0BAA0B,YAAY,KAAK,IAAI,MAC/C;IACJ,aAAa,SAAS,IAClB,uBAAuB,aAAa,KAAK,IAAI,MAC7C;IACJ,gBAAgB,KAAA,KAAa,gBAAgB,KACzC,SAAS,gBACT;IACJ,eAAe,KACX,sBAAsB,eACtB;IACJ;IACA,MAAM,QAAQ,YAAY;GAC5B,CAAC,CAAC,QAAO,SAAQ,SAAS,EAAE,CAAC,CAAC,KAAK,IAGE;EAAE,CAAC;EACtC,QAAQ;GAAE,MAAM;GAAU,QAAQ;EAAkB;CACtD,CAAC,CAAC;CACF,MAAM,UAA2B;EAC/B,UAAU,OAAO;EACjB,OAAO,OAAO;EACd;EACA,QAAQ,kBAAkB,OAAO;EAGjC,WAAW,KAAK,IAAI,OAAO,WAAW,GAAK;EAC3C,aAAa;CACf;CAEA,MAAM,EAAE,OAAO,QAAQ;CAEvB,MAAM,YAAY,IAAI,eAAe;CACrC,IAAI;CACJ,WAAW,MAAM,SAAS,IAAI,IAAI,OAAO,OAAO,GAAG;EACjD,UAAU,KAAK,KAAK;EACpB,IAAI,MAAM,SAAS,cACjB,MAAM;GAAE,OAAO;GAAS,MAAM,MAAM;EAAK;CAE7C;CACA,MAAM,SAAS,UAAU;CACzB,IAAI,OAAO,SAAS,WAAW,OAAO,SAAS,WAC7C,8BAAc,IAAI,MAAM,QAAQ,OAAO,KAAK,KAAK,OAAO,QAAQ,SAAS;MACpE,IAAI,OAAO,SAAS,cACzB,8BAAc,IAAI,MAAM,2CAA2C;CAErE,MAAM,OAAO,UACV,OAAO,CAAC,CACR,QAAQ,UAA4F,MAAM,SAAS,MAAM,CAAC,CAC1H,KAAI,UAAS,MAAM,IAAI,CAAC,CACxB,KAAK,IAAI,CAAC,CACV,KAAK;CACR,IAAI,gBAAgB,KAAA,GAAW,MAAM;CACrC,IAAI,KAAK,SAAS,KAAK,MAAM,IAAI,MAAM,iBAAiB;CAGxD,MAAM,WAAW,gBAAgB,OAAO;CACxC,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;CACxC,cAAc,KAAK,WAAW,QAAQ,GAAG,MAAM,QAAQ,GAAG,IAAI,QAAQ,MAAM,MAAM,KAAK,KAAK,MAAM;CAElG,QAAQ,SAAS;CACjB,QAAQ,QAAQ,KAAK;CACrB,QAAQ,OAAO;CACf,QAAQ,QAAQ,KAAA;CAChB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CAC3C,YAAY,WAAW,OAAO;CAE9B,MAAM;EAAE,OAAO;EAAQ,MAAM;EAAU,OAAO,KAAK;CAAO;AAC5D;;AAGA,eAAsB,iBACpB,KACA,QACA,SACA,WACA,WACiB;CACjB,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,SAAS;CAC7D,IAAI,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,UAAU,OAAO;CAClE,MAAM,OAAO,gBAAgB,WAAW,OAAO;CAC/C,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,UAAU,UAAU;CAQlE,QAAQ,WAAU,MADI,SAAS,KAAK,QAAQ;EAAE,QAN/B;GACb;GACA;GACA;EACF,CAAC,CAAC,KAAK,IAE4C;EAAG,MADzC,KAAK,QAAQ,aAAa,EAAE,CAAC,CAAC,KACc;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;CAAE,CAAC,EAAA,CACjG,MAAM,GAAG,GAAG;CACtC,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CAC3C,YAAY,WAAW,OAAO;CAC9B,OAAO,QAAQ;AACjB;;;;;;AAOA,eAAsB,yBACpB,KACA,QACA,SACA,WACA,WACiD;CACjD,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,SAAS;CAC7D,IAAI,YAAY,KAAA,GAAW,OAAO;EAAE,SAAS;EAAI,WAAW;CAAE;CAC9D,MAAM,OAAO,gBAAgB,WAAW,OAAO;CAC/C,IAAI,SAAS,KAAA,GAAW,OAAO;EAAE,SAAS;EAAI,WAAW;CAAE;CAS3D,MAAM,MAAM,gBAAwD,MADjD,SAAS,KAAK,QAAQ;EAAE,QAP5B;GACb;GACA;GACA;GACA;EACF,CAAC,CAAC,KAAK,IAEyC;EAAG,MADtC,KAAK,QAAQ,aAAa,EAAE,CAAC,CAAC,KACW;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;CAAE,CAAC,CAChD;CACxE,MAAM,UAAU,OAAO,IAAI,YAAY,WAAW,IAAI,QAAQ,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,IAAI;CACrF,MAAM,YAAY,MAAM,QAAQ,IAAI,KAAK,IACrC,IAAI,MACD,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CACxE,KAAI,MAAK,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,IAClC,CAAC;CACL,IAAI,YAAY,IAAI,QAAQ,UAAU;CACtC,MAAM,OAAO,QAAQ,SAAS,CAAC;CAC/B,KAAK,MAAM,QAAQ,UAAU,MAAM,GAAG,CAAC,GAAG,KAAK,KAAK;EAAE;EAAW,MAAM;CAAK,CAAC;CAC7E,QAAQ,QAAQ,KAAK,MAAM,IAAI;CAC/B,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CAC3C,YAAY,WAAW,OAAO;CAC9B,OAAO;EAAE;EAAS,WAAW,UAAU;CAAO;AAChD;;;;;;AAOA,SAAgB,sBACd,SACA,WACA,WACQ;CACR,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,SAAS;CAC7D,IAAI,YAAY,KAAA,GAAW,OAAO;CAClC,MAAM,OAAO,gBAAgB,WAAW,OAAO;CAC/C,IAAI,SAAS,KAAA,GAAW,OAAO;CAC/B,IAAI,SAAS;CACb,KAAK,MAAM,KAAK,QAAQ,eAAe,CAAC,GAAG;EACzC,IAAI,EAAE,WAAW,WAAW;EAC5B,IAAI,EAAE,mBAAmB,KAAA,GAAW;EAEpC,MAAM,SAAS,EAAE,YAAY,MAAM,8BAA8B;EACjE,MAAM,YAAY,WAAW,OAAO,SAAS,CAAC,EAAA,CAC3C,KAAI,MAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,CACxB,QAAO,MAAK,EAAE,UAAU,CAAC;EAE5B,MAAM,aAAa,EAAE,kBAAkB,KAAA,KAAa,KAAK,IAAI,EAAE,gBAAgB,SAAS,KAAK;EAC7F,IAAI,SAAS,WAAW,KAAK,CAAC,YAAY;EAC1C,MAAM,MAAM,SAAS,WAAW,IAC5B,QACA,SAAS,MAAK,MAAK,KAAK,SAAS,CAAC,CAAC;EACvC,IAAI,OAAQ,SAAS,WAAW,KAAK;OAE/B,KAAK;IACP,EAAE,SAAS;IACX,EAAE,iBAAiB;IACnB;GACF;;CAEJ;CACA,IAAI,SAAS,GAAG;EACd,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;EAC3C,YAAY,WAAW,OAAO;CAChC;CACA,OAAO;AACT;;;;;;AAOA,eAAsB,aACpB,KACA,QACA,SACA,WACA,WACiB;CACjB,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,SAAS;CAC7D,IAAI,YAAY,KAAA,GAAW,OAAO;CAClC,MAAM,OAAO,gBAAgB,WAAW,OAAO;CAC/C,IAAI,SAAS,KAAA,GAAW,OAAO;CAY/B,MAAM,SAAQ,MADK,SAAS,KAAK,QAAQ;EAAE,QAV5B;GACb;GACA;GACA;GACA;GACA;GACA;EACF,CAAC,CAAC,KAAK,IAGyC;EAAG,MAFtC,KAAK,QAAQ,aAAa,EAAE,CAAC,CAAC,KAEW;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;CAAE,CAAC,EAAA,CACrG,MAAM,IAAI,CAAC,CAC3B,KAAI,SAAQ,KAAK,QAAQ,eAAe,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CACnD,QAAO,SAAQ,KAAK,SAAS,CAAC,CAAC,CAC/B,MAAM,GAAG,CAAC;CACb,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,MAAM,QAAQ,QAAQ,SAAS,CAAC;CAChC,KAAK,MAAM,QAAQ,OAAO,MAAM,KAAK;EAAE;EAAW,MAAM,KAAK,MAAM,GAAG,GAAG;CAAE,CAAC;CAC5E,QAAQ,QAAQ,MAAM,MAAM,IAAI;CAChC,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CAC3C,YAAY,WAAW,OAAO;CAC9B,OAAO,MAAM;AACf;AAIA,MAAM,mBAAmB;;AAGzB,eAAe,WACb,KACA,QACA,SACA,WACA,OACuB;CACvB,MAAM,SAAS;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,cAAc,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK,KAAK,EAAE,UAAU,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,IAAI;CACtG,MAAM,gBAAgB,MAAM,KAAI,MAAK;EAEnC,MAAM,WADO,gBAAgB,WAAW,CACpB,KAAK,GAAA,CAAI,QAAQ,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG;EACzE,OAAO,KAAK,EAAE,GAAG,IAAI,EAAE,MAAM,MAAM;CACrC,CAAC,CAAC,CAAC,KAAK,MAAM;CAed,MAAM,SAAS,eAAwC,MADpC,SAAS,KAAK,QAAQ;EAAE;EAAQ,MAbtC;GACX;GACA,QAAQ,UAAU,KAAA,IACd,YAAY;IACV,QAAQ,MAAM,WAAW,SAAS,IAAI,UAAU,QAAQ,MAAM,WAAW,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,MAAM;IAC3G,QAAQ,MAAM,SAAS,SAAS,IAAI,UAAU,QAAQ,MAAM,SAAS,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,MAAM;IACvG,QAAQ,MAAM,WAAW,SAAS,IAAI,QAAQ,QAAQ,MAAM,WAAW,KAAI,OAAM,KAAK,GAAG,KAAK,GAAG,GAAG,OAAO,KAAK,GAAG,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,MAAM;GAC1I,CAAC,CAAC,QAAO,MAAK,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI,IACjC;GACJ,eAAe,KAAK,YAAY,eAAe;GAC/C,qBAAqB;GACrB;EACF,CAAC,CAAC,QAAO,MAAK,MAAM,EAAE,CAAC,CAAC,KAAK,MACyB;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAAE,CAAC,CAC9D;CAC3D,MAAM,SAAuB,CAAC;CAC9B,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;EAC3D,IAAI,SAAS,IAAI;EACjB,OAAO,KAAK;GACV,WAAW,OAAO,MAAM,SAAS,KAAK;GACtC,UAAU;IAAC;IAAQ;IAAU;GAAK,CAAC,CAAC,SAAS,MAAM,QAAkB,IACjE,MAAM,WACN;GACJ;GACA,YAAY,OAAO,MAAM,eAAe,WAAW,MAAM,aAAa;EACxE,CAAC;CACH;CACA,OAAO;AACT;;AAGA,eAAsB,UACpB,KACA,QACA,SACA,WACA,YACuB;CACvB,MAAM,UAAU,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,YAAY;CAChG,IAAI,QAAQ,WAAW,GAAG;EACxB,aAAa,GAAG,CAAC;EACjB,OAAO,CAAC;CACV;CAEA,MAAM,eAAe,KAAK,KAAK,QAAQ,SAAS,gBAAgB;CAChE,MAAM,MAAoB,CAAC;CAC3B,aAAa,GAAG,YAAY;CAC5B,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,kBAAkB;EACzD,MAAM,QAAQ,QAAQ,MAAM,GAAG,IAAI,gBAAgB;EACnD,IAAI;GACF,IAAI,KAAK,GAAG,MAAM,WAAW,KAAK,QAAQ,SAAS,WAAW,KAAK,CAAC;EACtE,QAAQ,CAAoB;EAC5B,aAAa,KAAK,IAAI,KAAK,MAAM,IAAI,oBAAoB,gBAAgB,GAAG,YAAY,GAAG,YAAY;CACzG;CACA,OAAO,IAAI,MAAM,GAAG,EAAE;AACxB;;AAGA,eAAsB,cACpB,KACA,QACA,SACA,UAAU,IACO;CACjB,MAAM,SAAS;EACb;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,aAAa,QAAQ,OAAO,UAAU,KAAA,IAAY,MAAM,QAAQ,MAAM,UAAU;CACtF,MAAM,eAAe,QAAQ,WAAW,CAAC,EAAA,CAAG,MAAM,GAAG,CAAC,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,CAAC,KAAK,GAAG;CAalF,QADc,MADK,SAAS,KAAK,QAAQ;EAAE;EAAQ,MAVtC;GACX,OAAO,QAAQ,SAAS;GACxB;GACA,gBAAgB,KAAK,OAAO,gBAAgB;GAC5C,SAAS,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,YAAY,CAAC,CAAC;GAC3F,YAAY,QAAQ,QAAQ,MAAM,GAAG,IAAI;GACzC,QAAQ,KAAK,MAAM,KACf,iCAAiC,QAAQ,KAAK,MAC9C;EACN,CAAC,CAAC,QAAO,MAAK,MAAM,EAAE,CAAC,CAAC,KAAK,MACyB;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;CAAE,CAAC,EAAA,CACrG,QAAQ,oBAAoB,EAAE,CAAC,CAAC,QAAQ,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,GAClF;AACb;;;;;;AASA,SAAgB,aAAa,SAAuB,QAAoC,UAAkB;CACxG,MAAM,IAAc,CAAC;CACrB,EAAE,KAAK,MAAM,QAAQ,UAAU;CAC/B,EAAE,KAAK,WAAW,QAAQ,SAAS;CACnC,IAAI,QAAQ,UAAU,KAAA,GAAW;EAC/B,MAAM,QAAQ,QAAQ;EACtB,EAAE,KAAK,QAAQ;EACf,IAAI,MAAM,UAAU,IAAI,EAAE,KAAK,QAAQ,MAAM,OAAO;EACpD,IAAI,MAAM,WAAW,SAAS,GAAG,EAAE,KAAK,YAAY,MAAM,WAAW,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;EAClG,IAAI,MAAM,WAAW,SAAS,GAAG;GAC/B,EAAE,KAAK,MAAM;GACb,KAAK,MAAM,QAAQ,MAAM,YAAY;IACnC,MAAM,WAAW;KAAE,aAAa;KAAM,YAAY;KAAM,YAAY;KAAM,OAAO;IAAK,EAAE,KAAK;IAC7F,EAAE,KAAK,KAAK,KAAK,KAAK,GAAG,SAAS,IAAI,KAAK,OAAO,KAAK,GAAG,IAAI,KAAK,UAAU,KAAK,OAAO,KAAK,UAAU,KAAK,KAAK,cAAc,KAAK,OAAO,KAAK,cAAc,IAAI;GACrK;EACF;EACA,IAAI,MAAM,SAAS,SAAS,GAAG,EAAE,KAAK,YAAY,MAAM,SAAS,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;EAC9F,IAAI,MAAM,MAAM,SAAS,GAAG,EAAE,KAAK,YAAY,MAAM,MAAM,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;CAC1F;CACA,MAAM,aAAa,YAAY,QAAQ,KAAK;CAC5C,IAAI,eAAe,IAAI,EAAE,KAAK,UAAU;CACxC,IAAI,QAAQ,YAAY,KAAA,KAAa,QAAQ,QAAQ,SAAS,GAAG;EAC/D,EAAE,KAAK,OAAO;EACd,KAAK,MAAM,KAAK,QAAQ,SACtB,EAAE,KAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,IAAI,EAAE,QAAQ,MAAM,EAAE,aAAa,GAAG,EAAE,WAAW,EAAE;CAErF;CACA,IAAI,QAAQ,SAAS,SAAS,GAAG;EAE/B,MAAM,QAAQ,QAAQ,SAAS,QAAQ,GAAG,MAAM,KAAK,IAAI,GAAG,EAAE,EAAE,GAAG,CAAC;EACpE,MAAM,QAAQ,QAAQ,SAAS,QAAO,MAAK;GACzC,IAAI,UAAU,QAAQ,OAAO;GAC7B,IAAI,OAAO,UAAU,UAAU,OAAO,EAAE,WAAW;GACnD,OAAO,EAAE,KAAK,KAAK,IAAI,GAAG,QAAQ,EAAE;EACtC,CAAC;EACD,MAAM,QAAQ,UAAU,SAAS,wBAAwB,OAAO,UAAU,WAAW,KAAK,MAAM,uBAAuB,MAAM,MAAM,OAAO;EAC1I,EAAE,KAAK,IAAI,MAAM,EAAE;EACnB,MAAM,aAAqC;GAAE,SAAS;GAAO,YAAY;GAAO,SAAS;GAAO,WAAW;GAAO,UAAU;GAAO,UAAU;GAAO,OAAO;EAAK;EAChK,KAAK,MAAM,KAAK,OACd,EAAE,KAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,IAAI,WAAW,EAAE,WAAW,EAAE,OAAO,GAAG,EAAE,UAAU,KAAA,IAAY,IAAI,EAAE,MAAM,KAAK,GAAG,SAAS,EAAE,MAAM,OAAO,EAAE,WAAW,KAAK;EAE5J,IAAI,UAAU,UAAU,QAAQ,SAAS,SAAS,MAAM,QACtD,EAAE,KAAK,OAAO,QAAQ,SAAS,SAAS,MAAM,OAAO,+BAA+B;CAExF;CACA,KAAK,QAAQ,SAAS,CAAC,EAAA,CAAG,SAAS,GAAG;EACpC,EAAE,KAAK,mCAAmC;EAC1C,KAAK,MAAM,MAAM,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAM,GAAG,GAC7C,EAAE,KAAK,OAAO,EAAE,UAAU,KAAK,EAAE,MAAM;CAE3C;CACA,IAAI,QAAQ,YAAY,SAAS,GAAG;EAClC,EAAE,KAAK,MAAM;EACb,KAAK,MAAM,KAAK,QAAQ,aACtB,EAAE,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE,cAAc,EAAE,kBAAkB,KAAA,IAAY,OAAO,EAAE,cAAc,SAAS,IAAI;CAElH;CACA,IAAI,QAAQ,UAAU,KAAA,KAAa,QAAQ,UAAU,IAAI,EAAE,KAAK,SAAS,QAAQ,OAAO;CACxF,OAAO,EAAE,KAAK,MAAM;AACtB;;;;;AAkBA,eAAsB,cACpB,KACA,QACA,SACA,WACA,QACuB;CACvB,MAAM,SAAS;EACb;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,UAAU,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,YAAY;CAGhG,MAAM,OAAO;EACX,SAAS;EACT;EACA,UAAU,QAAQ,QAAQ,MAAM,GAAG,GAAI;EACvC,QAAQ,UAAU,KAAA,IACd,MAAM,QAAQ,MAAM,WAAW,OAAO,WAAW,QAAQ,MAAM,SAAS,OAAO,YAAY,QAAQ,MAAM,WAAW,KAAI,MAAK,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,MAC7I;GACH,QAAQ,SAAS,CAAC,EAAA,CAAG,SAAS,IAC3B,iBAAiB,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK,KAAK,EAAE,UAAU,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,IAAI,MACnG;CACN,CAAC,CAAC,QAAO,MAAK,MAAM,EAAE,CAAC,CAAC,KAAK,MAAM;CACnC,MAAM,QAAsB,CAAC;CAE7B,MAAM,oBAAoB;CAC1B,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,mBAAmB;EAC1D,MAAM,QAAQ,QAAQ,MAAM,GAAG,IAAI,iBAAiB;EACpD,MAAM,eAAe,MAAM,KAAI,MAAK;GAElC,MAAM,WADO,gBAAgB,WAAW,CACpB,KAAK,GAAA,CAAI,QAAQ,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG;GACzE,OAAO,KAAK,EAAE,GAAG,IAAI,EAAE,MAAM,MAAM;EACrC,CAAC,CAAC,CAAC,KAAK,MAAM;EACd,MAAM,OAAO,GAAG,KAAK,aAAa,MAAM,EAAE,CAAE,GAAG,GAAG,MAAM,MAAM,SAAS,EAAE,CAAE,GAAG,QAAQ,aAAa;EACnG,IAAI;GACF,MAAM,OAAO,MAAM,SAAS,KAAK,QAAQ;IAAE;IAAQ;IAAM,aAAa;IAAK,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;GAAE,CAAC;GACzH,KAAK,MAAM,SAAS,eAAwC,IAAI,GAAG;IACjE,MAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,KAAK,IAAI;IACrE,IAAI,UAAU,IAAI;IAClB,MAAM,KAAK;KACT,UAAU,OAAO,MAAM,aAAa,WAAW,MAAM,WAAW;KAChE,OAAO,MAAM,MAAM,GAAG,GAAG;KACzB,YAAY,OAAO,MAAM,eAAe,WAAW,MAAM,aAAa;KACtE,MAAM,MAAM,SAAS,UAAU,MAAM,SAAS,cAAc,MAAM,SAAS,SAAS,MAAM,OAAO;IACnG,CAAC;GACH;EACF,QAAQ,CAAoB;CAC9B;CACA,OAAO,MAAM,MAAM,GAAG,EAAE;AAC1B;;AAGA,SAAgB,YAAY,OAAuC;CACjE,IAAI,UAAU,KAAA,GAAW,OAAO;CAChC,MAAM,WAAqB,CAAC,8DAA8D;CAC1F,IAAI,MAAM,OAAO,SAAS,GAAG;EAC3B,SAAS,KAAK,yBAAyB;EACvC,MAAM,OAAO,SAAS,OAAO,MAAM;GACjC,SAAS,KAAK,GAAG,IAAI,EAAE,IAAI,MAAM,OAAO,MAAM,gBAAgB,KAAK,MAAM,MAAM,gBAAgB,IAAI;EACrG,CAAC;CACH;CACA,IAAI,MAAM,QAAQ,SAAS,GAAG;EAC5B,SAAS,KAAK,OAAO;EACrB,KAAK,MAAM,UAAU,MAAM,SACzB,SAAS,KAAK,KAAK,OAAO,OAAO,OAAO,gBAAgB,KAAK,IAAI,OAAO,gBAAgB,KAAK,OAAO,YAAY,KAAA,KAAa,OAAO,YAAY,KAAK,OAAO,OAAO,QAAQ,KAAK,IAAI;CAExL;CACA,IAAI,MAAM,SAAS,SAAS,GAAG;EAC7B,SAAS,KAAK,OAAO;EACrB,KAAK,MAAM,WAAW,MAAM,UAC1B,SAAS,KAAK,KAAK,QAAQ,KAAK,GAAG,QAAQ,KAAK,GAAG,QAAQ,gBAAgB,KAAK,IAAI,QAAQ,gBAAgB,KAAK,QAAQ,WAAW,KAAA,KAAa,QAAQ,WAAW,KAAK,OAAO,QAAQ,OAAO,KAAK,IAAI;CAE5M;CACA,OAAO,SAAS,KAAK,IAAI;AAC3B;;AAGA,eAAsB,aACpB,KACA,QACA,SACqB;CACrB,MAAM,SAAS;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,MAAM,aAAa,QAAQ,UAAU,KAAA,IACjC,CACE,QAAQ,MAAM,UAAU,KAAK,MAAM,QAAQ,MAAM,UAAU,IAC3D,QAAQ,MAAM,WAAW,SAAS,IAAI,UAAU,QAAQ,MAAM,WAAW,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,MAAM,EAC7G,CAAC,CAAC,QAAO,MAAK,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI,IACjC;CASJ,MAAM,MAAM,gBAA6E,MADtE,SAAS,KAAK,QAAQ;EAAE;EAAQ,MAPtC;GACX;GACA,OAAO,QAAQ,SAAS;GACxB,eAAe,KAAK,aAAa;GACjC,UAAU,QAAQ,QAAQ,MAAM,GAAG,GAAI;GACvC;EACF,CAAC,CAAC,QAAO,MAAK,MAAM,EAAE,CAAC,CAAC,KAAK,MACyB;EAAG,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAAE,CAAC,CAC5B;CAC7F,MAAM,OAAO,UAA2B,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;CACnF,MAAM,YAAY,UAChB,MAAM,QAAQ,KAAK,IAAI,MAAM,QAAQ,MAAoC,OAAO,MAAM,YAAY,MAAM,IAAI,IAAI,CAAC;CAkBnH,OAAO;EAhBL,QAAQ,SAAS,IAAI,MAAM,CAAC,CAAC,KAAI,WAAU;GACzC,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE,KAAK;GACtC,aAAa,IAAI,MAAM,WAAW,CAAC,CAAC,MAAM,GAAG,GAAG;EAClD,EAAE,CAAC,CAAC,QAAO,MAAK,EAAE,SAAS,WAAW,EAAE,gBAAgB,EAAE;EAC1D,SAAS,SAAS,IAAI,OAAO,CAAC,CAAC,KAAI,WAAU;GAC3C,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE,KAAK;GACtC,aAAa,IAAI,MAAM,WAAW,CAAC,CAAC,MAAM,GAAG,GAAG;GAChD,SAAS,IAAI,MAAM,OAAO,CAAC,CAAC,MAAM,GAAG,EAAE;EACzC,EAAE,CAAC,CAAC,QAAO,MAAK,EAAE,SAAS,WAAW,EAAE,gBAAgB,EAAE;EAC1D,UAAU,SAAS,IAAI,QAAQ,CAAC,CAAC,KAAI,WAAU;GAC7C,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE,KAAK;GACtC,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE,KAAK;GACtC,aAAa,IAAI,MAAM,WAAW,CAAC,CAAC,MAAM,GAAG,GAAG;GAChD,QAAQ,IAAI,MAAM,MAAM,CAAC,CAAC,MAAM,GAAG,EAAE;EACvC,EAAE,CAAC,CAAC,QAAO,MAAK,EAAE,SAAS,WAAW,EAAE,gBAAgB,EAAE;CAEjD;AACb;;;;;AAMA,eAAsB,cACpB,KACA,QACA,SACA,WACiB;CACjB,MAAM,OAAO,IAAI,KAAK,QAAQ,SAAS,CAAC,EAAA,CAAG,KAAI,MAAK,EAAE,SAAS,CAAC;CAChE,IAAI,SAAS;CACb,KAAK,MAAM,WAAW,QAAQ,UAAU;EACtC,IAAI,QAAQ,WAAW,aAAa,QAAQ,WAAW,cAAc;EACrE,IAAI,QAAQ,SAAS,KAAA,KAAa,KAAK,IAAI,QAAQ,EAAE,GAAG;EACxD,IAAI;GAEF,IAAI,MADY,aAAa,KAAK,QAAQ,SAAS,WAAW,QAAQ,EAAE,IAChE,GAAG;EACb,QAAQ,CAAgC;EACxC,KAAK,IAAI,QAAQ,EAAE;CACrB;CACA,OAAO;AACT;;;;;AAMA,eAAsB,kBACpB,KACA,QACA,SACA,WAC2B;CAG3B,MAAM,YADe,QAAQ,SAAS,CAAC,EAAA,CAAG,SAAS,IAAI,QAAQ,QAAQ,QAAQ,OAAO,eAAe,CAAC,EAAA,CAC7E,KAAI,OAAM;EACjC,MAAM,EAAE;EACR,QAAQ,EAAE,UAAU,CAAC;EACrB,MAAM,EAAE,cAAc,KAAA,IAAY,EAAE,YAAa,EAAE,QAAQ;CAC7D,EAAE;CACF,MAAM,QAAQ,QAAQ,SAAS,CAAC;CAChC,IAAI,OAAO,WAAW,KAAK,MAAM,WAAW,GAAG,OAAO,CAAC;CAGvD,MAAM,uBAAO,IAAI,IAAqD;CACtE,MAAM,QAAQ,OAAO,KAAI,SAAQ,KAAK,IAAI;CAC1C,KAAK,MAAM,WAAW,QAAQ,UAAU;EACtC,IAAI,QAAQ,WAAW,aAAa,QAAQ,WAAW,cAAc;EACrE,MAAM,OAAO,gBAAgB,WAAW,OAAO;EAC/C,IAAI,SAAS,KAAA,GAAW;EACxB,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,SAAS,IAAI,GAAG;GACvB,MAAM,QAAQ,KAAK,IAAI,IAAI,KAAK;IAAE,0BAAU,IAAI,IAAY;IAAG,MAAM;GAAE;GACvE,MAAM,SAAS,IAAI,QAAQ,EAAE;GAC7B,IAAI,QAAQ,KAAK,MAAM,MAAM,MAAM,OAAO,QAAQ;GAClD,KAAK,IAAI,MAAM,KAAK;EACtB;CAEJ;CAGA,IAAI,2BAAW,IAAI,IAAoB;CACvC,IAAI,MAAM,SAAS,GAAG;EACpB,MAAM,SAAS;GACb;GACA;GACA;EACF,CAAC,CAAC,KAAK,IAAI;EACX,MAAM,cAAc,OAAO,KAAI,OAAM,KAAK,GAAG,KAAK,GAAG,GAAG,OAAO,KAAK,GAAG,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI;EACtF,MAAM,aAAa,MAAM,KAAI,MAAK,KAAK,EAAE,UAAU,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,IAAI;EAC3E,MAAM,OAAO;GACX,UAAU;GACV,UAAU,MAAM,OAAO,QAAQ,WAAW,MAAM,IAAK;GACrD;EACF,CAAC,CAAC,KAAK,MAAM;EACb,IAAI;GACF,MAAM,OAAO,MAAM,SAAS,KAAK,QAAQ;IAAE;IAAQ;IAAM,aAAa;IAAK,WAAW,KAAK,IAAI,OAAO,WAAW,GAAI;GAAE,CAAC;GACxH,KAAK,MAAM,SAAS,eAAwC,IAAI,GAAG;IACjE,MAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;IAC3D,IAAI,SAAS,MAAM,OAAO,MAAM,WAAW,UAAU,SAAS,IAAI,MAAM,MAAM,MAAM;GACtF;EACF,QAAQ,CAA2B;CACrC;CAGA,MAAM,QAA0B,CAAC;CACjC,MAAM,UAAU,SAAyB,OAAO,MAAK,MAAK,EAAE,SAAS,IAAI,CAAC,EAAE,QAAQ;CACpF,KAAK,MAAM,QAAQ,QAAQ;EACzB,MAAM,QAAQ,KAAK,IAAI,KAAK,IAAI;EAChC,MAAM,KAAK;GACT,MAAM,KAAK;GACX,MAAM,KAAK;GACX,QAAQ,SAAS,IAAI,KAAK,IAAI,KAAK;GACnC,aAAa,OAAO,QAAQ;GAC5B,aAAa,OAAO,SAAS,QAAQ;EACvC,CAAC;CACH;CAEA,KAAK,MAAM,CAAC,MAAM,UAAU,MAC1B,IAAI,CAAC,MAAM,MAAK,MAAK,EAAE,SAAS,IAAI,GAClC,MAAM,KAAK;EACT;EACA,MAAM,OAAO,IAAI;EACjB,QAAQ,SAAS,IAAI,IAAI,KAAK;EAC9B,aAAa,MAAM;EACnB,aAAa,MAAM,SAAS;CAC9B,CAAC;CAGL,OAAO;AACT;;AAKA,SAAS,yBAAiC;CACxC,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;AAGA,eAAsB,mBACpB,KACA,QACA,SACuB;CACvB,MAAM,OAAO;EACX;EACA,QAAQ,QAAQ;EAChB,UAAU,QAAQ,SAAS;CAC7B,CAAC,CAAC,KAAK,IAAI;CAEX,MAAM,SAAS,eAAwC,MADpC,SAAS,KAAK,QAAQ;EAAE,QAAQ,uBAAuB;EAAG;EAAM,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAAE,CAAC,CACxF;CAC3D,MAAM,WAAW,IAAI,IAAI,QAAQ,YAAY,KAAI,MAAK,EAAE,WAAW,CAAC;CACpE,MAAM,UAAwB,CAAC;CAC/B,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EACjD,MAAM,cAAc,OAAO,MAAM,gBAAgB,WAAW,MAAM,YAAY,KAAK,IAAI;EACvF,IAAI,gBAAgB,MAAM,SAAS,IAAI,WAAW,GAAG;EACrD,SAAS,IAAI,WAAW;EACxB,QAAQ,KAAK;GACX,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,GAAG,QAAQ;GAC7C,aAAa,YAAY,MAAM,GAAG,GAAG;GACrC,gBAAgB,OAAO,MAAM,mBAAmB,WAAW,MAAM,iBAAiB,KAAA;GAClF,eAAe,OAAO,MAAM,kBAAkB,WAAW,MAAM,gBAAgB,KAAA;GAC/E,QAAQ;EACV,CAAC;CACH;CACA,QAAQ,YAAY,KAAK,GAAG,OAAO;CACnC,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CAC3C,OAAO;AACT;;;;;AAQA,eAAsB,kBACpB,KACA,QACA,YAC8G;CAC9G,MAAM,OAAO,6BAA6B;CAE1C,MAAM,MAAM,gBAAqH,MAD9G,SAAS,KAAK,QAAQ;EAAE,QAAQ,wBAAwB;EAAG;EAAM,aAAa;EAAK,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;CAAE,CAAC,CACf;CACrI,MAAM,YAAY,UAChB,MAAM,QAAQ,KAAK,IAAI,MAAM,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE,IAAI,CAAC;CACvG,MAAM,SAAS;EACb,YAAY,SAAS,IAAI,UAAU;EACnC,eAAe,SAAS,IAAI,aAAa;EACzC,kBAAkB,SAAS,IAAI,gBAAgB;EAC/C,YAAY,SAAS,IAAI,UAAU;CACrC;CACA,IAAI,OAAO,WAAW,SAAS,OAAO,cAAc,SAAS,OAAO,iBAAiB,SAAS,OAAO,WAAW,WAAW,GACzH,MAAM,IAAI,MAAM,mBAAmB;CAErC,OAAO;AACT;;AAKA,SAAgB,WAAW,WAAmB,SAAuB,QAAyE;CAC5I,MAAM,QAAkB,CAAC;CACzB,IAAI,WAAW,MACb,MAAM,KAAK,KAAK,QAAQ,SAAS,GAAG;MAEpC,MAAM,KAAK,QAAQ,UAAU,EAAE;CAEjC,MAAM,OAAO,QAAQ,SAAS,QAAO,MAAK,EAAE,SAAS,KAAA,CAAS;CAC9D,KAAK,MAAM,WAAW,MAAM;EAC1B,MAAM,OAAO,gBAAgB,WAAW,OAAO,KAAK;EACpD,IAAI,WAAW,MACb,MAAM,KAAK,SAAS,QAAQ,GAAG,IAAI,QAAQ,MAAM,KAAK,KAAK,KAAK,GAAG,EAAE;OAErE,MAAM,KAAK,IAAI,IAAI,QAAQ,GAAG,IAAI,QAAQ,SAAS,IAAI,KAAK,KAAK,GAAG,EAAE;CAE1E;CACA,MAAM,UAAU,MAAM,KAAK,IAAI;CAC/B,MAAM,MAAM,WAAW,OAAO,OAAO;CACrC,MAAM,OAAO,IAAI,aAAa,QAAQ,QAAQ,EAAE,MAAM;CACtD,cAAc,KAAK,WAAW,IAAI,GAAG,SAAS,MAAM;CACpD,OAAO;EAAE;EAAM,OAAO,QAAQ;EAAQ,UAAU,KAAK;CAAO;AAC9D;;;;;;;;ACj3FA,SAAgB,gBAAwB;CACtC,OAAO,KAAK,QAAQ,GAAG,QAAQ,gCAAgC;AACjE;AAOA,SAAS,eAA+B;CACtC,OAAO;EAAE,OAAO,CAAC;EAAG,cAAc;CAAK;AACzC;;AAGA,SAAgB,gBAAgC;CAC9C,MAAM,OAAO,cAAc;CAC3B,IAAI,CAAC,WAAW,IAAI,GAAG,OAAO,aAAa;CAC3C,IAAI;EACF,IAAI,MAAM,aAAa,MAAM,MAAM;EACnC,IAAI,IAAI,WAAW,CAAC,MAAM,OAAQ,MAAM,IAAI,MAAM,CAAC;EACnD,MAAM,SAAS,KAAK,MAAM,GAAG;EAC7B,IAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,GAAG,OAAO,aAAa;EACtD,OAAO;GAAE,OAAO,OAAO;GAAO,cAAc,OAAO,gBAAgB;EAAK;CAC1E,QAAQ;EACN,OAAO,aAAa;CACtB;AACF;;AAGA,SAAS,cAAc,OAA6B;CAClD,MAAM,OAAO,cAAc;CAC3B,UAAU,KAAK,QAAQ,GAAG,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;CACtD,cAAc,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,MAAM;AAC5D;;AAGA,SAAgB,WAAW,OAA8C;CACvE,OAAO,MAAM,MAAM,MAAK,MAAK,EAAE,OAAO,MAAM,YAAY;AAC1D;;AAGA,SAAgB,kBAAkB,OAA0C;CAC1E,OAAO;EACL,OAAO,MAAM,MAAM,KAAI,SAAQ;GAC7B,MAAM,UAAU,YAAY,KAAK,SAAS;GAC1C,MAAM,OAAO,YAAY,KAAA,IAAY,IAAI,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,cAAc,EAAE,WAAW,aAAa,EAAE,WAAW,UAAU,CAAC,CAAC;GACpJ,MAAM,WAAW,SAAS,cAAc,KAAA,KAAa,QAAQ,cAAc,MAAM,WAAW,KAAK,KAAK,WAAW,QAAQ,SAAS,CAAC;GACnI,OAAO;IACL,GAAG;IACH;IACA,OAAO,SAAS,SAAS,UAAU;IACnC,YAAY,YAAY,KAAA;IACxB;IACA,OAAO,SAAS;GAClB;EACF,CAAC;EACD,cAAc,MAAM;CACtB;AACF;;AAGA,SAAgB,WAAW,UAAkB,WAA8B;CACzE,MAAM,QAAQ,cAAc;CAC5B,MAAM,KAAK,QAAQ,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,SAAS,KAAK;CAC3E,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;CACnC,MAAM,OAAkB;EAAE;EAAI;EAAU;EAAW,WAAW;EAAK,WAAW;CAAI;CAClF,MAAM,MAAM,KAAK,IAAI;CACrB,MAAM,eAAe;CACrB,cAAc,KAAK;CACnB,OAAO;AACT;;AAGA,SAAgB,WAAW,IAAY,UAA2B;CAChE,MAAM,QAAQ,cAAc;CAC5B,MAAM,OAAO,MAAM,MAAM,MAAK,MAAK,EAAE,OAAO,EAAE;CAC9C,IAAI,SAAS,KAAA,GAAW,OAAO;CAC/B,KAAK,WAAW;CAChB,KAAK,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CACxC,cAAc,KAAK;CACnB,OAAO;AACT;;;;;;;AAQA,SAAgB,2BAA2B,WAA4B;CAErE,IADc,cACN,CAAC,CAAC,MAAM,SAAS,GAAG,OAAO;CACnC,IAAI,CAAC,WAAW,SAAS,GAAG,OAAO;CAEnC,MAAM,aAAa,WAAW,KAAK,WAAW,oBAAoB,CAAC;CACnE,MAAM,cAAc,WAAW,SAAS;CACxC,IAAI,CAAC,cAAc,CAAC,aAAa,OAAO;CAGxC,WAFgB,YAAY,SACL,CAAC,EAAE,YAAY,UAAU,MAAM,OAAO,CAAC,CAAC,IAAI,KAAK,SACnD,SAAS;CAC9B,OAAO;AACT;;AAGA,SAAgB,aAAa,IAAmC;CAC9D,MAAM,QAAQ,cAAc;CAC5B,MAAM,OAAO,MAAM,MAAM,MAAK,MAAK,EAAE,OAAO,EAAE;CAC9C,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;CAC/B,MAAM,eAAe;CACrB,KAAK,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CACxC,cAAc,KAAK;CACnB,OAAO;AACT;;AAGA,SAAgB,WAAW,IAAqB;CAC9C,MAAM,QAAQ,cAAc;CAC5B,MAAM,MAAM,MAAM,MAAM,WAAU,MAAK,EAAE,OAAO,EAAE;CAClD,IAAI,QAAQ,IAAI,OAAO;CACvB,MAAM,MAAM,OAAO,KAAK,CAAC;CACzB,IAAI,MAAM,iBAAiB,IACzB,MAAM,eAAe,MAAM,MAAM,EAAE,EAAE,MAAM;CAE7C,cAAc,KAAK;CACnB,OAAO;AACT;;AAGA,SAAgB,sBAA0C;CAExD,OADa,WAAW,cAAc,CAC5B,CAAC,EAAE;AACf;;AAGA,SAAgB,oBAAoB,UAA0B;CAE5D,OAAO,KAAK,kCADE,SAAS,QAAQ,iBAAiB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE,KAAK,OACxB;AACrD;;;;;;;;;;ACzHA,SAAS,aAAa,WAA2B;CAC/C,OAAO,KAAK,WAAW,gBAAgB;AACzC;AAEA,IAAa,mBAAb,MAA8B;CAQR;CAPpB,QAAiC;CACjC,UAAkB;CAClB,iBAAyB;CACzB,gBAAwB;;CAExB,UAAiC;CAEjC,YAAY,MAA8D;EAAtD,KAAA,OAAA;CAAuD;;CAG3E,SAA0B;EACxB,IAAI,KAAK,UAAU,MAAM,OAAO,KAAK;EAErC,MAAM,aAAuB,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,SAAS;EAC7D,MAAM,YAAY,cAAc;EAChC,KAAK,MAAM,KAAK,UAAU,OAAO,IAAI,CAAC,WAAW,SAAS,EAAE,SAAS,GAAG,WAAW,KAAK,EAAE,SAAS;EACnG,KAAK,MAAM,aAAa,YAAY;GAClC,MAAM,OAAO,aAAa,SAAS;GACnC,IAAI,CAAC,WAAW,IAAI,GAAG;GACvB,IAAI;IACF,MAAM,MAAM,aAAa,MAAM,MAAM;IACrC,MAAM,SAAS,KAAK,MAAM,GAAG;IAC7B,IAAI,QAAQ,UAAU,KAAA,GAAW;IAEjC,IAAI,OAAO,WAAW,WAAW,OAAO,SAAS;IACjD,KAAK,QAAQ;IACb,KAAK,UAAU;IACf,OAAO,KAAK;GACd,QAAQ,CAA4B;EACtC;EACA,OAAO;CACT;CAEA,UAAwB;EACtB,IAAI,KAAK,UAAU,MAAM;EACzB,MAAM,YAAY,KAAK,WAAW,KAAK,KAAK,UAAU,CAAC,CAAC;EACxD,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;EACxC,cAAc,aAAa,SAAS,GAAG,KAAK,UAAU,KAAK,OAAO,MAAM,CAAC,GAAG,MAAM;CACpF;CAEA,IAAY,MAAoB;EAC9B,IAAI,KAAK,UAAU,MAAM;EACzB,KAAK,MAAM,IAAI,KAAK;GAAE,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;GAAG;EAAK,CAAC;EAC1D,IAAI,KAAK,MAAM,IAAI,SAAS,KAAK,KAAK,MAAM,MAAM,KAAK,MAAM,IAAI,MAAM,IAAI;EAC3E,KAAK,MAAM,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;CAChD;;CAGA,MAAM,MAAM,SAAiB,OAAkC;EAC7D,MAAM,SAAS,KAAK,KAAK,UAAU;EACnC,IAAI,KAAK,SAAS,MAAM,IAAI,MAAM,kBAAkB;EACpD,IAAI,UAAU,YAAY,OAAO,SAAS;EAC1C,IAAI,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,WAAW;EAGtD,IAAI,QAAQ,QAAQ,SAAS,QAAQ;GACnC,MAAM,OAAO,QAAQ,QAAQ,SAAS;GACtC,KAAK,IAAI,WAAW,KAAK,MAAM;GAC/B,MAAM,WAAW,MAAM,aAAa,KAAK,KAAK,KAAK,QAAQ,SAAS,MAAM,KAAA,GAAW,OAAO,SAAS;GACrG,sBAAsB,OAAO,WAAW,OAAO;GAC/C,QAAQ,SAAS,KAAK,GAAG,QAAQ;GACjC,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,OAAO,WAAW,OAAO;GACrC,KAAK,IAAI,YAAY,QAAQ,SAAS,OAAO,GAAG;EAClD;EAEA,KAAK,QAAQ;GACX,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE;GACpC;GACA;GACA,QAAQ;GACR,WAAW;GACX,OAAO;IAAE,WAAW;IAAG,SAAS;IAAG,UAAU;IAAG,aAAa;IAAG,OAAO;GAAE;GACzE,eAAe,CAAC;GAChB,KAAK,CAAC;GACN,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;GAClC,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EACpC;EACA,KAAK,iBAAiB;EACtB,KAAK,gBAAgB;EAErB,KAAK,UAAU,OAAO;EACtB,KAAK,UAAU;EACf,KAAK,QAAQ;EACb,KAAU,KAAK;EACf,OAAO,KAAK;CACd;CAEA,QAAc;EAAE,KAAK,iBAAiB;CAAK;CAC3C,SAAe;EACb,IAAI,KAAK,UAAU,QAAQ,KAAK,MAAM,WAAW,UAAU;EAC3D,KAAK,MAAM,SAAS;EACpB,KAAK,UAAU;EACf,KAAK,iBAAiB;EACtB,KAAK,gBAAgB;EACrB,KAAK,QAAQ;EACb,KAAU,KAAK;CACjB;CACA,OAAa;EAAE,KAAK,gBAAgB;CAAK;;CAGzC,MAAc,OAAsB;EAElC,MAAM,SAAS,KAAK,KAAK,UAAU;EACnC,MAAM,YAAY,KAAK,WAAW,OAAO;EACzC,IAAI;GACF,OAAO,KAAK,UAAU,MAAM;IAC1B,IAAI,KAAK,eAAe;KACtB,KAAK,gBAAgB;KACrB,KAAK,MAAM,SAAS;KACpB,KAAK,IAAI,QAAQ;KACjB,KAAK,QAAQ;KACb;IACF;IACA,IAAI,KAAK,gBAAgB;KACvB,KAAK,iBAAiB;KACtB,KAAK,MAAM,SAAS;KACpB,KAAK,IAAI,eAAe;KACxB,KAAK,QAAQ;KACb;IACF;IACA,MAAM,UAAU,YAAY,SAAS;IACrC,IAAI,YAAY,KAAA,GAAW;KACzB,KAAK,MAAM,SAAS;KACpB,KAAK,MAAM,QAAQ;KACnB,KAAK,QAAQ;KACb;IACF;IAEA,IAAI;IACJ,KAAK,IAAI,KAAK,KAAK,MAAM,WAAW,MAAM,KAAK,MAAM,OAAO,MAAM;KAChE,MAAM,KAAK,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,EAAE;KACjD,IAAI,OAAO,KAAA,GAAW;KACtB,IAAI,GAAG,WAAW,YAAY;MAAE,KAAK,MAAM,YAAY;MAAI;KAAS;KACpE,OAAO;KACP;IACF;IACA,IAAI,SAAS,KAAA,GAAW;KACtB,KAAK,MAAM,SAAS;KACpB,KAAK,IAAI,SAAS,KAAK,MAAM,QAAQ,GAAG,KAAK,MAAM,MAAM,OAAO;KAChE,KAAK,QAAQ;KACb;IACF;IACA,KAAK,MAAM,YAAY,KAAK;IAC5B,MAAM,KAAK,eAAe,SAAS,IAAI;IACvC,KAAK,QAAQ;GACf;EACF,SAAS,OAAO;GACd,IAAI,KAAK,UAAU,MAAM;IACvB,KAAK,MAAM,SAAS;IACpB,KAAK,MAAM,QAAS,MAAgB;IACpC,KAAK,IAAI,SAAU,MAAgB,SAAS;IAC5C,KAAK,QAAQ;GACf;EACF,UAAU;GACR,KAAK,UAAU;EACjB;CACF;CAEA,MAAc,eAAe,SAAuB,SAAqC;EACvF,IAAI,QAAQ,WAAW,aAAa,QAAQ,WAAW,WAAW,QAAQ,WAAW,WACnF,MAAM,KAAK,QAAQ,SAAS,OAAO;OAC9B,IAAI,QAAQ,WAAW,YAC5B,MAAM,KAAK,eAAe,SAAS,OAAO;OACrC,IAAI,QAAQ,WAAW,cAAc;GAE1C,QAAQ,SAAS;GACjB,MAAM,KAAK,QAAQ,SAAS,OAAO;EACrC;CACF;;CAGA,MAAc,QAAQ,SAAuB,SAAqC;EAChF,MAAM,EAAE,KAAK,cAAc,KAAK;EAChC,MAAM,SAAS,UAAU;EACzB,MAAM,YAAY,KAAK,WAAW,OAAO;EACzC,MAAM,KAAK,QAAQ;EACnB,MAAM,WAAW,QAAQ,WAAW;EACpC,QAAQ,SAAS;EACjB,QAAQ,QAAQ,KAAA;EAChB,QAAQ,gCAAe,IAAI,KAAK,EAAA,CAAE,YAAY;EAC9C,sBAAsB,WAAW,OAAO;EACxC,YAAY,WAAW,OAAO;EAC9B,KAAK,IAAI,WAAW,IAAI,GAAG,IAAI,QAAQ,MAAM,UAAU,IAAI,GAAG,IAAI,QAAQ,MAAM,KAAK;EACrF,IAAI;GACF,WAAW,MAAM,QAAQ,sBAAsB,KAAK,QAAQ,SAAS,WAAW,EAAE;GAClF,IAAI;IAAE,MAAM,yBAAyB,KAAK,QAAQ,SAAS,WAAW,EAAE;GAAE,SAAS,GAAG;IAAE,QAAQ,KAAK,wCAAyC,EAAY,OAAO;GAAE;GACnK,IAAI;IAAE,sBAAsB,SAAS,WAAW,EAAE;GAAE,SAAS,GAAG;IAAE,QAAQ,KAAK,qCAAsC,EAAY,OAAO;GAAE;GAC1I,IAAI,OAAO,cAAc,MAAM;IAC7B,MAAM,SAAS,MAAM,cAAc,KAAK,QAAQ,SAAS,WAAW,EAAE;IACtE,IAAI,KAAK,UAAU,MAAM,KAAK,MAAM,MAAM,WAAW,gBAAgB,YAAY;IACjF,KAAK,IAAI,IAAI,GAAG,OAAO,OAAO,MAAM,IAAI,OAAO,SAAS,SAAS,SAAS;GAC5E,OAAO;IACL,QAAQ,SAAS;IACjB,sBAAsB,WAAW,OAAO;IACxC,YAAY,WAAW,OAAO;GAChC;GACA,IAAI,OAAO,oBAAoB,MAC7B,IAAI;IACF,MAAM,OAAO,gBAAgB,WAAW,OAAO;IAC/C,IAAI,SAAS,KAAA,GAAW;KACtB,IAAI,WAAW;KACf,IAAI,KAAK,GAAG;MACV,MAAM,OAAO,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,KAAK,CAAC;MACvD,IAAI,SAAS,KAAA,GAAW,YAAY,gBAAgB,WAAW,IAAI,KAAK,GAAA,CAAI,QAAQ,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI;KACrH;KACA,MAAM,SAAS,MAAM,oBAAoB,KAAK,QAAQ,SAAS,IAAI,MAAM,QAAQ;KACjF,QAAQ,eAAe;KACvB,IAAI,OAAO,kBAAkB,KAAA,GAAW,kBAAkB,SAAS,IAAI,OAAO,aAAa;KAC3F,sBAAsB,WAAW,OAAO;KACxC,YAAY,WAAW,OAAO;IAChC;GACF,SAAS,GAAG;IAAE,QAAQ,KAAK,wCAAyC,EAAY,OAAO;GAAE;EAE7F,SAAS,OAAO;GACd,QAAQ,SAAS;GACjB,QAAQ,QAAS,MAAgB;GACjC,sBAAsB,WAAW,OAAO;GACxC,YAAY,WAAW,OAAO;GAC9B,IAAI,KAAK,UAAU,MAAM,KAAK,MAAM,MAAM;GAC1C,KAAK,IAAI,IAAI,GAAG,OAAQ,MAAgB,SAAS;EACnD;CACF;;CAGA,MAAc,eAAe,SAAuB,SAAqC;EACvF,MAAM,EAAE,KAAK,cAAc,KAAK;EAChC,MAAM,SAAS,UAAU;EACzB,MAAM,YAAY,KAAK,WAAW,OAAO;EACzC,MAAM,KAAK,QAAQ;EAEnB,MAAM,SADS,QAAQ,QACA,UAAU,CAAC,EAAA,CAAG,QAAO,MAAK,EAAE,aAAa,MAAM;EACtE,IAAI,MAAM,WAAW,GAAG;GACtB,QAAQ,SAAS;GACjB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,WAAW,OAAO;GAC9B,IAAI,KAAK,UAAU,MAAM,KAAK,MAAM,MAAM;GAC1C,KAAK,IAAI,IAAI,GAAG,eAAe;GAC/B;EACF;EACA,KAAK,IAAI,IAAI,GAAG,OAAO,MAAM,OAAO,UAAU;EAC9C,KAAK,IAAI,QAAQ,GAAG,SAAS,GAAG,SAAS;GACvC,MAAM,QAAQ,qBAAqB,MAAM,KAAI,MAAK,IAAI,EAAE,SAAS,IAAI,EAAE,OAAO,EAAE,eAAe,KAAK,QAAQ,EAAE,eAAe,IAAI,CAAC,CAAC,KAAK,MAAM;GAC9I,IAAI;IACF,WAAW,MAAM,QAAQ,qBAAqB,KAAK,QAAQ,SAAS,WAAW,IAAI,OAAO,KAAA,CAAS;GACrG,SAAS,OAAO;IACd,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,QAAS,MAAgB,SAAS;IAC7D;GACF;GAEA,MAAM,QAAQ,YAAY,SAAS;GACnC,MAAM,UAAU,OAAO,SAAS,MAAK,MAAK,EAAE,OAAO,EAAE;GACrD,MAAM,QAAQ,SAAS;GACvB,IAAI,UAAU,KAAA,KAAa,MAAM,SAAS,IAAI;IAC5C,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,SAAS;IACpC;GACF;GACA,MAAM,SAAS,MAAM,kBAAkB,KAAK,QAAQ,OAAQ,OAAO,QAAQ,MAAM;GACjF,MAAM,UAAU,OAAO,UAAU,CAAC,EAAA,CAAG,QAAO,MAAK,EAAE,aAAa,MAAM;GACtE,IAAI,OAAO,UAAU,OAAO,WAAW,GAAG;IAExC,KAAK,WAAW,OAAQ,SAAU,OAAO,MAAM;IAC/C,IAAI,KAAK,UAAU,MAAM,KAAK,MAAM,MAAM;IAC1C,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,QAAQ,OAAO,MAAM,GAAG;IACnD;GACF;GACA,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,OAAO,OAAO,OAAO,OAAO;EACzD;EACA,IAAI,KAAK,UAAU,MAAM,KAAK,MAAM,cAAc,KAAK,EAAE;EACzD,KAAK,IAAI,IAAI,GAAG,uBAAuB;CACzC;CAEA,WAAmB,SAAuB,SAAsB,OAAe,QAA4B;EACzG,MAAM,SAAS,KAAK,KAAK,UAAU;EACnC,MAAM,WAAW,gBAAgB,OAAO;EACxC,UAAU,OAAO,WAAW,EAAE,WAAW,KAAK,CAAC;EAC/C,MAAM,aAAa,KAAK,OAAO,WAAW,QAAQ;EAClD,IAAI,WAAW,UAAU,GACvB,aAAa,YAAY,KAAK,OAAO,WAAW,GAAG,SAAS,QAAQ,SAAS,EAAE,EAAE,QAAQ,CAAC;EAE5F,cAAc,YAAY,MAAM,QAAQ,GAAG,IAAI,QAAQ,MAAM,MAAM,MAAM,KAAK,MAAM;EACpF,QAAQ,eAAe,KAAA;EACvB,QAAQ,QAAQ,MAAM;EACtB,QAAQ,OAAO;EACf,IAAI,OAAO,OAAO,UAAU,UAAU;GACpC,QAAQ,SAAS;GACjB,QAAQ,SAAS,OAAO,WAAW,OAAO,aAAa;EACzD,OAAO;GACL,QAAQ,SAAS;GACjB,QAAQ,SAAS,KAAA;EACnB;EACA,QAAQ,QAAQ,KAAA;EAChB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;EAC3C,YAAY,OAAO,WAAW,OAAO;CACvC;AACF;;;;;;;;;;ACjUA,MAAa,YAAY;CACvB,QAAQ;CACR,aAAa;CACb,aAAa;CACb,MAAM;CACN,SAAS;CACT,OAAO;CACP,QAAQ;CACR,aAAa;CACb,UAAU;CACV,QAAQ;CACR,SAAS;CACT,QAAQ;;CAER,YAAY;;CAEZ,cAAc;CACd,SAAS;CACT,YAAY;CACZ,YAAY;CACZ,SAAS;;CAET,cAAc;;CAEd,aAAa;CACb,WAAW;CACX,kBAAkB;;CAElB,gBAAgB;CAChB,WAAW;;CAEX,OAAO;;CAEP,OAAO;;CAEP,mBAAmB;;CAEnB,eAAe;;CAEf,YAAY;;CAEZ,OAAO;;CAEP,QAAQ;;CAER,OAAO;;CAEP,OAAO;;CAEP,WAAW;;CAEX,OAAO;CACP,QAAQ;CACR,aAAa;;CAEb,gBAAgB;;CAEhB,cAAc;;CAEd,gBAAgB;;CAEhB,gBAAgB;;CAEhB,gBAAgB;;CAEhB,WAAW;;;;;CAKX,UAAU;;CAEV,YAAY;;CAEZ,WAAW;CACX,QAAQ;CACR,YAAY;AACd;;;;;;;;;AC3EA,SAAS,eAAe,MAAsB;CAC5C,OAAO,KACJ,QAAQ,SAAS,GAAG,CAAC,CACrB,QAAQ,SAAS,GAAG,CAAC,CACrB,QAAQ,WAAW,IAAG,CAAC,CACvB,QAAQ,WAAW,GAAG,CAAC,CACvB,QAAQ,UAAU,GAAG,CAAC,CACtB,QAAQ,WAAW,GAAG;AAC3B;;;;;;;;AASA,SAAgB,gBAAgB,QAA4B;CAC1D,IAAI;CACJ,IAAI;EACF,QAAQ,UAAU,MAAM;CAC1B,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,uCAAwC,MAAgB,SAAS;CACnF;CACA,MAAM,WAAW,MAAM;CACvB,IAAI,aAAa,KAAA,GACf,MAAM,IAAI,MAAM,8CAA8C;CAEhE,MAAM,MAAM,UAAU,QAAQ;CAE9B,MAAM,aAAuB,CAAC;CAE9B,MAAM,QAAQ,IAAI,MAAM,cAAc;CACtC,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,UAAU,MAAM;EAEtB,MAAM,OAAiB,CAAC;EAExB,KAAK,MAAM,SAAS,QAAQ,SAAS,sEAAK,GACxC,IAAI,MAAM,EAAE,CAAC,WAAW,QAAQ,GAC9B,KAAK,KAAK,GAAI;OACT,IAAI,MAAM,EAAE,CAAC,WAAW,OAAO,GACpC,KAAK,KAAK,IAAI;OAEd,KAAK,KAAK,eAAe,MAAM,MAAM,EAAE,CAAC;EAG5C,MAAM,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC,QAAQ,WAAW,GAAG,CAAC,CAAC,QAAQ;EAC3D,WAAW,KAAK,IAAI;CACtB;CAGA,MAAM,OAAO,WAAW,KAAK,IAAI,CAAC,CAAC,QAAQ,WAAW,MAAM,CAAC,CAAC,KAAK;CACnE,IAAI,KAAK,WAAW,GAClB,MAAM,IAAI,MAAM,mCAAmC;CAErD,OAAO;AACT;;;;;;AAOA,SAAgB,oBAAoB,MAAsB;CACxD,IAAI;CACJ,IAAI;EACF,SAAS,aAAa,IAAI;CAC5B,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,6BAA6B,KAAK,KAAM,MAAgB,SAAS;CACnF;CACA,OAAO,gBAAgB,IAAI,WAAW,MAAM,CAAC;AAC/C;;;;;;;;;;;;;;;;;;AC/CA,MAAa,yBAAyB;;AAGtC,MAAM,kBAAkB;;AAQxB,SAAgB,qBAAqB,WAAuC;CAC1E,MAAM,OAAO,KAAK,WAAW,sBAAsB;CACnD,IAAI,CAAC,WAAW,IAAI,GAAG,OAAO,CAAC;CAC/B,MAAM,WAA+B,CAAC;CACtC,IAAI;EACF,KAAK,MAAM,QAAQ,aAAa,MAAM,MAAM,CAAC,CAAC,MAAM,IAAI,GAAG;GACzD,IAAI,KAAK,KAAK,MAAM,IAAI;GACxB,IAAI;IACF,MAAM,SAAS,KAAK,MAAM,IAAI;IAC9B,IAAI,OAAO,OAAO,SAAS,YAAY,OAAO,OAAO,YAAY,UAAU,SAAS,KAAK,MAAM;GACjG,QAAQ,CAA4B;EACtC;CACF,QAAQ,CAA0C;CAClD,OAAO;AACT;;;;AAKA,SAAS,cAAc,WAAmB,SAAiC;CACzE,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;CACxC,MAAM,QAA0B,QAAQ,SAAS,UAAU,QAAQ,QAAQ,SAAS,MAChF;EAAE,GAAG;EAAS,SAAS,QAAQ,QAAQ,MAAM,GAAG,GAAI,IAAI;CAAyB,IACjF;CACJ,eAAe,KAAK,WAAW,sBAAsB,GAAG,KAAK,UAAU,KAAK,IAAI,MAAM,MAAM;AAC9F;;AAGA,SAAgB,sBAAsB,WAAyB;CAC7D,MAAM,OAAO,KAAK,WAAW,sBAAsB;CACnD,IAAI,WAAW,IAAI,GAAG,OAAO,MAAM,EAAE,OAAO,KAAK,CAAC;AACpD;;AAKA,SAAS,sBAAsB,SAA+B;CAC5D,MAAM,WAAqB,CAAC;CAC5B,SAAS,KAAK,MAAM,QAAQ,UAAU;CACtC,SAAS,KAAK,iCAAiC,QAAQ,QAAQ,MAAM,GAAG,IAAI,GAAG;CAE/E,MAAM,aAAuB,CAAC;CAC9B,IAAI,QAAQ,QAAQ,UAAU,KAAA,GAAW,WAAW,KAAK,MAAM,QAAQ,OAAO,MAAM,MAAM;CAC1F,IAAI,QAAQ,QAAQ,uBAAuB,KAAA,GAAW,WAAW,KAAK,OAAO,QAAQ,OAAO,mBAAmB,MAAM;CACrH,KAAK,QAAQ,QAAQ,aAAa,UAAU,KAAK,GAAG,WAAW,KAAK,MAAM,QAAQ,OAAQ,YAAa,KAAI,MAAK,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,GAAG;CACnI,KAAK,QAAQ,QAAQ,aAAa,UAAU,KAAK,GAAG,WAAW,KAAK,SAAS,QAAQ,OAAQ,YAAa,KAAI,MAAK,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,GAAG;CACtI,IAAI,WAAW,SAAS,GAAG,SAAS,KAAK,SAAS,WAAW,KAAK,KAAK,GAAG;CAC1E,IAAI,QAAQ,UAAU,KAAA,GAAW;EAC/B,MAAM,QAAQ,QAAQ;EACtB,SAAS,KAAK,MAAM;EACpB,IAAI,MAAM,UAAU,IAAI,SAAS,KAAK,QAAQ,MAAM,OAAO;EAC3D,IAAI,MAAM,WAAW,SAAS,GAAG,SAAS,KAAK,YAAY,MAAM,WAAW,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;EACzG,IAAI,MAAM,WAAW,SAAS,GAAG;GAC/B,SAAS,KAAK,MAAM;GACpB,KAAK,MAAM,QAAQ,MAAM,YAAY;IACnC,MAAM,WAAW;KAAE,aAAa;KAAM,YAAY;KAAM,YAAY;KAAM,OAAO;IAAK,EAAE,KAAK;IAC7F,SAAS,KAAK,KAAK,KAAK,KAAK,GAAG,SAAS,IAAI,KAAK,OAAO,KAAK,GAAG,IAAI,KAAK,UAAU,KAAK,OAAO,KAAK,UAAU,IAAI;GACrH;EACF;EACA,IAAI,MAAM,SAAS,SAAS,GAAG,SAAS,KAAK,YAAY,MAAM,SAAS,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;CACvG;CACA,IAAI,QAAQ,UAAU,KAAA,GAAW;EAC/B,MAAM,QAAQ,QAAQ;EACtB,SAAS,KAAK,OAAO;EACrB,IAAI,MAAM,OAAO,SAAS,GAAG,SAAS,KAAK,UAAU,MAAM,OAAO,KAAK,GAAG,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,YAAY,MAAM,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC;EAChJ,IAAI,MAAM,QAAQ,SAAS,GAAG,SAAS,KAAK,QAAQ,MAAM,QAAQ,KAAI,MAAK,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC;EAC5F,IAAI,MAAM,SAAS,SAAS,GAAG,SAAS,KAAK,QAAQ,MAAM,SAAS,KAAI,MAAK,GAAG,EAAE,KAAK,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC;CAChH;CACA,IAAI,QAAQ,YAAY,KAAA,KAAa,QAAQ,QAAQ,SAAS,GAAG;EAC/D,SAAS,KAAK,OAAO;EACrB,KAAK,MAAM,KAAK,QAAQ,SACtB,SAAS,KAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,IAAI,EAAE,QAAQ,MAAM,EAAE,aAAa,GAAG,EAAE,WAAW,EAAE;CAE5F;CACA,IAAI,QAAQ,SAAS,SAAS,GAAG;EAG/B,MAAM,QAAQ,QAAQ,SAAS,MAAM,GAAG;EACxC,SAAS,KAAK,eAAe,MAAM,OAAO,KAAK;EAC/C,KAAK,MAAM,KAAK,OAAO;GACrB,MAAM,aAAa;IAAE,SAAS;IAAO,YAAY;IAAO,SAAS;IAAO,WAAW;IAAO,UAAU;IAAO,UAAU;IAAO,OAAO;GAAK,EAAE,EAAE;GAC5I,SAAS,KAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,IAAI,WAAW,GAAG,EAAE,UAAU,KAAA,IAAY,IAAI,EAAE,MAAM,KAAK,KAAK,EAAE,YAAY,KAAA,KAAa,EAAE,YAAY,KAAK,OAAO,EAAE,YAAY,IAAI;EAC5K;EACA,IAAI,QAAQ,SAAS,SAAS,MAAM,QAClC,SAAS,KAAK,OAAO,QAAQ,SAAS,SAAS,MAAM,OAAO,0CAA0C;EAIxG,MAAM,SADU,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,cAAc,EAAE,WAAW,SAChE,CAAC,CAAC,MAAM,EAAE;EAC/B,IAAI,OAAO,SAAS,GAAG;GACrB,SAAS,KAAK,YAAY;GAC1B,KAAK,MAAM,KAAK,QACd,SAAS,KAAK,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,2BAA2B,EAAE,MAAM,MAAM,GAAG,GAAG,GAAG;EAEzF;CACF;CACA,IAAI,QAAQ,YAAY,SAAS,GAAG;EAClC,SAAS,KAAK,MAAM;EACpB,KAAK,MAAM,KAAK,QAAQ,aACtB,SAAS,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE,cAAc,EAAE,kBAAkB,KAAA,IAAY,OAAO,EAAE,cAAc,SAAS,IAAI;CAEzH;CACA,KAAK,QAAQ,SAAS,CAAC,EAAA,CAAG,SAAS,GAAG;EACpC,SAAS,KAAK,8BAA8B;EAC5C,KAAK,MAAM,MAAM,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAM,GAAG,GAC7C,SAAS,KAAK,OAAO,EAAE,UAAU,KAAK,EAAE,MAAM;CAElD;CACA,IAAI,QAAQ,UAAU,KAAA,KAAa,QAAQ,UAAU,IACnD,SAAS,KAAK,QAAQ,QAAQ,OAAO;CAEvC,OAAO,SAAS,KAAK,IAAI;AAC3B;;AAGA,SAAS,sBAAsB,SAA+B;CAC5D,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA,sBAAsB,OAAO;EAC7B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;;;;;;AAUA,gBAAuB,cACrB,KACA,QACA,SACA,WACA,MACA,MACyC;CACzC,MAAM,OAAO,UAA2B,OAAO,UAAU,WAAW,QAAQ;CAC5E,MAAM,OAAO,UAAuC,OAAO,UAAU,WAAW,QAAQ,KAAA;;CAGxF,MAAM,UAAU,iBAAiB,QAA2O;EAC1Q,WAAW,MAAM,QAAQ,QACvB,IAAI,KAAK,UAAU,SAAS,MAAM,KAAK;CAE3C;CAEA,QAAQ,MAAR;EACE,KAAK,iBAAiB;GAEpB,MAAM,WAAW,IAAI,KAAK,KAAK;GAM/B,OAAO,aAAa,SALN,aAAa,SACvB,SACA,iBAAiB,KAAK,QAAQ,IAC5B,OAAO,SAAS,MAAM,CAAC,CAAC,IACxB,QAC4B;EACpC;EACA,KAAK,eAAe;GAElB,MAAM,UAAU,IAAI,KAAK,OAAO,CAAC,CAAC,KAAK;GACvC,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,wBAAwB;GAC5D,MAAM,QAAQ,QAAQ,SAAS,CAAC,EAAA,CAAG,QAAO,MAAK,EAAE,KAAK,SAAS,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG;GAClF,IAAI,KAAK,WAAW,GAAG,OAAO,YAAY,QAAQ;GAClD,OAAO,SAAS,QAAQ,SAAS,KAAK,OAAO,UAAU,KAAK,KAAI,MAAK,OAAO,EAAE,UAAU,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,IAAI;EAClH;EACA,KAAK,mBAAmB;GACtB,MAAM,SAAS,IAAI,KAAK,MAAM;GAC9B,IAAI,WAAW,IAAI,MAAM,IAAI,MAAM,oCAAoC;GACvE,MAAM,QAAQ,MAAM,cAAc,KAAK,QAAQ,SAAS,WAAW,MAAM;GACzE,IAAI,MAAM,WAAW,GAAG,OAAO;GAC/B,MAAM,QAAQ,MAAM,KAAK,IAAI,MAAM,GAAG,IAAI,EAAE,KAAK,GAAG,SAAS,IAAI,GAAG,MAAM,GAAG,GAAG,eAAe,KAAK,MAAM,GAAG,eAAe,GAAG,GAAG,GAAG,SAAS,SAAS,SAAS,GAAG,SAAS,aAAa,OAAO,KAAK,EAAE;GACvM,OAAO,eAAe,MAAM,OAAO,QAAQ,MAAM,KAAK,IAAI,EAAE;EAC9D;EACA,KAAK,gBACH,OAAO,QAAQ;EAEjB,KAAK,mBAAmB;GACtB,MAAM,MAAM,IAAI,KAAK,GAAG;GACxB,MAAM,OAAO,IAAI,KAAK,GAAG;GACzB,IAAI,QAAQ,MAAM,CAAC,QAAQ,QAAQ,SAAS,GAAG,GAC7C,MAAM,IAAI,MAAM,YAAY,IAAI,MAAM,GAAG,EAAE,EAAE,GAAG;GAElD,QAAQ,UAAU,QAAQ,QAAQ,QAAQ,KAAK,IAAI;GACnD,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,WAAW,OAAO;GAC9B,OAAO,aAAa,IAAI,OAAO;EACjC;EACA,KAAK,kBAAkB;GACrB,IAAI,QAAQ,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,WAAW;GAC5D,MAAM,QAAQ,IAAI,KAAK,KAAK;GAC5B,IAAI,UAAU,KAAA,GACZ,QAAQ,MAAM,WAAW,SAAS,IAAI,KAAK,IAAI;QAC1C,IAAI,IAAI,KAAK,MAAM,MAAM,IAC9B,QAAQ,MAAM,WAAW,KAAK,IAAI,KAAK,MAAM,CAAC;QAE9C,MAAM,IAAI,MAAM,uCAAuC;GAEzD,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,WAAW,OAAO;GAC9B,OAAO,cAAc,QAAQ,MAAM,WAAW,OAAO;EACvD;EACA,KAAK,qBAAqB;GACxB,IAAI,QAAQ,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,WAAW;GAC5D,MAAM,QAAQ,IAAI,KAAK,KAAK;GAC5B,IAAI,UAAU,KAAA,GACZ,QAAQ,MAAM,SAAS,SAAS,IAAI,KAAK,IAAI;QACxC,IAAI,IAAI,KAAK,MAAM,MAAM,IAC9B,QAAQ,MAAM,SAAS,KAAK,IAAI,KAAK,MAAM,CAAC;QAE5C,MAAM,IAAI,MAAM,0CAA0C;GAE5D,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,WAAW,OAAO;GAC9B,OAAO,cAAc,QAAQ,MAAM,SAAS,OAAO;EACrD;EACA,KAAK,gBAAgB;GACnB,MAAM,KAAK,IAAI,KAAK,EAAE;GACtB,IAAI,OAAO,KAAA,GAAW,MAAM,IAAI,MAAM,oBAAoB;GAC1D,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,EAAE;GACtD,IAAI,YAAY,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,GAAG,KAAK;GACzD,MAAM,OAAO,gBAAgB,WAAW,OAAO;GAC/C,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,GAAG,MAAM;GACvD,OAAO;EACT;EACA,KAAK,mBAAmB;GACtB,MAAM,KAAK,IAAI,KAAK,EAAE;GACtB,IAAI,OAAO,KAAA,GAAW,MAAM,IAAI,MAAM,uBAAuB;GAC7D,MAAM,eAAe,IAAI,KAAK,YAAY;GAC1C,MAAM,SAAS,IAAI,KAAK,MAAM;GAC9B,WAAW,MAAM,SAAS,QAAQ,qBAAqB,KAAK,QAAQ,SAAS,WAAW,IAAI,cAAc,WAAW,KAAK,KAAA,IAAY,MAAM,CAAC,GAC3I,MAAM;GAIR,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,EAAE;GACtD,MAAM,QAAQ,SAAS;GACvB,IAAI,YAAY,KAAA,KAAa,UAAU,KAAA,KAAa,UAAU,IAC5D,MAAM,IAAI,MAAM,MAAM,GAAG,WAAW;GAEtC,MAAM,WAAW,gBAAgB,OAAO;GACxC,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;GACxC,cAAc,KAAK,WAAW,QAAQ,GAAG,MAAM,QAAQ,GAAG,IAAI,QAAQ,MAAM,MAAM,MAAM,KAAK,MAAM;GACnG,QAAQ,eAAe,KAAA;GACvB,QAAQ,SAAS;GACjB,QAAQ,QAAQ,MAAM;GACtB,QAAQ,OAAO;GACf,QAAQ,SAAS,KAAA;GACjB,QAAQ,QAAQ,KAAA;GAChB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,WAAW,OAAO;GAC9B,MAAM;GACN,IAAI;IACF,MAAM,yBAAyB,KAAK,QAAQ,SAAS,WAAW,EAAE;GACpE,QAAQ,CAAoB;GAC5B,MAAM;GACN,MAAM,SAAS,MAAM,cAAc,KAAK,QAAQ,SAAS,WAAW,EAAE;GACtE,OAAO,MAAM,GAAG,IAAI,WAAW,KAAK,OAAO,KAAK,OAAO,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,IAAI,WAAW,OAAO,MAAM,OAAO,OAAO;EACrJ;EACA,KAAK,oBAAoB;GACvB,MAAM,KAAK,IAAI,KAAK,EAAE;GACtB,IAAI,OAAO,KAAA,GAAW,MAAM,IAAI,MAAM,wBAAwB;GAC9D,WAAW,MAAM,SAAS,QAAQ,sBAAsB,KAAK,QAAQ,SAAS,WAAW,EAAE,CAAC,GAC1F,MAAM;GAER,MAAM;GACN,IAAI;IACF,MAAM,yBAAyB,KAAK,QAAQ,SAAS,WAAW,EAAE;GACpE,QAAQ,CAAoB;GAC5B,MAAM;GACN,MAAM,SAAS,MAAM,cAAc,KAAK,QAAQ,SAAS,WAAW,EAAE;GACtE,OAAO,MAAM,GAAG,OAAO,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,IAAI,SAAS,OAAO,MAAM,OAAO,OAAO;EACnH;EACA,KAAK,kBAAkB;GACrB,MAAM,KAAK,IAAI,KAAK,EAAE;GACtB,IAAI,OAAO,KAAA,GAAW,MAAM,IAAI,MAAM,sBAAsB;GAC5D,MAAM,SAAS,MAAM,cAAc,KAAK,QAAQ,SAAS,WAAW,EAAE;GACtE,MAAM,SAAS,OAAO,OAAO,KAAI,MAAK,IAAI,EAAE,SAAS,IAAI,EAAE,KAAK,KAAK,EAAE,YAAY,CAAC,CAAC,KAAK,IAAI;GAC9F,OAAO,MAAM,GAAG,MAAM,OAAO,MAAM,OAAO,OAAO,QAAQ,IAAI;EAC/D;EACA,KAAK,kBAAkB;GACrB,MAAM,cAAc,IAAI,KAAK,WAAW;GACxC,IAAI,gBAAgB,IAAI,MAAM,IAAI,MAAM,+BAA+B;GACvE,MAAM,gBAAgB,IAAI,KAAK,aAAa;GAC5C,QAAQ,YAAY,KAAK;IACvB,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE;IAChC;IACA;IACA,QAAQ;GACV,CAAC;GACD,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,WAAW,OAAO;GAC9B,OAAO,UAAU,YAAY,MAAM,GAAG,EAAE,EAAE;EAC5C;EACA,KAAK,qBAAqB;GACxB,MAAM,KAAK,IAAI,KAAK,EAAE;GACtB,MAAM,SAAS,IAAI,KAAK,MAAM;GAC9B,MAAM,SAAS,QAAQ,YAAY,MAAK,MAAK,EAAE,OAAO,EAAE;GACxD,IAAI,WAAW,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,GAAG,KAAK;GACxD,IAAI,CAAC;IAAC;IAAW;IAAW;IAAe;IAAY;GAAW,CAAC,CAAC,SAAS,MAAM,GACjF,MAAM,IAAI,MAAM,QAAQ,QAAQ;GAElC,OAAO,SAAS;GAChB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,WAAW,OAAO;GAC9B,OAAO,UAAU,OAAO,IAAI,OAAO,YAAY,MAAM,GAAG,EAAE,EAAE;EAC9D;EACA,KAAK,cAAc;GACjB,MAAM,SAAS,WAAW,WAAW,SAAS,KAAK;GACnD,OAAO,WAAW,OAAO,KAAK,GAAG,OAAO,MAAM,KAAK,OAAO,SAAS;EACrE;EACA,KAAK,iBAAiB;GACpB,MAAM,SAAS,QAAQ;GACvB,IAAI,WAAW,KAAA,GAAW,OAAO;GACjC,MAAM,QAAkB,CAAC;GACzB,IAAI,OAAO,UAAU,KAAA,GAAW,MAAM,KAAK,MAAM,OAAO,MAAM,MAAM;GACpE,IAAI,OAAO,uBAAuB,KAAA,GAAW,MAAM,KAAK,OAAO,OAAO,mBAAmB,MAAM;GAC/F,IAAI,OAAO,sBAAsB,SAAS,GAAG,MAAM,KAAK,QAAQ,OAAO,sBAAsB,KAAI,MAAK,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,GAAG;GACzH,IAAI,OAAO,YAAY,SAAS,GAAG,MAAM,KAAK,YAAY,OAAO,YAAY,KAAI,MAAK,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,GAAG;GACzG,IAAI,OAAO,YAAY,SAAS,GAAG,MAAM,KAAK,QAAQ,OAAO,YAAY,KAAI,MAAK,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,GAAG;GACrG,OAAO,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI;EAC/C;EACA,KAAK,oBAAoB;GACvB,MAAM,OAAO,IAAI,KAAK,IAAI;GAC1B,MAAM,cAAc,IAAI,KAAK,WAAW;GACxC,IAAI,SAAS,IAAI,MAAM,IAAI,MAAM,0BAA0B;GAC3D,IAAI,QAAQ,WAAW,KAAA,GAAW,QAAQ,SAAS,mBAAmB;GACtE,QAAQ,OAAO,QAAQ;IAAE;IAAM;IAAa,UAAU,CAAC;GAAE;GACzD,QAAQ,OAAO,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAClD,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,WAAW,OAAO;GAC9B,OAAO,SAAS,KAAK;EACvB;EACA,KAAK,0BAA0B;GAC7B,MAAM,OAAO,IAAI,KAAK,IAAI;GAC1B,MAAM,SAAS,IAAI,KAAK,MAAM;GAC9B,MAAM,UAAU,KAAK,YAAY;GACjC,IAAI,SAAS,IAAI,MAAM,IAAI,MAAM,gCAAgC;GACjE,IAAI,QAAQ,WAAW,KAAA,GAAW,QAAQ,SAAS,mBAAmB;GACtE,MAAM,OAAO;IACX;IACA,QAAQ,WAAW,KAAK,SAAS;IACjC,mBAAmB,IAAI,KAAK,iBAAiB;IAC7C,SAAS,MAAM,QAAQ,KAAK,OAAO,IAAI,KAAK,QAAQ,QAAQ,MAAmB,OAAO,MAAM,QAAQ,IAAI,CAAC;IACzG,OAAO,MAAM,QAAQ,KAAK,KAAK,IAAI,KAAK,MAAM,QAAQ,MAAmB,OAAO,MAAM,QAAQ,IAAI,CAAC;IACnG;GACF;GACA,IAAI,SAAS,QAAQ,OAAO,qBAAqB;QAC5C;IACH,IAAI,QAAQ,OAAO,0BAA0B,KAAA,GAAW,QAAQ,OAAO,wBAAwB,CAAC;IAChG,QAAQ,OAAO,sBAAsB,KAAK,IAAI;GAChD;GACA,QAAQ,OAAO,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAClD,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,WAAW,OAAO;GAC9B,OAAO,OAAO,UAAU,QAAQ,OAAO,OAAO,KAAK;EACrD;EACA,KAAK,mBAAmB;GACtB,MAAM,OAAO,IAAI,KAAK,IAAI;GAC1B,MAAM,QAAQ,IAAI,KAAK,KAAK;GAC5B,IAAI,UAAU,IAAI,MAAM,IAAI,MAAM,oCAAoC;GACtE,IAAI,QAAQ,WAAW,KAAA,GAAW,QAAQ,SAAS,mBAAmB;GACtE,IAAI,QAAQ,OAAO,gBAAgB,KAAA,GAAW,QAAQ,OAAO,cAAc,CAAC;GAC5E,QAAQ,OAAO,YAAY,KAAK;IAC9B,MAAM,SAAS,KAAK,OAAO,SAAS,QAAQ,OAAO,YAAY,SAAS;IACxE;IACA,KAAK,IAAI,KAAK,GAAG;GACnB,CAAC;GACD,QAAQ,OAAO,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAClD,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,WAAW,OAAO;GAC9B,OAAO,cAAc,SAAS,KAAK,OAAO,MAAM,MAAM,GAAG,EAAE,EAAE;EAC/D;EACA,SACE,MAAM,IAAI,MAAM,QAAQ,MAAM;CAClC;AACF;;AAKA,SAAS,cAAc,OAA2F;CAEhH,MAAM,QAAQ,mEAAmE,KAAK,KAAK;CAC3F,IAAI,UAAU,MAAM,OAAO,KAAA;CAC3B,MAAM,UAAU,MAAM,EAAE,EAAE,KAAK,KAAK;CACpC,IAAI;CACJ,IAAI;EACF,OAAO,YAAY,KAAK,CAAC,IAAI,KAAK,MAAM,OAAO;CACjD,QAAQ;EACN,MAAM,IAAI,MAAM,iBAAiB,QAAQ,MAAM,GAAG,EAAE,GAAG;CACzD;CACA,OAAO;EAAE,MAAM,MAAM,MAAM;EAAI;EAAM,OAAO,MAAM;CAAM;AAC1D;;AAGA,SAAS,kBAAkB,SAAwC;CACjE,MAAM,SAAS,QAAQ,MAAM,GAAqB;CAClD,MAAM,WAAsB,CAAC;CAC7B,KAAK,MAAM,SAAS,QAClB,IAAI,MAAM,SAAS,QACjB,SAAS,KAAK,kBAAkB;EAC9B,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM,MAAM;EAAQ,CAAC;EAC/C,QAAQ;GAAE,MAAM;GAAU,QAAQ;EAAkB;CACtD,CAAC,CAAC;MACG,IAAI,MAAM,SAAS,aACxB,SAAS,KAAK,uBAAuB;EACnC,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM,MAAM;EAAQ,CAAC;EAC/C,QAAQ;GAAE,UAAU;GAAqB,OAAO;EAAoB;CACtE,CAAC,CAAC;MACG,IAAI,MAAM,SAAS,QAAQ;EAGhC,MAAM,OAAO,MAAM,QAAQ,SAAS,MAChC,MAAM,QAAQ,MAAM,GAAG,GAAI,IAAI,+BAC/B,MAAM;EACV,SAAS,KAAK,kBAAkB;GAC9B,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM,OAAO,MAAM,QAAQ,GAAG,WAAW;GAAO,CAAC;GAC3E,QAAQ;IAAE,MAAM;IAAU,QAAQ;GAAkB;EACtD,CAAC,CAAC;CACJ;CAEF,OAAO;AACT;;AAGA,eAAe,SACb,KACA,QACA,QACA,SACiB;CACjB,MAAM,WAAW,kBAAkB,OAAO;CAI1C,MAAM,OAAO,SAAS,SAAS,SAAS;CACxC,IAAI,MAAM,SAAS,UAAU,MAAM,QAAQ,KAAK,OAAO,GAAG;EACxD,MAAM,SAAS,KAAK;EACpB,MAAM,MAAM,OAAO,WAAU,MAAK,EAAE,SAAS,MAAM;EACnD,IAAI,QAAQ,IAAI;GACd,MAAM,YAAY,OAAO;GACzB,MAAM,YAA4B,OAAO,KAAK,GAAG,MAAM,MAAM,MACzD;IAAE,GAAG;IAAW,MAAM,UAAU,OAAO;GAAoI,IAC3K,CAAC;GACL,SAAS,SAAS,SAAS,KAAK;IAAE,GAAG;IAAM,SAAS;GAAU;EAChE;CACF;CACA,MAAM,UAA2B;EAC/B,UAAU,OAAO;EACjB,OAAO,OAAO;EACd;EACA;EAEA,WAAW,KAAK,IAAI,OAAO,WAAW,IAAK;EAC3C,aAAa;CACf;CACA,MAAM,YAAY,IAAI,eAAe;CACrC,WAAW,MAAM,SAAS,IAAI,IAAI,OAAO,OAAO,GAC9C,UAAU,KAAK,KAAK;CAEtB,MAAM,SAAS,UAAU;CACzB,IAAI,OAAO,SAAS,WAAW,OAAO,SAAS,WAC7C,MAAM,IAAI,MAAM,UAAU,OAAO,KAAK,KAAK,OAAO,QAAQ,SAAS;CAErE,MAAM,SAAS,UAAU,OAAO;CAIhC,IAAI,OAHe,OAChB,QAAQ,UAA4F,MAAM,SAAS,MAAM,CAAC,CAC1H,KAAI,UAAS,MAAM,IACF,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK;CACtC,IAAI,SAAS,IAAI;EACf,MAAM,YAAY,OACf,QAAQ,UAAwD,MAAM,SAAS,WAAW,CAAC,CAC3F,KAAI,UAAS,MAAM,IAAI,CAAC,CACxB,KAAK,IAAI,CAAC,CACV,KAAK;EACR,IAAI,cAAc,IAAI,OAAO;CAC/B;CACA,OAAO;AACT;;AAGA,gBAAuB,iBACrB,KACA,QACA,SACA,WACA,aAOA;CACA,MAAM,UAAU,qBAAqB,SAAS;CAC9C,MAAM,SAAS,sBAAsB,OAAO;CAG5C,MAAM,YAA8B;EAAE,MAAM;EAAQ,SAAS;EAAa,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;CAAE;CACvG,QAAQ,KAAK,SAAS;CACtB,cAAc,WAAW,SAAS;CAElC,IAAI,QAAQ;;CAEZ,IAAI,SAAS;CACb,MAAM,aAAa;;CAEnB,IAAI,cAAc;CAMlB,MAAM,kBAA0C;EAC9C,kBAAkB;EAClB,iBAAiB;EACjB,gBAAgB;EAChB,iBAAiB;EACjB,gBAAgB;EAChB,mBAAmB;EACnB,gBAAgB;EAChB,mBAAmB;EACnB,YAAY;EACZ,kBAAkB;EAClB,wBAAwB;EACxB,iBAAiB;CACnB;;CAEA,IAAI,gBAAgB;CACpB,MAAM,cAAc,MAAc,gBAAiC;EACjE,IAAI,eAAe,OAAO;EAC1B,MAAM,MAAM,gBAAgB;EAC5B,IAAI,QAAQ,KAAA,GAAW,OAAO;EAE9B,MAAM,cAAc,QACjB,QAAO,MAAK,EAAE,SAAS,MAAM,CAAC,CAC9B,MAAM,EAAE,CAAC,CACT,KAAI,MAAK,EAAE,OAAO,CAAC,CACnB,KAAK,IAAI;EACZ,IAAI,IAAI,KAAK,WAAW,GAAG;GACzB,gBAAgB;GAChB,OAAO;EACT;EACA,OAAO;CACT;CACA,SAAS;EACP,IAAI,UAAU,IAAI;EAClB,MAAM,QAAQ,MAAM,SAAS,KAAK,QAAQ,QAAQ,OAAO;EAIzD,IADgB,MAAM,SAAS,OAAO,mBAAmB,KAAK,MAAM,MAAM,GAAG,GAAI,CAAC,GACrE;GACX;GACA,IAAI,eAAe,GAAG;IACpB,MAAM,cAAgC;KAAE,MAAM;KAAa,SAAS;KAAkC,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;IAAE;IACnI,QAAQ,KAAK,WAAW;IACxB,cAAc,WAAW,WAAW;IACpC,MAAM;KAAE,OAAO;KAAS,MAAM,YAAY;IAAQ;IAClD;GACF;GACA;EACF;EAEA,MAAM,SAAS,cAAc,KAAK;EAElC,IAAI,WAAW,KAAA,GAAW;GAIxB,MAAM,gBAAgB,mIAAmI,KAAK,KAAK;GAGnK,MAAM,iBAAiB,qEAAqE,KAAK,KAAK;GACtG,MAAM,WAAW,wBAAwB,KAAK,KAAK;GACnD,KAAK,iBAAiB,kBAAkB,aAAa,SAAS,YAAY;IAExE,MAAM,kBAAkB,OAAO,OAAO,eAAe,CAAC,CAAC,MAAK,OAAM,GAAG,KAAK,WAAW,CAAC;IACtF,MAAM,QAAQ,WAAW,IACpB,kBACG,iNACA,sLACH,kBACG,MAAM,SAAS,EAAE,gLACjB,MAAM,SAAS,EAAE;IACzB;IACA,QAAQ,KAAK;KAAE,MAAM;KAAQ,SAAS;KAAO,MAAM;KAAe,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;IAAE,CAAC;IAChG,cAAc,WAAW;KAAE,MAAM;KAAQ,SAAS;KAAO,MAAM;KAAe,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;IAAE,CAAC;IAC5G;GACF;GAEA,MAAM,iBAAmC;IAAE,MAAM;IAAa,SAAS;IAAO,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;GAAE;GAC3G,QAAQ,KAAK,cAAc;GAC3B,cAAc,WAAW,cAAc;GAEvC,MAAM;IAAE,OAAO;IAAS,MAAM;GAAM;GACpC;EACF;EAGA,MAAM,EAAE,MAAM,MAAM,UAAU;EAC9B,MAAM,QAAQ,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK;EAEzC,IAAI,CAAC,WAAW,MAAM,WAAW,GAAG;GAClC,MAAM,SAAS,UAAU,KAAK;GAC9B,QAAQ,KAAK;IAAE,MAAM;IAAQ,SAAS;IAAQ,MAAM;IAAM,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;GAAE,CAAC;GACxF,cAAc,WAAW;IAAE,MAAM;IAAQ,SAAS;IAAQ,MAAM;IAAM,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;GAAE,CAAC;GACpG,MAAM;IAAE,OAAO;IAAQ;IAAM,QAAQ;IAAS,QAAQ;GAAO;GAE7D,MAAM,iBAAmC;IAAE,MAAM;IAAa,SAAS;IAAQ,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;GAAE;GAC5G,QAAQ,KAAK,cAAc;GAC3B,cAAc,WAAW,cAAc;GACvC,MAAM;IAAE,OAAO;IAAS,MAAM;GAAO;GACrC;EACF;EACA,MAAM;GAAE,OAAO;GAAQ;GAAM,QAAQ;EAAQ;EAC7C,IAAI;EACJ,IAAI;GAIF,MAAM,WAAW,cAAc,KAAK,QAAQ,SAAS,WAAW,MAAM,IAAI,CAAC,CAAC,OAAO,cAAc,CAAC;GAClG,SAAS;GACT,SAAS;IACP,MAAM,OAAO,MAAM,SAAS,KAAK;IACjC,IAAI,KAAK,SAAS,MAAM;KACtB,SAAS,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;KACvD;IACF;IACA,MAAM,QAAQ,KAAK;IACnB,IAAI,OAAO,UAAU,YAAY,UAAU,IACzC,MAAM;KAAE,OAAO;KAAa;KAAM,MAAM;IAAM;GAElD;GACA,MAAM;IAAE,OAAO;IAAQ;IAAM,QAAQ;IAAQ,QAAQ,OAAO,MAAM,GAAG,GAAG;GAAE;EAC5E,SAAS,OAAO;GACd,SAAS,QAAS,MAAgB;GAClC,MAAM;IAAE,OAAO;IAAQ;IAAM,QAAQ;IAAS,QAAS,MAAgB;GAAQ;EACjF;EAGA,IAAI,UAAU,IAAI;GAChB,QAAQ,KAAK;IAAE,MAAM;IAAa,SAAS;IAAO,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;GAAE,CAAC;GAChF,cAAc,WAAW;IAAE,MAAM;IAAa,SAAS;IAAO,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;GAAE,CAAC;EAC9F;EACA,QAAQ,KAAK;GAAE,MAAM;GAAQ,SAAS;GAAQ,MAAM;GAAM,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;EAAE,CAAC;EACxF,cAAc,WAAW;GAAE,MAAM;GAAQ,SAAS;GAAQ,MAAM;GAAM,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;EAAE,CAAC;EAEpG;EACA,IAAI,SAAS,iBAAiB;GAC5B,MAAM,UAAU,UAAU,MAAM;GAChC,QAAQ,KAAK;IAAE,MAAM;IAAa,SAAS;IAAS,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;GAAE,CAAC;GAClF,cAAc,WAAW;IAAE,MAAM;IAAa,SAAS;IAAS,qBAAI,IAAI,KAAK,EAAA,CAAE,YAAY;GAAE,CAAC;GAC9F,MAAM;IAAE,OAAO;IAAS,MAAM;GAAQ;GACtC;EACF;CACF;AACF;;;;ACvnBA,MAAM,sBAAsB,KAAK,OAAO;;AAGxC,SAAS,kBAAkB,SAAmC;CAC5D,MAAM,UAAU,QAAQ,OAAO;CAC/B,IAAI,YAAY,eAAe,YAAY,SAAS,YAAY,oBAAoB,OAAO;CAC3F,MAAM,OAAO,QAAQ,QAAQ;CAC7B,IAAI,OAAO,SAAS,UAAU,OAAO;CACrC,IAAI;CACJ,IAAI;EACF,UAAU,IAAI,IAAI,UAAU,MAAM;CACpC,QAAQ;EACN,OAAO;CACT;CACA,IAAI,QAAQ,aAAa,eAAe,QAAQ,aAAa,eAAe,QAAQ,aAAa,SAAS,OAAO;CACjH,IAAI,QAAQ,QAAQ,sBAAsB,cAAc,OAAO;CAC/D,MAAM,SAAS,QAAQ,QAAQ;CAC/B,IAAI,WAAW,KAAA,GAAW,OAAO;CACjC,IAAI;EACF,OAAO,IAAI,IAAI,MAAM,CAAC,CAAC,SAAS,QAAQ;CAC1C,QAAQ;EACN,OAAO;CACT;AACF;;AAGA,SAAS,UAAU,KAAqB,QAAgB,MAAqB;CAC3E,MAAM,UAAU,KAAK,UAAU,IAAI;CACnC,IAAI,UAAU,QAAQ;EAAE,gBAAgB;EAAmC,mBAAmB;CAAc,CAAC;CAC7G,IAAI,IAAI,OAAO;AACjB;;AAGA,eAAe,aAAgB,KAA8C;CAC3E,MAAM,SAAmB,CAAC;CAC1B,IAAI,OAAO;CACX,WAAW,MAAM,SAAS,KAAK;EAC7B,MAAM,SAAS;EACf,QAAQ,OAAO;EACf,IAAI,OAAO,qBAAqB,OAAO,KAAA;EACvC,OAAO,KAAK,MAAM;CACpB;CACA,IAAI;EACF,OAAO,KAAK,MAAM,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC;CAC1D,QAAQ;EACN;CACF;AACF;;AAYA,MAAM,qBAAqB;;;;;;AAO3B,SAAgB,WAAW,MAAmC;CAC5D,MAAM,EAAE,KAAK,WAAW,gBAAgB;;CAGxC,IAAI,aAA0B;EAAE,QAAQ;EAAQ,cAAc;EAAG,kBAAkB;CAAE;;CAGrF,MAAM,SAAS,KAAsB,KAAqB,WAA4B;EACpF,IAAI,CAAC,kBAAkB,GAAG,GAAG;GAC3B,UAAU,KAAK,KAAK,EAAE,OAAO,2BAA2B,CAAC;GACzD,OAAO;EACT;EACA,IAAI,IAAI,WAAW,QAAQ;GACzB,UAAU,KAAK,KAAK,EAAE,OAAO,gCAAgC,OAAO,GAAG,CAAC;GACxE,OAAO;EACT;EACA,OAAO;CACT;;CAGA,MAAM,kBAAkB,QAAwD;EAC9E,MAAM,SAAS,UAAU;EACzB,MAAM,UAAU,YAAY,OAAO,SAAS;EAC5C,IAAI,YAAY,KAAA,GAAW;GACzB,UAAU,KAAK,KAAK,EAAE,OAAO,mBAAmB,CAAC;GACjD;EACF;EACA,oBAAoB,SAAS,OAAO,SAAS;EAC7C,YAAY,OAAO,WAAW,OAAO;EACrC,OAAO;CACT;CAGA,MAAM,cAAwB;EAC5B,MAAM;EACN,MAAM,UAAU;EAChB,UAAU,KAAK,QAAQ;GACrB,IAAI,CAAC,MAAM,KAAK,KAAK,KAAK,GAAG;GAC7B,MAAM,SAAS,UAAU;GAEzB,2BAA2B,OAAO,SAAS;GAC3C,MAAM,UAAU,YAAY,OAAO,SAAS;GAC5C,IAAI,YAAY,KAAA,GAAW;IAGzB,MAAM,UAAU,MAAU;IAC1B,KAAK,MAAM,KAAK,QAAQ,UACtB,IAAI,EAAE,WAAW,gBAAgB,EAAE,iBAAiB,KAAA,GAAW;KAC7D,MAAM,UAAU,IAAI,KAAK,EAAE,YAAY,CAAC,CAAC,QAAQ;KACjD,IAAI,OAAO,SAAS,OAAO,KAAK,KAAK,IAAI,IAAI,UAAU,SAAS;MAC9D,EAAE,SAAS;MACX,EAAE,QAAQ,KAAA;MACV,EAAE,eAAe,KAAA;KACnB;IACF;IAEF,oBAAoB,SAAS,OAAO,SAAS;IAC7C,YAAY,OAAO,WAAW,OAAO;GACvC;GAWA,UAAU,KAAK,KAAK;IATlB;IAGA,SAAS,YAAY,KAAA,IACjB;KAAE,GAAG;KAAS,QAAQ,QAAQ,SAAS,CAAC,EAAA,CAAG,MAAM,GAAG;IAAE,IACtD,KAAA;IACJ,gBAAgB,iBAAiB,OAAO,SAAS;IACjD,OAAO;GAEkB,CAAC;EAC9B;CACF;CAGA,MAAM,mBAA6B;EACjC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,OAAO,MAAM,aAAiC,GAAG;GACvD,MAAM,SAAS,UAAU;GACzB,IAAI;IACF,IAAI;IACJ,IAAI;IACJ,IAAI,MAAM,SAAS,KAAA,KAAa,KAAK,KAAK,KAAK,MAAM,IACnD,UAAU,KAAK,KAAK,KAAK;SACpB;KACL,MAAM,SAAS,MAAM,MAAM,KAAK,MAAM,MAAM,MAAM,SAAS,KAAA,IAAY,KAAK,OAAO,OAAO;KAC1F,UAAU,oBAAoB,MAAM;KACpC,OAAO;IACT;IACA,IAAI,QAAQ,SAAS,IAAI;KACvB,UAAU,KAAK,KAAK,EAAE,OAAO,gCAAgC,CAAC;KAC9D;IACF;IAOA,UAAU,KAAK,KAAK;KALlB;KACA,UAAU,cAAc,OAAO,CAAC,CAAC;KACjC,OAAO,QAAQ;KACf;IAEyB,CAAC;GAC9B,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;CAGA,MAAM,mBAA6B;EACjC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,OAAO,MAAM,aAAiC,GAAG;GACvD,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,MAAM,QAAQ;GAC9B,IAAI,QAAQ,KAAK,CAAC,CAAC,SAAS,IAAI;IAC9B,UAAU,KAAK,KAAK,EAAE,OAAO,iBAAiB,CAAC;IAC/C;GACF;GACA,IAAI,UAAU,YAAY,OAAO,SAAS;GAC1C,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;GACnC,IAAI,YAAY,KAAA,GACd,UAAU,cAAc,OAAO;QAC1B;IACL,QAAQ,UAAU;IAClB,QAAQ,WAAW,cAAc,OAAO,CAAC,CAAC;IAC1C,QAAQ,YAAY;GACtB;GACA,YAAY,OAAO,WAAW,OAAO;GACrC,UAAU,KAAK,KAAK;IAAE,IAAI;IAAM,UAAU,QAAQ;GAAS,CAAC;EAC9D;CACF;CAGA,MAAM,aAAuB;EAC3B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,OAAO,MAAM,aAA2B,GAAG;GACjD,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,YAAY,OAAO,SAAS;GAC5C,MAAM,UAAU,MAAM,SAAS,KAAK,MAAM,MAAM,MAAM,YAAY,KAAA,IAC9D,KAAK,UACL,SAAS;GACb,IAAI,YAAY,KAAA,KAAa,QAAQ,SAAS,IAAI;IAChD,UAAU,KAAK,KAAK,EAAE,OAAO,SAAS,CAAC;IACvC;GACF;GACA,IAAI;IACF,MAAM,QAAQ,MAAM,aAAa,KAAK,QAAQ,SAAS,OAAO;IAC9D,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;IACnC,MAAM,OAAO,WAAW,cAAc,OAAO;IAC7C,KAAK,QAAQ;IACb,KAAK,YAAY;IACjB,YAAY,OAAO,WAAW,IAAI;IAElC,UAAU,KAAK,KAAK,EADc,MACP,CAAC;GAC9B,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;CAGA,MAAM,eAAyB;EAC7B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,OAAO,MAAM,aAA6B,GAAG;GACnD,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,YAAY,OAAO,SAAS;GAC5C,MAAM,UAAU,MAAM,SAAS,KAAK,MAAM,MAAM,MAAM,YAAY,KAAA,IAC9D,KAAK,UACL,SAAS;GACb,IAAI,YAAY,KAAA,KAAa,QAAQ,SAAS,IAAI;IAChD,UAAU,KAAK,KAAK,EAAE,OAAO,SAAS,CAAC;IACvC;GACF;GACA,IAAI;IACF,MAAM,UAAU,MAAM,YAAY,KAAK,QAAQ,OAAO;IACtD,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;IACnC,MAAM,OAAO,WAAW,cAAc,OAAO;IAC7C,KAAK,UAAU;IACf,KAAK,YAAY;IACjB,YAAY,OAAO,WAAW,IAAI;IAElC,UAAU,KAAK,KAAK,EADgB,QACT,CAAC;GAC9B,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;CAGA,MAAM,YAAsB;EAC1B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,OAAO,MAAM,aAA0B,GAAG;GAChD,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,YAAY,OAAO,SAAS;GAC5C,MAAM,UAAU,MAAM,SAAS,KAAK,MAAM,MAAM,MAAM,YAAY,KAAA,IAC9D,KAAK,UACL,SAAS;GACb,IAAI,YAAY,KAAA,KAAa,QAAQ,SAAS,IAAI;IAChD,UAAU,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;IAChD;GACF;GACA,MAAM,QAAQ,MAAM,gBAAgB;GACpC,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,KAAK;IACxD,UAAU,KAAK,KAAK,EAAE,OAAO,4BAA4B,CAAC;IAC1D;GACF;GACA,IAAI;IACF,MAAM,OAAO,WAAW,cAAc,OAAO;IAC7C,MAAM,WAA0B,MAAM,aAAa,KAAK,QAAQ,MAAM,OAAO,MAAM,QAAQ,OAAO,SAAS;IAG3G,sBAAsB,OAAO,WAAW,IAAI;IAC5C,KAAK,SAAS,KAAK,GAAG,QAAQ;IAC9B,KAAK,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IACxC,YAAY,OAAO,WAAW,IAAI;IAElC,UAAU,KAAK,KAAK;KADa;KAAU,SAAS,KAAK;IAC9B,CAAC;GAC9B,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;CAGA,MAAM,gBAA0B;EAC9B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAA2D,GAAG;GACjF,MAAM,QAAQ,MAAM;GACpB,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAA,KAAa,QAAQ,GAAG;IAChE,UAAU,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;IAChD;GACF;GACA,MAAM,KAAa;GACnB,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,EAAE;GACtD,IAAI,YAAY,KAAA,GAAW;IACzB,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,GAAG,QAAQ,CAAC;IAC/C;GACF;GACA,IAAI,QAAQ,WAAW,cAAc;IACnC,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,GAAG,QAAQ,CAAC;IAC/C;GACF;GAGA,IAAI,UAAU,KAAK;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,qBAAqB;IACrB,mBAAmB;GACrB,CAAC;GACD,QAAQ,SAAS;GACjB,QAAQ,QAAQ,KAAA;GAChB,QAAQ,gCAAe,IAAI,KAAK,EAAA,CAAE,YAAY;GAE9C,sBAAsB,OAAO,WAAW,OAAO;GAC/C,YAAY,OAAO,WAAW,OAAO;GAErC,MAAM,QAAQ,UAA0B;IACtC,IAAI,MAAM,KAAK,UAAU,KAAK,IAAI,IAAI;GACxC;GAEA,IAAI;IACF,KAAK;KAAE,MAAM;KAAS;KAAI,OAAO,QAAQ;IAAM,CAAC;IAChD,WAAW,MAAM,QAAQ,sBAAsB,KAAK,QAAQ,SAAS,OAAO,WAAW,EAAE,GACvF,IAAI,KAAK,UAAU,SACjB,KAAK;KAAE,MAAM;KAAS,MAAM,KAAK;IAAK,CAAC;SAClC,IAAI,KAAK,UAAU,QACxB,KAAK;KAAE,MAAM;KAAQ;KAAI,MAAM,KAAK;KAAM,OAAO,KAAK;KAAO,OAAO,QAAQ;IAAM,CAAC;IAIvF,IAAI;KACF,MAAM,yBAAyB,KAAK,QAAQ,SAAS,OAAO,WAAW,EAAE;IAC3E,SAAS,OAAO;KACd,QAAQ,KAAK,2CAA4C,MAAgB,OAAO;IAClF;IAEA,IAAI;KACF,MAAM,SAAS,sBAAsB,SAAS,OAAO,WAAW,EAAE;KAClE,IAAI,SAAS,GACX,QAAQ,IAAI,sBAAsB,GAAG,QAAQ,OAAO,GAAG;IAE3D,SAAS,OAAO;KACd,QAAQ,KAAK,mDAAoD,MAAgB,OAAO;IAC1F;IACA,IAAI,EAAE,MAAM,eAAe,UAAU,OAAO,cAAc,OAExD,KAAK;KAAE,MAAM;KAAU;KAAI,QAAA,MADN,cAAc,KAAK,QAAQ,SAAS,OAAO,WAAW,EAAE;IAC3C,CAAC;SAC9B;KACL,QAAQ,SAAS;KACjB,sBAAsB,OAAO,WAAW,OAAO;KAC/C,YAAY,OAAO,WAAW,OAAO;IACvC;IAEA,IAAI,OAAO,oBAAoB,MAC7B,IAAI;KACF,MAAM,cAAc,gBAAgB,OAAO,WAAW,OAAO;KAC7D,IAAI,WAAW;KACf,IAAI,KAAK,GAAG;MACV,MAAM,OAAO,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,KAAK,CAAC;MACvD,IAAI,SAAS,KAAA,GACX,YAAY,gBAAgB,OAAO,WAAW,IAAI,KAAK,GAAA,CAAI,QAAQ,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI;KAEtG;KACA,IAAI,gBAAgB,KAAA,GAAW;MAC7B,MAAM,SAAS,MAAM,oBAAoB,KAAK,QAAQ,SAAS,IAAI,aAAa,QAAQ;MACxF,QAAQ,eAAe;MAEvB,IAAI,OAAO,kBAAkB,KAAA,GAC3B,kBAAkB,SAAS,IAAI,OAAO,aAAa;MAErD,sBAAsB,OAAO,WAAW,OAAO;MAC/C,YAAY,OAAO,WAAW,OAAO;MACrC,KAAK;OAAE,MAAM;OAAiB;OAAI;MAAO,CAAC;KAC5C;IACF,SAAS,OAAO;KACd,QAAQ,KAAK,2CAA4C,MAAgB,OAAO;IAClF;IAEF,IAAI,IAAI;GACV,SAAS,OAAO;IACd,QAAQ,SAAS;IACjB,QAAQ,QAAS,MAAgB;IACjC,sBAAsB,OAAO,WAAW,OAAO;IAC/C,YAAY,OAAO,WAAW,OAAO;IACrC,IAAI,CAAC,IAAI,eAAe;KACtB,KAAK;MAAE,MAAM;MAAS;MAAI,SAAU,MAAgB;KAAQ,CAAC;KAC7D,IAAI,IAAI;IACV;GACF;EACF;CACF;CAGA,MAAM,cAAwB;EAC5B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAA4B,GAAG;GAClD,IAAI,CAAC,OAAO,UAAU,MAAM,SAAS,GAAG;IACtC,UAAU,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;IAChD;GACF;GACA,MAAM,KAAK,KAAM;GACjB,IAAI;IAEF,UAAU,KAAK,KAAK,EAAE,QAAA,MADD,cAAc,KAAK,QAAQ,SAAS,OAAO,WAAW,EAAE,EAChD,CAAC;GAChC,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;CAGA,MAAM,eAAyB;EAC7B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAA6B,GAAG;GACnD,IAAI,CAAC,OAAO,UAAU,MAAM,SAAS,GAAG;IACtC,UAAU,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;IAChD;GACF;GACA,MAAM,KAAK,KAAM;GACjB,IAAI,UAAU,KAAK;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,qBAAqB;IACrB,mBAAmB;GACrB,CAAC;GACD,MAAM,QAAQ,UAA0B;IAAE,IAAI,MAAM,KAAK,UAAU,KAAK,IAAI,IAAI;GAAE;GAClF,IAAI;IACF,WAAW,MAAM,QAAQ,qBAAqB,KAAK,QAAQ,SAAS,OAAO,WAAW,IAAI,MAAM,gBAAgB,IAAI,MAAM,MAAM,GAC9H,IAAI,KAAK,UAAU,SAAS,KAAK;KAAE,MAAM;KAAS,MAAM,KAAK;IAAK,CAAC;SAC9D,IAAI,KAAK,UAAU,WAAW,KAAK;KAAE,MAAM;KAAW;KAAI,OAAO,KAAK;KAAO,OAAO,KAAK;IAAM,CAAC;IAIvG,IAAI,IAAI;GACV,SAAS,OAAO;IACd,IAAI,CAAC,IAAI,eAAe;KACtB,KAAK;MAAE,MAAM;MAAS;MAAI,SAAU,MAAgB;KAAQ,CAAC;KAC7D,IAAI,IAAI;IACV;GACF;EACF;CACF;CAGA,MAAM,cAAwB;EAC5B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAA4B,GAAG;GAClD,IAAI,CAAC,OAAO,UAAU,MAAM,SAAS,GAAG;IACtC,UAAU,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;IAChD;GACF;GACA,MAAM,KAAK,KAAM;GACjB,IAAI,UAAU,KAAK;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,qBAAqB;IACrB,mBAAmB;GACrB,CAAC;GACD,MAAM,QAAQ,UAA0B;IAAE,IAAI,MAAM,KAAK,UAAU,KAAK,IAAI,IAAI;GAAE;GAClF,IAAI;IACF,WAAW,MAAM,QAAQ,oBAAoB,KAAK,QAAQ,SAAS,OAAO,WAAW,EAAE,GACrF,IAAI,KAAK,UAAU,SAAS,KAAK;KAAE,MAAM;KAAS,MAAM,KAAK;IAAK,CAAC;SAC9D,IAAI,KAAK,UAAU,WAAW,KAAK;KAAE,MAAM;KAAW;KAAI,OAAO,KAAK;KAAO,OAAO,KAAK;IAAM,CAAC;IAEvG,IAAI,IAAI;GACV,SAAS,OAAO;IACd,IAAI,CAAC,IAAI,eAAe;KACtB,KAAK;MAAE,MAAM;MAAS;MAAI,SAAU,MAAgB;KAAQ,CAAC;KAC7D,IAAI,IAAI;IACV;GACF;EACF;CACF;;CAIA,MAAM,kBAA4B;EAChC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAAmC,GAAG;GACzD,IAAI,CAAC,OAAO,UAAU,MAAM,SAAS,GAAG;IACtC,UAAU,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;IAChD;GACF;GACA,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,KAAM,SAAU;GACpE,IAAI,YAAY,KAAA,GAAW;IACzB,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,KAAM,UAAU,QAAQ,CAAC;IAC5D;GACF;GACA,IAAI,QAAQ,iBAAiB,KAAA,KAAa,QAAQ,iBAAiB,IAAI;IACrE,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,QAAQ,GAAG,WAAW,CAAC;IAC1D;GACF;GACA,MAAM,QAAQ,QAAQ;GACtB,MAAM,WAAW,gBAAgB,OAAO;GACxC,UAAU,OAAO,WAAW,EAAE,WAAW,KAAK,CAAC;GAC/C,MAAM,aAAa,KAAK,OAAO,WAAW,QAAQ;GAElD,IAAI,WAAW,UAAU,GACvB,aAAa,YAAY,KAAK,OAAO,WAAW,GAAG,SAAS,QAAQ,SAAS,EAAE,EAAE,QAAQ,CAAC;GAE5F,cAAc,YAAY,MAAM,QAAQ,GAAG,IAAI,QAAQ,MAAM,MAAM,MAAM,KAAK,MAAM;GACpF,QAAQ,eAAe,KAAA;GACvB,QAAQ,QAAQ,MAAM;GACtB,QAAQ,OAAO;GAEf,MAAM,UAAU,MAAM;GACtB,IAAI,YAAY,KAAA,KAAa,OAAO,QAAQ,UAAU,UAAU;IAC9D,QAAQ,SAAS;IACjB,QAAQ,SAAS,QAAQ,SAAS,aAAa;GACjD,OAAO;IACL,QAAQ,SAAS;IACjB,QAAQ,SAAS,KAAA;GACnB;GACA,QAAQ,QAAQ,KAAA;GAChB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,OAAO,WAAW,OAAO;GACrC,UAAU,KAAK,KAAK;IAAE,IAAI;IAAM,OAAO,MAAM;IAAQ,MAAM;IAAU,UAAU;GAAM,CAAC;EACxF;CACF;;CAGA,MAAM,oBAA8B;EAClC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAAmC,GAAG;GACzD,IAAI,CAAC,OAAO,UAAU,MAAM,SAAS,GAAG;IACtC,UAAU,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;IAChD;GACF;GACA,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,KAAM,SAAU;GACpE,IAAI,YAAY,KAAA,GAAW;IACzB,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,KAAM,UAAU,QAAQ,CAAC;IAC5D;GACF;GACA,IAAI,QAAQ,iBAAiB,KAAA,GAAW;IACtC,QAAQ,eAAe,KAAA;IACvB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IAC3C,YAAY,OAAO,WAAW,OAAO;GACvC;GACA,UAAU,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;EAClC;CACF;CAGA,MAAM,eAAyB;EAC7B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAA6B,GAAG;GACnD,IAAI,CAAC,OAAO,UAAU,MAAM,SAAS,GAAG;IACtC,UAAU,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;IAChD;GACF;GACA,IAAI;IAEF,UAAU,KAAK,KAAK,EAAE,SAAA,MADA,iBAAiB,KAAK,QAAQ,SAAS,OAAO,WAAW,KAAM,SAAU,EACjE,CAAC;GACjC,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;CAGA,MAAM,kBAA4B;EAChC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAAgC,GAAG;GACtD,IAAI;IACF,IAAI,MAAM,YAAY,MAAM;KAE1B,MAAM,UAAU,MAAM,mBAAmB,KAAK,QAAQ,OAAO;KAC7D,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KAC3C,YAAY,OAAO,WAAW,OAAO;KAErC,UAAU,KAAK,KAAK,EADmB,aAAa,QACzB,CAAC;KAC5B;IACF;IACA,IAAI,MAAM,OAAO,KAAA,GAAW;KAE1B,MAAM,SAAS,QAAQ,YAAY,MAAK,MAAK,EAAE,OAAO,KAAK,EAAE;KAC7D,IAAI,WAAW,KAAA,GAAW;MACxB,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,KAAK,GAAG,MAAM,CAAC;MAClD;KACF;KACA,IAAI,KAAK,gBAAgB,KAAA,GAAW,OAAO,cAAc,KAAK;KAC9D,IAAI,KAAK,mBAAmB,KAAA,GAAW,OAAO,iBAAiB,KAAK;KACpE,IAAI,KAAK,kBAAkB,KAAA,GAAW,OAAO,gBAAgB,KAAK;KAClE,IAAI,KAAK,WAAW,KAAA,GAAW,OAAO,SAAS,KAAK;KACpD,IAAI,KAAK,iBAAiB,KAAA,GAAW,OAAO,eAAe,KAAK;IAClE,OAAO;KAEL,MAAM,cAAc,MAAM,aAAa,KAAK;KAC5C,IAAI,gBAAgB,KAAA,KAAa,gBAAgB,IAAI;MACnD,UAAU,KAAK,KAAK,EAAE,OAAO,iBAAiB,CAAC;MAC/C;KACF;KACA,QAAQ,YAAY,KAAK;MACvB,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE;MAChC;MACA,gBAAgB,MAAM;MACtB,eAAe,MAAM;MACrB,QAAQ,MAAM,UAAU;KAC1B,CAAC;IACH;IACA,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IAC3C,YAAY,OAAO,WAAW,OAAO;IAErC,UAAU,KAAK,KAAK,EADmB,aAAa,QAAQ,YACjC,CAAC;GAC9B,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;CAGA,MAAM,cAAwB;EAC5B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAE3B,MAAM,UAAS,MADI,aAA4B,GAAG,EAAA,EAC7B,WAAW,OAAO,OAAO;GAC9C,IAAI;IAGF,UAAU,KAAK,KAAK,EADe,GADpB,WAAW,OAAO,WAAW,SAAS,MACV,EAChB,CAAC;GAC9B,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;CAGA,MAAM,eAAyB;EAC7B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,KAAK,GAAG;GAC7B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB;GACtD,MAAM,QAAQ,OAAO,IAAI,aAAa,IAAI,IAAI,KAAK,GAAG;GACtD,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GAAG;IACzC,UAAU,KAAK,KAAK,EAAE,OAAO,WAAW,CAAC;IACzC;GACF;GACA,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,KAAK;GACzD,IAAI,YAAY,KAAA,GAAW;IACzB,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,MAAM,QAAQ,CAAC;IAClD;GACF;GACA,MAAM,WAAW,gBAAgB,OAAO,WAAW,OAAO;GAC1D,IAAI,aAAa,KAAA,GAAW;IAC1B,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,MAAM,OAAO,CAAC;IACjD;GACF;GAEA,UAAU,KAAK,KAAK;IADgB,IAAI,QAAQ;IAAI,OAAO,QAAQ;IAAO;GAC/C,CAAC;EAC9B;CACF;;CAIA,MAAM,oBAA8B;EAClC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAAiC,GAAG;GACvD,MAAM,OAAO,MAAM,MAAM,KAAK,KAAK;GACnC,IAAI,KAAK,SAAS,IAAI;IACpB,UAAU,KAAK,KAAK,EAAE,OAAO,qBAAqB,CAAC;IACnD;GACF;GACA,IAAI;IAGF,UAAU,KAAK,KAAK,EAAE,QAAA,MADD,kBAAkB,KAAK,QAAQ,SAAS,MAAM,MAAM,cAAc,EAC1D,CAAC;GAChC,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;;CAGA,MAAM,mBAA6B;EACjC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAAiC,GAAG;GACvD,IAAI,CAAC,OAAO,UAAU,MAAM,SAAS,GAAG;IACtC,UAAU,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;IAChD;GACF;GACA,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,KAAM,SAAU;GACpE,IAAI,YAAY,KAAA,GAAW;IACzB,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,KAAM,UAAU,QAAQ,CAAC;IAC5D;GACF;GACA,MAAM,OAAO,MAAM,MAAM,KAAK,KAAK;GACnC,IAAI,KAAK,SAAS,IAAI;IACpB,UAAU,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;IAChD;GACF;GACA,MAAM,WAAW,gBAAgB,OAAO;GACxC,UAAU,OAAO,WAAW,EAAE,WAAW,KAAK,CAAC;GAC/C,MAAM,aAAa,KAAK,OAAO,WAAW,QAAQ;GAClD,IAAI,WAAW,UAAU,GACvB,aAAa,YAAY,KAAK,OAAO,WAAW,GAAG,SAAS,QAAQ,SAAS,EAAE,EAAE,QAAQ,CAAC;GAE5F,cAAc,YAAY,MAAM,QAAQ,GAAG,IAAI,QAAQ,MAAM,MAAM,KAAK,KAAK,MAAM;GACnF,QAAQ,SAAS;GACjB,QAAQ,QAAQ,KAAK;GACrB,QAAQ,OAAO;GACf,QAAQ,eAAe,KAAA;GAEvB,IAAI;GACJ,MAAM,UAAU,MAAM;GACtB,IAAI,YAAY,KAAA,KAAa,OAAO,QAAQ,UAAU,UAAU;IAC9D,SAAS;IACT,QAAQ,SAAS;IACjB,QAAQ,SAAS,OAAO,SAAS,aAAa;GAChD,OACE,SAAS,MAAM,cAAc,KAAK,QAAQ,SAAS,OAAO,WAAW,QAAQ,EAAE;GAEjF,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,OAAO,WAAW,OAAO;GAErC,UAAU,KAAK,KAAK;IADoB,IAAI;IAAM,OAAO,KAAK;IAAQ,MAAM;IAAU;GAC3D,CAAC;EAC9B;CACF;CAGA,MAAM,iBAA2B;EAC/B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAE3B,MAAM,WAAU,MADG,aAA+B,GAAG,EAAA,EAC/B,SAAS,KAAK;GACpC,IAAI,YAAY,KAAA,KAAa,YAAY,IAAI;IAC3C,UAAU,KAAK,KAAK,EAAE,OAAO,SAAS,CAAC;IACvC;GACF;GACA,IAAI,UAAU,KAAK;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,qBAAqB;IACrB,mBAAmB;GACrB,CAAC;GACD,MAAM,QAAQ,UAAgC;IAAE,IAAI,MAAM,KAAK,UAAU,KAAK,IAAI,IAAI;GAAE;GACxF,IAAI;IACF,WAAW,MAAM,QAAQ,iBAAiB,KAAK,QAAQ,SAAS,OAAO,WAAW,OAAO,GACvF,IAAI,KAAK,UAAU,SAAS,KAAK;KAAE,MAAM;KAAS,MAAM,KAAK;IAAK,CAAC;SAC9D,IAAI,KAAK,UAAU,QAAQ,KAAK;KAAE,MAAM;KAAQ,MAAM,KAAK;KAAM,QAAQ,KAAK;KAAQ,QAAQ,KAAK;IAAO,CAAC;SAC3G,IAAI,KAAK,UAAU,aAAa,KAAK;KAAE,MAAM;KAAa,MAAM,KAAK;KAAM,MAAM,KAAK;IAAK,CAAC;IAEnG,KAAK,EAAE,MAAM,OAAO,CAAC;IACrB,IAAI,IAAI;GACV,SAAS,OAAO;IACd,IAAI,CAAC,IAAI,eAAe;KACtB,KAAK;MAAE,MAAM;MAAS,SAAU,MAAgB;KAAQ,CAAC;KACzD,IAAI,IAAI;IACV;GACF;EACF;CACF;CAGA,MAAM,wBAAkC;EACtC,MAAM;EACN,MAAM,UAAU;EAChB,UAAU,KAAK,QAAQ;GACrB,IAAI,CAAC,MAAM,KAAK,KAAK,KAAK,GAAG;GAG7B,UAAU,KAAK,KAAK,EADyB,UAAU,qBADxC,UACkE,CAAC,CAAC,SAAS,EACjE,CAAC;EAC9B;CACF;;CAIA,MAAM,sBAAgC;EACpC,MAAM;EACN,MAAM,UAAU;EAChB,UAAU,KAAK,QAAQ;GACrB,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAE9B,sBADe,UACY,CAAC,CAAC,SAAS;GACtC,UAAU,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;EAClC;CACF;CAGA,MAAM,cAAwB;EAC5B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAG3B,IAAI,IAAI,WAAW,SAAS,IAAI,WAAW,QAAQ;IACjD,UAAU,KAAK,KAAK,EAAE,OAAO,4CAA4C,CAAC;IAC1E;GACF;GACA,IAAI,CAAC,kBAAkB,GAAG,GAAG;IAC3B,UAAU,KAAK,KAAK,EAAE,OAAO,2BAA2B,CAAC;IACzD;GACF;GACA,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,YAAY,OAAO,SAAS;GAC5C,MAAM,gBAAgB,SAAS,UAAU,mBAAmB;GAC5D,IAAI,IAAI,WAAW,QAAQ;IACzB,MAAM,OAAO,MAAM,aAA0B,GAAG;IAChD,IAAI,SAAS,KAAA,GAAW;KACtB,UAAU,KAAK,KAAK,EAAE,OAAO,WAAW,CAAC;KACzC;IACF;IACA,IAAI,YAAY,KAAA,GAAW;KACzB,UAAU,KAAK,KAAK,EAAE,OAAO,aAAa,CAAC;KAC3C;IACF;IACA,IAAI,KAAK,UAAU,KAAA,GAAW,cAAc,QAAQ,KAAK;IACzD,IAAI,KAAK,uBAAuB,KAAA,GAAW,cAAc,qBAAqB,KAAK;IACnF,IAAI,KAAK,0BAA0B,KAAA,GAAW,cAAc,wBAAwB,KAAK;IACzF,IAAI,KAAK,gBAAgB,KAAA,GAAW,cAAc,cAAc,KAAK;IACrE,IAAI,KAAK,gBAAgB,KAAA,GAAW,cAAc,cAAc,KAAK;IACrE,cAAc,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IACjD,QAAQ,SAAS;IACjB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IAC3C,YAAY,OAAO,WAAW,OAAO;GACvC;GAQA,UAAU,KAAK,KAAK;IANlB;IACA,cAAc;IACd,eAAe;IACf,gBAAgB;IAChB,oBAAoB;GAEK,CAAC;EAC9B;CACF;CAGA,MAAM,mBAA6B;EACjC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,YAAY,OAAO,SAAS;GAC5C,MAAM,OAAO,MAAM,aAAiC,GAAG;GACvD,MAAM,SAAS,MAAM,YAAY,KAAK;GACtC,IAAI,WAAW,KAAA,KAAa,OAAO,SAAS,IAAI;IAC9C,UAAU,KAAK,KAAK,EAAE,OAAO,iCAAiC,CAAC;IAC/D;GACF;GACA,IAAI;IACF,MAAM,QAAQ,MAAM,kBAAkB,KAAK,QAAQ,MAAM;IAEzD,MAAM,aAAa;KACjB,OAFW,MAAM,MAAM,KAAK,MAAM,MAAM,MAAM,SAAS,KAAA,IAAY,KAAK,OAAO,QAAQ,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,IAAA,CAElG,MAAM,GAAG,EAAE;KACtB,GAAG;KACH,YAAY,OAAO,MAAM,GAAG,GAAI;KAChC,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;IACpC;IACA,IAAI,YAAY,KAAA,GAAW;KACzB,QAAQ,WAAW,mBAAmB;KACtC,QAAQ,OAAO,gBAAgB,CAAC;KAChC,QAAQ,OAAO,YAAY,KAAK,UAAU;KAC1C,QAAQ,OAAO,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KAClD,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KAC3C,YAAY,OAAO,WAAW,OAAO;IACvC;IACA,UAAU,KAAK,KAAK,EAAE,WAAW,CAAC;GACpC,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;CAGA,MAAM,iBAA2B;EAC/B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAE3B,IAAI,IAAI,WAAW,OAAO;IACxB,IAAI,CAAC,kBAAkB,GAAG,GAAG;KAC3B,UAAU,KAAK,KAAK,EAAE,OAAO,2BAA2B,CAAC;KACzD;IACF;IAEA,2BAA2B,UAAU,CAAC,CAAC,SAAS;IAEhD,UAAU,KAAK,KADqB,kBAAkB,cAAc,CACzC,CAAC;IAC5B;GACF;GACA,IAAI,IAAI,WAAW,QAAQ;IACzB,IAAI,CAAC,kBAAkB,GAAG,GAAG;KAC3B,UAAU,KAAK,KAAK,EAAE,OAAO,2BAA2B,CAAC;KACzD;IACF;IACA,MAAM,OAAO,MAAM,aAAgC,GAAG;IACtD,MAAM,WAAW,MAAM,UAAU,KAAK;IACtC,IAAI,aAAa,KAAA,KAAa,aAAa,IAAI;KAC7C,UAAU,KAAK,KAAK,EAAE,OAAO,gBAAgB,CAAC;KAC9C;IACF;IACA,MAAM,YAAY,MAAM,WAAW,KAAK,MAAM,MAAM,MAAM,cAAc,KAAA,IACpE,KAAK,YACL,oBAAoB,QAAQ;IAChC,MAAM,OAAO,WAAW,UAAU,SAAS;IAE3C,MAAM,UAAU,MAAM,SAAS,KAAK;IACpC,IAAI,YAAY,KAAA,KAAa,QAAQ,UAAU,IAAI;KACjD,MAAM,UAAU,cAAc,OAAO;KACrC,YAAY,WAAW,OAAO;KAC9B,WAAW,KAAK,IAAI,QAAQ,QAAQ;IACtC;IACA,UAAU,KAAK,KAAK,kBAAkB,cAAc,CAAC,CAAC;IACtD;GACF;GACA,UAAU,KAAK,KAAK,EAAE,OAAO,4CAA4C,CAAC;EAC5E;CACF;;CAIA,MAAM,aAAuB;EAC3B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,YAAY,OAAO,SAAS;GAC5C,IAAI,YAAY,KAAA,GAAW;IACzB,UAAU,KAAK,KAAK,EAAE,OAAO,iBAAiB,CAAC;IAC/C;GACF;GAEA,MAAM,WAAU,MADG,aAA2B,GAAG,EAAA,EAC3B,SAAS,KAAK;GACpC,IAAI,YAAY,KAAA,KAAa,QAAQ,UAAU,IAAI;IACjD,QAAQ,UAAU;IAClB,QAAQ,WAAW,cAAc,OAAO,CAAC,CAAC;GAC5C;GACA,QAAQ,QAAQ,KAAA;GAChB,QAAQ,UAAU,KAAA;GAClB,QAAQ,WAAW,CAAC;GACpB,QAAQ,cAAc,CAAC;GACvB,QAAQ,SAAS,mBAAmB;GACpC,QAAQ,QAAQ,CAAC;GACjB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,OAAO,WAAW,OAAO;GACrC,UAAU,KAAK,KAAK;IAAE,IAAI;IAAM,UAAU,QAAQ;GAAS,CAAC;EAC9D;CACF;CAGA,MAAM,yBAAmC;EACvC,MAAM;EACN,MAAM;EACN,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,OAAO,MAAM,aAAkC,GAAG;GACxD,IAAI,MAAM,OAAO,KAAA,KAAa,KAAK,OAAO,IAAI;IAC5C,UAAU,KAAK,KAAK,EAAE,OAAO,UAAU,CAAC;IACxC;GACF;GAEA,IADa,aAAa,KAAK,EACxB,MAAM,KAAA,GAAW;IACtB,UAAU,KAAK,KAAK,EAAE,OAAO,KAAK,KAAK,GAAG,MAAM,CAAC;IACjD;GACF;GACA,UAAU,KAAK,KAAK,kBAAkB,cAAc,CAAC,CAAC;EACxD;CACF;CAGA,MAAM,uBAAiC;EACrC,MAAM;EACN,MAAM;EACN,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,OAAO,MAAM,aAAgC,GAAG;GACtD,IAAI,MAAM,OAAO,KAAA,KAAa,KAAK,OAAO,IAAI;IAC5C,UAAU,KAAK,KAAK,EAAE,OAAO,UAAU,CAAC;IACxC;GACF;GAEA,IAAI,CADY,WAAW,KAAK,EACrB,GAAG;IACZ,UAAU,KAAK,KAAK,EAAE,OAAO,KAAK,KAAK,GAAG,MAAM,CAAC;IACjD;GACF;GACA,UAAU,KAAK,KAAK,kBAAkB,cAAc,CAAC,CAAC;EACxD;CACF;;CAIA,MAAM,aAAuB;EAC3B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GACzC,aAAa;IAAE,QAAQ;IAAW;IAAW,cAAc;IAAG,kBAAkB;GAAE;GAClF,IAAI;IACF,MAAM,SAAS,MAAM,UAAU,KAAK,QAAQ,SAAS,OAAO,YAAY,WAAW,UAAU;KAC3F,WAAW,eAAe;KAC1B,WAAW,mBAAmB;IAChC,CAAC;IACD,MAAM,kBAAkB,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,YAAY,CAAC,CAAC;IAC1G,aAAa;KACX,QAAQ;KACR;KACA,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KACnC,cAAc,WAAW;KACzB,kBAAkB,WAAW;KAC7B;KACA,aAAa,OAAO;KACpB;IACF;IAMA,UAAU,KAAK,KAAK;KAJlB;KACA;KACA,WAAW,WAAW;IAEG,CAAC;GAC9B,SAAS,OAAO;IACd,aAAa;KACX,GAAG;KACH,QAAQ;KACR,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KACnC,OAAQ,MAAgB;IAC1B;IACA,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;;CAIA,MAAM,yBAAmC;EACvC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,IAAI;IACF,MAAM,QAAQ,MAAM,kBAAkB,KAAK,QAAQ,SAAS,OAAO,SAAS;IAE5E,QAAQ,aAAa;IACrB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IAC3C,YAAY,OAAO,WAAW,OAAO;IACrC,UAAU,KAAK,KAAK,EAAE,MAAM,CAAC;GAC/B,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;;CAIA,MAAM,qBAA+B;EACnC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,IAAI;IAEF,UAAU,KAAK,KAAK;KAAE,IAAI;KAAM,QAAA,MADX,cAAc,KAAK,QAAQ,SAAS,OAAO,SAAS;IAClC,CAAC;GAC1C,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;;CAIA,MAAM,kBAA4B;EAChC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,IAAI,QAAQ,UAAU,KAAA,GAAW;IAC/B,UAAU,KAAK,KAAK,EAAE,OAAO,cAAc,CAAC;IAC5C;GACF;GACA,MAAM,OAAO,MAAM,aAAgC,GAAG;GACtD,IAAI,MAAM,QAAQ,MAAM,UAAU,GAAG,QAAQ,MAAM,aAAa,KAAK,WAAW,QAAO,MAAK,EAAE,KAAK,MAAM,EAAE;GAC3G,IAAI,MAAM,QAAQ,MAAM,QAAQ,GAAG,QAAQ,MAAM,WAAW,KAAK,SAAS,QAAO,MAAK,EAAE,KAAK,MAAM,EAAE;GACrG,IAAI,MAAM,QAAQ,MAAM,KAAK,GAAG,QAAQ,MAAM,QAAQ,KAAK,MAAM,QAAO,MAAK,EAAE,KAAK,MAAM,EAAE;GAC5F,IAAI,MAAM,QAAQ,MAAM,UAAU,GAChC,QAAQ,MAAM,aAAa,KAAK,WAC7B,QAAO,MAAK,MAAM,KAAA,KAAa,MAAM,QAAQ,OAAO,EAAE,SAAS,YAAY,EAAE,KAAK,KAAK,MAAM,EAAE,CAAC,CAChG,KAAI,OAAM;IACT,MAAM,EAAE,KAAK,KAAK;IAClB,MAAO;KAAC;KAAe;KAAc;KAAc;IAAO,CAAC,CAAW,SAAS,EAAE,IAAa,IAC1F,EAAE,OACF;IACJ,QAAQ,MAAM,QAAQ,EAAE,MAAM,IAAI,EAAE,OAAO,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE,IAAI,CAAC;IACnH,OAAO,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;IAC/C,WAAW,OAAO,EAAE,cAAc,WAAW,EAAE,YAAY;IAC3D,WAAW,MAAM,QAAQ,EAAE,SAAS,IAChC,EAAE,UAAU,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE,IAC/E,KAAA;GACN,EAAE;GAEN,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,OAAO,WAAW,OAAO;GACrC,UAAU,KAAK,KAAK,EAAE,OAAO,QAAQ,MAAM,CAAC;EAC9C;CACF;;CAIA,MAAM,aAAuB;EAC3B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAA2B,GAAG;GACjD,IAAI;IACF,IAAI,MAAM,WAAW,QAAQ;KAC3B,MAAM,OAAO,KAAK,MAAM,KAAK,KAAK;KAClC,QAAQ,QAAQ;KAChB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KAC3C,YAAY,OAAO,WAAW,OAAO;KACrC,UAAU,KAAK,KAAK,EAAE,OAAO,KAAK,CAAC;KACnC;IACF;IACA,MAAM,UAAU,MAAM,SAAS,KAAK,KAAK;IACzC,MAAM,QAAQ,MAAM,cAAc,KAAK,QAAQ,SAAS,OAAO;IAC/D,QAAQ,QAAQ;IAChB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IAC3C,YAAY,OAAO,WAAW,OAAO;IACrC,UAAU,KAAK,KAAK,EAAE,MAAM,CAAC;GAC/B,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;;CAIA,MAAM,aAAuB;EAC3B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,MAAM,SAAS,UAAU;GACzB,IAAI,IAAI,WAAW,OAAO;IACxB,IAAI,CAAC,kBAAkB,GAAG,GAAG;KAC3B,UAAU,KAAK,KAAK,EAAE,OAAO,2BAA2B,CAAC;KACzD;IACF;IAGA,MAAM,WAAW,IADD,IAAI,IAAI,OAAO,KAAK,kBACjB,CAAC,CAAC,aAAa,IAAI,KAAK;IAC3C,MAAM,YAAY,aAAa,QAAQ,aAAa,KAAK,WAAW,OAAO;IAE3E,MAAM,YADU,YAAY,SACJ,CAAC,EAAE;IAC3B,IAAI,cAAc,KAAA,KAAa,cAAc,IAAI;KAC/C,UAAU,KAAK,KAAK,EAAE,SAAS,KAAK,CAAyB;KAC7D;IACF;IACA,MAAM,OAAO,KAAK,WAAW,SAAS;IACtC,IAAI,CAAC,WAAW,IAAI,GAAG;KACrB,UAAU,KAAK,KAAK,EAAE,SAAS,KAAK,CAAyB;KAC7D;IACF;IAMA,UAAU,KAAK,KAAK,EAAE,SAAA,QALT,UAAU,YAAY,CAAC,CAAC,SAAS,MAAM,IAAI,cACpD,UAAU,YAAY,CAAC,CAAC,SAAS,MAAM,KAAK,UAAU,YAAY,CAAC,CAAC,SAAS,OAAO,IAAI,eACtF,UAAU,YAAY,CAAC,CAAC,SAAS,OAAO,IAAI,eAC1C,YACqB,UAAU,aAAa,IAAI,CAAC,CAAC,SAAS,QAAQ,IAC7C,CAAyB;IACvD;GACF;GACA,IAAI,IAAI,WAAW,QAAQ;IACzB,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;IAC9B,MAAM,UAAU,eAAe,GAAG;IAClC,IAAI,YAAY,KAAA,GAAW;IAC3B,MAAM,OAAO,MAAM,aAA2B,GAAG;IACjD,IAAI;KACF,IAAI,MAAM,WAAW,UAAU;MAC7B,IAAI,QAAQ,cAAc,KAAA,KAAa,QAAQ,cAAc,IAAI;OAC/D,MAAM,UAAU,KAAK,OAAO,WAAW,QAAQ,SAAS;OACxD,IAAI,WAAW,OAAO,GAAG,OAAO,SAAS,EAAE,OAAO,KAAK,CAAC;MAC1D;MACA,QAAQ,YAAY,KAAA;MACpB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;MAC3C,YAAY,OAAO,WAAW,OAAO;MACrC,UAAU,KAAK,KAAK;OAAE,IAAI;OAAM,WAAW;MAAK,CAAC;MACjD;KACF;KACA,MAAM,UAAU,MAAM,WAAW;KACjC,MAAM,QAAQ,qDAAqD,KAAK,OAAO;KAC/E,IAAI,UAAU,MAAM;MAClB,UAAU,KAAK,KAAK,EAAE,OAAO,uCAAuC,CAAC;MACrE;KACF;KACA,MAAM,OAAO,MAAM;KAEnB,MAAM,WAAW,SADL,SAAS,cAAc,QAAQ,SAAS,eAAe,SAAS;KAE5E,MAAM,aAAa,KAAK,OAAO,WAAW,QAAQ;KAClD,MAAM,UAAU,QAAQ;KACxB,UAAU,OAAO,WAAW,EAAE,WAAW,KAAK,CAAC;KAC/C,cAAc,YAAY,OAAO,KAAK,MAAM,IAAK,QAAQ,CAAC;KAC1D,IAAI,YAAY,KAAA,KAAa,YAAY,MAAM,YAAY,UAAU;MACnE,MAAM,UAAU,KAAK,OAAO,WAAW,OAAO;MAC9C,IAAI,WAAW,OAAO,GAAG,OAAO,SAAS,EAAE,OAAO,KAAK,CAAC;KAC1D;KACA,QAAQ,YAAY;KACpB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KAC3C,YAAY,OAAO,WAAW,OAAO;KACrC,UAAU,KAAK,KAAK;MAAE,IAAI;MAAM,WAAW;KAAS,CAAC;IACvD,SAAS,OAAO;KACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;IACzD;IACA;GACF;GACA,UAAU,KAAK,KAAK,EAAE,OAAO,4CAA4C,CAAC;EAC5E;CACF;;CAIA,MAAM,aAAuB;EAC3B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAA2B,GAAG;GACjD,IAAI;IACF,IAAI,MAAM,WAAW,UAAU,KAAK,UAAU,KAAA,GAAW;KACvD,QAAQ,QAAQ;MACd,QAAQ,MAAM,QAAQ,KAAK,MAAM,MAAM,IAAI,KAAK,MAAM,SAAS,CAAC;MAChE,SAAS,MAAM,QAAQ,KAAK,MAAM,OAAO,IAAI,KAAK,MAAM,UAAU,CAAC;MACnE,UAAU,MAAM,QAAQ,KAAK,MAAM,QAAQ,IAAI,KAAK,MAAM,WAAW,CAAC;KACxE;KACA,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KAC3C,YAAY,OAAO,WAAW,OAAO;KACrC,UAAU,KAAK,KAAK,EAAE,OAAO,QAAQ,MAAM,CAAC;KAC5C;IACF;IACA,MAAM,QAAQ,MAAM,aAAa,KAAK,QAAQ,OAAO;IACrD,QAAQ,QAAQ;IAChB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IAC3C,YAAY,OAAO,WAAW,OAAO;IACrC,UAAU,KAAK,KAAK,EAAE,MAAM,CAAC;GAC/B,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;;CAIA,MAAM,cAAwB;EAC5B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAE3B,MAAM,YAAW,MADE,aAA4B,GAAG,EAAA,EAC3B,UAAU,KAAK;GACtC,IAAI,aAAa,KAAA,KAAa,aAAa,IAAI;IAC7C,UAAU,KAAK,KAAK,EAAE,OAAO,SAAS,CAAC;IACvC;GACF;GACA,QAAQ,WAAW,SAAS,MAAM,GAAG,EAAE;GACvC,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,OAAO,WAAW,OAAO;GACrC,MAAM,QAAQ,cAAc;GAC5B,IAAI,MAAM,iBAAiB,MAAM,WAAW,MAAM,cAAc,QAAQ,QAAQ;GAChF,UAAU,KAAK,KAAK,EAAE,UAAU,QAAQ,SAAS,CAAC;EACpD;CACF;;CAIA,MAAM,iBAA2B;EAC/B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAA+B,GAAG;GACrD,IAAI,QAAQ,cAAc,KAAA,GAAW,QAAQ,YAAY,CAAC;GAC1D,MAAM,KAAK,MAAM;GACjB,IAAI,OAAO,SAAS,MAAM,SAAS,KAAA,GAAW;IAC5C,MAAM,OAAO,KAAK;IAClB,QAAQ,UAAU,KAAK;KACrB,IAAI,KAAK,OAAO,KAAK,KAAK,KAAK,MAAM,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;KACxF,MAAM,KAAK,KAAK,MAAM,GAAG,EAAE;KAC3B,MAAM,KAAK;KACX,MAAM,KAAK,KAAK,MAAM,GAAG,GAAG;KAC5B,UAAU,KAAK,SAAS,MAAM,GAAG,GAAG;KACpC,QAAQ,KAAK;KACb,UAAU,MAAM,QAAQ,KAAK,QAAQ,IAAI,KAAK,SAAS,QAAQ,MAAmB,OAAO,MAAM,QAAQ,IAAI,CAAC;KAC5G,WAAW,KAAK,cAAc,KAAK,KAAK,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IAC7E,CAAC;GACH,OAAO,IAAI,OAAO,YAAY,MAAM,SAAS,KAAA,KAAa,KAAK,KAAK,OAAO,IAAI;IAC7E,MAAM,MAAM,QAAQ,UAAU,WAAU,MAAK,EAAE,OAAO,KAAK,KAAM,EAAE;IACnE,IAAI,QAAQ,IAAI;KACd,MAAM,OAAO,KAAK;KAClB,QAAQ,UAAU,OAAO;MACvB,GAAG,QAAQ,UAAU;MACrB,MAAM,KAAK,KAAK,MAAM,GAAG,EAAE;MAC3B,MAAM,KAAK;MACX,MAAM,KAAK,KAAK,MAAM,GAAG,GAAG;MAC5B,UAAU,KAAK,SAAS,MAAM,GAAG,GAAG;MACpC,QAAQ,KAAK;KACf;IACF;GACF,OAAO,IAAI,OAAO,YAAY,MAAM,OAAO,KAAA,GACzC,QAAQ,YAAY,QAAQ,UAAU,QAAO,MAAK,EAAE,OAAO,KAAK,EAAE;QAC7D,IAAI,OAAO,UAAU,MAAM,OAAO,KAAA,KAAa,OAAO,KAAK,cAAc,YAAY,KAAK,YAAY,GAAG;IAC9G,MAAM,OAAO,QAAQ,UAAU,MAAK,MAAK,EAAE,OAAO,KAAK,EAAE;IACzD,IAAI,SAAS,KAAA,KAAa,CAAC,KAAK,SAAS,SAAS,KAAK,SAAS,GAAG;KACjE,KAAK,SAAS,KAAK,KAAK,SAAS;KACjC,IAAI,KAAK,WAAW,YAAY,KAAK,aAAa,IAChD,KAAK,WAAW,QAAQ,KAAK,UAAU;IAE3C;GACF,OAAO,IAAI,OAAO,WAChB,IAAI;IACF,MAAM,cAAc,MAAM,iBAAiB,KAAK,QAAQ,OAAO;IAC/D,UAAU,KAAK,KAAK;KAAE,WAAW,QAAQ;KAAW;IAAY,CAA6B;IAC7F;GACF,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAO,WAAY,MAAgB,UAAU,CAAC;IACpE;GACF;QACK,IAAI,OAAO,aAAa,MAAM,OAAO,KAAA,GAAW;IACrD,MAAM,OAAO,QAAQ,UAAU,MAAK,MAAK,EAAE,OAAO,KAAK,EAAE;IACzD,IAAI,SAAS,KAAA,GAAW;KACtB,UAAU,KAAK,KAAK,EAAE,OAAO,SAAS,CAAC;KACvC;IACF;IACA,IAAI;KAEF,KAAK,WAAW,MADO,wBAAwB,KAAK,QAAQ,SAAS,IAAI;KAEzE,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KAC3C,YAAY,OAAO,WAAW,OAAO;KACrC,UAAU,KAAK,KAAK,EAAE,WAAW,QAAQ,UAAU,CAA6B;KAChF;IACF,SAAS,OAAO;KACd,UAAU,KAAK,KAAK,EAAE,OAAO,UAAW,MAAgB,UAAU,CAAC;KACnE;IACF;GACF,OAAO,IAAI,OAAO,UAChB,IAAI;IACF,MAAM,SAAS,MAAM,sBAAsB,KAAK,QAAQ,OAAO;IAC/D,UAAU,KAAK,KAAK;KAAE,WAAW,QAAQ;KAAW;IAAO,CAA6B;IACxF;GACF,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAO,UAAW,MAAgB,UAAU,CAAC;IACnE;GACF;QACK,IAAI,OAAO,QAChB,IAAI;IACF,MAAM,SAAS,MAAM,sBAAsB,KAAK,QAAQ,OAAO;IAC/D,MAAM,OAAO,MAAM,mBAAmB,KAAK,QAAQ,SAAS,MAAM;IAClE,UAAU,KAAK,KAAK;KAAE,WAAW,QAAQ;KAAW;KAAQ;IAAK,CAA6B;IAC9F;GACF,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAO,YAAa,MAAgB,UAAU,CAAC;IACrE;GACF;GAEF,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,OAAO,WAAW,OAAO;GAErC,UAAU,KAAK,KAAK,EADkB,WAAW,QAAQ,UAC9B,CAAC;EAC9B;CACF;;CAIA,MAAM,iBAA2B;EAC/B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAAoC,GAAG;GAC1D,MAAM,OAAuB,CAAC;GAC9B,IAAI,UAAU;GACd,IAAI,MAAM,SAAS,KAAA,GACjB,KAAK,MAAM,OAAO,mBAAmB,KAAK,IAAI,GAC5C,KAAK,KAAK;IAAE,WAAW;IAAG,MAAM,IAAI;IAAM,UAAU,IAAI;IAAU,OAAO,IAAI;GAAM,CAAC;QAEjF,IAAI,OAAO,MAAM,cAAc,UAAU;IAC9C,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,KAAK,SAAS;IAClE,IAAI,YAAY,KAAA,GAAW;KACzB,MAAM,OAAO,gBAAgB,OAAO,WAAW,OAAO;KACtD,IAAI,SAAS,KAAA,GAAW;MACtB,UAAU;MACV,KAAK,MAAM,OAAO,mBAAmB,IAAI,GACvC,KAAK,KAAK;OAAE,WAAW,QAAQ;OAAI,MAAM,IAAI;OAAM,UAAU,IAAI;OAAU,OAAO,IAAI;MAAM,CAAC;KAEjG;IACF;GACF,OAAO,IAAI,MAAM,QAAQ,MACvB,KAAK,MAAM,WAAW,QAAQ,UAAU;IACtC,IAAI,QAAQ,WAAW,aAAa,QAAQ,WAAW,cAAc;IACrE,MAAM,OAAO,gBAAgB,OAAO,WAAW,OAAO;IACtD,IAAI,SAAS,KAAA,GAAW;IACxB;IACA,KAAK,MAAM,OAAO,mBAAmB,IAAI,GACvC,KAAK,KAAK;KAAE,WAAW,QAAQ;KAAI,MAAM,IAAI;KAAM,UAAU,IAAI;KAAU,OAAO,IAAI;IAAM,CAAC;GAEjG;QACK;IACL,UAAU,KAAK,KAAK,EAAE,OAAO,gCAAgC,CAAC;IAC9D;GACF;GAEA,UAAU,KAAK,KAAK;IADuB;IAAM,iBAAiB;GACvC,CAAC;EAC9B;CACF;;CAIA,MAAM,aAAuB;EAC3B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAA2B,GAAG;GACjD,IAAI,QAAQ,UAAU,KAAA,GAAW,QAAQ,QAAQ,CAAC;GAClD,MAAM,KAAK,MAAM;GACjB,IAAI,OAAO,WACT,IAAI;IACF,MAAM,aAAa,MAAM,aAAa,KAAK,QAAQ,OAAO;IAC1D,UAAU,KAAK,KAAK;KAAE,OAAO,QAAQ;KAAO;IAAW,CAAyB;IAChF;GACF,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAO,UAAW,MAAgB,UAAU,CAAC;IACnE;GACF;QACK,KAAK,OAAO,WAAW,OAAO,aAAa,MAAM,SAAS,KAAA,GAAW;IAC1E,MAAM,IAAI,KAAK;IACf,MAAM,MAAM,QAAQ,MAAM,WAAU,MAAK,EAAE,SAAS,EAAE,IAAI;IAC1D,IAAI,QAAQ,IAAI,QAAQ,MAAM,KAAK,CAAC;SAC/B,QAAQ,MAAM,OAAO;GAC5B,OAAO,IAAI,OAAO,YAAY,MAAM,SAAS,KAAA,GAC3C,QAAQ,QAAQ,QAAQ,MAAM,QAAO,MAAK,EAAE,SAAS,KAAK,IAAI;QACzD,IAAI,OAAO,SAAS;IACzB,MAAM,OAAO,MAAM,MAAM,KAAK;IAC9B,MAAM,UAAU,MAAM,SAAS,KAAK;IACpC,IAAI,SAAS,KAAA,KAAa,SAAS,IAAI;KACrC,UAAU,KAAK,KAAK,EAAE,OAAO,cAAc,CAAC;KAC5C;IACF;IACA,IAAI,YAAY,KAAA,KAAa,YAAY,IAAI;KAC3C,UAAU,KAAK,KAAK,EAAE,OAAO,iBAAiB,CAAC;KAC/C;IACF;IACA,MAAM,OAAO,QAAQ,MAAM,MAAK,MAAK,EAAE,SAAS,IAAI;IACpD,IAAI,SAAS,KAAA,GAAW;KACtB,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,KAAK,MAAM,CAAC;KAC/C;IACF;IACA,MAAM,QAAQ,MAAM,OAAO,KAAK,KAAK;IACrC,IAAI,UAAU,IAAI;KAEhB,KAAK,YAAY,CAAC;KAClB,KAAK,UAAU,KAAK,QAAQ,QAAO,MAAK,EAAE,UAAU,KAAK;KACzD,KAAK,QAAQ,KAAK;MAAE;MAAO;KAAQ,CAAC;KACpC,IAAI,UAAU,QAAQ,MAAM,SAAS,IAAI,GAAG,KAAK,WAAW;IAC9D,OAEE,KAAK,WAAW;IAElB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IAC3C,YAAY,OAAO,WAAW,OAAO;IACrC,UAAU,KAAK,KAAK;KAAE,OAAO,QAAQ;KAAO,UAAU,KAAK;IAAS,CAAyB;IAC7F;GACF,OAAO,IAAI,OAAO,eAAe;IAC/B,MAAM,OAAO,MAAM,MAAM,KAAK;IAC9B,MAAM,QAAQ,MAAM,OAAO,KAAK,KAAK;IACrC,MAAM,OAAO,QAAQ,MAAM,MAAK,MAAK,EAAE,SAAS,IAAI;IACpD,IAAI,SAAS,KAAA,GACX,IAAI,UAAU,IAAI;KAChB,KAAK,WAAW,KAAK,WAAW,CAAC,EAAA,CAAG,QAAO,MAAK,EAAE,UAAU,KAAK;KACjE,IAAI,UAAU,QAAQ,MAAM,SAAS,IAAI,GAAG,KAAK,WAAW,KAAA;IAC9D,OACE,KAAK,WAAW,KAAA;IAGpB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IAC3C,YAAY,OAAO,WAAW,OAAO;IACrC,UAAU,KAAK,KAAK,EAAE,OAAO,QAAQ,MAAM,CAAyB;IACpE;GACF,OAAO,IAAI,OAAO,iBAAiB;IACjC,MAAM,OAAO,MAAM,MAAM,KAAK;IAC9B,IAAI,SAAS,KAAA,KAAa,SAAS,IAAI;KACrC,UAAU,KAAK,KAAK,EAAE,OAAO,cAAc,CAAC;KAC5C;IACF;IACA,IAAI;KACF,MAAM,WAAW,MAAM,2BAA2B,KAAK,QAAQ,SAAS,OAAO,WAAW,MAAM,MAAM,SAAS,EAAE;KACjH,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KAC3C,YAAY,OAAO,WAAW,OAAO;KACrC,UAAU,KAAK,KAAK;MAAE,OAAO,QAAQ;MAAO;KAAS,CAAyB;KAC9E;IACF,SAAS,OAAO;KACd,UAAU,KAAK,KAAK,EAAE,OAAO,aAAc,MAAgB,UAAU,CAAC;KACtE;IACF;GACF,OAAO,IAAI,OAAO,UAAU;IAE1B,MAAM,OAAO,MAAM,MAAM,KAAK;IAC9B,IAAI,SAAS,KAAA,KAAa,SAAS,IAAI;KACrC,UAAU,KAAK,KAAK,EAAE,OAAO,cAAc,CAAC;KAC5C;IACF;IACA,IAAI;KACF,MAAM,SAAS,MAAM,kBAAkB,KAAK,QAAQ,SAAS,OAAO,WAAW,IAAI;KACnF,MAAM,OAAO,QAAQ,MAAM,MAAK,MAAK,EAAE,SAAS,IAAI;KACpD,IAAI,SAAS,KAAA,GAAW;MACtB,KAAK,cAAc;MACnB,KAAK,OAAO,eAAe,CAAC,EAAA,CAAG,SAAS,GAAG,KAAK,cAAc,OAAO;MACrE,IAAI,OAAO,cAAc,KAAA,GAAW,KAAK,YAAY,OAAO;KAC9D;KACA,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KAC3C,YAAY,OAAO,WAAW,OAAO;KACrC,UAAU,KAAK,KAAK;MAAE,OAAO,QAAQ;MAAO;KAAO,CAAyB;KAC5E;IACF,SAAS,OAAO;KACd,UAAU,KAAK,KAAK,EAAE,OAAO,UAAW,MAAgB,UAAU,CAAC;KACnE;IACF;GACF,OAAO,IAAI,OAAO,aAAa;IAE7B,MAAM,OAAO,MAAM,MAAM,KAAK;IAC9B,IAAI,SAAS,KAAA,KAAa,SAAS,IAAI;KACrC,UAAU,KAAK,KAAK,EAAE,OAAO,cAAc,CAAC;KAC5C;IACF;IACA,IAAI;KACF,MAAM,MAAM,MAAM,sBAAsB,KAAK,QAAQ,SAAS,IAAI;KAClE,MAAM,OAAO,QAAQ,MAAM,MAAK,MAAK,EAAE,SAAS,IAAI;KACpD,IAAI,SAAS,KAAA,GAAW,KAAK,YAAY;KACzC,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KAC3C,YAAY,OAAO,WAAW,OAAO;KACrC,UAAU,KAAK,KAAK;MAAE,OAAO,QAAQ;MAAO,WAAW;KAAI,CAAyB;KACpF;IACF,SAAS,OAAO;KACd,UAAU,KAAK,KAAK,EAAE,OAAO,WAAY,MAAgB,UAAU,CAAC;KACpE;IACF;GACF,OAAO;IACL,UAAU,KAAK,KAAK,EAAE,OAAO,eAAe,CAAC;IAC7C;GACF;GACA,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,OAAO,WAAW,OAAO;GAErC,UAAU,KAAK,KAAK,EADc,OAAO,QAAQ,MACtB,CAAC;EAC9B;CACF;;CAIA,MAAM,oBAA8B;EAClC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAE3B,MAAM,MAAK,MADQ,aAAqC,GAAG,EAAA,EAC1C;GACjB,IAAI,CAAC,OAAO,UAAU,EAAE,KAAK,OAAO,KAAA,KAAa,KAAK,GAAG;IACvD,UAAU,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;IAChD;GACF;GACA,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,EAAE;GACtD,IAAI,YAAY,KAAA,GAAW;IACzB,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,GAAG,QAAQ,CAAC;IAC/C;GACF;GACA,QAAQ,SAAS;GACjB,QAAQ,QAAQ,KAAA;GAChB,QAAQ,eAAe,KAAA;GACvB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,OAAO,WAAW,OAAO;GACrC,UAAU,KAAK,KAAK;IAAE,IAAI;IAAM;GAAG,CAAC;EACtC;CACF;;CAIA,MAAM,sBAAgC;EACpC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAE3B,MAAM,MAAK,MADQ,aAAqC,GAAG,EAAA,EAC1C;GACjB,IAAI,CAAC,OAAO,UAAU,EAAE,KAAK,OAAO,KAAA,KAAa,KAAK,GAAG;IACvD,UAAU,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;IAChD;GACF;GACA,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,EAAE;GACtD,IAAI,YAAY,KAAA,GAAW;IACzB,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,GAAG,QAAQ,CAAC;IAC/C;GACF;GACA,QAAQ,SAAS;GACjB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,OAAO,WAAW,OAAO;GACrC,UAAU,KAAK,KAAK;IAAE,IAAI;IAAM;GAAG,CAAC;EACtC;CACF;;CAIA,MAAM,sBAAgC;EACpC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAAqC,GAAG;;GAG3D,MAAM,SAAS,OAAO,YAAgD;IACpE,MAAM,cAAc,gBAAgB,OAAO,WAAW,OAAO;IAC7D,IAAI,gBAAgB,KAAA,GAAW,MAAM,IAAI,MAAM,MAAM,QAAQ,GAAG,UAAU;IAC1E,IAAI,WAAW;IACf,IAAI,QAAQ,KAAK,GAAG;KAClB,MAAM,OAAO,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,QAAQ,KAAK,CAAC;KAC/D,IAAI,SAAS,KAAA,GACX,YAAY,gBAAgB,OAAO,WAAW,IAAI,KAAK,GAAA,CAAI,QAAQ,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI;IAEtG;IACA,OAAO,oBAAoB,KAAK,QAAQ,SAAS,QAAQ,IAAI,aAAa,QAAQ;GACpF;GAGA,IAAI,OAAO,MAAM,cAAc,YAAY,KAAK,YAAY,GAAG;IAC7D,MAAM,UAAU,QAAQ,SAAS,MAAK,MAAK,EAAE,OAAO,KAAK,SAAS;IAClE,IAAI,YAAY,KAAA,GAAW;KACzB,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,KAAK,UAAU,QAAQ,CAAC;KAC3D;IACF;IACA,IAAI,QAAQ,WAAW,WAAW;KAChC,UAAU,KAAK,KAAK,EAAE,OAAO,gBAAgB,CAAC;KAC9C;IACF;IACA,IAAI;KACF,MAAM,SAAS,MAAM,OAAO,OAAO;KACnC,QAAQ,eAAe;KACvB,IAAI,OAAO,kBAAkB,KAAA,GAC3B,kBAAkB,SAAS,QAAQ,IAAI,OAAO,aAAa;KAE7D,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;KAC3C,YAAY,OAAO,WAAW,OAAO;KACrC,UAAU,KAAK,KAAK;MAAE,IAAI,QAAQ;MAAI;KAAO,CAAgD;KAC7F;IACF,SAAS,OAAO;KACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;KACvD;IACF;GACF;GAGA,MAAM,UAAU,QAAQ,SAAS,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,gBAAgB,EAAE,WAAW,WAAW,EAAE,iBAAiB,KAAA,CAAS;GACxJ,IAAI,QAAQ,WAAW,GAAG;IACxB,UAAU,KAAK,KAAK,EAAE,OAAO,EAAE,CAAC;IAChC;GACF;GACA,IAAI,UAAU,KAAK;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,mBAAmB;GACrB,CAAC;GACD,MAAM,QAAQ,UAA0B;IACtC,IAAI,MAAM,KAAK,UAAU,KAAK,IAAI,IAAI;GACxC;GACA,IAAI,OAAO;GACX,KAAK,MAAM,WAAW,SACpB,IAAI;IACF,MAAM,SAAS,MAAM,OAAO,OAAO;IACnC,QAAQ,eAAe;IACvB,IAAI,OAAO,kBAAkB,KAAA,GAC3B,kBAAkB,SAAS,QAAQ,IAAI,OAAO,aAAa;IAE7D;IACA,YAAY,OAAO,WAAW,OAAO;IACrC,KAAK;KAAE,MAAM;KAAiB,IAAI,QAAQ;KAAI;IAAO,CAAC;GACxD,SAAS,OAAO;IACd,QAAQ,KAAK,wCAAwC,QAAQ,GAAG,WAAY,MAAgB,OAAO;GACrG;GAEF,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,OAAO,WAAW,OAAO;GACrC,KAAK;IAAE,MAAM;IAAwB,OAAO;GAAK,CAAC;GAClD,IAAI,IAAI;EACV;CACF;CAGA,MAAM,cAAwB;EAC5B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,OAAO,MAAM,aAA0B,GAAG;GAChD,IAAI,SAAS,KAAA,GAAW;IACtB,UAAU,KAAK,KAAK,EAAE,OAAO,aAAa,CAAC;IAC3C;GACF;GACA,IAAI;IAEF,UAAU,KAAK,KAAK,EAAE,QAAQ,MADX,YAAY,IAAI,EACA,CAAC;GACtC,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;GACzD;EACF;CACF;CAGA,MAAM,kBAA4B;EAChC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAE9B,MAAM,MADS,UACE,CAAC,CAAC;GACnB,KAAK,aAAa,IAAI,QAAQ,MAAM,EAAE,EAAE,KAAK,UAAU;IACrD,IAAI,OACF,UAAU,KAAK,KAAK;KAAE,IAAI;KAAO,OAAO,MAAM;IAAQ,CAAC;SAEvD,UAAU,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;GAEpC,CAAC;EACH;CACF;;CAIA,MAAM,sBAAgC;EACpC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,OAAO,MAAM,aAAoC,GAAG;GAC1D,MAAM,OAAO,MAAM,MAAM,KAAK,KAAK;GACnC,IAAI,KAAK,SAAS,IAAI;IACpB,UAAU,KAAK,KAAK,EAAE,OAAO,sCAAsC,CAAC;IACpE;GACF;GACA,MAAM,QAAQ,MAAM,UAAU,KAAA,IAAY,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,KAAK,CAAC,CAAC,IAAI;GAC7F,MAAM,UAAU,MAAM,QAAQ,MAAM,OAAO,IAAI,KAAK,QAAQ,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC;GACrK,IAAI;IAGF,UAAU,KAAK,KAAK,EADuB,YAAA,MADlB,gBAAgB,KAAK,QAAQ,MAAM,OAAO,OAAO,EAE/C,CAAC;GAC9B,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAO,YAAa,MAAgB,UAAU,CAAC;GACvE;EACF;CACF;;CAIA,MAAM,iBAA2B;EAC/B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAA+B,GAAG;GACrD,IAAI;IAUF,UAAU,KAAK,KAAK,MATC,cACnB,KACA,QACA,SACA,OAAO,WACP,MAAM,SAAS,UACf,MAAM,UAAU,SAChB,MAAM,gBAAgB,GACxB,CACsD;GACxD,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAO,UAAW,MAAgB,UAAU,CAAC;GACrE;EACF;CACF;;CAIA,MAAM,cAAwB;EAC5B,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAA4B,GAAG;GAClD,IAAI,QAAQ,WAAW,KAAA,GAAW,QAAQ,SAAS,CAAC;GACpD,MAAM,KAAK,MAAM;GACjB,IAAI,OAAO,WACT,IAAI;IACF,MAAM,aAAa,MAAM,cAAc,KAAK,QAAQ,OAAO;IAC3D,UAAU,KAAK,KAAK;KAAE,QAAQ,QAAQ;KAAQ;IAAW,CAA0B;IACnF;GACF,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAO,UAAW,MAAgB,UAAU,CAAC;IACnE;GACF;QACK,KAAK,OAAO,WAAW,OAAO,aAAa,MAAM,UAAU,KAAA,GAAW;IAC3E,MAAM,IAAI,KAAK;IACf,MAAM,MAAM,QAAQ,OAAO,WAAU,MAAK,EAAE,SAAS,EAAE,IAAI;IAC3D,IAAI,QAAQ,IAAI,QAAQ,OAAO,KAAK,CAAC;SAChC,QAAQ,OAAO,OAAO;GAC7B,OAAO,IAAI,OAAO,YAAY,MAAM,SAAS,KAAA,GAC3C,QAAQ,SAAS,QAAQ,OAAO,QAAO,MAAK,EAAE,SAAS,KAAK,IAAI;QAC3D,IAAI,OAAO,SAAS;IACzB,MAAM,OAAO,MAAM,MAAM,KAAK;IAC9B,MAAM,UAAU,MAAM,SAAS,KAAK;IACpC,IAAI,SAAS,KAAA,KAAa,SAAS,MAAM,YAAY,KAAA,KAAa,YAAY,IAAI;KAChF,UAAU,KAAK,KAAK,EAAE,OAAO,wBAAwB,CAAC;KACtD;IACF;IACA,MAAM,QAAQ,QAAQ,OAAO,MAAK,MAAK,EAAE,SAAS,IAAI;IACtD,IAAI,UAAU,KAAA,GAAW;KACvB,UAAU,KAAK,KAAK,EAAE,OAAO,MAAM,KAAK,MAAM,CAAC;KAC/C;IACF;IACA,MAAM,QAAQ,MAAM,OAAO,KAAK,KAAK;IACrC,MAAM,YAAY,CAAC;IACnB,MAAM,UAAU,MAAM,QAAQ,QAAO,MAAK,EAAE,UAAU,KAAK;IAC3D,MAAM,QAAQ,KAAK;KAAE;KAAO;IAAQ,CAAC;GACvC,OAAO,IAAI,OAAO,eAAe;IAC/B,MAAM,OAAO,MAAM,MAAM,KAAK;IAC9B,MAAM,QAAQ,MAAM,OAAO,KAAK,KAAK;IACrC,MAAM,QAAQ,QAAQ,OAAO,MAAK,MAAK,EAAE,SAAS,IAAI;IACtD,IAAI,UAAU,KAAA,KAAa,UAAU,IACnC,MAAM,WAAW,MAAM,WAAW,CAAC,EAAA,CAAG,QAAO,MAAK,EAAE,UAAU,KAAK;GAEvE,OAAO;IACL,UAAU,KAAK,KAAK,EAAE,OAAO,QAAQ,KAAK,CAAC;IAC3C;GACF;GACA,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,YAAY,OAAO,WAAW,OAAO;GACrC,UAAU,KAAK,KAAK,EAAE,QAAQ,QAAQ,OAAO,CAA0B;EACzE;CACF;;CAIA,MAAM,mBAA6B;EACjC,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,OAAO,KAAK,QAAQ;GAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;GAC9B,MAAM,SAAS,UAAU;GACzB,MAAM,UAAU,eAAe,GAAG;GAClC,IAAI,YAAY,KAAA,GAAW;GAC3B,MAAM,OAAO,MAAM,aAAiC,GAAG;GACvD,IAAI,MAAM,OAAO,WACf,IAAI;IACF,MAAM,QAAQ,MAAM,mBAAmB,KAAK,QAAQ,OAAO;IAC3D,QAAQ,cAAc;IACtB,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IAC3C,YAAY,OAAO,WAAW,OAAO;IACrC,UAAU,KAAK,KAAK,EAAE,MAAM,CAA+B;IAC3D;GACF,SAAS,OAAO;IACd,UAAU,KAAK,KAAK,EAAE,OAAO,YAAa,MAAgB,UAAU,CAAC;IACrE;GACF;QACK,IAAI,MAAM,OAAO,UAAU,MAAM,QAAQ,KAAK,KAAK,GAAG;IAC3D,QAAQ,cAAc,KAAK,MAAM,QAAO,MAAK,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE;IAClI,QAAQ,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;IAC3C,YAAY,OAAO,WAAW,OAAO;IACrC,UAAU,KAAK,KAAK,EAAE,OAAO,QAAQ,YAAY,CAA+B;IAChF;GACF;GACA,UAAU,KAAK,KAAK,EAAE,OAAO,uBAAuB,CAAC;EACvD;CACF;;CAIA,MAAM,SAAS,IAAI,iBAAiB;EAAE;EAAK;CAAU,CAAC;CAiEtD,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;GA9GA,MAAM;GACN,MAAM,UAAU;GAChB,SAAS,OAAO,KAAK,QAAQ;IAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;IAC9B,MAAM,OAAO,MAAM,aAA8B,GAAG;IAEpD,MAAM,UAAU,YADD,UACkB,CAAC,CAAC,SAAS;IAC5C,IAAI,YAAY,KAAA,GAAW;KACzB,UAAU,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;KAC1C;IACF;IACA,MAAM,UAAU,OAAO,UAAU,MAAM,OAAO,KAAM,KAAM,WAAY,IAAK,KAAM,UAAW;IAC5F,IAAI;IACJ,IAAI,OAAO,UAAU,MAAM,KAAK,KAAM,KAAM,SAAU,SACpD,QAAQ,KAAM;SACT,IAAI,OAAO,UAAU,MAAM,KAAK,KAAM,KAAM,SAAU,KAAO,KAAM,SAAU,KAElF,QADa,KAAK,IAAI,GAAG,GAAG,QAAQ,SAAS,KAAI,MAAK,EAAE,EAAE,CAC/C,IAAI,KAAM;SAChB;KACL,UAAU,KAAK,KAAK,EAAE,OAAO,2BAA2B,CAAC;KACzD;IACF;IACA,IAAI;KAEF,UAAU,KAAK,KAAK,MADA,OAAO,MAAM,SAAS,KAAK,CACH;IAC9C,SAAS,OAAO;KACd,UAAU,KAAK,KAAK,EAAE,OAAQ,MAAgB,QAAQ,CAAC;IACzD;GACF;EAkFY;EACZ;GA/EA,MAAM;GACN,MAAM,UAAU;GAChB,SAAS,OAAO,KAAK,QAAQ;IAC3B,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG;IAC9B,MAAM,OAAO,MAAM,aAAgC,GAAG;IAEtD,IADc,OAAO,OACb,MAAM,MAAM;KAClB,UAAU,KAAK,KAAK,EAAE,OAAO,QAAQ,CAAC;KACtC;IACF;IACA,IAAI,MAAM,WAAW,SAAS,OAAO,MAAM;SACtC,IAAI,MAAM,WAAW,UAAU,OAAO,OAAO;SAC7C,IAAI,MAAM,WAAW,QAAQ,OAAO,KAAK;SACzC;KACH,UAAU,KAAK,KAAK,EAAE,OAAO,kCAAkC,CAAC;KAChE;IACF;IACA,UAAU,KAAK,KAAK,OAAO,OAAO,CAAC;GACrC;EA6Dc;EACd;GA1DA,MAAM;GACN,MAAM,UAAU;GAChB,UAAU,KAAK,QAAQ;IACrB,IAAI,CAAC,MAAM,KAAK,KAAK,KAAK,GAAG;IAC7B,UAAU,KAAK,KAAK,OAAO,OAAO,CAAC;GACrC;EAqDa;CACf;AACF;;;;AC9rEA,MAAa,OAAO;;AAGpB,MAAa,SAAS;CAAC;CAAa;CAAO;AAAc;;;;;;AAOzD,MAAa,2BAA2B,kBAAkB,iBAAiB;AAsC3E,MAAa,SAAoB,EAAE,OAAO;CACxC,iBAAiB,EAAE,QAAQ,CAAC,CAAC,QAAQ,IAAI;CACzC,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,IAAI;CACjC,aAAa,EAAE,OAAO,CAAC,CAAC,QAAQ,6DAA6D;CAC7F,WAAW,EAAE,OAAO,CAAC,CAAC,QAAQ,sCAAsC;CACpE,UAAU,EAAE,OAAO,CAAC,CAAC,QAAQ,mBAAmB;CAChD,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,mBAAmB;CAC7C,iBAAiB,EAAE,MAAM;EAAC;EAAO;EAAO;EAAQ;CAAK,CAAC,CAAC,CAAC,QAAQ,KAAK;CACrE,cAAc,EAAE,OAAO,CAAC,CAAC,QAAQ,IAAI;CACrC,WAAW,EAAE,OAAO,CAAC,CAAC,QAAQ,IAAK;CACnC,iBAAiB,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE;CACtC,YAAY,EAAE,QAAQ,CAAC,CAAC,QAAQ,IAAI;CACpC,kBAAkB,EAAE,QAAQ,CAAC,CAAC,QAAQ,IAAI;CAC1C,uBAAuB,EAAE,QAAQ,CAAC,CAAC,QAAQ,IAAI;CAC/C,aAAa,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE;CAClC,eAAe,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE;CACpC,iBAAiB,EAAE,QAAQ,CAAC,CAAC,QAAQ,KAAK;AAC5C,CAAC;;AAGD,MAAM,mBAAmB;AACzB,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB;AAC3B,MAAM,mBAAmB;AACzB,MAAM,gBAAgB;AACtB,MAAM,2BAA2B;AACjC,MAAM,wBAAwB;AAC9B,MAAM,qBAAqB;AAC3B,MAAM,4BAA4B;AAClC,MAAM,sBAAsB;AAC5B,MAAM,6BAA6B;AACnC,MAAM,mCAAmC;;AAGzC,MAAM,gBAAgB;;AAGtB,MAAa,iBAAiB;;AAG9B,SAAgB,cAAc,OAAiD;CAC7E,OAAO;EACL,aAAa,OAAO,eAAe;EACnC,WAAW,OAAO,aAAa;EAC/B,UAAU,OAAO,YAAY;EAC7B,OAAO,OAAO,SAAS;EACvB,iBAAiB,OAAO,mBAAmB;EAC3C,cAAc,OAAO,gBAAgB;EACrC,WAAW,OAAO,aAAa;EAC/B,iBAAiB,OAAO,mBAAmB;EAC3C,YAAY,OAAO,cAAc;EACjC,kBAAkB,OAAO,oBAAoB;EAC7C,uBAAuB,OAAO,yBAAyB;EACvD,aAAa,OAAO;EACpB,eAAe,OAAO;EACtB,iBAAiB,OAAO,mBAAmB;CAC7C;AACF;;;;;;AAOA,SAAgB,MAAM,KAAc,QAAuB;CAGzD,IAAI,gBAA8B,UAAU,CAAC;CAC7C,MAAM,gBAA6B;EACjC,MAAM,WAAW,cAAc,QAAQ,CAAC;EAExC,MAAM,WAAW,oBAAoB;EACrC,IAAI,aAAa,KAAA,GACf,OAAO;GAAE,GAAG;GAAU,WAAW;EAAS;EAE5C,OAAO;CACT;CAEA,MAAM,cAAc,OAAO,UAA6C;EACtE,MAAM,OAAoB,CAAC;EAC3B,IAAI,MAAM,gBAAgB,KAAA,GAAW,KAAK,cAAc,MAAM;EAC9D,IAAI,MAAM,cAAc,KAAA,GAAW,KAAK,YAAY,MAAM;EAC1D,IAAI,MAAM,aAAa,KAAA,GAAW,KAAK,WAAW,MAAM;EACxD,IAAI,MAAM,UAAU,KAAA,GAAW,KAAK,QAAQ,MAAM;EAClD,IAAI,MAAM,oBAAoB,KAAA,GAAW,KAAK,kBAAkB,MAAM;EACtE,IAAI,MAAM,iBAAiB,KAAA,GAAW,KAAK,eAAe,MAAM;EAChE,IAAI,MAAM,cAAc,KAAA,GAAW,KAAK,YAAY,MAAM;EAC1D,IAAI,MAAM,oBAAoB,KAAA,GAAW,KAAK,kBAAkB,MAAM;EACtE,IAAI,MAAM,eAAe,KAAA,GAAW,KAAK,aAAa,MAAM;EAC5D,IAAI,MAAM,qBAAqB,KAAA,GAAW,KAAK,mBAAmB,MAAM;EACxE,IAAI,MAAM,0BAA0B,KAAA,GAAW,KAAK,wBAAwB,MAAM;EAClF,IAAI,MAAM,gBAAgB,KAAA,GAAW,KAAK,cAAc,MAAM;EAC9D,IAAI,MAAM,kBAAkB,KAAA,GAAW,KAAK,gBAAgB,MAAM;EAClE,IAAI,MAAM,oBAAoB,KAAA,GAAW,KAAK,kBAAkB,MAAM;EAItE,MAAM,WAAW,IAAI,IAAI,UAAU;EACnC,IAAI,aAAa,KAAA,GACf,MAAM,SAAS,OAAO,0BAA0B,IAA+B;OAE/E,iBAAiB;GAAE,GAAG,QAAQ;GAAG,GAAG;EAAK;EAE3C,OAAO,QAAQ;CACjB;CAEA,IAAI;CACJ,IAAI;CAEJ,MAAM,aAAmB;EACvB,IAAI,mBAAmB,KAAA,GAAW;GAChC,eAAe;GACf,iBAAiB,KAAA;EACnB;EACA,IAAI,kBAAkB,KAAA,GAAW;GAC/B,cAAc;GACd,gBAAgB,KAAA;EAClB;EACc,QAAQ;EACtB,IAAI,EAAE,QAAQ,CAAC,CAAC,WAAW,OAAO;EAClC,IAAI,QAAQ,CAAC,CAAC,mBAAmB,kBAC/B,iBAAiB,IAAI,aAAa,QAAQ;GACxC,MAAM;GACN,OAAO;GACP,MAAM;EACR,CAAC;EAEH,MAAM,SAAS,WAAW;GAAE;GAAK,WAAW;GAAS;EAAY,CAAC;EAClE,gBAAgB,IAAI,aACZ;GACJ,MAAM,YAAY,OAAO,KAAI,UAAS,IAAI,UAAU,SAAS,KAAK,CAAC;GACnE,aAAa;IAAE,KAAK,MAAM,WAAW,WAAW,QAAQ;GAAE;EAC5D,GACA,yBACF;CAEF;CAEA,uBAAuB,KAAK,0BAA0B,QAAQ,UAAU,CAAC,GAAG;EAC1E,YAAY,WAAW;GACrB,UAAU;GACV,KAAK;EACP;EACA,UAAU;CACZ,CAAC;CAID,MAAM,gBAAgB,IAAI,IAAI,QAAQ;CACtC,IAAI,eAAe,aAAa,KAAA,GAAW;EACzC,MAAM,eAAe,cAAc,SAAS;GAC1C,MAAM;GACN,aAAa;GACb,SAAS;IACP;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACF,CAAC,CAAC,KAAK,IAAI;EACb,CAAC;EACD,IAAI,aAAa,cAAc,wBAAwB;CACzD;CAGA,KAAK;AACP"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/assets.ts","../src/comic-presets.ts","../src/engine.ts","../src/bookshelf.ts","../src/run.ts","../src/protocol.ts","../src/docx.ts","../src/assistant.ts","../src/routes.ts","../src/index.ts"],"sourcesContent":["/**\n * Writing assets — 题材基底库 / 推进模式库 / 反 AI 规则 / 写法引擎.\n *\n * Ported from AI-Novel-Writing-Assistant (Apache-2.0) built-in seed data:\n * - 8 preset style templates (DEFAULT_STYLE_TEMPLATES)\n * - 12 anti-AI rules with concrete detect patterns (DEFAULT_ANTI_AI_RULES)\n * - genre tree + progression mode seeds\n * Assets persist with the project (novel-project.json) and are injected into\n * generation / planning / review prompts, and available to the AI assistant.\n */\n\nimport type { AntiAiRule, GenreNode, ProgressionMode, ProjectAssets, StyleAsset, StyleTemplate } from './protocol.ts'\n\n// ------------------------------------------------------ built-in style templates\n\n/** 预置写法模板(来自 AI-Novel-Writing-Assistant 内置 DEFAULT_STYLE_TEMPLATES)。 */\nexport const BUILTIN_STYLE_TEMPLATES: StyleTemplate[] = [\n {\n key: 'power-up-escalation',\n name: '爽文递进推进流',\n description: '持续升级冲突和收益点,强化目标推进与爽点兑现。',\n category: '爽文流',\n applicableGenres: ['都市', '玄幻', '热血'],\n proseRules: [\n '围绕目标推进,尽快兑现局部收益;每段都要有目标推进或爽点兑现。',\n '保持明确因果和节奏抬升,场景单元按「目标→阻碍→压制→反转收益」推进。',\n '优先冲突和结果,少停留;段尾用钩子收束。',\n ],\n dialogueRules: [\n '角色表达直接,情绪跟随胜负切换。',\n '对话承担推进与信息功能,但保留角色自己的语气差异。',\n ],\n languageRules: [\n '句式清晰,减少无效分散信息。',\n '直接、明确,不做无谓铺垫。',\n ],\n rhythmRules: [\n '快节奏,段落密度中等,动作先于解释。',\n '尽快兑现局部收益,避免拖沓。',\n ],\n defaultAntiAiRuleKeys: ['禁止总结主题', '对话纯功能推进', '连续三段解释性叙事'],\n },\n {\n key: 'bottom-loop-reality',\n name: '底层循环现实流',\n description: '通过碎片化生活与反复落空表现人物困境。',\n category: '现实流',\n applicableGenres: ['都市', '现实', '成长'],\n proseRules: [\n '以时间推进和现实落差构成叙事张力,结尾不解决核心困境。',\n '场景单元按「行为→落差→自我合理化」推进。',\n '以碎片化生活推进,不做总括式回顾。',\n ],\n dialogueRules: [\n '人物情绪通过动作和嘴硬表达,允许短促口语化台词。',\n '对话保留生活杂音与无效信息。',\n ],\n languageRules: [\n '语言粗粝、口语化,允许生活杂音与不完整句。',\n '句子变化度高,允许无意义细节。',\n ],\n rhythmRules: [\n '段落密实,动作先于解释。',\n '中快节奏,允许碎片化流动。',\n ],\n defaultAntiAiRuleKeys: ['禁止解释型心理描写', '禁止段尾升华', '鼓励无意义小动作', '鼓励现实落差', '鼓励嘴硬补偿'],\n },\n {\n key: 'suspense-pressure',\n name: '悬疑压迫递增流',\n description: '通过信息遮蔽、细节异常和压力叠加制造不安感。',\n category: '悬疑流',\n applicableGenres: ['悬疑', '惊悚', '现实'],\n proseRules: [\n '以异常细节、信息差和节奏收束推动悬念层层加压。',\n '场景单元按「现场细节→异常→误判→新风险」推进。',\n '优先制造信息缺口和压迫氛围。',\n ],\n dialogueRules: [\n '角色反应克制,恐惧通过反应显现。',\n '对话保留克制感,不解释恐惧来源。',\n ],\n languageRules: [\n '细节精确,保留少量噪音增强现场感。',\n '克制、中等偏高句变化。',\n ],\n rhythmRules: [\n '通过节奏收束和信息延迟制造压力。',\n '中速,段落密度中等偏高。',\n ],\n defaultAntiAiRuleKeys: ['禁止解释型心理描写', '禁止总结主题', '段落长度过于整齐', '鼓励现实落差'],\n },\n {\n key: 'emotional-tension',\n name: '情绪拉扯流',\n description: '通过错位表达、停顿和误读制造关系张力。',\n category: '情感流',\n applicableGenres: ['言情', '都市', '群像'],\n proseRules: [\n '人物不直说核心情绪,靠误读、停顿和反应推动关系变化。',\n '场景单元按「动作→言外之意→误读→回避」推进。',\n '以关系错位推进,而非直接说明。',\n ],\n dialogueRules: [\n '情绪通过停顿、动作和言外之意体现。',\n '对话充满潜台词与试探。',\n ],\n languageRules: [\n '语言自然,允许留白与停顿。',\n '句子变化度高,允许无意义细节。',\n ],\n rhythmRules: [\n '给关系反应留空间,但避免空洞抒情。',\n '中慢节奏,段落密度中等。',\n ],\n defaultAntiAiRuleKeys: ['禁止直接说教', '禁止段尾升华', '对话纯功能推进', '鼓励无意义小动作'],\n },\n {\n key: 'ensemble-weave',\n name: '群像交织流',\n description: '以多人行动线和视角差异交织推进事件。',\n category: '群像流',\n applicableGenres: ['群像', '都市', '悬疑'],\n proseRules: [\n '多角色并行推进,但每个角色的表达和认知范围必须区分清楚。',\n '多线并进,但视角切换要受控。',\n ],\n dialogueRules: [\n '不同角色口吻必须拉开差异,避免所有人说话一样。',\n ],\n languageRules: [\n '保持角色差异,句式变化度高。',\n '减少无效分散信息。',\n ],\n rhythmRules: [\n '多线交织但节奏不乱,平衡推进。',\n '动作先于解释。',\n ],\n defaultAntiAiRuleKeys: ['对话纯功能推进', '句式重复率过高', '禁止总结主题'],\n },\n {\n key: 'immersive-daily',\n name: '日常浸没流',\n description: '通过生活细节和细微情绪变化建立持续沉浸感。',\n category: '日常流',\n applicableGenres: ['日常', '治愈', '都市'],\n proseRules: [\n '重场景体验和关系温度,核心情绪通过场景自然流出。',\n '允许保留生活性动作和无效信息。',\n ],\n dialogueRules: [\n '人物表达自然,不用高强度戏剧句。',\n '对话保留生活气息。',\n ],\n languageRules: [\n '保留生活细节和杂音,不追求工整。',\n '口语化,句子变化中等偏高。',\n ],\n rhythmRules: [\n '慢节奏沉浸,但避免空转。',\n '允许碎片化流动。',\n ],\n defaultAntiAiRuleKeys: ['禁止段尾升华', '段落长度过于整齐', '鼓励无意义小动作'],\n },\n {\n key: 'cold-professional',\n name: '冷峻专业流',\n description: '以专业事实和行业细节压住情绪,形成克制压力感。',\n category: '专业流',\n applicableGenres: ['职场', '现实', '悬疑'],\n proseRules: [\n '行业事实和程序细节优先,情绪不直说,信息密度高于抒情密度。',\n '场景单元按「事实→动作→专业判断→后果」推进。',\n '让专业事实承担叙事重量。',\n ],\n dialogueRules: [\n '情绪藏在专业动作和事实选择里。',\n '对话以信息性表达为主,克制。',\n ],\n languageRules: [\n '术语和事实优先,避免廉价金句。',\n '正式、克制的语言。',\n ],\n rhythmRules: [\n '信息密度高,但不铺张解释。',\n '平衡节奏,段落密度中等偏高。',\n ],\n defaultAntiAiRuleKeys: ['禁止直接说教', '禁止总结主题', '句式重复率过高'],\n },\n {\n key: 'absurd-dark-humor',\n name: '荒诞黑色幽默流',\n description: '通过反差、冷感观察和荒诞细节制造黑色幽默。',\n category: '黑色幽默',\n applicableGenres: ['都市', '黑色幽默', '现实'],\n proseRules: [\n '用反差和荒诞细节放大现实困境,笑点和压迫感同时存在。',\n '场景单元按「现实细节→荒诞偏差→冷反应」推进。',\n '依赖反差和冷感观察,而非热闹吐槽。',\n ],\n dialogueRules: [\n '情绪藏在冷反应和嘴硬里。',\n '台词冷面、口语化,允许自嘲与转移。',\n ],\n languageRules: [\n '允许夹带荒诞杂质和冷幽默节奏。',\n '口语化,句子变化度高。',\n ],\n rhythmRules: [\n '反差点要快落地,不要解释笑点。',\n '平衡节奏,段落密度中等偏高。',\n ],\n defaultAntiAiRuleKeys: ['禁止解释型心理描写', '禁止段尾升华', '鼓励现实落差', '鼓励嘴硬补偿'],\n },\n]\n\n// ---------------------------------------------------------- built-in rules\n\n/** 内置全局反 AI 规则(来自 AI-Novel-Writing-Assistant 内置 DEFAULT_ANTI_AI_RULES)。 */\nexport const BUILTIN_ANTI_AI_RULES: AntiAiRule[] = [\n {\n name: '禁止解释型心理描写',\n avoid: '直接使用\"他感到\"\"他意识到\"\"他明白了\"等句式解释人物心理。',\n fix: '把心理解释改成动作、语气、停顿、环境反应或结果。',\n detectPatterns: ['他感到', '她感到', '他意识到', '她意识到', '他明白了', '她明白了'],\n builtin: true,\n },\n {\n name: '禁止段尾升华',\n avoid: '在段尾或收尾处用总结句升华主题(如\"生活就是\"\"命运总会\"\"说到底\")。',\n fix: '删除升华句,回到具体动作、现场或悬而未决的处境。',\n detectPatterns: ['生活就是', '命运总会', '归根结底', '说到底', '这就是'],\n builtin: true,\n },\n {\n name: '禁止总结主题',\n avoid: '把段落写成总结中心思想或提炼人生道理(如\"这说明\"\"这意味着\")。',\n fix: '删掉主题总结,让信息通过事件和结果自然显现。',\n detectPatterns: ['这说明', '这意味着', '归根结底', '其实就是'],\n builtin: true,\n },\n {\n name: '禁止直接说教',\n avoid: '作者替角色或读者做直接价值判断和说教(如\"我们都应该\"\"人总要学会\")。',\n fix: '改成角色具体处境或对话,不做抽象说教。',\n detectPatterns: ['我们都应该', '人总要学会', '真正重要的是'],\n builtin: true,\n },\n {\n name: '段落长度过于整齐',\n avoid: '段落长度和节奏过于平均,产生 AI 作文感。',\n fix: '打破段落长度均衡,让句子和段落有自然起伏。',\n detectPatterns: [],\n builtin: true,\n },\n {\n name: '连续三段解释性叙事',\n avoid: '连续几段只有解释没有动作,削弱现场感。',\n fix: '插入动作、对话、环境反馈,减少连段说明。',\n detectPatterns: [],\n builtin: true,\n },\n {\n name: '对话纯功能推进',\n avoid: '对话只有信息推进,没有人物语气和生活噪音(如\"告诉你\"\"我们现在要\")。',\n fix: '补入停顿、绕弯、语气差异和无效信息。',\n detectPatterns: ['告诉你', '我们现在要', '接下来就'],\n builtin: true,\n },\n {\n name: '句式重复率过高',\n avoid: '连续句式过于整齐(如\"首先\"\"然后\"\"接着\"\"最后\"),显得机械。',\n fix: '拉开句式长度和起句方式,打散结构。',\n detectPatterns: ['首先', '然后', '接着', '最后'],\n builtin: true,\n },\n {\n name: 'AI 高频套话',\n avoid: '滥用\"不禁\"\"仿佛\"\"一时间\"\"不由得\"\"顿时\"\"然而\"\"缓缓\"\"轻轻\"\"微微\"\"似乎\"\"终于\"等模式词及套路比喻。',\n fix: '用具体、有画面感的表达替换套话;每个比喻都应当是新造的。',\n detectPatterns: ['不禁', '仿佛', '一时间', '不由得', '顿时', '缓缓', '轻轻', '微微'],\n builtin: true,\n },\n {\n name: '鼓励无意义小动作',\n avoid: '(鼓励类)全篇缺少真实但不推动主线的小动作,人物显得空洞。',\n fix: '补入挠头、点烟、抠包装、挪椅子等小动作,增加人味与生活感。',\n detectPatterns: [],\n builtin: true,\n },\n {\n name: '鼓励现实落差',\n avoid: '(鼓励类)人物预期和现实结果完全一致,缺少落差。',\n fix: '补出人物预期与实际结果之间的差距,制造张力。',\n detectPatterns: [],\n builtin: true,\n },\n {\n name: '鼓励嘴硬补偿',\n avoid: '(鼓励类)人物吃瘪后没有维持体面的反应。',\n fix: '给角色补一句嘴硬找补或自我合理化,保持人设温度。',\n detectPatterns: [],\n builtin: true,\n },\n]\n\n/** 内置题材基底库(常用网文题材树,跨书复用)。 */\nexport const BUILTIN_GENRE_LIBRARY: GenreNode[] = [\n {\n name: '仙侠修真',\n description: '以修仙境界、宗门斗争、法宝丹药为核心,读者期待从凡人到强者的成长与长生问道。',\n children: [\n { name: '凡人流', description: '资质平凡、步步为营,靠资源积累与心机博弈逆袭,强调真实感与代入感。', children: [] },\n { name: '苟道流', description: '主角苟且发育、藏锋敛芒,坐收渔利,强调生存智慧与反差爽点。', children: [] },\n { name: '争霸流', description: '宗门、王朝或大陆争锋,主角由弱到强整合势力,强调格局与权谋。', children: [] },\n ],\n },\n {\n name: '都市异能',\n description: '现代都市背景叠加超能力,读者期待隐藏身份、扮猪吃虎与日常反差。',\n children: [\n { name: '异能升级', description: '觉醒超能力后不断变强,隐藏于都市,遇敌碾压。', children: [] },\n { name: '重生复仇', description: '重生回到过去,利用先知先觉改变命运、清算仇敌。', children: [] },\n { name: '商业经营', description: '以超能力或见识经商扩张,建立商业帝国,强调经营爽感。', children: [] },\n ],\n },\n {\n name: '悬疑推理',\n description: '以谜题、案件与真相揭露为核心,读者期待线索层层展开与反转。',\n children: [\n { name: '本格推理', description: '公平线索、逻辑推演,读者可与主角一同解谜。', children: [] },\n { name: '刑侦探案', description: '警察或侦探视角连续破案,案件串联主线,强调现实与人性。', children: [] },\n { name: '无限流', description: '主角穿梭于不同副本世界解谜求生,副本之间累积成长。', children: [] },\n ],\n },\n {\n name: '玄幻奇幻',\n description: '异世界或架空大陆的冒险成长,读者期待宏大世界观、奇遇与战力突破。',\n children: [\n { name: '学院流', description: '入学修炼、同窗竞争、大赛扬名,强调青春感与阶梯式打脸。', children: [] },\n { name: '废柴逆袭', description: '开局废柴受辱,觉醒金手指后一路逆袭打脸,强调反差与爽点。', children: [] },\n { name: '诸天万界', description: '穿越诸天世界收集资源与能力,强调世界多样性与成长曲线。', children: [] },\n ],\n },\n {\n name: '历史军事',\n description: '以历史时代为背景的争霸、谋略或军旅故事,读者期待权谋博弈与时代质感。',\n children: [\n { name: '王朝争霸', description: '乱世崛起、招贤纳士、逐鹿天下,强调战略与人心。', children: [] },\n { name: '穿越种田', description: '穿越古代发展生产、经营家族,强调建设感与生活细节。', children: [] },\n ],\n },\n {\n name: '末世科幻',\n description: '末世危机或科幻设定下的生存与重建,读者期待资源管理、危机升级与人性考验。',\n children: [\n { name: '基地经营', description: '建立基地、收集资源、抵御危机,强调建设与扩张。', children: [] },\n { name: '进化觉醒', description: '末世异变中觉醒能力不断进化,强调战力成长与危机求生。', children: [] },\n ],\n },\n]\n\n/** 内置常用推进模式。 */\nexport const BUILTIN_PROGRESSION_MODES: ProgressionMode[] = [\n {\n name: '升级变强',\n driver: '主角的实力、境界或能力持续增长,读者期待每次突破带来的碾压与认可。',\n readerExpectation: '每隔几章有一次明确的实力提升或打脸兑现;大境界突破要有仪式感。',\n payoffs: ['突破境界', '学会新技能', '越级战胜强敌', '当众打脸质疑者'],\n risks: ['升级重复套路', '战力膨胀失控', '无铺垫强行突破'],\n primary: false,\n },\n {\n name: '经营扩张',\n driver: '主角的产业、势力或领地不断扩张,资源复利滚雪球。',\n readerExpectation: '经营投入有可感知的回报,扩张遇到新挑战并解决。',\n payoffs: ['新产业上线', '规模翻倍', '吞并对手', '资源闭环成型'],\n risks: ['过程枯燥', '扩张无阻力', '数值失衡'],\n primary: false,\n },\n {\n name: '解谜揭露',\n driver: '主线谜团(身世、阴谋、世界观真相)持续牵引读者,每揭开一层又引出更深一层。',\n readerExpectation: '定期有真相碎片放出,回收旧伏笔、埋设新伏笔。',\n payoffs: ['伏笔回收', '身份揭露', '阴谋浮出水面', '反转打脸'],\n risks: ['谜题拖太久', '伏笔忘记回收', '反转生硬'],\n primary: false,\n },\n {\n name: '渔翁得利',\n driver: '强敌相互厮杀,主角躲在暗处观察、收割,风险由他人承担、果实由主角获取。',\n readerExpectation: '冲突升级时主角以最小代价获取最大收益,且不暴露自身。',\n payoffs: ['坐收渔利', '捡漏宝物', '敌人两败俱伤', '信息差获利'],\n risks: ['重复套路', '收割太轻易', '主角全程无风险'],\n primary: false,\n },\n {\n name: '关系拉扯',\n driver: '人物关系(知己、对手、师徒、情感线)的张力与变化持续推动剧情。',\n readerExpectation: '关系有进有退、有误会与和解,情绪起伏带动阅读欲。',\n payoffs: ['关系升温', '信任建立', '背叛与挽回', '并肩作战'],\n risks: ['情感线停滞', '工业糖精', '为虐而虐'],\n primary: false,\n },\n]\n\n// ------------------------------------------------------------- persistence\n\n/** 默认(空)项目写作资产。 */\nexport function emptyProjectAssets(): ProjectAssets {\n return {\n auxiliaryProgressions: [],\n antiAiRules: [],\n styleAssets: [],\n }\n}\n\n/** 合并项目资产与内置库:返回「生效的反 AI 规则」(内置全局 + 项目自定义)。 */\nexport function effectiveAntiAiRules(assets: ProjectAssets | undefined): AntiAiRule[] {\n const custom = assets?.antiAiRules ?? []\n const customNames = new Set(custom.map(r => r.name))\n return [...BUILTIN_ANTI_AI_RULES.filter(r => !customNames.has(r.name)), ...custom]\n}\n\n/** 把生效规则渲染成提示词块(压缩:avoid/fix 截断,省 token)。 */\nexport function renderAntiAiRules(assets: ProjectAssets | undefined): string {\n const rules = effectiveAntiAiRules(assets)\n if (rules.length === 0) return ''\n const clip = (value: string, max: number): string => value.length > max ? value.slice(0, max) + '…' : value\n return [\n '==================== 反 AI 规则(写作时必须遵守的表达边界) ====================',\n ...rules.map(r => `- ${r.name}:避免——${clip(r.avoid, 90)}${r.fix !== '' ? `;修正——${clip(r.fix, 50)}` : ''}`),\n ].join('\\n')\n}\n\n/** 渲染题材与推进模式提示词块。 */\nexport function renderGenreAndProgression(assets: ProjectAssets | undefined): string {\n const sections: string[] = []\n if (assets?.genre !== undefined) {\n sections.push('==================== 题材基底(本书的题材定位与读者期待) ====================')\n sections.push(`题材:${assets.genre.name}`)\n if (assets.genre.description !== '') sections.push(`读者期待:${assets.genre.description}`)\n const walk = (node: GenreNode, depth: number): void => {\n for (const child of node.children) {\n sections.push(`${' '.repeat(depth)}- ${child.name}:${child.description}`)\n walk(child, depth + 1)\n }\n }\n walk(assets.genre, 1)\n }\n const modes = [\n ...(assets?.primaryProgression !== undefined ? [assets.primaryProgression] : []),\n ...(assets?.auxiliaryProgressions ?? []),\n ]\n if (modes.length > 0) {\n sections.push('==================== 推进模式(读者为什么继续看) ====================')\n for (const mode of modes) {\n const tag = mode.primary ? '(主推进)' : '(辅助)'\n sections.push(`- 模式「${mode.name}」${tag}:驱动力——${mode.driver}`)\n sections.push(` 读者期待:${mode.readerExpectation}`)\n if (mode.payoffs.length > 0) sections.push(` 常见兑现:${mode.payoffs.join('、')}`)\n if (mode.risks.length > 0) sections.push(` 节奏风险(避免):${mode.risks.join('、')}`)\n }\n }\n return sections.join('\\n')\n}\n\n/** 渲染写法资产提示词块(规则去重,省 token)。 */\nexport function renderStyleAssets(assets: ProjectAssets | undefined): string {\n const styles = assets?.styleAssets ?? []\n if (styles.length === 0) return ''\n const sections: string[] = ['==================== 写法资产(本书的叙事风格约束) ====================']\n for (const style of styles) {\n sections.push(`【${style.name}】`)\n const unique = (rules: string[]): string[] => [...new Set(rules)]\n if (style.proseRules.length > 0) sections.push('叙述与节奏:\\n' + unique(style.proseRules).map(r => `- ${r}`).join('\\n'))\n if (style.dialogueRules.length > 0) sections.push('台词风格:\\n' + unique(style.dialogueRules).map(r => `- ${r}`).join('\\n'))\n if (style.descriptionRules.length > 0) sections.push('描写与情绪:\\n' + unique(style.descriptionRules).map(r => `- ${r}`).join('\\n'))\n if (style.boundaries.length > 0) sections.push('表达边界:\\n' + unique(style.boundaries).map(r => `- ${r}`).join('\\n'))\n }\n return sections.join('\\n')\n}\n\n/** 渲染全部写作资产提示词(供生成/规划/审稿注入)。 */\nexport function renderAllAssets(assets: ProjectAssets | undefined): string {\n const parts = [\n renderGenreAndProgression(assets),\n renderStyleAssets(assets),\n renderAntiAiRules(assets),\n ].filter(part => part !== '')\n return parts.join('\\n\\n')\n}\n\n/** 预置写法模板 → 可直接绑定的 StyleAsset。 */\nexport function styleTemplateToAsset(template: StyleTemplate): StyleAsset {\n return {\n name: template.name,\n proseRules: [...template.proseRules, ...template.rhythmRules.map(r => `节奏:${r}`)],\n dialogueRules: template.dialogueRules,\n descriptionRules: template.languageRules,\n boundaries: [`模板「${template.name}」适用题材:${template.applicableGenres.join('、')}`, '不要违背模板的叙事单元结构与节奏约束'],\n createdAt: new Date().toISOString(),\n }\n}\n\n// ------------------------------------------------------- style extraction\n\n/** 写法引擎:从样本文本提取风格资产的系统提示词。 */\nexport function styleEngineSystemPrompt(): string {\n return [\n '你是一位资深网文文风分析师。你会收到一段样本文本,请提炼出可复用的叙事风格规则,供后续章节保持同一种味道。',\n '要求:',\n '1. 从样本中归纳,不要泛泛而谈;每条规则都要能落到具体写法(句式、用词、视角、节奏、对话方式、描写密度)。',\n '2. 台词风格要说明角色说话的语气特征与常用表达方式。',\n '3. 表达边界要写明这段风格「不会怎么做」(如:不用华丽辞藻、不写长段心理独白、不用成语堆砌)。',\n '4. 输出必须是合法 JSON 对象,不要输出任何其他文字。',\n 'JSON 结构:',\n '{\"proseRules\": [\"叙述视角与句式节奏规则\"], \"dialogueRules\": [\"台词风格规则\"], \"descriptionRules\": [\"描写密度与情绪表达规则\"], \"boundaries\": [\"表达边界\"]}',\n ].join('\\n')\n}\n","/** 漫画风格预设:每个预设对应一组出图提示词与排版偏好。 */\n\nexport interface ComicStylePreset {\n id: string\n label: string\n /** 注入 imagePrompt 的风格描述词。 */\n prompt: string\n /** 可选:排版偏好说明。 */\n layoutHint?: string\n}\n\nexport const COMIC_STYLE_PRESETS: ComicStylePreset[] = [\n {\n id: 'japan',\n label: '日漫 / 黑白',\n prompt: 'manga style, screentone, bold ink lines, high contrast, black and white, cel shading',\n layoutHint: '页漫优先',\n },\n {\n id: 'korea',\n label: '韩漫 / 条漫',\n prompt: 'manhwa style, soft cel shading, vibrant colors, clean lineart, webtoon vertical composition, glossy highlights',\n layoutHint: '条漫优先',\n },\n {\n id: 'china',\n label: '国漫 / 古风',\n prompt: 'chinese ink painting style, flowing brush strokes, traditional palette, ethereal atmosphere, xianxia aesthetic',\n layoutHint: '页漫/条漫均可',\n },\n {\n id: 'america',\n label: '美漫 / 超级英雄',\n prompt: 'american comic style, bold outlines, dramatic lighting, dynamic poses, vibrant colors, halftone shading',\n layoutHint: '页漫优先',\n },\n {\n id: 'chibi',\n label: 'Q版 / 搞笑',\n prompt: 'chibi style, cute proportions, big head, exaggerated expressions, simple background, bright colors',\n layoutHint: '条漫/四格优先',\n },\n {\n id: 'realistic',\n label: '写实 / 电影感',\n prompt: 'realistic cinematic style, detailed textures, natural lighting, film grain, high detail',\n layoutHint: '页漫/全彩',\n },\n {\n id: 'cyber',\n label: '赛博 / 暗黑',\n prompt: 'cyberpunk style, neon lights, dark atmosphere, high contrast, futuristic city, cool tones',\n layoutHint: '页漫/全彩',\n },\n]\n\nexport function getComicStylePrompt(styleId?: string): string {\n if (!styleId) return ''\n const preset = COMIC_STYLE_PRESETS.find(s => s.id === styleId)\n return preset?.prompt ?? ''\n}\n\nexport function getComicStyleLabel(styleId?: string): string {\n if (!styleId) return ''\n const preset = COMIC_STYLE_PRESETS.find(s => s.id === styleId)\n return preset?.label ?? styleId\n}\n","/**\n * Novel engine — the host half's core: LLM-driven story-bible extraction,\n * volume planning, chapter planning, chapter-by-chapter writing with\n * auto-review + rewrite, polish (de-AI-ify), narrative summaries, foreshadow\n * tracking, project persistence, and whole-book export. Pure Node (no\n * web-server dependencies), so routes stay thin and logic is testable.\n */\n\n/**\n * 内容合规红线(平台硬性要求):所有书籍、所有章节无条件生效,\n * 优先级高于单书大纲/圣经中的任何设定与作者自定义红线。\n * 注入点:章节生成系统提示 + 审稿系统提示(命中即 high)。\n */\nexport const COMPLIANCE_REDLINES: ReadonlyArray<string> = [\n '1. 不得出现反对宪法所确定的基本原则的内容。',\n '2. 不得出现危害国家安全、泄露国家秘密、颠覆国家政权、破坏国家统一的内容。',\n '3. 不得出现危害国家荣誉和利益的内容。',\n '4. 不得出现煽动民族仇恨、民族歧视、破坏民族团结的内容。',\n '5. 不得出现破坏国家宗教政策、宣扬邪教和愚昧迷信的内容(不得以真实宗教、邪教或迷信活动为背景进行宣扬)。',\n '6. 不得出现散布谣言、扰乱社会秩序、破坏社会稳定的内容。',\n '7. 不得出现淫秽色情、赌博、暴力、凶杀、恐怖或教唆犯罪的内容(网文语境:禁止露骨性描写、血腥暴力渲染、赌博教唆、犯罪手法详细教学)。',\n '8. 不得出现侮辱或者诽谤他人、侵害他人合法权益的内容(不得以真实人物、组织为原型进行侮辱或影射攻击)。',\n '9. 不得出现法律法规禁止的其他内容。',\n]\n\nimport { mkdirSync, readFileSync, writeFileSync, readdirSync, existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { createUserMessage, BlockAssembler, ReasoningEffortId, type GenerateOptions, type Message, type StreamChunk } from '@deepseek-ai/dsh-llm'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { emptyProjectAssets, renderAllAssets, styleEngineSystemPrompt } from './assets.ts'\nimport { getComicStylePrompt } from './comic-presets.ts'\nimport type {\n AuditIssue,\n AuthorReview,\n BreakdownResponse,\n ChapterPlan,\n Foreshadow,\n NovelConfig,\n OutlineCandidate,\n Plotline,\n PlotlineHealthReport,\n PlotlinePlan,\n ProjectState,\n ReviewReport,\n RoleRecord,\n RoleStatusCard,\n SceneCard,\n StoryBible,\n Volume,\n WorldState,\n} from './protocol.ts'\n\n/** Project state file name inside the output dir. */\nexport const PROJECT_FILE = 'novel-project.json'\n\n// ------------------------------------------------------------------ helpers\n\n/** Sanitize a file name: keep CJK/alphanumerics/space/dash/underscore. */\nfunction safeFileName(name: string): string {\n return name\n .replace(/[\\\\/:*?\"<>|]/g, '')\n .replace(/\\s+/g, ' ')\n .trim()\n .slice(0, 60)\n}\n\n/** Chapter output file name, e.g. 第001章_开篇.md */\nexport function chapterFileName(chapter: ChapterPlan): string {\n const title = safeFileName(chapter.title) || `第${chapter.no}章`\n return `第${String(chapter.no).padStart(3, '0')}章_${title}.md`\n}\n\n/** Infer a book name from the outline's first non-empty line. */\nexport function inferBookName(outline: string): string {\n const line = outline.split('\\n').map(l => l.trim()).find(l => l.length > 0)\n return (line ?? '未命名小说').replace(/^《/, '').replace(/》.*$/, '').slice(0, 40)\n}\n\n// ------------------------------------------------------------------ project\n\n/** Read the persisted project from the output dir (undefined when absent). */\nexport function loadProject(outputDir: string): ProjectState | undefined {\n const file = join(outputDir, PROJECT_FILE)\n if (!existsSync(file)) return undefined\n try {\n let rawText = readFileSync(file, 'utf8')\n // Tolerate a UTF-8 BOM (some editors / PowerShell writes add one).\n if (rawText.charCodeAt(0) === 0xFEFF) rawText = rawText.slice(1)\n const raw = JSON.parse(rawText) as ProjectState\n if (typeof raw.outline !== 'string' || !Array.isArray(raw.chapters)) return undefined\n // Normalize legacy projects (foreshadows / assets may be missing).\n if (!Array.isArray(raw.foreshadows)) raw.foreshadows = []\n if (raw.assets === undefined || typeof raw.assets !== 'object') raw.assets = emptyProjectAssets()\n if (!Array.isArray(raw.assets.antiAiRules)) raw.assets.antiAiRules = []\n if (!Array.isArray(raw.assets.auxiliaryProgressions)) raw.assets.auxiliaryProgressions = []\n if (!Array.isArray(raw.assets.styleAssets)) raw.assets.styleAssets = []\n if (!Array.isArray(raw.facts)) raw.facts = []\n if (!Array.isArray(raw.plotlines)) raw.plotlines = []\n return raw\n } catch {\n return undefined\n }\n}\n\n/** Persist the project state next to the chapters. */\nexport function saveProject(outputDir: string, project: ProjectState): void {\n mkdirSync(outputDir, { recursive: true })\n writeFileSync(join(outputDir, PROJECT_FILE), JSON.stringify(project, null, 2), 'utf8')\n}\n\n/**\n * 并发保护:长任务(章节计划生成/正文生成)在内存中持有旧快照,\n * 期间其他请求可能修改了「易变字段」(道藏/角色库/剧情线/人物志存档/简介/封面)。\n * 保存前用磁盘最新版本合并这些字段,避免旧快照覆盖新修改(曾导致角色卡丢失)。\n * 注意:调用方若自己修改了这些字段,不要使用本函数。\n */\nexport function mergeVolatileFromDisk(outputDir: string, project: ProjectState): void {\n try {\n const disk = loadProject(outputDir)\n if (disk === undefined) return\n project.bible = disk.bible\n project.roles = disk.roles\n project.plotlines = disk.plotlines\n project.roleStatus = disk.roleStatus\n project.blurb = disk.blurb\n project.coverPath = disk.coverPath\n project.facts = disk.facts\n project.assets = disk.assets\n project.world = disk.world\n project.volumes = disk.volumes\n } catch { /* 磁盘读取失败时保持原状 */ }\n}\n\n// ------------------------------------------------------------ sensitive words\n\n/**\n * 内置违禁词库(网文平台常见审查类别)。只做硬匹配提示,不代替人工判断。\n * 词语刻意保持常见写法;作者可自行判断是否修改。\n */\nconst SENSITIVE_WORDS: ReadonlyArray<{ word: string; category: string }> = [\n // 政治敏感\n { word: '共匪', category: '政治' }, { word: '独裁', category: '政治' },\n { word: '法轮', category: '政治' }, { word: '六四', category: '政治' },\n { word: '天安门事件', category: '政治' }, { word: '翻墙', category: '政治' },\n { word: '政治敏感', category: '政治' },\n // 色情擦边\n { word: '乳沟', category: '擦边' }, { word: '酥胸', category: '擦边' },\n { word: '淫荡', category: '擦边' }, { word: '做爱', category: '擦边' },\n { word: '上床', category: '擦边' }, { word: '裸体', category: '擦边' },\n { word: '一丝不挂', category: '擦边' }, { word: '胴体', category: '擦边' },\n { word: '春药', category: '擦边' }, { word: '催情', category: '擦边' },\n { word: '迷奸', category: '擦边' }, { word: '强暴', category: '擦边' },\n { word: '轮奸', category: '擦边' }, { word: '援交', category: '擦边' },\n { word: '嫖娼', category: '擦边' }, { word: '卖淫', category: '擦边' },\n { word: '色情', category: '擦边' }, { word: '情色', category: '擦边' },\n { word: '撸管', category: '擦边' }, { word: '自慰', category: '擦边' },\n { word: '口交', category: '擦边' }, { word: '打炮', category: '擦边' },\n { word: '约炮', category: '擦边' }, { word: '一夜情', category: '擦边' },\n // 暴力血腥\n { word: '碎尸', category: '暴力' }, { word: '分尸', category: '暴力' },\n { word: '凌迟', category: '暴力' }, { word: '剥皮', category: '暴力' },\n { word: '开膛', category: '暴力' }, { word: '剖腹', category: '暴力' },\n { word: '挖心', category: '暴力' }, { word: '虐杀', category: '暴力' },\n { word: '凌辱', category: '暴力' }, { word: '血腥', category: '暴力' },\n { word: '大屠杀', category: '暴力' }, { word: '灭门', category: '暴力' },\n { word: '满门抄斩', category: '暴力' }, { word: '腰斩', category: '暴力' },\n { word: '活埋', category: '暴力' }, { word: '点天灯', category: '暴力' },\n // 辱骂攻击\n { word: '傻逼', category: '辱骂' }, { word: '傻B', category: '辱骂' },\n { word: '草泥马', category: '辱骂' }, { word: '妈的', category: '辱骂' },\n { word: '尼玛', category: '辱骂' }, { word: '去死', category: '辱骂' },\n { word: '废物', category: '辱骂' }, { word: '垃圾', category: '辱骂' },\n { word: '人渣', category: '辱骂' }, { word: '贱人', category: '辱骂' },\n { word: '婊子', category: '辱骂' }, { word: '狗日的', category: '辱骂' },\n // 广告引流\n { word: '加微信', category: '广告' }, { word: '加QQ', category: '广告' },\n { word: '微信公众号', category: '广告' }, { word: '淘宝', category: '广告' },\n { word: '拼多多', category: '广告' }, { word: '刷单', category: '广告' },\n { word: '充值返利', category: '广告' }, { word: '扫码领', category: '广告' },\n { word: '加群领', category: '广告' }, { word: 'vx', category: '广告' },\n { word: '扣扣', category: '广告' },\n // 其他违禁\n { word: '赌博', category: '其他' }, { word: '赌场', category: '其他' },\n { word: '毒品', category: '其他' }, { word: '冰毒', category: '其他' },\n { word: '摇头丸', category: '其他' }, { word: '自杀方法', category: '其他' },\n { word: '邪教', category: '其他' }, { word: '传销', category: '其他' },\n { word: '军火', category: '其他' }, { word: '枪支', category: '其他' },\n { word: '管制刀具', category: '其他' },\n]\n\n/** 对一段文本做违禁词硬匹配,返回命中(词/类别/次数)。 */\nexport function checkSensitiveText(text: string): Array<{ word: string; category: string; count: number }> {\n const hits: Array<{ word: string; category: string; count: number }> = []\n for (const entry of SENSITIVE_WORDS) {\n let count = 0\n let idx = text.indexOf(entry.word)\n while (idx !== -1) {\n count++\n idx = text.indexOf(entry.word, idx + entry.word.length)\n }\n if (count > 0) hits.push({ word: entry.word, category: entry.category, count })\n }\n return hits\n}\n\n/** List generated chapter files in the output dir (sorted). */\nexport function listChapterFiles(outputDir: string): string[] {\n if (!existsSync(outputDir)) return []\n try {\n return readdirSync(outputDir)\n .filter(name => /^第\\d+章_.*\\.md$/.test(name) && !name.endsWith('.bak.md'))\n .sort((a, b) => {\n const na = Number(/^第(\\d+)章/.exec(a)?.[1] ?? 0)\n const nb = Number(/^第(\\d+)章/.exec(b)?.[1] ?? 0)\n return na - nb\n })\n } catch {\n return []\n }\n}\n\n/** Re-sync chapter status against files on disk (a file may exist without state). */\nexport function syncProjectWithDisk(project: ProjectState, outputDir: string): void {\n const files = new Map<string, string>()\n for (const file of listChapterFiles(outputDir)) {\n const no = Number(/^第(\\d+)章/.exec(file)?.[1] ?? 0)\n if (no > 0) files.set(String(no), file)\n }\n for (const chapter of project.chapters) {\n const file = files.get(String(chapter.no))\n if (file !== undefined && (chapter.status === 'pending' || chapter.status === 'generating')) {\n chapter.status = 'written'\n chapter.file = file\n }\n }\n project.updatedAt = new Date().toISOString()\n}\n\n/** Read a chapter's markdown body from disk (undefined when missing). */\nexport function readChapterFile(outputDir: string, chapter: ChapterPlan): string | undefined {\n if (chapter.file === undefined) return undefined\n const path = join(outputDir, chapter.file)\n if (!existsSync(path)) return undefined\n return readFileSync(path, 'utf8')\n}\n\n/** Create a fresh project from an outline. */\nexport function createProject(outline: string, outlinePath?: string): ProjectState {\n const now = new Date().toISOString()\n return {\n bookName: inferBookName(outline),\n outline,\n outlinePath,\n chapters: [],\n foreshadows: [],\n assets: emptyProjectAssets(),\n facts: [],\n createdAt: now,\n updatedAt: now,\n }\n}\n\n// ------------------------------------------------------------------- llm\n\n/** One complete non-streaming LLM call. */\nasync function complete(\n ctx: Context,\n config: NovelConfig,\n options: { system: string; user: string; temperature?: number; maxTokens?: number },\n): Promise<string> {\n const messages: Message[] = [createUserMessage({\n content: [{ type: 'text', text: options.user }],\n source: { kind: 'plugin', plugin: 'dsh-novel-forge' },\n })]\n const request: GenerateOptions = {\n provider: config.provider,\n model: config.model,\n messages,\n system: options.system,\n maxTokens: options.maxTokens ?? config.maxTokens,\n temperature: options.temperature ?? 0.7,\n reasoningEffort: ReasoningEffortId(config.reasoningEffort ?? 'off'),\n }\n const assembler = new BlockAssembler()\n for await (const chunk of ctx.llm.stream(request)) {\n assembler.push(chunk)\n }\n const finish = assembler.finish\n if (finish.kind === 'error' || finish.kind === 'aborted') {\n throw new Error(`LLM 调用失败(${finish.kind}): ${finish.failure.message}`)\n }\n if (finish.kind === 'max-tokens') {\n throw new Error('LLM 输出达到 maxTokens 上限,请增大配置后重试')\n }\n const blocks = assembler.blocks()\n // Diagnostics: log the assembled block shape (reasoning-only turns yield no\n // text blocks — the v4-flash model can answer entirely in the reasoning\n // channel, which the adapter surfaces as a reasoning block).\n if (process.env.DSH_NOVEL_DEBUG === '1') {\n console.error('[dsh-novel-forge] complete: finish=%j blocks=%j', JSON.stringify(finish), blocks.map(b => `${b.type}:${'text' in b ? b.text.length : '?'}`))\n }\n const textBlocks = blocks\n .filter((block): block is Extract<StreamChunk, { type: 'block-end' }>['block'] & { type: 'text' } => block.type === 'text')\n .map(block => block.text)\n let text = textBlocks.join('\\n').trim()\n // v4-flash can answer entirely in the reasoning channel (the adapter\n // surfaces that as a 'reasoning' block). Fall back to it when no text came\n // back — the reasoning content is the model's actual answer here.\n if (text === '') {\n const reasoning = blocks\n .filter((block): block is { type: 'reasoning'; text: string } => block.type === 'reasoning')\n .map(block => block.text)\n .join('\\n')\n .trim()\n if (reasoning !== '') text = reasoning\n }\n return text\n}\n\n/**\n * Parse a JSON value out of a model response. Multi-level tolerance because\n * models are sloppy: prose around the JSON, ```json fences, a truncated tail,\n * or raw newlines inside string values all defeat a single JSON.parse. We\n * walk candidates from strictest to loosest.\n */\nfunction parseJson<T>(text: string, wantArray: boolean): T {\n const candidates: string[] = []\n const push = (value: string | undefined): void => {\n if (value !== undefined && value.trim() !== '') candidates.push(value.trim())\n }\n\n // 1. Whole response, and any ```json fence body.\n push(text)\n const fenced = /```(?:json)?\\s*([\\s\\S]*?)```/.exec(text)\n push(fenced?.[1])\n // 2. From the first opener to the last closer.\n const opener = wantArray ? '[' : '{'\n const closer = wantArray ? ']' : '}'\n const start = text.indexOf(opener)\n const end = text.lastIndexOf(closer)\n if (start !== -1 && end > start) push(text.slice(start, end + 1))\n // 3. Trim trailing prose (a \"}...\" tail after the last closer).\n const trimmed = text.replace(new RegExp(`${closer}[\\\\s\\\\S]*$`), closer)\n push(trimmed)\n const start2 = trimmed.indexOf(opener)\n if (start2 !== -1) push(trimmed.slice(start2))\n\n // Repair: models love raw newlines inside string values, which JSON forbids.\n const repair = (value: string): string => {\n let out = ''\n let inString = false\n for (let i = 0; i < value.length; i++) {\n const ch = value[i]!\n if (inString) {\n if (ch === '\\\\') {\n out += ch + (value[i + 1] ?? '')\n i++\n continue\n }\n if (ch === '\"') {\n inString = false\n out += ch\n continue\n }\n if (ch === '\\n' || ch === '\\r') {\n out += '\\\\n'\n continue\n }\n out += ch\n } else {\n if (ch === '\"') inString = true\n out += ch\n }\n }\n return out\n }\n\n for (const candidate of candidates) {\n for (const attempt of [candidate, repair(candidate)]) {\n try {\n const value = JSON.parse(attempt) as unknown\n if (!wantArray || Array.isArray(value)) return value as T\n // wantArray but the model wrapped the list in an object, e.g.\n // {\"chapters\": [...]} — extract the first array-valued key.\n if (typeof value === 'object' && value !== null) {\n for (const key of Object.keys(value as Record<string, unknown>)) {\n const inner = (value as Record<string, unknown>)[key]\n if (Array.isArray(inner)) return inner as T\n }\n }\n // Not an array — keep trying the remaining candidates.\n } catch {\n // try the next candidate\n }\n }\n }\n const preview = text.length > 300 ? text.slice(0, 300) + '…' : text\n throw new Error(`模型输出中未找到 JSON 数据。模型原始输出:${preview}`)\n}\n\n/** Parse a JSON array (chapters, volumes, issues...). */\nfunction parseJsonArray<T>(text: string): T[] {\n const value = parseJson<T[]>(text, true)\n return Array.isArray(value) ? value : []\n}\n\n/** Parse a JSON object. */\nfunction parseJsonObject<T>(text: string): T {\n const value = parseJson<T>(text, false)\n if (typeof value !== 'object' || value === null) throw new Error('模型输出不是 JSON 对象')\n return value\n}\n\n// ------------------------------------------------------------------ bible\n\n/** System prompt for story-bible extraction. */\nfunction bibleSystemPrompt(): string {\n return [\n '你是一位资深网文编辑兼设定架构师。你会收到一份小说大纲,请把它提炼成结构化的「设定圣经」(Story Bible),供后续写作时严格引用。',\n '要求:',\n '1. 忠于大纲,不自行发明大纲之外的设定。',\n '2. 角色卡覆盖大纲明确出现的角色(主角必含),每个角色给出性格标签、目标、关键关系。',\n '3. 世界规则覆盖力量体系、金手指机制、势力、地理等所有硬性规则,逐条列出。',\n '4. 红线列出大纲中明确禁止的内容(如无后宫、不圣母、无无脑碾压等)。',\n '5. 风格列出叙事基调、节奏、POV 等写作风格要点。',\n '6. 角色名必须用正文/编年录中的真实姓名;若大纲只写「主角」未点名,而已写章节或编年录中有名字,则用该真实姓名;禁止输出「主角(描述)」这类把身份塞进名字的占位名。',\n '输出必须是合法 JSON 对象,不要输出任何其他文字或 Markdown 代码块标记。',\n '重要:所有字符串值内部不得包含换行符(不要用多行字符串),JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程或推理内容写在输出里。',\n 'JSON 结构:',\n '{\"genre\": \"题材与基调一句话\", \"worldRules\": [\"规则1\", \"规则2\", ...], \"characters\": [{\"name\": \"角色名\", \"role\": \"protagonist|supporting|antagonist|other\", \"traits\": [\"标签1\", ...], \"goals\": \"目标与动机\", \"relations\": \"关键关系\"}], \"redLines\": [\"红线1\", ...], \"style\": [\"风格1\", ...]}',\n ].join('\\n')\n}\n\n/** Extract the story bible from an outline. */\nexport async function extractBible(ctx: Context, config: NovelConfig, outline: string, project?: ProjectState): Promise<StoryBible> {\n // 已写章节/编年录只在「确认真实姓名与已确立设定」时参考,仍忠于大纲、不新增大纲外设定。\n const written = (project?.chapters ?? []).filter(c => c.status !== 'pending' && c.status !== 'generating' && c.file !== undefined)\n const excerpts: string[] = []\n for (const chapter of written.slice(0, 3)) {\n const body = readChapterFile(config.outputDir, chapter)\n if (body === undefined) continue\n const text = body.replace(/^#.*$/gm, '').trim()\n if (text.length > 0) excerpts.push(`第${chapter.no}章《${chapter.title}》\\n${text.slice(0, 2200)}`)\n }\n const facts = (project?.facts ?? []).slice(-40)\n const user = [\n `请为下面这部小说提炼设定圣经:\\n\\n${outline}`,\n facts.length > 0\n ? `\\n\\n【已写章节事实(编年录)】用于确认真实角色姓名与已确立设定;忠于大纲,不要新增大纲外设定:\\n${facts.map(f => `[第${f.chapterNo}章] ${f.text.slice(0, 100)}`).join('\\n')}`\n : '',\n excerpts.length > 0\n ? `\\n\\n【已写章节正文摘录】角色姓名、身份以正文为准(大纲未点名时用正文里的真实姓名,禁止用「主角(描述)」占位名):\\n${excerpts.join('\\n\\n')}`\n : '',\n ].filter(s => s !== '').join('\\n')\n const text = await complete(ctx, config, {\n system: bibleSystemPrompt(),\n user,\n temperature: 0.4,\n maxTokens: Math.max(config.maxTokens, 16000),\n })\n const raw = parseJsonObject<{\n genre?: unknown\n worldRules?: unknown\n characters?: unknown\n redLines?: unknown\n style?: unknown\n }>(text)\n const strArray = (value: unknown): string[] =>\n Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string' && v.trim() !== '') : []\n const characters: StoryBible['characters'] = Array.isArray(raw.characters)\n ? raw.characters\n .filter((v): v is Record<string, unknown> => typeof v === 'object' && v !== null)\n .map(entry => ({\n name: typeof entry.name === 'string' ? entry.name.trim() : '未命名',\n role: (['protagonist', 'supporting', 'antagonist', 'other'] as const).includes(entry.role as never)\n ? entry.role as StoryBible['characters'][number]['role']\n : 'other',\n traits: strArray(entry.traits),\n goals: typeof entry.goals === 'string' ? entry.goals : '',\n relations: typeof entry.relations === 'string' ? entry.relations : '',\n knowledge: strArray(entry.knowledge),\n }))\n .filter(card => card.name !== '')\n : []\n // 占位名修复:大纲未点名主角时模型可能输出「主角(…)」,用角色库真实主角名替换。\n const realProtagonist = (project?.roles ?? []).find(r => r.roleLabel === 'protagonist')?.name?.trim()\n if (realProtagonist !== undefined && realProtagonist !== '') {\n for (const card of characters) {\n if (card.role === 'protagonist' && /^(主角|未命名)/.test(card.name)) card.name = realProtagonist\n }\n }\n const bible: StoryBible = {\n genre: typeof raw.genre === 'string' ? raw.genre : '',\n worldRules: strArray(raw.worldRules),\n characters,\n redLines: strArray(raw.redLines),\n style: strArray(raw.style),\n generatedAt: new Date().toISOString(),\n }\n if (bible.worldRules.length === 0 && bible.characters.length === 0 && bible.redLines.length === 0) {\n throw new Error('道藏生成失败:模型没有返回有效内容')\n }\n return bible\n}\n\n// ------------------------------------------------------------------ volumes\n\n/** System prompt for volume planning. */\nfunction volumeSystemPrompt(): string {\n return [\n '你是一位资深网文总编。你会收到一份小说大纲,请把全书划分为若干「卷」(分卷),每卷有明确的剧情定位与起止章节。',\n '要求:',\n '1. 大纲已有分卷时,严格遵循大纲的分卷结构;没有时按剧情弧线合理划分(3-8 卷)。',\n '2. 卷定位一句话说明该卷的剧情重心。',\n '3. chapterStart/chapterEnd 给出该卷覆盖的章节区间(从 1 开始连续编号)。',\n '输出必须是合法 JSON 数组,不要输出任何其他文字:',\n '[{\"no\": 1, \"title\": \"卷名\", \"summary\": \"卷定位与剧情重心\", \"chapterStart\": 1, \"chapterEnd\": 80}]',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程或推理内容写在输出里。',\n ].join('\\n')\n}\n\n/** Plan volumes from an outline. */\nexport async function planVolumes(ctx: Context, config: NovelConfig, outline: string): Promise<Volume[]> {\n const user = `请为下面这部小说划分卷:\\n\\n${outline}`\n const text = await complete(ctx, config, { system: volumeSystemPrompt(), user, temperature: 0.4, maxTokens: Math.max(config.maxTokens, 12000) })\n const parsed = parseJsonArray<Record<string, unknown>>(text)\n const volumes: Volume[] = []\n for (let i = 0; i < parsed.length; i++) {\n const entry = parsed[i]\n if (typeof entry !== 'object' || entry === null) continue\n const no = typeof entry.no === 'number' ? entry.no : i + 1\n const title = typeof entry.title === 'string' ? entry.title.trim() : `第${no}卷`\n const summary = typeof entry.summary === 'string' ? entry.summary.trim() : ''\n const start = typeof entry.chapterStart === 'number' ? entry.chapterStart : undefined\n const end = typeof entry.chapterEnd === 'number' ? entry.chapterEnd : undefined\n volumes.push({\n no,\n title: title.slice(0, 40),\n summary: summary.slice(0, 300),\n chapterStart: start ?? 1,\n chapterEnd: end ?? 1,\n })\n }\n if (volumes.length === 0) throw new Error('卷计划生成失败:模型没有返回有效卷')\n return volumes\n}\n\n/** Assign a chapter to its volume by number. */\nfunction volumeOf(chapterNo: number, volumes: Volume[] | undefined): number {\n if (volumes === undefined || volumes.length === 0) return 0\n for (const volume of volumes) {\n if (chapterNo >= volume.chapterStart && chapterNo <= volume.chapterEnd) return volume.no\n }\n return volumes[volumes.length - 1]?.no ?? 0\n}\n\n// ------------------------------------------------------------------- plan\n\n/** The chapter-planning prompt template. */\nfunction planSystemPrompt(volumes: Volume[] | undefined): string {\n const volumeBlock = volumes !== undefined && volumes.length > 0\n ? ['\\n全书分卷结构(规划章节时需落在对应卷内):']\n .concat(volumes.map(v => `第${v.no}卷《${v.title}》:${v.summary}(章节 ${v.chapterStart}-${v.chapterEnd})`))\n .join('\\n')\n : ''\n return [\n '你是一位资深中文网文策划编辑,擅长把小说大纲拆解为可执行的章节计划。',\n '你会收到一份小说大纲。请根据大纲的设定、主线与节奏,规划出一份章节计划。',\n '要求:',\n '1. 每章必须有明确的核心剧情推进(不能只是过渡或凑字数)。',\n '2. 章节之间要衔接自然,前章结尾为后章埋下钩子。',\n '3. 严格遵循大纲的人设、金手指规则、战力体系与世界观设定,不得自行发明冲突设定。',\n '4. 输出必须是合法的 JSON 数组,不要输出任何其他文字或 Markdown 代码块标记。',\n '5. 数组每个元素格式:{\"title\": \"章节标题(10字以内,有网文感)\", \"beats\": \"结构化剧情要点(150-250字,必须包含四段,段间用换行分隔):\\\\n本章目标:本章要完成的核心推进;\\\\n剧情要点:主要情节的起承转合(2-4 句);\\\\n爽点/钩子:本章的爽点兑现或情绪钩子;\\\\n结尾钩子:本章结尾为下一章埋下的悬念\"}',\n '重要:beats 字段内部必须使用 \\\\n 转义表示换行(JSON 字符串内不得有真实换行符),其余字符串值也不得包含真实换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程或推理内容写在输出里。',\n volumeBlock,\n ].join('\\n')\n}\n\n/** Build the writing system prompt (bible + outline + active foreshadows). */\nfunction writeSystemPrompt(project: ProjectState): string {\n const bible = project.bible\n const sections: string[] = []\n if (bible !== undefined) {\n sections.push('==================== 设定圣经(写作时严格遵守) ====================')\n if (bible.genre !== '') sections.push(`题材基调:${bible.genre}`)\n if (bible.worldRules.length > 0) sections.push('世界规则:\\n' + bible.worldRules.map(r => `- ${r}`).join('\\n'))\n if (bible.characters.length > 0) {\n sections.push('角色卡:')\n for (const card of bible.characters) {\n const roleName = { protagonist: '主角', supporting: '配角', antagonist: '反派', other: '其他' }[card.role]\n sections.push(`- ${card.name}(${roleName}):${card.traits.join('、')}${card.goals !== '' ? `;目标:${card.goals}` : ''}${card.relations !== '' ? `;关系:${card.relations}` : ''}`)\n if (Array.isArray(card.knowledge) && card.knowledge.length > 0) {\n sections.push(` 已知信息(该角色知道的:${card.knowledge.join(';')};未列出的信息该角色一律不知道,不得写其知晓或提及)`)\n }\n }\n }\n // 角色库注入:定位 + 身份 + 关系(角色互动按定位规格写)。\n const roleLib = project.roles ?? []\n if (roleLib.length > 0) {\n const labelName = { protagonist: '主角', female_lead: '女主', female_support: '女配', support: '配角', antagonist: '反派', extra: '路人' }\n sections.push('角色库(出场角色按定位规格刻画互动):')\n for (const r of roleLib) {\n sections.push(`- ${r.name}(${labelName[r.roleLabel]}):${r.identity}${r.relations.length > 0 ? `;关系:${r.relations.join('、')}` : ''}`)\n }\n }\n if (bible.redLines.length > 0) sections.push('写作红线(违反即失败):\\n' + bible.redLines.map(r => `- ${r}`).join('\\n'))\n if (bible.style.length > 0) sections.push('风格要求:\\n' + bible.style.map(r => `- ${r}`).join('\\n'))\n }\n const worldBlock = renderWorld(project.world)\n if (worldBlock !== '') sections.push(worldBlock)\n sections.push('==================== 全书大纲 ====================')\n // 超长大纲截断保护(防止上下文超限);完整大纲在总纲页查看。\n const outlineBlock = project.outline.length > 6000\n ? project.outline.slice(0, 6000) + '\\n…(大纲过长已节选,完整内容见总纲页)'\n : project.outline\n sections.push(outlineBlock)\n sections.push('==================== 大纲结束 ====================')\n const assetsBlock = renderAllAssets(project.assets)\n if (assetsBlock !== '') sections.push(assetsBlock)\n const active = project.foreshadows.filter(f => f.status === 'planted' || f.status === 'progressing')\n if (active.length > 0) {\n sections.push('==================== 活跃伏笔(近期需推进或回收的线索) ====================')\n for (const f of active) {\n sections.push(`- [${f.status === 'planted' ? '已埋设' : '推进中'}] ${f.description}${f.targetChapter !== undefined ? `(预计 ${f.targetChapter} 章回收)` : ''}`)\n }\n }\n const lines = (project.plotlines ?? []).filter(l => l.status === 'active' || l.status === 'paused')\n if (lines.length > 0) {\n const kindName = { main: '主线', branch: '支线', character: '人物线', mystery: '悬念线' }\n sections.push('==================== 剧情线(本章应推进至少一条活跃线) ====================')\n for (const l of lines) {\n sections.push(`- [${kindName[l.kind]}${l.status === 'paused' ? '·暂停中' : ''}] ${l.name}:${l.goal}${l.progress !== '' ? `(当前进度:${l.progress})` : ''}`)\n }\n }\n sections.push('')\n sections.push('写作硬性要求:')\n sections.push('1. 每章 3000-4000 字(按中文字符计),只输出章节正文,不要输出标题、章回名、作者的话或任何 Markdown 标记。')\n sections.push('2. 以主角视角展开,动作、对话、心理描写交替推进,禁止大段设定说明。')\n sections.push('3. 尊重大纲与设定圣经:人设不崩、金手指规则不自相矛盾、战力不随意膨胀。')\n sections.push('4. 章末留一个钩子(悬念、反转或新线索),吸引读者读下一章。')\n sections.push('5. 语言流畅自然,符合中文网文语感,避免翻译腔与病句。')\n sections.push('6. 对话与冲突密度:每章至少 1 处实质对话或正面对抗/交锋场面;推理与心理活动必须用动作、环境细节、微表情、对话呈现,禁止整章纯内心独白铺陈(禁止\"解说式\"交代线索)。')\n sections.push('7. 反派与对手的行动力:本章出现的反派/对手必须有其行动、反制或压迫感(布局、试探、追索、交锋至少占其一),不得作为纯背景板存在。')\n sections.push('8. 配角辨识度:重要新登场配角应给姓名或可辨识的独有特征;禁止通篇用\"瘦高个/灰衣人/戴面具者\"等身形标签代称同一角色。')\n sections.push('9. 信息呈现方式:关键线索、设定、局势通过对话、动作、发现物呈现,禁止主角内心\"讲解\"给读者听。')\n sections.push('')\n sections.push('==================== 内容合规红线(平台硬性要求,最高优先级,违反即失败) ====================')\n sections.push(COMPLIANCE_REDLINES.join('\\n'))\n sections.push('以上九条为硬性底线,任何情况下不得以任何形式出现或影射;若剧情确需涉及(如批判、反讽),只能以明确否定、揭露、批判的立场呈现,且不得展开细节。')\n return sections.join('\\n')\n}\n\n/**\n * Plan chapters from an outline (optionally for one volume).\n */\nexport async function planChapters(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n chapterCount: number,\n volumeNo?: number,\n outputDir?: string,\n): Promise<ChapterPlan[]> {\n const volume = project.volumes?.find(v => v.no === volumeNo)\n const existing = project.chapters\n const startNo = existing.length === 0 ? 1 : Math.max(...existing.map(c => c.no)) + 1\n const NL = String.fromCharCode(10)\n const continuation = existing.length > 0\n const latestFacts = continuation && Array.isArray(project.facts)\n ? project.facts.slice(-15).map(f => `[第${f.chapterNo}章] ${f.text.slice(0, 150)}`).join('\\n')\n : ''\n // 上一章(已写章节中章号最大者)结尾原文,作为续写剧情起点。\n let prevTail = ''\n if (continuation) {\n const written = existing.filter(c => c.status !== 'pending')\n const last = written[written.length - 1]\n if (last !== undefined && last.file !== undefined && outputDir !== undefined) {\n try {\n const raw = readFileSync(join(outputDir, last.file), 'utf8')\n prevTail = raw.replace(/^#.*$/m, '').trim().slice(-600)\n } catch { /* 文件缺失时忽略,仅依赖编年录 */ }\n }\n }\n // 续写模式大纲注入:精简大纲(≤2 万字)直接全量,避免误伤「分卷收官规划」(如第五卷双结局);\n // 超大 docx 大纲才节选——截到「记忆梗」之前,保留分卷大纲与红线,去掉后续冗余。\n const outlineBlock = continuation\n ? (() => {\n if (project.outline.length <= 20000) return project.outline\n const cut = project.outline.indexOf('十、全书核心弹幕记忆梗')\n if (cut > 1500) return project.outline.slice(0, cut).trimEnd() + '\\n(大纲过长,末尾记忆梗从略)'\n return project.outline.slice(0, 8000) + '\\n…(大纲过长已节选)'\n })()\n : project.outline\n const user = [\n '请为下面这部小说规划章节。',\n volume !== undefined\n ? `本次只规划第 ${volume.no} 卷《${volume.title}》的章节:\\n${volume.summary}`\n : continuation\n ? `本书已有 ${existing.length} 章已规划/已写作(见下方「已有章节」)。请规划**后续**章节:从第 ${startNo} 章开始。`\n : '请规划全书开篇章节。',\n continuation\n ? '【续写硬性要求】已有章节的剧情不得重写或重复,章节标题也不得与已有章节重复。以下情节均已在已有章节中发生过,后续章节**绝对不得再次出现**:穿越、暴雨送餐、滴血认主/古玉认主、首次进入墟境、用废铁淬炼首件法器、绝境肉身入鼎洗炼(该机缘已用尽)、杀死白袍弟子与灰衣随从、藏尸水沟。' + NL + '若本次规划已进入大纲的收尾区间(接近全书规划总章数),最后 5-10 章必须按大纲推进到大结局(终极抉择/清算/双结局等),**禁止以悬念、逃离、未解之谜收尾**——收尾区间按大纲卷定位判断,不以当前剧情是否“感觉像结尾”为准。'\n : '',\n prevTail !== ''\n ? `【上一章(第 ${startNo - 1} 章)结尾原文】第 ${startNo} 章必须紧接此状态继续,从新的事件写起,不得回顾重述:\\n${prevTail}`\n : '',\n latestFacts !== ''\n ? `【最新剧情状态(本书编年录,第 ${startNo - 1} 章结尾的事实)】规划续写时必须以此为起点,时间线、人物状态与地点衔接一致:\\n${latestFacts}`\n : '',\n continuation\n ? '已有章节(共 ' + existing.length + ' 章;仅列最近 80 章,更早的以标题计数为准,剧情以「编年录」为权威):\\n'\n + existing.slice(-80).map(c => {\n const sm = c.summary !== undefined && c.summary !== '' ? `(${c.summary.slice(0, 120)})` : ''\n return `第${c.no}章《${c.title}》${sm}`\n }).join('\\n')\n : '',\n `全书大纲(设定参考,续写剧情不得与设定冲突):\\n${outlineBlock}`,\n '',\n `请规划 ${chapterCount} 章。输出 JSON 数组(不要输出其他文字):`,\n ].join('\\n')\n const system = planSystemPrompt(project.volumes) + (continuation\n ? '\\n重要:本次是**续写规划**——已有章节的剧情不得重写或重复,新章节标题不得与已有章节标题相同,新章节的剧情必须从上一章结尾自然接续(人物状态、时间线、地点衔接一致)。'\n : '')\n const text = await complete(ctx, config, { system, user, temperature: 0.7, maxTokens: Math.max(config.maxTokens, 40000) })\n const parsed = parseJsonArray<Record<string, unknown>>(text)\n const chapters: ChapterPlan[] = []\n const existingNos = new Set(existing.map(c => c.no))\n const existingTitles = new Set(existing.map(c => c.title))\n let cursor = startNo\n for (const item of parsed) {\n if (chapters.length >= chapterCount) break\n if (typeof item !== 'object' || item === null) continue\n const entry = item as Record<string, unknown>\n const title = typeof entry.title === 'string' ? entry.title.trim().slice(0, 30) : ''\n const beats = typeof entry.beats === 'string' ? entry.beats.trim() : ''\n if (title === '' && beats === '') continue\n // 续写模式下,标题与已有章节重复的一律丢弃(模型可能复述旧章节)。\n if (title !== '' && existingTitles.has(title)) continue\n while (existingNos.has(cursor)) cursor++\n const no = cursor++\n chapters.push({\n no,\n volume: volumeOf(no, project.volumes),\n title: title || `第${no}章`,\n beats,\n targetChars: config.chapterChars,\n status: 'pending',\n })\n }\n if (chapters.length === 0) {\n throw new Error('章节计划生成失败:模型没有返回有效章节')\n }\n return chapters\n}\n\n// ------------------------------------------------------------------ writing\n\n/** The review system prompt. */\nfunction reviewSystemPrompt(project: ProjectState): string {\n const bible = project.bible\n const sections: string[] = [\n '你是一位严格的网文审稿编辑。你会收到一章正文以及本书的设定圣经与红线。',\n '请从以下维度审查本章:',\n '1. 人设一致性:角色行为是否符合角色卡(主角不圣母、不无脑、痞坏有分寸等)。',\n '2. 设定一致性:金手指规则、战力体系、世界观是否与设定圣经冲突。',\n '3. 红线检查:是否触犯写作红线(无后宫、无擦边、无无脑碾压等)。',\n '4. 文笔质量:语病、翻译腔、AI 套话(\"不禁\"\"仿佛\"\"一时间\"等高频词滥用)、流水账。',\n '5. 节奏与爽点:本章是否有推进、有钩子,是否拖沓灌水。',\n '6. 逻辑漏洞:前后矛盾、时间线错误、对话失真。',\n '7. 反 AI 规则:逐条核对下方「反 AI 规则」清单,命中即列为问题。',\n '8. 呈现方式:整章是否纯内心推理铺陈(无对话/无对抗,推理全靠解说);反派是否纯背景板无行动;重要配角是否无名标签化(瘦高个/灰衣人全程代称)——命中即列为问题。',\n '9. 内容合规(最高优先级):逐条核对下方「内容合规红线」,任何一条命中(含影射、暗示、详细描写)必须列为 high,并给出改写建议。',\n '输出必须是合法 JSON 对象,不要输出任何其他文字:',\n '{\"score\": 0-100的整数, \"verdict\": \"一句话总评\", \"issues\": [{\"severity\": \"high|medium|low\", \"item\": \"问题描述\", \"suggestion\": \"修改建议\"}]}',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ]\n const assetsBlock = renderAllAssets(project.assets)\n if (assetsBlock !== '') sections.push('\\n' + assetsBlock)\n if (bible !== undefined) {\n sections.push('\\n==================== 设定圣经 ====================')\n if (bible.worldRules.length > 0) sections.push('世界规则:\\n' + bible.worldRules.map(r => `- ${r}`).join('\\n'))\n if (bible.characters.length > 0) {\n sections.push('角色卡:')\n for (const card of bible.characters) {\n sections.push(`- ${card.name}(${card.role}):${card.traits.join('、')}`)\n if (Array.isArray(card.knowledge) && card.knowledge.length > 0) {\n sections.push(` 该角色知道:${card.knowledge.join(';')}(未列出的信息该角色不知道)`)\n }\n }\n }\n if (bible.redLines.length > 0) sections.push('红线:\\n' + bible.redLines.map(r => `- ${r}`).join('\\n'))\n }\n sections.push('\\n==================== 内容合规红线(平台硬性要求,最高优先级) ====================')\n sections.push(COMPLIANCE_REDLINES.join('\\n'))\n sections.push('以上九条为硬性底线:正文中任何一条命中(含影射、暗示、详细展开)都必须列为 high,并给出改写建议;作者自定义红线不得豁免这九条。')\n return sections.join('\\n')\n}\n\n/** Run the AI review on one chapter. */\nexport async function reviewChapter(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): Promise<ReviewReport> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) throw new Error(`章节 ${chapterNo} 不在计划中`)\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) throw new Error(`章节 ${chapterNo} 的正文文件不存在`)\n const user = [\n `本章标题:《${chapter.title}》`,\n `本章剧情要点:${chapter.beats}`,\n '==================== 章节正文 ====================',\n body.replace(/^#\\s+.*$/m, '').trim(),\n ].join('\\n')\n const text = await complete(ctx, config, { system: reviewSystemPrompt(project), user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 16000) })\n const raw = parseJsonObject<{ score?: unknown; verdict?: unknown; issues?: unknown }>(text)\n const issues = Array.isArray(raw.issues)\n ? raw.issues\n .filter((v): v is Record<string, unknown> => typeof v === 'object' && v !== null)\n .map(entry => ({\n severity: (['high', 'medium', 'low'] as const).includes(entry.severity as never)\n ? entry.severity as 'high' | 'medium' | 'low'\n : 'medium',\n item: typeof entry.item === 'string' ? entry.item : '',\n suggestion: typeof entry.suggestion === 'string' ? entry.suggestion : '',\n }))\n .filter(issue => issue.item !== '')\n : []\n const score = typeof raw.score === 'number' ? Math.max(0, Math.min(100, Math.round(raw.score))) : 60\n // 无 high 问题且评分 ≥60 → 直接通过(medium/low 主观项记录但不阻塞,避免“72 分卡线”空转修订)\n const passed = score >= config.reviewPassScore || (issues.every(i => i.severity !== 'high') && score >= 60)\n const report: ReviewReport = {\n score,\n passed,\n verdict: typeof raw.verdict === 'string' ? raw.verdict.slice(0, 200) : '',\n issues,\n reviewedAt: new Date().toISOString(),\n }\n chapter.review = report\n chapter.status = report.passed ? 'approved' : 'rejected'\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return report\n}\n\n/**\n * 审查「任意正文文本」(作者手动编辑后的草稿,不落盘)。\n * 复用审稿提示词与红线/道藏/反AI规则;仅返回报告,不改文件不改状态。\n */\nexport async function reviewChapterText(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n text: string,\n previousReport?: ReviewReport,\n): Promise<ReviewReport> {\n const user = [\n `书名:《${project.bookName}》`,\n previousReport !== undefined\n ? '==================== 上一轮审稿意见(逐条核对是否已解决) ====================\\n'\n + previousReport.issues.map((it, i) => `${i + 1}. [${it.severity}] ${it.item}${it.suggestion !== '' ? ` → ${it.suggestion}` : ''}`).join('\\n')\n : '',\n previousReport !== undefined\n ? '==================== 修订稿(上一轮审稿后按意见修订的正文) ===================='\n : '==================== 待审查正文 ====================',\n text.slice(0, 20000),\n ].join('\\n')\n // 验证模式:携带上一轮报告时,逐条核对原意见是否解决 + 只挑新增 high,不再全新找茬。\n const system = previousReport !== undefined ? verifySystemPrompt(project) : reviewSystemPrompt(project)\n const raw = parseJsonObject<{ score?: unknown; verdict?: unknown; issues?: unknown }>(\n await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 16000) }),\n )\n const issues = Array.isArray(raw.issues)\n ? raw.issues\n .filter((v): v is Record<string, unknown> => typeof v === 'object' && v !== null)\n .map(entry => ({\n severity: (['high', 'medium', 'low'] as const).includes(entry.severity as never)\n ? entry.severity as 'high' | 'medium' | 'low'\n : 'medium',\n item: typeof entry.item === 'string' ? entry.item : '',\n suggestion: typeof entry.suggestion === 'string' ? entry.suggestion : '',\n }))\n .filter(issue => issue.item !== '')\n : []\n const score = typeof raw.score === 'number' ? Math.max(0, Math.min(100, Math.round(raw.score))) : 60\n // 非验证模式:无 high 且评分 ≥60 → 通过;验证模式判定:原 high 全部解决 + 无新增 high → 通过(主观项不再卡修订)。\n let passed = score >= config.reviewPassScore || (issues.every(i => i.severity !== 'high') && score >= 60)\n if (previousReport !== undefined) {\n const hasHigh = issues.some(i => i.severity === 'high')\n const prevHigh = previousReport.issues.filter(i => i.severity === 'high')\n const prevHighResolved = prevHigh.every(p => !issues.some(i => i.item.includes(p.item.slice(0, 12))))\n passed = !hasHigh && prevHighResolved\n }\n return {\n score,\n passed,\n verdict: typeof raw.verdict === 'string' ? raw.verdict.slice(0, 200) : '',\n issues,\n reviewedAt: new Date().toISOString(),\n }\n}\n\n/** 验证模式系统提示:修订后逐条核对原意见是否解决,只挑新增 high,不重复挑剔主观项。 */\nfunction verifySystemPrompt(project: ProjectState): string {\n return [\n '你是一位网文审稿验证员。作者已按上一轮审稿意见修订了本章,你需要验证修订效果。',\n '你的任务(严格按此执行):',\n '1. 逐条核对「上一轮意见」中的每一条是否已在修订稿中解决——已解决的不再列出;未解决或部分解决的,按原严重度列出(item 需注明\"未解决:原意见 xxx\")。',\n '2. 只挑修订【新引入】的 high 级问题(设定矛盾/逻辑硬伤/事实错误)——新引入的 medium/low 主观项(文笔/套话/节奏)不要列。',\n '3. 禁止重复挑剔上一轮已指出且本次已解决的主观项(如\"缓缓/微微\"等套话、错别字)——即使换个说法再提也不行。',\n '4. 严禁为了显得专业而新增\"换一批毛病\"式的意见;如果修订稿已解决全部 high 且无新增 high,输出 issues 为空数组。',\n 'score 评分:按修订稿整体质量给 50-90 分(解决全部 high 且无新增 high 时给 70 以上)。',\n 'verdict:一句话结论(如\"原 high 已解决,无新增高风险问题\"或\"仍有未解决的 high\")。',\n '输出必须是合法 JSON 对象:{\"score\": 数字, \"verdict\": \"一句话\", \"issues\": [{\"severity\": \"high|medium|low\", \"item\": \"问题\", \"suggestion\": \"建议\"}]}',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n `本书设定圣经(核对设定冲突用):\\n${project.bible !== undefined ? JSON.stringify(project.bible).slice(0, 3000) : '(无)'}`,\n ].join('\\n')\n}\n\n/** Build the author-review system prompt (narrative structure, not prose). */\nfunction authorReviewSystemPrompt(): string {\n return [\n '你是一位网文作者复盘助手。你会收到:本章正文、上一章结尾(钩子)、上一章作者复盘(如有)、活跃剧情线与编年录近期事实。',\n '请从叙事结构层面复盘本章(不评文笔,那是审稿的事):',\n '1. hookHonored:上一章结尾的钩子/悬念是否在本章兑现或推进(true/false)。',\n '2. hookNote:钩子兑现情况一句话;未兑现时说明并给出\"建议在第几章补\"的建议。',\n '3. endingHook:本章结尾钩子强度,0-10 的整数(低于 6 说明结尾平淡,读者可能不想看下一章)。',\n '4. plotlineProgress:本章推进了哪条剧情线(主线/支线名),或\"无实质推进\"(连续无推进要提醒)。',\n '5. advancedLines:本章实际推进的剧情线名称数组——从「活跃剧情线」清单中选出推进了的线(名称必须与清单中的线名一字不差;没推进任何线则输出空数组)。',\n '6. continuity:与上一章结尾的衔接检查(人物位置/时间/伤势/资源/对话状态),发现问题要指出。',\n '7. trend:结合上一章复盘看近期节奏趋势(是否连续拖沓、爽点密度是否下降、是否需要调整)。',\n '输出必须是合法 JSON 对象,不要输出任何其他文字:',\n '{\"hookHonored\": true或false, \"hookNote\": \"一句话\", \"endingHook\": 0-10整数, \"plotlineProgress\": \"一句话\", \"advancedLines\": [\"线名\"], \"continuity\": \"一句话\", \"trend\": \"一句话\"}',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n}\n\n/** 作者复盘:对一章做叙事结构复盘(钩子兑现/结尾钩子/推进/连续性/趋势)。 */\nexport async function authorReviewChapter(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n chapterNo: number,\n body: string,\n prevTail: string,\n): Promise<AuthorReview> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n const prevChapter = chapterNo > 1 ? project.chapters.find(c => c.no === chapterNo - 1) : undefined\n const lines = (project.plotlines ?? []).filter(l => l.status === 'active' || l.status === 'paused')\n const facts = (project.facts ?? []).slice(-10)\n const user = [\n `书名:《${project.bookName}》`,\n chapter !== undefined ? `本章:第 ${chapter.no} 章《${chapter.title}》` : `本章:第 ${chapterNo} 章`,\n prevTail !== ''\n ? `==================== 上一章(第 ${chapterNo - 1} 章)结尾(钩子) ====================\\n${prevTail}`\n : '(本书第一章,无上一章钩子;hookHonored 视为 true,hookNote 写\"开篇无前置钩子\")',\n prevChapter?.authorReview !== undefined\n ? `==================== 上一章作者复盘 ====================\\n${JSON.stringify(prevChapter.authorReview)}`\n : '',\n lines.length > 0\n ? `==================== 活跃剧情线 ====================\\n${lines.map(l => `- [${l.kind}] ${l.name}:${l.goal}${l.progress !== '' ? `(${l.progress})` : ''}`).join('\\n')}`\n : '',\n facts.length > 0\n ? `==================== 编年录近期事实 ====================\\n${facts.map(f => `[第${f.chapterNo}章] ${f.text}`).join('\\n')}`\n : '',\n '==================== 本章正文 ====================',\n body.slice(0, 16000),\n '',\n '只输出 JSON 对象。',\n ].join('\\n')\n const raw = parseJsonObject<{\n hookHonored?: unknown\n hookNote?: unknown\n endingHook?: unknown\n plotlineProgress?: unknown\n advancedLines?: unknown\n continuity?: unknown\n trend?: unknown\n }>(\n await complete(ctx, config, { system: authorReviewSystemPrompt(), user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 4000) }),\n )\n // 解析推进的线名(与项目线名精确匹配;过滤不存在的名字)。\n const knownLineNames = new Set((project.plotlines ?? []).map(l => l.name))\n const advancedLines = Array.isArray(raw.advancedLines)\n ? raw.advancedLines.filter((n): n is string => typeof n === 'string' && n.trim() !== '' && knownLineNames.has(n.trim())).map(n => n.trim())\n : []\n return {\n hookHonored: raw.hookHonored === true,\n hookNote: typeof raw.hookNote === 'string' ? raw.hookNote.slice(0, 200) : '',\n endingHook: typeof raw.endingHook === 'number' ? Math.max(0, Math.min(10, Math.round(raw.endingHook))) : 5,\n plotlineProgress: typeof raw.plotlineProgress === 'string' ? raw.plotlineProgress.slice(0, 200) : '',\n advancedLines,\n continuity: typeof raw.continuity === 'string' ? raw.continuity.slice(0, 200) : '',\n trend: typeof raw.trend === 'string' ? raw.trend.slice(0, 200) : '',\n reviewedAt: new Date().toISOString(),\n }\n}\n\n/** 复盘后自动关联:把本章号写入复盘标记推进的剧情线(按名称匹配,去重)。 */\nexport function autoLinkPlotlines(project: ProjectState, chapterNo: number, advancedLines: string[]): void {\n if (!Array.isArray(project.plotlines) || advancedLines.length === 0) return\n for (const line of project.plotlines) {\n if (advancedLines.includes(line.name) && !line.chapters.includes(chapterNo)) {\n line.chapters.push(chapterNo)\n }\n }\n}\n\n/** AI 建议剧情线:基于大纲/卷计划/已写章节/编年录,提炼候选线。 */\nexport async function suggestPlotlines(ctx: Context, config: NovelConfig, project: ProjectState): Promise<Plotline[]> {\n const system = [\n '你是一位网文剧情架构师。根据本书的大纲、卷计划、已写章节标题与编年录,为作者提炼建议的剧情线(主线/支线/人物线/悬念线)。',\n '每条线要:名称简洁有力;目标写清楚这条线最终要完成什么;progress 写当前推进到哪(没有就空字符串)。',\n '建议 4-8 条,覆盖:1 条主线、1-2 条人物线、1-2 条悬念线、1-3 条支线。避免与大纲明显重复的废话线。',\n '输出必须是合法 JSON 数组,格式:[{\"name\": \"线名\", \"kind\": \"main|branch|character|mystery\", \"goal\": \"目标\", \"progress\": \"\"}]',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending')\n const user = [\n `书名:《${project.bookName}》`,\n `大纲(节选前 4000 字):\\n${project.outline.slice(0, 4000)}`,\n project.volumes !== undefined && project.volumes.length > 0\n ? `卷计划:\\n${project.volumes.map(v => `第${v.no}卷《${v.title}》:${v.summary}`).join('\\n')}`\n : '',\n written.length > 0\n ? `已写章节:\\n${written.map(c => `第${c.no}章《${c.title}》${c.summary !== undefined && c.summary !== '' ? `:${c.summary.slice(0, 80)}` : ''}`).join('\\n')}`\n : '',\n (project.facts ?? []).length > 0\n ? `编年录近期事实(最近 15 条):\\n${(project.facts ?? []).slice(-15).map(f => `[第${f.chapterNo}章] ${f.text.slice(0, 100)}`).join('\\n')}`\n : '',\n '只输出 JSON 数组。',\n ].join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.6, maxTokens: Math.max(config.maxTokens, 4000) })\n const raw = parseJsonArray<Record<string, unknown>>(text)\n const lines: Plotline[] = []\n const kinds = new Set(['main', 'branch', 'character', 'mystery'])\n for (const entry of raw) {\n if (typeof entry !== 'object' || entry === null) continue\n const name = typeof entry.name === 'string' ? entry.name.trim().slice(0, 40) : ''\n if (name === '') continue\n lines.push({\n id: '',\n name,\n kind: kinds.has(entry.kind as string) ? entry.kind as Plotline['kind'] : 'branch',\n goal: typeof entry.goal === 'string' ? entry.goal.trim().slice(0, 300) : '',\n progress: typeof entry.progress === 'string' ? entry.progress.trim().slice(0, 300) : '',\n status: 'active',\n chapters: [],\n createdAt: new Date().toISOString(),\n })\n }\n return lines\n}\n\n/** AI 刷新单条剧情线的进度:结合编年录与各章摘要分析该线推进到哪。 */\nexport async function refreshPlotlineProgress(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n line: Plotline,\n): Promise<string> {\n const system = [\n '你是一位网文剧情线管理员。请根据「剧情线信息」与「本书已写章节摘要/编年录」,判断这条线目前推进到了哪一步。',\n '输出一句话(30-60 字):这条线当前的状态、最近一次推进发生在第几章、下一步可能的方向。如果这条线还没开始推进,明确说\"尚未推进\"。',\n '输出必须是合法 JSON 对象:{\"progress\": \"一句话\"}',\n '重要:不要输出任何其他文字。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending' && (c.summary !== undefined && c.summary !== ''))\n const user = [\n `剧情线:${line.name}(${line.kind})`,\n `目标:${line.goal}`,\n `已知进度:${line.progress !== '' ? line.progress : '(无)'}`,\n `已关联章节:${line.chapters.length > 0 ? line.chapters.map(n => `第${n}章`).join('、') : '(无)'}`,\n `章节摘要(最近 8 章):\\n${written.slice(-8).map(c => `第${c.no}章《${c.title}》:${c.summary!.slice(0, 120)}`).join('\\n')}`,\n (project.facts ?? []).length > 0\n ? `编年录近期事实(最近 15 条):\\n${(project.facts ?? []).slice(-15).map(f => `[第${f.chapterNo}章] ${f.text.slice(0, 100)}`).join('\\n')}`\n : '',\n '只输出 JSON 对象。',\n ].join('\\n\\n')\n const raw = parseJsonObject<{ progress?: unknown }>(\n await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 2000) }),\n )\n return typeof raw.progress === 'string' ? raw.progress.trim().slice(0, 300) : ''\n}\n\n/** ✨ AI 从全书提炼角色库:大纲 + 道藏 + 编年录 + 章节摘要 → 结构化角色清单。 */\nexport async function extractRoles(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n): Promise<RoleRecord[]> {\n const system = [\n '你是一位网文角色库管理员。请根据本书的大纲、设定、编年录与章节摘要,提炼完整的角色库。',\n '覆盖原则:所有在编年录/章节中实际出场或有名有姓的角色都应收录;无名的功能性人物(如\"矮胖姑娘\")用其身份简称收录并标注。',\n '数量控制:最多输出 10 个角色,宁缺毋滥;路人级一次带过的不要收录。',\n '每个角色输出:',\n '1. name:角色名(或身份简称)。主角/有名配角必须用正文中实际出现的人名(如「沈放」),禁止用「主角(38岁超市理货员)」这类把身份塞进名字的占位名;正文确实没点名时才可用身份简称(如「富商」「灰衣老人」)。',\n '2. roleLabel:定位——protagonist=主角;female_lead=女主(唯一知己/感情线核心,无后宫前提下只此一位);female_support=重要女配;support=普通配角;antagonist=反派;extra=路人/背景。',\n '3. identity:身份一句话(宗门/势力/血脉/职业)。',\n '4. traits:3-6 个性格标签。',\n '5. goals:目标与动机一句话。',\n '6. relations:关系网数组,格式[\"角色名(关系)\", ...]。',\n '7. arc:成长线数组,格式[\"阶段:说明\", ...](如\"出场:祭品身份\"/\"转折:祭祀被中断脱身\")。',\n '8. knowledge:该角色已经知道的关键信息(3-8 条),不知道的信息不要写进去。',\n '精简要求:identity 控制在 30 字内;traits 3-6 个短标签;goals 60 字内;relations 2-5 条;arc 2-4 条;knowledge 每条 40 字内。整体输出量要紧凑,避免冗长。',\n '重要:用户消息里列出的「已收录角色」绝不要再次输出——这些角色已经在角色库里,跳过它们,只提炼未收录的。',\n '输出必须是合法 JSON 数组,不要输出其他文字:[{\"name\":\"...\", \"roleLabel\":\"...\", \"identity\":\"...\", \"traits\":[...], \"goals\":\"...\", \"relations\":[...], \"arc\":[...], \"knowledge\":[...]}]',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating')\n const existingRoles = project.roles ?? []\n // 正文摘录:让提炼真正读到书的内容(角色姓名/身份/关系以正文为准)。\n const excerptParts: string[] = []\n for (const chapter of written.slice(0, 3)) {\n const body = readChapterFile(config.outputDir, chapter)\n if (body === undefined) continue\n const text = body.replace(/^#.*$/gm, '').trim()\n if (text.length > 0) excerptParts.push(`第${chapter.no}章《${chapter.title}》\\n${text.slice(0, 2400)}`)\n }\n const user = [\n `书名:《${project.bookName}》`,\n existingRoles.length > 0\n ? `已收录角色(跳过,不要输出):${existingRoles.map(r => r.name).join('、')}`\n : '',\n `大纲(节选前 3000 字):\\n${project.outline.slice(0, 3000)}`,\n excerptParts.length > 0\n ? `已写正文摘录(角色姓名/身份/关系以正文为准):\\n${excerptParts.join('\\n\\n')}`\n : '',\n project.bible !== undefined && project.bible.characters.length > 0\n ? `已有角色卡(补充信息):\\n${project.bible.characters.map(c => `- ${c.name}(${c.role}):${c.traits.join('、')}${c.goals !== '' ? `;目标:${c.goals}` : ''}`).join('\\n')}`\n : '',\n (project.facts ?? []).length > 0\n ? `编年录(最近 60 条):\\n${(project.facts ?? []).slice(-60).map(f => `[第${f.chapterNo}章] ${f.text.slice(0, 80)}`).join('\\n')}`\n : '',\n written.length > 0\n ? `已写章节标题(${written.length} 章):\\n${written.map(c => `第${c.no}章《${c.title}》`).join('、')}`\n : '',\n '只输出 JSON 数组。',\n ].join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 24000) })\n const raw = parseJsonArray<Record<string, unknown>>(text)\n const labels = new Set(['protagonist', 'female_lead', 'female_support', 'support', 'antagonist', 'extra'])\n const strArr = (v: unknown): string[] => Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string' && x.trim() !== '') : []\n const roles: RoleRecord[] = []\n for (const entry of raw) {\n if (typeof entry !== 'object' || entry === null) continue\n const name = typeof entry.name === 'string' ? entry.name.trim().slice(0, 30) : ''\n if (name === '') continue\n roles.push({\n name,\n roleLabel: labels.has(entry.roleLabel as string) ? entry.roleLabel as RoleRecord['roleLabel'] : 'support',\n identity: typeof entry.identity === 'string' ? entry.identity.slice(0, 100) : '',\n traits: strArr(entry.traits).map(t => t.slice(0, 20)).slice(0, 8),\n goals: typeof entry.goals === 'string' ? entry.goals.slice(0, 200) : '',\n relations: strArr(entry.relations).map(r => r.slice(0, 60)).slice(0, 10),\n arc: strArr(entry.arc).map(a => a.slice(0, 120)).slice(0, 10),\n knowledge: strArr(entry.knowledge).map(k => k.slice(0, 120)).slice(0, 12),\n })\n }\n return roles\n}\n\n/** ✨ AI 从全书提炼场景库:正文/编年录 → 高频重要场景的结构化视觉锚点。 */\nexport async function extractScenes(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n): Promise<SceneCard[]> {\n const system = [\n '你是一位网文漫剧场景导演。根据本书的大纲、编年录与已写章节摘录,提炼「镜头场景」——漫剧分镜/生图时每个镜头要知道\"在哪、什么时间光态、拍什么情节、人物什么状态\"。',\n '按五幕结构覆盖全书核心场景(短篇 10 章内可少于五幕,按实际剧情组织):第一幕后场/核心主场、第二幕对外卖场/营业区、第三幕禁忌区域/地下深仓、第四幕外部人间世界(短暂出逃)、第五幕回归与抉择。',\n '每个场景必须是「镜头场景」而非仅场地:给出该场景的关键情节镜头(人物动作+情绪+镜头推进)。',\n '数量控制:最多输出 8 个场景;每个场景必须能对应到正文实际出现过的地点与情节,不得凭空虚构。',\n '每个场景输出:',\n '1. name:场景名(地点+光态,如「后场通道·装卸口(雨夜)」)。',\n '2. act:幕归属(第一幕后场/第二幕卖场/第三幕深仓/第四幕外界/第五幕抉择)。',\n '3. moment:时间光态(夜间闭店后/雨夜/凌晨/频闪灯…)。',\n '4. summary:一句话定位(空间类型/功能/氛围)。',\n '5. beats:关键情节镜头 1-3 条(人物动作+情绪+镜头推进,如\"沈放佝偻站在货架过道,镜头推近,情绪从漠然过渡到压抑悲伤\")。',\n '6. characterState:主角/关键角色在该场景的状态一句话(含标志物细节如标签磨损、手腕红痕)。',\n '7. elements:环境构成数组 3-6 项(空间结构/陈设/标志物)。',\n '8. palette:色调与光影数组 2-4 项(颜色词,可附 HEX)。',\n '9. moods:氛围关键词 2-4 个(压抑/神秘/空旷/悲凉…)。',\n '10. zh:中文生图提示词(连贯一段,写实电影感,含环境/光线/氛围/人物状态)。',\n '11. en:英文生图提示词(booru 风格逗号分隔,含 photorealistic/cinematic)。',\n '12. tags:3-6 个关键标签。',\n '13. source:依据来源说明(哪几章哪些描写)。',\n '若故事存在结局抉择(如双分支),最后 1-2 个场景应为「抉择场景」,zh 里写明分支 A/B 两种画面。',\n '输出必须是合法 JSON 数组,不要输出其他文字:[{\"name\":\"...\", \"act\":\"...\", \"moment\":\"...\", \"summary\":\"...\", \"beats\":[...], \"characterState\":\"...\", \"elements\":[...], \"palette\":[...], \"moods\":[...], \"zh\":\"...\", \"en\":\"...\", \"tags\":[...], \"source\":\"...\"}]',\n '重要:所有字符串值内部不得包含换行符;直接输出 JSON 结果本身。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating')\n const excerptParts: string[] = []\n for (const chapter of written.slice(0, 4)) {\n const body = readChapterFile(config.outputDir, chapter)\n if (body === undefined) continue\n const text = body.replace(/^#.*$/gm, '').trim()\n if (text.length > 0) excerptParts.push('第' + chapter.no + '章《' + chapter.title + '》' + '\\n' + text.slice(0, 1800))\n }\n const user = [\n '书名:《' + project.bookName + '》',\n (project.facts ?? []).length > 0\n ? '编年录(最近 80 条,场景地点以这里为准):' + '\\n' + (project.facts ?? []).slice(-80).map(f => '[第' + f.chapterNo + '章] ' + f.text.slice(0, 80)).join('\\n')\n : '',\n excerptParts.length > 0\n ? '已写正文摘录(场景描写以正文为准):' + '\\n' + excerptParts.join('\\n')\n : '',\n '只输出 JSON 数组。',\n ].filter(s => s !== '').join('\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.4, maxTokens: Math.max(config.maxTokens, 12000) })\n const raw = parseJsonArray<Record<string, unknown>>(text)\n const strArr = (v: unknown): string[] => Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string' && x.trim() !== '') : []\n const str = (v: unknown): string => typeof v === 'string' ? v.trim() : ''\n const scenes: SceneCard[] = []\n for (const entry of raw) {\n if (typeof entry !== 'object' || entry === null) continue\n const name = str(entry.name).slice(0, 40)\n if (name === '') continue\n scenes.push({\n name,\n act: str(entry.act).slice(0, 40),\n moment: str(entry.moment).slice(0, 60),\n summary: str(entry.summary).slice(0, 120),\n beats: strArr(entry.beats).map(t => t.slice(0, 120)).slice(0, 3),\n characterState: str(entry.characterState).slice(0, 160),\n elements: strArr(entry.elements).map(t => t.slice(0, 60)).slice(0, 6),\n palette: strArr(entry.palette).map(t => t.slice(0, 40)).slice(0, 4),\n moods: strArr(entry.moods).map(t => t.slice(0, 20)).slice(0, 4),\n zh: str(entry.zh).slice(0, 800),\n en: str(entry.en).slice(0, 600),\n tags: strArr(entry.tags).map(t => t.slice(0, 24)).slice(0, 6),\n source: str(entry.source).slice(0, 120),\n })\n }\n return scenes\n}\n\n/** 动漫形象描述词(中文描述 + 英文 booru 标签 + 关键外貌标签)。 */\nexport interface RoleVisualPrompt {\n zh: string\n en: string\n tags: string[]\n source: string\n /** 该角色所需情绪表情清单(6-12 个,如 疲惫/麻木/压抑悲伤)。 */\n expressions?: string[]\n /** 四类精修提示词(立绘/四视图/表情/细节,一次提炼直接产出)。 */\n promptKit?: RoleRecord['promptKit']\n}\n\n/**\n * 为单个角色提炼「动漫形象描述词」:扫描该角色出场的已写章节正文,\n * 截取含外貌描写的段落,交给 LLM 提炼中文描述 + 英文绘图标签。\n */\nexport async function extractRoleVisual(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n roleName: string,\n): Promise<RoleVisualPrompt> {\n const role = (project.roles ?? []).find(r => r.name === roleName)\n if (role === undefined) throw new Error(`角色「${roleName}」不在角色库中`)\n\n // 1. 扫描正文:收集该角色出场且可能含外貌描写的段落(最近 60 章内,每章最多 2 段,共 12 段)。\n // 支持“描述型角色名”(如「灰蓝工装女人」):先精确匹配,匹配不到时用角色名拆分出的关键词兜底。\n const appearanceHints = /(发|眉|眼|眸|脸|肤|唇|身材|身高|衣|袍|裙|衫|靴|腰带|气质|模样|长相|容貌|披|束|扎|戴|佩|挂|绣|青|白|黑|红|蓝|紫|灰|银|金|少年|青年|少女|汉子|老者|中年|纤细|挺拔|瘦削|壮实|清秀|俊朗|英气|阴鸷|慈眉)/\n // 从角色名 + 身份描述中提取可检索关键词,支持“描述型角色名”(灰蓝工装女人)和“身份型角色名”(富商)。\n const roleText = `${role.name} ${role.identity ?? ''}`\n const colorWords = ['深灰', '灰蓝', '灰', '蓝', '白', '黑', '红', '青', '紫', '银', '金', '黄', '绿', '粉', '棕']\n const garmentWords = ['工装', '西装', '定制西装', '袍', '裙', '衫', '衣', '裤', '靴', '鞋', '帽', '腰带', '制服', '外套', '马甲', '夹克']\n const roleWords = ['女人', '男人', '老者', '老人', '中年', '青年', '少女', '姑娘', '男子', '女子', '工人', '路人', '购买者']\n const locationWords = ['别墅', '小区', '街区']\n const identityTokens = (role.identity ?? '').split(/[,,。\\s]+/).filter(t => t.length >= 2)\n const searchTokens = Array.from(new Set([\n roleName,\n ...identityTokens,\n ...colorWords.filter(w => roleText.includes(w)),\n ...garmentWords.filter(w => roleText.includes(w)),\n ...roleWords.filter(w => roleText.includes(w)),\n ...locationWords.filter(w => roleText.includes(w)),\n ])).filter(t => t.length >= 2)\n const matchesRole = (para: string): boolean => para.includes(roleName) || searchTokens.some(tok => para.includes(tok))\n const excerpts: Array<{ no: number; text: string }> = []\n const written = project.chapters\n .filter(c => c.status !== 'pending' && c.status !== 'generating' && c.file !== undefined)\n .slice(-60)\n for (const chapter of written) {\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) continue\n const paras = body.split(/\\n{2,}/).map(p => p.trim()).filter(p => p.length > 0)\n let perChapter = 0\n for (const para of paras) {\n if (perChapter >= 2 || excerpts.length >= 12) break\n if (!matchesRole(para)) continue\n // 优先外貌描写段(含外貌关键词),否则纯动作段也收(LLM 自己判断)。\n if (appearanceHints.test(para) || excerpts.length < 4) {\n excerpts.push({ no: chapter.no, text: para.slice(0, 220) })\n perChapter++\n }\n }\n if (excerpts.length >= 12) break\n }\n if (excerpts.length === 0) {\n throw new Error(`正文中未找到「${roleName}」的出场描写(仅搜索最近 60 章),请确认角色名与正文一致`)\n }\n\n // 2. LLM 提炼:一次输出 锚点 + 表情清单 + 四类精修提示词。\n const rules = project.visualRules ?? []\n const system = [\n '你是一位动漫角色设定师与 AI 绘图提示词工程师。根据网文正文中该角色的实际外貌描写,输出「形象锚点」与「四类生图提示词」——一次完成,用于 AI 绘图(NovelAI / Stable Diffusion / Midjourney / 豆包等)生成一致的角色立绘。',\n '硬性要求(依据优先):',\n '1. 发色/发型/瞳色/服装/气质/标志物必须来自提供的正文段落,不得凭空发明。',\n '2. 正文未明确写到的项目(如瞳色没写、身高没写),用「未定」标注或直接不写,不要编造数值。',\n '3. 服装优先取正文明确出现的(颜色+款式),多次出现取最常穿的组合;服装按分件组织(上身/下身/鞋/配饰)。',\n '4. 标志物(标签/印记/饰品)必须出现在每段提示词中——它们是一致性的命根子。',\n '【本书视觉规则】(必须内嵌进每段提示词,保证设定不跑偏):',\n ...rules.map(r => '- ' + r),\n '输出六部分:',\n '- zh:中文形象锚点,一段连贯文字(60-150 字):发色发型、瞳色、脸型气质、服装(颜色款式)、身材、标志性物件。',\n '- en:英文形象锚点,booru 风格、逗号分隔、小写,30-50 个标签:含性别(1boy/1girl)、发色、发型、瞳色、服装、气质、标志物。不要输出负面提示词。',\n '- tags:中文关键标签数组,5-10 个(如 [\"黑发\",\"束发\",\"青色道袍\",\"清秀\",\"腰悬古玉\"])。',\n '- source:说明依据(如\"第1章/第8章外貌描写;瞳色未明确\")。',\n '- expressions:该角色在本书剧情中需要的情绪表情清单数组,6-12 个(如 [\"疲惫\",\"麻木\",\"压抑悲伤\",\"皱眉\",\"紧绷\",\"放空\"]),依据正文情绪描写与角色处境推断。',\n '- promptKit:四类精修提示词(字段化+出图约束,参考示例结构):',\n ' · portrait 立绘:严格按字段顺序写(参考示例结构):开头构图定位(正面站立全身人像)→ 风格(3D动漫,超精细建模)→ 背景(纯白纯色背景)→ 身份(男子,{角色名},外表{年龄},男性)→ 发型发色 → 胡茬 → 眼眸 → 面部 → 气质 → 上身服装分件(颜色款式+磨损细节)→ 下身 → 鞋 → 标志物(标签/印记,含细节如洇暗翘边)→ 收尾(角色设计稿,细节完整展示,无多余杂物,全身完整无裁切)。',\n ' · sheet 四视图:同一角色的 正面/左侧面/右侧面/背面 四视图设定表(character sheet),纯白背景,全身完整,四个视角分别描述,服装与标志物细节完整展示。',\n ' · expressions 表情:每个表情一段,脸部特写(头部到锁骨),纯白背景,五官与角色定稿完全一致,只换情绪表达(眼神/嘴角/眉),皮肤纹理细节完整,无多余杂物。',\n ' · details 细节:多组局部细节集合参考图(一张图多个局部框),纯白背景;把该角色全部标志物逐项列出(如标签/印记/工牌/袖口磨损/鞋),每项一句特写描述;细节清晰锐利,角色细节参考稿,无多余杂物。',\n 'promptKit 每段 zh:连贯中文 60-150 字;en:booru 标签 30-50 个。',\n '输出必须是合法 JSON 对象:{\"zh\": \"...\", \"en\": \"...\", \"tags\": [...], \"source\": \"...\", \"expressions\": [...], \"promptKit\": {\"portrait\": {\"zh\":\"...\", \"en\":\"...\"}, \"sheet\": {\"zh\":\"...\", \"en\":\"...\"}, \"expressions\": [{\"name\":\"疲惫\",\"zh\":\"...\",\"en\":\"...\"}], \"details\": {\"zh\":\"...\", \"en\":\"...\"}}}',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n const user = [\n `书名:《${project.bookName}》`,\n `目标角色:${role.name}(${role.identity})`,\n role.traits.length > 0 ? `性格标签:${role.traits.join('、')}` : '',\n `正文出场描写(含外貌线索的段落):`,\n ...excerpts.map(e => `[第${e.no}章] ${e.text}`),\n '只输出 JSON 对象。',\n ].join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.4, maxTokens: Math.max(config.maxTokens, 12000) })\n const raw = parseJsonObject<{ zh?: unknown; en?: unknown; tags?: unknown; source?: unknown; expressions?: unknown; promptKit?: unknown }>(text)\n const zh = typeof raw.zh === 'string' ? raw.zh.trim().slice(0, 500) : ''\n const en = typeof raw.en === 'string' ? raw.en.trim().slice(0, 1500) : ''\n const tags = Array.isArray(raw.tags)\n ? raw.tags.filter((t): t is string => typeof t === 'string' && t.trim() !== '').map(t => t.trim().slice(0, 20)).slice(0, 12)\n : []\n const source = typeof raw.source === 'string' ? raw.source.trim().slice(0, 300) : ''\n const expressions = Array.isArray(raw.expressions)\n ? raw.expressions.filter((e): e is string => typeof e === 'string' && e.trim() !== '').map(e => e.trim().slice(0, 12)).slice(0, 12)\n : []\n // 四类精修提示词(一次提炼直接产出)\n const str = (v: unknown): string => typeof v === 'string' ? v.trim() : ''\n const pair = (v: unknown): { zh: string; en: string } => {\n const o = (typeof v === 'object' && v !== null) ? v as Record<string, unknown> : {}\n return { zh: str(o.zh).slice(0, 800), en: str(o.en).slice(0, 1200) }\n }\n const kitRaw = (typeof raw.promptKit === 'object' && raw.promptKit !== null) ? raw.promptKit as Record<string, unknown> : {}\n const kitExpr = Array.isArray(kitRaw.expressions) ? kitRaw.expressions.filter((e): e is Record<string, unknown> => typeof e === 'object' && e !== null) : []\n let promptKit: RoleRecord['promptKit']\n try {\n promptKit = {\n portrait: pair(kitRaw.portrait),\n sheet: pair(kitRaw.sheet),\n expressions: kitExpr.map(e => ({\n name: str(e.name).slice(0, 12) || '表情',\n zh: str(e.zh).slice(0, 800),\n en: str(e.en).slice(0, 1200),\n })).slice(0, 12),\n details: pair(kitRaw.details),\n }\n } catch {\n promptKit = undefined\n }\n if (zh === '' || en === '') {\n throw new Error('形象描述提炼失败:LLM 未返回有效 JSON')\n }\n return { zh, en, tags, source, expressions, promptKit }\n}\n\n/**\n * 角色四类生图提示词精修包(promptKit):以锚点 + 表情清单 + 视觉规则为输入,\n * LLM 产出 立绘/四视图/表情×N/细节 四套 zh+en 提示词(比前端拼装更精炼)。\n */\nexport async function generateRolePromptKit(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n roleName: string,\n): Promise<RoleRecord['promptKit']> {\n const role = (project.roles ?? []).find(r => r.name === roleName)\n if (role === undefined) throw new Error(`角色「${roleName}」不在角色库中`)\n if (role.imagePrompt === undefined) throw new Error(`角色「${roleName}」还没有形象锚点,请先生成锚点`)\n const rules = project.visualRules ?? []\n const system = [\n '你是一位 AI 绘图提示词工程师。基于给定角色的形象锚点、表情清单与本书视觉规则,输出四类生图提示词(每类 zh+en 各一段)。',\n '四类:',\n '1. portrait 立绘:正面站立全身人像,3D动漫超精细建模,纯白纯色背景;按字段流组织:身份(男子,角色名,外表年龄)→ 发型发色 → 胡茬 → 眼眸 → 面部 → 气质 → 上身服装分件(含磨损)→ 下身 → 鞋 → 标志物(含细节)→ 收尾(角色设计稿,细节完整展示,无多余杂物,全身完整无裁切)。',\n '2. sheet 四视图:同一角色的 正面/左侧面/右侧面/背面 四视图设定表(character sheet),纯白背景,四个视角分别描述。',\n '3. expressions 表情:每个表情一段,脸部特写(头部到锁骨),纯白背景,五官与角色定稿完全一致,只换情绪表达(眼神/嘴角/眉),皮肤纹理细节完整,无多余杂物。',\n '4. details 细节:多组局部细节集合参考图(一张图多个局部框),纯白背景;把该角色全部标志物逐项列出,每项一句特写描述;细节清晰锐利,角色细节参考稿,无多余杂物。',\n '【本书视觉规则】(必须内嵌进每段提示词,保证设定不跑偏):',\n ...rules.map(r => '- ' + r),\n 'zh 要求:连贯中文,写实电影感,60-150 字/段;en 要求:booru 风格逗号分隔标签,30-50 个/段。',\n '输出必须是合法 JSON 对象:{\"portrait\": {\"zh\": \"...\", \"en\": \"...\"}, \"sheet\": {\"zh\": \"...\", \"en\": \"...\"}, \"expressions\": [{\"name\": \"疲惫\", \"zh\": \"...\", \"en\": \"...\"}], \"details\": {\"zh\": \"...\", \"en\": \"...\"}}',\n '重要:所有字符串值内部不得包含换行符;直接输出 JSON 结果本身。',\n ].join('\\n')\n const user = [\n `角色:${role.name}(${role.identity ?? ''})`,\n `中文锚点:${role.imagePrompt.zh}`,\n `英文锚点:${role.imagePrompt.en}`,\n `关键标签:${role.imagePrompt.tags.join('、')}`,\n `表情清单:${(role.expressions ?? []).join('、') || '(未提供,按角色气质推断 6 个)'}`,\n '只输出 JSON 对象。',\n ].join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.4, maxTokens: Math.max(config.maxTokens, 12000) })\n const raw = parseJsonObject<Record<string, unknown>>(text)\n const str = (v: unknown): string => typeof v === 'string' ? v.trim() : ''\n const pair = (v: unknown): { zh: string; en: string } => {\n const o = (typeof v === 'object' && v !== null) ? v as Record<string, unknown> : {}\n return { zh: str(o.zh).slice(0, 800), en: str(o.en).slice(0, 1200) }\n }\n const expressionsRaw = Array.isArray(raw.expressions) ? raw.expressions.filter((e): e is Record<string, unknown> => typeof e === 'object' && e !== null) : []\n const kit: RoleRecord['promptKit'] = {\n portrait: pair(raw.portrait),\n sheet: pair(raw.sheet),\n expressions: expressionsRaw.map(e => ({\n name: str(e.name).slice(0, 12) || '表情',\n zh: str(e.zh).slice(0, 800),\n en: str(e.en).slice(0, 1200),\n })).slice(0, 12),\n details: pair(raw.details),\n }\n if (kit.portrait.zh === '' || kit.portrait.en === '') {\n throw new Error('提示词精修失败:LLM 未返回有效 JSON')\n }\n return kit\n}\n\n/** ✨ 从道藏/红线提炼「视觉世界观规则」:生图/生视频必须遵守的设定纠偏(如\"商品=人,禁止常规超市商品\")。 */\nexport async function extractVisualRules(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n): Promise<string[]> {\n const system = [\n '你是一位 AI 绘图的视觉规则设计师。本书的设定是\"反常识\"的,生图/生视频模型默认会画成现实世界的样子,你需要提炼 3-6 条「视觉规则」钉住本书的视觉世界观。',\n '规则要求:',\n '1. 每条必须可执行:明确\"画面里必须出现什么/禁止出现什么\"(如\"货架上的一切商品都是活人,禁止画成罐头/饮料/日用品\")。',\n '2. 覆盖本书最容易被模型画错的 2-4 个核心反常识点。',\n '3. 每条 40 字内,禁止泛泛而谈。',\n '输出必须是合法 JSON 数组:[\"规则1\", \"规则2\", ...],不要输出其他文字。',\n ].join('\\n')\n const bible = project.bible\n const user = [\n `书名:《${project.bookName}》`,\n `题材:${bible?.genre ?? ''}`,\n bible !== undefined && bible.worldRules.length > 0\n ? `世界规则:\\n${bible.worldRules.map(r => '- ' + r).join('\\n')}`\n : '',\n bible !== undefined && bible.redLines.length > 0\n ? `红线:\\n${bible.redLines.map(r => '- ' + r).join('\\n')}`\n : '',\n '只输出 JSON 数组。',\n ].filter(s => s !== '').join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 4000) })\n const raw = parseJsonArray<string>(text)\n return raw.map(r => typeof r === 'string' ? r.trim().slice(0, 80) : '').filter(r => r !== '').slice(0, 8)\n}\n\n\n/**\n * 开书想法 → AI 大纲:输入一句话想法,生成 2-3 个方向不同、可直接开书的完整大纲方案。\n * @param count 本次生成几个(默认 3,最多 3)\n * @param exclude 已暂留方案的剧情方向/卖点摘要(换批时避开,防止重复)\n */\nexport async function suggestOutlines(\n ctx: Context,\n config: NovelConfig,\n idea: string,\n count = 3,\n exclude: string[] = [],\n): Promise<OutlineCandidate[]> {\n const n = Math.max(1, Math.min(3, Math.floor(count)))\n const system = [\n '你是一位资深网文策划。作者只给了一句「想法」,你需要把它扩展成 2-3 个【方向差异明显】的完整小说大纲方案,供作者挑选。',\n '每个方案必须满足:',\n '1. bookName:书名(6 字以内,抓眼球、点题)。',\n '2. genre:题材(如 仙侠修真 / 都市异能 / 玄幻 / 悬疑)。',\n '3. sellingPoint:核心卖点一句话(金手指/爽点/差异化,40 字内)。',\n '4. outline:完整大纲文本(至少 800 字,可直接作为开书大纲),结构包含:书名与题材、金手指/核心设定、主角人设与动机、主线剧情走向(至少 5 个阶段)、关键配角与势力、卖点与爽点设计、预计分卷(3-5 卷)。',\n '方向差异要求:',\n '- 方案之间的金手指/剧情走向必须明显不同(如:苟道发育流 vs 随身老爷爷流 vs 群像争霸流),不能只是换书名。',\n '- 忠实于作者想法的核心要素,但允许在不同方向上进行合理演绎。',\n '- 不输出任何与已列「需避开的方向」雷同的方案。',\n '输出必须是合法 JSON 数组,只输出数组本身:',\n '[{\"id\": \"唯一id\", \"bookName\": \"...\", \"genre\": \"...\", \"sellingPoint\": \"...\", \"outline\": \"...\"}]',\n `本次只输出 ${n} 个方案。`,\n '重要:所有字符串值内部不得包含换行符(大纲内部分段请用「。\\n」或「;」自然断句),JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n const user = [\n `作者的想法:${idea}`,\n idea.trim().length < 40\n ? '作者的想法非常简短(可能只有一句)。请基于通用网文套路合理扩展补全:为每个方案自洽地设计金手指/核心设定、主角人设与动机、主线走向,使其成为完整可开书的大纲;不同方案的方向仍须明显差异。'\n : '',\n exclude.length > 0\n ? `需避开的已暂留方案方向(新方案不得与之雷同):\\n${exclude.map((e, i) => `${i + 1}. ${e}`).join('\\n')}`\n : '',\n `请生成 ${n} 个大纲方案。`,\n '只输出 JSON 数组。',\n ].join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.85, maxTokens: Math.max(config.maxTokens, 12000) })\n const parsed = parseJsonArray<Record<string, unknown>>(text)\n const candidates: OutlineCandidate[] = []\n for (const entry of parsed) {\n if (typeof entry !== 'object' || entry === null) continue\n const bookName = typeof entry.bookName === 'string' ? entry.bookName.trim().slice(0, 30) : ''\n const outline = typeof entry.outline === 'string' ? entry.outline.trim() : ''\n if (bookName === '' || outline.length < 300) continue\n candidates.push({\n id: typeof entry.id === 'string' && entry.id !== '' ? entry.id : `oc-${Date.now().toString(36)}-${candidates.length}`,\n bookName,\n genre: typeof entry.genre === 'string' ? entry.genre.trim().slice(0, 20) : '',\n sellingPoint: typeof entry.sellingPoint === 'string' ? entry.sellingPoint.trim().slice(0, 120) : '',\n outline,\n })\n }\n if (candidates.length === 0) {\n throw new Error('大纲方案生成失败:LLM 未返回有效 JSON(可重试)')\n }\n return candidates.slice(0, n)\n}\n\n/** 拆书分析:对已写章节做结构/人物/文风/卖点四维体检。\n * 两阶段管道(借鉴 AI-Novel-Writing-Assistant):\n * ① 源片段笔记:每章抽取结构化笔记(剧情/人物/设定/写法/卖点/短板信号)\n * ② 分节分析:按维度各跑一次 LLM,输出可读分析稿 + 结构化数据 + 证据链。\n * @param scope 'recent'(默认最近20章) | 'volume:N' | 'all'\n * @param preset 'quick'(总览/剧情/人物/文风) | 'standard'(+卖点)\n * @param budgetTokens token 预算上限(超过即截断章节取样)。\n */\nexport async function breakdownBook(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n scope = 'recent',\n preset: 'quick' | 'standard' = 'quick',\n budgetTokens = 50000,\n): Promise<BreakdownResponse> {\n // 1. 选章节范围。\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating' && c.summary !== undefined && c.summary !== '')\n let selected = written\n if (scope === 'recent') selected = written.slice(-20)\n else if (/^volume:\\d+$/.test(scope)) {\n const v = Number(scope.slice(7))\n selected = written.filter(c => c.volume === v)\n }\n if (selected.length === 0) throw new Error('没有可分析的已写章节(需要已生成并带摘要)')\n\n // 2. token 预算:估算每章正文+摘要成本,超预算则只取最近的章节。\n let budget = budgetTokens\n const chunks: Array<{ no: number; title: string; summary: string; body: string }> = []\n for (const c of selected.slice().reverse()) {\n const body = readChapterFile(outputDir, c) ?? ''\n // 粗估:每 4 字符 ≈ 1 token(中文),章节正文截 4000 字上限。\n const bodySlice = body.replace(/^#\\s+.*$/m, '').trim().slice(0, 4000)\n const est = Math.ceil((bodySlice.length + (c.summary?.length ?? 0)) / 4) + 400\n if (est > budget && chunks.length > 0) break\n chunks.unshift({ no: c.no, title: c.title, summary: c.summary ?? '', body: bodySlice })\n budget -= est\n }\n\n // 3. 阶段一:源片段笔记(每章一次 LLM,串行控制 token)。\n const notes: string[] = []\n let usedTokens = 0\n const noteSystem = [\n '你是中文网文拆书助手。把单章正文整理成结构化笔记,供后续章节级分析复用。',\n '只输出 JSON 对象:',\n '{\"summary\": \"1-2句\", \"plotPoints\": [\"...\"], \"characters\": [\"...\"], \"worldbuilding\": [\"...\"], \"styleTechniques\": [\"...\"], \"marketHighlights\": [\"...\"], \"weaknessSignals\": [\"...\"]}',\n '硬规则:只提取正文明确出现的信息;每数组最多 4 项;不要补写原文外的动机/意图;evidence 不在此阶段输出。',\n '重要:直接输出 JSON,不要输出其他文字;字符串内不含换行。',\n ].join('\\n')\n for (const ch of chunks) {\n const noteUser = [`第${ch.no}章《${ch.title}》`, '正文:', ch.body.slice(0, 3000)].join('\\n')\n try {\n const text = await complete(ctx, config, { system: noteSystem, user: noteUser, temperature: 0.2, maxTokens: Math.max(config.maxTokens, 3000) })\n const raw = parseJsonObject<Record<string, unknown>>(text)\n const pick = (k: string): string[] => Array.isArray(raw[k]) ? raw[k].filter((x): x is string => typeof x === 'string' && x.trim() !== '').map(x => x.trim().slice(0, 120)).slice(0, 4) : []\n notes.push(\n `【第${ch.no}章《${ch.title}》】\\n`\n + `摘要:${typeof raw.summary === 'string' ? raw.summary.slice(0, 200) : ''}\\n`\n + `剧情:${pick('plotPoints').join(';')}\\n`\n + `人物:${pick('characters').join(';')}\\n`\n + `设定:${pick('worldbuilding').join(';')}\\n`\n + `写法:${pick('styleTechniques').join(';')}\\n`\n + `卖点:${pick('marketHighlights').join(';')}\\n`\n + `短板信号:${pick('weaknessSignals').join(';') || '(无明显短板信号)'}`,\n )\n usedTokens += 800\n } catch {\n // 单章笔记失败不致命——跳过继续。\n }\n }\n\n // 4. 阶段二:分节分析。\n const sectionsConfig: Array<{ key: string; title: string; focus: string; system: string }> = [\n {\n key: 'overview',\n title: '拆书总览',\n focus: '一句话定位、题材标签、整体优势与短板',\n system: [\n '你是资深中文网文拆书分析师,负责《拆书总览》小节。',\n '基于给定章节笔记做低风险综合判断,输出 JSON:{\"markdown\": \"可直接展示的分析稿(简体中文,先给结论再说明体现在哪、为何成立)\", \"structured\": {\"oneLinePositioning\": \"一句话定位\", \"genreTags\": [\"题材标签\"], \"sellingPointTags\": [\"卖点标签\"], \"strengths\": [\"整体优势\"], \"weaknesses\": [\"整体短板\"]}}',\n '硬规则:只基于笔记归纳;推断用「更偏向/可能」等谨慎措辞;证据不足写「材料不足」;不虚构原文细节。',\n '重要:直接输出 JSON,字符串内不含换行。',\n ].join('\\n'),\n },\n {\n key: 'plot',\n title: '剧情结构',\n focus: '主线梗概、阶段推进、冲突升级、节奏风险',\n system: [\n '你是资深中文网文拆书分析师,负责《剧情结构》小节。',\n '基于给定章节笔记分析,输出 JSON:{\"markdown\": \"分析稿(简体中文,先结论后依据)\", \"structured\": {\"mainlineSummary\": \"主线梗概\", \"phaseProgressions\": [\"阶段推进\"], \"escalationDesigns\": [\"冲突升级\"], \"paceRisks\": [\"节奏风险\"], \"reusablePatterns\": [\"可复用套路\"]}}',\n '硬规则:只基于笔记归纳;推断谨慎措辞;不虚构。',\n '重要:直接输出 JSON,字符串内不含换行。',\n ].join('\\n'),\n },\n {\n key: 'character',\n title: '人物系统',\n focus: '主角定位、配角功能、关系网络、成长弧线、辨识度风险',\n system: [\n '你是资深中文网文拆书分析师,负责《人物系统》小节。',\n '基于给定章节笔记分析,输出 JSON:{\"markdown\": \"分析稿(简体中文,先结论后依据)\", \"structured\": {\"protagonistPositioning\": \"主角定位\", \"supportingFunctions\": [\"配角功能\"], \"relationshipNetwork\": [\"关系网络\"], \"growthArcs\": [\"成长弧线\"], \"clarityRisks\": [\"辨识度风险\"]}}',\n '硬规则:只基于笔记归纳;推断谨慎措辞;不虚构。',\n '重要:直接输出 JSON,字符串内不含换行。',\n ].join('\\n'),\n },\n {\n key: 'style',\n title: '文风与技法',\n focus: '叙事视角、语言风格、描写方式、节奏控制、钩子设计、可复用写法',\n system: [\n '你是资深中文网文拆书分析师,负责《文风与技法》小节。',\n '基于给定章节笔记分析,输出 JSON:{\"markdown\": \"分析稿(简体中文,先结论后依据)\", \"structured\": {\"narrativePov\": \"叙事视角\", \"languageStyle\": \"语言风格\", \"dialoguePatterns\": [\"对话特征\"], \"rhythmControl\": [\"节奏控制\"], \"hookDesigns\": [\"钩子设计\"], \"reusableTechniques\": [\"可复用写法\"]}}',\n '硬规则:只基于笔记归纳;推断谨慎措辞;不虚构。',\n '重要:直接输出 JSON,字符串内不含换行。',\n ].join('\\n'),\n },\n ]\n if (preset === 'standard') {\n sectionsConfig.push({\n key: 'market',\n title: '商业化卖点',\n focus: '读者爽点、点击驱动、人物/题材卖点、商业化风险',\n system: [\n '你是资深中文网文拆书分析师,负责《商业化卖点》小节。',\n '基于给定章节笔记分析,输出 JSON:{\"markdown\": \"分析稿(简体中文,先结论后依据)\", \"structured\": {\"hookPoints\": [\"读者爽点\"], \"clickDrivers\": [\"点击驱动\"], \"characterSellingPoints\": [\"人物卖点\"], \"genreSellingPoints\": [\"题材卖点\"], \"commercialRisks\": [\"商业化风险\"]}}',\n '硬规则:只基于笔记归纳;推断谨慎措辞;不虚构。',\n '重要:直接输出 JSON,字符串内不含换行。',\n ].join('\\n'),\n })\n }\n\n const notesText = notes.join('\\n\\n')\n const sections: BreakdownResponse['sections'] = []\n const evidence: BreakdownResponse['evidence'] = []\n for (const sec of sectionsConfig) {\n try {\n const text = await complete(ctx, config, {\n system: sec.system,\n user: `分析范围:${selected.length} 章(${scope === 'all' ? '全书' : scope === 'recent' ? '最近 20 章' : '指定卷'})。\\n\\n章节笔记:\\n${notesText}`,\n temperature: 0.3,\n maxTokens: Math.max(config.maxTokens, 6000),\n })\n const raw = parseJsonObject<{ markdown?: unknown; structured?: unknown }>(text)\n sections.push({\n key: sec.key,\n title: sec.title,\n markdown: typeof raw.markdown === 'string' ? raw.markdown.trim() : '(生成失败)',\n structured: typeof raw.structured === 'object' && raw.structured !== null ? raw.structured as Record<string, unknown> : {},\n })\n usedTokens += 2000\n } catch {\n sections.push({ key: sec.key, title: sec.title, markdown: '(本节生成失败,可重试)', structured: {} })\n }\n }\n\n return {\n sections,\n evidence,\n chaptersScanned: chunks.length,\n usedTokens,\n }\n}\n\nexport async function generateRoleReferenceImage(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n name: string,\n style = '',\n): Promise<string> {\n const role = project.roles?.find(r => r.name === name)\n if (role === undefined) throw new Error(`角色 ${name} 不存在`)\n if (role.imagePrompt === undefined) throw new Error(`角色 ${name} 还没有形象锚点,请先生成锚点`)\n if (config.imageApiEnabled !== true) throw new Error('豆包生图未启用,请在设置中开启')\n const apiKey = config.imageApiKey\n const model = config.imageApiModel\n if (apiKey === undefined || apiKey === '' || model === undefined || model === '') {\n throw new Error('请先在设置中配置豆包 API Key 和生图模型')\n }\n const stylePrompt = getComicStylePrompt(style)\n const prompt = [\n role.imagePrompt.zh,\n role.imagePrompt.en,\n role.imagePrompt.tags.join(', '),\n stylePrompt,\n 'character reference sheet, front view, clean background, consistent design',\n ].filter(Boolean).join(', ')\n\n const res = await fetch('https://ark.cn-beijing.volces.com/api/v3/images/generations', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model,\n prompt,\n response_format: 'url',\n size: '2K',\n stream: false,\n watermark: false,\n }),\n })\n if (!res.ok) {\n const text = await res.text()\n throw new Error(`豆包生图失败(${res.status}):${text}`)\n }\n const json = (await res.json()) as { data?: Array<{ url?: string }> }\n const url = json.data?.[0]?.url\n if (url === undefined || url === '') throw new Error('豆包生图未返回图片 URL')\n\n const imgRes = await fetch(url)\n if (!imgRes.ok) throw new Error('下载豆包图片失败')\n const buf = Buffer.from(await imgRes.arrayBuffer())\n const contentType = imgRes.headers.get('content-type') || 'image/jpeg'\n const dataUrl = `data:${contentType};base64,${buf.toString('base64')}`\n role.imageUrl = dataUrl\n return dataUrl\n}\n\n/** 🩺 剧情健康检查:基于已写章节数/各线状态/编年录,判断是否需要新线及添加时机。 */\nexport async function analyzePlotlineHealth(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n): Promise<PlotlineHealthReport> {\n const system = [\n '你是一位网文剧情架构师。请对本书的「剧情线体系」做健康检查,判断当前是否需要新增剧情线、应在多少章后添加。',\n '评估维度:各线最近推进到第几章(已写章节与关联章节的差值越大越危险)、各线状态、已写章节总数、卷计划当前进度、编年录近期事实。',\n '输出规则:',\n '1. verdict:一句话结论——\"需要新增线\" / \"暂不需要\" / \"再写 N 章后需要\"(N 给出具体章数)。',\n '2. timing:说明建议添加的时机(如:第 25 章前引入新支线,因为主线预计第 22 章告一段落)。',\n '3. reasons:3-5 条依据(引用具体数据:哪条线多少章没推进、已写章节数、卷进度等)。',\n '4. lines:对每条线给健康度——ok(近期推进过)/ warning(超过 5 章未推进)/ stale(超过 10 章未推进或悬置过久)。',\n '输出必须是合法 JSON 对象:{\"verdict\": \"...\", \"timing\": \"...\", \"reasons\": [\"...\"], \"lines\": [{\"name\": \"线名\", \"health\": \"ok|warning|stale\", \"note\": \"一句说明\"}]}',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating')\n const lines = (project.plotlines ?? []).filter(l => l.status === 'active' || l.status === 'paused')\n const user = [\n `书名:《${project.bookName}》`,\n `已写章节数:${written.length}(最新章号 ${written.length > 0 ? written[written.length - 1]!.no : 0})`,\n project.volumes !== undefined && project.volumes.length > 0\n ? `卷计划:\\n${project.volumes.map(v => `第${v.no}卷《${v.title}》(${v.chapterStart}-${v.chapterEnd}):${v.summary.slice(0, 60)}`).join('\\n')}`\n : '',\n `剧情线(${lines.length} 条):\\n${lines.length > 0\n ? lines.map(l => `- [${l.kind}] ${l.name}|目标:${l.goal}|进度:${l.progress !== '' ? l.progress : '未推进'}|最近关联章节:${l.chapters.length > 0 ? '第' + Math.max(...l.chapters) + '章' : '无'}`).join('\\n')\n : '(暂无剧情线)'}`,\n (project.facts ?? []).length > 0\n ? `编年录近期事实(最近 10 条):\\n${(project.facts ?? []).slice(-10).map(f => `[第${f.chapterNo}章] ${f.text.slice(0, 80)}`).join('\\n')}`\n : '',\n '只输出 JSON 对象。',\n ].join('\\n\\n')\n const raw = parseJsonObject<{\n verdict?: unknown\n timing?: unknown\n reasons?: unknown\n lines?: unknown\n }>(await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 3000) }))\n const strArr = (v: unknown): string[] => Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string' && x.trim() !== '') : []\n const lineArr = Array.isArray(raw.lines)\n ? raw.lines\n .filter((v): v is Record<string, unknown> => typeof v === 'object' && v !== null)\n .map(entry => ({\n name: typeof entry.name === 'string' ? entry.name.slice(0, 40) : '',\n health: (['ok', 'warning', 'stale'] as const).includes(entry.health as never) ? entry.health as 'ok' | 'warning' | 'stale' : 'ok',\n note: typeof entry.note === 'string' ? entry.note.slice(0, 150) : '',\n }))\n .filter(x => x.name !== '')\n : []\n return {\n verdict: typeof raw.verdict === 'string' ? raw.verdict.slice(0, 100) : '',\n timing: typeof raw.timing === 'string' ? raw.timing.slice(0, 200) : '',\n reasons: strArr(raw.reasons).map(r => r.slice(0, 200)),\n lines: lineArr,\n }\n}\n\n/** ✨ AI 剧情方案:基于健康检查结果设计下一阶段方向与建议新线。 */\nexport async function designPlotlinePlan(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n health?: PlotlineHealthReport,\n): Promise<PlotlinePlan> {\n const system = [\n '你是一位网文剧情架构师。请为本书设计「下一阶段的剧情方案」:给出未来 5-10 章的剧情方向,并建议 2-3 条值得新增的剧情线。',\n '要求:方向必须结合本书大纲/卷计划/现有线/编年录;新线要能落地(和当前主角处境、已有伏笔、下一阶段舞台相关),不得重复已有线。',\n '输出必须是合法 JSON 对象:{\"direction\": \"下一阶段方向 60-120 字\", \"suggestions\": [{\"name\": \"线名\", \"kind\": \"main|branch|character|mystery\", \"goal\": \"目标\", \"progress\": \"初始进度(可空)\"}]}',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n '重要:直接输出 JSON 结果本身,不要把思考过程写在输出里。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating')\n const user = [\n `书名:《${project.bookName}》`,\n health !== undefined\n ? `健康检查结论:\\n判定:${health.verdict}\\n时机:${health.timing}\\n依据:${health.reasons.join(';')}`\n : '',\n `大纲(节选前 3000 字):\\n${project.outline.slice(0, 3000)}`,\n project.volumes !== undefined && project.volumes.length > 0\n ? `卷计划:\\n${project.volumes.map(v => `第${v.no}卷《${v.title}》:${v.summary.slice(0, 60)}`).join('\\n')}`\n : '',\n `现有剧情线:\\n${(project.plotlines ?? []).map(l => `- [${l.kind}${l.status === 'resolved' ? '·已完结' : ''}] ${l.name}:${l.goal}`).join('\\n') || '(无)'}`,\n written.length > 0\n ? `最近写的章节:\\n${written.slice(-5).map(c => `第${c.no}章《${c.title}》`).join('、')}`\n : '',\n '只输出 JSON 对象。',\n ].join('\\n\\n')\n const raw = parseJsonObject<{ direction?: unknown; suggestions?: unknown }>(\n await complete(ctx, config, { system, user, temperature: 0.6, maxTokens: Math.max(config.maxTokens, 3000) }),\n )\n const suggestions: Plotline[] = []\n const kinds = new Set(['main', 'branch', 'character', 'mystery'])\n if (Array.isArray(raw.suggestions)) {\n for (const entry of raw.suggestions) {\n if (typeof entry !== 'object' || entry === null) continue\n const e = entry as Record<string, unknown>\n const name = typeof e.name === 'string' ? e.name.trim().slice(0, 40) : ''\n if (name === '') continue\n suggestions.push({\n id: '',\n name,\n kind: kinds.has(e.kind as string) ? e.kind as Plotline['kind'] : 'branch',\n goal: typeof e.goal === 'string' ? e.goal.trim().slice(0, 300) : '',\n progress: typeof e.progress === 'string' ? e.progress.trim().slice(0, 300) : '',\n status: 'active',\n chapters: [],\n createdAt: new Date().toISOString(),\n })\n }\n }\n return {\n direction: typeof raw.direction === 'string' ? raw.direction.slice(0, 300) : '',\n suggestions,\n }\n}\n\n/** Build the rewrite system prompt (fix review issues / instructions). */\nfunction rewriteSystemPrompt(project: ProjectState): string {\n const base = writeSystemPrompt(project)\n return base + '\\n\\n额外要求:你正在【修订】一章已写好的正文。保留原文中好的部分,只修改需要修改的地方,输出完整的新正文(不要只输出修改片段),字数与原文相当。'\n}\n\n/**\n * Stream a chapter rewrite. With `target` (a passage of the body), only that\n * passage's paragraph is rewritten and spliced back — everything else stays\n * untouched (local revision). Without `target`, the whole chapter is\n * rewritten. Yields delta text; persists when done.\n */\nexport async function* rewriteChapterStream(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n instructions: string,\n target?: string,\n): AsyncGenerator<{ frame: 'start' } | { frame: 'delta'; text: string } | { frame: 'drafted'; chars: number; draft: string }, void, unknown> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) throw new Error(`章节 ${chapterNo} 不在计划中`)\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) throw new Error(`章节 ${chapterNo} 的正文文件不存在`)\n\n const reviewBlock = chapter.review !== undefined\n ? '审稿意见:\\n' + chapter.review.issues.map(i => `[${i.severity}] ${i.item} → ${i.suggestion}`).join('\\n')\n : ''\n\n // Local revision: find the paragraph containing `target` and only rewrite it.\n const bodyText = body.replace(/^#\\s+.*$/m, '').trim()\n let localTarget: { paragraph: string; before: string; after: string } | undefined\n if (target !== undefined && target.trim() !== '') {\n const wanted = target.trim()\n // Normalize whitespace so multi-line / quoted snippets still match:\n // the assistant often copies a passage with line breaks and quotes.\n const normalize = (value: string): string => value.replace(/\\s+/g, ' ').replace(/[“”\"'‘’]/g, '')\n const wantedFlat = normalize(wanted)\n // Split into paragraphs on blank lines (or double newlines).\n const paragraphs = bodyText.split(/\\n{2,}/)\n const idx = paragraphs.findIndex(p => normalize(p).includes(wantedFlat))\n if (idx === -1) {\n throw new Error(`在正文中未找到要修改的片段:「${wanted.slice(0, 40)}…」。请从正文中复制原文片段(无需整段,取片段即可)。`)\n }\n localTarget = {\n paragraph: paragraphs[idx]!,\n before: paragraphs.slice(0, idx).join('\\n\\n'),\n after: paragraphs.slice(idx + 1).join('\\n\\n'),\n }\n }\n\n const user = localTarget === undefined\n ? [\n `请修订第 ${chapter.no} 章《${chapter.title}》。`,\n reviewBlock,\n instructions !== '' ? `本次修订重点:${instructions}` : '',\n '==================== 原正文 ====================',\n bodyText,\n ].filter(line => line !== '').join('\\n')\n : [\n `请修订第 ${chapter.no} 章《${chapter.title}》中的一个自然段。`,\n instructions !== '' ? `修改要求:${instructions}` : '',\n '==================== 需要修改的原文段落 ====================',\n localTarget.paragraph,\n '',\n '要求:',\n '1. 只输出修改后的【这一个段落】的完整新文本,不要输出任何说明、标题或 Markdown 标记。',\n '2. 保留该段的情节走向与角色口吻,只按修改要求调整。',\n '3. 段落长度与原文相当。',\n ].filter(line => line !== '').join('\\n')\n\n const system = localTarget === undefined\n ? rewriteSystemPrompt(project)\n : '你是一位中文网文润色师。你会收到一章中的一个段落,请按修改要求重写该段。只输出新段落文本。'\n\n const messages: Message[] = [createUserMessage({\n content: [{ type: 'text', text: user }],\n source: { kind: 'plugin', plugin: 'dsh-novel-forge' },\n })]\n const request: GenerateOptions = {\n provider: config.provider,\n model: config.model,\n messages,\n system,\n // Rewriting outputs a full chapter: budget generously and skip\n // reasoning (a transform task) so the whole budget goes to the body.\n maxTokens: Math.max(config.maxTokens, 20000),\n temperature: 0.7,\n reasoningEffort: ReasoningEffortId('off'),\n }\n\n yield { frame: 'start' }\n const assembler = new BlockAssembler()\n let streamError: Error | undefined\n for await (const chunk of ctx.llm.stream(request)) {\n assembler.push(chunk)\n if (chunk.type === 'text-delta') yield { frame: 'delta', text: chunk.text }\n }\n const finish = assembler.finish\n if (finish.kind === 'error' || finish.kind === 'aborted') {\n streamError = new Error(`修订失败(${finish.kind}): ${finish.failure.message}`)\n } else if (finish.kind === 'max-tokens') {\n streamError = new Error('修订输出达到 maxTokens 上限,请增大配置后重试')\n }\n const rewritten = assembler\n .blocks()\n .filter((block): block is Extract<StreamChunk, { type: 'block-end' }>['block'] & { type: 'text' } => block.type === 'text')\n .map(block => block.text)\n .join('\\n')\n .trim()\n if (streamError !== undefined) throw streamError\n if (rewritten.length < 20) throw new Error('修订结果过短,可能失败,请重试')\n\n // Splice: local -> replace the paragraph; whole -> replace the body.\n let newBody: string\n if (localTarget !== undefined) {\n newBody = [localTarget.before, rewritten, localTarget.after].filter(part => part !== '').join('\\n\\n')\n } else {\n newBody = rewritten\n }\n if (newBody.length < 100) throw new Error('修订结果过短,可能失败,请重试')\n\n // Draft mode: do NOT overwrite the file yet. Store the new body as a\n // pending draft; the user reviews the diff and decides to apply or\n // discard. File overwrite + status change happen on draft/apply.\n chapter.pendingDraft = newBody\n chapter.error = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n yield { frame: 'drafted', chars: newBody.length, draft: newBody }\n}\n\n/** The de-AI-ify polish system prompt (with project writing assets injected). */\nfunction polishSystemPrompt(project: ProjectState): string {\n const assetsBlock = renderAllAssets(project.assets)\n return [\n '你是一位中文网文润色师。你会收到一章正文,请做「去 AI 味」润色:',\n '1. 删除/替换 AI 高频套话与模式词:如\"不禁\"\"仿佛\"\"一时间\"\"不由得\"\"顿时\"\"然而\"\"缓缓\"\"轻轻\"\"微微\"\"默默\"\"似乎\"\"终于\"等滥用。',\n '2. 把书面翻译腔改成口语化的中文网文语感。',\n '3. 拆分过长的排比句与堆砌的修饰语。',\n '4. 保留全部情节、人物、对话内容不变,只改表达。',\n '5. 输出完整的新正文,不要输出任何说明文字或 Markdown 标记。',\n '6. 必须遵守下方「反 AI 规则」与「写法资产」的表达边界;写法资产要求保留的风格特征(句式、台词、节奏)不得在润色中丢失。',\n assetsBlock !== '' ? assetsBlock : '',\n ].join('\\n')\n}\n\n/** Stream a chapter polish (de-AI-ify). Draft-mode: the polished body lands\n * in `chapter.pendingDraft` and is only applied on draft/apply. */\nexport async function* polishChapterStream(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): AsyncGenerator<{ frame: 'start' } | { frame: 'delta'; text: string } | { frame: 'drafted'; chars: number; draft: string }, void, unknown> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) throw new Error(`章节 ${chapterNo} 不在计划中`)\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) throw new Error(`章节 ${chapterNo} 的正文文件不存在`)\n const messages: Message[] = [createUserMessage({\n content: [{ type: 'text', text: body.replace(/^#\\s+.*$/m, '').trim() }],\n source: { kind: 'plugin', plugin: 'dsh-novel-forge' },\n })]\n const request: GenerateOptions = {\n provider: config.provider,\n model: config.model,\n messages,\n system: polishSystemPrompt(project),\n // Polish rewrites the whole chapter: generous budget, no reasoning\n // (transform task — the entire budget should go to the body).\n maxTokens: Math.max(config.maxTokens, 20000),\n temperature: 0.5,\n reasoningEffort: ReasoningEffortId('off'),\n }\n yield { frame: 'start' }\n const assembler = new BlockAssembler()\n let streamError: Error | undefined\n for await (const chunk of ctx.llm.stream(request)) {\n assembler.push(chunk)\n if (chunk.type === 'text-delta') yield { frame: 'delta', text: chunk.text }\n }\n const finish = assembler.finish\n if (finish.kind === 'error' || finish.kind === 'aborted') {\n streamError = new Error(`润色失败(${finish.kind}): ${finish.failure.message}`)\n } else if (finish.kind === 'max-tokens') {\n streamError = new Error('润色输出达到 maxTokens 上限')\n }\n const newBody = assembler\n .blocks()\n .filter((block): block is Extract<StreamChunk, { type: 'block-end' }>['block'] & { type: 'text' } => block.type === 'text')\n .map(block => block.text)\n .join('\\n')\n .trim()\n if (streamError !== undefined) throw streamError\n if (newBody.length < 100) throw new Error('润色结果过短,可能失败,请重试')\n\n // Draft mode: keep the original file untouched until the user decides.\n chapter.pendingDraft = newBody\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n yield { frame: 'drafted', chars: newBody.length, draft: newBody }\n}\n\n/** Generate one chapter (streaming). Yields progress frames; persists when done. */\nexport async function* generateChapterStream(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): AsyncGenerator<{ frame: 'start' } | { frame: 'delta'; text: string } | { frame: 'done'; file: string; chars: number }, void, unknown> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) throw new Error(`章节 ${chapterNo} 不在计划中`)\n // Note: the route layer owns the 'generating' status + concurrency guard;\n // this function must not refuse when status is 'generating' (the route sets\n // it before calling us).\n\n // Continuity: previous chapter's ending + its summary (narrative memory).\n let continuity = ''\n const prev = project.chapters.find(c => c.no === chapterNo - 1)\n if (prev?.file !== undefined) {\n const prevPath = join(outputDir, prev.file)\n if (existsSync(prevPath)) {\n const text = readFileSync(prevPath, 'utf8')\n continuity = text.slice(-900)\n }\n }\n const prevSummary = prev?.summary\n // 事实注入:最近 20 条(近因记忆)+ 按本章剧情要点检索的「相关旧事实」。\n // 长篇后旧设定可能被挤出近期窗口,故检索覆盖全部事实库:trigram 重合度 +\n // 角色名命中加权 + 近因加权,取 top 15,与近期事实去重,保证关键状态不写飞。\n const allFacts = project.facts ?? []\n const recentFacts = allFacts.slice(-20).map(f => f.text)\n const recentSet = new Set(recentFacts)\n const beatsText = chapter.beats\n const roleNames = (project.roles ?? [])\n .map(r => r.name)\n .filter((n): n is string => typeof n === 'string' && n !== '')\n const trigrams = (s: string): Set<string> => {\n const out = new Set<string>()\n for (let i = 0; i + 3 <= s.length; i++) {\n const tri = s.slice(i, i + 3)\n if (tri.trim() !== '') out.add(tri)\n }\n return out\n }\n const beatsTri = trigrams(beatsText)\n const beatRoles = roleNames.filter(n => beatsText.includes(n))\n const relatedFacts = allFacts\n .map((f, idx) => {\n const head = f.text.slice(0, 80)\n let score = 0\n for (const tri of trigrams(head)) if (beatsTri.has(tri)) score += 1\n if (beatRoles.length > 0) {\n for (const n of beatRoles) if (head.includes(n)) score += 8\n }\n // 近因加权:越新越优先(封顶 40 章)\n score += Math.min(idx, 40) / 10\n return { f, score }\n })\n .filter(x => x.score >= 3)\n .sort((a, b) => b.score - a.score)\n .slice(0, 15)\n .map(x => `[第${x.f.chapterNo}章] ${x.f.text}`)\n .filter(t => !recentSet.has(t.slice(t.indexOf(']') + 2)))\n\n // 暗线(伏笔)埋点注入:检索「目标章在当前章附近 + 尚未回收」的 planned 伏笔,\n // 把埋点细节要求注入本次生成,保证正文按规划埋线(否则伏笔列表与正文脱节)。\n const foreshadowHints = (project.foreshadows ?? [])\n .filter(f => f.status === 'planned' && f.targetChapter !== undefined && f.targetChapter > 0)\n .filter(f => Math.abs((f.targetChapter as number) - chapterNo) <= 12)\n .map(f => `- ${f.description.slice(0, 120)}${f.targetChapter !== undefined ? `(计划回收于第 ${f.targetChapter} 章)` : ''}`)\n\n const user = [\n `现在写第 ${chapter.no} 章,标题《${chapter.title}》。`,\n `本章剧情要点:${chapter.beats}`,\n '',\n foreshadowHints.length > 0\n ? `本章附近需顺势埋下以下暗线(自然带过,不喧宾夺主,1-2 句即可,但细节要可辨识、与描述吻合):\\n${foreshadowHints.join('\\n')}`\n : '',\n recentFacts.length > 0\n ? `本书已确立的事实(新写内容不得与之矛盾):\\n${recentFacts.join('\\n')}`\n : '',\n relatedFacts.length > 0\n ? `本章相关的既往事实(同样不得违背):\\n${relatedFacts.join('\\n')}`\n : '',\n prevSummary !== undefined && prevSummary !== ''\n ? `上一章摘要:${prevSummary}`\n : '',\n continuity !== ''\n ? `上一章结尾(用于衔接,不要复述):\\n${continuity}`\n : '这是第一章,注意开篇要有吸引力。',\n '',\n `请写 ${chapter.targetChars} 字左右的正文,只输出正文。`,\n ].filter(line => line !== '').join('\\n')\n\n const messages: Message[] = [createUserMessage({\n content: [{ type: 'text', text: user }],\n source: { kind: 'plugin', plugin: 'dsh-novel-forge' },\n })]\n const request: GenerateOptions = {\n provider: config.provider,\n model: config.model,\n messages,\n system: writeSystemPrompt(project),\n // Full-chapter output: budget generously (4000 chars ≈ 8-12k tokens,\n // plus the model's reasoning channel).\n maxTokens: Math.max(config.maxTokens, 20000),\n temperature: 0.85,\n }\n\n yield { frame: 'start' }\n\n const assembler = new BlockAssembler()\n let streamError: Error | undefined\n for await (const chunk of ctx.llm.stream(request)) {\n assembler.push(chunk)\n if (chunk.type === 'text-delta') {\n yield { frame: 'delta', text: chunk.text }\n }\n }\n const finish = assembler.finish\n if (finish.kind === 'error' || finish.kind === 'aborted') {\n streamError = new Error(`生成失败(${finish.kind}): ${finish.failure.message}`)\n } else if (finish.kind === 'max-tokens') {\n streamError = new Error('达到 maxTokens 上限,正文可能不完整,请增大 maxTokens 后重试')\n }\n const body = assembler\n .blocks()\n .filter((block): block is Extract<StreamChunk, { type: 'block-end' }>['block'] & { type: 'text' } => block.type === 'text')\n .map(block => block.text)\n .join('\\n')\n .trim()\n if (streamError !== undefined) throw streamError\n if (body.length < 100) throw new Error('生成内容过短,可能失败,请重试')\n\n // Write the chapter file.\n const fileName = chapterFileName(chapter)\n mkdirSync(outputDir, { recursive: true })\n writeFileSync(join(outputDir, fileName), `# 第${chapter.no}章 ${chapter.title}\\n\\n${body}\\n`, 'utf8')\n\n chapter.status = 'written'\n chapter.chars = body.length\n chapter.file = fileName\n chapter.error = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n\n yield { frame: 'done', file: fileName, chars: body.length }\n}\n\n/** Generate a chapter summary (narrative memory). */\nexport async function summarizeChapter(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): Promise<string> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) throw new Error(`章节 ${chapterNo} 不在计划中`)\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) throw new Error(`章节 ${chapterNo} 的正文文件不存在`)\n const system = [\n '你是一位网文编辑。请为下面一章写一段 120-200 字的摘要,供后续章节写作时保持连贯性。',\n '摘要必须包含:本章发生的关键事件、主角状态变化(境界/资源/伤势/心境)、新增的伏笔或线索、角色关系变化。',\n '用客观陈述句,不要评价,不要剧透式感叹。只输出摘要正文。',\n ].join('\\n')\n const user = body.replace(/^#\\s+.*$/m, '').trim()\n const summary = await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 4000) })\n chapter.summary = summary.slice(0, 500)\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return chapter.summary\n}\n\n/**\n * 摘要 + 事实抽取合并为一次 LLM 调用(省一次调用与一次正文输入,\n * 批量生成时整体开销约省 25%)。\n * @returns 摘要与新增事实条数(失败返回空,调用方 best-effort)。\n */\nexport async function summarizeAndExtractFacts(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): Promise<{ summary: string; factCount: number }> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) return { summary: '', factCount: 0 }\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) return { summary: '', factCount: 0 }\n const system = [\n '你是一位网文编辑。请为下面一章做两件事,输出合法 JSON 对象:',\n '{\"summary\": \"120-200字摘要,含关键事件/主角状态变化(境界资源伤势心境)/新增伏笔线索/角色关系变化,客观陈述不评价\", \"facts\": [\"已确立事实1\", \"…3-6条\"]}',\n 'facts 指:本章明确写出的、对后续有约束力的事实——人物当前状态、重要关系变化、地点与时间线、已落地或新增的伏笔线索、关键道具去向。',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n ].join('\\n')\n const user = body.replace(/^#\\s+.*$/m, '').trim()\n const text = await complete(ctx, config, { system, user, temperature: 0.2, maxTokens: Math.max(config.maxTokens, 5000) })\n const raw = parseJsonObject<{ summary?: unknown; facts?: unknown }>(text)\n const summary = typeof raw.summary === 'string' ? raw.summary.trim().slice(0, 500) : ''\n const factLines = Array.isArray(raw.facts)\n ? raw.facts\n .filter((v): v is string => typeof v === 'string' && v.trim().length > 8)\n .map(v => v.trim().slice(0, 140))\n : []\n if (summary !== '') chapter.summary = summary\n const list = project.facts ?? []\n for (const line of factLines.slice(0, 8)) list.push({ chapterNo, text: line })\n project.facts = list.slice(-300)\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return { summary, factCount: factLines.length }\n}\n\n/**\n * 伏笔落地标记:检查刚生成的章节正文是否埋下了 planned 伏笔(关键词匹配),\n * 命中则将该伏笔标记为 planted 并记录 plantedChapter——保证暗线管理页与正文同步。\n * 纯关键词粗匹配,宁缺毋滥:仅处理「描述含可辨识关键词」的伏笔,无把握则不标。\n */\nexport function markForeshadowPlanted(\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): number {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) return 0\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) return 0\n let marked = 0\n for (const f of project.foreshadows ?? []) {\n if (f.status !== 'planned') continue\n if (f.plantedChapter !== undefined) continue\n // 从描述中提取关键词:书名号/引号内容优先(专有名词),否则取 2-4 字名词片段。\n const quoted = f.description.match(/[「“『《]([^」”』》]{2,12})[」”』》]/g)\n const keywords = (quoted !== null ? quoted : [])\n .map(q => q.slice(1, -1))\n .filter(k => k.length >= 2)\n // 无引号关键词时,退而求其次:用「本章附近注入过该伏笔」的信号(targetChapter 接近当前章)。\n const nearTarget = f.targetChapter !== undefined && Math.abs(f.targetChapter - chapterNo) <= 12\n if (keywords.length === 0 && !nearTarget) continue\n const hit = keywords.length === 0\n ? false\n : keywords.some(k => body.includes(k))\n if (hit || (keywords.length === 0 && nearTarget)) {\n // 命中或(无关键词但恰好在目标章附近被注入埋点要求)→ 保守起见,只有明确命中才标记。\n if (hit) {\n f.status = 'planted'\n f.plantedChapter = chapterNo\n marked++\n }\n }\n }\n if (marked > 0) {\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n }\n return marked\n}\n\n/**\n * 抽取本章「已确立事实」追加到事实库/时间线(最多 300 条,最新优先)。\n * 事实注入后续章节生成提示词,保证人物状态/境界/资源/关系长期一致。\n * @returns 新增事实条数(失败返回 0,调用方 best-effort)。\n */\nexport async function extractFacts(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n chapterNo: number,\n): Promise<number> {\n const chapter = project.chapters.find(c => c.no === chapterNo)\n if (chapter === undefined) return 0\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) return 0\n const system = [\n '你是一位网文编辑。请从本章正文中抽取「已确立事实」,供后续章节保持一致。',\n '事实指:人物当前状态(境界/修为/伤势/资源/心境)、重要关系变化、地点与时间线、已落地或新增的伏笔线索、关键道具去向。',\n '要求:',\n '1. 只抽取本章明确写出的、对后续有约束力的内容;纯心理活动与无关细节不要。',\n '2. 每行一条事实,用客观陈述句,不含主观评价。',\n '3. 输出 3-6 条,每行一条,不要编号、不要前缀、不要解释。',\n ].join('\\n')\n const user = body.replace(/^#\\s+.*$/m, '').trim()\n // v4-flash 推理模型:reasoning channel 也占 maxTokens,预算给足避免截断。\n const text = await complete(ctx, config, { system, user, temperature: 0.2, maxTokens: Math.max(config.maxTokens, 4000) })\n const lines = text.split('\\n')\n .map(line => line.replace(/^[-*\\d.\\s]+/, '').trim())\n .filter(line => line.length > 8)\n .slice(0, 8)\n if (lines.length === 0) return 0\n const facts = project.facts ?? []\n for (const line of lines) facts.push({ chapterNo, text: line.slice(0, 140) })\n project.facts = facts.slice(-300)\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return lines.length\n}\n\n// ------------------------------------------------------------ book audit\n\nconst AUDIT_BATCH_SIZE = 10\n\n/** 单批质检:设定 + 事实库 + 该批章节节选 → 矛盾清单。 */\nasync function auditBatch(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n batch: ChapterPlan[],\n): Promise<AuditIssue[]> {\n const system = [\n '你是一位严谨的网文连续性审校编辑。你会收到一本小说的设定圣经、事实库和一批章节正文节选。',\n '请找出这批章节中的一致性矛盾,例如:',\n '- 人物状态冲突:境界/修为/伤势/资源在同一章内或跨章前后矛盾。',\n '- 设定违背:正文与世界观规则、金手指规则、写作红线冲突。',\n '- 时间线错乱:事件顺序、时间跨度、地点移动不合逻辑。',\n '- 细节穿帮:人名/地名/物品/数字前后不一致。',\n '要求:',\n '1. 只报告有实质证据的矛盾,不要泛泛而谈写作质量问题。',\n '2. 每条必须定位到具体章节号。',\n '3. 输出必须是合法 JSON 数组,格式:[{\"chapterNo\": 章节号, \"severity\": \"high|medium|low\", \"item\": \"矛盾描述\", \"suggestion\": \"修改建议\"}]',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n ].join('\\n')\n const factsBlock = (project.facts ?? []).slice(-60).map(f => `[第${f.chapterNo}章] ${f.text}`).join('\\n')\n const chapterBlocks = batch.map(c => {\n const body = readChapterFile(outputDir, c)\n const excerpt = (body ?? '').replace(/^#\\s+.*$/m, '').trim().slice(0, 700)\n return `【第${c.no}章《${c.title}》】\\n${excerpt}`\n }).join('\\n\\n')\n const user = [\n '请对以下小说做一致性质检。',\n project.bible !== undefined\n ? '设定圣经:\\n' + [\n project.bible.worldRules.length > 0 ? `世界规则:\\n${project.bible.worldRules.map(r => `- ${r}`).join('\\n')}` : '',\n project.bible.redLines.length > 0 ? `写作红线:\\n${project.bible.redLines.map(r => `- ${r}`).join('\\n')}` : '',\n project.bible.characters.length > 0 ? `角色:\\n${project.bible.characters.map(ch => `- ${ch.name}(${ch.traits.join('、')})`).join('\\n')}` : '',\n ].filter(s => s !== '').join('\\n')\n : '',\n factsBlock !== '' ? `已确立事实库:\\n${factsBlock}` : '',\n `正文节选(每章前 700 字):\\n${chapterBlocks}`,\n '只输出 JSON 数组。',\n ].filter(s => s !== '').join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.2, maxTokens: Math.max(config.maxTokens, 12000) })\n const parsed = parseJsonArray<Record<string, unknown>>(text)\n const issues: AuditIssue[] = []\n for (const entry of parsed) {\n const item = typeof entry.item === 'string' ? entry.item : ''\n if (item === '') continue\n issues.push({\n chapterNo: Number(entry.chapterNo) || 0,\n severity: ['high', 'medium', 'low'].includes(entry.severity as string)\n ? entry.severity as AuditIssue['severity']\n : 'medium',\n item,\n suggestion: typeof entry.suggestion === 'string' ? entry.suggestion : '',\n })\n }\n return issues\n}\n\n/** 全书一致性质检:LLM 分批扫描已生成章节 + 设定 + 事实库,聚合矛盾清单。 */\nexport async function auditBook(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n onProgress?: (completedBatches: number, totalBatches: number) => void,\n): Promise<AuditIssue[]> {\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating')\n if (written.length === 0) {\n onProgress?.(0, 0)\n return []\n }\n // 分批:每批 AUDIT_BATCH_SIZE 章,避免超长后单次爆上下文。\n const totalBatches = Math.ceil(written.length / AUDIT_BATCH_SIZE)\n const all: AuditIssue[] = []\n onProgress?.(0, totalBatches)\n for (let i = 0; i < written.length; i += AUDIT_BATCH_SIZE) {\n const batch = written.slice(i, i + AUDIT_BATCH_SIZE)\n try {\n all.push(...await auditBatch(ctx, config, project, outputDir, batch))\n } catch { /* 单批失败不阻断其余批次 */ }\n onProgress?.(Math.min(Math.ceil((i + AUDIT_BATCH_SIZE) / AUDIT_BATCH_SIZE), totalBatches), totalBatches)\n }\n return all.slice(0, 50)\n}\n\n/** 小说简介:AI 生成或按已写开头补全(面向读者的作品门面)。 */\nexport async function generateBlurb(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n partial = '',\n): Promise<string> {\n const system = [\n '你是一位网文平台编辑,擅长写抓人的作品简介。',\n '要求:',\n '1. 120-250 字,突出核心卖点(金手指/题材/爽点/人设反差),用一两句抛出开局钩子。',\n '2. 不剧透结局与关键反转;语气贴合题材(热血/悬疑/轻松/虐心)。',\n '3. 中文,直接输出简介正文,不要 Markdown、不要引号包裹、不要「简介:」前缀。',\n ].join('\\n')\n const genreBlock = project.bible?.genre !== undefined ? `题材:${project.bible.genre}` : ''\n const volumeBlock = (project.volumes ?? []).slice(0, 3).map(v => v.title).join('、')\n const user = [\n `书名:《${project.bookName}》`,\n genreBlock,\n volumeBlock !== '' ? `卷结构:${volumeBlock}` : '',\n `已写章节数:${project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating').length}`,\n '大纲节选:\\n' + project.outline.slice(0, 2500),\n partial.trim() !== ''\n ? `已有开头草稿(请保留其内容与语气,续写补全为完整简介):\\n${partial.trim()}`\n : '请全量生成一份完整简介。',\n ].filter(s => s !== '').join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.7, maxTokens: Math.max(config.maxTokens, 4000) })\n const blurb = text.replace(/^[\"'「『]|[\"'」』]$/g, '').replace(/^简介[::]\\s*/, '').trim().slice(0, 600)\n return blurb\n}\n\n// ---------------------------------------------------------------- world\n\n/**\n * 组装全书上下文包(AI 助手 book_overview 工具)。\n * 分片策略:章节要点默认只给最近 30 章(避免超长后爆上下文);\n * scope='full' 全量;scope=数字 只给该卷章节。\n */\nexport function bookOverview(project: ProjectState, scope: 'recent' | 'full' | number = 'recent'): string {\n const s: string[] = []\n s.push(`书名:${project.bookName}`)\n s.push(`【大纲全文】\\n${project.outline}`)\n if (project.bible !== undefined) {\n const bible = project.bible\n s.push('【设定圣经】')\n if (bible.genre !== '') s.push(`题材基调:${bible.genre}`)\n if (bible.worldRules.length > 0) s.push('世界规则:\\n' + bible.worldRules.map(r => `- ${r}`).join('\\n'))\n if (bible.characters.length > 0) {\n s.push('角色卡:')\n for (const card of bible.characters) {\n const roleName = { protagonist: '主角', supporting: '配角', antagonist: '反派', other: '其他' }[card.role]\n s.push(`- ${card.name}(${roleName}):${card.traits.join('、')}${card.goals !== '' ? `;目标:${card.goals}` : ''}${card.relations !== '' ? `;关系:${card.relations}` : ''}`)\n }\n }\n if (bible.redLines.length > 0) s.push('写作红线:\\n' + bible.redLines.map(r => `- ${r}`).join('\\n'))\n if (bible.style.length > 0) s.push('风格要求:\\n' + bible.style.map(r => `- ${r}`).join('\\n'))\n }\n const worldBlock = renderWorld(project.world)\n if (worldBlock !== '') s.push(worldBlock)\n if (project.volumes !== undefined && project.volumes.length > 0) {\n s.push('【卷结构】')\n for (const v of project.volumes) {\n s.push(`第${v.no}卷《${v.title}》:${v.summary}(章节 ${v.chapterStart}-${v.chapterEnd})`)\n }\n }\n if (project.chapters.length > 0) {\n // 分片:默认最近 30 章;full 全量;数字 = 指定卷。\n const maxNo = project.chapters.reduce((m, c) => Math.max(m, c.no), 0)\n const shown = project.chapters.filter(c => {\n if (scope === 'full') return true\n if (typeof scope === 'number') return c.volume === scope\n return c.no > Math.max(0, maxNo - 30)\n })\n const label = scope === 'full' ? '全部章节(标题/状态/剧情要点/摘要)' : typeof scope === 'number' ? `第 ${scope} 卷章节(标题/状态/剧情要点/摘要)` : `最近 ${shown.length} 章(标题/状态/剧情要点/摘要)`\n s.push(`【${label}】`)\n const statusText: Record<string, string> = { pending: '待生成', generating: '生成中', written: '待审稿', reviewing: '审稿中', approved: '已通过', rejected: '待修订', error: '失败' }\n for (const c of shown) {\n s.push(`第${c.no}章《${c.title}》[${statusText[c.status] ?? c.status}]${c.chars !== undefined ? ` ${c.chars}字` : ''}\\n剧情要点:${c.beats}\\n摘要:${c.summary ?? '无'}`)\n }\n if (scope !== 'full' && project.chapters.length > shown.length) {\n s.push(`(还有 ${project.chapters.length - shown.length} 章未列出,可用 scope=volume:N 查看指定卷)`)\n }\n }\n if ((project.facts ?? []).length > 0) {\n s.push('【事实库(最近 40 条;更多用 facts_query 检索)】')\n for (const f of (project.facts ?? []).slice(-40)) {\n s.push(`- [第${f.chapterNo}章] ${f.text}`)\n }\n }\n if (project.foreshadows.length > 0) {\n s.push('【伏笔】')\n for (const f of project.foreshadows) {\n s.push(`- [${f.status}] ${f.description}${f.targetChapter !== undefined ? `(预计 ${f.targetChapter} 章回收)` : ''}`)\n }\n }\n if (project.blurb !== undefined && project.blurb !== '') s.push(`【小说简介】${project.blurb}`)\n return s.join('\\n\\n')\n}\n\n/** 一条影响分析结果(改动波及处)。 */\nexport interface ImpactItem {\n /** 位置:章节号 / 大纲 / 设定圣经 / 大世界 / 事实库 / 简介。 */\n location: string\n /** 原文片段(定位用)。 */\n quote: string\n /** 修改建议。 */\n suggestion: string\n /** must = 必须同步改;optional = 建议改;note = 备注(如保留旧称作古称)。 */\n kind: 'must' | 'optional' | 'note'\n}\n\n/**\n * 影响分析:LLM 扫描全书(大纲/设定/大世界/事实库/已写章节),\n * 定位一次改动波及的所有位置。助手在修改后主动调用,做连锁维护。\n */\nexport async function analyzeImpact(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n change: string,\n): Promise<ImpactItem[]> {\n const system = [\n '你是一位网文一致性审校。作者要做一处修改,请找出这次改动会波及的所有位置(设定、大纲、已写章节正文、事实库、简介中可能因此过时或矛盾的内容)。',\n '输出必须是合法 JSON 数组,格式:[{\"location\": \"位置(第N章/大纲/设定圣经-世界规则/大世界-境界/事实库/简介)\", \"quote\": \"原文片段(20-60字)\", \"suggestion\": \"修改建议\", \"kind\": \"must|optional|note\"}]',\n 'kind 含义:must=必须同步改否则矛盾;optional=建议改(影响观感);note=备注(如旧称保留为古称、或无需改但需知晓)。',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n ].join('\\n')\n const written = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating')\n // 轻量 base:大纲节选 + 道藏要点 + 编年录最近 40 条(替代全量 bookOverview,\n // 定位主要靠各批章节节选原文)。\n const base = [\n `要做的修改:${change}`,\n '以下为全书设定与规则要点(章节为分批节选):',\n `大纲节选:\\n${project.outline.slice(0, 2000)}`,\n project.bible !== undefined\n ? `道藏:${project.bible.worldRules.length} 条世界规则 / ${project.bible.redLines.length} 条红线 / 人物 ${project.bible.characters.map(c => c.name).join('、')}`\n : '',\n (project.facts ?? []).length > 0\n ? `编年录最近 40 条:\\n${(project.facts ?? []).slice(-40).map(f => `[第${f.chapterNo}章] ${f.text}`).join('\\n')}`\n : '',\n ].filter(s => s !== '').join('\\n\\n')\n const items: ImpactItem[] = []\n // 分批扫描章节正文(每批 8 章),聚合影响清单,避免超长后爆上下文。\n const IMPACT_BATCH_SIZE = 8\n for (let i = 0; i < written.length; i += IMPACT_BATCH_SIZE) {\n const batch = written.slice(i, i + IMPACT_BATCH_SIZE)\n const chapterBlock = batch.map(c => {\n const body = readChapterFile(outputDir, c)\n const excerpt = (body ?? '').replace(/^#\\s+.*$/m, '').trim().slice(0, 500)\n return `【第${c.no}章《${c.title}》】\\n${excerpt}`\n }).join('\\n\\n')\n const user = `${base}\\n\\n本批章节(第 ${batch[0]!.no}-${batch[batch.length - 1]!.no} 章):\\n${chapterBlock}\\n\\n只输出 JSON 数组。`\n try {\n const text = await complete(ctx, config, { system, user, temperature: 0.2, maxTokens: Math.max(config.maxTokens, 12000) })\n for (const entry of parseJsonArray<Record<string, unknown>>(text)) {\n const quote = typeof entry.quote === 'string' ? entry.quote.trim() : ''\n if (quote === '') continue\n items.push({\n location: typeof entry.location === 'string' ? entry.location : '未定位',\n quote: quote.slice(0, 120),\n suggestion: typeof entry.suggestion === 'string' ? entry.suggestion : '',\n kind: entry.kind === 'must' || entry.kind === 'optional' || entry.kind === 'note' ? entry.kind : 'optional',\n })\n }\n } catch { /* 单批失败不阻断其余批次 */ }\n }\n return items.slice(0, 30)\n}\n\n/** 把大世界结构化数据渲染成提示词块(境界体系按顺序强约束)。 */\nexport function renderWorld(world: WorldState | undefined): string {\n if (world === undefined) return ''\n const sections: string[] = ['==================== 大世界(结构化设定,写作时严格遵守) ====================']\n if (world.realms.length > 0) {\n sections.push('境界体系(由低到高,不得随意跳级或自创境界):')\n world.realms.forEach((realm, i) => {\n sections.push(`${i + 1}. ${realm.name}${realm.description !== '' ? ` — ${realm.description}` : ''}`)\n })\n }\n if (world.regions.length > 0) {\n sections.push('地理区域:')\n for (const region of world.regions) {\n sections.push(`- ${region.name}${region.description !== '' ? `:${region.description}` : ''}${region.faction !== undefined && region.faction !== '' ? `(势力:${region.faction})` : ''}`)\n }\n }\n if (world.factions.length > 0) {\n sections.push('势力分布:')\n for (const faction of world.factions) {\n sections.push(`- ${faction.name}(${faction.kind})${faction.description !== '' ? `:${faction.description}` : ''}${faction.region !== undefined && faction.region !== '' ? `(驻地:${faction.region})` : ''}`)\n }\n }\n return sections.join('\\n')\n}\n\n/** AI 提炼大世界:从大纲 + 设定圣经生成结构化境界体系/区域/势力。 */\nexport async function extractWorld(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n): Promise<WorldState> {\n const system = [\n '你是一位网文世界观架构师。请根据小说大纲与设定圣经,提炼结构化「大世界」数据。',\n '输出必须是合法 JSON 对象:',\n '{\"realms\": [{\"name\": \"境界名\", \"description\": \"突破条件/寿命/标志等\"}], \"regions\": [{\"name\": \"区域名\", \"description\": \"描述\", \"faction\": \"关联势力名或空\"}], \"factions\": [{\"name\": \"势力名\", \"kind\": \"宗门/家族/王朝/组织等\", \"description\": \"描述\", \"region\": \"驻地区域或空\"}]}',\n '要求:',\n '1. realms 按由低到高顺序排列(修仙题材必须含完整境界链;无境界设定的题材可输出空数组)。',\n '2. 数量贴合大纲:realms 3-12 个,regions 2-10 个,factions 2-10 个。',\n '3. 内容严格来自大纲与设定圣经,不要凭空发明与大纲冲突的设定。',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n ].join('\\n')\n const bibleBlock = project.bible !== undefined\n ? [\n project.bible.genre !== '' ? `题材:${project.bible.genre}` : '',\n project.bible.worldRules.length > 0 ? `世界规则:\\n${project.bible.worldRules.map(r => `- ${r}`).join('\\n')}` : '',\n ].filter(s => s !== '').join('\\n')\n : ''\n const user = [\n '请为这部小说提炼大世界数据。',\n `书名:《${project.bookName}》`,\n bibleBlock !== '' ? bibleBlock : '',\n '大纲:\\n' + project.outline.slice(0, 5000),\n '只输出 JSON 对象。',\n ].filter(s => s !== '').join('\\n\\n')\n const text = await complete(ctx, config, { system, user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 12000) })\n const raw = parseJsonObject<{ realms?: unknown; regions?: unknown; factions?: unknown }>(text)\n const str = (value: unknown): string => typeof value === 'string' ? value.trim() : ''\n const objArray = (value: unknown): Record<string, unknown>[] =>\n Array.isArray(value) ? value.filter((v): v is Record<string, unknown> => typeof v === 'object' && v !== null) : []\n const world: WorldState = {\n realms: objArray(raw.realms).map(entry => ({\n name: str(entry.name).slice(0, 20) || '未命名境界',\n description: str(entry.description).slice(0, 200),\n })).filter(r => r.name !== '未命名境界' || r.description !== ''),\n regions: objArray(raw.regions).map(entry => ({\n name: str(entry.name).slice(0, 30) || '未命名区域',\n description: str(entry.description).slice(0, 200),\n faction: str(entry.faction).slice(0, 30),\n })).filter(r => r.name !== '未命名区域' || r.description !== ''),\n factions: objArray(raw.factions).map(entry => ({\n name: str(entry.name).slice(0, 30) || '未命名势力',\n kind: str(entry.kind).slice(0, 20) || '组织',\n description: str(entry.description).slice(0, 200),\n region: str(entry.region).slice(0, 30),\n })).filter(f => f.name !== '未命名势力' || f.description !== ''),\n }\n return world\n}\n\n/**\n * 事实库回填:对历史已生成章节批量抽取事实(无事实记录的旧章节)。\n * @returns 回填的章节数。\n */\nexport async function backfillFacts(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n): Promise<number> {\n const have = new Set((project.facts ?? []).map(f => f.chapterNo))\n let filled = 0\n for (const chapter of project.chapters) {\n if (chapter.status === 'pending' || chapter.status === 'generating') continue\n if (chapter.file === undefined || have.has(chapter.no)) continue\n try {\n const n = await extractFacts(ctx, config, project, outputDir, chapter.no)\n if (n > 0) filled++\n } catch { /* best-effort per chapter */ }\n have.add(chapter.no)\n }\n return filled\n}\n\n/**\n * 角色卡刷新:出场统计由服务端从正文精确计算(角色名出现过的章节数、\n * 最近出现章节),LLM 只负责聚合「当前状态」一句话。\n */\nexport async function refreshCharacters(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n): Promise<RoleStatusCard[]> {\n // 名单优先用角色库(主表);无角色库时退回道藏角色卡。\n const rawRoster = (((project.roles ?? []).length > 0 ? project.roles : project.bible?.characters) ?? []) as Array<{ name: string; traits?: string[]; role?: string; roleLabel?: string }>\n const roster = rawRoster.map(r => ({\n name: r.name,\n traits: r.traits ?? [],\n role: r.roleLabel !== undefined ? r.roleLabel : (r.role ?? 'other'),\n }))\n const facts = project.facts ?? []\n if (roster.length === 0 && facts.length === 0) return []\n\n // 服务端精确出场统计:遍历已写章节正文,统计每个角色名出现过的章节。\n const stat = new Map<string, { chapters: Set<number>; last: number }>()\n const known = roster.map(card => card.name)\n for (const chapter of project.chapters) {\n if (chapter.status === 'pending' || chapter.status === 'generating') continue\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) continue\n for (const name of known) {\n if (body.includes(name)) {\n const entry = stat.get(name) ?? { chapters: new Set<number>(), last: 0 }\n entry.chapters.add(chapter.no)\n if (chapter.no > entry.last) entry.last = chapter.no\n stat.set(name, entry)\n }\n }\n }\n\n // LLM 只聚合状态:名单(含 traits)+ 事实库 → [{name, status}]\n let statuses = new Map<string, string>()\n if (facts.length > 0) {\n const system = [\n '你是一位网文角色档案管理员。请根据「角色名单」与「已确立事实库」,为每个角色输出「当前状态」一句话(境界/修为/伤势/资源/心境)。',\n '输出必须是合法 JSON 数组,格式:[{\"name\": \"角色名\", \"status\": \"当前状态一句话\"}]',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n ].join('\\n')\n const rosterBlock = roster.map(ch => `- ${ch.name}(${ch.traits.join('、')})`).join('\\n')\n const factsBlock = facts.map(f => `[第${f.chapterNo}章] ${f.text}`).join('\\n')\n const user = [\n `角色名单:\\n${rosterBlock}`,\n `已确立事实库(${facts.length} 条):\\n${factsBlock.slice(-6000)}`,\n '只输出 JSON 数组。',\n ].join('\\n\\n')\n try {\n const text = await complete(ctx, config, { system, user, temperature: 0.2, maxTokens: Math.max(config.maxTokens, 8000) })\n for (const entry of parseJsonArray<Record<string, unknown>>(text)) {\n const name = typeof entry.name === 'string' ? entry.name : ''\n if (name !== '' && typeof entry.status === 'string') statuses.set(name, entry.status)\n }\n } catch { /* status 聚合失败则只给出场统计 */ }\n }\n\n // 合并:出场统计(精确)+ 状态(LLM)+ 名单角色补全。\n const cards: RoleStatusCard[] = []\n const roleOf = (name: string): string => roster.find(c => c.name === name)?.role ?? 'other'\n for (const card of roster) {\n const entry = stat.get(card.name)\n cards.push({\n name: card.name,\n role: card.role,\n status: statuses.get(card.name) ?? '',\n lastChapter: entry?.last ?? 0,\n appearances: entry?.chapters.size ?? 0,\n })\n }\n // 名单外的角色(从事实库中识别到但不在设定圣经名单)仅当有出场统计时补充。\n for (const [name, entry] of stat) {\n if (!cards.some(c => c.name === name)) {\n cards.push({\n name,\n role: roleOf(name),\n status: statuses.get(name) ?? '',\n lastChapter: entry.last,\n appearances: entry.chapters.size,\n })\n }\n }\n return cards\n}\n\n// ------------------------------------------------------------- foreshadows\n\n/** System prompt for foreshadow suggestions. */\nfunction foreshadowSystemPrompt(): string {\n return [\n '你是一位网文伏笔设计师。你会收到大纲和已写的章节信息,请为小说建议 3-8 条值得埋设的伏笔。',\n '要求:',\n '1. 伏笔必须有明确的回收价值(推动主线、人物弧光、世界观揭秘)。',\n '2. 描述要具体,指出埋设章节与预计回收章节(可空缺)。',\n '3. 优先从大纲的暗线(如记忆代价、残片收集、身世谜团)中提炼。',\n '输出必须是合法 JSON 数组:',\n '[{\"description\": \"伏笔描述\", \"plantedChapter\": 章节号或null, \"targetChapter\": 章节号或null}]',\n '重要:所有字符串值内部不得包含换行符,JSON 必须在一段内完整结束。',\n ].join('\\n')\n}\n\n/** Suggest foreshadows from the outline + plan. */\nexport async function suggestForeshadows(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n): Promise<Foreshadow[]> {\n const user = [\n '请为下面这部小说设计伏笔。',\n `大纲:\\n${project.outline}`,\n `已规划章节数:${project.chapters.length}`,\n ].join('\\n')\n const text = await complete(ctx, config, { system: foreshadowSystemPrompt(), user, temperature: 0.5, maxTokens: Math.max(config.maxTokens, 12000) })\n const parsed = parseJsonArray<Record<string, unknown>>(text)\n const existing = new Set(project.foreshadows.map(f => f.description))\n const created: Foreshadow[] = []\n for (const entry of parsed) {\n if (typeof entry !== 'object' || entry === null) continue\n const description = typeof entry.description === 'string' ? entry.description.trim() : ''\n if (description === '' || existing.has(description)) continue\n existing.add(description)\n created.push({\n id: `fs-${Date.now().toString(36)}-${created.length}`,\n description: description.slice(0, 200),\n plantedChapter: typeof entry.plantedChapter === 'number' ? entry.plantedChapter : undefined,\n targetChapter: typeof entry.targetChapter === 'number' ? entry.targetChapter : undefined,\n status: 'planned',\n })\n }\n project.foreshadows.push(...created)\n project.updatedAt = new Date().toISOString()\n return created\n}\n\n// -------------------------------------------------------------- style asset\n\n/**\n * 写法引擎:从样本文本提取一份写法资产(叙事风格规则)。\n * @returns 提取出的风格规则(未持久化,由调用方存入 project.assets)。\n */\nexport async function extractStyleAsset(\n ctx: Context,\n config: NovelConfig,\n sampleText: string,\n): Promise<{ proseRules: string[]; dialogueRules: string[]; descriptionRules: string[]; boundaries: string[] }> {\n const user = `请分析下面这段样本文本,提炼其叙事风格规则:\\n\\n${sampleText}`\n const text = await complete(ctx, config, { system: styleEngineSystemPrompt(), user, temperature: 0.3, maxTokens: Math.max(config.maxTokens, 12000) })\n const raw = parseJsonObject<{ proseRules?: unknown; dialogueRules?: unknown; descriptionRules?: unknown; boundaries?: unknown }>(text)\n const strArray = (value: unknown): string[] =>\n Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string' && v.trim() !== '') : []\n const result = {\n proseRules: strArray(raw.proseRules),\n dialogueRules: strArray(raw.dialogueRules),\n descriptionRules: strArray(raw.descriptionRules),\n boundaries: strArray(raw.boundaries),\n }\n if (result.proseRules.length + result.dialogueRules.length + result.descriptionRules.length + result.boundaries.length === 0) {\n throw new Error('写法提取失败:模型没有返回有效规则')\n }\n return result\n}\n\n// ------------------------------------------------------------------ export\n\n/** Export the whole book as one txt/md file. */\nexport function exportBook(outputDir: string, project: ProjectState, format: 'txt' | 'md'): { file: string; chars: number; chapters: number } {\n const parts: string[] = []\n if (format === 'md') {\n parts.push(`# ${project.bookName}\\n`)\n } else {\n parts.push(project.bookName, '')\n }\n const done = project.chapters.filter(c => c.file !== undefined)\n for (const chapter of done) {\n const body = readChapterFile(outputDir, chapter) ?? ''\n if (format === 'md') {\n parts.push(`\\n## 第${chapter.no}章 ${chapter.title}\\n`, body.trim(), '')\n } else {\n parts.push('', `第${chapter.no}章 ${chapter.title}`, '', body.trim(), '')\n }\n }\n const content = parts.join('\\n')\n const ext = format === 'md' ? 'md' : 'txt'\n const file = `《${safeFileName(project.bookName)}》全本.${ext}`\n writeFileSync(join(outputDir, file), content, 'utf8')\n return { file, chars: content.length, chapters: done.length }\n}\n","/**\n * 书架(Bookshelf)— 多书管理:一本书记录一个独立输出目录。\n * 状态持久化到 ~/.dsh/dsh-novel-forge-bookshelf.json(跟随 dsh 配置惯例)。\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { randomBytes } from 'node:crypto'\nimport type { BookEntry, BookshelfSnapshot } from './protocol.ts'\nimport { loadProject } from './engine.ts'\n\n/** 书架配置文件路径。 */\nexport function bookshelfFile(): string {\n return join(homedir(), '.dsh', 'dsh-novel-forge-bookshelf.json')\n}\n\ninterface BookshelfStore {\n books: BookEntry[]\n activeBookId: string | null\n}\n\nfunction defaultStore(): BookshelfStore {\n return { books: [], activeBookId: null }\n}\n\n/** 读取书架(无则返回空)。 */\nexport function loadBookshelf(): BookshelfStore {\n const file = bookshelfFile()\n if (!existsSync(file)) return defaultStore()\n try {\n let raw = readFileSync(file, 'utf8')\n if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1)\n const parsed = JSON.parse(raw) as BookshelfStore\n if (!Array.isArray(parsed.books)) return defaultStore()\n return { books: parsed.books, activeBookId: parsed.activeBookId ?? null }\n } catch {\n return defaultStore()\n }\n}\n\n/** 持久化书架。 */\nfunction saveBookshelf(store: BookshelfStore): void {\n const file = bookshelfFile()\n mkdirSync(join(homedir(), '.dsh'), { recursive: true })\n writeFileSync(file, JSON.stringify(store, null, 2), 'utf8')\n}\n\n/** 当前激活的书。 */\nexport function activeBook(store: BookshelfStore): BookEntry | undefined {\n return store.books.find(b => b.id === store.activeBookId)\n}\n\n/** 书架快照(含每本书的进度摘要)。 */\nexport function bookshelfSnapshot(store: BookshelfStore): BookshelfSnapshot {\n return {\n books: store.books.map(book => {\n const project = loadProject(book.outputDir)\n const done = project === undefined ? 0 : project.chapters.filter(c => c.status === 'approved' || c.status === 'written' || c.status === 'rejected').length\n const hasCover = project?.coverPath !== undefined && project.coverPath !== '' && existsSync(join(book.outputDir, project.coverPath))\n return {\n ...book,\n done,\n total: project?.chapters.length ?? 0,\n hasProject: project !== undefined,\n hasCover,\n blurb: project?.blurb,\n }\n }),\n activeBookId: store.activeBookId,\n }\n}\n\n/** 新建一本书(自动成为当前书)。 */\nexport function createBook(bookName: string, outputDir: string): BookEntry {\n const store = loadBookshelf()\n const id = `book-${Date.now().toString(36)}-${randomBytes(3).toString('hex')}`\n const now = new Date().toISOString()\n const book: BookEntry = { id, bookName, outputDir, createdAt: now, updatedAt: now }\n store.books.push(book)\n store.activeBookId = id\n saveBookshelf(store)\n return book\n}\n\n/** 更新某本书的书名(开书向导导入大纲后书名以大纲首行为准)。 */\nexport function renameBook(id: string, bookName: string): boolean {\n const store = loadBookshelf()\n const book = store.books.find(b => b.id === id)\n if (book === undefined) return false\n book.bookName = bookName\n book.updatedAt = new Date().toISOString()\n saveBookshelf(store)\n return true\n}\n\n/**\n * 播种:书架为空时,把指定输出目录下已有的项目自动登记为第一本书。\n * 兼容升级场景 —— 旧版插件直接在输出目录写项目,从未登记书架。\n * @param outputDir - 候选输出目录(通常为 settings 的默认输出目录)。\n * @returns 是否发生了播种。\n */\nexport function seedBookshelfFromOutputDir(outputDir: string): boolean {\n const store = loadBookshelf()\n if (store.books.length > 0) return false\n if (!existsSync(outputDir)) return false\n // 有项目文件,或至少有章节文件,才视为\"已有的书\"。\n const hasProject = existsSync(join(outputDir, 'novel-project.json'))\n const hasChapters = existsSync(outputDir)\n if (!hasProject && !hasChapters) return false\n const project = loadProject(outputDir)\n const bookName = project?.bookName ?? outputDir.split(/[\\\\/]/).pop() ?? '未命名小说'\n createBook(bookName, outputDir)\n return true\n}\n\n/** 激活一本书。 */\nexport function activateBook(id: string): BookEntry | undefined {\n const store = loadBookshelf()\n const book = store.books.find(b => b.id === id)\n if (book === undefined) return undefined\n store.activeBookId = id\n book.updatedAt = new Date().toISOString()\n saveBookshelf(store)\n return book\n}\n\n/** 移除一本书。 */\nexport function removeBook(id: string): boolean {\n const store = loadBookshelf()\n const idx = store.books.findIndex(b => b.id === id)\n if (idx === -1) return false\n store.books.splice(idx, 1)\n if (store.activeBookId === id) {\n store.activeBookId = store.books[0]?.id ?? null\n }\n saveBookshelf(store)\n return true\n}\n\n/** 当前书输出目录(无书架则 undefined,回退 settings)。 */\nexport function activeBookOutputDir(): string | undefined {\n const book = activeBook(loadBookshelf())\n return book?.outputDir\n}\n\n/** 默认输出目录推断:小说目录/书名。 */\nexport function defaultOutputDirFor(bookName: string): string {\n const clean = bookName.replace(/[\\\\/:*?\"<>|]/g, '').trim().slice(0, 40) || '未命名小说'\n return join('D:\\\\ryan work\\\\harness\\\\novels', clean)\n}\n","/**\n * 生产单(Production Run):批量章节生产的标准执行器。\n * 职责:计划补足 → 逐章生成(完整质量门)→ 被拒分级处理(豁免/修订+验证/待人工)→ 断点续跑。\n * 与路由层解耦:只依赖 engine 导出函数与磁盘状态,自身不碰 HTTP。\n * 串行纪律:单例执行器 + working 锁;每章重新从磁盘加载,写前合并易变字段。\n */\nimport { existsSync, mkdirSync, readFileSync, copyFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { ChapterPlan, NovelConfig, ProjectState, ReviewReport, RunState } from './protocol.ts'\nimport {\n loadProject,\n saveProject,\n mergeVolatileFromDisk,\n planChapters,\n generateChapterStream,\n summarizeAndExtractFacts,\n markForeshadowPlanted,\n reviewChapter,\n reviewChapterText,\n authorReviewChapter,\n autoLinkPlotlines,\n readChapterFile,\n rewriteChapterStream,\n chapterFileName,\n} from './engine.ts'\nimport { loadBookshelf } from './bookshelf.ts'\n\n/** 生产单 checkpoint 文件名(放在书目录下)。 */\nfunction runStateFile(outputDir: string): string {\n return join(outputDir, 'run-state.json')\n}\n\nexport class ProductionRunner {\n private state: RunState | null = null\n private working = false\n private pauseRequested = false\n private stopRequested = false\n /** 生产单绑定目录(start 时快照;所有读写固定用它,防止运行中切书导致写错目录)。 */\n private bookDir: string | null = null\n\n constructor(private deps: { ctx: Context; getConfig: () => NovelConfig }) {}\n\n /** 当前生产单状态(内存优先;web 重启后从磁盘恢复)。 */\n status(): RunState | null {\n if (this.state !== null) return this.state\n // 重启恢复:先找当前激活书目录,再扫书架所有书目录(防切书后找不到)。\n const candidates: string[] = [this.deps.getConfig().outputDir]\n const bookshelf = loadBookshelf()\n for (const b of bookshelf.books) if (!candidates.includes(b.outputDir)) candidates.push(b.outputDir)\n for (const outputDir of candidates) {\n const file = runStateFile(outputDir)\n if (!existsSync(file)) continue\n try {\n const raw = readFileSync(file, 'utf8')\n const parsed = JSON.parse(raw) as RunState\n if (parsed?.runId === undefined) continue\n // 重启恢复:若之前 running,则视为可续跑(loop 未在跑)。\n if (parsed.status === 'running') parsed.status = 'paused'\n this.state = parsed\n this.bookDir = outputDir\n return this.state\n } catch { /* 该目录 run-state 损坏则跳过 */ }\n }\n return null\n }\n\n private persist(): void {\n if (this.state === null) return\n const outputDir = this.bookDir ?? this.deps.getConfig().outputDir\n mkdirSync(outputDir, { recursive: true })\n writeFileSync(runStateFile(outputDir), JSON.stringify(this.state, null, 2), 'utf8')\n }\n\n private log(text: string): void {\n if (this.state === null) return\n this.state.log.push({ at: new Date().toISOString(), text })\n if (this.state.log.length > 300) this.state.log = this.state.log.slice(-300)\n this.state.updatedAt = new Date().toISOString()\n }\n\n /** 启动/续跑生产单:startNo..endNo 区间,endNo 超出计划时先自动补计划。 */\n async start(startNo: number, endNo: number): Promise<RunState> {\n const config = this.deps.getConfig()\n if (this.working) throw new Error('生产单正在运行中,请先暂停或停止')\n let project = loadProject(config.outputDir)\n if (project === undefined) throw new Error('输出目录中没有项目')\n\n // 计划补足:目标区间超出已有计划 → 续写规划追加。\n if (endNo > project.chapters.length) {\n const need = endNo - project.chapters.length\n this.log(`计划不足,追加 ${need} 章计划…`)\n const chapters = await planChapters(this.deps.ctx, config, project, need, undefined, config.outputDir)\n mergeVolatileFromDisk(config.outputDir, project)\n project.chapters.push(...chapters)\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n this.log(`计划已追加,全书 ${project.chapters.length} 章`)\n }\n\n this.state = {\n runId: `run-${Date.now().toString(36)}`,\n startNo,\n endNo,\n status: 'running',\n currentNo: startNo,\n stats: { generated: 0, revised: 0, exempted: 0, regenerated: 0, error: 0 },\n pendingManual: [],\n log: [],\n startedAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n }\n this.pauseRequested = false\n this.stopRequested = false\n // 绑定生产单目录(快照):运行期间切书不影响本单的读写目标。\n this.bookDir = config.outputDir\n this.working = true\n this.persist()\n void this.loop()\n return this.state\n }\n\n pause(): void { this.pauseRequested = true }\n resume(): void {\n if (this.state === null || this.state.status !== 'paused') return\n this.state.status = 'running'\n this.working = true\n this.pauseRequested = false\n this.stopRequested = false\n this.persist()\n void this.loop()\n }\n stop(): void { this.stopRequested = true }\n\n /** 主循环:从 currentNo 扫描到 endNo,逐章处理;支持暂停/停止。 */\n private async loop(): Promise<void> {\n // 全部读写固定使用生产单绑定目录(bookDir),绝不跟随当前激活书。\n const config = this.deps.getConfig()\n const outputDir = this.bookDir ?? config.outputDir\n try {\n while (this.state !== null) {\n if (this.stopRequested) {\n this.stopRequested = false\n this.state.status = 'stopped'\n this.log('生产单已停止')\n this.persist()\n break\n }\n if (this.pauseRequested) {\n this.pauseRequested = false\n this.state.status = 'paused'\n this.log('生产单已暂停(随时可继续)')\n this.persist()\n break\n }\n const project = loadProject(outputDir)\n if (project === undefined) {\n this.state.status = 'error'\n this.state.error = '项目丢失'\n this.persist()\n break\n }\n // 找下一个需要处理的章(approved 快进)。\n let next: ChapterPlan | undefined\n for (let no = this.state.currentNo; no <= this.state.endNo; no++) {\n const ch = project.chapters.find(c => c.no === no)\n if (ch === undefined) continue\n if (ch.status === 'approved') { this.state.currentNo = no; continue }\n next = ch\n break\n }\n if (next === undefined) {\n this.state.status = 'done'\n this.log(`生产单完成:${this.state.startNo}-${this.state.endNo} 章处理完毕`)\n this.persist()\n break\n }\n this.state.currentNo = next.no\n await this.processChapter(project, next)\n this.persist()\n }\n } catch (error) {\n if (this.state !== null) {\n this.state.status = 'error'\n this.state.error = (error as Error).message\n this.log(`生产单异常:${(error as Error).message}`)\n this.persist()\n }\n } finally {\n this.working = false\n }\n }\n\n private async processChapter(project: ProjectState, chapter: ChapterPlan): Promise<void> {\n if (chapter.status === 'pending' || chapter.status === 'error' || chapter.status === 'written') {\n await this.produce(project, chapter)\n } else if (chapter.status === 'rejected') {\n await this.handleRejected(project, chapter)\n } else if (chapter.status === 'generating') {\n // 中断残留:复位重生成。\n chapter.status = 'pending'\n await this.produce(project, chapter)\n }\n }\n\n /** 完整质量门:生成 → 摘要+事实 → 伏笔标记 → 审稿 → 作者复盘。 */\n private async produce(project: ProjectState, chapter: ChapterPlan): Promise<void> {\n const { ctx, getConfig } = this.deps\n const config = getConfig()\n const outputDir = this.bookDir ?? config.outputDir\n const no = chapter.no\n const wasError = chapter.status === 'error'\n chapter.status = 'generating'\n chapter.error = undefined\n chapter.generatingAt = new Date().toISOString()\n mergeVolatileFromDisk(outputDir, project)\n saveProject(outputDir, project)\n this.log(wasError ? `第${no}章《${chapter.title}》重新生成…` : `第${no}章《${chapter.title}》生成…`)\n try {\n for await (const step of generateChapterStream(ctx, config, project, outputDir, no)) { /* drain */ }\n try { await summarizeAndExtractFacts(ctx, config, project, outputDir, no) } catch (e) { console.warn('[dsh-novel-forge] run summary/facts:', (e as Error).message) }\n try { markForeshadowPlanted(project, outputDir, no) } catch (e) { console.warn('[dsh-novel-forge] run foreshadow:', (e as Error).message) }\n if (config.autoReview ?? true) {\n const report = await reviewChapter(ctx, config, project, outputDir, no)\n if (this.state !== null) this.state.stats[wasError ? 'regenerated' : 'generated']++\n this.log(`第${no}章 审稿 ${report.score}分 ${report.passed ? '✅ 通过' : '⚠️ 被拒'}`)\n } else {\n chapter.status = 'approved'\n mergeVolatileFromDisk(outputDir, project)\n saveProject(outputDir, project)\n }\n if (config.autoAuthorReview ?? true) {\n try {\n const body = readChapterFile(outputDir, chapter)\n if (body !== undefined) {\n let prevTail = ''\n if (no > 1) {\n const prev = project.chapters.find(c => c.no === no - 1)\n if (prev !== undefined) prevTail = (readChapterFile(outputDir, prev) ?? '').replace(/^#.*$/m, '').trim().slice(-600)\n }\n const review = await authorReviewChapter(ctx, config, project, no, body, prevTail)\n chapter.authorReview = review\n if (review.advancedLines !== undefined) autoLinkPlotlines(project, no, review.advancedLines)\n mergeVolatileFromDisk(outputDir, project)\n saveProject(outputDir, project)\n }\n } catch (e) { console.warn('[dsh-novel-forge] run author review:', (e as Error).message) }\n }\n } catch (error) {\n chapter.status = 'error'\n chapter.error = (error as Error).message\n mergeVolatileFromDisk(outputDir, project)\n saveProject(outputDir, project)\n if (this.state !== null) this.state.stats.error++\n this.log(`第${no}章 失败:${(error as Error).message}`)\n }\n }\n\n /** 被拒分级处理:无 high 豁免;有 high 按意见修订(最多 2 轮)+ 验证模式;仍不过 → 待人工。 */\n private async handleRejected(project: ProjectState, chapter: ChapterPlan): Promise<void> {\n const { ctx, getConfig } = this.deps\n const config = getConfig()\n const outputDir = this.bookDir ?? config.outputDir\n const no = chapter.no\n const report = chapter.review\n const highs = (report?.issues ?? []).filter(i => i.severity === 'high')\n if (highs.length === 0) {\n chapter.status = 'approved'\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n if (this.state !== null) this.state.stats.exempted++\n this.log(`第${no}章 豁免通过(无 high)`)\n return\n }\n this.log(`第${no}章 修订(${highs.length} 个 high)…`)\n for (let round = 1; round <= 2; round++) {\n const instr = '按审稿意见修订(优先处理):\\n' + highs.map(h => `[${h.severity}] ${h.item}${h.suggestion !== '' ? `\\n建议:${h.suggestion}` : ''}`).join('\\n\\n')\n try {\n for await (const step of rewriteChapterStream(ctx, config, project, outputDir, no, instr, undefined)) { /* drain */ }\n } catch (error) {\n this.log(`第${no}章 第${round}轮修订出错:${(error as Error).message}`)\n continue\n }\n // rewrite 已写盘(pendingDraft + saveProject),重载拿最新草稿。\n const fresh = loadProject(outputDir)\n const freshCh = fresh?.chapters.find(c => c.no === no)\n const draft = freshCh?.pendingDraft\n if (draft === undefined || draft.length < 50) {\n this.log(`第${no}章 第${round}轮草稿缺失,重试`)\n continue\n }\n const verify = await reviewChapterText(ctx, config, fresh!, draft, chapter.review)\n const highs2 = (verify.issues ?? []).filter(i => i.severity === 'high')\n if (verify.passed || highs2.length === 0) {\n // 应用草稿(与 draft/apply 路由同逻辑):备份原稿 → 落盘 → 定状态。\n this.applyDraft(fresh!, freshCh!, draft, verify)\n if (this.state !== null) this.state.stats.revised++\n this.log(`第${no}章 第${round}轮修订通过(${verify.score}分)`)\n return\n }\n this.log(`第${no}章 第${round}轮仍不过(${highs2.length} high)`)\n }\n if (this.state !== null) this.state.pendingManual.push(no)\n this.log(`第${no}章 ⚠️ 两轮修订仍不过 → 保留草稿待人工`)\n }\n\n private applyDraft(project: ProjectState, chapter: ChapterPlan, draft: string, report: ReviewReport): void {\n const config = this.deps.getConfig()\n const fileName = chapterFileName(chapter)\n mkdirSync(config.outputDir, { recursive: true })\n const targetPath = join(config.outputDir, fileName)\n if (existsSync(targetPath)) {\n copyFileSync(targetPath, join(config.outputDir, `${fileName.replace(/\\.md$/, '')}.bak.md`))\n }\n writeFileSync(targetPath, `# 第${chapter.no}章 ${chapter.title}\\n\\n${draft}\\n`, 'utf8')\n chapter.pendingDraft = undefined\n chapter.chars = draft.length\n chapter.file = fileName\n if (typeof report.score === 'number') {\n chapter.review = report\n chapter.status = report.passed === true ? 'approved' : 'rejected'\n } else {\n chapter.status = 'written'\n chapter.review = undefined\n }\n chapter.error = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n }\n}\n","/**\n * dsh-novel-forge — shared protocol between the host half (Node) and the\n * browser half (web GUI). Route paths, request/response shapes, the project\n * state file format, and the NDJSON generation stream frames all live here so\n * both halves spell exactly one vocabulary.\n */\n\n/** The /api/dsh-novel-forge route family (same-origin, loopback-fenced). */\nexport const NOVEL_API = {\n status: '/api/dsh-novel-forge/status',\n loadOutline: '/api/dsh-novel-forge/load-outline',\n saveOutline: '/api/dsh-novel-forge/save-outline',\n plan: '/api/dsh-novel-forge/plan',\n volumes: '/api/dsh-novel-forge/volumes',\n bible: '/api/dsh-novel-forge/bible',\n assets: '/api/dsh-novel-forge/assets',\n styleEngine: '/api/dsh-novel-forge/style-engine',\n generate: '/api/dsh-novel-forge/generate',\n review: '/api/dsh-novel-forge/review',\n rewrite: '/api/dsh-novel-forge/rewrite',\n polish: '/api/dsh-novel-forge/polish',\n /** 采纳待确认草稿(润色/重写产物)覆盖正文文件。 */\n draftApply: '/api/dsh-novel-forge/draft/apply',\n /** 放弃待确认草稿,保留原稿。 */\n draftDiscard: '/api/dsh-novel-forge/draft/discard',\n summary: '/api/dsh-novel-forge/summary',\n foreshadow: '/api/dsh-novel-forge/foreshadow',\n exportBook: '/api/dsh-novel-forge/export',\n chapter: '/api/dsh-novel-forge/chapter',\n /** 审查任意正文文本(作者手动编辑后,不落盘)。 */\n chapterCheck: '/api/dsh-novel-forge/chapter/check',\n /** 保存手动编辑的正文(自动备份 .bak)。 */\n chapterSave: '/api/dsh-novel-forge/chapter/save',\n assistant: '/api/dsh-novel-forge/assistant',\n assistantHistory: '/api/dsh-novel-forge/assistant-history',\n /** 清空助手对话记录。 */\n assistantClear: '/api/dsh-novel-forge/assistant/clear',\n bookshelf: '/api/dsh-novel-forge/bookshelf',\n /** 重置项目(可选携带新大纲):清空设定/卷/章节/伏笔/资产/事实库。 */\n reset: '/api/dsh-novel-forge/reset',\n /** 全书一致性质检:LLM 扫描已生成章节,输出矛盾问题清单。 */\n audit: '/api/dsh-novel-forge/audit',\n /** 角色卡刷新:基于事实库与各章摘要聚合角色当前状态。 */\n charactersRefresh: '/api/dsh-novel-forge/characters/refresh',\n /** 事实库回填:对历史已生成章节批量抽取事实(旧章节无事实记录时用)。 */\n factsBackfill: '/api/dsh-novel-forge/facts/backfill',\n /** 设定圣经局部修补(如世界观规则编辑)。 */\n biblePatch: '/api/dsh-novel-forge/bible/patch',\n /** 小说简介:生成(AI)/补全(AI)/保存。 */\n blurb: '/api/dsh-novel-forge/blurb',\n /** 重命名当前书(同步项目与书架条目)。 */\n rename: '/api/dsh-novel-forge/rename',\n /** 大世界:AI 提炼 / 保存结构化数据(境界/区域/势力)。 */\n world: '/api/dsh-novel-forge/world',\n /** 封面:GET 读取(dataUrl)/ POST 上传或移除。 */\n cover: '/api/dsh-novel-forge/blurb/cover',\n /** 剧情线管理:增删改 + 关联章节。 */\n plotlines: '/api/dsh-novel-forge/plotlines',\n /** 角色库:AI 提炼 / 采纳 / 更新 / 删除。 */\n roles: '/api/dsh-novel-forge/roles',\n scenes: '/api/dsh-novel-forge/scenes',\n visualRules: '/api/dsh-novel-forge/visual-rules',\n /** 作者复盘补跑:对已写章节补齐 authorReview(全书流式 / 单章 JSON)。 */\n reviewBackfill: '/api/dsh-novel-forge/review/backfill',\n /** 章节复位:generating 卡死 → pending(可重新生成)。 */\n chapterReset: '/api/dsh-novel-forge/chapter/reset',\n /** 章节直接通过:作者对 rejected/written 章节行使最终决定权。 */\n chapterApprove: '/api/dsh-novel-forge/chapter/approve',\n /** 敏感词检查:全书已写章节或指定文本。 */\n sensitiveCheck: '/api/dsh-novel-forge/sensitive-check',\n /** 开书想法 → AI 补全大纲:输入一句话想法,生成 2-3 个可选大纲方案。 */\n outlineSuggest: '/api/dsh-novel-forge/outline/suggest',\n /** 拆书分析:对已写章节做结构/人物/文风/卖点四维体检(两阶段:源笔记→分节分析)。 */\n breakdown: '/api/dsh-novel-forge/breakdown',\n /** 漫剧分镜生成:章节 → 角色锚点 + 分镜表(可适配豆包/Seedance/SD)。 */\n /** 漫剧分集计划:读一卷 → 按故事弧线分集(高潮拆集/过渡并章)。 */\n /** 漫画脚本:章节 → 分页分格漫画脚本(含角色视觉锚点)。 */\n /** 生产单:启动批量生产(计划补足 + 逐章生成 + 被拒分级处理)。 */\n runStart: '/api/dsh-novel-forge/run/start',\n /** 生产单控制:pause / resume / stop。 */\n runControl: '/api/dsh-novel-forge/run/control',\n /** 生产单状态(含进度统计与日志)。 */\n runStatus: '/api/dsh-novel-forge/run/status',\n config: '/api/dsh-novel-forge/config',\n openFolder: '/api/dsh-novel-forge/open-folder',\n} as const\n\n/** 书架:一本书的条目。 */\nexport interface BookEntry {\n /** 稳定 id。 */\n id: string\n /** 书名。 */\n bookName: string\n /** 该书输出目录(独立项目目录)。 */\n outputDir: string\n /** 创建时间。 */\n createdAt: string\n /** 最后活动时间。 */\n updatedAt: string\n}\n\n/** 书架快照(含每本书的进度摘要)。 */\nexport interface BookshelfSnapshot {\n books: Array<BookEntry & { done: number; total: number; hasProject: boolean; hasCover: boolean; blurb?: string }>\n /** 当前激活的书 id(无则 null)。 */\n activeBookId: string | null\n}\n\n/** POST /bookshelf 请求:创建新书。 */\nexport interface BookCreateRequest {\n bookName: string\n outputDir?: string\n /** 开书向导:创建时直接导入的大纲文本(提供则立即建立项目)。 */\n outline?: string\n}\n\n/** POST /reset 请求:重置项目(可选更新大纲)。 */\nexport interface ResetRequest {\n /** 新大纲文本;提供则替换 outline,否则保留原大纲。 */\n outline?: string\n}\n\n/** POST /bookshelf/activate 请求:切换当前书。 */\nexport interface BookActivateRequest {\n id: string\n}\n\n/** POST /bookshelf/remove 请求:移除书架条目。 */\nexport interface BookRemoveRequest {\n id: string\n}\n\n/** Chapter lifecycle states (the writing pipeline's state machine). */\nexport type ChapterStatus =\n | 'pending' // planned, not started\n | 'generating' // LLM writing right now\n | 'written' // body on disk, awaiting review\n | 'reviewing' // review in progress\n | 'approved' // passed review (or user-approved)\n | 'rejected' // review found problems\n | 'error' // generation failed\n\n/** One chapter in the plan. */\nexport interface ChapterPlan {\n /** 1-based chapter number (stable identity; files are named from it). */\n no: number\n /** Volume this chapter belongs to (1-based; 0 = unassigned). */\n volume: number\n /** Chapter title, decided by the LLM plan step. */\n title: string\n /** Story beats / plot points for this chapter (model-facing guidance). */\n beats: string\n /** Target character count (defaults to the configured chapter size). */\n targetChars: number\n /** Generation/review state. */\n status: ChapterStatus\n /** 进入 generating 的时间(用于超时自动复位;未在生成时无此字段)。 */\n generatingAt?: string\n /** Actual character count once generated. */\n chars?: number\n /** Failure message when status is 'error'. */\n error?: string\n /** Output file name once generated (relative to the output dir). */\n file?: string\n /** LLM summary of the chapter (narrative memory for later chapters). */\n summary?: string\n /** Latest review report (present once reviewed). */\n review?: ReviewReport\n /** 作者复盘:钩子兑现/结尾钩子/剧情线推进/连续性/节奏趋势(生成后自动)。 */\n authorReview?: AuthorReview\n /**\n * 待确认草稿:润色(去AI味)或整章重写的产物正文。生成时先存这里,\n * 用户看过对比后点「采纳」才覆盖正文文件;点「放弃」则丢弃。刷新页面不丢失。\n */\n pendingDraft?: string\n}\n\n/** 作者复盘:叙事结构层面的逐章检查(钩子/推进/连续性/趋势)。 */\nexport interface AuthorReview {\n /** 上一章结尾钩子是否在本章兑现。 */\n hookHonored: boolean\n /** 钩子兑现说明(未兑现时给出建议)。 */\n hookNote: string\n /** 本章结尾钩子强度 0-10。 */\n endingHook: number\n /** 剧情线推进情况(推进了哪条线/或未推进)。 */\n plotlineProgress: string\n /** 结构化:本章推进的剧情线名称列表(与项目剧情线 name 精确匹配,复盘后自动关联章节)。 */\n advancedLines?: string[]\n /** 连续性检查(人物位置/时间/伤势/资源是否与上章衔接)。 */\n continuity: string\n /** 近期节奏趋势提示(拖沓/爽点密度等)。 */\n trend: string\n /** 复盘时间。 */\n reviewedAt: string\n}\n\n/** One review finding. */\nexport interface ReviewIssue {\n /** Severity: high = must fix, medium = should fix, low = suggestion. */\n severity: 'high' | 'medium' | 'low'\n /** What the problem is. */\n item: string\n /** Concrete suggestion for fixing it. */\n suggestion: string\n}\n\n/** AI review report for one chapter. */\nexport interface ReviewReport {\n /** Overall score 0-100. */\n score: number\n /** Pass threshold (config; 70 default). */\n passed: boolean\n /** One-line verdict. */\n verdict: string\n /** Individual findings. */\n issues: ReviewIssue[]\n /** When the review ran. */\n reviewedAt: string\n}\n\n/** A volume of the book. */\nexport interface Volume {\n /** 1-based volume number. */\n no: number\n /** Volume title. */\n title: string\n /** Volume positioning / summary. */\n summary: string\n /** First chapter number of this volume. */\n chapterStart: number\n /** Last chapter number (inclusive). */\n chapterEnd: number\n}\n\n/** A character card from the story bible. */\nexport interface CharacterCard {\n name: string\n role: 'protagonist' | 'supporting' | 'antagonist' | 'other'\n /** Personality / traits (short lines). */\n traits: string[]\n /** Goals and motivations. */\n goals: string\n /** Key relations to other characters. */\n relations: string\n /** 知情度:该角色已经知道的事实/秘密(未列出的信息该角色不知道)。 */\n knowledge?: string[]\n}\n\n/** The structured story bible (worldbuilding extracted from the outline). */\nexport interface StoryBible {\n /** Genre + tone tags. */\n genre: string\n /** Worldbuilding rules (power system, geography, factions...). */\n worldRules: string[]\n /** Character cards. */\n characters: CharacterCard[]\n /** Writing red lines (forbidden content / must-avoid tropes). */\n redLines: string[]\n /** Style guidance (pacing, pov, tone). */\n style: string[]\n /** When the bible was generated. */\n generatedAt?: string\n}\n\n/** A planted/active/resolved foreshadowing thread. */\nexport interface Foreshadow {\n /** Stable id. */\n id: string\n /** What the foreshadow is. */\n description: string\n /** Chapter where it was planted (undefined = planned). */\n plantedChapter?: number\n /** Chapter where it should be paid off. */\n targetChapter?: number\n /** Lifecycle state. */\n status: 'planned' | 'planted' | 'progressing' | 'resolved' | 'abandoned'\n /** Resolution note when resolved. */\n resolvedNote?: string\n}\n\n/** 一条已确立的叙事事实(事实库/时间线,注入后续章节生成)。 */\nexport interface ChapterFact {\n /** 来源章节号。 */\n chapterNo: number\n /** 事实文本(人物状态/境界资源/关系变化/伏笔落地等)。 */\n text: string\n}\n\n/** 一条全书质检发现的问题(一致性矛盾,定位到章)。 */\nexport interface AuditIssue {\n /** 问题所在章节号(无法定位时 0)。 */\n chapterNo: number\n severity: 'high' | 'medium' | 'low'\n /** 矛盾描述。 */\n item: string\n /** 修改建议。 */\n suggestion: string\n}\n\n/** POST /audit 响应。 */\nexport interface AuditResponse {\n issues: AuditIssue[]\n /** 参与质检的章节数。 */\n auditedChapters: number\n /** 质检时间。 */\n auditedAt: string\n}\n\n/** 全书质检的实时状态(通过 /status 暴露给面板/外部读取)。 */\nexport interface AuditStatus {\n status: 'idle' | 'running' | 'done' | 'error'\n /** 开始时间(ISO)。 */\n startedAt?: string\n /** 结束时间(ISO)。 */\n finishedAt?: string\n /** 总批次数(0 = 尚未开始/无章节)。 */\n totalBatches: number\n /** 已完成批次数。 */\n completedBatches: number\n /** 参与质检的章节数。 */\n auditedChapters?: number\n /** 发现的问题数(done 后有效)。 */\n issuesCount?: number\n /** 最近一次质检的问题清单(done 后有效;error 时为空)。 */\n issues?: AuditIssue[]\n /** 失败信息(error 时有效)。 */\n error?: string\n}\n\n/** 一条剧情线(主线/支线/人物线/悬念线)。 */\nexport interface Plotline {\n /** 稳定 id。 */\n id: string\n /** 线名。 */\n name: string\n /** 类型:主线 / 支线 / 人物线 / 悬念线。 */\n kind: 'main' | 'branch' | 'character' | 'mystery'\n /** 目标/终点(这条线最终要完成什么)。 */\n goal: string\n /** 当前进度说明(最近推进到哪)。 */\n progress: string\n /** 生命周期状态。 */\n status: 'active' | 'paused' | 'resolved' | 'abandoned'\n /** 关联章节号(推进/落地的章节)。 */\n chapters: number[]\n /** 创建时间。 */\n createdAt: string\n}\n\n/** POST /plotlines 请求:剧情线增删改 + 关联章节 + AI 辅助。 */\nexport interface PlotlinesRequest {\n op: 'add' | 'update' | 'remove' | 'link' | 'suggest' | 'refresh' | 'health' | 'plan'\n /** add / update 时传入的完整剧情线。 */\n line?: Plotline\n /** remove / link / refresh 时的目标线 id。 */\n id?: string\n /** link 时关联的章节号。 */\n chapterNo?: number\n}\n\n/** 剧情线健康检查报告。 */\nexport interface PlotlineHealthReport {\n /** 是否需要新线(需要 / 暂不需要 / 再写 X 章后需要)。 */\n verdict: string\n /** 建议添加新线的时机说明。 */\n timing: string\n /** 依据(基于数据的理由,每条一句)。 */\n reasons: string[]\n /** 各线健康度。 */\n lines: Array<{\n name: string\n /** ok=健康 / warning=预警 / stale=搁置过久。 */\n health: 'ok' | 'warning' | 'stale'\n note: string\n }>\n}\n\n/** AI 剧情方案:下一阶段目标 + 建议新线。 */\nexport interface PlotlinePlan {\n /** 下一阶段(未来 5-10 章)剧情方向。 */\n direction: string\n /** 建议的新线(可逐条采纳)。 */\n suggestions: Plotline[]\n}\n\n/** POST /plotlines 响应。 */\nexport interface PlotlinesResponse {\n plotlines: Plotline[]\n /** op=suggest 时的 AI 建议候选线。 */\n suggestions?: Plotline[]\n /** op=health 时的健康检查报告。 */\n health?: PlotlineHealthReport\n /** op=plan 时的剧情方案。 */\n plan?: PlotlinePlan\n}\n\n/** 一条敏感词命中。 */\nexport interface SensitiveHit {\n /** 命中章节号(文本检测时为 0)。 */\n chapterNo: number\n /** 命中的违禁词。 */\n word: string\n /** 类别:政治 / 擦边 / 暴力 / 辱骂 / 广告 / 其他。 */\n category: string\n /** 出现次数。 */\n count: number\n}\n\n/** POST /sensitive-check 请求:检测指定章节/任意文本/全书。 */\nexport interface SensitiveCheckRequest {\n /** 检测该章正文。 */\n chapterNo?: number\n /** 检测任意文本(优先于 chapterNo)。 */\n text?: string\n /** 扫描全部已写章节。 */\n all?: boolean\n}\n\n/** POST /sensitive-check 响应。 */\nexport interface SensitiveCheckResponse {\n hits: SensitiveHit[]\n /** 参与扫描的章节数。 */\n scannedChapters: number\n}\n\n/** 开书想法 → AI 大纲方案(一个候选)。 */\nexport interface OutlineCandidate {\n /** 唯一 id(前端暂留/换批用)。 */\n id: string\n /** 推荐书名。 */\n bookName: string\n /** 题材(如 仙侠修真 / 都市)。 */\n genre: string\n /** 核心卖点一句话。 */\n sellingPoint: string\n /** 完整大纲文本(可直接用作项目大纲,≥800 字)。 */\n outline: string\n}\n\n/** POST /outline/suggest 请求:想法 → 2-3 个可选大纲。 */\nexport interface OutlineSuggestRequest {\n /** 作者想法(一两句话,≥50 字)。 */\n idea: string\n /** 本次要生成的候选数(默认 3,最多 3)。 */\n count?: number\n /** 已暂留方案的剧情方向摘要(换批时让 LLM 避开,防止与已留方案重复)。 */\n exclude?: string[]\n}\n\n/** POST /outline/suggest 响应。 */\nexport interface OutlineSuggestResponse {\n candidates: OutlineCandidate[]\n}\n\n/** 拆书分析:一个分析小节。 */\nexport interface BreakdownSection {\n /** 小节键:overview / plot / character / style / market。 */\n key: string\n /** 小节标题(如「拆书总览」)。 */\n title: string\n /** 可读分析稿(markdown)。 */\n markdown: string\n /** 结构化数据(程序可消费)。 */\n structured: Record<string, unknown>\n}\n\n/** 拆书分析:一条证据(结论→原文回溯)。 */\nexport interface BreakdownEvidence {\n label: string\n excerpt: string\n /** 来源章节号(0 = 未定位)。 */\n chapterNo: number\n /** 指向的结构化字段。 */\n fieldKey?: string\n}\n\n/** POST /breakdown 请求:对已写章节做拆书分析。 */\nexport interface BreakdownRequest {\n /** 分析范围:'recent'=最近 20 章 / 'volume:N'=第 N 卷 / 'all'=全书(默认 recent)。 */\n scope?: string\n /** 分析档位:'quick'=4 维(总览/剧情/人物/文风)/ 'standard'=5 维(+卖点)。 */\n preset?: 'quick' | 'standard'\n /** token 预算上限(默认 50000)。 */\n budgetTokens?: number\n}\n\n/** POST /breakdown 响应。 */\nexport interface BreakdownResponse {\n sections: BreakdownSection[]\n evidence: BreakdownEvidence[]\n /** 参与分析的章节数。 */\n chaptersScanned: number\n /** 估算消耗 token。 */\n usedTokens: number\n}\n\n/** 角色卡:角色当前状态(从事实库聚合)。 */\nexport interface RoleStatusCard {\n name: string\n /** protagonist / supporting / antagonist / other。 */\n role: string\n /** 当前状态一句话(境界/资源/伤势/心境)。 */\n status: string\n /** 最近出场章节。 */\n lastChapter: number\n /** 出场次数。 */\n appearances: number\n}\n\n/** 角色库条目(主表:作者维护 + AI 提炼 + 编年录自动聚合)。 */\nexport interface RoleRecord {\n /** 角色名(唯一键)。 */\n name: string\n /** 定位:主角 / 女主 / 女配 / 配角 / 反派 / 路人。 */\n roleLabel: 'protagonist' | 'female_lead' | 'female_support' | 'support' | 'antagonist' | 'extra'\n /** 身份一句话(如:祭族后裔、青云宗杂役)。 */\n identity: string\n /** 性格标签。 */\n traits: string[]\n /** 目标与动机。 */\n goals: string\n /** 关系网:[角色名](关系)。 */\n relations: string[]\n /** 成长线:阶段 → 说明(可含章节)。 */\n arc: string[]\n /** 知情度:该角色已经知道的信息。 */\n knowledge: string[]\n /** 首次出场章节(编年录聚合,可手动修正)。 */\n firstChapter?: number\n /** 动漫形象描述词(AI 绘图用:中文描述 + 英文标签 + 关键外貌标签)。 */\n imagePrompt?: {\n /** 中文外貌描述:连贯一段(发色/瞳色/服装/气质/标志物)。 */\n zh: string\n /** 英文绘图标签:booru 风格逗号分隔。 */\n en: string\n /** 中文关键标签(发色/瞳色/服装/气质/标志物)。 */\n tags: string[]\n /** 依据来源说明(哪几章哪些描写)。 */\n source?: string\n }\n /** 角色参考图(dataURL 或 URL)。用于漫画/漫剧出图时锁定角色一致性。 */\n imageUrl?: string\n /** 角色图集(图像锚点):立绘/四视图/表情/场景/细节等,label 标注用途。 */\n gallery?: RoleImage[]\n /** 该角色所需的情绪表情清单(提炼时 LLM 补全 6-12 个,如\"疲惫/麻木/压抑悲伤\")。 */\n expressions?: string[]\n /** LLM 精修的四类生图提示词包(前端拼装版之外的高质量版,promptKit 接口生成)。 */\n promptKit?: {\n /** 立绘:全身/半身正视图。 */\n portrait: { zh: string; en: string }\n /** 四视图:正面/侧面/背面设定表。 */\n sheet: { zh: string; en: string }\n /** 表情:同一脸部锚换情绪,每表情一段。 */\n expressions: { name: string; zh: string; en: string }[]\n /** 细节:标志物局部特写。 */\n details: { zh: string; en: string }\n }\n /** 漫画/漫剧重要性:main=必须建卡保证一致;support=有锚点即可;extra=路人随机生成不约束。 */\n importance?: 'main' | 'support' | 'extra'\n}\n\n/** 角色图集条目:一张已定型的角色图(图像锚点)。 */\nexport interface RoleImage {\n /** 用途标签:立绘 / 四视图 / 表情-疲惫 / 场景 / 细节 等。 */\n label: string\n /** dataURL 或 URL。 */\n dataUrl: string\n}\n\n/** 场景库条目:从正文提炼的「镜头场景」视觉锚点(漫剧分镜/生图用)。 */\nexport interface SceneCard {\n /** 场景名(唯一键),如「旧茶渡·地下石殿」。 */\n name: string\n /** 一句话定位:空间/氛围/功能。 */\n summary: string\n /** 幕归属:第一幕·后场 / 第二幕·卖场 / …(便于按剧情段落组织)。 */\n act?: string\n /** 时间光态:夜间闭店后 / 雨夜 / 凌晨 / 频闪灯… */\n moment?: string\n /** 关键情节镜头 1-3 条:该场景拍什么(人物动作+情绪+镜头推进)。 */\n beats?: string[]\n /** 人物在场状态:主角/关键角色在该场景的状态一句话。 */\n characterState?: string\n /** 环境构成:空间结构/陈设/标志物。 */\n elements: string[]\n /** 色调与光影(含 HEX 色板,可空)。 */\n palette: string[]\n /** 氛围关键词:压抑/神秘/空旷… */\n moods: string[]\n /** 中文生图提示词(连贯一段,写实电影感)。 */\n zh: string\n /** 英文生图提示词(逗号分隔标签)。 */\n en: string\n /** 关键标签。 */\n tags: string[]\n /** 依据来源(哪几章哪些描写)。 */\n source?: string\n /** 场景图集(图像锚点):全景/局部/氛围 等。 */\n gallery?: RoleImage[]\n}\n\n/** POST /scenes 请求:场景库提炼 / 采纳 / 更新 / 删除 / 图集。 */\nexport interface ScenesRequest {\n op: 'extract' | 'adopt' | 'update' | 'remove' | 'image' | 'removeImage'\n /** adopt / update 时传入的场景卡(adopt 可修改后采纳)。 */\n scene?: SceneCard\n /** remove / image 时的场景名。 */\n name?: string\n /** op='image' 时的图片 dataURL 与用途标签(全景/局部/氛围)。 */\n dataUrl?: string\n label?: string\n}\n\n/** POST /visual-rules 请求:视觉世界观规则提炼 / 保存。 */\nexport interface VisualRulesRequest {\n op: 'extract' | 'save'\n /** op=save 时的规则数组。 */\n rules?: string[]\n}\n\n/** POST /visual-rules 响应。 */\nexport interface VisualRulesResponse {\n rules: string[]\n}\n\n/** POST /scenes 响应。 */\nexport interface ScenesResponse {\n scenes: SceneCard[]\n /** op=extract 时的 AI 候选场景。 */\n candidates?: SceneCard[]\n}\n\n/** POST /roles 请求:角色库增删改 + AI 提炼 + 参考图上传。 */\nexport interface RolesRequest {\n op: 'extract' | 'adopt' | 'update' | 'remove' | 'visual' | 'image' | 'removeImage' | 'imageGenerate' | 'promptKit'\n /** adopt / update 时传入的角色(adopt 可修改后采纳)。 */\n role?: RoleRecord\n /** remove 时的角色名。 */\n name?: string\n /** op='image' 时的参考图 dataURL。 */\n dataUrl?: string\n /** op='image' 时的图集用途标签(立绘/四视图/表情-x/场景/细节);缺省视为角色参考图(imageUrl)。 */\n label?: string\n /** op='imageGenerate' 时的漫画风格预设 id(用于统一角色图与漫画页风格)。 */\n style?: string\n}\n\n/** POST /roles 响应。 */\nexport interface RolesResponse {\n roles: RoleRecord[]\n /** op=extract 时的 AI 候选角色。 */\n candidates?: RoleRecord[]\n /** op=visual 时的动漫形象描述词(已写入角色卡)。 */\n visual?: RoleRecord['imagePrompt']\n /** op=promptKit 时的四类提示词精修包(已写入角色卡)。 */\n promptKit?: RoleRecord['promptKit']\n /** op=image 时的角色参考图 dataURL。 */\n imageUrl?: string\n}\n\n/** POST /bible/patch 请求:局部修补设定圣经。 */\nexport interface BiblePatchRequest {\n worldRules?: string[]\n redLines?: string[]\n style?: string[]\n /** 角色卡整体替换(人物志编辑知情度等)。 */\n characters?: CharacterCard[]\n}\n\n/** POST /blurb 请求:AI 生成/补全或手动保存小说简介。 */\nexport interface BlurbRequest {\n action: 'generate' | 'save'\n /** 已写好的开头(AI 补全时使用;留空 = 全量生成)。 */\n partial?: string\n /** 手动保存的完整简介(action=save 时)。 */\n text?: string\n}\n\n/** POST /chapter/check|save 请求:审查/保存手动编辑的正文。 */\nexport interface ChapterTextRequest {\n chapterNo: number\n /** 当前编辑中的正文全文。 */\n text: string\n /** 保存时携带:已在工作区审查过的报告(沿用落盘,不重复审);缺省则保存后自动正式审稿一次。 */\n report?: ReviewReport\n /** 审查/验证时携带:上一轮审稿报告。传入后进入「验证模式」——逐条核对原意见是否解决、\n * 只挑新增 high,不再全新找茬(防止\"越修 high 越多\")。 */\n previousReport?: ReviewReport\n}\n\n/** POST /chapter/save 响应。 */\nexport interface ChapterSaveResponse {\n ok: boolean\n chars: number\n file: string\n /** 落盘的审稿报告(沿用工作区报告或保存后自动审稿)。 */\n report?: ReviewReport\n}\n\n/** POST /cover 请求:上传或移除封面。 */\nexport interface CoverRequest {\n action: 'upload' | 'remove'\n /** 上传时:data:image/...;base64,... 格式的图片数据。 */\n dataUrl?: string\n}\n\n/** POST /rename 请求:重命名当前书。 */\nexport interface RenameRequest {\n bookName: string\n}\n\n/** 大世界:一个境界等级。 */\nexport interface WorldRealm {\n /** 境界名(练气/筑基/金丹…)。 */\n name: string\n /** 描述:突破条件/寿命/标志等。 */\n description: string\n}\n\n/** 大世界:一个地理区域。 */\nexport interface WorldRegion {\n name: string\n description: string\n /** 关联势力名(可空)。 */\n faction?: string\n}\n\n/** 大世界:一方势力。 */\nexport interface WorldFaction {\n name: string\n /** 类型:宗门/家族/王朝/组织… */\n kind: string\n description: string\n /** 驻地区域(可空)。 */\n region?: string\n}\n\n/** 大世界结构化数据。 */\nexport interface WorldState {\n realms: WorldRealm[]\n regions: WorldRegion[]\n factions: WorldFaction[]\n}\n\n/** POST /world 请求:AI 提炼或手动保存。 */\nexport interface WorldRequest {\n action: 'generate' | 'save'\n /** action=save 时的完整世界数据。 */\n world?: WorldState\n}\n\n/** GET /cover 响应:封面的 dataUrl(无封面为 null)。 */\nexport interface CoverResponse {\n dataUrl: string | null\n}\n\n/** The persisted project: outline + bible + plan + progress. */\nexport interface ProjectState {\n /** Book title (first non-empty line of the outline, usually). */\n bookName: string\n /** Full outline text (docx-extracted or pasted). */\n outline: string\n /** Source outline path when loaded from a docx. */\n outlinePath?: string\n /** Structured story bible (worldbuilding), if generated. */\n bible?: StoryBible\n /** Volumes, if planned. */\n volumes?: Volume[]\n /** Chapter plan. */\n chapters: ChapterPlan[]\n /** Foreshadowing threads. */\n foreshadows: Foreshadow[]\n /** 写作资产(题材基底/推进模式/反AI规则/写法资产)。 */\n assets?: ProjectAssets\n /** 事实库/时间线:每章生成后抽取,注入后续章节保持一致性。 */\n facts?: ChapterFact[]\n /** 小说简介(面向读者的作品门面,AI 生成或手动保存)。 */\n blurb?: string\n /** 封面文件名(相对输出目录,如 cover.png)。 */\n coverPath?: string\n /** 大世界结构化数据(境界体系/区域/势力)。 */\n world?: WorldState\n /** 剧情线(主线/支线/人物线/悬念线)。 */\n plotlines?: Plotline[]\n /** 角色库(作者维护 + AI 提炼的主表)。 */\n roles?: RoleRecord[]\n /** 场景库(作者维护 + AI 提炼的主表)。 */\n scenes?: SceneCard[]\n /** 视觉世界观规则(生图/生视频必须遵守,从道藏提炼,注入所有提示词)。 */\n visualRules?: string[]\n /** 人物志:角色当前状态聚合结果(从编年录刷新后存档,打开页面直接显示)。 */\n roleStatus?: RoleStatusCard[]\n /** 漫剧分镜结果缓存:章号 → 分镜(持久化,刷新不丢)。 */\n /** 漫剧分集计划缓存:卷号/0=全书 → 分集计划(持久化,刷新不丢)。 */\n /** 漫画脚本缓存:章号 → 漫画脚本(持久化,刷新不丢)。 */\n /** ISO timestamps. */\n createdAt: string\n updatedAt: string\n}\n\n/** Runtime config surface exposed to the panel (subset of plugin Config). */\nexport interface NovelConfig {\n /** Absolute path of the default docx outline to load. */\n outlinePath: string\n /** Absolute output directory for chapters + project state. */\n outputDir: string\n /** LLM provider route (e.g. deepseek-official). */\n provider: string\n /** LLM model id (e.g. deepseek-v4-flash). */\n model: string\n /** LLM reasoning effort: off = no thinking; low/high/max = thinking intensity. */\n reasoningEffort: 'off' | 'low' | 'high' | 'max'\n /** Target characters per chapter. */\n chapterChars: number\n /** Max output tokens per chapter call. */\n maxTokens: number\n /** Review pass threshold (0-100). */\n reviewPassScore: number\n /** Whether generation auto-runs review after writing. */\n autoReview: boolean\n /** Whether generation auto-runs the author review (hook/continuity/trend) after writing. */\n autoAuthorReview: boolean\n /** 修订/润色产出草稿后是否自动附带一次 AI 审查(工作区显示新稿评分与剩余问题)。 */\n autoReviewAfterRevise: boolean\n /** 豆包/Seedream 生图 API Key(保存在服务端配置,不暴露给前端明文回显)。 */\n imageApiKey?: string\n /** 豆包/Seedream 生图模型 ID(如 doubao-seedream-5-0-pro-260628)。 */\n imageApiModel?: string\n /** 是否启用豆包生图(默认关,避免误调用付费 API)。 */\n imageApiEnabled?: boolean\n}\n\n/** GET /status response. */\nexport interface StatusResponse {\n config: NovelConfig\n /** The persisted project, when one exists in the output dir. */\n project?: ProjectState\n /** Chapter files already on disk (basenames, sorted). */\n generatedFiles: string[]\n /** 全书质检实时状态(用于面板/外部读取进度)。 */\n audit?: AuditStatus\n}\n\n/** 生产单状态(生产单 = 区间批量生产执行器:计划补足 + 逐章生成 + 被拒分级处理)。 */\nexport interface RunState {\n runId: string\n /** 区间起点(含)。 */\n startNo: number\n /** 区间终点(含)。 */\n endNo: number\n status: 'running' | 'paused' | 'done' | 'stopped' | 'error'\n /** 当前处理到的章号(已 approved 的章会快进)。 */\n currentNo: number\n stats: {\n /** 新生成(含审稿)的章数。 */\n generated: number\n /** 被拒后按意见修订并通过的章数。 */\n revised: number\n /** 被拒后豁免通过(无 high)的章数。 */\n exempted: number\n /** error 后重新生成的章数。 */\n regenerated: number\n /** 生成失败的章数。 */\n error: number\n }\n /** 两轮修订仍不过、保留草稿待人工的章号。 */\n pendingManual: number[]\n /** 运行日志(保留最近 300 条)。 */\n log: Array<{ at: string; text: string }>\n startedAt: string\n updatedAt: string\n error?: string\n}\n\n/** POST /run/start request. */\nexport interface RunStartRequest {\n /** 起始章号(默认 1)。 */\n startNo?: number\n /** 结束章号(含;超出计划时自动补计划)。 */\n endNo?: number\n /** 或指定新增章数(从当前最后一章 +1 起)。 */\n count?: number\n}\n\n/** POST /run/control request. */\nexport interface RunControlRequest {\n action: 'pause' | 'resume' | 'stop'\n}\n\n/** POST /load-outline request: either a docx path or raw text. */\nexport interface LoadOutlineRequest {\n /** Absolute docx path; defaults to the configured outline path. */\n path?: string\n /** Raw outline text (takes precedence over path when present). */\n text?: string\n}\n\n/** POST /load-outline response. */\nexport interface LoadOutlineResponse {\n outline: string\n bookName: string\n chars: number\n path?: string\n}\n\n/** POST /plan request. */\nexport interface PlanRequest {\n /** Outline to plan from; defaults to the persisted project's outline. */\n outline?: string\n /** Number of chapters to plan (default: 30). */\n chapterCount?: number\n /** Volume to plan (1-based); when given, plans only that volume's chapters. */\n volume?: number\n}\n\n/** POST /plan response. */\nexport interface PlanResponse {\n chapters: ChapterPlan[]\n volumes?: Volume[]\n}\n\n/** POST /volumes request/response. */\nexport interface VolumesRequest {\n /** Outline to split into volumes; defaults to the project outline. */\n outline?: string\n}\nexport interface VolumesResponse {\n volumes: Volume[]\n}\n\n/** POST /bible request/response. */\nexport interface BibleRequest {\n /** Outline to extract from; defaults to the project outline. */\n outline?: string\n}\nexport interface BibleResponse {\n bible: StoryBible\n}\n\n/** POST /generate request: one chapter of the current project. */\nexport interface GenerateRequest {\n chapterNo: number\n /** When true, skips the auto-review step. */\n skipReview?: boolean\n}\n\n/** One NDJSON frame of a generation/review/rewrite stream. */\nexport type JobFrame =\n | { type: 'start'; no: number; title: string }\n | { type: 'delta'; text: string }\n | { type: 'progress'; chars: number }\n | { type: 'done'; no: number; file: string; chars: number; title: string }\n | { type: 'review'; no: number; report: ReviewReport }\n | { type: 'author-review'; no: number; review: AuthorReview }\n | { type: 'author-backfill-done'; count: number }\n | { type: 'rewritten'; no: number; file: string; chars: number }\n /** 润色/重写完成,产物作为待确认草稿(尚未覆盖正文)。 */\n | { type: 'drafted'; no: number; chars: number; draft: string }\n | { type: 'error'; no: number; message: string }\n\n/** POST /review request: review one written chapter. */\nexport interface ReviewRequest {\n chapterNo: number\n}\n\n/** POST /rewrite request: rewrite one chapter (optionally per review issues). */\nexport interface RewriteRequest {\n chapterNo: number\n /** Free-form instructions; defaults to fixing the review's high issues. */\n instructions?: string\n /**\n * 局部修订:正文中的一段原文(无需完全精确,取一个自然段内的片段即可)。\n * 提供时只重写该段,其余正文保持不变;不提供时整章重写。\n */\n target?: string\n}\n\n/** POST /polish request: de-AI-ify one chapter. */\nexport interface PolishRequest {\n chapterNo: number\n}\n\n/** POST /draft/apply | /draft/discard request: 采纳或放弃待确认草稿。 */\nexport interface DraftDecisionRequest {\n chapterNo: number\n /** apply 时可携带审查报告(沿用结论定状态;不携带则置 written)。 */\n report?: ReviewReport\n}\n\n/** POST /summary request: (re)generate a chapter summary. */\nexport interface SummaryRequest {\n chapterNo: number\n}\n\n/** POST /foreshadow request: create, update, or AI-suggest foreshadows. */\nexport interface ForeshadowRequest {\n /** When true, runs the LLM suggestion pass (ignores other fields). */\n suggest?: boolean\n /** When given, updates that foreshadow instead of creating one. */\n id?: string\n description?: string\n plantedChapter?: number\n targetChapter?: number\n status?: Foreshadow['status']\n resolvedNote?: string\n}\nexport interface ForeshadowResponse {\n foreshadows: Foreshadow[]\n}\n\n/** GET /chapter response. */\nexport interface ChapterResponse {\n no: number\n title: string\n markdown: string\n}\n\n/** POST /export request/response. */\nexport interface ExportRequest {\n format: 'txt' | 'md'\n}\nexport interface ExportResponse {\n file: string\n chars: number\n chapters: number\n}\n\n/** POST /config request: patch any subset of the runtime config. */\nexport interface ConfigPatch {\n outlinePath?: string\n outputDir?: string\n provider?: string\n model?: string\n reasoningEffort?: 'off' | 'low' | 'high' | 'max'\n chapterChars?: number\n maxTokens?: number\n reviewPassScore?: number\n autoReview?: boolean\n autoAuthorReview?: boolean\n autoReviewAfterRevise?: boolean\n imageApiKey?: string\n imageApiModel?: string\n imageApiEnabled?: boolean\n}\n\n// ------------------------------------------------------------ assistant\n\n/** One assistant conversation message (persisted per project). */\nexport interface AssistantMessage {\n role: 'user' | 'assistant' | 'tool'\n /** Message text (tool messages carry the tool result). */\n content: string\n /** ISO timestamp. */\n ts: string\n /** For tool messages: which tool ran. */\n tool?: string\n}\n\n/** POST /assistant request: one user turn. */\nexport interface AssistantRequest {\n message: string\n}\n\n/** One NDJSON frame of the assistant stream. */\nexport type AssistantFrame =\n | { type: 'delta'; text: string }\n | { type: 'tool'; name: string; status: 'start' | 'done' | 'error'; detail?: string }\n /** Live output while a tool runs (e.g. chapter text being generated). */\n | { type: 'toolDelta'; name: string; text: string }\n | { type: 'done' }\n | { type: 'error'; message: string }\n\n/** GET /assistant-history response. */\nexport interface AssistantHistoryResponse {\n messages: AssistantMessage[]\n}\n\n// ---------------------------------------------------------- writing assets\n\n/** 题材基底库:一本书属于哪个阅读市场。树形(题材→子题材→下级)。 */\nexport interface GenreNode {\n /** 题材名称(标签,如「仙侠修真」「都市异能」)。 */\n name: string\n /** 题材特征、常见爽点、叙事重心或读者期待。 */\n description: string\n /** 子题材。 */\n children: GenreNode[]\n}\n\n/** 推进模式库:读者为什么继续看下一章。 */\nexport interface ProgressionMode {\n /** 模式名称(如「升级变强」「经营扩张」「解谜揭露」)。 */\n name: string\n /** 核心驱动力:靠什么制造追读动力。 */\n driver: string\n /** 读者期待:每隔几章获得什么变化或回报。 */\n readerExpectation: string\n /** 常见兑现方式(爽点如何落地)。 */\n payoffs: string[]\n /** 节奏风险:最怕什么(重复升级、冲突变弱、谜题拖太久…)。 */\n risks: string[]\n /** 主模式或辅助模式。 */\n primary: boolean\n}\n\n/** 反 AI 规则:一条「要避免的问题 + 修正方向」。 */\nexport interface AntiAiRule {\n /** 规则名(如「禁止解释型心理描写」「AI 高频套话」)。 */\n name: string\n /** 要避免的表达问题,具体可检查。 */\n avoid: string\n /** 推荐修正方向。 */\n fix: string\n /** 命中即告警的具体表达模式(用于审稿逐条核对与去 AI 味检测)。 */\n detectPatterns?: string[]\n /** 是否内置全局规则(内置规则随插件发布,项目规则为用户自定义)。 */\n builtin?: boolean\n}\n\n/** 预置写法模板(来自 AI-Novel-Writing-Assistant 内置数据,一键绑定无需样本文本)。 */\nexport interface StyleTemplate {\n /** 模板 key(如 power-up-escalation)。 */\n key: string\n /** 模板名(如「爽文递进推进流」)。 */\n name: string\n /** 模板说明。 */\n description: string\n /** 分类(如「爽文流」「悬疑流」)。 */\n category: string\n /** 适用题材。 */\n applicableGenres: string[]\n /** 叙述规则。 */\n proseRules: string[]\n /** 角色/台词规则。 */\n dialogueRules: string[]\n /** 语言规则。 */\n languageRules: string[]\n /** 节奏规则。 */\n rhythmRules: string[]\n /** 该模板默认绑定的反 AI 规则 key(内置规则名)。 */\n defaultAntiAiRuleKeys: string[]\n}\n\n/** 写法引擎:从样本文本提取的叙事风格资产。 */\nexport interface StyleAsset {\n /** 资产名(如「林越式痞坏」「冷峻猎手风」)。 */\n name: string\n /** 叙述视角与句式节奏。 */\n proseRules: string[]\n /** 角色台词风格。 */\n dialogueRules: string[]\n /** 描写密度与情绪表达。 */\n descriptionRules: string[]\n /** 表达边界(不要做什么)。 */\n boundaries: string[]\n /** 来源样本文本(可空)。 */\n sourceText?: string\n /** 创建时间。 */\n createdAt: string\n}\n\n/** 项目写作资产(题材基底 + 推进模式 + 反 AI 规则 + 写法资产)。 */\nexport interface ProjectAssets {\n /** 本书选用的题材(可以是题材基底库中某节点名)。 */\n genre?: GenreNode\n /** 主推进模式。 */\n primaryProgression?: ProgressionMode\n /** 辅助推进模式。 */\n auxiliaryProgressions: ProgressionMode[]\n /** 生效的反 AI 规则(内置 + 自定义)。 */\n antiAiRules: AntiAiRule[]\n /** 绑定的写法资产。 */\n styleAssets: StyleAsset[]\n /** 资产更新时间。 */\n updatedAt?: string\n}\n\n/** GET /assets response(含全局题材库与反 AI 规则库)。 */\nexport interface AssetsResponse {\n projectAssets: ProjectAssets\n /** 全局题材基底库(可复用资产,跨书)。 */\n genreLibrary: GenreNode[]\n /** 全局反 AI 规则库(内置默认规则)。 */\n antiAiLibrary: AntiAiRule[]\n /** 预置写法模板(一键绑定,无需样本文本)。 */\n styleTemplates: StyleTemplate[]\n /** 内置推进模式候选。 */\n progressionLibrary: ProgressionMode[]\n}\n\n/** POST /assets request:更新项目写作资产(部分字段可选)。 */\nexport interface AssetsPatch {\n genre?: GenreNode\n primaryProgression?: ProgressionMode\n auxiliaryProgressions?: ProgressionMode[]\n antiAiRules?: AntiAiRule[]\n styleAssets?: StyleAsset[]\n}\n\n/** POST /style-engine request:从样本文本提取写法资产。 */\nexport interface StyleEngineRequest {\n /** 样本文本(风格来源)。 */\n sampleText: string\n /** 资产名(可选,默认「风格资产 N」)。 */\n name?: string\n}\n","/**\n * docx outline extraction: a .docx is a zip whose word/document.xml holds the\n * body text in <w:t> runs inside <w:p> paragraphs. We unzip with fflate and\n * walk the XML with a tiny tokenizer — no heavyweight XML/DOM dependency.\n */\n\nimport { readFileSync } from 'node:fs'\nimport { unzipSync, strFromU8 } from 'fflate'\n\n/** Decode the handful of XML entities docx bodies actually use. */\nfunction decodeEntities(text: string): string {\n return text\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&apos;/g, \"'\")\n .replace(/&amp;/g, '&')\n .replace(/&nbsp;/g, ' ')\n}\n\n/**\n * Extract plain text from a docx buffer: one line per <w:p> paragraph, with\n * <w:tab>/<w:br> preserved as whitespace. Tables and nested structures are\n * flattened in document order (their paragraphs are just <w:p> too).\n * @param buffer - the raw .docx bytes.\n * @returns the body text.\n */\nexport function extractDocxText(buffer: Uint8Array): string {\n let files: ReturnType<typeof unzipSync>\n try {\n files = unzipSync(buffer)\n } catch (error) {\n throw new Error(`not a valid docx (zip open failed): ${(error as Error).message}`)\n }\n const document = files['word/document.xml']\n if (document === undefined) {\n throw new Error('not a valid docx (word/document.xml missing)')\n }\n const xml = strFromU8(document)\n\n const paragraphs: string[] = []\n // Split on paragraph boundaries; keep the segment text of each.\n const parts = xml.split(/<w:p\\b[^>]*>/)\n for (let i = 1; i < parts.length; i++) {\n const segment = parts[i]!\n // Runs <w:t ...>…</w:t>; also honor <w:tab/> and <w:br/> as spaces.\n const runs: string[] = []\n const runRe = /<w:t(?:\\s[^>]*)?>([\\s\\S]*?)<\\/w:t>|<w:tab\\b[^>]*\\/>|<w:br\\b[^>]*\\/>/g\n for (const match of segment.matchAll(runRe)) {\n if (match[0].startsWith('<w:tab')) {\n runs.push('\\t')\n } else if (match[0].startsWith('<w:br')) {\n runs.push('\\n')\n } else {\n runs.push(decodeEntities(match[1] ?? ''))\n }\n }\n const line = runs.join('').replace(/\\u00a0/g, ' ').trimEnd()\n paragraphs.push(line)\n }\n\n // Collapse 3+ blank lines and trim.\n const text = paragraphs.join('\\n').replace(/\\n{3,}/g, '\\n\\n').trim()\n if (text.length === 0) {\n throw new Error('docx contains no extractable text')\n }\n return text\n}\n\n/**\n * Read and extract a docx outline from disk.\n * @param path - absolute path to the .docx file.\n * @returns the extracted outline text.\n */\nexport function readOutlineFromDocx(path: string): string {\n let buffer: Buffer\n try {\n buffer = readFileSync(path)\n } catch (error) {\n throw new Error(`cannot read outline file \"${path}\": ${(error as Error).message}`)\n }\n return extractDocxText(new Uint8Array(buffer))\n}\n","/**\n * AI assistant engine — a conversational editor over the novel project.\n *\n * The user talks to the assistant about plot, characters, settings; the\n * assistant can reply in prose AND emit action directives that the host\n * executes (rewrite a paragraph, edit the bible, regenerate a chapter,\n * export the book, ...). Conversation history persists next to the project\n * as NDJSON, so a reload keeps the thread.\n *\n * Action protocol: the model emits a line of the form\n * <dsh-action name=\"toolName\">{jsonArgs}</dsh-action>\n * anywhere in its reply. The host strips it, executes the tool, appends the\n * result as a tool-role message, and continues the loop (bounded rounds).\n */\n\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, appendFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { createUserMessage, createAssistantMessage, BlockAssembler, type GenerateOptions, type Message, type StreamChunk, type ContentBlock } from '@deepseek-ai/dsh-llm'\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { AssistantMessage, NovelConfig, ProjectState } from './protocol.ts'\nimport { emptyProjectAssets } from './assets.ts'\nimport {\n analyzeImpact,\n bookOverview,\n chapterFileName,\n exportBook,\n generateChapterStream,\n readChapterFile,\n reviewChapter,\n saveProject,\n summarizeAndExtractFacts,\n} from './engine.ts'\nimport { rewriteChapterStream } from './engine.ts'\n\n/** History file name inside the output dir. */\nexport const ASSISTANT_HISTORY_FILE = 'novel-assistant.jsonl'\n\n/** Max tool-call rounds per user turn (safety bound). */\nconst MAX_TOOL_ROUNDS = 6\n\n/** Max history messages kept in context (older ones summarized away). */\nconst MAX_HISTORY_MESSAGES = 18\n\n// ------------------------------------------------------------------ history\n\n/** Load the persisted conversation (empty when none). */\nexport function loadAssistantHistory(outputDir: string): AssistantMessage[] {\n const file = join(outputDir, ASSISTANT_HISTORY_FILE)\n if (!existsSync(file)) return []\n const messages: AssistantMessage[] = []\n try {\n for (const line of readFileSync(file, 'utf8').split('\\n')) {\n if (line.trim() === '') continue\n try {\n const parsed = JSON.parse(line) as AssistantMessage\n if (typeof parsed.role === 'string' && typeof parsed.content === 'string') messages.push(parsed)\n } catch { /* skip malformed line */ }\n }\n } catch { /* unreadable history -> start fresh */ }\n return messages\n}\n\n/** Append one message to the persisted history. Tool payloads (e.g. full\n * outline / chapter text) are capped so the jsonl and later LLM context\n * don't grow unboundedly. */\nfunction appendHistory(outputDir: string, message: AssistantMessage): void {\n mkdirSync(outputDir, { recursive: true })\n const entry: AssistantMessage = message.role === 'tool' && message.content.length > 4000\n ? { ...message, content: message.content.slice(0, 4000) + '\\n…(已截断,如需完整内容请重新调用工具)' }\n : message\n appendFileSync(join(outputDir, ASSISTANT_HISTORY_FILE), JSON.stringify(entry) + '\\n', 'utf8')\n}\n\n/** 清空助手对话记录(删除历史文件)。 */\nexport function clearAssistantHistory(outputDir: string): void {\n const file = join(outputDir, ASSISTANT_HISTORY_FILE)\n if (existsSync(file)) rmSync(file, { force: true })\n}\n\n// ----------------------------------------------------------------- context\n\n/** Render the project snapshot the assistant sees. */\nfunction renderProjectSnapshot(project: ProjectState): string {\n const sections: string[] = []\n sections.push(`书名:${project.bookName}`)\n sections.push(`总纲节选(如需全文用 outline_text 工具):\\n${project.outline.slice(0, 2500)}`)\n // 写作资产名称化(占位小,需要详情用 assets_status)。\n const assetNames: string[] = []\n if (project.assets?.genre !== undefined) assetNames.push(`题材:${project.assets.genre.name}`)\n if (project.assets?.primaryProgression !== undefined) assetNames.push(`主推进:${project.assets.primaryProgression.name}`)\n if ((project.assets?.styleAssets?.length ?? 0) > 0) assetNames.push(`写法:${project.assets!.styleAssets!.map(s => s.name).join('、')}`)\n if ((project.assets?.antiAiRules?.length ?? 0) > 0) assetNames.push(`文戒自定义:${project.assets!.antiAiRules!.map(r => r.name).join('、')}`)\n if (assetNames.length > 0) sections.push(`【写作资产】${assetNames.join(' · ')}`)\n if (project.bible !== undefined) {\n const bible = project.bible\n sections.push('【道藏】')\n if (bible.genre !== '') sections.push(`题材基调:${bible.genre}`)\n if (bible.worldRules.length > 0) sections.push('世界规则:\\n' + bible.worldRules.map(r => `- ${r}`).join('\\n'))\n if (bible.characters.length > 0) {\n sections.push('角色卡:')\n for (const card of bible.characters) {\n const roleName = { protagonist: '主角', supporting: '配角', antagonist: '反派', other: '其他' }[card.role]\n sections.push(`- ${card.name}(${roleName}):${card.traits.join('、')}${card.goals !== '' ? `;目标:${card.goals}` : ''}`)\n }\n }\n if (bible.redLines.length > 0) sections.push('写作红线:\\n' + bible.redLines.map(r => `- ${r}`).join('\\n'))\n }\n if (project.world !== undefined) {\n const world = project.world\n sections.push('【大世界】')\n if (world.realms.length > 0) sections.push('境界体系:' + world.realms.map((r, i) => `${i + 1}.${r.name}(${r.description.slice(0, 40)})`).join(' → '))\n if (world.regions.length > 0) sections.push('区域:' + world.regions.map(r => r.name).join('、'))\n if (world.factions.length > 0) sections.push('势力:' + world.factions.map(f => `${f.name}(${f.kind})`).join('、'))\n }\n if (project.volumes !== undefined && project.volumes.length > 0) {\n sections.push('【卷结构】')\n for (const v of project.volumes) {\n sections.push(`第${v.no}卷《${v.title}》:${v.summary}(章节 ${v.chapterStart}-${v.chapterEnd})`)\n }\n }\n if (project.chapters.length > 0) {\n // 快照只列最近 30 章(长书时防止上下文膨胀;更早章节可用\n // book_overview scope=volume:N 或 chapter_text 按需查看)。\n const shown = project.chapters.slice(-30)\n sections.push(`【章节计划与进度(最近 ${shown.length} 章)】`)\n for (const c of shown) {\n const statusText = { pending: '待生成', generating: '生成中', written: '待审稿', reviewing: '审稿中', approved: '已通过', rejected: '待修订', error: '失败' }[c.status]\n sections.push(`第${c.no}章《${c.title}》[${statusText}]${c.chars !== undefined ? ` ${c.chars}字` : ''}${c.summary !== undefined && c.summary !== '' ? ` 摘要:${c.summary}` : ''}`)\n }\n if (project.chapters.length > shown.length) {\n sections.push(`(还有 ${project.chapters.length - shown.length} 章未列出,可用 book_overview scope=volume:N 查看)`)\n }\n // 最近两章正文节选(讨论细节时参考)\n const written = project.chapters.filter(c => c.status === 'approved' || c.status === 'written')\n const recent = written.slice(-2)\n if (recent.length > 0) {\n sections.push('【最近章节正文节选】')\n for (const c of recent) {\n sections.push(`第${c.no}章《${c.title}》(节选,如需全文用 chapter_text):${c.beats.slice(0, 300)}`)\n }\n }\n }\n if (project.foreshadows.length > 0) {\n sections.push('【暗线】')\n for (const f of project.foreshadows) {\n sections.push(`- [${f.status}] ${f.description}${f.targetChapter !== undefined ? `(预计 ${f.targetChapter} 章回收)` : ''}`)\n }\n }\n if ((project.facts ?? []).length > 0) {\n sections.push('【已确立编年录(最近 40 条,回答设定问题必须遵守)】')\n for (const f of (project.facts ?? []).slice(-40)) {\n sections.push(`- [第${f.chapterNo}章] ${f.text}`)\n }\n }\n if (project.blurb !== undefined && project.blurb !== '') {\n sections.push(`【卷首语】${project.blurb}`)\n }\n return sections.join('\\n')\n}\n\n/** The assistant system prompt. */\nfunction assistantSystemPrompt(project: ProjectState): string {\n return [\n '你是「编辑老师」——服务这本书作者的资深中文网文编辑。',\n '人设:二十年网文老编辑,懂套路、懂市场、懂节奏,说话直接但句句有用。',\n '座右铭:「书是你的,但坑我替你盯着。」',\n '职责边界:陪作者讨论剧情/人设/世界观/爽点节奏并落地修改、维护全书一致性;不闲聊、不彩虹屁、不无意义长篇大论。',\n '==================== 模块正式名称(回复作者时一律使用,禁止使用括号里的旧称) ====================',\n '总纲 = 总纲;道藏 = 道藏;暗线 = 暗线;卷首语 = 卷首语;编年录 = 编年录。',\n '==================== 当前项目快照 ====================',\n renderProjectSnapshot(project),\n '==================== 快照结束 ====================',\n '',\n '工作规则(严格遵守):',\n '1. 全量知情:回答和修改必须基于项目真实数据,禁止编造书中不存在的设定。需要完整信息时,先调用 book_overview 获取全书上下文(总纲全文/道藏/大世界/编年录/全部章节要点/暗线/卷首语);需要某章正文用 chapter_text。',\n '2. 修改流程:改前用一句话说明意图 → 执行工具 → 改后简要汇报。',\n '3. 连锁维护:改动可能波及其它位置(其它章节、设定、编年录、卷首语)时,执行后主动调用 impact_analysis 分析影响面,并把「必须同步」的项一并处理或明确提示作者逐项确认。',\n '4. 删除红线:删除章节、清空设定等破坏性操作必须等作者明确同意。',\n '5. 品质门槛:建议必须具体——指出问题在哪一章、哪一段、哪一句,并给出可落地的改法;禁止\"建议增强冲突\"这类空话。',\n '6. 设定忠诚:忠于总纲、道藏、大世界、编年录;发现书中已有内容与设定冲突时,主动指出并给修正方案。',\n '7. 中文回复,简洁有干货。',\n '',\n '可用工具:',\n '- book_overview:{\"scope\": \"recent|full|volume:2\"(可选,默认 recent)}。返回全书上下文包(总纲/道藏/大世界/章节要点/编年录/暗线/卷首语)。recent=最近30章;full=全部章节(书很长时慎用);volume:N=只看第N卷。',\n '- facts_query:{\"keyword\": \"关键词\"}。从编年录按关键词检索相关事实(如灵石、境界名、人物名)。',\n '- impact_analysis:{\"change\": \"要做的修改描述\"}。分析这次改动会波及哪些位置,返回影响清单(定位到章节/设定/编年录)。',\n '- outline_text:无参数。返回当前总纲全文。',\n '- outline_replace:{\"old\": \"要替换的原文片段\", \"new\": \"新文本\"}。在总纲中替换一段文字(old 必须能在总纲中找到)。',\n '- bible_set_rule:{\"index\": 序号(0起), \"text\": \"新规则文本\"} 或 {\"append\": \"追加的规则\"}。修改道藏的世界规则。',\n '- bible_set_redline:同上,修改写作红线。',\n '- chapter_text:{\"no\": 章节号}。返回该章正文。',\n '- chapter_rewrite:{\"no\": 章节号, \"instructions\": \"修改要求\", \"target\": \"原文片段(可选,留空整章)\"}。按讨论结果修订章节;给了 target 只改该自然段。',\n '- chapter_generate:{\"no\": 章节号}。重新生成该章。',\n '- chapter_review:{\"no\": 章节号}。对该章执行 AI 审稿。',\n '- foreshadow_add:{\"description\": \"暗线描述\", \"targetChapter\": 预计回收章(可选)}。新增暗线。',\n '- foreshadow_update:{\"id\": \"暗线id\", \"status\": \"planned|planted|progressing|resolved|abandoned\"}。更新暗线状态。',\n '- export_txt:无参数。导出全本 TXT。',\n '- assets_status:无参数。查看本书当前写作资产(题材/推进模式/反AI规则/写法)。',\n '- assets_set_genre:{\"name\": \"题材名\", \"description\": \"题材说明(可选)\"}。设置本书题材基底。',\n '- assets_set_progression:{\"name\": \"模式名\", \"driver\": \"驱动力\", \"primary\": true/false}。设置主/辅助推进模式。',\n '- assets_add_rule:{\"name\": \"规则名(可选)\", \"avoid\": \"要避免的表达问题\", \"fix\": \"修正方向(可选)}。新增反 AI 规则。',\n '',\n '回答质量要求(非常重要):',\n '- 具体:回答必须引用项目里的真实内容(人名、境界、章节、暗线、设定),禁止空泛套话。快照里没有的信息,先调用工具获取(chapter_text / outline_text)再回答。',\n '- 专业:给建议时说明理由,指出问题所在章节/段落,给出可直接落地的修改方案(改什么、怎么改)。',\n '- 主动:作者说\"改一下\",主动调用对应工具执行,不要只给建议不动手;执行前用一句话说明意图,执行后简短汇报结果。',\n '- 忠于设定:以总纲、道藏、编年录为准,不得自相矛盾;发现问题(如剧情与设定冲突)主动指出。',\n '- 中文回复;文字量适中,别啰嗦。',\n '',\n '使用规则(非常重要):',\n '- 写操作(chapter_generate / chapter_rewrite / chapter_review / outline_replace / bible_set_* / foreshadow_* / assets_set_* / export_txt)只有在作者明确要求时才能调用——例如作者说\"生成第 120 章\"\"把第 105 章结尾改一下\"\"帮我审一下第 88 章\"。作者只是提问、闲聊、查信息时,一律用文字回答,禁止调用任何写操作,也不要先斩后奏(如\"为了回答你,我先把第 X 章生成了\")。',\n '- 当你想执行任何工具时,你的【整个回复】必须只包含动作指令标签,格式如下(不要有任何解释文字、不要用自然语言说\"我要去改\",直接输出标签):',\n ' 正确示例:<dsh-action name=\"outline_replace\">{\"old\":\"要替换的原文\",\"new\":\"新文本\"}</dsh-action>',\n ' 正确示例:<dsh-action name=\"chapter_text\">{\"no\":1}</dsh-action>',\n ' 错误示例(绝对不要这样回复):\"好的,我先看一下总纲,马上改。\" ← 这只是文字,不会执行任何操作',\n ' 错误示例(绝对不要这样回复):\"先拉完整上下文确认改动落地情况,避免继续空转。\" ← 没有动作标签,不会执行任何操作',\n ' 错误示例(绝对不要这样回复):\"现在处理暗线库,我先看当前列表定位 id。\" ← 没有动作标签,不会执行任何操作',\n '- 铁律:只要你想执行任何操作,你的【整个回复】必须只包含一个动作标签,禁止先说话、禁止解释\"我要做什么\"、禁止铺垫——直接输出标签。',\n '- 如果你收到「格式提示」(宿主说你没有输出动作标签):你的下一条回复必须只输出动作标签,禁止再解释、禁止再道歉、禁止再描述计划。',\n '- 工具调用是自动的:你输出标签后,宿主会执行并把结果反馈给你,你再基于结果继续。',\n '- 每次回复最多调用 1 个动作;执行结果会反馈给你,你可以继续讨论或再调用。',\n '- 需要先看总纲/章节再决定怎么改?那就先输出一个 outline_text / chapter_text 的标签,等结果回来。',\n '- chapter_rewrite 的 target 参数:从章节正文中复制一小段(一句话或几句话即可),不要带换行、不要带引号,取连续文本片段。',\n '- 如果工具执行失败(例如片段未找到),根据错误信息修正参数后自动重试一次,不要直接放弃或让作者手动操作。',\n '- 修改前先向作者说明你要改什么、为什么;动作执行后简要汇报结果。',\n '- 涉及删除类操作(删除章节、清空设定)必须等作者明确同意。',\n '- 严格忠于道藏与总纲;不得自行发明与既有设定冲突的内容。',\n '- 用中文回复。',\n ].join('\\n')\n}\n\n// ------------------------------------------------------------- action exec\n\n/** Execute one action directive. Returns a text result (or throws). */\n/**\n * Execute one action directive as an async generator: yields live progress\n * text (chapter text being generated/rewritten), then yields the final result\n * string. Throws on failure.\n */\nexport async function* executeAction(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n name: string,\n args: Record<string, unknown>,\n): AsyncGenerator<string, string, unknown> {\n const str = (value: unknown): string => typeof value === 'string' ? value : ''\n const num = (value: unknown): number | undefined => typeof value === 'number' ? value : undefined\n\n /** Forward live text deltas from a streaming chapter job (text only). */\n const forward = async function* (stream: AsyncGenerator<{ frame: 'start' } | { frame: 'delta'; text: string } | { frame: 'done'; file: string; chars: number } | { frame: 'drafted'; chars: number; draft: string }, void, unknown>): AsyncGenerator<string, void, unknown> {\n for await (const step of stream) {\n if (step.frame === 'delta') yield step.text\n }\n }\n\n switch (name) {\n case 'book_overview': {\n // 全书上下文包(分片:默认最近 30 章;scope=full 全量;scope=volume:N 指定卷)。\n const scopeArg = str(args.scope)\n const scope = scopeArg === 'full'\n ? 'full' as const\n : /^volume:(\\d+)$/.test(scopeArg)\n ? Number(scopeArg.slice(7))\n : 'recent' as const\n return bookOverview(project, scope)\n }\n case 'facts_query': {\n // 从编年录按关键词检索相关事实。\n const keyword = str(args.keyword).trim()\n if (keyword === '') throw new Error('facts_query 需要 keyword')\n const hits = (project.facts ?? []).filter(f => f.text.includes(keyword)).slice(-30)\n if (hits.length === 0) return `编年录中未找到与「${keyword}」相关的事实记录。`\n return `编年录中与「${keyword}」相关的事实(${hits.length} 条):\\n` + hits.map(f => `- [第${f.chapterNo}章] ${f.text}`).join('\\n')\n }\n case 'impact_analysis': {\n const change = str(args.change)\n if (change === '') throw new Error('impact_analysis 需要 change(要做的修改描述)')\n const items = await analyzeImpact(ctx, config, project, outputDir, change)\n if (items.length === 0) return '影响分析:未发现需要同步修改的位置。'\n const lines = items.map((it, i) => `${i + 1}. [${it.location}]「${it.quote}」${it.suggestion !== '' ? ` → ${it.suggestion}` : ''}(${it.kind === 'must' ? '必须同步' : it.kind === 'optional' ? '建议' : '备注'})`)\n return `影响分析:这次改动波及 ${items.length} 处——\\n${lines.join('\\n')}\\n请据此提示作者逐项处理;章节内的修改可引导作者在工作区查看。`\n }\n case 'outline_text': {\n return project.outline\n }\n case 'outline_replace': {\n const old = str(args.old)\n const next = str(args.new)\n if (old === '' || !project.outline.includes(old)) {\n throw new Error(`总纲中未找到片段「${old.slice(0, 40)}…」`)\n }\n project.outline = project.outline.replace(old, next)\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `总纲已修改:替换了 ${old.length} 字符的片段。`\n }\n case 'bible_set_rule': {\n if (project.bible === undefined) throw new Error('尚无道藏,请先提炼')\n const index = num(args.index)\n if (index !== undefined) {\n project.bible.worldRules[index] = str(args.text)\n } else if (str(args.append) !== '') {\n project.bible.worldRules.push(str(args.append))\n } else {\n throw new Error('bible_set_rule 需要 index+text 或 append')\n }\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `世界规则已更新(当前 ${project.bible.worldRules.length} 条)。`\n }\n case 'bible_set_redline': {\n if (project.bible === undefined) throw new Error('尚无道藏,请先提炼')\n const index = num(args.index)\n if (index !== undefined) {\n project.bible.redLines[index] = str(args.text)\n } else if (str(args.append) !== '') {\n project.bible.redLines.push(str(args.append))\n } else {\n throw new Error('bible_set_redline 需要 index+text 或 append')\n }\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `写作红线已更新(当前 ${project.bible.redLines.length} 条)。`\n }\n case 'chapter_text': {\n const no = num(args.no)\n if (no === undefined) throw new Error('chapter_text 需要 no')\n const chapter = project.chapters.find(c => c.no === no)\n if (chapter === undefined) throw new Error(`章节 ${no} 不存在`)\n const body = readChapterFile(outputDir, chapter)\n if (body === undefined) throw new Error(`章节 ${no} 尚未生成`)\n return body\n }\n case 'chapter_rewrite': {\n const no = num(args.no)\n if (no === undefined) throw new Error('chapter_rewrite 需要 no')\n const instructions = str(args.instructions)\n const target = str(args.target)\n for await (const chunk of forward(rewriteChapterStream(ctx, config, project, outputDir, no, instructions, target === '' ? undefined : target))) {\n yield chunk\n }\n // Draft mode: the assistant acts on the user's explicit instruction, so\n // apply the draft immediately — summarize/review must see the new body.\n const chapter = project.chapters.find(c => c.no === no)\n const draft = chapter?.pendingDraft\n if (chapter === undefined || draft === undefined || draft === '') {\n throw new Error(`章节 ${no} 修订后没有产出草稿`)\n }\n const fileName = chapterFileName(chapter)\n mkdirSync(outputDir, { recursive: true })\n writeFileSync(join(outputDir, fileName), `# 第${chapter.no}章 ${chapter.title}\\n\\n${draft}\\n`, 'utf8')\n chapter.pendingDraft = undefined\n chapter.status = 'written'\n chapter.chars = draft.length\n chapter.file = fileName\n chapter.review = undefined\n chapter.error = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n yield '(已采纳修订稿,正在生成章节摘要与编年录…)'\n try {\n await summarizeAndExtractFacts(ctx, config, project, outputDir, no)\n } catch { /* best-effort */ }\n yield '(正在 AI 审稿…)'\n const report = await reviewChapter(ctx, config, project, outputDir, no)\n return `章节 ${no} 已${target === '' ? '整章' : '局部'}修订完成(${project.chapters.find(c => c.no === no)?.chars ?? '?'} 字)。重新审稿:${report.score} 分 — ${report.verdict}`\n }\n case 'chapter_generate': {\n const no = num(args.no)\n if (no === undefined) throw new Error('chapter_generate 需要 no')\n for await (const chunk of forward(generateChapterStream(ctx, config, project, outputDir, no))) {\n yield chunk\n }\n yield '(正在生成章节摘要与编年录…)'\n try {\n await summarizeAndExtractFacts(ctx, config, project, outputDir, no)\n } catch { /* best-effort */ }\n yield '(正在 AI 审稿…)'\n const report = await reviewChapter(ctx, config, project, outputDir, no)\n return `章节 ${no} 已生成(${project.chapters.find(c => c.no === no)?.chars ?? '?'} 字)。审稿:${report.score} 分 — ${report.verdict}`\n }\n case 'chapter_review': {\n const no = num(args.no)\n if (no === undefined) throw new Error('chapter_review 需要 no')\n const report = await reviewChapter(ctx, config, project, outputDir, no)\n const issues = report.issues.map(i => `[${i.severity}] ${i.item} → ${i.suggestion}`).join('\\n')\n return `章节 ${no} 审稿:${report.score} 分 — ${report.verdict}\\n${issues}`\n }\n case 'foreshadow_add': {\n const description = str(args.description)\n if (description === '') throw new Error('foreshadow_add 需要 description')\n const targetChapter = num(args.targetChapter)\n project.foreshadows.push({\n id: `fs-${Date.now().toString(36)}`,\n description,\n targetChapter,\n status: 'planned',\n })\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `已新增暗线:「${description.slice(0, 50)}」`\n }\n case 'foreshadow_update': {\n const id = str(args.id)\n const status = str(args.status) as 'planned' | 'planted' | 'progressing' | 'resolved' | 'abandoned'\n const target = project.foreshadows.find(f => f.id === id)\n if (target === undefined) throw new Error(`暗线 ${id} 不存在`)\n if (!['planned', 'planted', 'progressing', 'resolved', 'abandoned'].includes(status)) {\n throw new Error(`非法状态 ${status}`)\n }\n target.status = status\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `暗线已更新为 ${status}:「${target.description.slice(0, 50)}」`\n }\n case 'export_txt': {\n const result = exportBook(outputDir, project, 'txt')\n return `已导出 TXT:${result.file}(${result.chars} 字,${result.chapters} 章)`\n }\n case 'assets_status': {\n const assets = project.assets\n if (assets === undefined) return '本书尚未配置写作资产。'\n const parts: string[] = []\n if (assets.genre !== undefined) parts.push(`题材:${assets.genre.name}`)\n if (assets.primaryProgression !== undefined) parts.push(`主推进:${assets.primaryProgression.name}`)\n if (assets.auxiliaryProgressions.length > 0) parts.push(`辅助推进:${assets.auxiliaryProgressions.map(m => m.name).join('、')}`)\n if (assets.antiAiRules.length > 0) parts.push(`自定义反AI规则:${assets.antiAiRules.map(r => r.name).join('、')}`)\n if (assets.styleAssets.length > 0) parts.push(`写法资产:${assets.styleAssets.map(s => s.name).join('、')}`)\n return parts.length > 0 ? parts.join('\\n') : '本书尚未配置写作资产。'\n }\n case 'assets_set_genre': {\n const name = str(args.name)\n const description = str(args.description)\n if (name === '') throw new Error('assets_set_genre 需要 name')\n if (project.assets === undefined) project.assets = emptyProjectAssets()\n project.assets.genre = { name, description, children: [] }\n project.assets.updatedAt = new Date().toISOString()\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `题材已设为「${name}」`\n }\n case 'assets_set_progression': {\n const name = str(args.name)\n const driver = str(args.driver)\n const primary = args.primary !== false\n if (name === '') throw new Error('assets_set_progression 需要 name')\n if (project.assets === undefined) project.assets = emptyProjectAssets()\n const mode = {\n name,\n driver: driver !== '' ? driver : name,\n readerExpectation: str(args.readerExpectation),\n payoffs: Array.isArray(args.payoffs) ? args.payoffs.filter((v): v is string => typeof v === 'string') : [],\n risks: Array.isArray(args.risks) ? args.risks.filter((v): v is string => typeof v === 'string') : [],\n primary,\n }\n if (primary) project.assets.primaryProgression = mode\n else {\n if (project.assets.auxiliaryProgressions === undefined) project.assets.auxiliaryProgressions = []\n project.assets.auxiliaryProgressions.push(mode)\n }\n project.assets.updatedAt = new Date().toISOString()\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `推进模式${primary ? '(主)' : '(辅助)'}已设置:「${name}」`\n }\n case 'assets_add_rule': {\n const name = str(args.name)\n const avoid = str(args.avoid)\n if (avoid === '') throw new Error('assets_add_rule 需要 avoid(要避免的表达问题)')\n if (project.assets === undefined) project.assets = emptyProjectAssets()\n if (project.assets.antiAiRules === undefined) project.assets.antiAiRules = []\n project.assets.antiAiRules.push({\n name: name !== '' ? name : `自定义规则 ${project.assets.antiAiRules.length + 1}`,\n avoid,\n fix: str(args.fix),\n })\n project.assets.updatedAt = new Date().toISOString()\n project.updatedAt = new Date().toISOString()\n saveProject(outputDir, project)\n return `已新增反 AI 规则「${name !== '' ? name : avoid.slice(0, 20)}」`\n }\n default:\n throw new Error(`未知工具 ${name}`)\n }\n}\n\n// ------------------------------------------------------------------- chat\n\n/** Extract the first action directive from a reply (tolerant to common tag misspellings). */\nfunction extractAction(reply: string): { name: string; args: Record<string, unknown>; index: number } | undefined {\n // 容错:dsh-action 的常见误拼(dash-action / dsah-action / dhs-action 等)。\n const match = /<([a-z_]*d[a-z]?sh?-action)\\s+name=\"([^\"]+)\"\\s*>([\\s\\S]*?)<\\/\\1>/.exec(reply)\n if (match === null) return undefined\n const rawArgs = match[3]?.trim() ?? ''\n let args: Record<string, unknown>\n try {\n args = rawArgs === '' ? {} : JSON.parse(rawArgs) as Record<string, unknown>\n } catch {\n throw new Error(`动作参数不是合法 JSON:${rawArgs.slice(0, 80)}`)\n }\n return { name: match[2] ?? '', args, index: match.index }\n}\n\n/** Render the recent history as LLM messages (skipping tool chatter in early rounds). */\nfunction historyToMessages(history: AssistantMessage[]): Message[] {\n const recent = history.slice(-MAX_HISTORY_MESSAGES)\n const messages: Message[] = []\n for (const entry of recent) {\n if (entry.role === 'user') {\n messages.push(createUserMessage({\n content: [{ type: 'text', text: entry.content }],\n source: { kind: 'plugin', plugin: 'dsh-novel-forge' },\n }))\n } else if (entry.role === 'assistant') {\n messages.push(createAssistantMessage({\n content: [{ type: 'text', text: entry.content }],\n source: { provider: 'deepseek-official', model: 'deepseek-v4-flash' },\n }))\n } else if (entry.role === 'tool') {\n // 工具结果(book_overview/总纲全文等可能很大)截断后进上下文,\n // 避免多轮对话上下文翻倍膨胀触发「上下文到限制」。\n const body = entry.content.length > 2000\n ? entry.content.slice(0, 2000) + '\\n…(结果过长已截断,需要完整内容请重新调用工具)'\n : entry.content\n messages.push(createUserMessage({\n content: [{ type: 'text', text: `【工具 ${entry.tool ?? ''} 的执行结果】\\n${body}` }],\n source: { kind: 'plugin', plugin: 'dsh-novel-forge' },\n }))\n }\n }\n return messages\n}\n\n/** One non-streaming LLM chat turn (used inside the tool loop). */\nasync function chatOnce(\n ctx: Context,\n config: NovelConfig,\n system: string,\n history: AssistantMessage[],\n): Promise<string> {\n const messages = historyToMessages(history)\n // 纪律提醒贴在最后一条消息(当前用户输入)末尾:紧邻模型要生成回复的位置,\n // 比放在 system 里更不容易被长上下文稀释(位置效应)。\n // 注意:dsh-llm 的消息/内容块对象是只读的,必须重建新对象,不能直接改属性。\n const last = messages[messages.length - 1]\n if (last?.role === 'user' && Array.isArray(last.content)) {\n const blocks = last.content as ContentBlock[]\n const idx = blocks.findIndex(b => b.type === 'text')\n if (idx !== -1) {\n const textBlock = blocks[idx] as { type: 'text'; text: string }\n const newBlocks: ContentBlock[] = blocks.map((b, i) => i === idx\n ? { ...textBlock, text: textBlock.text + '\\n\\n(回复格式提醒:如果你需要执行任何操作,你的回复必须【只包含】一个 <dsh-action name=\"工具名\">{\"参数\":值}</dsh-action> 标签,禁止先说话、禁止解释、禁止铺垫;如果你只是在回答或讨论,正常回复即可,不要输出标签。)' }\n : b)\n messages[messages.length - 1] = { ...last, content: newBlocks }\n }\n }\n const request: GenerateOptions = {\n provider: config.provider,\n model: config.model,\n messages,\n system,\n // v4-flash 推理模型:reasoning channel 占预算,给足避免回复被截断。\n maxTokens: Math.max(config.maxTokens, 16000),\n temperature: 0.7,\n }\n const assembler = new BlockAssembler()\n for await (const chunk of ctx.llm.stream(request)) {\n assembler.push(chunk)\n }\n const finish = assembler.finish\n if (finish.kind === 'error' || finish.kind === 'aborted') {\n throw new Error(`助手调用失败(${finish.kind}): ${finish.failure.message}`)\n }\n const blocks = assembler.blocks()\n const textBlocks = blocks\n .filter((block): block is Extract<StreamChunk, { type: 'block-end' }>['block'] & { type: 'text' } => block.type === 'text')\n .map(block => block.text)\n let text = textBlocks.join('\\n').trim()\n if (text === '') {\n const reasoning = blocks\n .filter((block): block is { type: 'reasoning'; text: string } => block.type === 'reasoning')\n .map(block => block.text)\n .join('\\n')\n .trim()\n if (reasoning !== '') text = reasoning\n }\n return text\n}\n\n/** Run one user turn. Yields stream frames; persists history. */\nexport async function* runAssistantTurn(\n ctx: Context,\n config: NovelConfig,\n project: ProjectState,\n outputDir: string,\n userMessage: string,\n): AsyncGenerator<\n | { frame: 'delta'; text: string }\n | { frame: 'tool'; name: string; status: 'start' | 'done' | 'error'; detail?: string }\n | { frame: 'toolDelta'; name: string; text: string },\n void,\n unknown\n> {\n const history = loadAssistantHistory(outputDir)\n const system = assistantSystemPrompt(project)\n\n // Persist the user message.\n const userEntry: AssistantMessage = { role: 'user', content: userMessage, ts: new Date().toISOString() }\n history.push(userEntry)\n appendHistory(outputDir, userEntry)\n\n let round = 0\n /** 已提示模型输出动作标签的次数(0 = 尚未提示;超过上限则按纯文字回复结束,防死循环)。 */\n let nudged = 0\n const MAX_NUDGES = 6\n /** 连续收到 hex 乱码回复的次数(≥2 次判定 LLM 侧异常,放弃本轮避免死循环)。 */\n let garbleCount = 0\n\n // ---- 写操作意图守卫 ------------------------------------------------\n // 写类工具会改动项目数据/正文文件:仅当用户消息(含最近一轮上下文)里\n // 出现与该工具对应的明确修改动词时才放行;否则拒绝执行,防止\"随口一问\"\n // 被模型误判成创作指令(如问角色是否登场 → 自主生成整章)。\n const WRITE_TOOL_KEYS: Record<string, RegExp> = {\n chapter_generate: /(生成|写第\\s*\\d+\\s*章|写一[章篇]|新写|续写|接着写|继续写|开始写|写正文|写书|创作)/,\n chapter_rewrite: /(重写|改写|修订|修改|改一下|调整|替换|润色|优化|修正|完善|回炉|换一种|从头)/,\n chapter_review: /(审|检查|校验|点评|评估|把关|质量|怎么样|如何)/,\n outline_replace: /(大纲|总纲|简介)/,\n bible_set_rule: /(道藏|设定|规则|红线|世界|金手指)/,\n bible_set_redline: /(道藏|设定|红线)/,\n foreshadow_add: /(暗线|伏笔|埋)/,\n foreshadow_update: /(暗线|伏笔)/,\n export_txt: /(导出|打包|下载|txt)/,\n assets_set_genre: /(题材)/,\n assets_set_progression: /(推进)/,\n assets_add_rule: /(规则|文戒|反AI)/,\n }\n /** 本轮已放行过写操作:后续写操作(生成→审稿→修订闭环)不再逐个拦截。 */\n let writeUnlocked = false\n const guardWrite = (name: string, userMessage: string): boolean => {\n if (writeUnlocked) return true\n const key = WRITE_TOOL_KEYS[name]\n if (key === undefined) return true // 只读工具 / 未登记工具一律放行\n // 近两轮用户消息合并判断(支持\"继续\"类延续指令)。\n const recentUsers = history\n .filter(m => m.role === 'user')\n .slice(-2)\n .map(m => m.content)\n .join('\\n')\n if (key.test(recentUsers)) {\n writeUnlocked = true\n return true\n }\n return false\n }\n for (;;) {\n if (round++ > 20) break\n const reply = await chatOnce(ctx, config, system, history)\n\n // 异常输出防护:全 hex/二进制乱码(模型偶发把回复编码成十六进制)——丢弃重试一次。\n const hexLike = reply.length > 120 && /^[0-9a-fA-F\\s]+$/.test(reply.slice(0, 2000))\n if (hexLike) {\n garbleCount++\n if (garbleCount >= 2) {\n const garbleEntry: AssistantMessage = { role: 'assistant', content: '(模型本次返回了异常编码内容,已忽略;请重新描述你的问题。)', ts: new Date().toISOString() }\n history.push(garbleEntry)\n appendHistory(outputDir, garbleEntry)\n yield { frame: 'delta', text: garbleEntry.content }\n return\n }\n continue\n }\n\n const action = extractAction(reply)\n\n if (action === undefined) {\n // No parseable action tag. If the reply clearly intends to modify\n // something (or contains a malformed action tag), nudge — repeatedly,\n // with escalating firmness, until the model emits a tag or gives up.\n const intendsAction = /(改|修改|修订|重写|替换|调整|生成|新增|删除|导出|看看|查看|调出|读一下|加上|加一个|去掉|删掉|把.+改成|定位|处理|转轨|检查|确认|搜索|找一下|列一下|查一下|查一遍|查一查|再查|查查|核实|核对|清点|盘点|看一下|看下|继续)/.test(reply)\n // 兜底:回复提到任何可操作对象名词(即使动词是\"看/查/说\"的变体)也视为有操作意图,\n // 避免\"先查一遍编年录\"这类措辞漏网被静默当作纯聊天。\n const mentionsTarget = /(编年录|道藏|暗线|总纲|卷首语|章节|正文|规则|红线|伏笔|简介|大纲|事实|设定|世界|角色|人物|第\\s*\\d+\\s*章)/.test(reply)\n const strayTag = /<[a-z_-]*action[^>]*>/.test(reply)\n if ((intendsAction || mentionsTarget || strayTag) && nudged < MAX_NUDGES) {\n // 用户消息本身没有写意图时,引导模型直接文字回答(不要被逼出写操作标签)。\n const userWriteIntent = Object.values(WRITE_TOOL_KEYS).some(re => re.test(userMessage))\n const nudge = nudged === 0\n ? (userWriteIntent\n ? '你的上一条回复表达了想操作项目的意图(或动作标签格式有误),因此没有执行任何操作。请直接输出动作标签来执行,格式必须为 <dsh-action name=\"工具名\">{\"参数\":值}</dsh-action>(注意拼写是 dsh-action,不是 dash-action;标签成对出现,参数为合法 JSON)。如果需要先看内容,先输出 outline_text 或 chapter_text 标签。'\n : '你刚才的回复看起来在讨论项目内容,但没有必要执行任何操作。如果用户只是在提问或闲聊,请直接以文字回答即可,不要输出动作标签,也不要自行调用任何写操作(生成/修订/删除等只有用户明确要求时才允许)。若确实需要先查看数据,最多使用只读工具(outline_text / chapter_text / book_overview / facts_query)。')\n : (userWriteIntent\n ? `你第 ${nudged + 1} 次表达了操作意图但没有输出动作标签,因此仍未执行任何操作。铁律:你的【整个回复】现在必须只包含一个 <dsh-action> 标签(例如 <dsh-action name=\"chapter_text\">{\"no\":1}</dsh-action>),禁止任何解释、铺垫或\"我这就去\"之类的文字。若你其实不打算执行任何操作,请明确回复「不执行」。`\n : `你第 ${nudged + 1} 次回复仍不需要执行操作。再次强调:用户没有要求修改,请直接给出文字回答(可以简短引用项目数据),不要输出动作标签。写操作只会在用户明确要求时被允许。`)\n nudged++\n history.push({ role: 'tool', content: nudge, tool: 'format-hint', ts: new Date().toISOString() })\n appendHistory(outputDir, { role: 'tool', content: nudge, tool: 'format-hint', ts: new Date().toISOString() })\n continue\n }\n // Plain prose reply — done.\n const assistantEntry: AssistantMessage = { role: 'assistant', content: reply, ts: new Date().toISOString() }\n history.push(assistantEntry)\n appendHistory(outputDir, assistantEntry)\n // Stream the prose (without any stray action markup).\n yield { frame: 'delta', text: reply }\n return\n }\n\n // Execute the action, then feed the result back and continue.\n const { name, args, index } = action\n const prose = reply.slice(0, index).trim()\n // 写操作意图守卫:用户没明确要求修改时,拒绝执行并提示(不写盘、不消耗生成额度)。\n if (!guardWrite(name, userMessage)) {\n const denied = `【操作被拒绝】${name} 是写操作(会修改正文/项目数据),但你当前的消息里没有明确要求执行该修改。如果需要,请明确说明(如「生成第 120 章」「把第 105 章结尾改一下」)。我不会擅自修改你的作品。`\n history.push({ role: 'tool', content: denied, tool: name, ts: new Date().toISOString() })\n appendHistory(outputDir, { role: 'tool', content: denied, tool: name, ts: new Date().toISOString() })\n yield { frame: 'tool', name, status: 'error', detail: denied }\n // 拒绝后结束本轮:等作者重新明确指令。\n const assistantEntry: AssistantMessage = { role: 'assistant', content: denied, ts: new Date().toISOString() }\n history.push(assistantEntry)\n appendHistory(outputDir, assistantEntry)\n yield { frame: 'delta', text: denied }\n return\n }\n yield { frame: 'tool', name, status: 'start' }\n let result: string\n try {\n // executeAction is an async generator: it yields live progress text\n // (chapter text being generated) and returns the final result string.\n // Iterate manually so we see both the yielded deltas and the return.\n const iterator = executeAction(ctx, config, project, outputDir, name, args)[Symbol.asyncIterator]()\n result = ''\n for (;;) {\n const step = await iterator.next()\n if (step.done === true) {\n result = typeof step.value === 'string' ? step.value : ''\n break\n }\n const chunk = step.value\n if (typeof chunk === 'string' && chunk !== '') {\n yield { frame: 'toolDelta', name, text: chunk }\n }\n }\n yield { frame: 'tool', name, status: 'done', detail: result.slice(0, 200) }\n } catch (error) {\n result = `执行失败:${(error as Error).message}`\n yield { frame: 'tool', name, status: 'error', detail: (error as Error).message }\n }\n\n // Persist assistant prose + tool result as history entries.\n if (prose !== '') {\n history.push({ role: 'assistant', content: prose, ts: new Date().toISOString() })\n appendHistory(outputDir, { role: 'assistant', content: prose, ts: new Date().toISOString() })\n }\n history.push({ role: 'tool', content: result, tool: name, ts: new Date().toISOString() })\n appendHistory(outputDir, { role: 'tool', content: result, tool: name, ts: new Date().toISOString() })\n\n round++\n if (round >= MAX_TOOL_ROUNDS) {\n const message = `(已连续执行 ${round} 次修改操作,本轮停止。如需继续请再说。)`\n history.push({ role: 'assistant', content: message, ts: new Date().toISOString() })\n appendHistory(outputDir, { role: 'assistant', content: message, ts: new Date().toISOString() })\n yield { frame: 'delta', text: message }\n return\n }\n }\n}\n\nexport { chapterFileName }\n","/**\n * The /api/dsh-novel-forge route family: status, docx outline loading, LLM\n * story-bible extraction, volume planning, chapter planning, streaming\n * generation / rewrite / polish (NDJSON frames), review, summaries,\n * foreshadows, export, chapter reading, config patching, and opening the\n * output folder. Every route carries the same loopback-only trust fence as\n * the family plugins — these endpoints invoke the LLM and write files on the\n * host machine.\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport { exec } from 'node:child_process'\nimport { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { WebRoute } from '@deepseek-ai/dsh-host-webserver'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { ProductionRunner } from './run.ts'\nimport {\n NOVEL_API,\n type AssetsPatch,\n type AssetsResponse,\n type AssistantFrame,\n type AssistantHistoryResponse,\n type AssistantRequest,\n type AuditResponse,\n type AuditStatus,\n type AuthorReview,\n type BiblePatchRequest,\n type BibleRequest,\n type BlurbRequest,\n type CoverRequest,\n type CoverResponse,\n type RenameRequest,\n type WorldRequest,\n type BibleResponse,\n type BookActivateRequest,\n type BookCreateRequest,\n type BookRemoveRequest,\n type BookshelfSnapshot,\n type ChapterResponse,\n type ChapterPlan,\n type ChapterSaveResponse,\n type ChapterTextRequest,\n type ConfigPatch,\n type DraftDecisionRequest,\n type ExportRequest,\n type ExportResponse,\n type ForeshadowRequest,\n type ForeshadowResponse,\n type JobFrame,\n type LoadOutlineRequest,\n type LoadOutlineResponse,\n type NovelConfig,\n type PlotlinesRequest,\n type PlotlinesResponse,\n type PlanRequest,\n type PlanResponse,\n type PolishRequest,\n type ResetRequest,\n type ReviewReport,\n type ReviewRequest,\n type RunControlRequest,\n type RunStartRequest,\n type RunState,\n type RewriteRequest,\n type RolesRequest,\n type RolesResponse,\n type SceneCard,\n type ScenesRequest,\n type ScenesResponse,\n type VisualRulesRequest,\n type VisualRulesResponse,\n type OutlineSuggestRequest,\n type OutlineSuggestResponse,\n type BreakdownRequest,\n type BreakdownResponse,\n type SensitiveCheckRequest,\n type SensitiveCheckResponse,\n type SensitiveHit,\n type StatusResponse,\n type StoryBible,\n type StyleEngineRequest,\n type SummaryRequest,\n type VolumesRequest,\n type VolumesResponse,\n} from './protocol.ts'\nimport { readOutlineFromDocx } from './docx.ts'\nimport { clearAssistantHistory, loadAssistantHistory, runAssistantTurn } from './assistant.ts'\nimport { activateBook, bookshelfSnapshot, createBook, defaultOutputDirFor, loadBookshelf, removeBook, renameBook, seedBookshelfFromOutputDir } from './bookshelf.ts'\nimport { BUILTIN_ANTI_AI_RULES, BUILTIN_GENRE_LIBRARY, BUILTIN_PROGRESSION_MODES, BUILTIN_STYLE_TEMPLATES, emptyProjectAssets } from './assets.ts'\nimport {\n chapterFileName,\n auditBook,\n authorReviewChapter,\n autoLinkPlotlines,\n backfillFacts,\n createProject,\n exportBook,\n extractBible,\n extractStyleAsset,\n extractWorld,\n generateBlurb,\n generateChapterStream,\n listChapterFiles,\n loadProject,\n markForeshadowPlanted,\n mergeVolatileFromDisk,\n planChapters,\n planVolumes,\n polishChapterStream,\n readChapterFile,\n refreshCharacters,\n refreshPlotlineProgress,\n reviewChapter,\n reviewChapterText,\n rewriteChapterStream,\n saveProject,\n analyzePlotlineHealth,\n designPlotlinePlan,\n extractRoles,\n extractScenes,\n generateRolePromptKit,\n extractVisualRules,\n extractRoleVisual,\n suggestOutlines,\n breakdownBook,\n generateRoleReferenceImage,\n checkSensitiveText,\n suggestForeshadows,\n suggestPlotlines,\n summarizeAndExtractFacts,\n summarizeChapter,\n syncProjectWithDisk,\n} from './engine.ts'\n\n/** Cap on JSON request bodies (generous: cover images travel as base64). */\nconst MAX_JSON_BODY_BYTES = 16 * 1024 * 1024\n\n/** Loopback-only fence (mirrors the family plugins' pairing routes). */\nfunction isLoopbackRequest(request: IncomingMessage): boolean {\n const address = request.socket.remoteAddress\n if (address !== '127.0.0.1' && address !== '::1' && address !== '::ffff:127.0.0.1') return false\n const host = request.headers.host\n if (typeof host !== 'string') return false\n let hostUrl: URL\n try {\n hostUrl = new URL(`http://${host}`)\n } catch {\n return false\n }\n if (hostUrl.hostname !== '127.0.0.1' && hostUrl.hostname !== 'localhost' && hostUrl.hostname !== '[::1]') return false\n if (request.headers['sec-fetch-site'] === 'cross-site') return false\n const origin = request.headers.origin\n if (origin === undefined) return true\n try {\n return new URL(origin).host === hostUrl.host\n } catch {\n return false\n }\n}\n\n/** One JSON response. */\nfunction writeJson(res: ServerResponse, status: number, body: unknown): void {\n const payload = JSON.stringify(body)\n res.writeHead(status, { 'content-type': 'application/json; charset=utf-8', 'referrer-policy': 'no-referrer' })\n res.end(payload)\n}\n\n/** Read a JSON request body. */\nasync function readJsonBody<T>(req: IncomingMessage): Promise<T | undefined> {\n const chunks: Buffer[] = []\n let size = 0\n for await (const chunk of req) {\n const buffer = chunk as Buffer\n size += buffer.length\n if (size > MAX_JSON_BODY_BYTES) return undefined\n chunks.push(buffer)\n }\n try {\n return JSON.parse(Buffer.concat(chunks).toString('utf8')) as T\n } catch {\n return undefined\n }\n}\n\n/** Route deps. */\nexport interface NovelRoutesDeps {\n ctx: Context\n /** Resolve the live plugin config (settings-aware). */\n getConfig: () => NovelConfig\n /** Persist a config patch through the settings seam. */\n patchConfig: (patch: ConfigPatch) => Promise<NovelConfig>\n}\n\n/** Default chapter count for planning when the request omits it. */\nconst DEFAULT_PLAN_COUNT = 30\n\n/**\n * Build every /api/dsh-novel-forge route.\n * @param deps - context, config resolver, config patcher.\n * @returns the route list.\n */\nexport function makeRoutes(deps: NovelRoutesDeps): WebRoute[] {\n const { ctx, getConfig, patchConfig } = deps\n\n /** 全书质检实时状态(内存态,重启后回到 idle;用于 /status 暴露进度)。 */\n let auditState: AuditStatus = { status: 'idle', totalBatches: 0, completedBatches: 0 }\n\n /** Guard helper: fence + method check. */\n const guard = (req: IncomingMessage, res: ServerResponse, method: string): boolean => {\n if (!isLoopbackRequest(req)) {\n writeJson(res, 403, { error: 'forbidden: loopback-only' })\n return false\n }\n if (req.method !== method) {\n writeJson(res, 405, { error: `method not allowed (expected ${method})` })\n return false\n }\n return true\n }\n\n /** Load (and sync) the project, or respond 400. */\n const requireProject = (res: ServerResponse): ReturnType<typeof loadProject> => {\n const config = getConfig()\n const project = loadProject(config.outputDir)\n if (project === undefined) {\n writeJson(res, 400, { error: '输出目录中没有项目,请先加载大纲' })\n return undefined\n }\n syncProjectWithDisk(project, config.outputDir)\n saveProject(config.outputDir, project)\n return project\n }\n\n // -------------------------------------------------------------- status\n const statusRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.status,\n handler: (req, res) => {\n if (!guard(req, res, 'GET')) return\n const config = getConfig()\n // 书架为空时播种 settings 默认输出目录里的已有项目。\n seedBookshelfFromOutputDir(config.outputDir)\n const project = loadProject(config.outputDir)\n if (project !== undefined) {\n // 自动兜底:generating 超过 10 分钟(正常一章 2-5 分钟)视为卡死/中断,\n // 复位为 pending,避免\"生成中\"状态卡死无法重新生成。\n const staleMs = 10 * 60 * 1000\n for (const c of project.chapters) {\n if (c.status === 'generating' && c.generatingAt !== undefined) {\n const started = new Date(c.generatingAt).getTime()\n if (Number.isFinite(started) && Date.now() - started > staleMs) {\n c.status = 'pending'\n c.error = undefined\n c.generatingAt = undefined\n }\n }\n }\n syncProjectWithDisk(project, config.outputDir)\n saveProject(config.outputDir, project)\n }\n const response: StatusResponse = {\n config,\n // 瘦身:facts 只回最近 80 条(客户端最多展示 60),避免长篇后\n // status 响应体随编年录无限膨胀。\n project: project !== undefined\n ? { ...project, facts: (project.facts ?? []).slice(-80) }\n : undefined,\n generatedFiles: listChapterFiles(config.outputDir),\n audit: auditState,\n }\n writeJson(res, 200, response)\n },\n }\n\n // -------------------------------------------------------- load-outline\n const loadOutlineRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.loadOutline,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<LoadOutlineRequest>(req)\n const config = getConfig()\n try {\n let outline: string\n let path: string | undefined\n if (body?.text !== undefined && body.text.trim() !== '') {\n outline = body.text.trim()\n } else {\n const target = body?.path?.trim() !== '' && body?.path !== undefined ? body.path : config.outlinePath\n outline = readOutlineFromDocx(target)\n path = target\n }\n if (outline.length < 50) {\n writeJson(res, 400, { error: '大纲内容过短(<50 字符),请检查文件或直接粘贴大纲文本' })\n return\n }\n const response: LoadOutlineResponse = {\n outline,\n bookName: createProject(outline).bookName,\n chars: outline.length,\n path,\n }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 400, { error: (error as Error).message })\n }\n },\n }\n\n // -------------------------------------------------------- save-outline\n const saveOutlineRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.saveOutline,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<LoadOutlineRequest>(req)\n const config = getConfig()\n const outline = body?.text ?? ''\n if (outline.trim().length < 50) {\n writeJson(res, 400, { error: '大纲内容过短(<50 字符)' })\n return\n }\n let project = loadProject(config.outputDir)\n const now = new Date().toISOString()\n if (project === undefined) {\n project = createProject(outline)\n } else {\n project.outline = outline\n project.bookName = createProject(outline).bookName\n project.updatedAt = now\n }\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, bookName: project.bookName })\n },\n }\n\n // --------------------------------------------------------------- bible\n const bibleRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.bible,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<BibleRequest>(req)\n const config = getConfig()\n const project = loadProject(config.outputDir)\n const outline = body?.outline?.trim() !== '' && body?.outline !== undefined\n ? body.outline\n : project?.outline\n if (outline === undefined || outline.length < 50) {\n writeJson(res, 400, { error: '请先加载大纲' })\n return\n }\n try {\n const bible = await extractBible(ctx, config, outline, project)\n const now = new Date().toISOString()\n const next = project ?? createProject(outline)\n next.bible = bible\n next.updatedAt = now\n saveProject(config.outputDir, next)\n const response: BibleResponse = { bible }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ------------------------------------------------------------- volumes\n const volumesRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.volumes,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<VolumesRequest>(req)\n const config = getConfig()\n const project = loadProject(config.outputDir)\n const outline = body?.outline?.trim() !== '' && body?.outline !== undefined\n ? body.outline\n : project?.outline\n if (outline === undefined || outline.length < 50) {\n writeJson(res, 400, { error: '请先加载大纲' })\n return\n }\n try {\n const volumes = await planVolumes(ctx, config, outline)\n const now = new Date().toISOString()\n const next = project ?? createProject(outline)\n next.volumes = volumes\n next.updatedAt = now\n saveProject(config.outputDir, next)\n const response: VolumesResponse = { volumes }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ----------------------------------------------------------------- plan\n const planRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.plan,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<PlanRequest>(req)\n const config = getConfig()\n const project = loadProject(config.outputDir)\n const outline = body?.outline?.trim() !== '' && body?.outline !== undefined\n ? body.outline\n : project?.outline\n if (outline === undefined || outline.length < 50) {\n writeJson(res, 400, { error: '请先加载大纲(或粘贴大纲文本)' })\n return\n }\n const count = body?.chapterCount ?? DEFAULT_PLAN_COUNT\n if (!Number.isInteger(count) || count < 1 || count > 200) {\n writeJson(res, 400, { error: 'chapterCount 须为 1-200 的整数' })\n return\n }\n try {\n const next = project ?? createProject(outline)\n const chapters: ChapterPlan[] = await planChapters(ctx, config, next, count, body?.volume, config.outputDir)\n // 并发保护:长 LLM 调用期间磁盘可能已被其他请求更新(角色库/剧情线等),\n // 保存前合并磁盘最新易变字段,避免旧快照覆盖新修改。\n mergeVolatileFromDisk(config.outputDir, next)\n next.chapters.push(...chapters)\n next.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, next)\n const response: PlanResponse = { chapters, volumes: next.volumes }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ------------------------------------------------------------- generate\n const generateRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.generate,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<{ chapterNo?: number; skipReview?: boolean }>(req)\n const rawNo = body?.chapterNo\n if (!Number.isInteger(rawNo) || rawNo === undefined || rawNo < 1) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const no: number = rawNo\n const chapter = project.chapters.find(c => c.no === no)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${no} 不在计划中` })\n return\n }\n if (chapter.status === 'generating') {\n writeJson(res, 409, { error: `章节 ${no} 正在生成中` })\n return\n }\n\n // NDJSON stream.\n res.writeHead(200, {\n 'content-type': 'application/x-ndjson; charset=utf-8',\n 'cache-control': 'no-cache',\n 'x-accel-buffering': 'no',\n 'referrer-policy': 'no-referrer',\n })\n chapter.status = 'generating'\n chapter.error = undefined\n chapter.generatingAt = new Date().toISOString()\n // 并发保护:合并磁盘最新易变字段后保存,避免本请求覆盖并发修改(角色库/剧情线等)。\n mergeVolatileFromDisk(config.outputDir, project)\n saveProject(config.outputDir, project)\n\n const send = (frame: JobFrame): void => {\n res.write(JSON.stringify(frame) + '\\n')\n }\n\n try {\n send({ type: 'start', no, title: chapter.title })\n for await (const step of generateChapterStream(ctx, config, project, config.outputDir, no)) {\n if (step.frame === 'delta') {\n send({ type: 'delta', text: step.text })\n } else if (step.frame === 'done') {\n send({ type: 'done', no, file: step.file, chars: step.chars, title: chapter.title })\n }\n }\n // Auto pipeline: summary + facts(一次调用)-> review(unless skipped)。\n try {\n await summarizeAndExtractFacts(ctx, config, project, config.outputDir, no)\n } catch (error) {\n console.warn('[dsh-novel-forge] summary/facts failed:', (error as Error).message)\n }\n // 伏笔落地标记:正文中命中 planned 伏笔关键词 → 自动标为 planted(暗线管理页与正文同步)。\n try {\n const marked = markForeshadowPlanted(project, config.outputDir, no)\n if (marked > 0) {\n console.log(`[dsh-novel-forge] 第${no}章已埋伏笔 ${marked} 条`)\n }\n } catch (error) {\n console.warn('[dsh-novel-forge] markForeshadowPlanted failed:', (error as Error).message)\n }\n if (!(body?.skipReview === true) && (config.autoReview ?? true)) {\n const report = await reviewChapter(ctx, config, project, config.outputDir, no)\n send({ type: 'review', no, report })\n } else {\n chapter.status = 'approved'\n mergeVolatileFromDisk(config.outputDir, project)\n saveProject(config.outputDir, project)\n }\n // 作者复盘:叙事结构检查(钩子兑现/结尾钩子/推进/连续性/趋势;不改变章节状态)。\n if (config.autoAuthorReview ?? true) {\n try {\n const currentBody = readChapterFile(config.outputDir, chapter)\n let prevTail = ''\n if (no > 1) {\n const prev = project.chapters.find(c => c.no === no - 1)\n if (prev !== undefined) {\n prevTail = (readChapterFile(config.outputDir, prev) ?? '').replace(/^#.*$/m, '').trim().slice(-600)\n }\n }\n if (currentBody !== undefined) {\n const review = await authorReviewChapter(ctx, config, project, no, currentBody, prevTail)\n chapter.authorReview = review\n // 复盘标记推进的剧情线 → 自动关联本章。\n if (review.advancedLines !== undefined) {\n autoLinkPlotlines(project, no, review.advancedLines)\n }\n mergeVolatileFromDisk(config.outputDir, project)\n saveProject(config.outputDir, project)\n send({ type: 'author-review', no, review })\n }\n } catch (error) {\n console.warn('[dsh-novel-forge] author review failed:', (error as Error).message)\n }\n }\n res.end()\n } catch (error) {\n chapter.status = 'error'\n chapter.error = (error as Error).message\n mergeVolatileFromDisk(config.outputDir, project)\n saveProject(config.outputDir, project)\n if (!res.writableEnded) {\n send({ type: 'error', no, message: (error as Error).message })\n res.end()\n }\n }\n },\n }\n\n // --------------------------------------------------------------- review\n const reviewRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.review,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<ReviewRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const no = body!.chapterNo!\n try {\n const report = await reviewChapter(ctx, config, project, config.outputDir, no)\n writeJson(res, 200, { report })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // -------------------------------------------------------------- rewrite\n const rewriteRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.rewrite,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<RewriteRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const no = body!.chapterNo!\n res.writeHead(200, {\n 'content-type': 'application/x-ndjson; charset=utf-8',\n 'cache-control': 'no-cache',\n 'x-accel-buffering': 'no',\n 'referrer-policy': 'no-referrer',\n })\n const send = (frame: JobFrame): void => { res.write(JSON.stringify(frame) + '\\n') }\n try {\n for await (const step of rewriteChapterStream(ctx, config, project, config.outputDir, no, body?.instructions ?? '', body?.target)) {\n if (step.frame === 'delta') send({ type: 'delta', text: step.text })\n else if (step.frame === 'drafted') send({ type: 'drafted', no, chars: step.chars, draft: step.draft })\n }\n // Draft mode: no auto re-review — the user reviews the diff and\n // decides; re-run review after applying if wanted.\n res.end()\n } catch (error) {\n if (!res.writableEnded) {\n send({ type: 'error', no, message: (error as Error).message })\n res.end()\n }\n }\n },\n }\n\n // --------------------------------------------------------------- polish\n const polishRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.polish,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<PolishRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const no = body!.chapterNo!\n res.writeHead(200, {\n 'content-type': 'application/x-ndjson; charset=utf-8',\n 'cache-control': 'no-cache',\n 'x-accel-buffering': 'no',\n 'referrer-policy': 'no-referrer',\n })\n const send = (frame: JobFrame): void => { res.write(JSON.stringify(frame) + '\\n') }\n try {\n for await (const step of polishChapterStream(ctx, config, project, config.outputDir, no)) {\n if (step.frame === 'delta') send({ type: 'delta', text: step.text })\n else if (step.frame === 'drafted') send({ type: 'drafted', no, chars: step.chars, draft: step.draft })\n }\n res.end()\n } catch (error) {\n if (!res.writableEnded) {\n send({ type: 'error', no, message: (error as Error).message })\n res.end()\n }\n }\n },\n }\n\n // ---------------------------------------------------- draft apply/discard\n /** 采纳待确认草稿:覆盖正文文件 + 状态回 written + 清空草稿。 */\n const draftApplyRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.draftApply,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<DraftDecisionRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const chapter = project.chapters.find(c => c.no === body!.chapterNo!)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${body!.chapterNo} 不在计划中` })\n return\n }\n if (chapter.pendingDraft === undefined || chapter.pendingDraft === '') {\n writeJson(res, 400, { error: `章节 ${chapter.no} 没有待确认的草稿` })\n return\n }\n const draft = chapter.pendingDraft\n const fileName = chapterFileName(chapter)\n mkdirSync(config.outputDir, { recursive: true })\n const targetPath = join(config.outputDir, fileName)\n // 采纳前自动备份当前原稿为 .bak.md(每次应用都刷新为最新原稿),可随时回退。\n if (existsSync(targetPath)) {\n copyFileSync(targetPath, join(config.outputDir, `${fileName.replace(/\\.md$/, '')}.bak.md`))\n }\n writeFileSync(targetPath, `# 第${chapter.no}章 ${chapter.title}\\n\\n${draft}\\n`, 'utf8')\n chapter.pendingDraft = undefined\n chapter.chars = draft.length\n chapter.file = fileName\n // 携带审查报告则沿用结论定状态(修订后审查通过 → approved);否则置 written 待审。\n const carried = body?.report\n if (carried !== undefined && typeof carried.score === 'number') {\n chapter.review = carried\n chapter.status = carried.passed ? 'approved' : 'rejected'\n } else {\n chapter.status = 'written'\n chapter.review = undefined\n }\n chapter.error = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, chars: draft.length, file: fileName, markdown: draft })\n },\n }\n\n /** 放弃待确认草稿:保留原稿,仅清空草稿字段。 */\n const draftDiscardRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.draftDiscard,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<DraftDecisionRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const chapter = project.chapters.find(c => c.no === body!.chapterNo!)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${body!.chapterNo} 不在计划中` })\n return\n }\n if (chapter.pendingDraft !== undefined) {\n chapter.pendingDraft = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n }\n writeJson(res, 200, { ok: true })\n },\n }\n\n // -------------------------------------------------------------- summary\n const summaryRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.summary,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<SummaryRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n try {\n const summary = await summarizeChapter(ctx, config, project, config.outputDir, body!.chapterNo!)\n writeJson(res, 200, { summary })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ---------------------------------------------------------- foreshadow\n const foreshadowRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.foreshadow,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<ForeshadowRequest>(req)\n try {\n if (body?.suggest === true) {\n // AI suggestion pass: create several foreshadows from the outline.\n const created = await suggestForeshadows(ctx, config, project)\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n const response: ForeshadowResponse = { foreshadows: created }\n writeJson(res, 200, response)\n return\n }\n if (body?.id !== undefined) {\n // Update an existing foreshadow.\n const target = project.foreshadows.find(f => f.id === body.id)\n if (target === undefined) {\n writeJson(res, 404, { error: `伏笔 ${body.id} 不存在` })\n return\n }\n if (body.description !== undefined) target.description = body.description\n if (body.plantedChapter !== undefined) target.plantedChapter = body.plantedChapter\n if (body.targetChapter !== undefined) target.targetChapter = body.targetChapter\n if (body.status !== undefined) target.status = body.status\n if (body.resolvedNote !== undefined) target.resolvedNote = body.resolvedNote\n } else {\n // Create one manually.\n const description = body?.description?.trim()\n if (description === undefined || description === '') {\n writeJson(res, 400, { error: 'description 必填' })\n return\n }\n project.foreshadows.push({\n id: `fs-${Date.now().toString(36)}`,\n description,\n plantedChapter: body?.plantedChapter,\n targetChapter: body?.targetChapter,\n status: body?.status ?? 'planned',\n })\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n const response: ForeshadowResponse = { foreshadows: project.foreshadows }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // -------------------------------------------------------------- export\n const exportRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.exportBook,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<ExportRequest>(req)\n const format = body?.format === 'md' ? 'md' : 'txt'\n try {\n const result = exportBook(config.outputDir, project, format)\n const response: ExportResponse = { ...result }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // -------------------------------------------------------------- chapter\n const chapterRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.chapter,\n handler: async (req, res) => {\n if (!guard(req, res, 'GET')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const url = new URL(req.url ?? '/', 'http://localhost')\n const rawNo = Number(url.searchParams.get('no') ?? '0')\n if (!Number.isInteger(rawNo) || rawNo < 1) {\n writeJson(res, 400, { error: 'no 须为正整数' })\n return\n }\n const chapter = project.chapters.find(c => c.no === rawNo)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${rawNo} 不在计划中` })\n return\n }\n const markdown = readChapterFile(config.outputDir, chapter)\n if (markdown === undefined) {\n writeJson(res, 404, { error: `章节 ${rawNo} 尚未生成` })\n return\n }\n const response: ChapterResponse = { no: chapter.no, title: chapter.title, markdown }\n writeJson(res, 200, response)\n },\n }\n\n // ------------------------------------------------------ chapter check/save\n /** 审查手动编辑的正文(不落盘,返回审稿报告)。 */\n const chapterCheckRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.chapterCheck,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<ChapterTextRequest>(req)\n const text = body?.text?.trim() ?? ''\n if (text.length < 50) {\n writeJson(res, 400, { error: '正文过短(<50 字),请先编辑内容' })\n return\n }\n try {\n // 携带上一轮报告 → 验证模式(逐条核对原意见解决情况 + 只挑新增 high)。\n const report = await reviewChapterText(ctx, config, project, text, body?.previousReport)\n writeJson(res, 200, { report })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n /** 保存手动编辑的正文(自动备份 .bak,状态回 written)。 */\n const chapterSaveRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.chapterSave,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<ChapterTextRequest>(req)\n if (!Number.isInteger(body?.chapterNo)) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const chapter = project.chapters.find(c => c.no === body!.chapterNo!)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${body!.chapterNo} 不在计划中` })\n return\n }\n const text = body?.text?.trim() ?? ''\n if (text.length < 50) {\n writeJson(res, 400, { error: '正文过短(<50 字),未保存' })\n return\n }\n const fileName = chapterFileName(chapter)\n mkdirSync(config.outputDir, { recursive: true })\n const targetPath = join(config.outputDir, fileName)\n if (existsSync(targetPath)) {\n copyFileSync(targetPath, join(config.outputDir, `${fileName.replace(/\\.md$/, '')}.bak.md`))\n }\n writeFileSync(targetPath, `# 第${chapter.no}章 ${chapter.title}\\n\\n${text}\\n`, 'utf8')\n chapter.status = 'written'\n chapter.chars = text.length\n chapter.file = fileName\n chapter.pendingDraft = undefined\n // 保存即审稿:携带工作区审查报告则沿用(不重复审);否则自动正式审稿一次。\n let report: ReviewReport | undefined\n const carried = body?.report\n if (carried !== undefined && typeof carried.score === 'number') {\n report = carried\n chapter.review = report\n chapter.status = report.passed ? 'approved' : 'rejected'\n } else {\n report = await reviewChapter(ctx, config, project, config.outputDir, chapter.no)\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n const response: ChapterSaveResponse = { ok: true, chars: text.length, file: fileName, report }\n writeJson(res, 200, response)\n },\n }\n\n // ----------------------------------------------------------- assistant\n const assistantRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.assistant,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<AssistantRequest>(req)\n const message = body?.message?.trim()\n if (message === undefined || message === '') {\n writeJson(res, 400, { error: '消息不能为空' })\n return\n }\n res.writeHead(200, {\n 'content-type': 'application/x-ndjson; charset=utf-8',\n 'cache-control': 'no-cache',\n 'x-accel-buffering': 'no',\n 'referrer-policy': 'no-referrer',\n })\n const send = (frame: AssistantFrame): void => { res.write(JSON.stringify(frame) + '\\n') }\n try {\n for await (const step of runAssistantTurn(ctx, config, project, config.outputDir, message)) {\n if (step.frame === 'delta') send({ type: 'delta', text: step.text })\n else if (step.frame === 'tool') send({ type: 'tool', name: step.name, status: step.status, detail: step.detail })\n else if (step.frame === 'toolDelta') send({ type: 'toolDelta', name: step.name, text: step.text })\n }\n send({ type: 'done' })\n res.end()\n } catch (error) {\n if (!res.writableEnded) {\n send({ type: 'error', message: (error as Error).message })\n res.end()\n }\n }\n },\n }\n\n // -------------------------------------------------- assistant-history\n const assistantHistoryRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.assistantHistory,\n handler: (req, res) => {\n if (!guard(req, res, 'GET')) return\n const config = getConfig()\n const response: AssistantHistoryResponse = { messages: loadAssistantHistory(config.outputDir) }\n writeJson(res, 200, response)\n },\n }\n\n // --------------------------------------------------- assistant-clear\n /** 清空助手对话记录。 */\n const assistantClearRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.assistantClear,\n handler: (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n clearAssistantHistory(config.outputDir)\n writeJson(res, 200, { ok: true })\n },\n }\n\n // --------------------------------------------------------------- assets\n const assetsRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.assets,\n handler: async (req, res) => {\n // GET (read) and POST (patch) are both allowed — check methods first,\n // then the loopback fence (guard() would 405 on POST, which is wrong).\n if (req.method !== 'GET' && req.method !== 'POST') {\n writeJson(res, 405, { error: 'method not allowed (expected GET or POST)' })\n return\n }\n if (!isLoopbackRequest(req)) {\n writeJson(res, 403, { error: 'forbidden: loopback-only' })\n return\n }\n const config = getConfig()\n const project = loadProject(config.outputDir)\n const projectAssets = project?.assets ?? emptyProjectAssets()\n if (req.method === 'POST') {\n const body = await readJsonBody<AssetsPatch>(req)\n if (body === undefined) {\n writeJson(res, 400, { error: '无效的 JSON' })\n return\n }\n if (project === undefined) {\n writeJson(res, 400, { error: '请先加载大纲创建项目' })\n return\n }\n if (body.genre !== undefined) projectAssets.genre = body.genre\n if (body.primaryProgression !== undefined) projectAssets.primaryProgression = body.primaryProgression\n if (body.auxiliaryProgressions !== undefined) projectAssets.auxiliaryProgressions = body.auxiliaryProgressions\n if (body.antiAiRules !== undefined) projectAssets.antiAiRules = body.antiAiRules\n if (body.styleAssets !== undefined) projectAssets.styleAssets = body.styleAssets\n projectAssets.updatedAt = new Date().toISOString()\n project.assets = projectAssets\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n }\n const response: AssetsResponse = {\n projectAssets,\n genreLibrary: BUILTIN_GENRE_LIBRARY,\n antiAiLibrary: BUILTIN_ANTI_AI_RULES,\n styleTemplates: BUILTIN_STYLE_TEMPLATES,\n progressionLibrary: BUILTIN_PROGRESSION_MODES,\n }\n writeJson(res, 200, response)\n },\n }\n\n // ----------------------------------------------------------- style-engine\n const styleEngineRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.styleEngine,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = loadProject(config.outputDir)\n const body = await readJsonBody<StyleEngineRequest>(req)\n const sample = body?.sampleText?.trim()\n if (sample === undefined || sample.length < 50) {\n writeJson(res, 400, { error: '样本文本过短(<50 字符),请粘贴一段能代表目标风格的文字' })\n return\n }\n try {\n const rules = await extractStyleAsset(ctx, config, sample)\n const name = body?.name?.trim() !== '' && body?.name !== undefined ? body.name : `风格资产 ${Date.now().toString(36)}`\n const styleAsset = {\n name: name.slice(0, 40),\n ...rules,\n sourceText: sample.slice(0, 3000),\n createdAt: new Date().toISOString(),\n }\n if (project !== undefined) {\n project.assets ??= emptyProjectAssets()\n project.assets.styleAssets ??= []\n project.assets.styleAssets.push(styleAsset)\n project.assets.updatedAt = new Date().toISOString()\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n }\n writeJson(res, 200, { styleAsset })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ------------------------------------------------------------- bookshelf\n const bookshelfRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.bookshelf,\n handler: async (req, res) => {\n // GET = snapshot; POST = create book.\n if (req.method === 'GET') {\n if (!isLoopbackRequest(req)) {\n writeJson(res, 403, { error: 'forbidden: loopback-only' })\n return\n }\n // 书架为空时,把 settings 默认输出目录里已有的项目播种为第一本书。\n seedBookshelfFromOutputDir(getConfig().outputDir)\n const snapshot: BookshelfSnapshot = bookshelfSnapshot(loadBookshelf())\n writeJson(res, 200, snapshot)\n return\n }\n if (req.method === 'POST') {\n if (!isLoopbackRequest(req)) {\n writeJson(res, 403, { error: 'forbidden: loopback-only' })\n return\n }\n const body = await readJsonBody<BookCreateRequest>(req)\n const bookName = body?.bookName?.trim()\n if (bookName === undefined || bookName === '') {\n writeJson(res, 400, { error: 'bookName 不能为空' })\n return\n }\n const outputDir = body?.outputDir?.trim() !== '' && body?.outputDir !== undefined\n ? body.outputDir\n : defaultOutputDirFor(bookName)\n const book = createBook(bookName, outputDir)\n // 开书向导:创建时带大纲 → 立即建立项目(书名以大纲首行为准)。\n const outline = body?.outline?.trim()\n if (outline !== undefined && outline.length >= 50) {\n const project = createProject(outline)\n saveProject(outputDir, project)\n renameBook(book.id, project.bookName)\n }\n writeJson(res, 200, bookshelfSnapshot(loadBookshelf()))\n return\n }\n writeJson(res, 405, { error: 'method not allowed (expected GET or POST)' })\n },\n }\n\n // --------------------------------------------------------------- reset\n /** 重置项目:清空设定/卷/章节计划/正文/伏笔/资产/事实库(可携带新大纲)。 */\n const resetRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.reset,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = loadProject(config.outputDir)\n if (project === undefined) {\n writeJson(res, 400, { error: '输出目录中没有项目,无需重置' })\n return\n }\n const body = await readJsonBody<ResetRequest>(req)\n const outline = body?.outline?.trim()\n if (outline !== undefined && outline.length >= 50) {\n project.outline = outline\n project.bookName = createProject(outline).bookName\n }\n project.bible = undefined\n project.volumes = undefined\n project.chapters = []\n project.foreshadows = []\n project.assets = emptyProjectAssets()\n project.facts = []\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, bookName: project.bookName })\n },\n }\n\n // --------------------------------------------------- bookshelf activate\n const bookshelfActivateRoute: WebRoute = {\n kind: 'exact',\n path: '/api/dsh-novel-forge/bookshelf/activate',\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<BookActivateRequest>(req)\n if (body?.id === undefined || body.id === '') {\n writeJson(res, 400, { error: 'id 不能为空' })\n return\n }\n const book = activateBook(body.id)\n if (book === undefined) {\n writeJson(res, 404, { error: `书 ${body.id} 不存在` })\n return\n }\n writeJson(res, 200, bookshelfSnapshot(loadBookshelf()))\n },\n }\n\n // ---------------------------------------------------- bookshelf remove\n const bookshelfRemoveRoute: WebRoute = {\n kind: 'exact',\n path: '/api/dsh-novel-forge/bookshelf/remove',\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<BookRemoveRequest>(req)\n if (body?.id === undefined || body.id === '') {\n writeJson(res, 400, { error: 'id 不能为空' })\n return\n }\n const removed = removeBook(body.id)\n if (!removed) {\n writeJson(res, 404, { error: `书 ${body.id} 不存在` })\n return\n }\n writeJson(res, 200, bookshelfSnapshot(loadBookshelf()))\n },\n }\n\n // ---------------------------------------------------------------- audit\n /** 全书一致性质检。 */\n const auditRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.audit,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const startedAt = new Date().toISOString()\n auditState = { status: 'running', startedAt, totalBatches: 0, completedBatches: 0 }\n try {\n const issues = await auditBook(ctx, config, project, config.outputDir, (completed, total) => {\n auditState.totalBatches = total\n auditState.completedBatches = completed\n })\n const auditedChapters = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating').length\n auditState = {\n status: 'done',\n startedAt,\n finishedAt: new Date().toISOString(),\n totalBatches: auditState.totalBatches,\n completedBatches: auditState.totalBatches,\n auditedChapters,\n issuesCount: issues.length,\n issues,\n }\n const response: AuditResponse = {\n issues,\n auditedChapters,\n auditedAt: auditState.finishedAt!,\n }\n writeJson(res, 200, response)\n } catch (error) {\n auditState = {\n ...auditState,\n status: 'error',\n finishedAt: new Date().toISOString(),\n error: (error as Error).message,\n }\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ----------------------------------------------------- characters refresh\n /** 角色卡刷新(出场统计精确化 + LLM 聚合状态)。 */\n const charactersRefreshRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.charactersRefresh,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n try {\n const cards = await refreshCharacters(ctx, config, project, config.outputDir)\n // 存档:人物志聚合结果落盘,下次打开直接显示,无需重新计算。\n project.roleStatus = cards\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { cards })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ------------------------------------------------------- facts backfill\n /** 事实库回填:对历史已生成章节批量抽取事实。 */\n const factsBackfillRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.factsBackfill,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n try {\n const filled = await backfillFacts(ctx, config, project, config.outputDir)\n writeJson(res, 200, { ok: true, filled })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ---------------------------------------------------------- bible patch\n /** 设定圣经局部修补(世界观规则/红线/风格)。 */\n const biblePatchRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.biblePatch,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n if (project.bible === undefined) {\n writeJson(res, 400, { error: '尚未生成道藏,请先生成' })\n return\n }\n const body = await readJsonBody<BiblePatchRequest>(req)\n if (Array.isArray(body?.worldRules)) project.bible.worldRules = body.worldRules.filter(r => r.trim() !== '')\n if (Array.isArray(body?.redLines)) project.bible.redLines = body.redLines.filter(r => r.trim() !== '')\n if (Array.isArray(body?.style)) project.bible.style = body.style.filter(r => r.trim() !== '')\n if (Array.isArray(body?.characters)) {\n project.bible.characters = body.characters\n .filter(c => c !== undefined && c !== null && typeof c.name === 'string' && c.name.trim() !== '')\n .map(c => ({\n name: c.name.trim(),\n role: (['protagonist', 'supporting', 'antagonist', 'other'] as const).includes(c.role as never)\n ? c.role as StoryBible['characters'][number]['role']\n : 'other',\n traits: Array.isArray(c.traits) ? c.traits.filter((t): t is string => typeof t === 'string' && t.trim() !== '') : [],\n goals: typeof c.goals === 'string' ? c.goals : '',\n relations: typeof c.relations === 'string' ? c.relations : '',\n knowledge: Array.isArray(c.knowledge)\n ? c.knowledge.filter((k): k is string => typeof k === 'string' && k.trim() !== '')\n : undefined,\n }))\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { bible: project.bible })\n },\n }\n\n // ---------------------------------------------------------------- blurb\n /** 小说简介:AI 生成/补全,或手动保存。 */\n const blurbRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.blurb,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<BlurbRequest>(req)\n try {\n if (body?.action === 'save') {\n const text = body.text?.trim() ?? ''\n project.blurb = text\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { blurb: text })\n return\n }\n const partial = body?.partial?.trim() ?? ''\n const blurb = await generateBlurb(ctx, config, project, partial)\n project.blurb = blurb\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { blurb })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // ---------------------------------------------------------------- cover\n /** 封面:GET 读取(dataUrl);POST 上传(base64)或移除。 */\n const coverRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.cover,\n handler: async (req, res) => {\n const config = getConfig()\n if (req.method === 'GET') {\n if (!isLoopbackRequest(req)) {\n writeJson(res, 403, { error: 'forbidden: loopback-only' })\n return\n }\n // 书架页按书读取:?dir=<输出目录>;省略时用当前激活书目录。\n const url = new URL(req.url ?? '/', 'http://localhost')\n const dirParam = url.searchParams.get('dir')\n const targetDir = dirParam !== null && dirParam !== '' ? dirParam : config.outputDir\n const project = loadProject(targetDir)\n const coverPath = project?.coverPath\n if (coverPath === undefined || coverPath === '') {\n writeJson(res, 200, { dataUrl: null } satisfies CoverResponse)\n return\n }\n const file = join(targetDir, coverPath)\n if (!existsSync(file)) {\n writeJson(res, 200, { dataUrl: null } satisfies CoverResponse)\n return\n }\n const mime = coverPath.toLowerCase().endsWith('.png') ? 'image/png'\n : coverPath.toLowerCase().endsWith('.jpg') || coverPath.toLowerCase().endsWith('.jpeg') ? 'image/jpeg'\n : coverPath.toLowerCase().endsWith('.webp') ? 'image/webp'\n : 'image/png'\n const dataUrl = `data:${mime};base64,${readFileSync(file).toString('base64')}`\n writeJson(res, 200, { dataUrl } satisfies CoverResponse)\n return\n }\n if (req.method === 'POST') {\n if (!guard(req, res, 'POST')) return\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<CoverRequest>(req)\n try {\n if (body?.action === 'remove') {\n if (project.coverPath !== undefined && project.coverPath !== '') {\n const oldFile = join(config.outputDir, project.coverPath)\n if (existsSync(oldFile)) rmSync(oldFile, { force: true })\n }\n project.coverPath = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, coverPath: null })\n return\n }\n const dataUrl = body?.dataUrl ?? ''\n const match = /^data:(image\\/(?:png|jpeg|jpg|webp));base64,(.+)$/s.exec(dataUrl)\n if (match === null) {\n writeJson(res, 400, { error: '封面须为 PNG/JPEG/WebP 的 base64 data URL' })\n return\n }\n const mime = match[1]!\n const ext = mime === 'image/png' ? 'png' : mime === 'image/webp' ? 'webp' : 'jpg'\n const fileName = `cover.${ext}`\n const targetPath = join(config.outputDir, fileName)\n const oldPath = project.coverPath\n mkdirSync(config.outputDir, { recursive: true })\n writeFileSync(targetPath, Buffer.from(match[2]!, 'base64'))\n if (oldPath !== undefined && oldPath !== '' && oldPath !== fileName) {\n const oldFile = join(config.outputDir, oldPath)\n if (existsSync(oldFile)) rmSync(oldFile, { force: true })\n }\n project.coverPath = fileName\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, coverPath: fileName })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n return\n }\n writeJson(res, 405, { error: 'method not allowed (expected GET or POST)' })\n },\n }\n\n // ---------------------------------------------------------------- world\n /** 大世界:AI 提炼或手动保存(境界体系/区域/势力)。 */\n const worldRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.world,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<WorldRequest>(req)\n try {\n if (body?.action === 'save' && body.world !== undefined) {\n project.world = {\n realms: Array.isArray(body.world.realms) ? body.world.realms : [],\n regions: Array.isArray(body.world.regions) ? body.world.regions : [],\n factions: Array.isArray(body.world.factions) ? body.world.factions : [],\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { world: project.world })\n return\n }\n const world = await extractWorld(ctx, config, project)\n project.world = world\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { world })\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n }\n },\n }\n\n // --------------------------------------------------------------- rename\n /** 重命名当前书:同步项目 bookName 与书架条目。 */\n const renameRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.rename,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<RenameRequest>(req)\n const bookName = body?.bookName?.trim()\n if (bookName === undefined || bookName === '') {\n writeJson(res, 400, { error: '书名不能为空' })\n return\n }\n project.bookName = bookName.slice(0, 60)\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n const store = loadBookshelf()\n if (store.activeBookId !== null) renameBook(store.activeBookId, project.bookName)\n writeJson(res, 200, { bookName: project.bookName })\n },\n }\n\n // ------------------------------------------------------------- plotlines\n /** 剧情线管理:增删改 + 关联章节(主线/支线/人物线/悬念线)。 */\n const plotlinesRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.plotlines,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<PlotlinesRequest>(req)\n if (project.plotlines === undefined) project.plotlines = []\n const op = body?.op\n if (op === 'add' && body?.line !== undefined) {\n const line = body.line\n project.plotlines.push({\n id: line.id !== '' ? line.id : `pl-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,\n name: line.name.slice(0, 40),\n kind: line.kind,\n goal: line.goal.slice(0, 300),\n progress: line.progress.slice(0, 300),\n status: line.status,\n chapters: Array.isArray(line.chapters) ? line.chapters.filter((n): n is number => typeof n === 'number') : [],\n createdAt: line.createdAt !== '' ? line.createdAt : new Date().toISOString(),\n })\n } else if (op === 'update' && body?.line !== undefined && body.line.id !== '') {\n const idx = project.plotlines.findIndex(l => l.id === body.line!.id)\n if (idx !== -1) {\n const line = body.line\n project.plotlines[idx] = {\n ...project.plotlines[idx]!,\n name: line.name.slice(0, 40),\n kind: line.kind,\n goal: line.goal.slice(0, 300),\n progress: line.progress.slice(0, 300),\n status: line.status,\n }\n }\n } else if (op === 'remove' && body?.id !== undefined) {\n project.plotlines = project.plotlines.filter(l => l.id !== body.id)\n } else if (op === 'link' && body?.id !== undefined && typeof body.chapterNo === 'number' && body.chapterNo > 0) {\n const line = project.plotlines.find(l => l.id === body.id)\n if (line !== undefined && !line.chapters.includes(body.chapterNo)) {\n line.chapters.push(body.chapterNo)\n if (line.status === 'active' && line.progress === '') {\n line.progress = `推进至第 ${body.chapterNo} 章`\n }\n }\n } else if (op === 'suggest') {\n try {\n const suggestions = await suggestPlotlines(ctx, config, project)\n writeJson(res, 200, { plotlines: project.plotlines, suggestions } satisfies PlotlinesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `AI 建议失败:${(error as Error).message}` })\n return\n }\n } else if (op === 'refresh' && body?.id !== undefined) {\n const line = project.plotlines.find(l => l.id === body.id)\n if (line === undefined) {\n writeJson(res, 404, { error: '剧情线不存在' })\n return\n }\n try {\n const progress = await refreshPlotlineProgress(ctx, config, project, line)\n line.progress = progress\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { plotlines: project.plotlines } satisfies PlotlinesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `刷新进度失败:${(error as Error).message}` })\n return\n }\n } else if (op === 'health') {\n try {\n const health = await analyzePlotlineHealth(ctx, config, project)\n writeJson(res, 200, { plotlines: project.plotlines, health } satisfies PlotlinesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `健康检查失败:${(error as Error).message}` })\n return\n }\n } else if (op === 'plan') {\n try {\n const health = await analyzePlotlineHealth(ctx, config, project)\n const plan = await designPlotlinePlan(ctx, config, project, health)\n writeJson(res, 200, { plotlines: project.plotlines, health, plan } satisfies PlotlinesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `剧情方案生成失败:${(error as Error).message}` })\n return\n }\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n const response: PlotlinesResponse = { plotlines: project.plotlines }\n writeJson(res, 200, response)\n },\n }\n\n // --------------------------------------------------------- sensitive\n /** 敏感词检查:指定章节 / 任意文本 / 全书已写章节。 */\n const sensitiveRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.sensitiveCheck,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<SensitiveCheckRequest>(req)\n const hits: SensitiveHit[] = []\n let scanned = 0\n if (body?.text !== undefined) {\n for (const hit of checkSensitiveText(body.text)) {\n hits.push({ chapterNo: 0, word: hit.word, category: hit.category, count: hit.count })\n }\n } else if (typeof body?.chapterNo === 'number') {\n const chapter = project.chapters.find(c => c.no === body.chapterNo)\n if (chapter !== undefined) {\n const text = readChapterFile(config.outputDir, chapter)\n if (text !== undefined) {\n scanned = 1\n for (const hit of checkSensitiveText(text)) {\n hits.push({ chapterNo: chapter.no, word: hit.word, category: hit.category, count: hit.count })\n }\n }\n }\n } else if (body?.all === true) {\n for (const chapter of project.chapters) {\n if (chapter.status === 'pending' || chapter.status === 'generating') continue\n const text = readChapterFile(config.outputDir, chapter)\n if (text === undefined) continue\n scanned++\n for (const hit of checkSensitiveText(text)) {\n hits.push({ chapterNo: chapter.no, word: hit.word, category: hit.category, count: hit.count })\n }\n }\n } else {\n writeJson(res, 400, { error: '请提供 chapterNo / text / all 之一' })\n return\n }\n const response: SensitiveCheckResponse = { hits, scannedChapters: scanned }\n writeJson(res, 200, response)\n },\n }\n\n // ---------------------------------------------------------------- roles\n /** 角色库:AI 提炼 / 采纳 / 更新 / 删除。 */\n const rolesRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.roles,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<RolesRequest>(req)\n if (project.roles === undefined) project.roles = []\n const op = body?.op\n if (op === 'extract') {\n try {\n const candidates = await extractRoles(ctx, config, project)\n writeJson(res, 200, { roles: project.roles, candidates } satisfies RolesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `角色提炼失败:${(error as Error).message}` })\n return\n }\n } else if ((op === 'adopt' || op === 'update') && body?.role !== undefined) {\n const r = body.role\n const idx = project.roles.findIndex(x => x.name === r.name)\n if (idx === -1) project.roles.push(r)\n else project.roles[idx] = r\n } else if (op === 'remove' && body?.name !== undefined) {\n project.roles = project.roles.filter(x => x.name !== body.name)\n } else if (op === 'image') {\n const name = body?.name?.trim()\n const dataUrl = body?.dataUrl?.trim()\n if (name === undefined || name === '') {\n writeJson(res, 400, { error: 'name(角色名)必填' })\n return\n }\n if (dataUrl === undefined || dataUrl === '') {\n writeJson(res, 400, { error: 'dataUrl(参考图)必填' })\n return\n }\n const role = project.roles.find(r => r.name === name)\n if (role === undefined) {\n writeJson(res, 404, { error: `当前激活《${project.bookName}》,角色 ${name} 不存在——若期望的书不对,请先在书架切换该书并刷新` })\n return\n }\n const label = body?.label?.trim() ?? ''\n if (label !== '') {\n // 图集上传:带用途标签。标签「立绘」时同步为角色参考图(imageUrl)。\n role.gallery ??= []\n role.gallery = role.gallery.filter(g => g.label !== label)\n role.gallery.push({ label, dataUrl })\n if (label === '立绘' || label.includes('立绘')) role.imageUrl = dataUrl\n } else {\n // 兼容旧行为:不带标签 = 角色参考图。\n role.imageUrl = dataUrl\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { roles: project.roles, imageUrl: role.imageUrl } satisfies RolesResponse)\n return\n } else if (op === 'removeImage') {\n const name = body?.name?.trim()\n const label = body?.label?.trim() ?? ''\n const role = project.roles.find(r => r.name === name)\n if (role !== undefined) {\n if (label !== '') {\n role.gallery = (role.gallery ?? []).filter(g => g.label !== label)\n if (label === '立绘' || label.includes('立绘')) role.imageUrl = undefined\n } else {\n role.imageUrl = undefined\n }\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { roles: project.roles } satisfies RolesResponse)\n return\n } else if (op === 'imageGenerate') {\n const name = body?.name?.trim()\n if (name === undefined || name === '') {\n writeJson(res, 400, { error: 'name(角色名)必填' })\n return\n }\n try {\n const imageUrl = await generateRoleReferenceImage(ctx, config, project, config.outputDir, name, body?.style ?? '')\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { roles: project.roles, imageUrl } satisfies RolesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `角色参考图生成失败:${(error as Error).message}` })\n return\n }\n } else if (op === 'visual') {\n // 动漫形象描述词提炼:扫描正文外貌描写 → LLM 提炼 → 写入角色卡。\n const name = body?.name?.trim()\n if (name === undefined || name === '') {\n writeJson(res, 400, { error: 'name(角色名)必填' })\n return\n }\n try {\n const visual = await extractRoleVisual(ctx, config, project, config.outputDir, name)\n const role = project.roles.find(r => r.name === name)\n if (role !== undefined) {\n role.imagePrompt = visual\n if ((visual.expressions ?? []).length > 0) role.expressions = visual.expressions\n if (visual.promptKit !== undefined) role.promptKit = visual.promptKit\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { roles: project.roles, visual } satisfies RolesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `形象提炼失败:${(error as Error).message}` })\n return\n }\n } else if (op === 'promptKit') {\n // 角色四类提示词精修包(立绘/四视图/表情/细节)\n const name = body?.name?.trim()\n if (name === undefined || name === '') {\n writeJson(res, 400, { error: 'name(角色名)必填' })\n return\n }\n try {\n const kit = await generateRolePromptKit(ctx, config, project, name)\n const role = project.roles.find(r => r.name === name)\n if (role !== undefined) role.promptKit = kit\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { roles: project.roles, promptKit: kit } satisfies RolesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `提示词精修失败:${(error as Error).message}` })\n return\n }\n } else {\n writeJson(res, 400, { error: '未知的 roles op' })\n return\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n const response: RolesResponse = { roles: project.roles }\n writeJson(res, 200, response)\n },\n }\n\n // ------------------------------------------------------- chapter reset\n /** 章节复位:generating 卡死 → pending(可重新生成)。 */\n const chapterResetRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.chapterReset,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<{ chapterNo?: number }>(req)\n const no = body?.chapterNo\n if (!Number.isInteger(no) || no === undefined || no < 1) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const chapter = project.chapters.find(c => c.no === no)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${no} 不在计划中` })\n return\n }\n chapter.status = 'pending'\n chapter.error = undefined\n chapter.generatingAt = undefined\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, no })\n },\n }\n\n // ------------------------------------------------------ chapter approve\n /** 章节直接通过:作者行使最终决定权(不重审,保留审稿记录)。 */\n const chapterApproveRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.chapterApprove,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<{ chapterNo?: number }>(req)\n const no = body?.chapterNo\n if (!Number.isInteger(no) || no === undefined || no < 1) {\n writeJson(res, 400, { error: 'chapterNo 须为正整数' })\n return\n }\n const chapter = project.chapters.find(c => c.no === no)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${no} 不在计划中` })\n return\n }\n chapter.status = 'approved'\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { ok: true, no })\n },\n }\n\n // ------------------------------------------------------ author review backfill\n /** 作者复盘补跑:对已写章节补齐 authorReview(body.chapterNo=单章 JSON,缺省=全书 NDJSON 流)。 */\n const reviewBackfillRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.reviewBackfill,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<{ chapterNo?: number }>(req)\n\n /** 对一章执行作者复盘(读取已落盘正文,不改变章节状态/正文)。 */\n const runOne = async (chapter: ChapterPlan): Promise<AuthorReview> => {\n const currentBody = readChapterFile(config.outputDir, chapter)\n if (currentBody === undefined) throw new Error(`章节 ${chapter.no} 的正文文件不存在`)\n let prevTail = ''\n if (chapter.no > 1) {\n const prev = project.chapters.find(c => c.no === chapter.no - 1)\n if (prev !== undefined) {\n prevTail = (readChapterFile(config.outputDir, prev) ?? '').replace(/^#.*$/m, '').trim().slice(-600)\n }\n }\n return authorReviewChapter(ctx, config, project, chapter.no, currentBody, prevTail)\n }\n\n // 单章:JSON 响应。\n if (typeof body?.chapterNo === 'number' && body.chapterNo > 0) {\n const chapter = project.chapters.find(c => c.no === body.chapterNo)\n if (chapter === undefined) {\n writeJson(res, 404, { error: `章节 ${body.chapterNo} 不在计划中` })\n return\n }\n if (chapter.status === 'pending') {\n writeJson(res, 400, { error: '该章尚未生成正文,无法复盘' })\n return\n }\n try {\n const review = await runOne(chapter)\n chapter.authorReview = review\n if (review.advancedLines !== undefined) {\n autoLinkPlotlines(project, chapter.no, review.advancedLines)\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { no: chapter.no, review } satisfies { no: number; review: AuthorReview })\n return\n } catch (error) {\n writeJson(res, 500, { error: (error as Error).message })\n return\n }\n }\n\n // 全书:NDJSON 流式补跑缺失复盘的已写章节。\n const missing = project.chapters.filter(c => c.status !== 'pending' && c.status !== 'generating' && c.status !== 'error' && c.authorReview === undefined)\n if (missing.length === 0) {\n writeJson(res, 200, { count: 0 })\n return\n }\n res.writeHead(200, {\n 'content-type': 'application/x-ndjson; charset=utf-8',\n 'cache-control': 'no-cache',\n 'referrer-policy': 'no-referrer',\n })\n const send = (frame: JobFrame): void => {\n res.write(JSON.stringify(frame) + '\\n')\n }\n let done = 0\n for (const chapter of missing) {\n try {\n const review = await runOne(chapter)\n chapter.authorReview = review\n if (review.advancedLines !== undefined) {\n autoLinkPlotlines(project, chapter.no, review.advancedLines)\n }\n done++\n saveProject(config.outputDir, project)\n send({ type: 'author-review', no: chapter.no, review })\n } catch (error) {\n console.warn(`[dsh-novel-forge] author backfill ch.${chapter.no} failed:`, (error as Error).message)\n }\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n send({ type: 'author-backfill-done', count: done })\n res.end()\n },\n }\n\n // --------------------------------------------------------------- config\n const configRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.config,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<ConfigPatch>(req)\n if (body === undefined) {\n writeJson(res, 400, { error: '无效的配置 JSON' })\n return\n }\n try {\n const next = await patchConfig(body)\n writeJson(res, 200, { config: next })\n } catch (error) {\n writeJson(res, 400, { error: (error as Error).message })\n }\n },\n }\n\n // ---------------------------------------------------------- open-folder\n const openFolderRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.openFolder,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const dir = config.outputDir\n exec(`explorer \"${dir.replace(/\"/g, '')}\"`, (error) => {\n if (error) {\n writeJson(res, 500, { ok: false, error: error.message })\n } else {\n writeJson(res, 200, { ok: true })\n }\n })\n },\n }\n\n // ------------------------------------------------------- outline suggest\n /** 开书想法 → AI 大纲:2-3 个可选方案(支持暂留换批:count 只补空槽 + exclude 避开已留方向)。 */\n const outlineSuggestRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.outlineSuggest,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const body = await readJsonBody<OutlineSuggestRequest>(req)\n const idea = body?.idea?.trim() ?? ''\n if (idea.length < 50) {\n writeJson(res, 400, { error: '想法太短(<50 字),请多写一两句:主角是谁、什么世界、想要什么爽点' })\n return\n }\n const count = body?.count !== undefined ? Math.max(1, Math.min(3, Math.floor(body.count))) : 3\n const exclude = Array.isArray(body?.exclude) ? body.exclude.filter((e): e is string => typeof e === 'string' && e.trim() !== '').map(e => e.trim().slice(0, 200)) : []\n try {\n const candidates = await suggestOutlines(ctx, config, idea, count, exclude)\n const response: OutlineSuggestResponse = { candidates }\n writeJson(res, 200, response)\n } catch (error) {\n writeJson(res, 500, { error: `大纲方案生成失败:${(error as Error).message}` })\n }\n },\n }\n\n // ----------------------------------------------------------- breakdown\n /** 拆书分析:对已写章节做结构/人物/文风/卖点体检(两阶段:源笔记→分节分析)。 */\n const breakdownRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.breakdown,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<BreakdownRequest>(req)\n try {\n const result = await breakdownBook(\n ctx,\n config,\n project,\n config.outputDir,\n body?.scope ?? 'recent',\n body?.preset ?? 'quick',\n body?.budgetTokens ?? 50000,\n )\n writeJson(res, 200, result satisfies BreakdownResponse)\n } catch (error) {\n writeJson(res, 500, { error: `拆书分析失败:${(error as Error).message}` })\n }\n },\n }\n\n // --------------------------------------------------------------- scenes\n /** 场景库:AI 提炼 / 采纳 / 更新 / 删除 / 图集。 */\n const scenesRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.scenes,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<ScenesRequest>(req)\n if (project.scenes === undefined) project.scenes = []\n const op = body?.op\n if (op === 'extract') {\n try {\n const candidates = await extractScenes(ctx, config, project)\n writeJson(res, 200, { scenes: project.scenes, candidates } satisfies ScenesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `场景提炼失败:${(error as Error).message}` })\n return\n }\n } else if ((op === 'adopt' || op === 'update') && body?.scene !== undefined) {\n const s = body.scene\n const idx = project.scenes.findIndex(x => x.name === s.name)\n if (idx === -1) project.scenes.push(s)\n else project.scenes[idx] = s\n } else if (op === 'remove' && body?.name !== undefined) {\n project.scenes = project.scenes.filter(x => x.name !== body.name)\n } else if (op === 'image') {\n const name = body?.name?.trim()\n const dataUrl = body?.dataUrl?.trim()\n if (name === undefined || name === '' || dataUrl === undefined || dataUrl === '') {\n writeJson(res, 400, { error: 'name(场景名)与 dataUrl 必填' })\n return\n }\n const scene = project.scenes.find(x => x.name === name)\n if (scene === undefined) {\n writeJson(res, 404, { error: `当前激活《${project.bookName}》,场景 ${name} 不存在——若期望的书不对,请先在书架切换该书并刷新` })\n return\n }\n const label = body?.label?.trim() ?? '全景'\n scene.gallery ??= []\n scene.gallery = scene.gallery.filter(g => g.label !== label)\n scene.gallery.push({ label, dataUrl })\n } else if (op === 'removeImage') {\n const name = body?.name?.trim()\n const label = body?.label?.trim() ?? ''\n const scene = project.scenes.find(x => x.name === name)\n if (scene !== undefined && label !== '') {\n scene.gallery = (scene.gallery ?? []).filter(g => g.label !== label)\n }\n } else {\n writeJson(res, 400, { error: `未知操作 ${op}` })\n return\n }\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { scenes: project.scenes } satisfies ScenesResponse)\n },\n }\n\n // ----------------------------------------------------------- visual rules\n /** 视觉世界观规则:从道藏提炼(生图/生视频纠偏),或手动保存。 */\n const visualRulesRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.visualRules,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const config = getConfig()\n const project = requireProject(res)\n if (project === undefined) return\n const body = await readJsonBody<VisualRulesRequest>(req)\n if (body?.op === 'extract') {\n try {\n const rules = await extractVisualRules(ctx, config, project)\n project.visualRules = rules\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { rules } satisfies VisualRulesResponse)\n return\n } catch (error) {\n writeJson(res, 500, { error: `视觉规则提炼失败:${(error as Error).message}` })\n return\n }\n } else if (body?.op === 'save' && Array.isArray(body.rules)) {\n project.visualRules = body.rules.filter(r => typeof r === 'string' && r.trim() !== '').map(r => r.trim().slice(0, 80)).slice(0, 12)\n project.updatedAt = new Date().toISOString()\n saveProject(config.outputDir, project)\n writeJson(res, 200, { rules: project.visualRules } satisfies VisualRulesResponse)\n return\n }\n writeJson(res, 400, { error: 'op 须为 extract 或 save' })\n },\n }\n\n // ----------------------------------------------------------- production run\n /** 生产单执行器(单例):计划补足 → 逐章生成 → 被拒分级处理 → 断点续跑。 */\n const runner = new ProductionRunner({ ctx, getConfig })\n\n const runStartRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.runStart,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<RunStartRequest>(req)\n const config = getConfig()\n const project = loadProject(config.outputDir)\n if (project === undefined) {\n writeJson(res, 400, { error: '输出目录中没有项目' })\n return\n }\n const startNo = Number.isInteger(body?.startNo) && (body!.startNo! >= 1) ? body!.startNo! : 1\n let endNo: number\n if (Number.isInteger(body?.endNo) && (body!.endNo! >= startNo)) {\n endNo = body!.endNo!\n } else if (Number.isInteger(body?.count) && (body!.count! >= 1) && (body!.count! <= 200)) {\n const last = Math.max(0, ...project.chapters.map(c => c.no))\n endNo = last + body!.count!\n } else {\n writeJson(res, 400, { error: '请提供 endNo 或 count(1-200)' })\n return\n }\n try {\n const state = await runner.start(startNo, endNo)\n writeJson(res, 200, state satisfies RunState)\n } catch (error) {\n writeJson(res, 409, { error: (error as Error).message })\n }\n },\n }\n\n const runControlRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.runControl,\n handler: async (req, res) => {\n if (!guard(req, res, 'POST')) return\n const body = await readJsonBody<RunControlRequest>(req)\n const state = runner.status()\n if (state === null) {\n writeJson(res, 400, { error: '没有生产单' })\n return\n }\n if (body?.action === 'pause') runner.pause()\n else if (body?.action === 'resume') runner.resume()\n else if (body?.action === 'stop') runner.stop()\n else {\n writeJson(res, 400, { error: 'action 须为 pause / resume / stop' })\n return\n }\n writeJson(res, 200, runner.status())\n },\n }\n\n const runStatusRoute: WebRoute = {\n kind: 'exact',\n path: NOVEL_API.runStatus,\n handler: (req, res) => {\n if (!guard(req, res, 'GET')) return\n writeJson(res, 200, runner.status())\n },\n }\n\n return [\n statusRoute,\n loadOutlineRoute,\n saveOutlineRoute,\n bibleRoute,\n volumesRoute,\n planRoute,\n generateRoute,\n reviewRoute,\n rewriteRoute,\n polishRoute,\n draftApplyRoute,\n draftDiscardRoute,\n summaryRoute,\n foreshadowRoute,\n exportRoute,\n chapterRoute,\n chapterCheckRoute,\n chapterSaveRoute,\n assetsRoute,\n styleEngineRoute,\n assistantRoute,\n assistantHistoryRoute,\n assistantClearRoute,\n bookshelfRoute,\n bookshelfActivateRoute,\n bookshelfRemoveRoute,\n resetRoute,\n auditRoute,\n charactersRefreshRoute,\n factsBackfillRoute,\n biblePatchRoute,\n blurbRoute,\n coverRoute,\n worldRoute,\n renameRoute,\n plotlinesRoute,\n rolesRoute,\n scenesRoute,\n visualRulesRoute,\n sensitiveRoute,\n reviewBackfillRoute,\n chapterResetRoute,\n chapterApproveRoute,\n configRoute,\n openFolderRoute,\n outlineSuggestRoute,\n breakdownRoute,\n runStartRoute,\n runControlRoute,\n runStatusRoute,\n ]\n}\n\n// Re-export for tests / type consumers.\nexport type {\n ConfigPatch,\n NovelConfig,\n StatusResponse,\n PlanResponse,\n LoadOutlineResponse,\n BibleResponse,\n VolumesResponse,\n ExportResponse,\n}\nexport { chapterFileName }\n","/**\n * dsh-novel-forge — host half. Mounts the AI novel-forge workbench: docx\n * outline import, LLM chapter planning, chapter-by-chapter generation\n * (3000-4000 chars each), Markdown output into your chosen folder, and the\n * /api/dsh-novel-forge route family. The browser half (./client) renders the\n * workbench panel. Everything rides official NPM SDK packages — no dsh source\n * changes.\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport { installSettingsSection, settingsNamespace } from '@deepseek-ai/dsh-settings'\nimport z from 'schemastery'\nimport type {} from '@deepseek-ai/dsh-host-webserver'\nimport type {} from '@deepseek-ai/dsh-llm'\nimport type {} from '@deepseek-ai/dsh-system-prompt'\nimport type { ConfigPatch, NovelConfig } from './protocol.ts'\nimport { makeRoutes } from './routes.ts'\nimport { activeBookOutputDir } from './bookshelf.ts'\n\n/** Stable cordis plugin name. */\nexport const name = 'novel-forge'\n\n/** Services required before the novel-forge surfaces can mount. */\nexport const inject = ['webServer', 'llm', 'systemPrompt']\n\n/**\n * Settings namespace of the novel-forge capability — the section the web\n * settings surface edits. Spelled here rather than imported: the browser half\n * spells the same value and must not depend on a Host package.\n */\nexport const NOVEL_SETTINGS_NAMESPACE = settingsNamespace('dsh-novel-forge')\n\n/** Plugin config, validated by the same-named schemastery schema. */\nexport interface Config {\n /** When true (default), a system-prompt section announces the plugin to every agent. */\n announceToAgent?: boolean\n /** Master switch for the plugin (routes, prompt section). */\n enabled?: boolean\n /** Absolute path of the default docx outline to load. */\n outlinePath?: string\n /** Absolute output directory for chapters + project state. */\n outputDir?: string\n /** LLM provider route. */\n provider?: string\n /** LLM model id. */\n model?: string\n /** LLM reasoning effort (off/low/high/max). */\n reasoningEffort?: 'off' | 'low' | 'high' | 'max'\n /** Target characters per chapter. */\n chapterChars?: number\n /** Max output tokens per chapter call. */\n maxTokens?: number\n /** Review pass threshold (0-100). */\n reviewPassScore?: number\n /** Whether generation auto-runs review after writing. */\n autoReview?: boolean\n /** Whether generation auto-runs the author review (hook/continuity/trend). */\n autoAuthorReview?: boolean\n /** 修订/润色产出草稿后自动附带一次 AI 审查(默认开,可在设置页关闭省 token)。 */\n autoReviewAfterRevise?: boolean\n /** 豆包/Seedream 生图 API Key。 */\n imageApiKey?: string\n /** 豆包/Seedream 生图模型 ID。 */\n imageApiModel?: string\n /** 是否启用豆包生图(默认关)。 */\n imageApiEnabled?: boolean\n}\n\nexport const Config: z<Config> = z.object({\n announceToAgent: z.boolean().default(true),\n enabled: z.boolean().default(true),\n outlinePath: z.string().default('D:\\\\ryan work\\\\harness\\\\novels\\\\归墟玉主\\\\《归墟玉主》全书大纲_重新排版版.docx'),\n outputDir: z.string().default('D:\\\\ryan work\\\\harness\\\\novels\\\\归墟玉主'),\n provider: z.string().default('deepseek-official'),\n model: z.string().default('deepseek-v4-flash'),\n reasoningEffort: z.union(['off', 'low', 'high', 'max']).default('off'),\n chapterChars: z.number().default(3500),\n maxTokens: z.number().default(12000),\n reviewPassScore: z.number().default(70),\n autoReview: z.boolean().default(true),\n autoAuthorReview: z.boolean().default(true),\n autoReviewAfterRevise: z.boolean().default(true),\n imageApiKey: z.string().default(''),\n imageApiModel: z.string().default(''),\n imageApiEnabled: z.boolean().default(false),\n})\n\n/** Schema defaults, re-read for hand-built test contexts. */\nconst DEFAULT_ANNOUNCE = true\nconst DEFAULT_OUTLINE_PATH = 'D:\\\\ryan work\\\\harness\\\\novels\\\\归墟玉主\\\\《归墟玉主》全书大纲_重新排版版.docx'\nconst DEFAULT_OUTPUT_DIR = 'D:\\\\ryan work\\\\harness\\\\novels\\\\归墟玉主'\nconst DEFAULT_PROVIDER = 'deepseek-official'\nconst DEFAULT_MODEL = 'deepseek-v4-flash'\nconst DEFAULT_REASONING_EFFORT = 'off' as const\nconst DEFAULT_CHAPTER_CHARS = 3500\nconst DEFAULT_MAX_TOKENS = 12000\nconst DEFAULT_REVIEW_PASS_SCORE = 70\nconst DEFAULT_AUTO_REVIEW = true\nconst DEFAULT_AUTO_AUTHOR_REVIEW = true\nconst DEFAULT_AUTO_REVIEW_AFTER_REVISE = true\n\n/** Order of the announcement section within the tool-guidance band. */\nconst SECTION_ORDER = 160\n\n/** Model-facing announcement: plugin presence, capabilities, and limits. */\nexport const NOVEL_GUIDANCE = '本机已安装 dsh-novel-forge 插件(AI 编译小说工作台):侧边栏「小说工坊」入口。能力:读取 docx 大纲(默认 D:\\\\ryan work\\\\harness\\\\novels\\\\归墟玉主 大纲)或粘贴大纲文本;用 LLM 提炼道藏(人设/世界观/金手指规则/写作红线,即设定圣经);生成卷计划与章节计划;逐章调用 LLM 生成 3000-4000 字正文并保存为 Markdown(默认输出到 D:\\\\ryan work\\\\harness\\\\novels\\\\归墟玉主);每章自动生成摘要(叙事记忆)、自动 AI 审稿(人设/设定/红线/文笔/爽点/逻辑),支持按审稿意见重写、去 AI 味润色、暗线(伏笔)管理、批量连写与全本导出(txt/md)。限制:生成消耗 LLM API 额度;输出目录与模型可在插件设置中修改;章节正文质量取决于大纲完整度。用户提到「小说 / 大纲 / 写小说 / 章节 / 审稿 / 润色 / 归墟玉主」时即指本插件,请据此协作。'\n\n/** Resolve a config-like value into the full runtime config. */\nexport function resolveConfig(value: Partial<Config> | undefined): NovelConfig {\n return {\n outlinePath: value?.outlinePath ?? DEFAULT_OUTLINE_PATH,\n outputDir: value?.outputDir ?? DEFAULT_OUTPUT_DIR,\n provider: value?.provider ?? DEFAULT_PROVIDER,\n model: value?.model ?? DEFAULT_MODEL,\n reasoningEffort: value?.reasoningEffort ?? DEFAULT_REASONING_EFFORT,\n chapterChars: value?.chapterChars ?? DEFAULT_CHAPTER_CHARS,\n maxTokens: value?.maxTokens ?? DEFAULT_MAX_TOKENS,\n reviewPassScore: value?.reviewPassScore ?? DEFAULT_REVIEW_PASS_SCORE,\n autoReview: value?.autoReview ?? DEFAULT_AUTO_REVIEW,\n autoAuthorReview: value?.autoAuthorReview ?? DEFAULT_AUTO_AUTHOR_REVIEW,\n autoReviewAfterRevise: value?.autoReviewAfterRevise ?? DEFAULT_AUTO_REVIEW_AFTER_REVISE,\n imageApiKey: value?.imageApiKey,\n imageApiModel: value?.imageApiModel,\n imageApiEnabled: value?.imageApiEnabled ?? false,\n }\n}\n\n/**\n * Mount the routes and announcement.\n * @param ctx - host plugin context carrying webServer/llm/systemPrompt.\n * @param config - resolved plugin config (schema defaults applied by the loader).\n */\nexport function apply(ctx: Context, config?: Config): void {\n // The live source the routes read: the settings section once the web\n // settings surface is served, the composition entry otherwise.\n let current: () => Config = () => config ?? {}\n const resolve = (): NovelConfig => {\n const resolved = resolveConfig(current())\n // 书架激活的书优先决定输出目录(settings 仍可改默认值)。\n const shelfDir = activeBookOutputDir()\n if (shelfDir !== undefined) {\n return { ...resolved, outputDir: shelfDir }\n }\n return resolved\n }\n\n const patchConfig = async (patch: ConfigPatch): Promise<NovelConfig> => {\n const next: ConfigPatch = {}\n if (patch.outlinePath !== undefined) next.outlinePath = patch.outlinePath\n if (patch.outputDir !== undefined) next.outputDir = patch.outputDir\n if (patch.provider !== undefined) next.provider = patch.provider\n if (patch.model !== undefined) next.model = patch.model\n if (patch.reasoningEffort !== undefined) next.reasoningEffort = patch.reasoningEffort\n if (patch.chapterChars !== undefined) next.chapterChars = patch.chapterChars\n if (patch.maxTokens !== undefined) next.maxTokens = patch.maxTokens\n if (patch.reviewPassScore !== undefined) next.reviewPassScore = patch.reviewPassScore\n if (patch.autoReview !== undefined) next.autoReview = patch.autoReview\n if (patch.autoAuthorReview !== undefined) next.autoAuthorReview = patch.autoAuthorReview\n if (patch.autoReviewAfterRevise !== undefined) next.autoReviewAfterRevise = patch.autoReviewAfterRevise\n if (patch.imageApiKey !== undefined) next.imageApiKey = patch.imageApiKey\n if (patch.imageApiModel !== undefined) next.imageApiModel = patch.imageApiModel\n if (patch.imageApiEnabled !== undefined) next.imageApiEnabled = patch.imageApiEnabled\n // Persist through the settings seam when available; otherwise keep in memory.\n // (ctx.get is the non-strict service access — no inject requirement, same\n // pattern installSettingsSection itself uses.)\n const settings = ctx.get('settings')\n if (settings !== undefined) {\n await settings.update(NOVEL_SETTINGS_NAMESPACE, next as Record<string, unknown>)\n } else {\n current = () => ({ ...current(), ...next })\n }\n return resolve()\n }\n\n let disposeSection: (() => void) | undefined\n let disposeRoutes: (() => void) | undefined\n\n const sync = (): void => {\n if (disposeSection !== undefined) {\n disposeSection()\n disposeSection = undefined\n }\n if (disposeRoutes !== undefined) {\n disposeRoutes()\n disposeRoutes = undefined\n }\n const value = resolve()\n if (!(current().enabled ?? true)) return\n if (current().announceToAgent ?? DEFAULT_ANNOUNCE) {\n disposeSection = ctx.systemPrompt.section({\n name: 'plugin:dsh-novel-forge',\n order: SECTION_ORDER,\n text: NOVEL_GUIDANCE,\n })\n }\n const routes = makeRoutes({ ctx, getConfig: resolve, patchConfig })\n disposeRoutes = ctx.effect(\n () => {\n const disposers = routes.map(route => ctx.webServer.register(route))\n return () => { for (const dispose of disposers) dispose() }\n },\n 'dsh-novel-forge: routes',\n )\n void value\n }\n\n installSettingsSection(ctx, NOVEL_SETTINGS_NAMESPACE, Config, config ?? {}, {\n setSource: (source) => {\n current = source\n sync()\n },\n onChange: sync,\n })\n\n // 运行时 skill:章节批量生产与值守处理(只在本插件环境可用)。\n // 通过 ctx.get('skills') 获取注册表(服务存在时注册,缺失则跳过,不影响其他能力)。\n const skillsService = ctx.get('skills') as { register?: (skill: { name: string; description: string; content: string }) => () => void } | undefined\n if (skillsService?.register !== undefined) {\n const disposeSkill = skillsService.register({\n name: 'novel-forge-chapter-batch',\n description: '批量生成小说章节并值守处理审稿未过的章节(豁免/按意见修订/验证模式/重新生成),依赖 dsh-novel-forge 的 /api/dsh-novel-forge/* 路由。',\n content: [\n '# 小说章节批量生产与值守处理',\n '',\n '## 0. 值守纪律(最高优先级,违反即空转)',\n '1. 启动后台任务后立即停下,不轮询、不连续 wait、不做无意义动作——后台任务完成时运行时自动通知。',\n '2. 只有收到「任务完成」通知或用户新消息时,才继续下一步(读结果→处理未过→汇报)。',\n '3. 等待期间可做与当前任务无关的其他有用工作,但不得为等任务而空转。',\n '4. 任务因 web 重启中断时:待 3080 恢复后,复位卡死章节(generating/error → reset)再续跑,并向用户说明中断原因。',\n '',\n '## 1. 前置检查',\n '1. `GET /api/dsh-novel-forge/status` 确认服务在跑,读项目章节数。',\n '2. 列出目标区间 pending 章节号,避免重复生成已处理章节。',\n '3. **串行执行,禁止并行写 project.json**(并发会互相覆盖状态,实测教训)。',\n '',\n '## 2. 批量生成',\n '逐章串行调用 `POST /generate` `{ chapterNo, skipReview: false }`(走完整质量门:生成→摘要+编年录→审稿→复盘)。',\n '响应为 NDJSON,找 review 帧取 score/passed。每章 2-5 分钟;失败重试 1 次;后台跑并告知预计时长。',\n '用 Node 脚本(fetch 逐章循环),避免 PowerShell 转义坑,用完删除。',\n '',\n '## 3. 未过章节分级处理',\n '### A. 无 high → 豁免通过:`POST /chapter/approve`(主观项不磨)',\n '### B. 有 high 且明确 → 按意见修订 + 验证模式:',\n '1. 拼指令 `按审稿意见修订(优先处理):\\n[severity] item → suggestion`(high 优先,无 high 取前 3 medium)',\n '2. `POST /rewrite` 产草稿;3. `POST /chapter/check` 带 `previousReport` 走验证模式(只核对原意见解决+只挑新增 high)',\n '4. 判定 `passed || 无 high` 可接受;5. `POST /draft/apply` 带 passed 报告落盘 approved',\n '6. 不可接受 → 第二轮修订(指令更精确)→ 再验证;每章最多修 2 轮,仍不过保留草稿待人工',\n '### C. 结构性 high(修订改不好)→ `POST /draft/discard` 后 `POST /generate` 重写,剩主观项再走 A',\n '### D. error 状态 → `POST /chapter/reset` 后 `POST /generate`',\n '注意:approved 但 review 有 high 的保留不动;修订指令越精确越有效(具体数字/行为一次就过)。',\n '',\n '## 4. 收尾',\n '`GET /status` 验证目标区间全 approved;可选刷新剧情线(`POST /plotlines` op=refresh,注意只读最近 8 章摘要);汇报通过/未过/失败与遗留项。',\n '',\n '## 5. 已知陷阱',\n '- 并发写 project.json 互相覆盖 → 必须串行',\n '- rewrite 草稿可能偶发不落盘 → 应用前检查 pendingDraft,不存在则重跑',\n '- PowerShell 调 API 引号/中文转义是坑 → 用 Node 脚本',\n '- 验证模式 500 偶发 → 重试一次',\n ].join('\\n'),\n })\n ctx.effect(() => disposeSkill, 'dsh-novel-forge: skill')\n }\n\n // Initial registration from the composition entry.\n sync()\n}\n"],"mappings":";;;;;;;;;;;AAgBA,MAAa,0BAA2C;CACtD;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAM;EAAI;EACnC,YAAY;GACV;GACA;GACA;EACF;EACA,eAAe,CACb,oBACA,2BACF;EACA,eAAe,CACb,kBACA,eACF;EACA,aAAa,CACX,sBACA,gBACF;EACA,uBAAuB;GAAC;GAAU;GAAW;EAAW;CAC1D;CACA;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAM;EAAI;EACnC,YAAY;GACV;GACA;GACA;EACF;EACA,eAAe,CACb,4BACA,gBACF;EACA,eAAe,CACb,yBACA,iBACF;EACA,aAAa,CACX,gBACA,eACF;EACA,uBAAuB;GAAC;GAAa;GAAU;GAAY;GAAU;EAAQ;CAC/E;CACA;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAM;EAAI;EACnC,YAAY;GACV;GACA;GACA;EACF;EACA,eAAe,CACb,oBACA,kBACF;EACA,eAAe,CACb,qBACA,aACF;EACA,aAAa,CACX,oBACA,cACF;EACA,uBAAuB;GAAC;GAAa;GAAU;GAAY;EAAQ;CACrE;CACA;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAM;EAAI;EACnC,YAAY;GACV;GACA;GACA;EACF;EACA,eAAe,CACb,qBACA,aACF;EACA,eAAe,CACb,iBACA,iBACF;EACA,aAAa,CACX,qBACA,cACF;EACA,uBAAuB;GAAC;GAAU;GAAU;GAAW;EAAU;CACnE;CACA;EACE,KAAK;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,kBAAkB;GAAC;GAAM;GAAM;EAAI;EACnC,YAAY,CACV,gCACA,gBACF;EACA,eAAe,CACb,yBACF;EACA,eAAe,CACb,kBACA,WACF;EACA,aAAa,CACX,mBACA,SACF;EACA,uBAAuB;GAAC;GAAW;GAAW;EAAQ;CACxD;CACA;EACE,KAAK;EACL,MAAM;EACN,aA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"}