dsh-novel-writer 4.0.0 → 4.1.0

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 CHANGED
@@ -1,17 +1,35 @@
1
- # 📚 dsh-novel-writer — Novel Writing Assistant
1
+ # 📚 dsh-novel-writer — on-device style checkup for novel writers
2
2
 
3
- English | [**中文**](./README.md)
3
+ English | [中文](./README.md)
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/dsh-novel-writer.svg?style=flat-square&color=blue)](https://www.npmjs.com/package/dsh-novel-writer)
6
+ [![npm downloads](https://img.shields.io/npm/dm/dsh-novel-writer.svg?style=flat-square&color=green)](https://www.npmjs.com/package/dsh-novel-writer)
6
7
  [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg?style=flat-square)](LICENSE)
7
- [![GitHub stars](https://img.shields.io/github/stars/siweina/dsh-novel-writer.svg?style=flat-square&color=orange)](https://github.com/siweina/dsh-novel-writer/stargazers)
8
- [![GitHub release](https://img.shields.io/github/v/release/siweina/dsh-novel-writer.svg?style=flat-square)](https://github.com/siweina/dsh-novel-writer/releases)
9
- [![DSH plugin](https://img.shields.io/badge/DSH-plugin-4b8bbe.svg?style=flat-square)](https://github.com/deepseek-ai/deepseek-harness)
8
+ [![Node](https://img.shields.io/badge/node-%3E%3D22.3-339933.svg?style=flat-square)](https://nodejs.org)
9
+ [![DSH](https://img.shields.io/badge/DSH-%E2%89%A50.1.1--rc.2-4b8bbe.svg?style=flat-square)](https://github.com/deepseek-ai/deepseek-harness)
10
10
 
11
- A novel-writing assistant plugin for **DeepSeek Harness (DSH)**: chapter library management, sentence-pattern analysis, emotion purification & quantification, **12-axis vibe spectrum**, **style portrait report**, **six-dimension style baseline band**, **writing sentinels (bridge/OOC/outline drift)**, plot & settings management, local semantic search (0 token), webnovel signal detection, **original mode with creation files (bible/dynamic outline/hook backfill)**, batch import, and AI-assisted continuation writing. The semantic engine depends on `onnxruntime-web` and `@huggingface/tokenizers` (auto-installed with the package). **Requires Node ≥ 22.3.**
11
+ **16 tools that turn "my writing drifted" into numbers you can act on.**
12
+ Sentence, emotion and style-baseline analysis all run **on your machine**: a 24MB Chinese model ships with the package,
13
+ **zero API cost, your manuscript never leaves the device**. Built for DeepSeek Harness (DSH); the same engine is also
14
+ exposed as a **stdio MCP server** for Claude Desktop / Cursor.
12
15
 
13
- > **A note to non-Chinese users**: This plugin is designed specifically for Chinese-language novel analysis and writing — its core capabilities (sentence-pattern analysis, emotion quantification, imagery detection) and its built-in semantic model are all built and tuned for Chinese text. Fully supporting English or other languages alongside Chinese is beyond my current capability. I sincerely apologize for any inconvenience this may cause.
16
+ ## Install
14
17
 
18
+ `sh
19
+ dsh plugin --profile web add dsh-novel-writer
20
+ # or
21
+ npm install dsh-novel-writer
22
+ `
23
+
24
+ Requires **Node >= 22.3**. Restart the web app; a "写作助手功能" panel appears in the sidebar.
25
+
26
+ ## MCP server
27
+
28
+ `sh
29
+ node /path/to/node_modules/dsh-novel-writer/mcp/server.mjs --root /path/to/your/novels
30
+ `
31
+
32
+ See [mcp/README.md](./mcp/README.md) for the Claude Desktop / Cursor config.
15
33
 
16
34
  ---
17
35
 
@@ -92,6 +110,33 @@ Under `<library-root>/.novel-writer/`: `plots` / `settings` / `summaries` / `ana
92
110
 
93
111
  ---
94
112
 
113
+ ## Dependencies, permissions and failure bounds
114
+
115
+ **Runtime dependencies** (installed by `npm install`; all public packages):
116
+
117
+ - `onnxruntime-web` ^1.24.3 — local ONNX inference (WASM backend) for semantic search and style distance;
118
+ - `@huggingface/tokenizers` ^0.1.0 — tokenization (WASM);
119
+ - peerDependency `react` ^18.2.0 — the browser half reuses the React shipped with the DSH Web GUI.
120
+
121
+ **Local model**: `lib/models/` ships the quantized bge-small-zh-v1.5 model (~24MB ONNX) and its tokenizer
122
+ (`tokenizer.json.gz`, decompressed on load). All inference runs on the local CPU; no text is uploaded.
123
+
124
+ **Permissions and external services**:
125
+
126
+ - Filesystem: only the user-chosen library root (`novels/`), its data directory (`<root>/.novel-writer/`)
127
+ and the plugin state file (`~/.dsh/dsh-novel-writer/state.json`).
128
+ - Local HTTP: five routes registered inside the DSH Web GUI, loopback-only by default.
129
+ - Network: the only outbound call is the GitHub Releases API (`api.github.com`) for update checks —
130
+ 3s timeout, 24h cache, silent fallback; no manuscript content is sent.
131
+ - Subprocesses: none, except opening the OS file manager with an argv array.
132
+ - Lifecycle scripts: none.
133
+
134
+ **Failure bounds**: semantic engine failure falls back to pure rule mode; cache/disk failures never block
135
+ tool results; a plugin load failure cannot affect the DSH host process.
136
+
137
+ **Compatibility**: Node.js >= 22.3 (`engines.node`); DSH >= 0.1.1-rc.2 (`dsh.engines.dsh`).
138
+
139
+ ---
95
140
  ## License
96
141
 
97
142
  [MIT](./LICENSE)
package/README.md CHANGED
@@ -1,37 +1,96 @@
1
- # 📚 dsh-novel-writer — 小说写作助手
1
+ # 📚 dsh-novel-writer — 给网文作者的本地章节体检
2
2
 
3
- [**English**](./README.en.md) | 中文
3
+ [English](./README.en.md) | 中文
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/dsh-novel-writer.svg?style=flat-square&color=blue)](https://www.npmjs.com/package/dsh-novel-writer)
6
+ [![npm downloads](https://img.shields.io/npm/dm/dsh-novel-writer.svg?style=flat-square&color=green)](https://www.npmjs.com/package/dsh-novel-writer)
6
7
  [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg?style=flat-square)](LICENSE)
8
+ [![Node](https://img.shields.io/badge/node-%3E%3D22.3-339933.svg?style=flat-square)](https://nodejs.org)
9
+ [![DSH](https://img.shields.io/badge/DSH-%E2%89%A50.1.1--rc.2-4b8bbe.svg?style=flat-square)](https://github.com/deepseek-ai/deepseek-harness)
7
10
  [![GitHub stars](https://img.shields.io/github/stars/siweina/dsh-novel-writer.svg?style=flat-square&color=orange)](https://github.com/siweina/dsh-novel-writer/stargazers)
8
- [![GitHub release](https://img.shields.io/github/v/release/siweina/dsh-novel-writer.svg?style=flat-square)](https://github.com/siweina/dsh-novel-writer/releases)
9
- [![DSH plugin](https://img.shields.io/badge/DSH-plugin-4b8bbe.svg?style=flat-square)](https://github.com/deepseek-ai/deepseek-harness)
10
11
 
11
- 为 **DeepSeek Harness (DSH)** 打造的小说写作助手插件:章节库管理、句式分析、情感净化与量化、氛围光谱、**风格画像报告**、**文笔六维基线带**、**写作哨兵三件套(衔接/OOC/大纲走偏)**、伏笔设定管理、本地语义检索(0 token)、网文信号识别、**原创模式与创作资料管理(设定书/动态大纲/钩子回填)**、批量导入与 AI 续写辅助。语义引擎依赖 `onnxruntime-web` 与 `@huggingface/tokenizers`(随包自动安装),浏览器端仅依赖 Web GUI 自带的 react。**要求 Node ≥ 22.3。**
12
-
13
- > **致非中文用户**:本插件为中文小说分析写作而设计——句式、情感、意象等核心能力以及内置的语义模型,全部针对中文语料构建与调优。在深耕中文的同时兼顾英文等其他语言,确实超出了我目前的能力范围。若因此给您带来不便,我深感抱歉,恳请谅解。
12
+ **16 个工具,把"文风跑偏"变成可量化的数字。**
13
+ 句式 / 情感 / 风格基线全部**在本地算**:24MB 中文模型随包分发,**零 API 花费、正文不出本机**。
14
+ 为 DeepSeek Harness(DSH)打造;同一套能力也可作为 **MCP 服务器**给 Claude Desktop / Cursor 使用。
14
15
 
16
+ [安装](#安装) · [60 秒上手](#60-秒上手) · [看看输出](#看看输出长什么样) · [16 个工具](#提供的工具16-个) · [MCP 服务器](#mcp-服务器非-dsh-用户也能用)
15
17
 
16
18
  ---
17
19
 
20
+ ## 它解决什么问题
21
+
22
+ | 你的困扰 | 这里给的答案 |
23
+ |---|---|
24
+ | "我续写的这段,读起来不像我自己写的" | **文笔六维基线**:从句法复杂度 / 修饰密度 / 抽象度 / 动作密度 / 不确定性 / 留白指数六个维度算出原著的 μ±σ,新章逐维对照,出带标 ⚠ |
25
+ | "AI 说文风变了,但说不清哪儿变了" | **风格自检**:相似度 + 偏差清单(哪类句式多了、句长偏了多少、主导情绪有没有换) |
26
+ | "分析小说要花钱调 API" | 语义检索与情感分析**全本地推理**,零 token 花费 |
27
+ | "伏笔埋了忘了收" | **伏笔登记表**:add / list / scan / done,自动记录每条伏笔在哪些章被提到 |
28
+ | "人物设定前后打架" | **设定五张表 + 连贯性审计**(衔接 / OOC / 大纲走偏三件套) |
29
+ | "报告看不懂" | 全是**表格化数字 + 原文锚段**,可以直接截图分享 |
30
+
18
31
  ## 安装
19
32
 
20
33
  **方式一:npm(推荐)**
21
34
 
22
- ```sh
35
+ `sh
23
36
  dsh plugin --profile web add dsh-novel-writer
24
- # 或
25
- npm install dsh-novel-writer
26
- ```
37
+ `
27
38
 
28
39
  **方式二:从 GitHub 安装**
29
40
 
30
- ```sh
41
+ `sh
31
42
  dsh plugin --profile web add github:siweina/dsh-novel-writer#main
43
+ `
44
+
45
+ **方式三:MCP(不用 DSH 也能用)** —— 见 [MCP 服务器](#mcp-服务器非-dsh-用户也能用)
46
+
47
+ 要求 **Node ≥ 22.3**。安装后**重启 Web 应用**,侧边栏出现「写作助手功能」面板。
48
+
49
+ ## 60 秒上手
50
+
51
+ `sh
52
+ mkdir -p novels/我的小说 # 把章节文件放进去(第01章.md、第02章.md …)
53
+ `
54
+
55
+ 然后在对话里说:**"用 novel_style_report 给我的小说做一次风格画像"**,你会拿到:
56
+
57
+ ```text
58
+ 全书 1329 字:六维基线 μ=句法复杂度:2.3 修饰密度:35.6 抽象度:0.5 动作密度:101.7 不确定性:2.1 留白指数:7.0
59
+ 推荐容差 25%/35%/100%…
60
+ ```
61
+
62
+ ## 看看输出长什么样
63
+
64
+ **风格自检**(新章 vs 全书基线):
65
+
66
+ ```text
67
+ 相似度 0.946 · verdict: high
68
+ 偏差清单:心理占比略多 · 对话占比略少 · 短句占比略少 · 主导情绪由 anger 变为 joy
69
+ fixAnchors:3 条原著锚段(对话 / 心理 / 描写各一条,供逐句对照修正)
32
70
  ```
33
71
 
34
- 安装后**重启 web 应用**生效(宿主端注册 16 个工具与 state/reveal 路由,浏览器端挂载侧边栏「写作助手功能」开关面板)。
72
+ **语义检索**(自然语言,本地向量):
73
+
74
+ ```text
75
+ 查询「与那盏没有点的灯有关的段落」→
76
+ 第02章.md 0.619 对街那盏灯,亮了。
77
+ 第01章.md 0.593 阿澈的目光越过老周的肩膀,落在对街那栋小楼上…
78
+ ```
79
+
80
+ **段落结构**:共 34 段(对话 5 / 心理 0 / 混合 15 / 叙述 14)
81
+
82
+ ## 为什么不用在线 AI 写作工具
83
+
84
+ | | 本插件 | 在线 AI 写作工具 | 通用文本分析库 |
85
+ |---|---|---|---|
86
+ | 正文是否离开本机 | **否** | 是 | 视实现 |
87
+ | 花费 | **0(本地推理)** | 按 token 计费 | 自建 |
88
+ | 中文小说专用 | **是** | 通用 | 否 |
89
+ | 风格基线(μ±σ) | **有** | 少见 | 无 |
90
+ | 与 DSH 集成 | **16 工具 + 侧边栏开关** | 无 | 无 |
91
+ | 非 DSH 用户可用 | **可以(MCP)** | 可以 | 需自己封装 |
92
+
93
+ > **致非中文用户**:本插件为中文小说分析写作而设计——句式、情感、意象等核心能力以及内置的语义模型,全部针对中文语料构建与调优。在深耕中文的同时兼顾英文等其他语言,确实超出了我目前的能力范围。若因此给您带来不便,我深感抱歉,恳请谅解。
35
94
 
36
95
  ---
37
96
 
@@ -75,6 +134,27 @@ dsh plugin --profile web add github:siweina/dsh-novel-writer#main
75
134
 
76
135
  ---
77
136
 
137
+ ## MCP 服务器(非 DSH 用户也能用)
138
+
139
+ 包里自带一个 **stdio MCP 服务器**(`mcp/server.mjs`),把 16 个工具原样暴露给任何 MCP 客户端,
140
+ 例如 Claude Desktop、Cursor。**它是跑在你自己电脑上的本地进程,不需要服务器、不需要联网、不需要常驻。**
141
+
142
+ ```json
143
+ {
144
+ "mcpServers": {
145
+ "dsh-novel-writer": {
146
+ "command": "node",
147
+ "args": ["/绝对路径/mcp/server.mjs", "--root", "/你的小说库路径"]
148
+ }
149
+ }
150
+ }
151
+ ```
152
+
153
+ 书库根目录优先级:`--root` > 环境变量 `DSH_NOVEL_WRITER_ROOT` > 当前工作目录。
154
+ 细节见 [mcp/README.md](./mcp/README.md)。
155
+
156
+ ---
157
+
78
158
  ## 配置
79
159
 
80
160
  ```yaml
@@ -92,6 +172,38 @@ dsh plugin --profile web add github:siweina/dsh-novel-writer#main
92
172
 
93
173
  ---
94
174
 
175
+ ## 依赖、权限与失败边界
176
+
177
+ **运行时依赖**(`npm install` 自动安装,均为公开包):
178
+
179
+ - `onnxruntime-web` ^1.24.3 —— 本地 ONNX 推理(WASM 后端),用于语义检索与语义风格距离;
180
+ - `@huggingface/tokenizers` ^0.1.0 —— 中文分词(WASM);
181
+ - peerDependency:`react` ^18.2.0(浏览器端复用 DSH Web GUI 自带的 React,不额外打包)。
182
+
183
+ **本地模型**:`lib/models/` 随包分发 bge-small-zh-v1.5 量化模型(约 24MB,ONNX)与分词器
184
+ (`tokenizer.json.gz`,加载时解压)。全部推理在本机 CPU 完成,**不上传任何文本**。
185
+
186
+ **权限与外部服务**:
187
+
188
+ - 文件系统:只读写用户指定的书库根目录 `novels/` 与其数据目录 `<root>/.novel-writer/`,
189
+ 以及插件自身的开关文件 `~/.dsh/dsh-novel-writer/state.json`;不访问其他路径。
190
+ - 本地 HTTP:在 DSH Web GUI 内注册 5 条路由(state / reveal / reports / demo / update-check),
191
+ 仅回环地址可访问;`allowLanState` 默认关闭,局域网访问默认拒绝。
192
+ - 外部网络:唯一外呼是 GitHub Releases API(`api.github.com`)检查新版本——3 秒超时、24 小时缓存、
193
+ 失败静默降级;请求不含任何书籍内容。
194
+ - 子进程:无。唯一例外是打开系统文件管理器(Windows `explorer` / macOS `open` / Linux `xdg-open`),
195
+ 以数组参数直调、不经 shell。
196
+ - 生命周期脚本:无(无 preinstall / postinstall / prepare)。
197
+
198
+ **失败边界**:
199
+
200
+ - 语义引擎不可用(模型缺失或 WASM 初始化失败)时自动回退纯规则模式,其余功能不受影响;
201
+ - 分析结果落盘失败不阻塞工具返回;缓存损坏按"无缓存"处理并重建;
202
+ - 插件加载失败不影响 DSH 主进程:工具注册与提示词注入相互独立。
203
+
204
+ **兼容范围**:Node.js >= 22.3(`engines.node`);DSH >= 0.1.1-rc.2(`dsh.engines.dsh`)。
205
+
206
+ ---
95
207
  ## 许可证
96
208
 
97
209
  [MIT](./LICENSE)
package/lib/analysis.js CHANGED
@@ -1573,13 +1573,15 @@ export function densityOf(text) {
1573
1573
  // v2.5 修复:接入 lib/lexicons/dutir_seven.json(大连理工七类情感词表 27,413 词)
1574
1574
  // 懒加载 + 内存缓存;七类 → 五情感映射,供 sentimentCounts 扩展计数(词表未覆盖的词也能计分)
1575
1575
  import { createRequire } from "node:module";
1576
+ import { gunzipSync } from "node:zlib";
1576
1577
  const __req = createRequire(import.meta.url);
1577
1578
  let DUTIR = null;
1578
1579
  function loadDutir() {
1579
1580
  if (DUTIR) return DUTIR;
1580
1581
  try {
1581
- const p = __req.resolve("./lexicons/dutir_seven.json");
1582
- DUTIR = JSON.parse(__req("node:fs").readFileSync(p, "utf8"));
1582
+ // v4.0.1:dutir 词表以 gzip 随包分发(原文件 383KB 超出商店单文件上限),加载时解压
1583
+ const p = __req.resolve("./lexicons/dutir_seven.json.gz");
1584
+ DUTIR = JSON.parse(gunzipSync(__req("node:fs").readFileSync(p)).toString("utf8"));
1583
1585
  } catch {
1584
1586
  DUTIR = {};
1585
1587
  }