dsh-novel-writer 4.3.0 → 4.3.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.
- package/README.en.md +3 -0
- package/README.md +3 -0
- package/cordis.patch.yml +1 -1
- package/lib/core.js +38 -5
- package/lib/index.js +18 -0
- package/package.json +2 -2
- package/server.json +2 -2
package/README.en.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# 📚 dsh-novel-writer — on-device style checkup for novel writers
|
|
2
2
|
|
|
3
|
+
> 🌐 **[Project site](https://siweina.github.io/dsh-novel-writer/)** · [Technical docs — implementation details, formulas and limits for all 16 tools](https://siweina.github.io/dsh-novel-writer/tools/)
|
|
4
|
+
|
|
3
5
|
English | [中文](./README.md)
|
|
4
6
|
|
|
5
7
|
[](https://www.npmjs.com/package/dsh-novel-writer)
|
|
@@ -8,6 +10,7 @@ English | [中文](./README.md)
|
|
|
8
10
|
[](https://nodejs.org)
|
|
9
11
|
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
10
12
|
[](https://github.com/siweina/dsh-novel-writer/stargazers)
|
|
13
|
+
[](https://glama.ai/mcp/servers/siweina/dsh-novel-writer)
|
|
11
14
|
|
|
12
15
|
**16 tools that turn "my writing drifted" into numbers you can act on.**
|
|
13
16
|
Sentence, emotion and style-baseline analysis all run **on your machine**: a 24MB Chinese model ships with the package,
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# 📚 dsh-novel-writer — 给网文作者的本地章节体检
|
|
2
2
|
|
|
3
|
+
> 🌐 **[在线主页](https://siweina.github.io/dsh-novel-writer/)** · [完整技术文档(16 个工具的实现细节、公式与约束)](https://siweina.github.io/dsh-novel-writer/tools/)
|
|
4
|
+
|
|
3
5
|
[English](./README.en.md) | 中文
|
|
4
6
|
|
|
5
7
|
[](https://www.npmjs.com/package/dsh-novel-writer)
|
|
@@ -8,6 +10,7 @@
|
|
|
8
10
|
[](https://nodejs.org)
|
|
9
11
|
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
10
12
|
[](https://github.com/siweina/dsh-novel-writer/stargazers)
|
|
13
|
+
[](https://glama.ai/mcp/servers/siweina/dsh-novel-writer)
|
|
11
14
|
|
|
12
15
|
**16 个工具,把"文风跑偏"变成可量化的数字。**
|
|
13
16
|
句式 / 情感 / 风格基线全部**在本地算**:24MB 中文模型随包分发,**零 API 花费、正文不出本机**。
|
package/cordis.patch.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# dsh-novel-writer v4.3.
|
|
1
|
+
# dsh-novel-writer v4.3.1 bundle patch: 16 tools (incl. novel_semantic_search) + local embedding engine.
|
|
2
2
|
# dsh-novel-writer bundle patch: mounts the novel-writing assistant plugin
|
|
3
3
|
# into the profile's loader tree. The entry's name is the plugin package
|
|
4
4
|
# itself, resolved from the profile's node_modules.
|
package/lib/core.js
CHANGED
|
@@ -375,14 +375,31 @@ export async function chapterStats(bookPath, chapter, exec) {
|
|
|
375
375
|
}
|
|
376
376
|
export function findChapter(chapters, chapterArg) {
|
|
377
377
|
const needle = String(chapterArg).trim();
|
|
378
|
+
const lower = needle.toLowerCase();
|
|
379
|
+
// v4.3.1 修正(P0):精确文件名(含省略扩展名的文件名)**优先于**章号解析。
|
|
380
|
+
// 旧版把章号匹配放在最前,于是「第03章 重逢.md」这种完整文件名也会被 parseChapterNumber 解析出章号 3,
|
|
381
|
+
// 命中同章的另一个文件;被抢走的那一份用章号/文件名/标题三条路都读不到(永久不可达,实测复现)。
|
|
382
|
+
const plain = lower.replace(/\.(md|markdown|txt)$/i, "");
|
|
383
|
+
const byFile = chapters.find((c) => {
|
|
384
|
+
const file = c.file.toLowerCase();
|
|
385
|
+
return file === lower || file.replace(/\.[^.]+$/, "") === plain;
|
|
386
|
+
});
|
|
387
|
+
if (byFile) return byFile;
|
|
378
388
|
const asNumber = parseChapterNumber(needle);
|
|
379
389
|
if (asNumber !== void 0) {
|
|
380
|
-
const
|
|
381
|
-
|
|
390
|
+
const matched = chapters.filter((c) => c.number === asNumber);
|
|
391
|
+
// v4.3.1 修正(P0):同章号多文件不再"静默取排序后的第一个"——那会让另一份永远读不到。
|
|
392
|
+
// 改为拒绝并列出候选;候选文件名可直接回传给 chapter 参数(文件名匹配已在上方优先)。
|
|
393
|
+
if (matched.length > 1) {
|
|
394
|
+
throw new Error(
|
|
395
|
+
`第 ${asNumber} 章有 ${matched.length} 个文件,无法确定要哪一份:` +
|
|
396
|
+
matched.map((c) => c.file).join("、") +
|
|
397
|
+
`。请把 chapter 参数写成其中一个文件名(可省略扩展名)来指定;` +
|
|
398
|
+
`或用 novel_continuity_check 查看同章号清单后改名。`
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
if (matched.length === 1) return matched[0];
|
|
382
402
|
}
|
|
383
|
-
const lower = needle.toLowerCase();
|
|
384
|
-
const byFile = chapters.find((c) => c.file.toLowerCase() === lower);
|
|
385
|
-
if (byFile) return byFile;
|
|
386
403
|
// v4.0.0 修正:纯数字参数必须"章号完全相等",否则 findChapter("1") 会子串命中第 10/11/12 章
|
|
387
404
|
// v4.3.0 修正:这里原有一段 `chapters.find(c => String(c.number) === needle)` 的"精确查找",
|
|
388
405
|
// 恒为无效代码——走到此处说明没有任何章号的数值等于 asNumber,而 c.number 是 parseChapterNumber 产出的
|
|
@@ -2278,6 +2295,22 @@ export function formatChapters(value) {
|
|
|
2278
2295
|
const number = chapter.number === void 0 ? "?" : String(chapter.number).padStart(2, "0");
|
|
2279
2296
|
lines.push(`- 第${number}章 ${chapter.title} — ${chapter.chars} 字 / ${chapter.lines} 行 (${chapter.file}, 更新于 ${chapter.updated.slice(0, 10)})`);
|
|
2280
2297
|
}
|
|
2298
|
+
// v4.3.1:同章号多文件提示。这类书按章号读取会被 findChapter 拒绝(避免静默读错稿),
|
|
2299
|
+
// 但列表里两条只是"同名条目",不主动说明的话用户不知道磁盘上是两份文件——必须在这里就看见。
|
|
2300
|
+
const dupByNumber = new Map();
|
|
2301
|
+
for (const chapter of value.chapters) {
|
|
2302
|
+
if (chapter.number === void 0) continue;
|
|
2303
|
+
const list = dupByNumber.get(chapter.number) ?? [];
|
|
2304
|
+
list.push(chapter.file);
|
|
2305
|
+
dupByNumber.set(chapter.number, list);
|
|
2306
|
+
}
|
|
2307
|
+
const conflicts = [...dupByNumber.entries()].filter(([, files]) => files.length > 1);
|
|
2308
|
+
if (conflicts.length > 0) {
|
|
2309
|
+
lines.push("", `⚠️ 同章号多文件 ${conflicts.length} 组(按章号读取会因歧义被拒绝;请改名到空闲章号,或用 novel_import 重新导入自动避让):`);
|
|
2310
|
+
for (const [number, files] of conflicts) {
|
|
2311
|
+
lines.push(` 第${String(number).padStart(2, "0")}章: ${files.join(" / ")}`);
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2281
2314
|
lines.push("", "</content>");
|
|
2282
2315
|
return lines.join("\n");
|
|
2283
2316
|
}
|
package/lib/index.js
CHANGED
|
@@ -1964,6 +1964,24 @@ function registerNovelContinuityCheck(ctx, config) {
|
|
|
1964
1964
|
};
|
|
1965
1965
|
}
|
|
1966
1966
|
const candidates = [];
|
|
1967
|
+
// v4.3.1(P0):同章号多文件检测。findChapter 现在会在章号命中多个文件时拒绝执行(不再静默读错稿),
|
|
1968
|
+
// 所以在审计里先把撞号清单摆出来,否则用户只看到"读取失败"却不知道哪几章撞了。
|
|
1969
|
+
const dupByNumber = new Map();
|
|
1970
|
+
for (const c of chapters) {
|
|
1971
|
+
if (c.number === void 0) continue;
|
|
1972
|
+
const list = dupByNumber.get(c.number) ?? [];
|
|
1973
|
+
list.push(c.file);
|
|
1974
|
+
dupByNumber.set(c.number, list);
|
|
1975
|
+
}
|
|
1976
|
+
for (const [number, files] of dupByNumber) {
|
|
1977
|
+
if (files.length > 1) {
|
|
1978
|
+
candidates.push({
|
|
1979
|
+
type: "同章号多文件",
|
|
1980
|
+
detail: `第 ${number} 章有 ${files.length} 个文件共用同一章号:${files.join("、")}——按章号读取会被拒绝(需改用文件名指定)`,
|
|
1981
|
+
chapters: files
|
|
1982
|
+
});
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1967
1985
|
// v3.2.0:大纲 vs 实际偏离检查
|
|
1968
1986
|
// v4.0.0 修正:移到全书读取之前——大纲模式不用 chapterTexts,旧版先无条件读完全书再进分支,
|
|
1969
1987
|
// 且分支内又对每章整读一遍再 slice(0,600)(同一章读两遍,第一遍纯浪费)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-novel-writer",
|
|
3
|
-
"version": "4.3.
|
|
4
|
-
"description": "小说写作助手插件(v4.3.
|
|
3
|
+
"version": "4.3.1",
|
|
4
|
+
"description": "小说写作助手插件(v4.3.1):句式/情感/意象分析、伏笔设定管理、本地语义检索、氛围光谱、风格画像报告、文笔六维基线带、原创模式与创作资料、写作哨兵(衔接/OOC/大纲);附 stdio MCP 服务器(Claude Desktop / Cursor 可用)。",
|
|
5
5
|
"mcpName": "io.github.siweina/dsh-novel-writer",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "lib/index.js",
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.siweina/dsh-novel-writer",
|
|
4
4
|
"title": "dsh-novel-writer — 网文写作体检",
|
|
5
5
|
"description": "Offline toolkit: 16 tools for Chinese web-novel style, plot-thread and continuity audits.",
|
|
6
|
-
"version": "4.3.
|
|
6
|
+
"version": "4.3.1",
|
|
7
7
|
"repository": {
|
|
8
8
|
"url": "https://github.com/siweina/dsh-novel-writer",
|
|
9
9
|
"source": "github"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
{
|
|
14
14
|
"registryType": "npm",
|
|
15
15
|
"identifier": "dsh-novel-writer",
|
|
16
|
-
"version": "4.3.
|
|
16
|
+
"version": "4.3.1",
|
|
17
17
|
"runtimeHint": "npx",
|
|
18
18
|
"packageArguments": [
|
|
19
19
|
{
|