novel_new_chapter
新建章节。为指定作品创建一个章节文件,章号可显式指定或自动取下一个,可同时写入 Markdown 一级标题与初始正文。同号章节一律拒绝创建,绝不覆盖既有稿件;创建成功后返回体自带全书六维风格基线 μ 摘要与「风格锚包」(原著代表性段落 + 句式骨架),使调用方模型在动笔前即可拿到测量数据与用于校准语感的样例,无需先调用风格报告工具。
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
book | string | 是 | 书名,即 novels/ 下的子目录名。经 sanitizeSegment 清洗:剥离 \ / : * ? " < > |、首尾点与空白,Windows 保留名(CON / NUL 等)加下划线前缀;清洗后为空则报错。目录不存在时自动创建。 |
chapter | integer | 否 | 显式章号,须为 1–99999 的整数。省略时取现有最大可解析章号 + 1。 |
title | string | 否 | 章节标题,写为正文首行 # 标题,并(v5.0.0 起)一并进文件名:第NN章 标题.md。空串或纯空白视为未提供。 |
content | string | 否 | 初始正文。空串或纯空白视为未提供。 |
root | string | 否 | 章节库根目录。缺省回退顺序:args.root → config.root → 会话工作目录。MCP 形态下必须落在启动参数 --root 之内。 |
参数对象声明 additionalProperties: false,多传的键会被宿主拒绝。
输出结构
契约字段(output.schema.required):book / number / file / path / chars 五项必返;其余字段按条件出现。返回前经 cleanOutput 处理,值为 undefined 的键会被整体剔除。
| 字段 | 类型 | 内容 |
|---|---|---|
book | string | 必返。清洗后的书名 |
number | integer | 必返。本次实际使用的章号 |
file | string | 必返。文件名:无 title 时为 第NN章.md(章号左补零到至少 2 位);给了 title 时为 第NN章 标题.md(v5.0.0 修正:标题经 sanitizeSegment 剥掉 \ / : * ? " < > | 等非法字符并截断到 24 字;标题全是非法字符则退回不带标题的文件名,不因此拒绝创建) |
path | string | 必返。落盘绝对路径 |
chars | integer | 必返。写入文本的字符数(合成文本整体长度,含标题行与结尾换行) |
baseline | string | 全书六维基线 μ 摘要,形如「标签 值 / 标签 值 …」,无法计算时为缺失 |
reminder | string | 「基线怎么用」提示(v5.1.0 改口径:此前这段标题里带「强制」二字,现改为「基线怎么用」):① 锚段读一遍校准语感(不要照 skeletons 造句)② 写完建议跑一次 novel_style_check 自检,偏离明显时才逐句修正。当前实现下恒有值 |
anchors | array | 风格锚·原著段落,元素 { label, text },最多 5 条 |
skeletons | array | 句式骨架,元素 { type, text },最多 4 条 |
行为与实现
本工具不涉及统计模型,全部为确定性文件操作与规则抽取。执行顺序:校验 → 建目录 → 扫描现有章节 → 定章号 → 查重 → 合成文本 → 独占写入 → 计算基线 → 构建锚包 → 记录书库根。
1 · 章号解析与文件名
现有章节由 scanChapters 收集:只认书目录顶层的 .md / .markdown / .txt(扩展名小写比较),子目录中的文件不参与,排序为「章号升序(不可解析者排最后)+ 文件名 localeCompare」。章号解析入口先做全角宽度归一(第01章 → 第01章),因此下列写法都解析为同一章号:第1章.md、第01章.md、第一章.md、书名-01-标题.md、书名 01.md。中文数字支持到「千」位(如 第一千零一章 解析为 1001)。
2 · 防覆盖与独占写入
查重(按解析出的章号)与写入(按文件名是否存在)是两套口径,两者之间存在竞态窗口;wx 标志把该窗口收敛为一次可上报的失败,而不是静默互相覆盖。已知取舍:建目录发生在查重之前,因此同号创建失败时书目录仍可能已被创建。
3 · 文本合成与字符数口径
标题行与正文之间由数组 join 产生的空行是格式的一部分,会一并计入 chars。该字段用于核对「是否真的写入了内容」,不代表正文字数。
4 · 风格基线 μ 摘要
基线测量集合包含新章,以与风格报告、风格自检的「全章集合」保持同一缓存键(否则三者交替调用会全部缓存 miss);但摘要本身排除新章,因为新章不能作为自己的基线。无其它章节时不输出 μ=0 的假基线。novel_style_report 基线计算中「正文不足 40 字的章节不参与统计」的规则由测量层统一执行。整段被 try/catch 包裹:失败静默,不影响章节创建。
5 · 风格锚包
锚包是「校准语感」的载体,不是造句模板:anchors 读一遍对上味道即可,skeletons 只在写不出该类型句子时参考,不要照它造句、不要套句式模板;数字基线只用于事后校验。整段同样被 try/catch 包裹,失败时返回空锚包。
6 · 渲染文本
约束与边界
- 同号即失败,不覆盖:
第1章.md/第01章.md/第一章.md都按章号 1 拦截。需要改写既有章节时应另选章号或先由调用方删除旧文件——本工具不提供任何覆盖或更新通道。 - chapter 的取值范围是硬断言:非整数(浮点、数字字符串)、0、负数、大于 99999 一律被拒绝并报错,而不是截断到边界。
- 并发只报错不重试:独占创建失败时返回「刚被并发创建」,需调用方自行重试或改用其它章号。
- 建目录是前置副作用:即使后续因同号失败,书目录也已被创建。
- 基线/锚包均为可选增强:任一环节抛错都被吞掉,返回体中相应字段缺失或为空数组。调用方不应假定
baseline恒有值——单章作品、基线计算失败、锚包抽取失败都会导致缺失。 - 只统计顶层文件:
scanChapters不递归,放在子目录里的章节文件对本书「不可见」,既不计入章号也不参与基线。 - 自动章号依赖可解析章号:目录内若存在无法解析章号的文件(命名完全不含数字或中文数字),它们被排到末尾且不参与
max;此时「下一个章号」由可解析的最大值决定,可能与文件名视觉顺序不一致。 - 章号解析的已知缺口:中文数字解析器识别
十/百/千,但不识别「万」——第一万章.md解析不出章号,会被当作不可解析文件排到列表末尾,既不参与自动章号计算,也不阻止同号冲突检测(该文件不占用任何章号)。四位以内的阿拉伯章号不受此影响。 - root 与 MCP 边界:MCP 形态下服务器为未显式提供
root的调用注入--root书库根;显式传入越界路径会被静默回退书库根。 - 工具开关:
execute首行执行assertToolEnabled,若该工具在「写作助手功能」UI 中被关闭,调用直接报错(可用novel_sentence_config重新开启)。 - 写盘编码固定为 UTF-8,不写 BOM,换行为
\n;不生成备份文件与临时文件。
相关工具
- novel_chapters —— 创建前查看现有章号,避免显式
chapter撞号。 - novel_read —— 按章号或标题读回刚创建的正文。
- novel_style_check ——
reminder建议的写后自检,用同一套六维基线与目标章比对;偏离明显时才据其修正。 - novel_import —— 已有整批原稿件时的入库入口,替代逐章创建。
源码位置
- lib/index.js —— 工具注册与
execute:参数 schema、输出契约、基线摘要、提醒文案(registerNovelNewChapter,约 2879 行) - lib/core.js ——
sanitizeSegment路径段清洗、resolveRoot根目录回退、bookDir/novelsDir路径拼接、scanChapters章节扫描、parseChapterNumber章号解析、cleanOutput输出清理 - lib/core.js ——
buildStyleAnchorPackage风格锚包抽样与分类(约 2071 行)、metricChaptersCached六维测量缓存(约 1864 行) - lib/style-metrics.js ——
computeBaselineFromPerChapter/METRIC_ORDER/METRIC_LABELS,基线 μ 的计算与维度顺序