dsh-novel-writer 6.6.0 → 6.6.5

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
@@ -173,7 +173,7 @@ fixAnchors:3 条原著锚段(对话 / 心理 / 描写各一条,供逐句
173
173
  3. **12-axis vibe spectrum**: nightmare / angst / heartwarming / fluff / tearjerker / dark / mystery / blaze / absurd / lonesome / aesthetic / sensual — with traceable evidence, 0 token.
174
174
  4. **Local semantic engine**: bge-small-zh Chinese model (24MB, shipped with the plugin) local CPU inference — `novel_semantic_search` finds semantically related passages with natural language (with chapter location), semantic style comparison, semantic implicit emotion; lazy loading + graceful fallback.
175
175
  5. **Sentence-pattern analysis**: 9 categories, arrangement patterns, rhythm, emotion curve, style fingerprint + guidance, with cache & report export.
176
- 6. **Emotion purification & quantification**: strong/weak emotion-word grading, pollution detection, caveat warning + AI re-verification; Valence sliding window → variance V / delta Δ / conflict index C + implicit imagery carriers.
176
+ 6. **Emotion purification & quantification**: strong/weak emotion-word grading, pollution detection, caveat warning + AI re-verification; Valence sliding window → variance V / delta Δ / conflict index C + implicit imagery carriers.<br>**Emotion complexity now follows confidence (v6.6.5)**: when the conclusion is not trustworthy (a pollution threshold is hit, the text contains no emotion words at all, or no usable clean counts remain) the tool no longer hands out a top-tier verdict — `complexity.level` is reported as `unknown`, together with `reliable: false` and a `reliabilityNote` giving the reason, and the rendered text prints that warning on its own line; `score` keeps its numeric value for cross-chapter comparison. The emotion dimension is simply not applicable to R18 / high-physiological prose — use rhythm, payoff and dialogue density instead.
177
177
  7. **Worldview & pragmatics detection**: auto cultural-baseline detection with confidence; speechStyle title/honorifics/rituals/tone norms; genre & theme + webnovel signals.
178
178
  8. **Writing toolkit**: plot tracking / five settings tables (characters·locations·items·timeline·worldview) / chapter summaries / continuity audit / batch import / style check / continuation writing.
179
179
  9. **Per-tool UI toggles**: a 「写作助手功能」 ("Writing Assistant") entry in the left sidebar plus a main-column panel (**official DSH 0.2.0 seats**; hosts older than 0.2.0 fall back automatically) — master switch + grouped tool toggles + feature toggles + prompt mode/scene/**lean workflow**, plain-language labels, data-dir usage & semantic-engine status. All colors go through `--dsw-alias-*` semantic tokens (three themes in sync with the host), controls use the official UI primitives, DeepSeek-blue accents, a glow hero header with section kickers, and equal-width pages across every level.<br>**The UI goes further (Plan A)**: source split + build chain (assert-failed builds never write, `--check` verifies source==artifact), 6 unified components with a single row pattern (`PreferenceRow`), group cards across every switch page, 19+5 line icons, a slider as auxiliary input on the tolerance rows, and page-level push-pop transition animations (zero state / zero hook).
package/README.md CHANGED
@@ -169,7 +169,7 @@ fixAnchors:3 条原著锚段(对话 / 心理 / 描写各一条,供逐句
169
169
  3. **氛围光谱 12 轴**:噩梦感 / 焦虑压抑 / 温馨治愈 / 甜宠日常 / 催泪虐心 / 黑暗残酷 / 悬疑神秘 / 热血激昂 / 荒诞无厘头 / 孤独疏离 / 文艺唯美 / 情欲暧昧——证据链可追溯,0 token。
170
170
  4. **本地语义引擎**:bge-small-zh 中文模型(24MB 随插件分发)本地 CPU 推理——`novel_semantic_search` 自然语言搜全书语义相关段落(带章节定位),语义级风格对比、语义隐性情感,懒加载 + 自动回退。
171
171
  5. **句式模式分析**:九类句式分布、排列规律、句长节奏、情感曲线、风格指纹与节奏建议,带缓存与报告导出。
172
- 6. **情感净化 + 量化**:强/弱情绪词分级、污染源检测、caveat 预警 + AI 复核;Valence 滑动窗口 → 方差 V / 斜率 Δ / 矛盾指数 C + 隐性意象载体。
172
+ 6. **情感净化 + 量化**:强/弱情绪词分级、污染源检测、caveat 预警 + AI 复核;Valence 滑动窗口 → 方差 V / 斜率 Δ / 矛盾指数 C + 隐性意象载体。<br>**情感复杂度与置信度联动(v6.6.5)**:结论不可采信时(污染命中阈值、全文零情感词命中,或没有可用的 clean 情感计数)不再给顶格结论——`complexity.level` 标为 `unknown`,并附 `reliable: false` 与 `reliabilityNote` 说明原因,渲染文本里也会单独一行写出这句警告;`score` 保留数值便于跨章对比。R18 / 高生理描写文本的情感维度本就不适用,建议改用节奏、爽点、对话密度等维度。
173
173
  7. **世界观与语用检测**:文化基准自动判断(西/东/混合)+ 置信度;speechStyle 称谓/客套/仪式/语气规范;题材流派 + 网文信号。
174
174
  8. **写作辅助全家桶**:伏笔登记表 / 设定五张表(人物·地点·道具·时间线·世界观)/ 章节摘要 / 连贯性审计 / 批量导入 / 风格自检 / 续写辅助。
175
175
  9. **全工具 UI 开关**:左栏「写作助手功能」入口 + 主栏面板(**DSH 0.2.0 官方席位**;老宿主 < 0.2.0 自动回退旧挂载)——总开关 + 工具开关分组 + 功能开关 + 提示词档位/场景/**精简工作流**,大白话文案,显示数据目录占用与语义引擎状态。颜色全走 `--dsw-alias-*` 语义 token(三主题与官方同源)、控件用官方 UI primitives、品牌蓝强调、光晕头部与分区 kicker、各级页面等宽。<br>**界面再进一步(方案 A)**:源码分块 + 构建链装配(构建失败不写盘、`--check` 校验源与产物一致)、6 个统一组件与单一行模式(`PreferenceRow`)、分组卡片贯穿全部开关页、19+5 枚线图标、阈值 slider 辅助输入、页面级 push-pop 过渡动画(零 state / 零 hook)。
package/lib/analysis.js CHANGED
@@ -1165,20 +1165,57 @@ export function chapterEmotionStats(counts) {
1165
1165
  };
1166
1166
  }
1167
1167
 
1168
- /** v1.6.0 全书聚合:复杂度评分 0-1(熵归一化0.5 + 多样性0.25 + 主次冲突0.25)+ 章间漂移。 */
1169
- export function emotionComplexity(perChapter) {
1168
+ /**
1169
+ * v1.6.0 全书聚合:复杂度评分 0-1(熵归一化0.5 + 多样性0.25 + 主次冲突0.25)+ 章间漂移。
1170
+ *
1171
+ * v6.6.5 修正(用户反馈「第一章的情感复杂度会直接爆掉」):
1172
+ * 复杂度此前**与置信度完全脱钩** ✗ —— 同一份输出里一边写着 `confidence: "low"` + 「检测到高密度
1173
+ * R18/生理描写,dominant 可能来自生理/爽感词而非真实情感,请勿采信」,另一边**照样**给出
1174
+ * `complexity: { score: 0.6, level: "high" }`。下游 AI 只要读 `level` 就会得出「情感复杂度高」的
1175
+ * 结论,**而这个结论已被工具自己否定**。实测(棍妹 第一/二章,R18 密度 8.99‰ / 9.77‰):
1176
+ * 两章都判 `level: "high"`,而两章的 `confidence` 都是 `"low"`。
1177
+ *
1178
+ * 现在接收 `reliability`(由调用方把污染/无数据判定传进来),当结论不可采信时:
1179
+ * · `level` 降级为 `"unknown"`(**不再给顶格的 high**)
1180
+ * · 加 `reliable: false` + `reliabilityNote`(固定说明)—— 让"不可采信"出现在**结论字段本身**,
1181
+ * 而不是只写在旁边的 caveat 里(那正是误导的来源)
1182
+ * · `score` 数值保留(便于对比),但 `reliable: false` 已标明其地位
1183
+ *
1184
+ * @param perChapter 分章计数(**clean 计数**,调用方已用 cleanScoresOf 聚合)
1185
+ * @param reliability 可选:{ polluted?: boolean, pollutedBy?: string[], noData?: boolean }
1186
+ */
1187
+ export function emotionComplexity(perChapter, reliability) {
1188
+ const rel = reliability && typeof reliability === "object" ? reliability : null;
1189
+ const polluted = rel?.polluted === true;
1190
+ const noData = rel?.noData === true;
1191
+ const unreliable = polluted || noData;
1192
+ const reliabilityNote = polluted
1193
+ ? "⚠️ 本复杂度基于已被污染的情感计数(" + ((rel?.pollutedBy ?? []).join("、") || "高密度场景性用词") + "),不可采信:请勿据此判断文本的情感复杂度,须 novel_read 抽查原文后自行判断。"
1194
+ : noData
1195
+ ? "ℹ️ 未检出任何情感词,本复杂度无数据可依(score 0 表示「没测到」,不是「情感简单」),请勿据此下结论。"
1196
+ : "";
1197
+ const levelOf = (raw) => (unreliable ? "unknown" : raw);
1170
1198
  // v4.0.0 修正:c.counts 缺失时不再抛 TypeError(与其余 ?? 0 的防御风格一致)
1171
1199
  const list = Array.isArray(perChapter) ? perChapter : [];
1172
1200
  const stats = list.map((c) => ({ chapter: c?.chapter, ...(chapterEmotionStats(c?.counts) ?? {}) })).filter((s) => s.entropy !== void 0);
1173
1201
  if (stats.length === 0) {
1174
- // 无情感词命中:不复杂(low),恒有值供模型读取
1202
+ // v6.6.5 修正(**由文档负责人在实测中独立发现的同类残留**,与本次要修的是同一类问题):
1203
+ // 走到这里说明 **clean 情感计数为空**(stats 正是从 clean 计数算出来的)—— 也就是复杂度
1204
+ // **无数据可依** ✗。而此前只在 `noData`(**raw** 计数为零)时才标不可采信,于是
1205
+ // 「raw 命中了弱词、clean 一个强词都没有」这类文本(实测 `她笑了笑,眼泪掉了下来。`)
1206
+ // 会得到 `level: "low"` + `reliable: true`,**而 `reliabilityNote` 却写着「无数据可依」** ✗
1207
+ // —— 结论与说明自相矛盾,正是本版要消灭的形态。现在统一:**没有 clean 数据 ⇒ 不可采信、level 给 unknown**。
1175
1208
  return {
1176
- score: 0, level: "low", entropy: 0, maxEntropy: Math.round(EMOTION_MAX_ENTROPY * 1000) / 1000,
1209
+ score: 0, level: "unknown", entropy: 0, maxEntropy: Math.round(EMOTION_MAX_ENTROPY * 1000) / 1000,
1177
1210
  // v4.3.0(清单第 35 条):无次要情感时 secondary 统一为空串(旧版此处"neutral"、
1178
1211
  // 上方非空分支却给"joy"这类 0 占比情感,两处口径不同)。
1179
1212
  diversity: 0, dominant: "neutral", dominantRatio: 0, secondary: "", secondaryRatio: 0,
1180
1213
  conflict: "", conflictStrength: 0,
1181
- chapterDrift: { meanEntropy: 0, entropyVariance: 0, swinging: false }
1214
+ chapterDrift: { meanEntropy: 0, entropyVariance: 0, swinging: false },
1215
+ reliable: false,
1216
+ reliabilityNote: polluted
1217
+ ? reliabilityNote
1218
+ : "ℹ️ 未检出可用的情感计数(clean 计数为空),本复杂度无数据可依:score 0 表示「没测到」,不是「情感简单」,请勿据此下结论。"
1182
1219
  };
1183
1220
  }
1184
1221
  const totalCounts = {};
@@ -1196,7 +1233,8 @@ export function emotionComplexity(perChapter) {
1196
1233
  const level = score >= 0.6 ? "high" : score >= 0.4 ? "medium" : "low";
1197
1234
  return {
1198
1235
  score: Math.round(score * 100) / 100,
1199
- level,
1236
+ // v6.6.5:不可采信时降级为 "unknown" —— 见函数头说明(原先照样给 high,与 confidence:"low" 自相矛盾)
1237
+ level: levelOf(level),
1200
1238
  entropy: global.entropy,
1201
1239
  maxEntropy: Math.round(EMOTION_MAX_ENTROPY * 1000) / 1000,
1202
1240
  diversity: global.diversity,
@@ -1212,14 +1250,19 @@ export function emotionComplexity(perChapter) {
1212
1250
  meanEntropy: Math.round(meanEntropy * 1000) / 1000,
1213
1251
  entropyVariance: Math.round(entropyVariance * 10000) / 10000,
1214
1252
  swinging: entropyVariance > 0.03
1215
- }
1253
+ },
1254
+ reliable: !unreliable,
1255
+ reliabilityNote
1216
1256
  };
1217
1257
  }
1218
1258
 
1219
1259
  /**
1220
1260
  * v1.6.0 情感量化入口:三指标 + 显隐对比 + 复杂度 + 复合共现(纯规则 0 token)。
1261
+ *
1262
+ * v6.6.5:新增第 4 个可选参数 `reliability`,透传给 `emotionComplexity`——
1263
+ * 让复杂度知道"这次的情感计数是否被污染/是否根本没数据",从而不再给出与 `confidence` 矛盾的顶格结论。
1221
1264
  */
1222
- export function emotionalQuantification(text, perChapter, blocks) {
1265
+ export function emotionalQuantification(text, perChapter, blocks, reliability) {
1223
1266
  // v4.3.0(清单第 33 条):入参兜底——旧版 emotionalQuantification("x", [{chapter,counts}])
1224
1267
  // 抛 "blocks is not iterable",而它下面的 fallback 分支本意就是支持"无分章数据"这一输入。
1225
1268
  const src = String(text ?? "");
@@ -1242,7 +1285,7 @@ export function emotionalQuantification(text, perChapter, blocks) {
1242
1285
  stats,
1243
1286
  implicit,
1244
1287
  compare: explicitImplicitCompare(meanValence, implicit),
1245
- complexity: emotionComplexity(perChapter),
1288
+ complexity: emotionComplexity(perChapter, reliability),
1246
1289
  composites: compositeEmotionPairs(blockList)
1247
1290
  };
1248
1291
  }
@@ -1537,7 +1580,13 @@ export function analyzeText(text, options = {}) {
1537
1580
  }).filter((m) => Object.values(m.counts).some((v) => v > 0))
1538
1581
  };
1539
1582
  })();
1540
- const quantification = emotionalQuantification(sampleText, perChapterGroups.entries, blockMeta.map((m) => m.sentences).filter((s) => s.length > 0));
1583
+ const quantification = emotionalQuantification(sampleText, perChapterGroups.entries, blockMeta.map((m) => m.sentences).filter((s) => s.length > 0), {
1584
+ // v6.6.5:把"这次的情感计数可不可信"传给复杂度,避免出现
1585
+ // 「confidence: low(勿采信)」与「complexity.level: high」并存的矛盾输出。
1586
+ polluted,
1587
+ pollutedBy,
1588
+ noData: totalEmotion === 0
1589
+ });
1541
1590
  if (quantification?.complexity?.chapterDrift) quantification.complexity.chapterDrift.basis = perChapterGroups.basis;
1542
1591
  const emotion = {
1543
1592
  dominant: dominantEmotion,
package/lib/core.js CHANGED
@@ -2070,7 +2070,19 @@ ${value.message ?? ""}
2070
2070
  lines.push("", "【情感量化】");
2071
2071
  lines.push(`- Valence: 均值 ${stats.meanValence ?? 0}, 方差V ${stats.variance ?? 0}, 相邻撕裂 ${stats.adjVariance ?? 0}, 斜率Δ ${stats.delta ?? 0}, 矛盾指数C ${stats.conflict ?? 0}`);
2072
2072
  if (q.compare) lines.push(`- 显隐对比: ${JSON.stringify(q.compare).slice(0, 120)}`);
2073
- if (q.complexity) lines.push(`- 复杂度: ${JSON.stringify(q.complexity).slice(0, 120)}`);
2073
+ if (q.complexity) {
2074
+ const cx = q.complexity;
2075
+ // v6.6.5 修正(用户反馈「情感复杂度会直接爆掉」的真凶):
2076
+ // 原先这里打印的是 `JSON.stringify(q.complexity).slice(0, 120)` ✗ —— 而 `reliable` /
2077
+ // `reliabilityNote` 排在对象**末尾**,**必然被 120 字符截掉** ✗,于是「本项不可采信」
2078
+ // 这个最要紧的信息永远到不了渲染文本:读者只看到一个 `high`,看不到旁边的警告。
2079
+ // 现在改成可读行,并在不可采信时**单独起一行**写明原因。
2080
+ lines.push("- 复杂度: " + (cx.score ?? 0) + "(" + (cx.level ?? "?") + ")"
2081
+ + "熵 " + (cx.entropy ?? 0) + "/" + (cx.maxEntropy ?? 0) + ",多样性 " + (cx.diversity ?? 0)
2082
+ + (cx.conflict ? ",主次 " + cx.conflict + "(" + (cx.conflictStrength ?? 0) + ")" : "")
2083
+ + (cx.chapterDrift ? ",章间漂移 " + (cx.chapterDrift.swinging ? "有" : "无") + "(基准 " + (cx.chapterDrift.basis ?? "?") + ")" : ""));
2084
+ if (cx.reliable === false) lines.push(" " + String(cx.reliabilityNote ?? "⚠️ 本项不可采信,请勿据此下结论。"));
2085
+ }
2074
2086
  if (q.implicit && (q.implicit.ambiguous || []).length > 0) {
2075
2087
  // v3.9.0 修正:implicit 无 hits 字段(不再输出误导性的「隐性情感句 0 处」)
2076
2088
  lines.push(`- 隐性意象: 变色龙词 ${(q.implicit.ambiguous || []).length} 个(语义层裁决见下文/quantification.implicit)`);
package/lib/index.js CHANGED
@@ -2404,6 +2404,17 @@ function registerNovelStyleReport(ctx, config) {
2404
2404
  ? siDist.slice(0, 8).map(function (kv) { return kv[0] + "×" + kv[1]; }).join(" ") + (siDist.length > 8 ? " …(共 " + siDist.length + " 类)" : "")
2405
2405
  : "(无)";
2406
2406
  lines.push(" 隐性情绪:" + siText);
2407
+ // v6.6.5:把「情感复杂度」也渲染出来 —— 此前渲染层**完全没有这一项** ✗,于是
2408
+ // `complexity.level = high` 只出现在结构化字段里,人类读渲染文本看不到它,
2409
+ // 更看不到它与 `confidence: "low"` 的矛盾(用户反馈「情感复杂度会直接爆掉」正是这么来的)。
2410
+ // 不可采信时**明确写出 level=unknown + 原因**,而不是让读者从数字里自己猜。
2411
+ const cx = q.complexity;
2412
+ if (cx && typeof cx === "object") {
2413
+ lines.push(" 情感复杂度 " + (cx.score ?? 0) + "(" + (cx.level ?? "?") + ")"
2414
+ + " 熵 " + (cx.entropy ?? 0) + "/" + (cx.maxEntropy ?? 0) + " 多样性 " + (cx.diversity ?? 0)
2415
+ + (cx.conflict ? " 主次 " + cx.conflict + "(" + (cx.conflictStrength ?? 0) + ")" : ""));
2416
+ if (cx.reliable === false) lines.push(" " + String(cx.reliabilityNote ?? "⚠️ 本项不可采信,请勿据此下结论。"));
2417
+ }
2407
2418
  } else {
2408
2419
  lines.push(" 情感量化已关闭(emotionComplexity=false,不输出 Δ/V/C 与量化派生项)");
2409
2420
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-novel-writer",
3
- "version": "6.6.0",
3
+ "version": "6.6.5",
4
4
  "description": "小说写作助手插件(20 个工具):覆盖「动笔前取材料 → 写完量化自检 → 改稿按优先级复测 → 跨章结构体检」整条流程。含句式模式分析、情感量化与氛围光谱、风格画像报告、文笔六维基线带、本地语义检索(离线)、章节库浏览与摘要、设定表与伏笔登记、原创模式创作资料、连贯性审计(衔接/OOC/大纲对照)、开写包与改稿台;必用词表支持书级+全局两层登记、批量导入、开写包硬清单注入与成稿用词审计;用语规范按作品文化基准(欧式/中式/现代)自动选表,并支持逐词静音。界面为官方侧栏面板(右侧栏标签 + 页脚入口)。附 stdio MCP 服务器(Claude Desktop / Cursor 可用)。",
5
5
  "mcpName": "io.github.siweina/dsh-novel-writer",
6
6
  "type": "module",
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: 20 tools for Chinese web-novel style, plot-thread and continuity audits.",
6
- "version": "6.6.0",
6
+ "version": "6.6.5",
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": "6.6.0",
16
+ "version": "6.6.5",
17
17
  "runtimeHint": "npx",
18
18
  "packageArguments": [
19
19
  {