@waterwx/dsh-novel-forge 1.3.1 → 1.3.3

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/lib/index.js CHANGED
@@ -1,10 +1,10 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
1
3
  import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
2
4
  import z from "schemastery";
3
5
  import { exec } from "node:child_process";
4
6
  import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
5
- import { join } from "node:path";
6
7
  import { BlockAssembler, ReasoningEffortId, createAssistantMessage, createUserMessage } from "@deepseek-ai/dsh-llm";
7
- import { homedir } from "node:os";
8
8
  import { randomBytes } from "node:crypto";
9
9
  import { strFromU8, unzipSync } from "fflate";
10
10
  //#region src/assets.ts
@@ -2060,7 +2060,7 @@ async function extractRoleVisual(ctx, config, project, outputDir, roleName) {
2060
2060
  "- source:说明依据(如\"第1章/第8章外貌描写;瞳色未明确\")。",
2061
2061
  "- expressions:该角色在本书剧情中需要的情绪表情清单数组,6-12 个(如 [\"疲惫\",\"麻木\",\"压抑悲伤\",\"皱眉\",\"紧绷\",\"放空\"]),依据正文情绪描写与角色处境推断。",
2062
2062
  "- promptKit:四类精修提示词(字段化+出图约束,参考示例结构):",
2063
- " · portrait 立绘:角色设计稿定位,纯白纯色背景,全身完整无裁切,无多余杂物;字段流:年龄感、身高(有依据才写)、发型发色、胡茬、眼眸、面部气质、上身服装分件(含磨损)、下身、鞋、标志物细节。",
2063
+ " · portrait 立绘:严格按字段顺序写(参考示例结构):开头构图定位(正面站立全身人像)→ 风格(3D动漫,超精细建模)→ 背景(纯白纯色背景)→ 身份(男子,{角色名},外表{年龄},男性)→ 发型发色 → 胡茬 → 眼眸 → 面部 → 气质 → 上身服装分件(颜色款式+磨损细节)→ 下身 → 鞋 → 标志物(标签/印记,含细节如洇暗翘边)→ 收尾(角色设计稿,细节完整展示,无多余杂物,全身完整无裁切)。",
2064
2064
  " · sheet 四视图:同一角色的 正面/左侧面/右侧面/背面 四视图设定表(character sheet),纯白背景,全身完整,四个视角分别描述,服装与标志物细节完整展示。",
2065
2065
  " · expressions 表情:每个表情一段,脸部特写(头部到锁骨),纯白背景,五官与角色定稿完全一致,只换情绪表达(眼神/嘴角/眉),皮肤纹理细节完整,无多余杂物。",
2066
2066
  " · details 细节:多组局部细节集合参考图(一张图多个局部框),纯白背景;把该角色全部标志物逐项列出(如标签/印记/工牌/袖口磨损/鞋),每项一句特写描述;细节清晰锐利,角色细节参考稿,无多余杂物。",
@@ -2132,7 +2132,7 @@ async function generateRolePromptKit(ctx, config, project, roleName) {
2132
2132
  system: [
2133
2133
  "你是一位 AI 绘图提示词工程师。基于给定角色的形象锚点、表情清单与本书视觉规则,输出四类生图提示词(每类 zh+en 各一段)。",
2134
2134
  "四类:",
2135
- "1. portrait 立绘:全身/半身正视图,含完整服装与标志物。",
2135
+ "1. portrait 立绘:正面站立全身人像,3D动漫超精细建模,纯白纯色背景;按字段流组织:身份(男子,角色名,外表年龄)→ 发型发色 → 胡茬 → 眼眸 → 面部 → 气质 → 上身服装分件(含磨损)→ 下身 → 鞋 → 标志物(含细节)→ 收尾(角色设计稿,细节完整展示,无多余杂物,全身完整无裁切)。",
2136
2136
  "2. sheet 四视图:同一角色的 正面/左侧面/右侧面/背面 四视图设定表(character sheet),纯白背景,四个视角分别描述。",
2137
2137
  "3. expressions 表情:每个表情一段,脸部特写(头部到锁骨),纯白背景,五官与角色定稿完全一致,只换情绪表达(眼神/嘴角/眉),皮肤纹理细节完整,无多余杂物。",
2138
2138
  "4. details 细节:多组局部细节集合参考图(一张图多个局部框),纯白背景;把该角色全部标志物逐项列出,每项一句特写描述;细节清晰锐利,角色细节参考稿,无多余杂物。",
@@ -3525,9 +3525,10 @@ function removeBook(id) {
3525
3525
  function activeBookOutputDir() {
3526
3526
  return activeBook(loadBookshelf())?.outputDir;
3527
3527
  }
3528
- /** 默认输出目录推断:小说目录/书名。 */
3528
+ /** 默认输出目录推断:~/.dsh/novels/书名。 */
3529
3529
  function defaultOutputDirFor(bookName) {
3530
- return join("D:\\ryan work\\harness\\novels", bookName.replace(/[\\/:*?"<>|]/g, "").trim().slice(0, 40) || "未命名小说");
3530
+ const clean = bookName.replace(/[\\/:*?"<>|]/g, "").trim().slice(0, 40) || "未命名小说";
3531
+ return join(homedir(), ".dsh", "novels", clean);
3531
3532
  }
3532
3533
  //#endregion
3533
3534
  //#region src/run.ts
@@ -6207,7 +6208,7 @@ function makeRoutes(deps) {
6207
6208
  }
6208
6209
  const role = project.roles.find((r) => r.name === name);
6209
6210
  if (role === void 0) {
6210
- writeJson(res, 404, { error: `角色 ${name} 不存在` });
6211
+ writeJson(res, 404, { error: `当前激活《${project.bookName}》,角色 ${name} 不存在——若期望的书不对,请先在书架切换该书并刷新` });
6211
6212
  return;
6212
6213
  }
6213
6214
  const label = body?.label?.trim() ?? "";
@@ -6564,7 +6565,7 @@ function makeRoutes(deps) {
6564
6565
  }
6565
6566
  const scene = project.scenes.find((x) => x.name === name);
6566
6567
  if (scene === void 0) {
6567
- writeJson(res, 404, { error: `场景 ${name} 不存在` });
6568
+ writeJson(res, 404, { error: `当前激活《${project.bookName}》,场景 ${name} 不存在——若期望的书不对,请先在书架切换该书并刷新` });
6568
6569
  return;
6569
6570
  }
6570
6571
  const label = body?.label?.trim() ?? "全景";
@@ -6730,6 +6731,14 @@ function makeRoutes(deps) {
6730
6731
  }
6731
6732
  //#endregion
6732
6733
  //#region src/index.ts
6734
+ /**
6735
+ * dsh-novel-forge — host half. Mounts the AI novel-forge workbench: docx
6736
+ * outline import, LLM chapter planning, chapter-by-chapter generation
6737
+ * (3000-4000 chars each), Markdown output into your chosen folder, and the
6738
+ * /api/dsh-novel-forge route family. The browser half (./client) renders the
6739
+ * workbench panel. Everything rides official NPM SDK packages — no dsh source
6740
+ * changes.
6741
+ */
6733
6742
  /** Stable cordis plugin name. */
6734
6743
  const name = "novel-forge";
6735
6744
  /** Services required before the novel-forge surfaces can mount. */
@@ -6747,8 +6756,8 @@ const NOVEL_SETTINGS_NAMESPACE = settingsNamespace("dsh-novel-forge");
6747
6756
  const Config = z.object({
6748
6757
  announceToAgent: z.boolean().default(true),
6749
6758
  enabled: z.boolean().default(true),
6750
- outlinePath: z.string().default("D:\\ryan work\\harness\\novels\\归墟玉主\\《归墟玉主》全书大纲_重新排版版.docx"),
6751
- outputDir: z.string().default("D:\\ryan work\\harness\\novels\\归墟玉主"),
6759
+ outlinePath: z.string().default(""),
6760
+ outputDir: z.string().default(join(homedir(), ".dsh", "novels")),
6752
6761
  provider: z.string().default("deepseek-official"),
6753
6762
  model: z.string().default("deepseek-v4-flash"),
6754
6763
  reasoningEffort: z.union([
@@ -6769,8 +6778,8 @@ const Config = z.object({
6769
6778
  });
6770
6779
  /** Schema defaults, re-read for hand-built test contexts. */
6771
6780
  const DEFAULT_ANNOUNCE = true;
6772
- const DEFAULT_OUTLINE_PATH = "D:\\ryan work\\harness\\novels\\归墟玉主\\《归墟玉主》全书大纲_重新排版版.docx";
6773
- const DEFAULT_OUTPUT_DIR = "D:\\ryan work\\harness\\novels\\归墟玉主";
6781
+ const DEFAULT_OUTLINE_PATH = "";
6782
+ const DEFAULT_OUTPUT_DIR = join(homedir(), ".dsh", "novels");
6774
6783
  const DEFAULT_PROVIDER = "deepseek-official";
6775
6784
  const DEFAULT_MODEL = "deepseek-v4-flash";
6776
6785
  const DEFAULT_REASONING_EFFORT = "off";
@@ -6783,7 +6792,7 @@ const DEFAULT_AUTO_REVIEW_AFTER_REVISE = true;
6783
6792
  /** Order of the announcement section within the tool-guidance band. */
6784
6793
  const SECTION_ORDER = 160;
6785
6794
  /** Model-facing announcement: plugin presence, capabilities, and limits. */
6786
- const NOVEL_GUIDANCE = "本机已安装 dsh-novel-forge 插件(AI 编译小说工作台):侧边栏「小说工坊」入口。能力:读取 docx 大纲(默认 D:\\ryan work\\harness\\novels\\归墟玉主 大纲)或粘贴大纲文本;用 LLM 提炼道藏(人设/世界观/金手指规则/写作红线,即设定圣经);生成卷计划与章节计划;逐章调用 LLM 生成 3000-4000 字正文并保存为 Markdown(默认输出到 D:\\ryan work\\harness\\novels\\归墟玉主);每章自动生成摘要(叙事记忆)、自动 AI 审稿(人设/设定/红线/文笔/爽点/逻辑),支持按审稿意见重写、去 AI 味润色、暗线(伏笔)管理、批量连写与全本导出(txt/md)。限制:生成消耗 LLM API 额度;输出目录与模型可在插件设置中修改;章节正文质量取决于大纲完整度。用户提到「小说 / 大纲 / 写小说 / 章节 / 审稿 / 润色 / 归墟玉主」时即指本插件,请据此协作。";
6795
+ const NOVEL_GUIDANCE = "本机已安装 dsh-novel-forge 插件(AI 编译小说工作台):侧边栏「小说工坊」入口。能力:读取 docx 大纲或粘贴大纲文本;用 LLM 提炼道藏(人设/世界观/金手指规则/写作红线,即设定圣经);生成卷计划与章节计划;逐章调用 LLM 生成 3000-4000 字正文并保存为 Markdown(默认输出到用户主目录 ~/.dsh/novels);每章自动生成摘要(叙事记忆)、自动 AI 审稿(人设/设定/红线/文笔/爽点/逻辑),支持按审稿意见重写、去 AI 味润色、暗线(伏笔)管理、批量连写与全本导出(txt/md)。限制:生成消耗 LLM API 额度;输出目录与模型可在插件设置中修改;章节正文质量取决于大纲完整度。用户提到「小说 / 大纲 / 写小说 / 章节 / 审稿 / 润色」时即指本插件,请据此协作。";
6787
6796
  /** Resolve a config-like value into the full runtime config. */
6788
6797
  function resolveConfig(value) {
6789
6798
  return {