Skill: q7766206/character-profile-cn (version 1.0.0)

--- name: character-profile description: "Novel Character Profile Builder (小说人物档案创建工具) — A bilingual CN/EN skill for creating structured, detailed character profiles for fiction writing. Generates complete markdown profiles including backstory, personality, relationships, character arcs, and consistency checks. Supports protagonist, antagonist, and supporting character templates with built-in conflict detection and relationship matrix tools. Ideal for web novel (网文), fantasy, romance, and literary fiction authors." --- # 小说人物档案创建工具 ## 概述 本skill帮助小说作者创建结构化的人物角色档案，以markdown格式输出。适用于小说创作前期的人物设定阶段，确保角色设定完整、一致，为故事创作奠定基础。 ## 快速开始 当用户需要创建人物档案时： 0. **设置工作目录**：访问用户工作目录，并切换到该目录 1. **收集角色信息**：询问用户角色的核心信息 2. **选择模板类型**：根据角色类型选择合适的模板 3. **填充详细信息**：逐步引导用户完善各个字段 4. **生成markdown档案**：输出格式化的markdown文档 ## 核心工作流程 ### 1. 确定角色类型 首先识别角色在故事中的定位： - **主角**：故事核心，需要最详细的档案 - **重要配角**：关键支持角色，需要较详细档案 - **次要角色**：功能性角色，需要基本档案 - **反派**：对立角色，需要动机和背景深度分析 ### 2. 信息收集顺序 按照以下逻辑顺序收集信息： 1. **基础身份**：姓名、年龄、性别、职业等 2. **外在特征**：外貌、着装、举止 3. **内在特质**：性格、价值观、信仰 4. **背景故事**：过去经历、关键事件 5. **关系网络**：与其他角色的联系 6. **故事功能**：角色弧线、目标、冲突 ### 3. 档案结构 所有档案都包含以下核心部分： ```markdown # [角色姓名] - 角色档案 ## 基本信息 - **姓名**： - **年龄**： - **性别**： - **职业/身份**： - **故事中的角色**： ## 外貌特征 - **整体印象**： - **面部特征**： - **身材体型**： - **着装风格**： - **标志性特征**： ## 性格特点 - **核心性格**： - **优点**： - **缺点**： - **价值观**： - **恐惧**： - **渴望**： ## 背景故事 - **出身背景**： - **关键经历**： - **转折点**： - **未解之谜**： ## 人物关系 - **与主角关系**： - **重要关系人**： - **敌对关系**： - **情感羁绊**： ## 故事发展 - **角色目标**： - **内在冲突**： - **外在冲突**： - **发展弧线**： - **可能的结局**： ## 创作笔记 - **灵感来源**： - **象征意义**： - **潜在发展**： ``` ## 详细指南 ### 针对不同角色类型的调整 #### 主角模板 - 需要最完整的背景故事和内心冲突 - 详细的发展弧线规划 - 复杂的动机层次 - 参考：[主角详细指南](references/protagonist.md) #### 反派模板 - 重点刻画动机的合理性 - 详细的对立逻辑 - 潜在的救赎可能性 - 参考：[反派塑造指南](references/antagonist.md) #### 配角模板 - 突出功能性特点 - 简化的背景故事 - 明确的故事作用 - 参考：[配角设计指南](references/supporting.md) ### 高级技巧 #### 角色一致性检查 创建档案后，进行以下检查： 1. **动机一致性**：行为是否与动机匹配 2. **发展合理性**：变化是否有合理铺垫 3. **关系逻辑性**：人物关系是否自然 4. **冲突有效性**：冲突是否推动故事 #### 角色关系矩阵 对于多个角色，创建关系矩阵： - 情感强度 - 冲突程度 - 信任等级 - 依赖关系 ## 使用示例 ### 示例1：创建奇幻小说主角 ``` 用户：我需要创建一个奇幻小说的主角，年轻法师，出身平凡但有特殊血统 步骤： 1. 识别为"主角"类型 2. 使用主角模板 3. 重点询问：特殊血统的设定、法师能力的限制、成长路径 4. 生成完整档案，强调魔法系统和成长弧线 ``` ### 示例2：创建都市情感故事配角 ``` 用户：需要一个都市故事的女主角闺蜜，性格开朗但有自己的秘密 步骤： 1. 识别为"重要配角"类型 2. 使用配角模板，调整情感深度 3. 重点询问：秘密的内容、与女主的关系、独立故事线 4. 生成档案，平衡功能性和深度 ``` ## 输出文件处理 生成的markdown档案可以： 1. 直接保存为`.md`文件 2. 集成到小说写作软件 3. 作为角色卡片打印使用 4. 后续更新和迭代 ## 常见问题 ### Q: 如何避免角色模板化？ A: 在每个部分加入独特细节，寻找角色的矛盾点和非常规特征。 ### Q: 档案应该多详细？ A: 根据角色重要性调整，主角可能需要5000+字，配角500-1000字。 ### Q: 如何处理角色发展？ A: 在"故事发展"部分规划多个阶段的状态变化。 ## 参考文件 - [主角详细指南](references/protagonist.md) - 主角塑造的深入指导 - [反派塑造指南](references/antagonist.md) - 反派角色的创作要点 - [配角设计指南](references/supporting.md) - 配角的功能性和深度平衡 - [关系网络设计](references/relationships.md) - 角色关系矩阵构建方法 ## 最佳实践 1. **从核心概念开始**：先确定角色的核心理念 2. **逐步丰富细节**：层层添加具体特征 3. **检查逻辑一致性**：确保所有元素协调 4. **预留发展空间**：为故事发展留有余地 5. **迭代更新**：随着写作进展更新档案 ## 增强功能 (v1.1+) ### 概述 从v1.1版本开始，工具增加了LoreBible管理和冲突检测功能，帮助作者维护统一的故事设定宇宙。 ### 核心功能 #### 1. LoreBible目录管理 - **工作目录支持**：使用`--workspace`参数指定LoreBible工作目录 - **自动目录创建**：自动创建`00_Prepare`、`02_LoreBible/Characters`等标准目录结构 - **现有角色扫描**：自动扫描和解析现有角色档案，构建角色索引 #### 2. 冲突检测 - **重复角色检测**：检测姓名重复或高度相似的角色 - **常识校验**：检查年龄合理性、时间线一致性等常识错误 - **关系冲突检测**：检测角色关系中的矛盾和不一致 - **冲突报告**：生成详细的冲突报告和建议解决方案 #### 3. 会话管理 - **临时文件系统**：用户确认前在`00_Prepare`目录保存临时档案 - **用户确认流程**：交互式展示冲突，用户确认后移动到最终目录 - **会话状态持久化**：支持断点续传，自动清理过期会话 #### 4. 子代理工作流 - **任务分解**：将角色创建过程分解为原子任务 - **依赖管理**：自动处理任务依赖关系 - **错误恢复**：任务失败时自动重试，提供详细错误报告 ### 使用方法 #### 命令行增强模式 ```bash # 基本用法（传统模式） python scripts/generate_profile.py --name "张三" --age "25" --gender "男" # 增强模式（推荐） python scripts/generate_profile.py --name "李四" --age "30" --workspace "/path/to/lorebible" # 跳过用户确认 python scripts/generate_profile.py --name "王五" --workspace "/path/to/lorebible" --no-confirm # 指定模板类型 python scripts/generate_profile.py --name "赵六" --type "protagonist" --workspace "/path/to/lorebible" ``` #### 目录结构 ``` 工作目录/ ├── 00_Prepare/ # 临时档案目录 ├── 01_Research/ # 研究资料目录（可选） └── 02_LoreBible/ ├── Characters/ # 最终角色档案目录 ├── Locations/ # 地点设定目录（可选） ├── Organizations/ # 组织设定目录（可选） └── Timeline/ # 时间线目录（可选） ``` #### 子代理工作流 ```bash # 运行完整工作流 python scripts/subagent_orchestrator.py "/path/to/lorebible" "character_creation" # 运行快速创建模式 python scripts/subagent_orchestrator.py "/path/to/lorebible" "quick_creation" ``` ### 配置文件 #### 校验规则配置 (`config/validation_rules.json`) ```json { "rules": [ { "id": "age_realistic", "name": "年龄合理性", "description": "检查年龄是否在合理范围内", "condition": "age.isdigit() and not (0 <= int(age) <= 150)", "severity": "warning" } ] } ``` #### 工作流配置 (`config/workflow_tasks.json`) ```json { "workflows": { "character_creation": { "name": "角色创建工作流", "tasks": [ { "id": "init_workspace", "name": "初始化工作空间", "agent_type": "lore_bible_manager" } ] } } } ``` ### 新脚本模块 1. **`lore_bible_manager.py`** - LoreBible目录管理和角色扫描 2. **`conflict_detector.py`** - 冲突检测和常识校验 3. **`profile_session.py`** - 会话管理和用户确认流程 4. **`subagent_orchestrator.py`** - 子代理工作流协调 ### 向后兼容性 - 传统模式：不指定`--workspace`参数时，使用传统生成模式 - 交互模式：增强模式也支持交互式创建 - 输出文件：传统模式输出到当前目录，增强模式输出到LoreBible目录 ### 故障排除 #### 常见问题 1. **导入错误**：确保所有新脚本文件在`scripts/`目录中 2. **目录权限**：确保工作目录有读写权限 3. **配置文件缺失**：`config/`目录需要包含`validation_rules.json`和`workflow_tasks.json` #### 日志查看 启用详细日志： ```python import logging logging.basicConfig(level=logging.DEBUG) ``` ### 未来计划 - 图形用户界面支持 - 云同步功能 - AI辅助角色生成 - 跨作品角色库管理 --- **版本历史**: - v1.0 (初始版本): 基础角色档案生成功能 - v1.1 (当前版本): LoreBible管理、冲突检测、会话管理、子代理工作流

path: assets/example_antagonist.md
content: # 夜影 - 角色档案

> 生成时间：2025-01-26 11:15:00
> 模板类型：反派模板

## 基本信息
- **姓名**：夜影（本名：陈无涯）
- **年龄**：42岁
- **性别**：男
- **职业/身份**：暗影议会议长/前魔法管理局高级官员
- **故事中的角色**：主要反派

## 外貌特征
- **整体印象**：威严冷峻，如同黑夜本身凝聚成人形，眼神深邃如渊
- **面部特征**：轮廓分明，剑眉星目但总笼罩着一层阴影，右脸颊有一道淡淡的魔法灼伤疤痕
- **身材体型**：身高185cm，体型修长挺拔，举止间带有军人的精准和优雅
- **着装风格**：永恒不变的黑色西装或长袍，剪裁完美，除了左胸一枚银色的暗影徽章外无任何装饰
- **标志性特征**：说话时喜欢轻轻转动左手无名指上的黑曜石戒指，在施展强大魔法时双眼会变成纯黑色

## 性格特点
- **核心性格**：冷静、理智、极端理想主义者
- **优点**：智慧超群、意志坚定、极具领导力、对目标无限执着
- **缺点**：缺乏同理心、手段冷酷、难以信任他人、无法容忍不确定性
- **价值观**：秩序高于一切，为了更大的利益可以牺牲少数，力量是实现理想的唯一途径
- **恐惧**：魔法彻底失控导致世界毁灭，自己的理念被证明是错误的
- **渴望**：建立一个完全由理性控制的魔法世界，消除所有不可控因素

## 核心理念
- **世界观**：世界本质是混沌的，魔法是混沌的具现，唯有建立绝对秩序才能避免毁灭
- **核心信念**：情感和欲望是魔法的污染源，真正的魔法应该是纯粹、可控、可计算的力量
- **正义观**：能够保护最多数人、带来最大稳定的就是正义，过程的手段无关紧要
- **变革愿景**：建立魔法联邦，将所有魔法师纳入统一管理，消除私自使用魔法的现象

## 动机发展
- **初始状态**：魔法管理局的优秀官员，相信体制可以规范魔法使用
- **转折事件**：
  - 妻子在魔法失控事件中丧生，管理局因程序拖延未能及时救援
  - 亲眼目睹一个天赋极高的年轻魔法师因情感失控毁灭了整个村庄
  - 发现管理局高层腐败，为了利益掩盖多起魔法事故
- **理念形成**：现有体制无法真正控制魔法，需要更彻底、更强硬的解决方案
- **行动决定**：离开管理局，成立暗影议会，开始推行自己的理念

## 镜像对比
- **相似点**：
  - 都曾相信体制的力量
  - 都拥有极高的魔法天赋
  - 都经历过重要之人的失去
  - 都在寻找控制魔法的方法
- **分歧点**：
  - 林晓风相信理解和共存，夜影相信控制和秩序
  - 林晓风重视个体价值，夜影重视集体利益
  - 林晓风愿意承担风险给予信任，夜影只相信制度和规则
- **对立逻辑**：代表了魔法世界两种根本对立的治理哲学
- **潜在转化**：如果看到自己的方法造成了更大的伤害，可能会重新审视理念，但转变极为困难

## 资源能力
- **核心团队**：
  - **月华**：副议长，战术大师，夜影最信任的副手
  - **铁面**：执行部长，前特种部队指挥官，负责武力行动
  - **智瞳**：情报部长，信息控制专家，掌握大量秘密
- **盟友势力**：
  - 部分对现状不满的魔法师家族
  - 追求稳定秩序的世俗政府官员
  - 受够魔法失控威胁的普通人社区代表
- **影响范围**：
  - 魔法界的暗中控制网络
  - 世俗政府中的秘密支持者
  - 多个关键魔法资源点的实际控制
- **弱点环节**：
  - 过度依赖中央指挥，中层缺乏自主性
  - 理念过于极端，难以获得广泛支持
  - 个人情感创伤导致的盲点

## 故事发展
- **角色目标**：
  - 短期：获取远古魔法神器"秩序之眼"
  - 中期：推翻现有魔法管理局，建立暗影议会主导的新秩序
  - 长期：在全球范围内实施魔法管制，消除所有魔法自由使用
- **内在冲突**：
  - 理性告诉自己需要冷酷，但内心仍有对妻子的愧疚
  - 知道自己的手段残忍，但相信这是必要的代价
  - 渴望有人理解自己的理念，又害怕真正的亲密连接
- **外在冲突**：
  - 与魔法管理局的正面对抗
  - 与林晓风等自由魔法师的理念斗争
  - 组织内部不同派系的权力博弈
- **发展弧线**：
  - **起始**：坚定执行计划，相信自己的道路唯一正确
  - **考验**：计划遭遇重大挫折，手下出现背叛，开始怀疑方法
  - **挣扎**：在坚持理念和调整方法间摇摆，与林晓风多次交锋
  - **抉择**：面临最终选择，是坚持到底还是承认错误
  - **结局**：根据选择走向不同结局（毁灭/救赎/转变）
- **可能的结局**：
  - **悲剧结局**：计划成功但失去一切，发现建立的新秩序同样腐败
  - **救赎结局**：在关键时刻醒悟，牺牲自己阻止更坏的结果
  - **转变结局**：理念转变，成为改革者而非独裁者
  - **坚持结局**：坚持到底，成为新一代的"必要之恶"

---

## 档案元数据
- **角色类型**：反派模板
- **创建时间**：2025-01-26 11:15:00
- **状态**：完成
- **版本**：1.1

path: assets/example_protagonist.md
content: # 林晓风 - 角色档案

> 生成时间：2025-01-26 10:30:00
> 模板类型：主角模板

## 基本信息
- **姓名**：林晓风
- **年龄**：24岁
- **性别**：男
- **职业/身份**：年轻法师/古籍研究员
- **故事中的角色**：主角

## 外貌特征
- **整体印象**：清瘦儒雅，眼神中带有书卷气与隐约的忧郁
- **面部特征**：五官清秀，鼻梁高挺，时常微微蹙眉思考，左眼角有一颗浅褐色小痣
- **身材体型**：身高178cm，体型偏瘦但并非孱弱，长期的古籍搬运工作让他有不错的体力
- **着装风格**：偏好深色系长袍，样式简洁但有精致的暗纹，总带着一副细框眼镜
- **标志性特征**：左手手背有一道淡银色的魔法印记，在情绪激动时会微微发光

## 性格特点
- **核心性格**：内省、执着、善良但有些优柔寡断
- **优点**：博学多识、细心谨慎、有同理心、坚韧不拔
- **缺点**：过度思虑、缺乏自信、不擅表达情感、有时过于理想化
- **价值观**：相信知识的力量，认为理解比征服更重要，重视生命的尊严
- **恐惧**：无法保护所爱之人，让老师失望，自己的力量失控伤害他人
- **渴望**：真正理解魔法的本质，找到自己在世界中的位置，获得内心的平静

## 背景故事
- **出身背景**：出生于学者世家，父母都是皇家学院的教授，在学术氛围中长大
- **关键经历**：
  - 12岁时无意中激活了家传的古籍，发现了自己的魔法天赋
  - 15岁拜入隐世大法师门下，开始系统学习魔法
  - 20岁时老师神秘失踪，只留下一本未完成的魔法笔记
  - 22岁进入皇家古籍馆工作，暗中调查老师失踪的真相
- **转折点**：在古籍馆发现一本记载着禁忌魔法的古籍，意识到老师的失踪与一个古老的神秘组织有关
- **未解之谜**：父母的真实身份是什么？老师为何突然失踪？手背上的魔法印记来自何处？

## 动机层次
- **表层目标**：找到失踪的老师，解开古籍中的秘密
- **情感需求**：获得认可和归属感，不再感到自己是世界的异类
- **存在需求**：理解自己为何拥有魔法天赋，找到生命的意义
- **未意识需求**：渴望被需要、被依赖，证明自己的价值

## 核心身份
- **本质自我**：一个渴望理解和被理解的求知者
- **社会面具**：沉稳内敛的古籍研究员
- **理想自我**：能够掌控魔法力量，保护所爱之人的强大法师
- **恐惧自我**：力量失控的怪物，让所有人失望的失败者

## 人物关系
- **与主角关系**：本故事的主角
- **重要关系人**：
  - **苏沐雨**：青梅竹马，现在的同事，暗恋对象，不知道他的魔法身份
  - **玄清法师**：失踪的老师，如父如师的存在
  - **陆明轩**：古籍馆馆长，知道他的秘密并暗中保护
  - **影月**：神秘组织的女刺客，亦敌亦友的复杂关系
- **敌对关系**：
  - **暗影议会**：追求禁忌魔法的神秘组织
  - **陈司长**：魔法管理局官员，怀疑他的身份并处处刁难
- **情感羁绊**：
  - 对苏沐雨：暗恋但不敢表白，害怕自己的秘密会伤害她
  - 对玄清法师：敬爱如父，对其失踪怀有深深的愧疚
  - 对影月：初为敌人，后逐渐理解彼此的立场，产生微妙的情感

## 故事发展
- **角色目标**：
  - 短期：解开老师留下的笔记秘密
  - 中期：查明暗影议会的真正目的
  - 长期：找到魔法与人类共存的平衡之道
- **内在冲突**：
  - 求知欲与安全顾虑的矛盾
  - 对力量的控制与恐惧
  - 个人感情与责任的抉择
- **外在冲突**：
  - 与暗影议会的魔法对抗
  - 躲避魔法管理局的追查
  - 保护朋友不卷入危险
- **发展弧线**：
  - **起始**：谨慎低调，隐藏力量，独自承担秘密
  - **成长**：逐渐信任他人，组建自己的团队，学会合作
  - **考验**：面临重大抉择，在力量、责任、感情间权衡
  - **转变**：从被动防御到主动出击，从隐藏到接纳自我
  - **完成**：找到内心的平衡，明确自己的道路
- **可能的结局**：
  - 理想结局：揭穿暗影议会的阴谋，找到老师，与苏沐雨在一起
  - 牺牲结局：为保护他人牺牲自己，成为传说
  - 开放结局：继续游走于两个世界之间，寻找新的平衡

## 创作笔记
- **灵感来源**：东方玄幻与都市奇幻的结合，探讨现代社会中传统与现代的冲突
- **象征意义**：
  - 魔法印记：天赋与诅咒的双重象征
  - 古籍：传统知识与现代价值的桥梁
  - 眼镜：理性与感性的分界
- **潜在发展**：
  - 魔法印记的真正来源可能是某个古老血脉
  - 父母可能与暗影议会有某种联系
  - 苏沐雨可能也有未被发现的神秘能力

---

## 档案元数据
- **角色类型**：主角模板
- **创建时间**：2025-01-26 10:30:00
- **状态**：完成
- **版本**：1.2

path: assets/example_supporting.md
content: # 苏沐雨 - 角色档案

> 生成时间：2025-01-26 11:45:00
> 模板类型：配角模板

## 基本定位
- **功能类型**：盟友型配角 + 潜在爱情对象
- **重要性级别**：一级配角（重要配角）
- **与主角关系**：青梅竹马、同事、暗恋对象
- **核心功能**：提供情感支持、推动主角情感发展、连接世俗世界

## 独立身份
- **个人目标**：
  - 成为顶尖的古籍修复专家
  - 解开父母失踪的真相（与主线潜在连接点）
  - 找到真正理解自己、能坦诚相待的伴侣
- **生活背景**：
  - 书香门第，父母都是考古学家，在她16岁时在一次考古事故中失踪
  - 由祖母抚养长大，继承了父母对古籍的热爱
  - 大学攻读古籍保护专业，毕业后进入皇家古籍馆工作
- **价值观**：
  - 相信真相和知识的力量
  - 重视人与人之间的真诚和信任
  - 认为保护文化遗产是每个人的责任
- **秘密或矛盾**：
  - 隐约感觉到林晓风在隐藏什么，但尊重他的隐私没有追问
  - 自己也在暗中调查父母失踪的真相，怀疑那不是普通事故
  - 对林晓风有好感但不确定他的心意，同时有另一个追求者（陆明轩的侄子）

## 功能性设计
- **推动剧情的方式**：
  1. 情感支线：与林晓风的感情发展推动主角的情感成长
  2. 线索提供：通过古籍修复工作发现关键线索
  3. 危机制造：因接近真相而陷入危险，需要主角救援
  4. 价值观对比：代表世俗、理性的视角，与魔法世界形成对比
- **服务主角的方式**：
  1. **情感支持**：在林晓风迷茫时给予安慰和建议
  2. **现实锚点**：提醒主角普通人的生活和价值观
  3. **技能补充**：古籍修复和鉴定能力补充主角的魔法知识
  4. **信任考验**：主角需要决定是否向她坦白秘密
- **独特价值**：
  - 连接魔法世界和世俗世界的桥梁
  - 体现"知识不分魔法与科学"的主题
  - 提供温暖、稳定的情感基调
- **退出时机**：
  - 中期可能因发现真相暂时离开，给主角成长空间
  - 后期回归，在最终决战中发挥关键作用
  - 结局根据感情线发展决定去向

## 关系发展
- **初始关系**：亲近的青梅竹马，默契的工作伙伴，彼此有好感但未挑明
- **关系转折点**：
  1. **发现端倪**：开始察觉林晓风的异常，关系出现微妙距离
  2. **危机时刻**：因调查父母失踪陷入危险，被林晓风以魔法救下
  3. **真相揭露**：林晓风坦白魔法身份，关系面临信任考验
  4. **共同冒险**：决定帮助林晓风，关系从青梅竹马升级为战友
  5. **情感抉择**：在感情上面临选择，决定彼此的心意
- **最终关系**：
  - 理想线：成为情侣，共同面对魔法世界的挑战
  - 友情线：保持深厚友谊，各自找到适合的伴侣
  - 牺牲线：为保护对方或理想牺牲，成为主角永远的遗憾
- **关系影响**：
  - 促使林晓风学会信任和敞开心扉
  - 让主角在魔法和世俗间找到平衡
  - 为主题增添"爱与责任"的维度

## 发展可能性
- **潜在成长**：
  1. 从被保护者成长为能够保护他人的强者
  2. 发现自己的潜在能力（可能与父母的研究有关）
  3. 从古籍专家成长为连接两个世界的桥梁人物
- **故事线扩展**：
  - **父母线**：父母失踪与暗影议会的早期实验有关
  - **能力线**：遗传了父母对古魔法的特殊感应能力
  - **职业线**：建立魔法古籍保护中心，成为新领域的开创者
- **意外发展**：
  - 可能短暂被暗影议会利用或控制
  - 可能发现自己是某个古老魔法血脉的后裔
  - 可能在关键时刻做出出人意料的选择
- **结局设想**：
  - **圆满结局**：与林晓风在一起，共同建立魔法与人类共存的新秩序
  - **独立结局**：成为独立的古籍保护专家，与魔法世界保持合作但不过度深入
  - **传承结局**：继承父母的遗志，揭开某个重大秘密，成为新一代的守护者
  - **开放结局**：继续探索两个世界的边界，寻找自己的道路

---

## 档案元数据
- **角色类型**：配角模板
- **创建时间**：2025-01-26 11:45:00
- **状态**：完成
- **版本**：1.0

path: config/validation_rules.json
content: {
  "rules": [
    {
      "id": "age_realistic",
      "name": "年龄合理性",
      "description": "检查年龄是否在合理范围内（0-150岁）",
      "condition": "age.isdigit() and not (0 <= int(age) <= 150)",
      "severity": "warning",
      "enabled": true,
      "category": "common_sense"
    },
    {
      "id": "age_format",
      "name": "年龄格式",
      "description": "年龄应为数字或数字范围",
      "pattern": "^\\d+(\\s*-\\s*\\d+)?$",
      "severity": "info",
      "enabled": true,
      "category": "common_sense"
    },
    {
      "id": "name_length",
      "name": "姓名长度",
      "description": "角色姓名应在2-20个字符之间",
      "condition": "len(name) < 2 or len(name) > 20",
      "severity": "warning",
      "enabled": true,
      "category": "common_sense"
    },
    {
      "id": "gender_valid",
      "name": "性别有效性",
      "description": "性别应为常见值",
      "pattern": "^(男|女|其他|未指定|非二元|未知)$",
      "severity": "info",
      "enabled": true,
      "category": "common_sense"
    },
    {
      "id": "occupation_length",
      "name": "职业描述长度",
      "description": "职业/身份描述不应过长",
      "condition": "len(occupation) > 100",
      "severity": "warning",
      "enabled": true,
      "category": "common_sense"
    },
    {
      "id": "role_required",
      "name": "角色定位",
      "description": "故事中的角色不应为空",
      "condition": "not role or role.strip() == ''",
      "severity": "warning",
      "enabled": true,
      "category": "common_sense"
    },
    {
      "id": "duplicate_name_strict",
      "name": "严格重复姓名检测",
      "description": "检测完全相同的姓名（忽略大小写和空格）",
      "severity": "error",
      "enabled": true,
      "category": "duplicate"
    },
    {
      "id": "similar_name",
      "name": "相似姓名检测",
      "description": "检测高度相似的姓名",
      "severity": "warning",
      "enabled": true,
      "category": "duplicate"
    },
    {
      "id": "timeline_consistency",
      "name": "时间线一致性",
      "description": "检查关键事件时间线是否合理",
      "severity": "warning",
      "enabled": true,
      "category": "timeline"
    },
    {
      "id": "relationship_symmetry",
      "name": "关系对称性",
      "description": "检查角色关系是否相互一致",
      "severity": "warning",
      "enabled": true,
      "category": "relationships"
    }
  ],
  "metadata": {
    "version": "1.0",
    "created": "2026-01-26",
    "description": "角色档案常识校验规则"
  }
}

path: config/workflow_tasks.json
content: {
  "workflows": {
    "character_creation": {
      "name": "角色创建工作流",
      "description": "完整的角色创建和验证流程",
      "tasks": [
        {
          "id": "init_workspace",
          "name": "初始化工作空间",
          "description": "验证和创建目录结构",
          "agent_type": "lore_bible_manager",
          "inputs": ["workspace"],
          "outputs": ["directory_status", "missing_dirs"],
          "timeout": 30,
          "retry_count": 2
        },
        {
          "id": "scan_existing",
          "name": "扫描现有角色",
          "description": "扫描现有角色档案，构建索引",
          "agent_type": "lore_bible_manager",
          "inputs": ["workspace"],
          "outputs": ["character_index", "character_count"],
          "depends_on": ["init_workspace"],
          "timeout": 60
        },
        {
          "id": "generate_profile",
          "name": "生成角色档案",
          "description": "根据模板生成角色档案内容",
          "agent_type": "profile_generator",
          "inputs": ["character_data", "template_type"],
          "outputs": ["profile_content"],
          "timeout": 30
        },
        {
          "id": "save_temp",
          "name": "保存临时档案",
          "description": "将档案保存到临时目录",
          "agent_type": "profile_session",
          "inputs": ["profile_content", "character_name", "workspace"],
          "outputs": ["temp_file_path"],
          "depends_on": ["init_workspace", "generate_profile"],
          "timeout": 30
        },
        {
          "id": "detect_conflicts",
          "name": "检测冲突",
          "description": "检测与现有角色的冲突和常识错误",
          "agent_type": "conflict_detector",
          "inputs": ["character_data", "character_index"],
          "outputs": ["conflicts", "is_valid"],
          "depends_on": ["scan_existing"],
          "timeout": 45
        },
        {
          "id": "user_review",
          "name": "用户审核",
          "description": "向用户展示冲突并获取确认",
          "agent_type": "profile_session",
          "inputs": ["conflicts", "temp_file_path"],
          "outputs": ["user_confirmed", "user_notes"],
          "depends_on": ["detect_conflicts", "save_temp"],
          "timeout": 300,
          "interactive": true
        },
        {
          "id": "move_final",
          "name": "移动到最终目录",
          "description": "用户确认后移动档案到Characters目录",
          "agent_type": "profile_session",
          "inputs": ["temp_file_path", "character_name", "user_confirmed"],
          "outputs": ["final_file_path"],
          "depends_on": ["user_review"],
          "condition": "user_confirmed == true",
          "timeout": 30
        },
        {
          "id": "cleanup",
          "name": "清理临时文件",
          "description": "清理会话和临时文件",
          "agent_type": "profile_session",
          "inputs": ["session_id", "workspace"],
          "outputs": ["cleaned_count"],
          "depends_on": ["move_final"],
          "timeout": 30
        }
      ]
    },
    "quick_creation": {
      "name": "快速创建模式",
      "description": "简化版本，跳过部分检查",
      "tasks": [
        {
          "id": "init_workspace",
          "name": "初始化工作空间",
          "description": "验证和创建目录结构",
          "agent_type": "lore_bible_manager",
          "inputs": ["workspace"],
          "outputs": ["directory_status"]
        },
        {
          "id": "generate_and_save",
          "name": "生成并保存",
          "description": "生成档案并直接保存到Characters目录",
          "agent_type": "profile_generator",
          "inputs": ["character_data", "template_type", "workspace"],
          "outputs": ["final_file_path"],
          "depends_on": ["init_workspace"]
        }
      ]
    }
  },
  "agents": {
    "lore_bible_manager": {
      "module": "scripts.lore_bible_manager",
      "class": "LoreBibleManager"
    },
    "conflict_detector": {
      "module": "scripts.conflict_detector",
      "class": "ConflictDetector"
    },
    "profile_session": {
      "module": "scripts.profile_session",
      "class": "ProfileSession"
    },
    "profile_generator": {
      "module": "scripts.generate_profile",
      "class": "CharacterProfileGenerator"
    }
  },
  "metadata": {
    "version": "1.0",
    "created": "2026-01-26",
    "description": "子代理任务工作流定义"
  }
}

path: references/antagonist.md
content: # 反派塑造指南

## 反派的核心原则

### 1. 合理性原则
- 反派的行为应有合理动机
- 目标应在其世界观内合理
- 手段应与其能力和资源匹配

### 2. 威胁性原则
- 对主角构成真实威胁
- 有能力实现其目标
- 能造成实质性后果

### 3. 深度原则
- 不应是纯粹的邪恶象征
- 应有可理解的动机
- 最好有某种程度的共情点

## 反派类型分类

### 1. 理念型反派
```
特征：
- 坚持某种理念或理想
- 认为自己的行为是必要的
- 可能曾是正面角色
- 理念本身可能有合理性

例子：
- 为"更大利益"牺牲个体
- 推行极端的社会改革
- 维护某种传统或秩序

塑造要点：
- 理念的逻辑性
- 从合理到极端的过程
- 与主角理念的对比
```

### 2. 创伤型反派
```
特征：
- 行为源于过去的创伤
- 动机是复仇或补偿
- 心理状态不稳定
- 有可同情的背景

例子：
- 家人受害后的复仇者
- 被背叛后的报复者
- 心理创伤导致的行为扭曲

塑造要点：
- 创伤的真实性
- 从受害者到加害者的转变
- 心理状态的描绘
```

### 3. 野心型反派
```
特征：
- 追求权力、财富、地位
- 明确的目标导向
- 理性的算计者
- 道德观念淡漠

例子：
- 政治野心家
- 商业掠夺者
- 权力追求者

塑造要点：
- 野心的根源
- 手段的合理性
- 代价的计算
```

### 4. 混沌型反派
```
特征：
- 追求混乱或破坏本身
- 无固定目标
- 享受过程的愉悦
- 心理异常状态

例子：
- 纯粹的破坏者
- 享受混乱的小丑型
- 心理变态者

塑造要点：
- 避免单纯的精神病标签
- 混乱的内在逻辑
- 对秩序的反抗本质
```

## 反派档案特殊字段

### 核心理念层
```markdown
## 核心理念
- **世界观**：如何看待世界和人性
- **核心信念**：坚信不疑的原则
- **正义观**：个人的正义标准
- **变革愿景**：希望创造的新秩序
```

### 动机发展史
```markdown
## 动机发展
- **初始状态**：成为反派前的状态
- **转折事件**：改变世界观的关键
- **理念形成**：核心理念的确立
- **行动决定**：开始行动的时点
```

### 与主角的镜像关系
```markdown
## 镜像对比
- **相似点**：与主角的共同之处
- **分歧点**：关键的选择分歧
- **对立逻辑**：为何成为对立面
- **潜在转化**：可能改变的可能性
```

## 反派能力与资源

### 能力设计原则
1. **与目标匹配**：能力应服务于其目标
2. **与理念匹配**：能力体现其世界观
3. **与威胁匹配**：足够对主角构成挑战
4. **与弱点匹配**：能力应有相应的弱点

### 资源网络
```markdown
## 资源网络
- **核心团队**：直接追随者
- **盟友势力**：利益共同体
- **影响范围**：控制或影响的领域
- **弱点环节**：依赖的关键点
```

## 反派与主角的关系动态

### 对立层次
1. **目标对立**：追求相互排斥的目标
2. **理念对立**：持有相反的世界观
3. **方法对立**：使用不同的手段
4. **存在对立**：本质上的不兼容

### 互动模式
- **直接对抗**：正面冲突
- **间接较量**：通过代理或策略
- **心理博弈**：心理层面的对抗
- **理念辩论**：价值观的争论

## 反派发展弧线

### 可能的弧线类型
1. **坚持到底**：始终坚持理念，最终失败
2. **理念动摇**：开始怀疑自己的道路
3. **转化救赎**：转变立场或获得救赎
4. **悲剧结局**：意识到错误但为时已晚

### 结局设计考虑
- **理念的考验**：核心理念是否经得起考验
- **选择的后果**：为其选择承担后果
- **影响的延续**：即使失败，影响是否延续
- **主题的体现**：结局如何体现故事主题

## 反派塑造检查表

### 动机合理性检查
- [ ] 动机有可理解的根源
- [ ] 目标在其世界观内合理
- [ ] 手段与目标匹配
- [ ] 有明确的得失计算

### 威胁性检查
- [ ] 对主角构成真实威胁
- [ ] 有能力实现部分目标
- [ ] 能造成实质性伤害
- [ ] 给主角带来成长压力

### 深度检查
- [ ] 不是单纯的邪恶象征
- [ ] 有可共情的元素
- [ ] 理念有一定的逻辑性
- [ ] 与主角形成有意义对比

## 常见问题与解决方案

### 问题：反派动机薄弱
**解决方案**：
1. 连接个人经历
2. 强化理念基础
3. 增加情感投入
4. 设置合理目标

### 问题：反派能力过强
**解决方案**：
1. 增加内在限制
2. 设置资源依赖
3. 创造性格弱点
4. 安排能力代价

### 问题：反派过于单薄
**解决方案**：
1. 添加矛盾特质
2. 设置人性时刻
3. 创造复杂关系
4. 安排理念冲突

## 优秀反派案例要点

### 案例1：理念型反派
- **理念**：清晰且有吸引力的世界观
- **转变**：从合理理念到极端实践的渐变
- **对比**：与主角理念形成思想交锋
- **结局**：理念被证伪但人物保持尊严

### 案例2：创伤型反派
- **创伤**：真实且有影响力的过去
- **扭曲**：合理情感的不合理表达
- **共情**：读者能理解其痛苦
- **悲剧**：可避免但不可避免的结局

### 案例3：镜像反派
- **相似**：与主角相似的起点
- **分歧**：关键时刻的不同选择
- **对比**：展示道路选择的后果
- **警示**：主角可能成为的样子

## 创作建议

1. **从理解开始**：先理解反派的视角
2. **寻找共情点**：即使不赞同，也要理解
3. **注重理念交锋**：真正的对立是价值观对立
4. **避免简单化**：复杂性增加真实感
5. **服务主题**：反派应体现故事的核心主题

## 反派与故事主题

### 主题体现方式
- **直接对抗**：反派代表主题的反面
- **极端体现**：反派体现主题的极端版本
- **扭曲反映**：反派是对主题的扭曲理解
- **必要挑战**：反派是主题必须面对的挑战

### 主题深化技巧
1. **让反派有道理**：其论点应有某种合理性
2. **让选择困难**：主角的选择不应显而易见
3. **让代价真实**：对抗反派应有真实代价
4. **让反思可能**：反派促使主角和读者反思

path: references/protagonist.md
content: # 主角塑造详细指南

## 主角的核心特征

### 1. 深度与复杂性
- **多层次动机**：表面目标 vs 深层需求
- **内在矛盾**：价值观冲突、情感纠葛
- **成长潜力**：明显的缺陷和改进空间

### 2. 读者连接点
- **可识别性**：读者能在某种程度上认同
- **情感投入**：激发读者的关心和共鸣
- **成长期待**：读者希望看到角色发展

## 主角档案的特殊字段

### 核心身份层
```markdown
## 核心身份
- **本质自我**：角色最根本的存在状态
- **社会面具**：对外展示的形象
- **理想自我**：渴望成为的样子
- **恐惧自我**：害怕变成的样子
```

### 动机层次
```markdown
## 动机层次
- **表层目标**：故事中明确追求的目标
- **情感需求**：内心深处渴望的情感满足
- **存在需求**：关于身份、意义的核心需求
- **未意识需求**：角色自己尚未察觉的需要
```

### 成长弧线
```markdown
## 成长弧线
- **起始状态**：故事开始时的状态
- **诱发事件**：促使改变的关键事件
- **抗拒改变**：对变化的抵抗和挣扎
- **突破时刻**：决定改变的转折点
- **新平衡态**：故事结束时的成长结果
```

## 主角类型参考

### 1. 英雄型主角
```
特征：
- 主动追求目标
- 道德感较强
- 承担社会责任
- 经历考验成长

关注点：
- 考验的合理性
- 成长的代价
- 道德困境
```

### 2. 反英雄型主角
```
特征：
- 非传统道德观
- 有缺陷但有能力
- 灰色地带行动
- 复杂动机

关注点：
- 魅力的来源
- 读者的容忍度
- 救赎的可能性
```

### 3. 成长型主角
```
特征：
- 初始能力不足
- 通过学习成长
- 心态转变
- 赢得认可

关注点：
- 成长的节奏
- 导师的作用
- 挫败的意义
```

### 4. 探索型主角
```
特征：
- 寻求真相/知识
- 挑战现有秩序
- 自我发现之旅
- 改变世界观

关注点：
- 发现的阶梯
- 认知的转变
- 代价与收获
```

## 主角关系网络

### 核心关系类型
1. **导师关系**：指导成长的角色
2. **盟友关系**：并肩作战的伙伴
3. **爱情关系**：情感发展的对象
4. **敌对关系**：主要冲突来源
5. **镜像关系**：反映主角另一面的角色

### 关系发展模式
```
初始阶段 → 建立联系 → 深化关系 → 考验关系 → 关系转变
```

## 主角冲突设计

### 内在冲突
- **价值观冲突**：不同信念之间的抉择
- **身份冲突**：不同社会角色间的矛盾
- **欲望冲突**：相互矛盾的愿望
- **恐惧冲突**：逃避vs面对的心理斗争

### 外在冲突
- **目标障碍**：实现目标的直接阻碍
- **关系冲突**：人际关系的矛盾
- **社会冲突**：与体制、规范的对抗
- **生存冲突**：基本的生存威胁

## 主角发展检查表

### 档案完整性检查
- [ ] 核心动机清晰且有层次
- [ ] 性格缺陷明确且影响故事
- [ ] 成长路径有清晰的阶段
- [ ] 关键关系有深度发展
- [ ] 内在冲突与外在冲突交织

### 故事功能检查
- [ ] 推动剧情发展的主动性
- [ ] 关键决策的合理性
- [ ] 情感变化的可信度
- [ ] 成长转变的明显性
- [ ] 结局状态的满意度

## 常见问题与解决方案

### 问题：主角过于完美
**解决方案**：
1. 添加有代价的优点
2. 设置情境性弱点
3. 创造道德困境
4. 安排能力限制

### 问题：主角缺乏主动性
**解决方案**：
1. 强化内在动机
2. 设置个人化目标
3. 增加情感投入
4. 减少被动应对

### 问题：成长弧线不清晰
**解决方案**：
1. 明确起始缺陷
2. 设计针对性考验
3. 安排导师指导
4. 展示渐进改变

## 优秀主角案例要点

### 案例1：成长型英雄
- **起始**：天真、能力不足
- **考验**：责任与能力的差距
- **成长**：技能和心态的双重提升
- **成就**：赢得尊重和自我认同

### 案例2：堕落与救赎
- **起始**：有原则但脆弱
- **堕落**：妥协导致的道德滑坡
- **挣扎**：良心与现实的冲突
- **救赎**：牺牲带来的回归

### 案例3：认知转变
- **起始**：坚信某种世界观
- **冲击**：遭遇颠覆性事实
- **抗拒**：否认和寻找解释
- **接受**：整合新认知，改变行动

## 创作建议

1. **从内心开始**：先确定主角的核心情感需求
2. **向外扩展**：根据内心需求设计外在表现
3. **预留空间**：为主角的意外反应留余地
4. **保持真实**：即使在不现实的情境中，反应要真实
5. **重视转变**：最大的魅力来自改变的过程

path: references/relationships.md
content: # 角色关系网络设计

## 关系设计基本原则

### 1. 功能性原则
- 关系应服务剧情发展
- 关系应推动角色成长
- 关系应体现故事主题
- 关系应有明确目的

### 2. 真实性原则
- 关系发展应有合理过程
- 关系变化应有充分动机
- 关系互动应符合角色性格
- 关系深度应有相应基础

### 3. 动态性原则
- 关系应有发展变化
- 关系应有考验时刻
- 关系应有转折点
- 关系应有最终状态

## 关系类型体系

### 按情感性质分类

#### 1. 亲情关系
```
核心特征：
- 血缘或拟血缘连接
- 长期共同生活基础
- 深厚的情感羁绊
- 复杂的责任义务

常见模式：
- 保护与被保护
- 期望与失望
- 代际冲突
- 牺牲与回报

塑造要点：
- 避免刻板印象
- 体现具体家庭的独特性
- 平衡爱与冲突
- 展现发展变化
```

#### 2. 友情关系
```
核心特征：
- 自愿选择的连接
- 相互认可的基础
- 共同经历的支持
- 平等互惠的性质

常见模式：
- 互补型友谊
- 竞争型友谊
- 救赎型友谊
- 成长型友谊

塑造要点：
- 友谊建立的自然性
- 共同价值的体现
- 考验时刻的真实性
- 发展变化的合理性
```

#### 3. 爱情关系
```
核心特征：
- 强烈的吸引连接
- 情感和欲望的交织
- 亲密和承诺的维度
- 个人成长的催化剂

常见模式：
- 互补吸引型
- 相似共鸣型
- 对立冲突型
- 救赎治愈型

塑造要点：
- 避免一见钟情套路
- 展现深层的连接点
- 平衡理想与现实
- 体现双方的成长
```

#### 4. 敌对关系
```
核心特征：
- 目标或利益的冲突
- 价值观的对立
- 情感的对抗
- 能力的较量

常见模式：
- 理念对立型
- 利益冲突型
- 情感仇恨型
- 竞争较量型

塑造要点：
- 对立的深层原因
- 对抗的规则限制
- 复杂的情感交织
- 可能的转化空间
```

### 按功能作用分类

#### 1. 成长催化关系
- 推动角色关键成长
- 提供必要的挑战
- 促使认知转变
- 激发潜能突破

#### 2. 情节推动关系
- 直接推动剧情发展
- 制造关键冲突
- 提供必要信息
- 改变局势平衡

#### 3. 主题体现关系
- 体现故事核心主题
- 展示价值观冲突
- 进行理念辩论
- 深化主题探讨

#### 4. 情感支撑关系
- 提供情感安全感
- 给予无条件支持
- 创造归属感受
- 平衡故事情感基调

## 关系发展阶段模型

### 阶段一：建立期
```
关键事件：
- 初次相遇
- 初步印象形成
- 建立连接契机
- 决定继续互动

塑造要点：
- 相遇的自然性
- 初印象的独特性
- 连接点的显著性
- 继续互动的合理性
```

### 阶段二：发展期
```
关键事件：
- 共同经历考验
- 相互了解加深
- 情感连接建立
- 关系模式形成

塑造要点：
- 共同经历的意义
- 了解过程的渐进性
- 情感建立的真实性
- 模式形成的自然性
```

### 阶段三：考验期
```
关键事件：
- 面临重大冲突
- 价值观碰撞
- 利益抉择时刻
- 信任危机考验

塑造要点：
- 冲突的不可避免性
- 选择的困难程度
- 代价的真实性
- 考验结果的影响
```

### 阶段四：稳定期或转折期
```
可能走向：
- 深化巩固：关系更加牢固
- 转变性质：关系类型改变
- 疏远淡化：关系逐渐冷却
- 彻底断裂：关系完全结束

塑造要点：
- 变化的内在逻辑
- 新状态的稳定性
- 对双方的影响
- 后续发展的可能性
```

## 关系矩阵设计工具

### 关系强度矩阵
```
设计方法：
1. 列出所有主要角色
2. 评估两两关系强度（1-10分）
3. 标注关系性质（+正面/-负面）
4. 分析网络密度和平衡

分析要点：
- 主角的关系集中度
- 负面关系的分布
- 孤立角色的存在
- 关系网络的完整性
```

### 关系动态跟踪表
```markdown
## 关系动态跟踪

角色A - 角色B 关系发展

### 故事开始前
- 初始状态：
- 历史背景：
- 未解问题：

### 第一阶段（开头-25%）
- 关键互动：
- 关系变化：
- 情感状态：

### 第二阶段（25%-50%）
- 关键互动：
- 关系变化：
- 情感状态：

### 第三阶段（50%-75%）
- 关键互动：
- 关系变化：
- 情感状态：

### 第四阶段（75%-结尾）
- 关键互动：
- 关系变化：
- 最终状态：
```

## 复杂关系设计技巧

### 1. 多重关系交织
- 同一对角色有多种关系性质
- 关系性质随时间变化
- 公开关系与真实关系的差异
- 关系中的角色扮演成分

### 2. 关系网络效应
- 关系变化引发连锁反应
- 三角关系的张力设计
- 群体内的关系动态
- 秘密关系的影响扩散

### 3. 关系不对称性
- 情感投入的不对等
- 权力地位的不平衡
- 依赖程度的不同
- 期望值的差异

## 关系冲突设计

### 冲突类型
1. **目标冲突**：追求相互排斥的目标
2. **价值观冲突**：根本信念的对立
3. **利益冲突**：具体利益的争夺
4. **情感冲突**：情感需求的矛盾
5. **认知冲突**：对事实理解的分歧

### 冲突升级路径
```
初始分歧 → 情绪反应 → 立场固化 → 对抗行动 → 关系危机 → 解决或破裂
```

### 冲突解决方式
- **妥协型**：双方各让一步
- **超越型**：找到更高层次的解决
- **胜负型**：一方战胜另一方
- **转化型**：冲突性质发生转变
- **悬置型**：暂时搁置未解决

## 关系与角色发展

### 关系作为成长催化剂
- 通过关系发现自我
- 在关系中克服弱点
- 因关系改变价值观
- 为关系承担责任

### 关系发展的双向性
- 双方都应有所改变
- 改变程度可以不同
- 改变方向可能相反
- 改变应有相互影响

## 关系设计检查表

### 功能性检查
- [ ] 关系是否服务剧情需要
- [ ] 关系是否推动角色发展
- [ ] 关系是否体现故事主题
- [ ] 关系是否有多重价值

### 真实性检查
- [ ] 关系建立过程是否自然
- [ ] 关系发展节奏是否合理
- [ ] 关系变化动机是否充分
- [ ] 关系互动是否符合性格

### 动态性检查
- [ ] 关系是否有明显发展
- [ ] 关系是否有考验时刻
- [ ] 关系是否有转折变化
- [ ] 关系最终状态是否明确

## 特殊关系类型处理

### 跨阶层关系
- 处理权力不平衡
- 展现相互影响
- 避免浪漫化压迫
- 体现结构限制

### 跨文化关系
- 尊重文化差异
- 展现误解和学习
- 避免刻板印象
- 体现交流价值

### 年龄差关系
- 处理代际差异
- 展现相互学习
- 平衡尊重与平等
- 体现时间视角

## 关系与故事结构

### 关系作为结构线索
- 关系发展对应情节阶段
- 关系转折对应情节转折
- 关系危机对应故事高潮
- 关系结局对应故事结局

### 关系网络作为世界构建
- 通过关系展现社会结构
- 通过关系体现文化规范
- 通过关系揭示权力动态
- 通过关系构建可信世界

## 创作建议

1. **从核心关系开始**：先设计最重要的几对关系
2. **向外扩展网络**：根据核心关系设计相关关系
3. **注重关系质量**：深度比数量更重要
4. **保持关系动态**：让关系有生命力和变化
5. **服务故事整体**：所有关系最终服务于故事主题和情感效果

path: references/supporting.md
content: # 配角设计指南

## 配角的双重属性

### 1. 功能性属性
- 推动剧情发展的作用
- 服务主角成长的功能
- 丰富故事世界的作用
- 提供信息或资源的功能

### 2. 独立性属性
- 有自己的动机和目标
- 有自己的生活和背景
- 有自己的性格和声音
- 有自己的发展和变化

## 配角分类体系

### 按功能分类

#### 1. 导师型配角
```
核心功能：
- 提供指导和建议
- 传授技能或知识
- 给予精神支持
- 推动主角成长

特征：
- 通常比主角更有经验
- 有独特的智慧或视角
- 可能有自己的教学理念
- 与主角有特殊情感联系

塑造要点：
- 避免全知全能
- 教学应有局限性
- 应有自己的动机
- 可能也需要成长
```

#### 2. 盟友型配角
```
核心功能：
- 提供实际帮助
- 并肩作战
- 情感支持
- 补充主角能力

特征：
- 能力与主角互补
- 忠诚但有独立性
- 有自己的专长领域
- 可能发展为深度关系

塑造要点：
- 避免单纯的工具人
- 应有自己的判断
- 关系应有发展变化
- 可能产生冲突
```

#### 3. 挑战者型配角
```
核心功能：
- 提供竞争或挑战
- 激发主角潜力
- 制造冲突张力
- 推动技术进步

特征：
- 能力与主角相当或更强
- 可能有复杂关系
- 推动主角超越自我
- 最终可能成为盟友

塑造要点：
- 挑战的合理性
- 成长的催化剂作用
- 关系的演变可能
- 独立的目标追求
```

#### 4. 镜像型配角
```
核心功能：
- 反映主角的另一面
- 展示不同选择的结果
- 提供对比视角
- 深化主题探讨

特征：
- 与主角有相似起点
- 做出了不同选择
- 展示另一种可能性
- 促使主角反思

塑造要点：
- 对比的清晰性
- 选择的合理性
- 命运的差异性
- 主题的相关性
```

### 按重要性分级

#### 一级配角（重要配角）
- 有独立的故事线
- 对主线有重要影响
- 与主角有深度互动
- 可能有显著发展

#### 二级配角（功能性配角）
- 主要发挥特定功能
- 与主角互动有限
- 背景相对简单
- 发展空间较小

#### 三级配角（背景配角）
- 丰富故事世界
- 提供氛围和细节
- 功能单一明确
- 基本没有发展

## 配角档案模板

### 重要配角模板
```markdown
# [角色姓名] - 配角档案

## 基本定位
- **功能类型**：
- **重要性级别**：
- **与主角关系**：
- **核心功能**：

## 独立身份
- **个人目标**：
- **生活背景**：
- **价值观**：
- **秘密或矛盾**：

## 功能性设计
- **推动剧情的方式**：
- **服务主角的方式**：
- **独特价值**：
- **退出时机**：

## 关系发展
- **初始关系**：
- **关系转折点**：
- **最终关系**：
- **关系影响**：

## 发展可能性
- **潜在成长**：
- **故事线扩展**：
- **意外发展**：
- **结局设想**：
```

### 功能性配角模板
```markdown
# [角色姓名] - 功能角色档案

## 功能定义
- **核心作用**：
- **出现场景**：
- **必要特征**：
- **功能限制**：

## 基本设定
- **身份背景**：
- **性格特点**：
- **能力专长**：
- **存在理由**：

## 互动设计
- **与主角互动模式**：
- **台词风格**：
- **行为模式**：
- **退出方式**：

## 注意事项
- **避免过度发展**：
- **保持功能性**：
- **控制出场频率**：
- **服务核心需求**：
```

## 配角与主角的关系设计

### 关系建立逻辑
1. **相遇合理性**：如何自然地相遇
2. **连接点**：最初建立联系的基础
3. **关系深化**：如何从相识到相知
4. **关系考验**：面临挑战时的反应
5. **关系定型**：稳定后的关系状态

### 关系动态类型
- **互补关系**：能力或性格的互补
- **镜像关系**：相似但不同的对比
- **成长关系**：相互促进成长
- **冲突关系**：有建设性的冲突
- **转变关系**：关系性质发生变化

## 配角独立性设计

### 个人生活圈
- **家庭关系**：配角的家庭背景
- **社交网络**：除了主角外的朋友
- **日常活动**：主角不在时的生活
- **个人兴趣**：独立的爱好和追求

### 个人时间线
- **遇见主角前**：之前的生活状态
- **与主角交集期**：共同经历的时期
- **分离期**：暂时分开时的状态
- **最终状态**：故事结束时的状态

## 配角功能性检查

### 功能有效性检查
- [ ] 功能明确且必要
- [ ] 功能发挥的时机恰当
- [ ] 功能实现的方式自然
- [ ] 功能完成后合理退出

### 功能平衡检查
- [ ] 不过度依赖单一配角
- [ ] 功能分配合理分布
- [ ] 配角负担不过重
- [ ] 主角保持主动性

## 常见问题与解决方案

### 问题：配角抢戏
**解决方案**：
1. 明确功能边界
2. 控制出场时间
3. 聚焦主角视角
4. 保持配角服务性

### 问题：配角工具化
**解决方案**：
1. 添加个人动机
2. 给予独立时刻
3. 创造内心矛盾
4. 安排个人选择

### 问题：配角功能重复
**解决方案**：
1. 合并相似角色
2. 分化功能侧重
3. 创造个性差异
4. 调整出场顺序

## 优秀配角案例要点

### 案例1：导师型配角
- **功能**：推动主角关键成长
- **独立**：有自己的过去和遗憾
- **关系**：从师徒到朋友到平等
- **结局**：完成使命后合理退场

### 案例2：盟友型配角
- **功能**：补充主角能力不足
- **独立**：有自己的目标和挣扎
- **关系**：从合作到信任到依赖
- **发展**：与主角共同成长变化

### 案例3：镜像型配角
- **功能**：展示不同道路的结果
- **独立**：完整的个人故事线
- **对比**：与主角形成鲜明对照
- **主题**：深化故事核心主题

## 配角创作流程建议

### 设计步骤
1. **确定功能**：首先明确配角的核心作用
2. **设计个性**：根据功能设计相应性格
3. **添加独立**：给予适当的独立生活
4. **建立关系**：设计与主角的关系动态
5. **规划发展**：考虑可能的成长变化

### 检验标准
1. **功能实现**：是否能有效完成预定功能
2. **自然程度**：出现和行动是否自然
3. **记忆点**：是否有让人印象深刻的特质
4. **关系价值**：与主角的关系是否有意义

## 配角网络构建

### 网络设计原则
1. **功能覆盖**：所有必要功能都有相应配角
2. **个性区分**：每个配角有明显区分度
3. **关系多样**：配角间也有相互关系
4. **层次清晰**：重要性层次分明

### 网络检查要点
- 是否有功能缺失或重叠
- 是否有多元的声音和视角
- 是否有合理的互动网络
- 是否有动态的关系变化

## 特殊类型配角处理

### 喜剧性配角
- **功能**：提供幽默和轻松时刻
- **注意**：避免破坏严肃情境
- **技巧**：幽默应源于性格而非刻意

### 神秘性配角
- **功能**：制造悬念和神秘感
- **注意**：最终应有合理解释
- **技巧**：神秘感应服务于主题

### 过渡性配角
- **功能**：连接不同情节阶段
- **注意**：完成连接后合理退场
- **技巧**：退场方式应有意义

记住：最好的配角是那些读者会好奇"他们的故事是什么"的角色，但同时明白故事的重点仍然是主角。

path: scripts/analyze_profile.py
content: #!/usr/bin/env python3
"""
人物档案分析脚本
分析markdown格式的人物档案完整性
"""

import os
import re
import sys
from pathlib import Path

class ProfileAnalyzer:
    """人物档案分析器"""

    def __init__(self):
        self.placeholder_patterns = [
            r'待填写',
            r'TODO',
            r'待补充',
            r'待完善',
            r'\[.*\]',
            r'\{.*\}',
            r'未指定',
            r'未知',
            r'待定'
        ]

        # 检测平台，Windows上使用简单符号
        self.is_windows = sys.platform.startswith('win')

        # 符号定义
        if self.is_windows:
            self.symbols = {
                'chart': '[统计]',
                'trophy': '[评估]',
                'file': '[章节]',
                'warning': '[注意]',
                'bulb': '[建议]',
                'check': '[OK]',
                'arrow': '->',
                'cross': '[X]',
                'green_circle': '[良好]',
                'yellow_circle': '[一般]',
                'red_circle': '[需改进]',
                'bullet': '-'
            }
        else:
            self.symbols = {
                'chart': '📊',
                'trophy': '🏆',
                'file': '📑',
                'warning': '⚠️',
                'bulb': '💡',
                'check': '✓',
                'arrow': '→',
                'cross': '✗',
                'green_circle': '🟢',
                'yellow_circle': '🟡',
                'red_circle': '🔴',
                'bullet': '•'
            }

    def analyze_markdown(self, filepath):
        """分析markdown档案

        Args:
            filepath: markdown文件路径

        Returns:
            分析结果字典
        """
        with open(filepath, 'r', encoding='utf-8') as f:
            content = f.read()

        # 基本统计
        lines = content.split('\n')
        total_lines = len(lines)
        non_empty_lines = len([line for line in lines if line.strip()])

        # 章节分析
        sections = self._extract_sections(content)

        # 占位符检测
        placeholder_count = 0
        placeholder_details = []

        for i, line in enumerate(lines, 1):
            for pattern in self.placeholder_patterns:
                if re.search(pattern, line):
                    placeholder_count += 1
                    placeholder_details.append({
                        'line': i,
                        'content': line.strip()[:50] + '...' if len(line.strip()) > 50 else line.strip()
                    })
                    break

        # 完整性评分
        completeness_score = self._calculate_completeness_score(
            non_empty_lines, placeholder_count, len(sections)
        )

        return {
            'filepath': filepath,
            'total_lines': total_lines,
            'non_empty_lines': non_empty_lines,
            'sections_count': len(sections),
            'sections': sections,
            'placeholder_count': placeholder_count,
            'placeholder_details': placeholder_details[:10],  # 只显示前10个
            'completeness_score': completeness_score,
            'completeness_level': self._get_completeness_level(completeness_score)
        }

    def _extract_sections(self, content):
        """提取章节信息"""
        sections = []

        # 匹配各级标题
        header_pattern = r'^(#{1,3})\s+(.+?)$'

        lines = content.split('\n')
        current_section = None

        for i, line in enumerate(lines):
            match = re.match(header_pattern, line.strip())
            if match:
                level = len(match.group(1))
                title = match.group(2).strip()

                # 计算章节内容行数（直到下一个标题）
                content_lines = 0
                for j in range(i + 1, len(lines)):
                    if re.match(r'^#{1,3}\s+', lines[j].strip()):
                        break
                    if lines[j].strip():
                        content_lines += 1

                sections.append({
                    'level': level,
                    'title': title,
                    'start_line': i + 1,
                    'content_lines': content_lines
                })

        return sections

    def _calculate_completeness_score(self, non_empty_lines, placeholder_count, sections_count):
        """计算完整性评分（0-100）"""
        if non_empty_lines == 0:
            return 0

        # 基础分：基于非空行数（假设完整档案至少50行）
        base_score = min(100, (non_empty_lines / 50) * 60)

        # 占位符扣分：每个占位符扣2分，最多扣30分
        placeholder_penalty = min(30, placeholder_count * 2)

        # 章节加分：每节加5分，最多加20分
        section_bonus = min(20, sections_count * 5)

        score = base_score - placeholder_penalty + section_bonus
        return max(0, min(100, score))

    def _get_completeness_level(self, score):
        """获取完整性等级"""
        if score >= 90:
            return "优秀"
        elif score >= 75:
            return "良好"
        elif score >= 60:
            return "一般"
        elif score >= 40:
            return "待完善"
        else:
            return "草稿"

    def generate_report(self, analysis_result, output_format='text'):
        """生成分析报告"""
        result = analysis_result

        if output_format == 'text':
            report_lines = []
            report_lines.append("=" * 60)
            report_lines.append(f"人物档案分析报告")
            report_lines.append(f"文件: {result['filepath']}")
            report_lines.append("=" * 60)
            report_lines.append("")

            # 基本信息
            report_lines.append(f"{self.symbols['chart']} 基本信息")
            report_lines.append(f"  总行数: {result['total_lines']}")
            report_lines.append(f"  非空行数: {result['non_empty_lines']}")
            report_lines.append(f"  章节数: {result['sections_count']}")
            report_lines.append(f"  占位符数量: {result['placeholder_count']}")
            report_lines.append("")

            # 完整性评分
            report_lines.append(f"{self.symbols['trophy']} 完整性评估")
            report_lines.append(f"  评分: {result['completeness_score']:.1f}/100")
            report_lines.append(f"  等级: {result['completeness_level']}")
            report_lines.append("")

            # 章节详情
            if result['sections']:
                report_lines.append(f"{self.symbols['file']} 章节详情")
                for section in result['sections']:
                    level_indent = "  " * (section['level'] - 1)
                    report_lines.append(f"{level_indent}{self.symbols['bullet']} {section['title']} (行 {section['start_line']}, {section['content_lines']} 行)")
                report_lines.append("")

            # 占位符详情
            if result['placeholder_details']:
                report_lines.append(f"{self.symbols['warning']} 需要完善的部分")
                for detail in result['placeholder_details']:
                    report_lines.append(f"  第 {detail['line']} 行: {detail['content']}")

                if result['placeholder_count'] > 10:
                    report_lines.append(f"  ... 还有 {result['placeholder_count'] - 10} 个占位符未显示")
                report_lines.append("")

            # 建议
            report_lines.append(f"{self.symbols['bulb']} 建议")
            if result['completeness_score'] >= 80:
                report_lines.append(f"  {self.symbols['check']} 档案比较完整，可以开始用于创作")
                report_lines.append(f"  {self.symbols['arrow']} 可以考虑添加更多细节和情感描写")
            elif result['completeness_score'] >= 60:
                report_lines.append(f"  {self.symbols['warning']} 档案基本完整，但还有完善空间")
                report_lines.append(f"  {self.symbols['arrow']} 建议完善 {result['placeholder_count']} 处占位符")
            else:
                report_lines.append(f"  {self.symbols['cross']} 档案还处于草稿阶段")
                report_lines.append(f"  {self.symbols['arrow']} 需要补充大量内容，建议逐个章节完善")

            report_lines.append("")
            report_lines.append("=" * 60)

            return "\n".join(report_lines)

        elif output_format == 'json':
            import json
            return json.dumps(result, ensure_ascii=False, indent=2)

        else:
            raise ValueError(f"不支持的输出格式: {output_format}")

    def analyze_directory(self, directory_path, recursive=True):
        """分析目录下的所有markdown档案"""
        directory = Path(directory_path)

        if not directory.exists():
            raise FileNotFoundError(f"目录不存在: {directory_path}")

        # 查找markdown文件
        md_files = []
        if recursive:
            md_files = list(directory.rglob("*.md"))
        else:
            md_files = list(directory.glob("*.md"))

        if not md_files:
            return {"message": "未找到markdown文件", "files": []}

        # 分析每个文件
        results = []
        for md_file in md_files:
            try:
                analysis = self.analyze_markdown(str(md_file))
                results.append(analysis)
            except Exception as e:
                results.append({
                    'filepath': str(md_file),
                    'error': str(e)
                })

        # 按完整性评分排序
        valid_results = [r for r in results if 'completeness_score' in r]
        sorted_results = sorted(valid_results, key=lambda x: x['completeness_score'], reverse=True)

        return {
            'total_files': len(md_files),
            'successful_analysis': len(valid_results),
            'failed_analysis': len(results) - len(valid_results),
            'results': sorted_results
        }

    def generate_directory_report(self, analysis_results, output_format='text'):
        """生成目录分析报告"""
        if output_format == 'text':
            report_lines = []
            report_lines.append("=" * 60)
            report_lines.append(f"人物档案目录分析报告")
            report_lines.append(f"分析文件数: {analysis_results['total_files']}")
            report_lines.append(f"成功分析: {analysis_results['successful_analysis']}")
            if analysis_results['failed_analysis'] > 0:
                report_lines.append(f"分析失败: {analysis_results['failed_analysis']}")
            report_lines.append("=" * 60)
            report_lines.append("")

            # 文件列表（按评分排序）
            if analysis_results['results']:
                report_lines.append(f"{self.symbols['file']} 文件完整性排名")
                for i, result in enumerate(analysis_results['results'], 1):
                    score = result['completeness_score']
                    level = result['completeness_level']
                    filename = os.path.basename(result['filepath'])

                    # 使用符号表示等级
                    if score >= 80:
                        icon = self.symbols['green_circle']
                    elif score >= 60:
                        icon = self.symbols['yellow_circle']
                    else:
                        icon = self.symbols['red_circle']

                    report_lines.append(f"{icon} {i:2d}. {filename:<40} {score:5.1f}分 ({level})")

                report_lines.append("")

                # 统计信息
                avg_score = sum(r['completeness_score'] for r in analysis_results['results']) / len(analysis_results['results'])
                max_score = max(r['completeness_score'] for r in analysis_results['results'])
                min_score = min(r['completeness_score'] for r in analysis_results['results'])

                report_lines.append(f"{self.symbols['chart']} 统计信息")
                report_lines.append(f"  平均分: {avg_score:.1f}")
                report_lines.append(f"  最高分: {max_score:.1f}")
                report_lines.append(f"  最低分: {min_score:.1f}")
                report_lines.append("")

                # 建议
                report_lines.append(f"{self.symbols['bulb']} 整体建议")
                if avg_score >= 75:
                    report_lines.append(f"  {self.symbols['check']} 整体完成度良好")
                    report_lines.append(f"  {self.symbols['arrow']} 可以考虑开始故事创作")
                elif avg_score >= 50:
                    report_lines.append(f"  {self.symbols['warning']} 整体完成度一般")
                    report_lines.append(f"  {self.symbols['arrow']} 建议继续完善人物档案")
                else:
                    report_lines.append(f"  {self.symbols['cross']} 整体完成度较低")
                    report_lines.append(f"  {self.symbols['arrow']} 需要重点完善主要角色的档案")

            report_lines.append("")
            report_lines.append("=" * 60)

            return "\n".join(report_lines)

        else:
            import json
            return json.dumps(analysis_results, ensure_ascii=False, indent=2)


def main():
    """主函数"""
    import argparse

    parser = argparse.ArgumentParser(description='分析人物档案markdown文件')
    parser.add_argument('path', help='要分析的markdown文件或目录路径')
    parser.add_argument('--recursive', '-r', action='store_true', help='递归分析目录')
    parser.add_argument('--format', '-f', choices=['text', 'json'], default='text', help='输出格式')
    parser.add_argument('--output', '-o', help='输出文件路径')

    args = parser.parse_args()

    analyzer = ProfileAnalyzer()
    path = Path(args.path)

    try:
        if path.is_file():
            # 分析单个文件
            if path.suffix.lower() != '.md':
                print("错误: 文件必须是.md格式")
                return 1

            analysis = analyzer.analyze_markdown(str(path))
            report = analyzer.generate_report(analysis, args.format)

        elif path.is_dir():
            # 分析目录
            analysis_results = analyzer.analyze_directory(str(path), args.recursive)
            report = analyzer.generate_directory_report(analysis_results, args.format)

        else:
            print(f"错误: 路径不存在: {args.path}")
            return 1

        # 输出结果
        if args.output:
            with open(args.output, 'w', encoding='utf-8') as f:
                f.write(report)
            print(f"报告已保存到: {args.output}")
        else:
            print(report)

        return 0

    except Exception as e:
        print(f"分析失败: {e}")
        return 1


if __name__ == "__main__":
    sys.exit(main())

path: scripts/conflict_detector.py
content: #!/usr/bin/env python3
"""
冲突检测和常识校验模块
检测角色冲突和常识错误
"""

import re
import json
from typing import Dict, List, Optional, Tuple, Set, Any
from pathlib import Path
import logging
from dataclasses import dataclass, field
from enum import Enum

logger = logging.getLogger(__name__)


class ConflictSeverity(Enum):
    """冲突严重程度"""
    INFO = "info"       # 信息提示
    WARNING = "warning" # 警告
    ERROR = "error"     # 错误


class ConflictType(Enum):
    """冲突类型"""
    DUPLICATE_NAME = "duplicate_name"           # 重复姓名
    SIMILAR_CHARACTER = "similar_character"     # 相似角色
    TIMELINE_CONFLICT = "timeline_conflict"     # 时间线冲突
    RELATIONSHIP_CONFLICT = "relationship_conflict"  # 关系冲突
    AGE_INCONSISTENCY = "age_inconsistency"     # 年龄不一致
    COMMON_SENSE_ERROR = "common_sense_error"   # 常识错误
    LOGIC_CONFLICT = "logic_conflict"          # 逻辑冲突


@dataclass
class Conflict:
    """冲突信息"""
    type: ConflictType
    severity: ConflictSeverity
    message: str
    character_name: str
    details: Dict[str, Any] = field(default_factory=dict)
    related_characters: List[str] = field(default_factory=list)
    suggested_fixes: List[str] = field(default_factory=list)


@dataclass
class ValidationRule:
    """校验规则"""
    id: str
    name: str
    description: str
    pattern: Optional[str] = None
    condition: Optional[str] = None
    severity: ConflictSeverity = ConflictSeverity.WARNING
    enabled: bool = True
    category: str = "common_sense"


class ConflictDetector:
    """冲突检测器"""

    # 预定义常识规则
    DEFAULT_COMMON_SENSE_RULES = [
        ValidationRule(
            id="age_realistic",
            name="年龄合理性",
            description="检查年龄是否在合理范围内（0-150岁）",
            condition="age.isdigit() and not (0 <= int(age) <= 150)",
            severity=ConflictSeverity.WARNING,
            category="common_sense"
        ),
        ValidationRule(
            id="age_format",
            name="年龄格式",
            description="年龄应为数字或数字范围",
            pattern=r"^\d+(\s*-\s*\d+)?$",
            severity=ConflictSeverity.INFO,
            category="common_sense"
        ),
        ValidationRule(
            id="timeline_consistency",
            name="时间线一致性",
            description="检查关键事件时间线是否合理",
            condition="'background' in character and 'timeline_events' in character",
            severity=ConflictSeverity.WARNING,
            category="timeline"
        ),
        ValidationRule(
            id="relationship_consistency",
            name="关系一致性",
            description="检查角色关系是否相互一致",
            condition="'relationships' in character",
            severity=ConflictSeverity.WARNING,
            category="relationships"
        ),
        ValidationRule(
            id="duplicate_detection",
            name="重复检测",
            description="检测是否有重复角色",
            condition="True",  # 始终启用
            severity=ConflictSeverity.ERROR,
            category="duplicate"
        )
    ]

    def __init__(self, rules_file: Optional[str] = None):
        """初始化冲突检测器

        Args:
            rules_file: 规则配置文件路径
        """
        self.rules = self._load_rules(rules_file)
        self.character_index = {}  # 角色信息索引

    def _load_rules(self, rules_file: Optional[str]) -> List[ValidationRule]:
        """加载校验规则

        Args:
            rules_file: 规则文件路径

        Returns:
            规则列表
        """
        rules = []

        # 先加载默认规则
        rules.extend(self.DEFAULT_COMMON_SENSE_RULES)

        # 如果指定了规则文件，从文件加载
        if rules_file and Path(rules_file).exists():
            try:
                with open(rules_file, 'r', encoding='utf-8') as f:
                    rule_data = json.load(f)

                for rule_item in rule_data.get("rules", []):
                    rule = ValidationRule(
                        id=rule_item.get("id"),
                        name=rule_item.get("name"),
                        description=rule_item.get("description"),
                        pattern=rule_item.get("pattern"),
                        condition=rule_item.get("condition"),
                        severity=ConflictSeverity(rule_item.get("severity", "warning")),
                        enabled=rule_item.get("enabled", True),
                        category=rule_item.get("category", "common_sense")
                    )
                    rules.append(rule)

                logger.info(f"从文件加载了 {len(rule_data.get('rules', []))} 条规则")
            except Exception as e:
                logger.error(f"加载规则文件失败: {e}")

        return rules

    def set_character_index(self, character_index: Dict):
        """设置角色信息索引

        Args:
            character_index: 角色索引字典
        """
        self.character_index = character_index

    def detect_conflicts(self, new_character: Dict, existing_characters: List[Dict] = None) -> List[Conflict]:
        """检测新角色与现有角色的冲突

        Args:
            new_character: 新角色信息
            existing_characters: 现有角色列表，为None时使用character_index

        Returns:
            冲突列表
        """
        conflicts = []

        # 获取现有角色
        if existing_characters is None:
            existing_characters = self.character_index.get("characters", [])

        # 1. 检测重复姓名
        duplicate_conflicts = self._detect_duplicate_names(new_character, existing_characters)
        conflicts.extend(duplicate_conflicts)

        # 2. 检测相似角色
        similar_conflicts = self._detect_similar_characters(new_character, existing_characters)
        conflicts.extend(similar_conflicts)

        # 3. 检测常识错误
        common_sense_conflicts = self._check_common_sense(new_character)
        conflicts.extend(common_sense_conflicts)

        # 4. 检测时间线冲突
        timeline_conflicts = self._detect_timeline_conflicts(new_character, existing_characters)
        conflicts.extend(timeline_conflicts)

        # 5. 检测关系冲突
        relationship_conflicts = self._detect_relationship_conflicts(new_character, existing_characters)
        conflicts.extend(relationship_conflicts)

        return conflicts

    def _detect_duplicate_names(self, new_char: Dict, existing_chars: List[Dict]) -> List[Conflict]:
        """检测重复姓名

        Args:
            new_char: 新角色
            existing_chars: 现有角色

        Returns:
            冲突列表
        """
        conflicts = []
        new_name = new_char.get("name", "").strip().lower()

        if not new_name:
            return conflicts

        for existing_char in existing_chars:
            existing_name = existing_char.get("name", "").strip().lower()

            if existing_name and existing_name == new_name:
                conflict = Conflict(
                    type=ConflictType.DUPLICATE_NAME,
                    severity=ConflictSeverity.ERROR,
                    message=f"角色姓名重复: '{new_char.get('name')}' 已存在",
                    character_name=new_char.get("name", "未知"),
                    details={
                        "new_character": new_char.get("name"),
                        "existing_character": existing_char.get("name"),
                        "existing_file": existing_char.get("file_path", "")
                    },
                    related_characters=[existing_char.get("name", "未知")],
                    suggested_fixes=[
                        f"修改新角色姓名为 '{new_char.get('name')}_新'",
                        f"合并两个角色的设定",
                        f"删除或重命名现有角色"
                    ]
                )
                conflicts.append(conflict)

        return conflicts

    def _detect_similar_characters(self, new_char: Dict, existing_chars: List[Dict]) -> List[Conflict]:
        """检测相似角色

        Args:
            new_char: 新角色
            existing_chars: 现有角色

        Returns:
            冲突列表
        """
        conflicts = []
        new_name = new_char.get("name", "").lower()

        if not new_name:
            return conflicts

        # 相似度检测阈值
        similarity_threshold = 0.7

        for existing_char in existing_chars:
            existing_name = existing_char.get("name", "").lower()

            # 计算姓名相似度
            similarity = self._calculate_name_similarity(new_name, existing_name)

            if similarity > similarity_threshold:
                conflict = Conflict(
                    type=ConflictType.SIMILAR_CHARACTER,
                    severity=ConflictSeverity.WARNING,
                    message=f"角色姓名相似: '{new_char.get('name')}' 与 '{existing_char.get('name')}' 相似度较高",
                    character_name=new_char.get("name", "未知"),
                    details={
                        "new_character": new_char.get("name"),
                        "existing_character": existing_char.get("name"),
                        "similarity_score": similarity,
                        "existing_file": existing_char.get("file_path", "")
                    },
                    related_characters=[existing_char.get("name", "未知")],
                    suggested_fixes=[
                        f"确认是否为不同角色",
                        f"修改其中一个角色的姓名以增加区分度",
                        f"检查角色设定是否重复"
                    ]
                )
                conflicts.append(conflict)

            # 检查其他相似特征
            similarity_features = self._check_feature_similarity(new_char, existing_char)
            if similarity_features:
                conflict = Conflict(
                    type=ConflictType.SIMILAR_CHARACTER,
                    severity=ConflictSeverity.INFO,
                    message=f"角色特征相似: '{new_char.get('name')}' 与 '{existing_char.get('name')}' 有相似特征",
                    character_name=new_char.get("name", "未知"),
                    details={
                        "new_character": new_char.get("name"),
                        "existing_character": existing_char.get("name"),
                        "similar_features": similarity_features,
                        "existing_file": existing_char.get("file_path", "")
                    },
                    related_characters=[existing_char.get("name", "未知")],
                    suggested_fixes=[
                        f"区分角色特征",
                        f"强化角色独特性",
                        f"考虑角色合并"
                    ]
                )
                conflicts.append(conflict)

        return conflicts

    def _calculate_name_similarity(self, name1: str, name2: str) -> float:
        """计算姓名相似度

        Args:
            name1: 姓名1
            name2: 姓名2

        Returns:
            相似度得分 (0-1)
        """
        if not name1 or not name2:
            return 0.0

        # 简单的相似度计算：共同字符比例
        set1 = set(name1.replace(' ', ''))
        set2 = set(name2.replace(' ', ''))

        if not set1 or not set2:
            return 0.0

        intersection = len(set1.intersection(set2))
        union = len(set1.union(set2))

        return intersection / union if union > 0 else 0.0

    def _check_feature_similarity(self, char1: Dict, char2: Dict) -> List[str]:
        """检查特征相似性

        Args:
            char1: 角色1
            char2: 角色2

        Returns:
            相似特征列表
        """
        similar_features = []

        # 检查年龄
        age1 = char1.get("age", "")
        age2 = char2.get("age", "")
        if age1 and age2 and age1 == age2:
            similar_features.append(f"年龄相同: {age1}")

        # 检查职业
        occupation1 = char1.get("occupation", "")
        occupation2 = char2.get("occupation", "")
        if occupation1 and occupation2 and occupation1.lower() == occupation2.lower():
            similar_features.append(f"职业相同: {occupation1}")

        # 检查角色类型
        type1 = char1.get("character_type", "")
        type2 = char2.get("character_type", "")
        if type1 and type2 and type1.lower() == type2.lower():
            similar_features.append(f"角色类型相同: {type1}")

        return similar_features

    def _check_common_sense(self, character: Dict) -> List[Conflict]:
        """检查常识错误

        Args:
            character: 角色信息

        Returns:
            冲突列表
        """
        conflicts = []

        for rule in self.rules:
            if not rule.enabled or rule.category != "common_sense":
                continue

            # 根据规则类型进行检查
            if rule.pattern:
                # 模式匹配规则
                for field_name, field_value in character.items():
                    if isinstance(field_value, str):
                        if not re.match(rule.pattern, field_value):
                            conflict = Conflict(
                                type=ConflictType.COMMON_SENSE_ERROR,
                                severity=rule.severity,
                                message=f"{rule.name}: {field_name} '{field_value}' 不符合格式要求",
                                character_name=character.get("name", "未知"),
                                details={
                                    "rule_id": rule.id,
                                    "rule_name": rule.name,
                                    "field": field_name,
                                    "value": field_value,
                                    "expected_pattern": rule.pattern
                                },
                                suggested_fixes=[
                                    f"修改 {field_name} 为符合格式: {rule.pattern}",
                                    f"检查 {field_name} 是否正确"
                                ]
                            )
                            conflicts.append(conflict)

            elif rule.condition:
                # 条件规则（简化实现）
                try:
                    # 这里实现简化的条件检查
                    if rule.id == "age_realistic":
                        age_str = character.get("age", "")
                        if age_str.isdigit():
                            age = int(age_str)
                            if not (0 <= age <= 150):
                                conflict = Conflict(
                                    type=ConflictType.COMMON_SENSE_ERROR,
                                    severity=rule.severity,
                                    message=f"{rule.name}: 年龄 {age} 不在合理范围 (0-150)",
                                    character_name=character.get("name", "未知"),
                                    details={
                                        "rule_id": rule.id,
                                        "rule_name": rule.name,
                                        "field": "age",
                                        "value": age,
                                        "expected_range": "0-150"
                                    },
                                    suggested_fixes=[
                                        "调整年龄到合理范围",
                                        "如果是特殊设定（如非人类），请明确说明"
                                    ]
                                )
                                conflicts.append(conflict)
                except Exception as e:
                    logger.debug(f"规则检查失败 {rule.id}: {e}")

        return conflicts

    def _detect_timeline_conflicts(self, new_char: Dict, existing_chars: List[Dict]) -> List[Conflict]:
        """检测时间线冲突

        Args:
            new_char: 新角色
            existing_chars: 现有角色

        Returns:
            冲突列表
        """
        conflicts = []
        # 这里实现时间线冲突检测逻辑
        # 需要从角色信息中提取时间线事件
        return conflicts

    def _detect_relationship_conflicts(self, new_char: Dict, existing_chars: List[Dict]) -> List[Conflict]:
        """检测关系冲突

        Args:
            new_char: 新角色
            existing_chars: 现有角色

        Returns:
            冲突列表
        """
        conflicts = []
        # 这里实现关系冲突检测逻辑
        # 需要从角色信息中提取关系信息
        return conflicts

    def validate_character(self, character: Dict) -> Tuple[bool, List[Conflict]]:
        """验证单个角色

        Args:
            character: 角色信息

        Returns:
            (是否有效, 冲突列表)
        """
        conflicts = self.detect_conflicts(character)
        is_valid = all(conflict.severity != ConflictSeverity.ERROR for conflict in conflicts)

        return is_valid, conflicts

    def generate_report(self, conflicts: List[Conflict], output_format: str = "text") -> str:
        """生成冲突报告

        Args:
            conflicts: 冲突列表
            output_format: 输出格式，支持 'text', 'json', 'markdown'

        Returns:
            报告字符串
        """
        if output_format == "json":
            report_data = []
            for conflict in conflicts:
                report_data.append({
                    "type": conflict.type.value,
                    "severity": conflict.severity.value,
                    "message": conflict.message,
                    "character_name": conflict.character_name,
                    "details": conflict.details,
                    "related_characters": conflict.related_characters,
                    "suggested_fixes": conflict.suggested_fixes
                })
            return json.dumps(report_data, ensure_ascii=False, indent=2)

        elif output_format == "markdown":
            report_lines = ["# 冲突检测报告", ""]

            # 按严重程度分组
            errors = [c for c in conflicts if c.severity == ConflictSeverity.ERROR]
            warnings = [c for c in conflicts if c.severity == ConflictSeverity.WARNING]
            infos = [c for c in conflicts if c.severity == ConflictSeverity.INFO]

            if errors:
                report_lines.append("## ❌ 错误")
                for conflict in errors:
                    report_lines.append(f"### {conflict.message}")
                    report_lines.append(f"- **角色**: {conflict.character_name}")
                    report_lines.append(f"- **类型**: {conflict.type.value}")
                    if conflict.related_characters:
                        report_lines.append(f"- **相关角色**: {', '.join(conflict.related_characters)}")
                    if conflict.suggested_fixes:
                        report_lines.append(f"- **建议**:")
                        for fix in conflict.suggested_fixes:
                            report_lines.append(f"  - {fix}")
                    report_lines.append("")

            if warnings:
                report_lines.append("## ⚠️ 警告")
                for conflict in warnings:
                    report_lines.append(f"### {conflict.message}")
                    report_lines.append(f"- **角色**: {conflict.character_name}")
                    report_lines.append(f"- **类型**: {conflict.type.value}")
                    if conflict.suggested_fixes:
                        report_lines.append(f"- **建议**: {conflict.suggested_fixes[0]}")
                    report_lines.append("")

            if infos:
                report_lines.append("## ℹ️ 提示")
                for conflict in infos:
                    report_lines.append(f"- {conflict.message}")
                report_lines.append("")

            return "\n".join(report_lines)

        else:  # text格式
            report_lines = ["冲突检测报告", "=" * 40, ""]

            # 统计
            error_count = len([c for c in conflicts if c.severity == ConflictSeverity.ERROR])
            warning_count = len([c for c in conflicts if c.severity == ConflictSeverity.WARNING])
            info_count = len([c for c in conflicts if c.severity == ConflictSeverity.INFO])

            report_lines.append(f"发现 {error_count} 个错误, {warning_count} 个警告, {info_count} 个提示")
            report_lines.append("")

            # 按角色分组显示
            characters_conflicts = {}
            for conflict in conflicts:
                char_name = conflict.character_name
                if char_name not in characters_conflicts:
                    characters_conflicts[char_name] = []
                characters_conflicts[char_name].append(conflict)

            for char_name, char_conflicts in characters_conflicts.items():
                report_lines.append(f"角色: {char_name}")
                report_lines.append("-" * 30)

                for conflict in char_conflicts:
                    severity_icon = {
                        ConflictSeverity.ERROR: "[错误]",
                        ConflictSeverity.WARNING: "[警告]",
                        ConflictSeverity.INFO: "[提示]"
                    }.get(conflict.severity, "[未知]")

                    report_lines.append(f"{severity_icon} {conflict.message}")

                    if conflict.related_characters:
                        report_lines.append(f"  相关角色: {', '.join(conflict.related_characters)}")

                    if conflict.suggested_fixes:
                        report_lines.append(f"  建议: {conflict.suggested_fixes[0]}")

                report_lines.append("")

            return "\n".join(report_lines)


def main():
    """命令行测试"""
    import sys

    if len(sys.argv) < 2:
        print("用法: python conflict_detector.py <新角色JSON文件> [现有角色目录]")
        sys.exit(1)

    # 加载新角色信息
    new_char_file = sys.argv[1]
    try:
        with open(new_char_file, 'r', encoding='utf-8') as f:
            new_character = json.load(f)
    except Exception as e:
        print(f"加载新角色文件失败: {e}")
        sys.exit(1)

    # 创建检测器
    detector = ConflictDetector()

    # 如果有现有角色目录，扫描现有角色
    existing_characters = []
    if len(sys.argv) > 2:
        from lore_bible_manager import LoreBibleManager
        try:
            manager = LoreBibleManager(sys.argv[2])
            existing_characters = manager.scan_existing_characters()
            print(f"扫描到 {len(existing_characters)} 个现有角色")
        except Exception as e:
            print(f"扫描现有角色失败: {e}")

    # 设置角色索引
    if existing_characters:
        detector.set_character_index({
            "characters": existing_characters,
            "total_count": len(existing_characters)
        })

    # 检测冲突
    conflicts = detector.detect_conflicts(new_character, existing_characters)

    # 生成报告
    report = detector.generate_report(conflicts, "text")
    print(report)

    # 检查是否有效
    is_valid, _ = detector.validate_character(new_character)
    if is_valid:
        print("\n✓ 角色设定基本有效")
    else:
        print("\n✗ 角色设定存在错误")


if __name__ == "__main__":
    main()

path: scripts/generate_profile.py
content: #!/usr/bin/env python3
"""
人物档案生成脚本
根据模板生成结构化的人物档案markdown文件
"""

import os
import sys
import json
from datetime import datetime
from pathlib import Path
import logging
from typing import Optional, Dict, List, Tuple

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
logger = logging.getLogger(__name__)

class CharacterProfileGenerator:
    """人物档案生成器"""

    def __init__(self, template_type="standard", workspace=None):
        """初始化生成器

        Args:
            template_type: 模板类型，可选值: 'protagonist', 'antagonist', 'supporting', 'standard'
            workspace: 工作目录路径，启用LoreBible管理功能
        """
        self.template_type = template_type
        self.templates = self._load_templates()
        self.workspace = workspace
        self.enable_enhanced_features = workspace is not None

        if self.enable_enhanced_features:
            logger.info(f"启用增强功能，工作目录: {workspace}")
            # 延迟导入，避免循环依赖
            self.lore_bible_manager = None
            self.conflict_detector = None
            self.profile_session = None

    def _init_enhanced_components(self):
        """初始化增强组件"""
        if not self.enable_enhanced_features:
            return

        try:
            # 延迟导入
            from lore_bible_manager import LoreBibleManager
            from conflict_detector import ConflictDetector
            from profile_session import ProfileSession, SessionConfig

            # 初始化管理器
            self.lore_bible_manager = LoreBibleManager(self.workspace)

            # 验证并创建目录结构
            is_valid, missing_dirs = self.lore_bible_manager.validate_directory_structure()
            if not is_valid:
                logger.warning(f"目录结构不完整，缺失: {missing_dirs}")
                logger.info("正在创建缺失目录...")
                if self.lore_bible_manager.create_directory_structure():
                    logger.info("目录结构创建成功")
                else:
                    logger.error("创建目录结构失败")

            # 初始化冲突检测器
            self.conflict_detector = ConflictDetector()

            # 配置会话（稍后在generate_markdown中创建）
            self.session_config = SessionConfig(
                workspace=self.workspace,
                character_name="",  # 稍后设置
                template_type=self.template_type,
                enable_validation=True,
                enable_conflict_check=True,
                require_confirmation=True
            )

            logger.info("增强组件初始化完成")

        except ImportError as e:
            logger.error(f"导入增强组件失败: {e}")
            logger.error("请确保lore_bible_manager.py、conflict_detector.py、profile_session.py在脚本目录中")
            self.enable_enhanced_features = False
        except Exception as e:
            logger.error(f"初始化增强组件失败: {e}")
            self.enable_enhanced_features = False

    def _load_templates(self):
        """加载模板配置"""
        templates = {
            "protagonist": {
                "name": "主角模板",
                "sections": [
                    {"id": "basic", "title": "基本信息", "required": True},
                    {"id": "appearance", "title": "外貌特征", "required": True},
                    {"id": "personality", "title": "性格特点", "required": True},
                    {"id": "background", "title": "背景故事", "required": True},
                    {"id": "motivation", "title": "动机层次", "required": True},
                    {"id": "relationships", "title": "人物关系", "required": True},
                    {"id": "development", "title": "故事发展", "required": True},
                    {"id": "core_identity", "title": "核心身份", "required": False},
                    {"id": "notes", "title": "创作笔记", "required": False}
                ]
            },
            "antagonist": {
                "name": "反派模板",
                "sections": [
                    {"id": "basic", "title": "基本信息", "required": True},
                    {"id": "appearance", "title": "外貌特征", "required": True},
                    {"id": "personality", "title": "性格特点", "required": True},
                    {"id": "core_belief", "title": "核心理念", "required": True},
                    {"id": "motivation", "title": "动机发展", "required": True},
                    {"id": "mirror", "title": "镜像对比", "required": True},
                    {"id": "resources", "title": "资源能力", "required": True},
                    {"id": "development", "title": "故事发展", "required": True}
                ]
            },
            "supporting": {
                "name": "配角模板",
                "sections": [
                    {"id": "basic", "title": "基本定位", "required": True},
                    {"id": "identity", "title": "独立身份", "required": True},
                    {"id": "function", "title": "功能性设计", "required": True},
                    {"id": "relationships", "title": "关系发展", "required": True},
                    {"id": "development", "title": "发展可能性", "required": True}
                ]
            },
            "standard": {
                "name": "标准模板",
                "sections": [
                    {"id": "basic", "title": "基本信息", "required": True},
                    {"id": "appearance", "title": "外貌特征", "required": True},
                    {"id": "personality", "title": "性格特点", "required": True},
                    {"id": "background", "title": "背景故事", "required": True},
                    {"id": "relationships", "title": "人物关系", "required": True},
                    {"id": "development", "title": "故事发展", "required": True},
                    {"id": "notes", "title": "创作笔记", "required": False}
                ]
            }
        }
        return templates

    def _get_section_content(self, section_id, character_data):
        """获取章节内容

        Args:
            section_id: 章节ID
            character_data: 角色数据字典

        Returns:
            章节内容字符串
        """
        section_templates = {
            "basic": """- **姓名**：{name}
- **年龄**：{age}
- **性别**：{gender}
- **职业/身份**：{occupation}
- **故事中的角色**：{role}""",

            "appearance": """- **整体印象**：{overall_impression}
- **面部特征**：{facial_features}
- **身材体型**：{body_type}
- **着装风格**：{clothing_style}
- **标志性特征**：{distinctive_features}""",

            "personality": """- **核心性格**：{core_personality}
- **优点**：{strengths}
- **缺点**：{weaknesses}
- **价值观**：{values}
- **恐惧**：{fears}
- **渴望**：{desires}""",

            "background": """- **出身背景**：{origin}
- **关键经历**：{key_experiences}
- **转折点**：{turning_points}
- **未解之谜**：{unsolved_mysteries}""",

            "relationships": """- **与主角关系**：{relationship_with_protagonist}
- **重要关系人**：{important_relationships}
- **敌对关系**：{enemy_relationships}
- **情感羁绊**：{emotional_bonds}""",

            "development": """- **角色目标**：{goals}
- **内在冲突**：{internal_conflicts}
- **外在冲突**：{external_conflicts}
- **发展弧线**：{development_arc}
- **可能的结局**：{possible_endings}""",

            "notes": """- **灵感来源**：{inspiration_sources}
- **象征意义**：{symbolic_meanings}
- **潜在发展**：{potential_developments}""",

            "core_identity": """- **本质自我**：{true_self}
- **社会面具**：{social_mask}
- **理想自我**：{ideal_self}
- **恐惧自我**：{feared_self}""",

            "motivation": """- **表层目标**：{surface_goals}
- **情感需求**：{emotional_needs}
- **存在需求**：{existential_needs}
- **未意识需求**：{unconscious_needs}""",

            "core_belief": """- **世界观**：{worldview}
- **核心信念**：{core_beliefs}
- **正义观**：{justice_view}
- **变革愿景**：{change_vision}""",

            "mirror": """- **相似点**：{similarities}
- **分歧点**：{divergences}
- **对立逻辑**：{opposition_logic}
- **潜在转化**：{potential_transformation}""",

            "resources": """- **核心团队**：{core_team}
- **盟友势力**：{ally_forces}
- **影响范围**：{influence_scope}
- **弱点环节**：{weakness_points}""",

            "function": """- **推动剧情的方式**：{plot_push_methods}
- **服务主角的方式**：{protagonist_service_methods}
- **独特价值**：{unique_value}
- **退出时机**：{exit_timing}"""
        }

        template = section_templates.get(section_id, "")
        if not template:
            return ""

        # 从character_data中获取数据，如果不存在则使用占位符
        content = template
        for key in character_data:
            placeholder = "{" + key + "}"
            if placeholder in content:
                content = content.replace(placeholder, character_data.get(key, f"[待填写{key}]"))

        # 清理未替换的占位符
        import re
        content = re.sub(r'\{[^}]*\}', '[待填写]', content)

        return content

    def generate_markdown(self, character_data, output_path=None):
        """生成markdown档案

        Args:
            character_data: 角色数据字典，必须包含'name'字段
            output_path: 输出文件路径，如果为None则返回字符串

        Returns:
            如果output_path为None，返回markdown字符串；否则写入文件
        """
        if 'name' not in character_data:
            raise ValueError("角色数据必须包含'name'字段")

        template = self.templates.get(self.template_type, self.templates["standard"])

        # 生成markdown内容
        lines = []
        lines.append(f"# {character_data['name']} - 角色档案")
        lines.append("")
        lines.append(f"> 生成时间：{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        lines.append(f"> 模板类型：{template['name']}")
        lines.append("")

        for section in template['sections']:
            section_id = section['id']
            section_title = section['title']

            lines.append(f"## {section_title}")
            lines.append("")

            content = self._get_section_content(section_id, character_data)
            if content:
                lines.append(content)
            else:
                lines.append(f"*{section_title}内容待填写*")

            lines.append("")

        # 添加元数据部分
        lines.append("---")
        lines.append("")
        lines.append("## 档案元数据")
        lines.append("")
        lines.append(f"- **角色类型**：{template['name']}")
        lines.append(f"- **创建时间**：{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        lines.append(f"- **状态**：{'草稿' if character_data.get('status') != 'final' else '完成'}")
        lines.append(f"- **版本**：{character_data.get('version', '1.0')}")
        lines.append("")

        markdown_content = "\n".join(lines)

        if output_path:
            # 确保目录存在
            output_dir = os.path.dirname(output_path)
            if output_dir:
                os.makedirs(output_dir, exist_ok=True)

            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(markdown_content)

            print(f"档案已生成：{output_path}")
            return output_path
        else:
            return markdown_content

    def generate_enhanced_profile(self, character_data, require_confirmation=True):
        """使用增强功能生成角色档案

        Args:
            character_data: 角色数据字典，必须包含'name'字段
            require_confirmation: 是否需要用户确认

        Returns:
            (是否成功, 最终文件路径, 冲突列表)
        """
        if not self.enable_enhanced_features:
            logger.error("增强功能未启用，请指定workspace参数初始化生成器")
            return False, None, []

        if 'name' not in character_data:
            raise ValueError("角色数据必须包含'name'字段")

        # 初始化增强组件
        if self.lore_bible_manager is None:
            self._init_enhanced_components()

        if not self.enable_enhanced_features:
            return False, None, []

        try:
            from profile_session import ProfileSession, SessionConfig

            # 更新会话配置
            self.session_config.character_name = character_data['name']
            self.session_config.require_confirmation = require_confirmation

            # 创建会话
            session = ProfileSession(self.session_config)

            # 生成基础markdown内容
            markdown_content = self.generate_markdown(character_data, output_path=None)

            # 保存临时档案
            temp_path = session.save_temp_profile(markdown_content)
            if not temp_path:
                logger.error("保存临时档案失败")
                return False, None, []

            # 验证和冲突检测
            is_valid, conflicts = session.validate_and_check_conflicts(character_data)

            # 展示给用户
            if require_confirmation:
                user_confirmed = session.present_to_user(conflicts)
                if not user_confirmed:
                    logger.info("用户取消创建")
                    session.cancel()
                    return False, None, conflicts
            else:
                logger.info("跳过用户确认")

            # 确认并移动
            final_path = session.confirm_and_move()
            if not final_path:
                logger.error("移动档案失败")
                return False, None, conflicts

            # 清理会话
            session.cleanup()

            logger.info(f"角色档案创建成功: {final_path}")
            return True, final_path, conflicts

        except Exception as e:
            logger.error(f"增强生成失败: {e}")
            return False, None, []

    def create_from_cli(self):
        """从命令行交互创建"""
        print("=== 人物档案生成器 ===")
        print("")

        # 选择模板
        print("请选择角色类型：")
        print("1. 主角")
        print("2. 反派")
        print("3. 配角")
        print("4. 标准")

        choice = input("请输入选择 (1-4，默认4): ").strip()
        type_map = {"1": "protagonist", "2": "antagonist", "3": "supporting", "4": "standard"}
        template_type = type_map.get(choice, "standard")

        self.template_type = template_type
        print(f"使用模板：{self.templates[template_type]['name']}")
        print("")

        # 收集基本信息
        character_data = {}
        print("请输入角色基本信息：")
        character_data['name'] = input("角色姓名: ").strip() or "未命名角色"
        character_data['age'] = input("年龄: ").strip() or "未知"
        character_data['gender'] = input("性别: ").strip() or "未指定"
        character_data['occupation'] = input("职业/身份: ").strip() or "未指定"
        character_data['role'] = input("故事中的角色: ").strip() or "未指定"

        print("")
        print("其他信息将在生成的档案中以占位符形式出现，请后续编辑完善。")

        # 生成文件名
        safe_name = "".join(c for c in character_data['name'] if c.isalnum() or c in (' ', '-', '_')).rstrip()
        filename = f"character_profile_{safe_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md"

        # 选择输出路径
        default_output = os.path.join(os.getcwd(), filename)
        output_path = input(f"输出文件路径 (默认: {default_output}): ").strip() or default_output

        # 生成档案
        try:
            result = self.generate_markdown(character_data, output_path)
            print("")
            print("✓ 人物档案生成成功！")
            print(f"文件位置: {result if isinstance(result, str) else output_path}")
            print("")
            print("下一步：")
            print("1. 使用文本编辑器打开生成的markdown文件")
            print("2. 根据模板提示填写详细信息")
            print("3. 保存并用于创作参考")

        except Exception as e:
            print(f"生成失败: {e}")
            return 1

        return 0


def main():
    """主函数"""
    if len(sys.argv) > 1:
        # 命令行参数模式
        import argparse

        parser = argparse.ArgumentParser(description='生成人物档案markdown文件')
        parser.add_argument('--type', '-t', choices=['protagonist', 'antagonist', 'supporting', 'standard'],
                          default='standard', help='角色类型')
        parser.add_argument('--name', '-n', required=True, help='角色姓名')
        parser.add_argument('--age', help='年龄')
        parser.add_argument('--gender', help='性别')
        parser.add_argument('--occupation', help='职业/身份')
        parser.add_argument('--role', help='故事中的角色')
        parser.add_argument('--output', '-o', help='输出文件路径')
        parser.add_argument('--workspace', '-w', help='工作目录路径，启用LoreBible管理功能')
        parser.add_argument('--no-confirm', action='store_true', help='跳过用户确认（仅增强模式）')
        parser.add_argument('--interactive', '-i', action='store_true', help='交互模式')

        args = parser.parse_args()

        if args.interactive:
            # 交互模式，暂时不支持增强功能
            generator = CharacterProfileGenerator(args.type)
            return generator.create_from_cli()
        else:
            character_data = {
                'name': args.name,
                'age': args.age or '未知',
                'gender': args.gender or '未指定',
                'occupation': args.occupation or '未指定',
                'role': args.role or '未指定'
            }

            # 检查是否启用增强模式
            if args.workspace:
                # 增强模式
                generator = CharacterProfileGenerator(args.type, workspace=args.workspace)

                # 使用增强生成
                success, final_path, conflicts = generator.generate_enhanced_profile(
                    character_data,
                    require_confirmation=not args.no_confirm
                )

                if success:
                    print(f"✓ 角色档案创建成功: {final_path}")
                    if conflicts:
                        print(f"   检测到 {len(conflicts)} 个问题，已处理")
                    return 0
                else:
                    print(f"✗ 角色档案创建失败")
                    if conflicts:
                        print(f"   存在 {len(conflicts)} 个问题需要解决")
                    return 1
            else:
                # 传统模式
                generator = CharacterProfileGenerator(args.type)

                if args.output:
                    output_path = args.output
                else:
                    safe_name = "".join(c for c in args.name if c.isalnum() or c in (' ', '-', '_')).rstrip()
                    filename = f"character_profile_{safe_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md"
                    output_path = os.path.join(os.getcwd(), filename)

                result = generator.generate_markdown(character_data, output_path)
                print(f"档案已生成: {output_path}")
                return 0
    else:
        # 交互模式
        generator = CharacterProfileGenerator()
        return generator.create_from_cli()


if __name__ == "__main__":
    sys.exit(main())

path: scripts/lore_bible_manager.py
content: #!/usr/bin/env python3
"""
LoreBible目录管理模块
负责管理LoreBible目录结构、文件操作和现有角色扫描
"""

import os
import json
import re
from pathlib import Path
from typing import Dict, List, Optional, Set, Tuple
import logging

logger = logging.getLogger(__name__)


class LoreBibleManager:
    """LoreBible目录管理器"""

    # 标准目录结构
    DEFAULT_DIRECTORY_STRUCTURE = {
        "00_Prepare": "临时档案目录",
        "01_Research": "研究资料目录",
        "02_LoreBible": {
            "Characters": "角色档案目录",
            "Locations": "地点设定目录",
            "Organizations": "组织设定目录",
            "Timeline": "时间线目录"
        }
    }

    def __init__(self, workspace: str):
        """初始化LoreBible管理器

        Args:
            workspace: 工作目录路径
        """
        self.workspace = Path(workspace).resolve()
        self.characters_dir = self.workspace / "02_LoreBible" / "Characters"
        self.prepare_dir = self.workspace / "00_Prepare"
        self._character_index = None  # 角色信息索引缓存

    def validate_directory_structure(self) -> Tuple[bool, List[str]]:
        """验证目录结构是否符合标准

        Returns:
            (是否有效, 缺失目录列表)
        """
        missing_dirs = []

        # 检查必需目录
        required_dirs = [
            self.workspace,
            self.characters_dir,
            self.prepare_dir
        ]

        for dir_path in required_dirs:
            if not dir_path.exists():
                missing_dirs.append(str(dir_path.relative_to(self.workspace)))

        return len(missing_dirs) == 0, missing_dirs

    def create_directory_structure(self) -> bool:
        """创建缺失的目录结构

        Returns:
            是否成功创建
        """
        try:
            # 创建必需目录
            self.characters_dir.mkdir(parents=True, exist_ok=True)
            self.prepare_dir.mkdir(parents=True, exist_ok=True)

            # 创建可选目录
            optional_dirs = [
                self.workspace / "01_Research",
                self.workspace / "02_LoreBible" / "Locations",
                self.workspace / "02_LoreBible" / "Organizations",
                self.workspace / "02_LoreBible" / "Timeline"
            ]

            for dir_path in optional_dirs:
                dir_path.mkdir(parents=True, exist_ok=True)

            logger.info(f"目录结构已创建在: {self.workspace}")
            return True

        except Exception as e:
            logger.error(f"创建目录结构失败: {e}")
            return False

    def scan_existing_characters(self) -> List[Dict]:
        """扫描现有角色档案

        Returns:
            角色信息列表
        """
        if not self.characters_dir.exists():
            return []

        characters = []
        pattern = re.compile(r'\.md$', re.IGNORECASE)

        for file_path in self.characters_dir.glob("*.md"):
            try:
                character_info = self._parse_character_file(file_path)
                if character_info:
                    characters.append(character_info)
            except Exception as e:
                logger.warning(f"解析角色文件失败 {file_path}: {e}")

        return characters

    def _parse_character_file(self, file_path: Path) -> Optional[Dict]:
        """解析单个角色档案文件

        Args:
            file_path: 角色档案文件路径

        Returns:
            角色信息字典，解析失败返回None
        """
        try:
            content = file_path.read_text(encoding='utf-8', errors='ignore')

            # 提取基本信息
            info = {
                "file_path": str(file_path),
                "file_name": file_path.name,
                "file_size": file_path.stat().st_size,
                "last_modified": file_path.stat().st_mtime
            }

            # 提取角色姓名（从标题行）
            name_match = re.search(r'^#\s+(.+?)\s+-', content, re.MULTILINE)
            if name_match:
                info["name"] = name_match.group(1).strip()
            else:
                # 尝试从文件名提取
                info["name"] = file_path.stem.replace('character_profile_', '').replace('_', ' ')

            # 提取年龄
            age_match = re.search(r'- \*\*年龄\*\*[：:]\s*(.+?)(?:\n|$)', content)
            if age_match:
                info["age"] = age_match.group(1).strip()

            # 提取性别
            gender_match = re.search(r'- \*\*性别\*\*[：:]\s*(.+?)(?:\n|$)', content)
            if gender_match:
                info["gender"] = gender_match.group(1).strip()

            # 提取职业/身份
            occupation_match = re.search(r'- \*\*职业/身份\*\*[：:]\s*(.+?)(?:\n|$)', content)
            if occupation_match:
                info["occupation"] = occupation_match.group(1).strip()

            # 提取故事中的角色
            role_match = re.search(r'- \*\*故事中的角色\*\*[：:]\s*(.+?)(?:\n|$)', content)
            if role_match:
                info["role"] = role_match.group(1).strip()

            # 提取角色类型（从元数据）
            type_match = re.search(r'- \*\*角色类型\*\*[：:]\s*(.+?)(?:\n|$)', content)
            if type_match:
                info["character_type"] = type_match.group(1).strip()

            # 提取创建时间
            created_match = re.search(r'- \*\*创建时间\*\*[：:]\s*(.+?)(?:\n|$)', content)
            if created_match:
                info["created"] = created_match.group(1).strip()

            # 提取状态
            status_match = re.search(r'- \*\*状态\*\*[：:]\s*(.+?)(?:\n|$)', content)
            if status_match:
                info["status"] = status_match.group(1).strip()

            # 提取关系信息（简单提取）
            relationships_section = self._extract_section(content, "人物关系")
            if relationships_section:
                info["has_relationships"] = True
                # 可以进一步解析具体关系

            # 提取背景故事
            background_section = self._extract_section(content, "背景故事")
            if background_section:
                info["has_background"] = True

            return info

        except Exception as e:
            logger.error(f"解析角色文件失败 {file_path}: {e}")
            return None

    def _extract_section(self, content: str, section_title: str) -> Optional[str]:
        """提取指定章节内容

        Args:
            content: 文档内容
            section_title: 章节标题

        Returns:
            章节内容，未找到返回None
        """
        # 寻找章节标题
        pattern = rf'##\s+{re.escape(section_title)}(.*?)(?=##\s+|---|\Z)'
        match = re.search(pattern, content, re.DOTALL | re.IGNORECASE)

        if match:
            return match.group(1).strip()
        return None

    def get_character_index(self, force_refresh: bool = False) -> Dict:
        """获取角色信息索引（带缓存）

        Args:
            force_refresh: 是否强制刷新缓存

        Returns:
            角色索引字典
        """
        if self._character_index is None or force_refresh:
            characters = self.scan_existing_characters()
            self._character_index = {
                "total_count": len(characters),
                "characters": characters,
                "name_map": {char.get("name", ""): char for char in characters if char.get("name")},
                "by_type": self._group_by_type(characters),
                "last_updated": os.path.getmtime(self.characters_dir) if self.characters_dir.exists() else 0
            }

        return self._character_index

    def _group_by_type(self, characters: List[Dict]) -> Dict:
        """按角色类型分组

        Args:
            characters: 角色列表

        Returns:
            按类型分组的字典
        """
        grouped = {}
        for char in characters:
            char_type = char.get("character_type", "未知")
            if char_type not in grouped:
                grouped[char_type] = []
            grouped[char_type].append(char)
        return grouped

    def save_temp_profile(self, content: str, character_name: str, session_id: str = None) -> Optional[Path]:
        """保存临时档案到00_Prepare目录

        Args:
            content: 档案内容
            character_name: 角色名称
            session_id: 会话ID，为None时自动生成

        Returns:
            临时文件路径，失败返回None
        """
        try:
            if not self.prepare_dir.exists():
                self.prepare_dir.mkdir(parents=True, exist_ok=True)

            # 生成会话ID
            import uuid
            if session_id is None:
                session_id = str(uuid.uuid4())[:8]

            # 安全文件名
            safe_name = re.sub(r'[^\w\s-]', '', character_name).strip()
            safe_name = re.sub(r'[-\s]+', '_', safe_name)

            # 临时文件名
            filename = f"temp_{safe_name}_{session_id}.md"
            temp_path = self.prepare_dir / filename

            # 写入文件
            temp_path.write_text(content, encoding='utf-8')
            logger.info(f"临时档案已保存: {temp_path}")

            return temp_path

        except Exception as e:
            logger.error(f"保存临时档案失败: {e}")
            return None

    def move_to_characters(self, temp_file_path: Path, character_name: str = None) -> Optional[Path]:
        """将临时档案移动到Characters目录

        Args:
            temp_file_path: 临时文件路径
            character_name: 角色名称，为None时从文件内容提取

        Returns:
            最终文件路径，失败返回None
        """
        try:
            if not temp_file_path.exists():
                logger.error(f"临时文件不存在: {temp_file_path}")
                return None

            # 确保目标目录存在
            if not self.characters_dir.exists():
                self.characters_dir.mkdir(parents=True, exist_ok=True)

            # 读取内容提取角色名
            if character_name is None:
                content = temp_file_path.read_text(encoding='utf-8', errors='ignore')
                name_match = re.search(r'^#\s+(.+?)\s+-', content, re.MULTILINE)
                if name_match:
                    character_name = name_match.group(1).strip()
                else:
                    character_name = temp_file_path.stem.replace('temp_', '').split('_')[0]

            # 安全文件名
            safe_name = re.sub(r'[^\w\s-]', '', character_name).strip()
            safe_name = re.sub(r'[-\s]+', '_', safe_name)

            # 最终文件名
            import datetime
            timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"character_profile_{safe_name}_{timestamp}.md"
            final_path = self.characters_dir / filename

            # 移动文件
            temp_file_path.rename(final_path)
            logger.info(f"档案已移动到: {final_path}")

            # 刷新缓存
            self._character_index = None

            return final_path

        except Exception as e:
            logger.error(f"移动档案失败: {e}")
            return None

    def cleanup_old_temp_files(self, max_age_hours: int = 24) -> int:
        """清理旧的临时文件

        Args:
            max_age_hours: 最大保留时间（小时）

        Returns:
            清理的文件数量
        """
        if not self.prepare_dir.exists():
            return 0

        import time
        current_time = time.time()
        max_age_seconds = max_age_hours * 3600

        cleaned_count = 0

        for file_path in self.prepare_dir.glob("temp_*.md"):
            try:
                file_age = current_time - file_path.stat().st_mtime
                if file_age > max_age_seconds:
                    file_path.unlink()
                    cleaned_count += 1
                    logger.debug(f"清理临时文件: {file_path}")
            except Exception as e:
                logger.warning(f"清理文件失败 {file_path}: {e}")

        if cleaned_count > 0:
            logger.info(f"清理了 {cleaned_count} 个临时文件")

        return cleaned_count

    def get_workspace_info(self) -> Dict:
        """获取工作空间信息

        Returns:
            工作空间信息字典
        """
        info = {
            "workspace": str(self.workspace),
            "characters_dir": str(self.characters_dir),
            "prepare_dir": str(self.prepare_dir),
            "characters_count": 0,
            "temp_files_count": 0,
            "directory_exists": self.workspace.exists()
        }

        if self.characters_dir.exists():
            info["characters_count"] = len(list(self.characters_dir.glob("*.md")))

        if self.prepare_dir.exists():
            info["temp_files_count"] = len(list(self.prepare_dir.glob("temp_*.md")))

        return info


def main():
    """命令行测试"""
    import sys

    if len(sys.argv) < 2:
        print("用法: python lore_bible_manager.py <工作目录>")
        sys.exit(1)

    workspace = sys.argv[1]
    manager = LoreBibleManager(workspace)

    print(f"工作目录: {workspace}")

    # 验证目录结构
    is_valid, missing_dirs = manager.validate_directory_structure()
    if is_valid:
        print("✓ 目录结构完整")
    else:
        print("✗ 缺失目录:")
        for dir_name in missing_dirs:
            print(f"  - {dir_name}")

        # 询问是否创建
        response = input("是否创建缺失目录? (y/n): ").strip().lower()
        if response == 'y':
            if manager.create_directory_structure():
                print("✓ 目录结构已创建")
            else:
                print("✗ 创建目录失败")

    # 扫描现有角色
    characters = manager.scan_existing_characters()
    print(f"现有角色数量: {len(characters)}")

    for char in characters[:5]:  # 显示前5个
        print(f"  - {char.get('name', '未知')} ({char.get('character_type', '未知类型')})")

    if len(characters) > 5:
        print(f"  ... 还有 {len(characters) - 5} 个角色")

    # 显示工作空间信息
    info = manager.get_workspace_info()
    print(f"\n工作空间信息:")
    print(f"  角色档案数: {info['characters_count']}")
    print(f"  临时文件数: {info['temp_files_count']}")


if __name__ == "__main__":
    main()

path: test_profiles/test_character.md
content: # 测试角色 - 角色档案

> 生成时间：2026-01-26 01:42:27
> 模板类型：主角模板

## 基本信息

- **姓名**：测试角色
- **年龄**：25
- **性别**：男
- **职业/身份**：测试职业
- **故事中的角色**：测试角色

## 外貌特征

- **整体印象**：[待填写]
- **面部特征**：[待填写]
- **身材体型**：[待填写]
- **着装风格**：[待填写]
- **标志性特征**：[待填写]

## 性格特点

- **核心性格**：[待填写]
- **优点**：[待填写]
- **缺点**：[待填写]
- **价值观**：[待填写]
- **恐惧**：[待填写]
- **渴望**：[待填写]

## 背景故事

- **出身背景**：[待填写]
- **关键经历**：[待填写]
- **转折点**：[待填写]
- **未解之谜**：[待填写]

## 动机层次

- **表层目标**：[待填写]
- **情感需求**：[待填写]
- **存在需求**：[待填写]
- **未意识需求**：[待填写]

## 人物关系

- **与主角关系**：[待填写]
- **重要关系人**：[待填写]
- **敌对关系**：[待填写]
- **情感羁绊**：[待填写]

## 故事发展

- **角色目标**：[待填写]
- **内在冲突**：[待填写]
- **外在冲突**：[待填写]
- **发展弧线**：[待填写]
- **可能的结局**：[待填写]

## 核心身份

- **本质自我**：[待填写]
- **社会面具**：[待填写]
- **理想自我**：[待填写]
- **恐惧自我**：[待填写]

## 创作笔记

- **灵感来源**：[待填写]
- **象征意义**：[待填写]
- **潜在发展**：[待填写]

---

## 档案元数据

- **角色类型**：主角模板
- **创建时间**：2026-01-26 01:42:27
- **状态**：草稿
- **版本**：1.0


Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)