novel-writer-cli 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +103 -0
  3. package/agents/chapter-writer.md +142 -0
  4. package/agents/character-weaver.md +117 -0
  5. package/agents/consistency-auditor.md +85 -0
  6. package/agents/plot-architect.md +128 -0
  7. package/agents/quality-judge.md +232 -0
  8. package/agents/style-analyzer.md +109 -0
  9. package/agents/style-refiner.md +97 -0
  10. package/agents/summarizer.md +128 -0
  11. package/agents/world-builder.md +161 -0
  12. package/dist/__tests__/character-voice.test.js +445 -0
  13. package/dist/__tests__/commit-prototype-pollution.test.js +45 -0
  14. package/dist/__tests__/engagement.test.js +382 -0
  15. package/dist/__tests__/foreshadow-visibility.test.js +131 -0
  16. package/dist/__tests__/hook-ledger.test.js +1028 -0
  17. package/dist/__tests__/naming-lint.test.js +132 -0
  18. package/dist/__tests__/narrative-health-injection.test.js +359 -0
  19. package/dist/__tests__/next-step-prejudge-guardrails.test.js +325 -0
  20. package/dist/__tests__/next-step-title-fix.test.js +153 -0
  21. package/dist/__tests__/platform-profile.test.js +274 -0
  22. package/dist/__tests__/promise-ledger.test.js +189 -0
  23. package/dist/__tests__/readability-lint.test.js +209 -0
  24. package/dist/__tests__/text-utils.test.js +39 -0
  25. package/dist/__tests__/title-policy.test.js +147 -0
  26. package/dist/advance.js +75 -0
  27. package/dist/character-voice.js +805 -0
  28. package/dist/checkpoint.js +126 -0
  29. package/dist/cli.js +563 -0
  30. package/dist/cliche-lint.js +515 -0
  31. package/dist/commit.js +1460 -0
  32. package/dist/consistency-auditor.js +684 -0
  33. package/dist/engagement.js +687 -0
  34. package/dist/errors.js +7 -0
  35. package/dist/fingerprint.js +16 -0
  36. package/dist/foreshadow-visibility.js +214 -0
  37. package/dist/fs-utils.js +68 -0
  38. package/dist/hook-ledger.js +721 -0
  39. package/dist/hook-policy.js +107 -0
  40. package/dist/instruction-gates.js +51 -0
  41. package/dist/instructions.js +406 -0
  42. package/dist/latest-summary-loader.js +29 -0
  43. package/dist/lock.js +121 -0
  44. package/dist/naming-lint.js +531 -0
  45. package/dist/ner.js +73 -0
  46. package/dist/next-step.js +408 -0
  47. package/dist/novel-ask.js +270 -0
  48. package/dist/output.js +9 -0
  49. package/dist/platform-constraints.js +518 -0
  50. package/dist/platform-profile.js +325 -0
  51. package/dist/prejudge-guardrails.js +370 -0
  52. package/dist/project.js +40 -0
  53. package/dist/promise-ledger.js +723 -0
  54. package/dist/readability-lint.js +555 -0
  55. package/dist/safe-parse.js +36 -0
  56. package/dist/safe-path.js +29 -0
  57. package/dist/scoring-weights.js +290 -0
  58. package/dist/steps.js +60 -0
  59. package/dist/text-utils.js +18 -0
  60. package/dist/title-policy.js +251 -0
  61. package/dist/type-guards.js +6 -0
  62. package/dist/validate.js +131 -0
  63. package/docs/user/README.md +17 -0
  64. package/docs/user/guardrails.md +179 -0
  65. package/docs/user/interactive-gates.md +124 -0
  66. package/docs/user/novel-cli.md +289 -0
  67. package/docs/user/ops.md +123 -0
  68. package/docs/user/quick-start.md +97 -0
  69. package/docs/user/spec-system.md +166 -0
  70. package/docs/user/storylines.md +144 -0
  71. package/package.json +48 -0
  72. package/schemas/README.md +18 -0
  73. package/schemas/character-voice-drift.schema.json +135 -0
  74. package/schemas/character-voice-profiles.schema.json +141 -0
  75. package/schemas/engagement-metrics.schema.json +38 -0
  76. package/schemas/hook-ledger.schema.json +108 -0
  77. package/schemas/platform-profile.schema.json +235 -0
  78. package/schemas/promise-ledger.schema.json +97 -0
  79. package/scripts/calibrate-quality-judge.sh +91 -0
  80. package/scripts/compare-regression-runs.sh +86 -0
  81. package/scripts/lib/_common.py +131 -0
  82. package/scripts/lib/calibrate_quality_judge.py +312 -0
  83. package/scripts/lib/compare_regression_runs.py +142 -0
  84. package/scripts/lib/run_regression.py +621 -0
  85. package/scripts/lint-blacklist.sh +201 -0
  86. package/scripts/lint-cliche.sh +370 -0
  87. package/scripts/lint-readability.sh +404 -0
  88. package/scripts/query-foreshadow.sh +252 -0
  89. package/scripts/run-ner.sh +669 -0
  90. package/scripts/run-regression.sh +122 -0
  91. package/skills/cli-step/SKILL.md +158 -0
  92. package/skills/continue/SKILL.md +348 -0
  93. package/skills/continue/references/context-contracts.md +169 -0
  94. package/skills/continue/references/continuity-checks.md +187 -0
  95. package/skills/continue/references/file-protocols.md +64 -0
  96. package/skills/continue/references/foreshadowing.md +130 -0
  97. package/skills/continue/references/gate-decision.md +53 -0
  98. package/skills/continue/references/periodic-maintenance.md +46 -0
  99. package/skills/novel-writing/SKILL.md +77 -0
  100. package/skills/novel-writing/references/quality-rubric.md +140 -0
  101. package/skills/novel-writing/references/style-guide.md +145 -0
  102. package/skills/start/SKILL.md +458 -0
  103. package/skills/start/references/quality-review.md +86 -0
  104. package/skills/start/references/setting-update.md +44 -0
  105. package/skills/start/references/vol-planning.md +61 -0
  106. package/skills/start/references/vol-review.md +58 -0
  107. package/skills/status/SKILL.md +116 -0
  108. package/skills/status/references/sample-output.md +60 -0
  109. package/templates/ai-blacklist.json +79 -0
  110. package/templates/brief-template.md +46 -0
  111. package/templates/genre-weight-profiles.json +90 -0
  112. package/templates/novel-ask/example.answer.json +12 -0
  113. package/templates/novel-ask/example.question.json +51 -0
  114. package/templates/platform-profile.json +148 -0
  115. package/templates/style-profile-template.json +58 -0
  116. package/templates/web-novel-cliche-lint.json +41 -0
@@ -0,0 +1,61 @@
1
+ # 规划本卷 / 规划新卷
2
+
3
+ > 仅当 `orchestrator_state == "VOL_PLANNING"`(或完成卷末回顾后进入 VOL_PLANNING)时执行。
4
+
5
+ 0. 计算本卷规划章节范围(确定性):
6
+ - `V = current_volume`
7
+ - `plan_start = last_completed_chapter + 1`
8
+ - `plan_end = V * 30`(每卷 30 章约定;如 `plan_start > plan_end` 视为数据异常,提示用户先修复 `.checkpoint.json`)
9
+ - 创建目录(幂等):`mkdir -p staging/volumes/vol-{V:02d}/chapter-contracts`
10
+ 1. 若 `.checkpoint.json.pending_actions` 存在与本卷有关的 `type == "spec_propagation"` 待办(例如世界规则/角色契约变更影响到 `plan_start..plan_end`):
11
+ - 展示待办摘要(变更项 + 受影响角色/章节契约)
12
+ - AskUserQuestion 让用户选择:
13
+ 1) 先处理待办并重新生成受影响契约 (Recommended)
14
+ 2) 继续规划(保留待办,后续人工处理)
15
+ 3) 取消
16
+ 2. 组装 PlotArchitect context(确定性,按 `docs/dr-workflow/novel-writer-tool/final/prd/08-orchestrator.md` §8.3):
17
+ - `volume_plan`: `{ "volume": V, "chapter_range": [plan_start, plan_end] }`
18
+ - `prev_volume_review`:读取 `volumes/vol-{V-1:02d}/review.md`(如存在,以 `<DATA type="summary" ...>` 注入)
19
+ - `global_foreshadowing`:读取 `foreshadowing/global.json`
20
+ - 可选:`promise_ledger_report_summary`:读取 `logs/promises/latest.json`(如存在)并裁剪为小体积摘要(建议仅保留 scope/stats/issues/dormant_promises 的前 5 条),作为“承诺推进/沉默提醒”的规划上下文(非剧透、不兑现)
21
+ - 可选:`engagement_report_summary`:读取 `logs/engagement/latest.json`(如存在)并裁剪为小体积摘要(建议仅保留 scope/stats/issues 的前 5 条),作为“爽点/推进密度”窗口提示(非剧透)
22
+ - 可选:`foreshadow_light_touch_tasks`:读取 `logs/foreshadowing/latest.json`(如存在)并从其中 `dormant_items[]` 提取(按沉默章数降序,建议取前 10)。字段建议:
23
+ - `{id, scope, status, chapters_since_last_update, instruction}`,其中 `instruction` 使用报告中的 `planning_task`(非剧透,不兑现)
24
+ - `storylines`:读取 `storylines/storylines.json`
25
+ - `world_docs`:读取 `world/*.md`(以 `<DATA type="world_doc" ...>` 注入)+ `world/rules.json`(结构化 JSON)
26
+ - `characters`:读取 `characters/active/*.md`(以 `<DATA type="character_profile" ...>` 注入)+ `characters/active/*.json`(L2 contracts 结构化 JSON)
27
+ - `user_direction`:用户额外方向指示(如有)
28
+ - `prev_chapter_summaries`(首卷替代 `prev_volume_review`):若 `prev_volume_review` 不存在且 `last_completed_chapter > 0`,读取最近 3 章 `summaries/chapter-*-summary.md` 作为上下文(黄金三章是 QUICK_START 多轮交互的核心产出,PlotArchitect 必须基于其已建立的人物关系和情节基调规划后续章节),以 `<DATA type="summary" ...>` 注入
29
+ 3. 使用 Task 派发 PlotArchitect Agent 生成本卷规划产物(写入 staging 目录,step 6 commit 到正式路径):
30
+ - `staging/volumes/vol-{V:02d}/outline.md`(严格格式:每章 `###` 区块 + 固定 `- **Key**:` 行)
31
+ - `staging/volumes/vol-{V:02d}/storyline-schedule.json`
32
+ - `staging/volumes/vol-{V:02d}/foreshadowing.json`
33
+ - `staging/volumes/vol-{V:02d}/new-characters.json`(可为空数组)
34
+ - `staging/volumes/vol-{V:02d}/chapter-contracts/chapter-{C:03d}.json`(`C ∈ [plan_start, plan_end]`)
35
+ - (注意:`foreshadowing/global.json` 为事实索引,由 `/novel:continue` 在每章 commit 阶段从 `foreshadow` ops 更新;卷规划阶段不生成/覆盖 global.json)
36
+ 4. 规划产物校验(对 `staging/` 下的产物执行;失败则停止并给出修复建议,禁止"缺文件继续写"导致断链):
37
+ - `outline.md` 可解析:可用 `/^### 第 (\\d+) 章/` 找到章节区块,且连续覆盖 `plan_start..plan_end`(不允许跳章,否则下游契约缺失会导致流水线崩溃)
38
+ - 每个章节区块包含固定 key 行:`Storyline/POV/Location/Conflict/Arc/Foreshadowing/StateChanges/TransitionHint`
39
+ - 允许 `TransitionHint` 值为空;但 key 行必须存在(便于机器解析)
40
+ - `storyline-schedule.json` 可解析(JSON),`active_storylines` ≤ 4,且本卷 `outline.md` 中出现的 `storyline_id` 均属于 `active_storylines`
41
+ - `chapter-contracts/` 全量存在且可解析(JSON),并满足最小一致性检查:
42
+ - `chapter == C`
43
+ - `storyline_id` 与 outline 中 `- **Storyline**:` 一致
44
+ - `objectives` 至少 1 条 `required: true`
45
+ - 链式传递检查(最小实现):若 `chapter-{C-1}.json.postconditions.state_changes` 中出现角色 X,则 `chapter-{C}.json.preconditions.character_states` 必须包含 X(值可不同,代表显式覆盖)。对 `plan_start` 章:若 `chapter-{plan_start-1}.json` 不存在(如首卷试写章无契约),跳过该章的链式传递检查,其 preconditions 由 PlotArchitect 从试写摘要派生
46
+ - `foreshadowing.json` 与 `new-characters.json` 均存在且为合法 JSON
47
+ 5. 审核点交互(AskUserQuestion):
48
+ - 展示摘要:
49
+ - `storyline-schedule.json` 的活跃线与交汇事件概览
50
+ - 每章 1 行清单:`Ch C | Storyline | Conflict | required objectives 简写`
51
+ - 让用户选择:
52
+ 1) 确认并进入写作 (Recommended)
53
+ 2) 我想调整方向并重新生成(清空 `staging/volumes/` 和 `staging/foreshadowing/` 后重新派发 PlotArchitect)
54
+ 3) 暂不进入写作(保持 VOL_PLANNING,规划产物保留在 staging 中)
55
+ 6. 若确认进入写作:
56
+ - commit 规划产物(staging → 正式目录):
57
+ - `mv staging/volumes/vol-{V:02d}/* → volumes/vol-{V:02d}/`(幂等覆盖)
58
+ - 清空 `staging/volumes/` 和 `staging/foreshadowing/`
59
+ - 读取 `volumes/vol-{V:02d}/new-characters.json`:
60
+ - 若非空:批量调用 CharacterWeaver 创建角色档案 + L2 契约(按 `first_chapter` 升序派发 Task,便于先创建早出场角色)
61
+ - 更新 `.checkpoint.json`(`orchestrator_state = "WRITING"`, `pipeline_stage = null`, `inflight_chapter = null`, `revision_count = 0`)
@@ -0,0 +1,58 @@
1
+ # 卷末回顾
2
+
3
+ 1. 收集本卷 `evaluations/`、`summaries/`、`foreshadowing/global.json`、`storylines/`,生成本卷回顾要点(质量趋势、低分章节、未回收伏笔、故事线节奏、桥梁断链)
4
+ 2. **全卷一致性报告(NER)**:
5
+ - 章节范围:优先使用本卷 `outline.md` 解析得到的 `[chapter_start, chapter_end]`;若解析失败则退化为”本卷 evaluations/ 与 summaries/ 中匹配 `chapter-(\d{3})` 的章节号集合,取 min/max 作为范围”
6
+ - 实体抽取与报告 schema:见 `skills/continue/references/continuity-checks.md`
7
+ - 若存在 `${NOVEL_CLI_ROOT}/scripts/run-ner.sh`:逐章执行抽取;否则回退 LLM(优先 summaries,必要时回看 chapters),按同一 schema 抽取 entities,并为每类实体输出 confidence
8
+ - 输出 timeline/location/relationship/mapping 等 issues(含 severity/confidence/evidence/suggestions)
9
+ - 落盘:
10
+ - 写入 `volumes/vol-{V:02d}/continuity-report.json`
11
+ - 同步写入/覆盖 `logs/continuity/latest.json`(供后续 `/novel:continue` 注入 QualityJudge LS-001)
12
+ 3. **伏笔盘点 + 桥梁检查 + 节奏分析**(卷级汇总;不阻断):
13
+ - 章节范围:使用 Step 2 得到的 `[chapter_start, chapter_end]`
14
+ - Read(如存在):
15
+ - 本卷伏笔计划:`volumes/vol-{V:02d}/foreshadowing.json`
16
+ - 本卷故事线调度:`volumes/vol-{V:02d}/storyline-schedule.json`
17
+ - 全局故事线定义:`storylines/storylines.json`
18
+ - 伏笔盘点(计划 vs 事实):
19
+ - planned_total:本卷 plan 中条目数(如 plan 缺失则为 0)
20
+ - resolved_in_global:plan 中 id 在 `foreshadowing/global.json` 存在且 status==resolved
21
+ - pending_in_global:plan 中 id 在 global 存在且 status!=resolved
22
+ - missing_in_global:plan 中 id 在 global 不存在(可能“计划未埋设”或“Summarizer 漏提取”)
23
+ - overdue_short:同质量回顾规则(`scope=="short"` 且未回收且超过 `target_resolve_range` 上限)(规则定义见 `skills/continue/references/foreshadowing.md` §4)
24
+ - 落盘:写入 `volumes/vol-{V:02d}/foreshadowing-report.json`
25
+ - 桥梁检查(shared_foreshadowing traceable):
26
+ - 若 `relationships` 为空或不存在:跳过桥梁检查
27
+ - 对 `storylines/storylines.json.relationships[].bridges.shared_foreshadowing[]` 的每个 id:
28
+ - 若存在于 global 或本卷 plan → ok,否则记为 broken(含 from/to/type + 建议动作)
29
+ - 落盘:写入 `volumes/vol-{V:02d}/broken-bridges.json`
30
+ - 节奏分析(storyline rhythm):
31
+ - 基于 summaries 的 `- storyline_id: ...`,在 `[chapter_start, chapter_end]` 内统计每条 active storyline 出场次数、last_seen、最大休眠间隔
32
+ - 基于 schedule 的 `secondary_min_appearance`(如能解析 every_N)对 secondary 线给出“疑似休眠”提示
33
+ - convergence_events 达成率:检查 involved_storylines 是否都在 event.range 内出现;未达成则列 missing + 偏差提示
34
+ - 落盘:写入 `volumes/vol-{V:02d}/storyline-rhythm.json`
35
+ - 同步 latest(便于 `/novel:continue` 与 `/novel:status` 快速展示):
36
+ - 创建目录(幂等):`mkdir -p logs/foreshadowing logs/storylines`
37
+ - 覆盖写入:`logs/foreshadowing/foreshadowing-check-latest.json`(避免覆盖 `logs/foreshadowing/latest.json`;后者用于 commit 阶段的“伏笔可见度报告”)、`logs/storylines/broken-bridges-latest.json`、`logs/storylines/rhythm-latest.json`
38
+ 4. 写入 `volumes/vol-{V:02d}/review.md`(在回顾中增加以下小节):
39
+ - 质量趋势与低分章节
40
+ - 伏笔完成度与风险项(引用 `foreshadowing-report.json` 的关键统计 + overdue 列表)
41
+ - 桥梁断链清单(引用 `broken-bridges.json`,按严重度/数量提示)
42
+ - 故事线节奏简报(引用 `storyline-rhythm.json`:出场统计 + 疑似休眠 + 交汇达成)
43
+ - 一致性报告摘要(issues_total、high 严重级列表、LS-001 风险提示)
44
+ 5. State 清理(每卷结束时,`docs/dr-workflow/novel-writer-tool/final/prd/08-orchestrator.md` §8.5;生成清理报告供用户确认):
45
+ - Read `state/current-state.json`(如存在)
46
+ - Read `world/rules.json`(如存在;用于辅助判断"持久化属性"vs"临时条目";缺失时该判断无法执行,相关条目一律归为候选)
47
+ - Read `characters/retired/*.json`(如存在;若 `characters/retired/` 目录不存在则先创建)并构建 `retired_ids`
48
+ - **确定性安全清理(可直接执行)**:
49
+ - 从 `state/current-state.json.characters` 移除 `retired_ids` 的残留条目
50
+ - **候选清理(默认不自动删除)**:
51
+ - 标记并汇总"过期临时条目"候选,判断规则:
52
+ 1. `state/current-state.json.world_state` 中的临时标记(如活动状态、事件标志):无活跃伏笔引用 AND 无故事线引用 AND 不属于 L1 rules 中定义的持久化属性
53
+ 2. `state/current-state.json.characters.{id}` 中的临时属性(如 inventory 中的一次性物品、临时 buff):无伏笔引用 AND 无故事线引用
54
+ 3. 不确定的条目一律归为"候选"而非"确定性清理",由用户决定
55
+ - 在 `volumes/vol-{V:02d}/review.md` 追加 "State Cleanup" 段落:已清理项 + 候选项 + 删除理由
56
+ - AskUserQuestion 让用户确认是否应用候选清理(不确定项默认保留)
57
+ 6. AskUserQuestion 让用户确认"进入下卷规划 / 调整设定 / 导入研究资料"
58
+ 7. 确认进入下卷规划后更新 `.checkpoint.json`:`current_volume += 1, orchestrator_state = "VOL_PLANNING"`(其余字段保持;`pipeline_stage=null`, `inflight_chapter=null`)
@@ -0,0 +1,116 @@
1
+ # 项目状态查看
2
+
3
+ 你是小说项目状态分析师,向用户展示当前项目的全景状态。
4
+
5
+ ## 运行约束
6
+
7
+ - **可用工具**:Read, Glob, Grep
8
+ <!-- 推荐模型:sonnet(由 orchestrator 决定) -->
9
+
10
+ ## 执行流程
11
+
12
+ ### Step 1: 读取核心文件
13
+
14
+ #### 前置检查
15
+
16
+ - 若 `.checkpoint.json` 不存在:输出"当前目录未检测到小说项目,请先运行 `/novel:start` 创建项目"并**终止**
17
+ - 若 `evaluations/` 为空或不存在:对应区块显示"暂无评估数据(尚未完成任何章节)"
18
+ - 若 `logs/` 为空或不存在:跳过成本统计区块或显示"暂无日志数据"
19
+ - 若 `foreshadowing/global.json` 不存在:跳过伏笔追踪区块或显示"暂无伏笔数据"
20
+ - 若 `volumes/vol-{V:02d}/storyline-schedule.json` 不存在:跳过故事线节奏区块或显示"暂无故事线调度数据"
21
+ - 若 `style-drift.json` 不存在:风格漂移区块显示"未生成纠偏文件(style-drift.json 不存在)"
22
+ - 若 `ai-blacklist.json` 不存在:黑名单维护区块显示"未配置 AI 黑名单"
23
+
24
+ ```
25
+ 1. .checkpoint.json → 当前卷号、章节数、状态
26
+ 2. brief.md → 项目名称和题材
27
+ 3. state/current-state.json → 角色位置、情绪、关系
28
+ 4. foreshadowing/global.json → 伏笔状态
29
+ 5. volumes/vol-{V:02d}/storyline-schedule.json → 本卷故事线调度(节奏提示用)
30
+ 6. Glob("summaries/chapter-*-summary.md") → 提取 storyline_id(节奏提示用)
31
+ 7. Glob("evaluations/chapter-*-eval.json") → 所有评分
32
+ 8. Glob("chapters/chapter-*.md") → 章节文件列表(统计字数)
33
+ 9. Glob("logs/chapter-*-log.json") → 流水线日志(成本、耗时、修订次数)
34
+ ```
35
+
36
+ ### Step 2: 计算统计
37
+
38
+ #### 数据字段来源
39
+
40
+ | 指标 | 来源文件 | JSON 路径 |
41
+ |------|---------|----------|
42
+ | 综合评分 | `evaluations/chapter-*-eval.json` | `.overall_final` |
43
+ | 门控决策 | `logs/chapter-*-log.json` | `.gate_decision` |
44
+ | 修订次数 | `logs/chapter-*-log.json` | `.revisions` |
45
+ | 强制通过 | `logs/chapter-*-log.json` | `.force_passed` |
46
+ | 伏笔状态 | `foreshadowing/global.json` | `.foreshadowing[].status` ∈ `{"planted","advanced","resolved"}` |
47
+ | Token/成本 | `logs/chapter-*-log.json` | `.stages[].input_tokens` / `.stages[].output_tokens` / `.total_cost_usd` |
48
+ | 漂移状态 | `style-drift.json` | `.active` / `.drifts[]` |
49
+ | 黑名单版本 | `ai-blacklist.json` | `.version` / `.last_updated` / `.words` / `.whitelist` |
50
+
51
+ ```
52
+ - 总章节数
53
+ - 总字数(估算:章节文件大小)
54
+ - 评分均值(overall 字段平均)
55
+ - 评分趋势(最近 10 章 vs 全局均值)
56
+ - 各维度均值
57
+ - 未回收伏笔数量和列表(planted/advanced)
58
+ - 超期 short 伏笔数量与列表(`scope=="short"` 且 `status!="resolved"` 且 `last_completed_chapter > target_resolve_range[1]`)(规则定义见 `skills/continue/references/foreshadowing.md` §4)
59
+ - 故事线节奏提示(基于 summaries 的 storyline_id + schedule 的 `secondary_min_appearance`)
60
+ - 活跃角色数量
61
+ - 累计成本(sum total_cost_usd)、平均每章成本、平均每章耗时
62
+ - 修订率(revisions > 0 的章节占比)
63
+ ```
64
+
65
+ #### 故事线节奏提示(轻量、只读)
66
+
67
+ 1. 读取并解析 `volumes/vol-{V:02d}/storyline-schedule.json`(如存在):
68
+ - `active_storylines[]`(storyline_id + volume_role)
69
+ - `interleaving_pattern.secondary_min_appearance`(形如 `"every_8_chapters"`)
70
+ 2. 从 `secondary_min_appearance` 解析最小出场频率窗口:
71
+ - 若匹配 `^every_(\\d+)_chapters$` → `N = int(...)`
72
+ - 否则 `N = null`(仅展示 last_seen,不做“疑似休眠”判断)
73
+ 3. 从 `summaries/chapter-*-summary.md` 提取每章 `storyline_id`:
74
+ - 建议只扫描最近 60 章 summaries(从新到旧),用正则 `^- storyline_id:\\s*(.+)$` 抽取
75
+ - 得到 `last_seen_chapter_by_storyline`
76
+ 4. 对每个 `active_storylines[]`:
77
+ - `chapters_since_last = last_completed_chapter - last_seen_chapter`(未出现过则显示“未出现”)
78
+ - 若 `volume_role=="secondary"` 且 `N!=null` 且 `chapters_since_last > N` → 记为“疑似休眠”(提示用户在后续章节/大纲中安排一次出场或通过回忆重建)
79
+
80
+ ### Step 3: 格式化输出
81
+
82
+ ```
83
+ 📖 {project_name}
84
+ ━━━━━━━━━━━━━━━━━━━━━━━━
85
+ 进度:第 {vol} 卷,第 {ch}/{total_ch} 章
86
+ 总字数:{word_count} 万字
87
+ 状态:{state}
88
+
89
+ 质量评分:
90
+ 均值:{avg}/5.0(近10章:{recent_avg}/5.0)
91
+ 最高:Ch {best_ch} — {best_score}
92
+ 最低:Ch {worst_ch} — {worst_score}
93
+
94
+ 伏笔追踪:
95
+ 活跃:{active_count} 个
96
+ 已回收:{resolved_count} 个
97
+ 超期 short(超过 target_resolve_range 上限):{overdue_short}
98
+
99
+ 故事线节奏:
100
+ 本卷活跃线:{active_storylines_brief}
101
+ 疑似休眠:{dormant_hints}
102
+
103
+ 活跃角色:{character_count} 个
104
+
105
+ 成本统计:
106
+ 累计:${total_cost}({total_chapters} 章)
107
+ 均章成本:${avg_cost}/章
108
+ 均章耗时:{avg_duration}s
109
+ 修订率:{revision_rate}%
110
+ ```
111
+
112
+ ## 约束
113
+
114
+ - 纯只读,不写入任何文件
115
+ - 不触发状态转移
116
+ - 所有输出使用中文
@@ -0,0 +1,60 @@
1
+ # Status Skill 输出示例
2
+
3
+ ## 场景 1:正常进度(已写 25 章)
4
+
5
+ 📖 **小说项目状态**
6
+
7
+ | 项目 | 值 |
8
+ |------|---|
9
+ | 项目名 | 《仙路浮屠》 |
10
+ | 当前卷 | 第 2 卷 |
11
+ | 已完成章节 | 25 / 40(本卷 5 / 20) |
12
+ | 当前状态 | WRITING |
13
+
14
+ **质量趋势**(近 10 章)
15
+ - 均分:3.82(全局均分 3.75)
16
+ - 低分章节:第 18 章(3.2,revise → force_passed)
17
+ - 修订章节:2 章(均已通过)
18
+
19
+ **风格漂移**
20
+ - 状态:active(第 25 章检测)
21
+ - 偏移:句长 +22%(基线 18 → 当前 22)
22
+ - 纠偏指令已注入后续章节
23
+
24
+ **AI 黑名单**
25
+ - 版本:1.0.3 | 更新:2026-02-24
26
+ - 词数:42 | 豁免词:3
27
+ - 最近变更:+2 added(第 23 章自动追加)
28
+
29
+ **伏笔追踪**
30
+ - 活跃:8 | 已回收:12 | 超期(>10章):1
31
+ - ⚠️ 超期伏笔:#F-007「古卷预言」(已 14 章未推进)
32
+
33
+ **成本估算**
34
+ - 本卷累计:$12.50 | 全局累计:$28.30
35
+
36
+ ## 场景 2:空项目(刚初始化)
37
+
38
+ 📖 **小说项目状态**
39
+
40
+ | 项目 | 值 |
41
+ |------|---|
42
+ | 项目名 | 《未命名项目》 |
43
+ | 当前卷 | — |
44
+ | 已完成章节 | 0 |
45
+ | 当前状态 | INIT |
46
+
47
+ **质量趋势**
48
+ 暂无评估数据(尚未完成任何章节)
49
+
50
+ **风格漂移**
51
+ 未启用漂移检测
52
+
53
+ **AI 黑名单**
54
+ 未配置 AI 黑名单
55
+
56
+ **伏笔追踪**
57
+ 暂无伏笔数据
58
+
59
+ **成本估算**
60
+ 暂无日志数据
@@ -0,0 +1,79 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "description": "AI 高频中文用语黑名单 — 生成时禁止使用",
4
+ "last_updated": "2026-02-21",
5
+ "words": [
6
+ "不禁",
7
+ "莫名",
8
+ "油然而生",
9
+ "心中暗道",
10
+ "嘴角微微上扬",
11
+ "嘴角勾起一抹弧度",
12
+ "眼中闪过一丝",
13
+ "深吸一口气",
14
+ "不由得",
15
+ "一股暖流",
16
+ "心头一震",
17
+ "宛如",
18
+ "恍若",
19
+ "仿佛置身于",
20
+ "与此同时",
21
+ "值得一提的是",
22
+ "毫无疑问",
23
+ "显而易见",
24
+ "不言而喻",
25
+ "如同一道闪电",
26
+ "眼神中带着一丝",
27
+ "嘴角微扬",
28
+ "紧握双拳",
29
+ "瞳孔骤缩",
30
+ "心中一凛",
31
+ "暗自思忖",
32
+ "不由自主",
33
+ "心中暗想",
34
+ "嘴角露出一丝笑意",
35
+ "眉头微皱",
36
+ "眼中闪过一抹异色",
37
+ "浑身一震",
38
+ "心中掀起波澜",
39
+ "一时间",
40
+ "顿时",
41
+ "霎时间",
42
+ "刹那间",
43
+ "仿佛被什么击中",
44
+ "如释重负",
45
+ "内心深处"
46
+ ],
47
+ "categories": {
48
+ "emotion_cliche": [
49
+ "不禁",
50
+ "莫名",
51
+ "油然而生",
52
+ "心中暗道",
53
+ "一股暖流",
54
+ "心头一震",
55
+ "心中一凛",
56
+ "心中掀起波澜",
57
+ "如释重负",
58
+ "内心深处"
59
+ ],
60
+ "expression_cliche": [
61
+ "嘴角微微上扬",
62
+ "嘴角勾起一抹弧度",
63
+ "眼中闪过一丝",
64
+ "嘴角微扬",
65
+ "眼神中带着一丝",
66
+ "嘴角露出一丝笑意",
67
+ "眉头微皱",
68
+ "眼中闪过一抹异色"
69
+ ],
70
+ "action_cliche": ["深吸一口气", "紧握双拳", "瞳孔骤缩", "浑身一震", "仿佛被什么击中"],
71
+ "transition_cliche": ["与此同时", "值得一提的是", "毫无疑问", "显而易见", "不言而喻"],
72
+ "simile_cliche": ["宛如", "恍若", "仿佛置身于", "如同一道闪电"],
73
+ "time_cliche": ["一时间", "顿时", "霎时间", "刹那间"],
74
+ "thought_cliche": ["暗自思忖", "不由自主", "不由得", "心中暗想"]
75
+ },
76
+ "whitelist": [],
77
+ "update_log": []
78
+ }
79
+
@@ -0,0 +1,46 @@
1
+ # 创作纲领
2
+
3
+ ## 基本信息
4
+
5
+ - **书名**:{book_title}
6
+ - **题材**:{genre}(如:玄幻、都市、悬疑、言情、科幻)
7
+ - **目标字数**:{target_word_count} 万字
8
+ - **目标卷数**:{target_volumes} 卷
9
+ - **每卷章数**:{chapters_per_volume} 章
10
+
11
+ ## 核心设定
12
+
13
+ ### 世界观一句话
14
+
15
+ {world_one_liner}
16
+
17
+ ### 核心冲突
18
+
19
+ {core_conflict}
20
+
21
+ ### 主角概念
22
+
23
+ - **姓名**:{protagonist_name}
24
+ - **身份**:{protagonist_identity}
25
+ - **目标**:{protagonist_goal}
26
+ - **内在矛盾**:{protagonist_contradiction}
27
+
28
+ ## 风格定位
29
+
30
+ - **基调**:{tone}(如:轻松幽默、热血燃向、暗黑压抑、细腻温暖)
31
+ - **节奏**:{pacing}(如:快节奏爽文、慢热型、张弛交替)
32
+ - **参考作品**:{reference_works}
33
+ - **风格样本来源**:{style_source}(original / reference / template / write_then_extract)
34
+
35
+ ## 读者画像
36
+
37
+ - **目标平台**:{platform}
38
+ - **叙事驱动类型**:{genre_drive_type}(plot / character / suspense / slice_of_life)
39
+ - **平台画像**:platform-profile.json(不可变平台绑定;字数/钩子/信息负载/合规等阈值单一事实来源)
40
+ - **平台约束摘要**:{platform_constraints_summary}(建议由 init 从 platform-profile.json 的 word_count/hook_policy/info_load/compliance 聚合生成;也可手填覆盖)
41
+ - **目标读者**:{target_reader}
42
+ - **核心卖点**:{selling_point}
43
+
44
+ ## 备注
45
+
46
+ {notes}
@@ -0,0 +1,90 @@
1
+ {
2
+ "schema_version": 1,
3
+ "description": "QualityJudge 权重档案(按 genre_drive_type 选择;权重需可归一化到 1.0)",
4
+ "last_updated": "2026-02-27",
5
+
6
+ "dimensions": [
7
+ "plot_logic",
8
+ "character",
9
+ "immersion",
10
+ "foreshadowing",
11
+ "pacing",
12
+ "style_naturalness",
13
+ "emotional_impact",
14
+ "storyline_coherence",
15
+ "hook_strength"
16
+ ],
17
+
18
+ "normalization": {
19
+ "_comment": "Validation rule: all weights must be finite numbers >= 0 and normalizable to sum_to within tolerance.",
20
+ "method": "scale_to_sum",
21
+ "sum_to": 1.0,
22
+ "tolerance": 0.0001
23
+ },
24
+
25
+ "default_profile_by_drive_type": {
26
+ "plot": "plot:v1",
27
+ "character": "character:v1",
28
+ "suspense": "suspense:v1",
29
+ "slice_of_life": "slice_of_life:v1"
30
+ },
31
+
32
+ "profiles": {
33
+ "plot:v1": {
34
+ "drive_type": "plot",
35
+ "weights": {
36
+ "plot_logic": 0.22,
37
+ "character": 0.16,
38
+ "immersion": 0.13,
39
+ "foreshadowing": 0.11,
40
+ "pacing": 0.08,
41
+ "style_naturalness": 0.11,
42
+ "emotional_impact": 0.06,
43
+ "storyline_coherence": 0.07,
44
+ "hook_strength": 0.06
45
+ }
46
+ },
47
+ "character:v1": {
48
+ "drive_type": "character",
49
+ "weights": {
50
+ "plot_logic": 0.13,
51
+ "character": 0.24,
52
+ "immersion": 0.16,
53
+ "foreshadowing": 0.09,
54
+ "pacing": 0.06,
55
+ "style_naturalness": 0.12,
56
+ "emotional_impact": 0.1,
57
+ "storyline_coherence": 0.05,
58
+ "hook_strength": 0.05
59
+ }
60
+ },
61
+ "suspense:v1": {
62
+ "drive_type": "suspense",
63
+ "weights": {
64
+ "plot_logic": 0.17,
65
+ "character": 0.12,
66
+ "immersion": 0.11,
67
+ "foreshadowing": 0.12,
68
+ "pacing": 0.11,
69
+ "style_naturalness": 0.1,
70
+ "emotional_impact": 0.06,
71
+ "storyline_coherence": 0.09,
72
+ "hook_strength": 0.12
73
+ }
74
+ },
75
+ "slice_of_life:v1": {
76
+ "drive_type": "slice_of_life",
77
+ "weights": {
78
+ "plot_logic": 0.13,
79
+ "character": 0.2,
80
+ "immersion": 0.18,
81
+ "foreshadowing": 0.07,
82
+ "pacing": 0.05,
83
+ "style_naturalness": 0.16,
84
+ "emotional_impact": 0.1,
85
+ "storyline_coherence": 0.08,
86
+ "hook_strength": 0.03
87
+ }
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 1,
3
+ "topic": "init.platform_binding",
4
+ "answers": {
5
+ "platform": "qidian",
6
+ "genre_drive_type": ["plot", "character"],
7
+ "tone": "noir",
8
+ "project_note": "Prefer 3k-4k words per chapter; keep POV consistent."
9
+ },
10
+ "answered_at": "2026-02-27T00:00:00Z",
11
+ "answered_by": "human"
12
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "version": 1,
3
+ "topic": "init.platform_binding",
4
+ "questions": [
5
+ {
6
+ "id": "platform",
7
+ "header": "Platform",
8
+ "question": "Choose your target platform.",
9
+ "kind": "single_choice",
10
+ "required": true,
11
+ "options": [
12
+ { "label": "qidian", "description": "Qidian / 起点中文网" },
13
+ { "label": "tomato", "description": "Tomato / 番茄小说" }
14
+ ],
15
+ "default": "qidian"
16
+ },
17
+ {
18
+ "id": "genre_drive_type",
19
+ "header": "Genre Drive",
20
+ "question": "Select one or more genre drive types.",
21
+ "kind": "multi_choice",
22
+ "required": true,
23
+ "options": [
24
+ { "label": "plot", "description": "Plot-driven" },
25
+ { "label": "character", "description": "Character-driven" },
26
+ { "label": "slice_of_life", "description": "Slice-of-life" }
27
+ ],
28
+ "default": ["plot"]
29
+ },
30
+ {
31
+ "id": "tone",
32
+ "header": "Tone",
33
+ "question": "Pick a default tone (or enter your own).",
34
+ "kind": "single_choice",
35
+ "required": false,
36
+ "options": [
37
+ { "label": "serious", "description": "Serious / tense" },
38
+ { "label": "light", "description": "Light / upbeat" }
39
+ ],
40
+ "allow_other": true,
41
+ "default": "serious"
42
+ },
43
+ {
44
+ "id": "project_note",
45
+ "header": "Notes",
46
+ "question": "Any special constraints or notes for the project?",
47
+ "kind": "free_text",
48
+ "required": false
49
+ }
50
+ ]
51
+ }