@waterwx/dsh-novel-forge 2.0.1-alpha → 2.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.
Files changed (183) hide show
  1. package/README.md +368 -362
  2. package/lib/client.js +20340 -19622
  3. package/lib/index.js +11313 -7285
  4. package/lib/types/action-guard.d.ts +61 -0
  5. package/lib/types/ai-scan.d.ts +0 -6
  6. package/lib/types/assets.d.ts +20 -9
  7. package/lib/types/assistant.d.ts +29 -0
  8. package/lib/types/author-assets.d.ts +1 -3
  9. package/lib/types/bookshelf.d.ts +13 -3
  10. package/lib/types/client/api.d.ts +136 -27
  11. package/lib/types/client/chip-prefs.d.ts +36 -0
  12. package/lib/types/client/docx.d.ts +2 -2
  13. package/lib/types/client/llmLive.d.ts +31 -0
  14. package/lib/types/client/locales.d.ts +15 -70
  15. package/lib/types/client/mount.d.ts +0 -2
  16. package/lib/types/client/panel/AiTag.d.ts +1 -0
  17. package/lib/types/client/panel/AssistantTab.d.ts +4 -1
  18. package/lib/types/client/panel/AuthorHome.d.ts +13 -11
  19. package/lib/types/client/panel/BookAnalysisView.d.ts +4 -0
  20. package/lib/types/client/panel/CmdPalette.d.ts +12 -0
  21. package/lib/types/client/panel/CreateBookView.d.ts +5 -1
  22. package/lib/types/client/panel/DirectorView.d.ts +7 -0
  23. package/lib/types/client/panel/IdeaInspirationView.d.ts +6 -0
  24. package/lib/types/client/panel/KnowledgeBaseView.d.ts +4 -0
  25. package/lib/types/client/panel/LiveFeedLog.d.ts +13 -0
  26. package/lib/types/client/panel/MarketRadarView.d.ts +5 -0
  27. package/lib/types/client/panel/ModelManager.d.ts +2 -2
  28. package/lib/types/client/panel/NovelPanel.d.ts +6 -1
  29. package/lib/types/client/panel/PageHeader.d.ts +18 -0
  30. package/lib/types/client/panel/PromptSlotsView.d.ts +11 -0
  31. package/lib/types/client/panel/SettingsView.d.ts +12 -9
  32. package/lib/types/client/panel/ShelfView.d.ts +10 -1
  33. package/lib/types/client/panel/SubPage.d.ts +27 -0
  34. package/lib/types/client/panel/TensionView.d.ts +18 -0
  35. package/lib/types/client/panel/TimelineView.d.ts +18 -0
  36. package/lib/types/client/panel/helpers.d.ts +5 -3
  37. package/lib/types/client/panel/market-radar-state.d.ts +56 -0
  38. package/lib/types/client/panel/outline-markdown.d.ts +112 -0
  39. package/lib/types/client/panel/status-badge.d.ts +13 -0
  40. package/lib/types/client/panel/storage-parse.d.ts +46 -0
  41. package/lib/types/client/panel/toast.d.ts +2 -0
  42. package/lib/types/client/panel/usePersistentState.d.ts +17 -0
  43. package/lib/types/client/panel/views.d.ts +21 -35
  44. package/lib/types/client/run-status.d.ts +21 -0
  45. package/lib/types/client/sidebar-entry.d.ts +0 -2
  46. package/lib/types/digest-parse.d.ts +29 -0
  47. package/lib/types/docx-core.d.ts +16 -0
  48. package/lib/types/docx.d.ts +2 -3
  49. package/lib/types/engine.d.ts +150 -103
  50. package/lib/types/global-assets.d.ts +6 -0
  51. package/lib/types/home.d.ts +11 -0
  52. package/lib/types/index.d.ts +26 -12
  53. package/lib/types/llm-live.d.ts +70 -0
  54. package/lib/types/llm-retry.d.ts +38 -0
  55. package/lib/types/market-radar-scan.d.ts +18 -0
  56. package/lib/types/market-radar-sources.d.ts +31 -0
  57. package/lib/types/migrate-output.d.ts +25 -0
  58. package/lib/types/model-capability.d.ts +119 -0
  59. package/lib/types/model-request.d.ts +36 -0
  60. package/lib/types/output-budget.d.ts +86 -0
  61. package/lib/types/plotline-align.d.ts +35 -0
  62. package/lib/types/prompt-slots.d.ts +57 -0
  63. package/lib/types/prompting.d.ts +10 -0
  64. package/lib/types/protocol.d.ts +841 -601
  65. package/lib/types/revision.d.ts +76 -0
  66. package/lib/types/routes.d.ts +9 -3
  67. package/lib/types/run-selection.d.ts +51 -0
  68. package/lib/types/run.d.ts +32 -1
  69. package/lib/types/settings-persist.d.ts +59 -0
  70. package/lib/types/snapshots.d.ts +46 -0
  71. package/lib/types/stage-contract.d.ts +58 -0
  72. package/lib/types/stream-fallback.d.ts +60 -0
  73. package/lib/types/strip-headings.d.ts +33 -0
  74. package/lib/types/tension.d.ts +53 -0
  75. package/lib/types/timeline.d.ts +37 -0
  76. package/package.json +50 -27
  77. package/assets/styles/arcane-thick-3d.webp +0 -0
  78. package/assets/styles/chinese-ink.webp +0 -0
  79. package/assets/styles/clay-stopmotion-3d.webp +0 -0
  80. package/assets/styles/dark-ghibli.webp +0 -0
  81. package/assets/styles/dark-gothic-3d.webp +0 -0
  82. package/assets/styles/film-photo.webp +0 -0
  83. package/assets/styles/guofeng-heavy.webp +0 -0
  84. package/assets/styles/guoman-2d-gufeng.webp +0 -0
  85. package/assets/styles/guoman-3d-tianyuan.webp +0 -0
  86. package/assets/styles/guoman-3d-xuanhuan.webp +0 -0
  87. package/assets/styles/horror-game-3d.webp +0 -0
  88. package/assets/styles/hyperreal-3d.webp +0 -0
  89. package/assets/styles/japan-cel-dark.webp +0 -0
  90. package/assets/styles/korean-webtoon.webp +0 -0
  91. package/assets/styles/low-cyberpunk-3d.webp +0 -0
  92. package/assets/styles/nextgen-cg.webp +0 -0
  93. package/assets/styles/noir-film.webp +0 -0
  94. package/assets/styles/openworld-survival.webp +0 -0
  95. package/assets/styles/paper-cut-3d.webp +0 -0
  96. package/assets/styles/pixar-adult-3d.webp +0 -0
  97. package/assets/styles/pop-marvel-2d.webp +0 -0
  98. package/assets/styles/sandiao-qban.webp +0 -0
  99. package/assets/styles/shinkai-anime.webp +0 -0
  100. package/assets/styles/tactical-stealth.webp +0 -0
  101. package/assets/styles/urban-lightreal-3d.webp +0 -0
  102. package/assets/styles/vaporwave-3d.webp +0 -0
  103. package/assets/styles/vhs90.webp +0 -0
  104. package/lib/types/client/panel/BookshelfBar.d.ts +0 -11
  105. package/lib/types/client/panel/FlowGuide.d.ts +0 -22
  106. package/lib/types/client/panel/MangaRoleLibrary.d.ts +0 -20
  107. package/lib/types/client/panel/MangaWorkspace.d.ts +0 -12
  108. package/lib/types/client/panel/ModelPicker.d.ts +0 -11
  109. package/lib/types/client/panel/ProgressHomeView.d.ts +0 -5
  110. package/lib/types/client/panel/PropLibrary.d.ts +0 -8
  111. package/lib/types/client/panel/SceneLibrary.d.ts +0 -16
  112. package/lib/types/client/panel/StoryboardTab.d.ts +0 -19
  113. package/lib/types/client/panel/StyleCard.d.ts +0 -8
  114. package/lib/types/client/panel/StyleGallery.d.ts +0 -1
  115. package/lib/types/comic-presets.d.ts +0 -12
  116. package/lib/types/manga-genre-rules.d.ts +0 -22
  117. package/lib/types/prompt-utils.d.ts +0 -35
  118. package/lib/types/review-policy.d.ts +0 -97
  119. package/lib/types/shot-language.d.ts +0 -46
  120. package/lib/types/story-beat-language.d.ts +0 -35
  121. package/lib/types/style-library.d.ts +0 -33
  122. package/skills/chapter-batch/SKILL.md +0 -81
  123. package/src/ai-scan.ts +0 -179
  124. package/src/assets.ts +0 -879
  125. package/src/assistant.ts +0 -770
  126. package/src/author-assets.ts +0 -147
  127. package/src/bookshelf.ts +0 -167
  128. package/src/client/api.ts +0 -617
  129. package/src/client/css-modules.d.ts +0 -8
  130. package/src/client/docx.ts +0 -69
  131. package/src/client/index.ts +0 -34
  132. package/src/client/locales.ts +0 -418
  133. package/src/client/mount.tsx +0 -97
  134. package/src/client/mount.tsx._new +0 -97
  135. package/src/client/mount.tsx._nf +0 -97
  136. package/src/client/mount.tsx._tmp +0 -97
  137. package/src/client/panel/AdaptModeView.tsx +0 -520
  138. package/src/client/panel/AssetsTab.tsx +0 -458
  139. package/src/client/panel/AssistantTab.tsx +0 -301
  140. package/src/client/panel/AuthorAssetsView.tsx +0 -208
  141. package/src/client/panel/AuthorHome.tsx +0 -204
  142. package/src/client/panel/BookshelfBar.tsx +0 -170
  143. package/src/client/panel/CreateBookView.tsx +0 -352
  144. package/src/client/panel/FlowGuide.tsx +0 -84
  145. package/src/client/panel/GlobalAssetLibraryView.tsx +0 -172
  146. package/src/client/panel/ImportModal.tsx +0 -303
  147. package/src/client/panel/MangaRoleLibrary.tsx +0 -1002
  148. package/src/client/panel/MangaWorkspace.tsx +0 -715
  149. package/src/client/panel/ModelManager.tsx +0 -205
  150. package/src/client/panel/NovelPanel.tsx +0 -4620
  151. package/src/client/panel/ProgressConsole.tsx +0 -64
  152. package/src/client/panel/ProgressHomeView.tsx +0 -87
  153. package/src/client/panel/PropLibrary.tsx +0 -175
  154. package/src/client/panel/ReaderView.tsx +0 -306
  155. package/src/client/panel/ReasoningSection.tsx +0 -31
  156. package/src/client/panel/RunPanel.tsx +0 -204
  157. package/src/client/panel/SceneLibrary.tsx +0 -453
  158. package/src/client/panel/SettingsView.tsx +0 -286
  159. package/src/client/panel/ShelfView.tsx +0 -242
  160. package/src/client/panel/StoryboardTab.tsx +0 -472
  161. package/src/client/panel/StyleCard.tsx +0 -90
  162. package/src/client/panel/StyleGallery.tsx +0 -58
  163. package/src/client/panel/WorldTab.tsx +0 -202
  164. package/src/client/panel/controller.ts +0 -45
  165. package/src/client/panel/helpers.ts +0 -67
  166. package/src/client/panel/panel.module.css +0 -4360
  167. package/src/client/panel/views.tsx +0 -314
  168. package/src/client/sidebar-entry.ts +0 -122
  169. package/src/client/text.ts +0 -28
  170. package/src/comic-presets.ts +0 -67
  171. package/src/docx.ts +0 -83
  172. package/src/engine.ts +0 -5200
  173. package/src/index.ts +0 -329
  174. package/src/manga-genre-rules.ts +0 -87
  175. package/src/novel-context.ts +0 -287
  176. package/src/prompt-utils.ts +0 -73
  177. package/src/protocol.ts +0 -2233
  178. package/src/review-policy.ts +0 -161
  179. package/src/routes.ts +0 -3419
  180. package/src/run.ts +0 -331
  181. package/src/shot-language.ts +0 -181
  182. package/src/story-beat-language.ts +0 -130
  183. package/src/style-library.ts +0 -84
package/src/index.ts DELETED
@@ -1,329 +0,0 @@
1
- /**
2
- * dsh-novel-forge — host half. Mounts the AI novel-forge workbench: docx
3
- * outline import, LLM chapter planning, chapter-by-chapter generation
4
- * (3000-4000 chars each), Markdown output into your chosen folder, and the
5
- * /api/dsh-novel-forge route family. The browser half (./client) renders the
6
- * workbench panel. Everything rides official NPM SDK packages — no dsh source
7
- * changes.
8
- */
9
-
10
- import { homedir } from 'node:os'
11
- import { join } from 'node:path'
12
- import type { Context } from '@deepseek-ai/cordis'
13
- import type {} from '@deepseek-ai/dsh-settings'
14
- import z from 'schemastery'
15
- import type {} from '@deepseek-ai/dsh-host-webserver'
16
- import type {} from '@deepseek-ai/dsh-llm'
17
- import type {} from '@deepseek-ai/dsh-system-prompt'
18
- import type { ConfigPatch, ImageModelConfig, NovelConfig } from './protocol.ts'
19
- import { makeRoutes } from './routes.ts'
20
- import { activeBookOutputDir } from './bookshelf.ts'
21
-
22
- /** Stable cordis plugin name. */
23
- export const name = 'novel-forge'
24
-
25
- /** Services required before the novel-forge surfaces can mount. */
26
- export const inject = ['webServer', 'llm', 'systemPrompt', 'settings']
27
-
28
- /**
29
- * Settings namespace of the novel-forge capability — the section the web
30
- * settings surface edits. Spelled here rather than imported: the browser half
31
- * spells the same value and must not depend on a Host package.
32
- */
33
- export const NOVEL_SETTINGS_NAMESPACE = 'dsh-novel-forge' as const
34
-
35
- /** Plugin config, validated by the same-named schemastery schema. */
36
- export interface Config {
37
- /** When true (default), a system-prompt section announces the plugin to every agent. */
38
- announceToAgent?: boolean
39
- /** Master switch for the plugin (routes, prompt section). */
40
- enabled?: boolean
41
- /** Absolute path of the default docx outline to load. */
42
- outlinePath?: string
43
- /** Absolute output directory for chapters + project state. */
44
- outputDir?: string
45
- /** LLM provider route. */
46
- provider?: string
47
- /** LLM model id. */
48
- model?: string
49
- /** LLM reasoning effort (off/low/high/max). */
50
- reasoningEffort?: 'off' | 'low' | 'high' | 'max'
51
- /** 分析类任务(提炼/拆书/反推大纲等)的推理档位;默认 low。 */
52
- analysisReasoning?: 'off' | 'low' | 'high' | 'max'
53
- /** Target characters per chapter. */
54
- chapterChars?: number
55
- /** Max output tokens per chapter call. */
56
- maxTokens?: number
57
- /** Review pass threshold (0-100). */
58
- reviewPassScore?: number
59
- /** Whether generation auto-runs review after writing. */
60
- autoReview?: boolean
61
- /** Whether generation auto-runs the author review (hook/continuity/trend). */
62
- autoAuthorReview?: boolean
63
- /** 修订/润色产出草稿后自动附带一次 AI 审查(默认开,可在设置页关闭省 token)。 */
64
- autoReviewAfterRevise?: boolean
65
- /** 生图模型库(多套并存,启用一条生效)。 */
66
- imageModels?: ImageModelConfig[]
67
- /** 豆包/Seedream 生图 API Key(旧字段,兼容迁移用)。 */
68
- imageApiKey?: string
69
- /** 豆包/Seedream 生图模型 ID(旧字段,兼容迁移用)。 */
70
- imageApiModel?: string
71
- /** 是否启用豆包生图(旧字段,兼容迁移用)。 */
72
- imageApiEnabled?: boolean
73
- /** 自定义背景图(URL / dataURL / 服务端路径引用)。 */
74
- themeBackground?: string
75
- /** 自定义背景遮罩/模糊强度 0-80。 */
76
- themeBackgroundBlur?: number
77
- /** 玻璃透明度 0-100(100=当前原样)。 */
78
- themeOpacity?: number
79
- /** 是否启用改编模式(默认关闭)。 */
80
- enableAdaptMode?: boolean
81
- }
82
-
83
- export const Config: z<Config> = z.object({
84
- announceToAgent: z.boolean().default(true),
85
- enabled: z.boolean().default(true),
86
- outlinePath: z.string().default(''),
87
- outputDir: z.string().default(join(homedir(), '.dsh', 'novels')),
88
- provider: z.string().default('deepseek-official'),
89
- model: z.string().default('deepseek-v4-flash'),
90
- reasoningEffort: z.union(['off', 'low', 'high', 'max']).default('off'),
91
- analysisReasoning: z.union(['off', 'low', 'high', 'max']).default('low'),
92
- chapterChars: z.number().default(3500),
93
- maxTokens: z.number().default(12000),
94
- reviewPassScore: z.number().default(70),
95
- autoReview: z.boolean().default(true),
96
- autoAuthorReview: z.boolean().default(true),
97
- autoReviewAfterRevise: z.boolean().default(true),
98
- imageModels: z.array(z.object({
99
- id: z.string().default(''),
100
- name: z.string().default(''),
101
- baseURL: z.string().default(''),
102
- apiKey: z.string().default(''),
103
- model: z.string().default(''),
104
- enabled: z.boolean().default(false),
105
- })).default([]),
106
- imageApiKey: z.string().default(''),
107
- imageApiModel: z.string().default(''),
108
- imageApiEnabled: z.boolean().default(false),
109
- themeBackground: z.string().default(''),
110
- themeBackgroundBlur: z.number().default(0),
111
- themeOpacity: z.number().default(100),
112
- enableAdaptMode: z.boolean().default(true),
113
- })
114
-
115
- /** Schema defaults, re-read for hand-built test contexts. */
116
- const DEFAULT_ANNOUNCE = true
117
- const DEFAULT_OUTLINE_PATH = ''
118
- const DEFAULT_OUTPUT_DIR = join(homedir(), '.dsh', 'novels')
119
- const DEFAULT_PROVIDER = 'deepseek-official'
120
- const DEFAULT_MODEL = 'deepseek-v4-flash'
121
- const DEFAULT_REASONING_EFFORT = 'off' as const
122
- const DEFAULT_ANALYSIS_REASONING = 'low' as const
123
- const DEFAULT_CHAPTER_CHARS = 3500
124
- const DEFAULT_MAX_TOKENS = 12000
125
- const DEFAULT_REVIEW_PASS_SCORE = 70
126
- const DEFAULT_AUTO_REVIEW = true
127
- const DEFAULT_AUTO_AUTHOR_REVIEW = true
128
- const DEFAULT_AUTO_REVIEW_AFTER_REVISE = true
129
-
130
- /** Order of the announcement section within the tool-guidance band. */
131
- const SECTION_ORDER = 160
132
-
133
- /** Model-facing announcement: plugin presence, capabilities, and limits. */
134
- export const NOVEL_GUIDANCE = '本机已安装 dsh-novel-forge 插件(AI 编译小说工作台):侧边栏「小说工坊」入口。能力:读取 docx 大纲或粘贴大纲文本;用 LLM 提炼道藏(人设/世界观/金手指规则/写作红线);生成卷计划与章节计划;逐章调用 LLM 生成 3000-4000 字正文并保存为 Markdown(默认输出到用户主目录 ~/.dsh/novels);每章自动生成摘要(叙事记忆)、自动 AI 审稿(人设/设定/红线/文笔/爽点/逻辑),支持按审稿意见重写、去 AI 味润色、暗线(伏笔)管理、批量连写与全本导出(txt/md)。限制:生成消耗 LLM API 额度;输出目录与模型可在插件设置中修改;章节正文质量取决于大纲完整度。用户提到「小说 / 大纲 / 写小说 / 章节 / 审稿 / 润色」时即指本插件,请据此协作。'
135
-
136
- /** Resolve a config-like value into the full runtime config. */
137
- export function resolveConfig(value: Partial<Config> | undefined): NovelConfig {
138
- return {
139
- outlinePath: value?.outlinePath ?? DEFAULT_OUTLINE_PATH,
140
- outputDir: value?.outputDir ?? DEFAULT_OUTPUT_DIR,
141
- provider: value?.provider ?? DEFAULT_PROVIDER,
142
- model: value?.model ?? DEFAULT_MODEL,
143
- reasoningEffort: value?.reasoningEffort ?? DEFAULT_REASONING_EFFORT,
144
- analysisReasoning: value?.analysisReasoning ?? DEFAULT_ANALYSIS_REASONING,
145
- chapterChars: value?.chapterChars ?? DEFAULT_CHAPTER_CHARS,
146
- maxTokens: value?.maxTokens ?? DEFAULT_MAX_TOKENS,
147
- reviewPassScore: value?.reviewPassScore ?? DEFAULT_REVIEW_PASS_SCORE,
148
- autoReview: value?.autoReview ?? DEFAULT_AUTO_REVIEW,
149
- autoAuthorReview: value?.autoAuthorReview ?? DEFAULT_AUTO_AUTHOR_REVIEW,
150
- autoReviewAfterRevise: value?.autoReviewAfterRevise ?? DEFAULT_AUTO_REVIEW_AFTER_REVISE,
151
- // 生图模型库:只有「从未保存过 imageModels」时才用旧配置迁移一条(豆包默认地址);
152
- // 已保存为空数组 = 用户主动删光,保持空,不再复活。
153
- imageModels: value?.imageModels !== undefined
154
- ? value.imageModels
155
- : (value?.imageApiKey !== undefined && value.imageApiKey !== ''
156
- ? [{ id: 'img-legacy', name: '豆包(旧配置)', baseURL: DEFAULT_IMAGE_BASE, apiKey: value.imageApiKey, model: value.imageApiModel ?? '', enabled: true }]
157
- : []),
158
- // 运行时生效值 = 启用条目(兼容旧代码读取 imageApiKey/imageApiModel/imageApiEnabled)。
159
- imageBaseUrl: (() => {
160
- const active = (value?.imageModels ?? []).find(m => m.enabled) ?? (value?.imageModels ?? [])[0]
161
- return active?.baseURL !== undefined && active.baseURL !== '' ? active.baseURL : (value?.imageApiKey !== undefined && value.imageApiKey !== '' ? DEFAULT_IMAGE_BASE : undefined)
162
- })(),
163
- imageApiKey: (() => {
164
- const active = (value?.imageModels ?? []).find(m => m.enabled) ?? (value?.imageModels ?? [])[0]
165
- return active?.apiKey ?? value?.imageApiKey
166
- })(),
167
- imageApiModel: (() => {
168
- const active = (value?.imageModels ?? []).find(m => m.enabled) ?? (value?.imageModels ?? [])[0]
169
- return active?.model ?? value?.imageApiModel
170
- })(),
171
- // 生图启用:总开关打开,或模型库里存在启用条目,均视为已启用(避免用户只配模型忘了开总开关)。
172
- imageApiEnabled: value?.imageApiEnabled === true || (value?.imageModels ?? []).some(m => m.enabled === true),
173
- themeBackground: value?.themeBackground ?? '',
174
- themeBackgroundBlur: value?.themeBackgroundBlur ?? 0,
175
- themeOpacity: value?.themeOpacity ?? 100,
176
- enableAdaptMode: value?.enableAdaptMode ?? true,
177
- }
178
- }
179
-
180
- /** 生图默认接口地址(豆包 ark,OpenAI 兼容)。 */
181
- const DEFAULT_IMAGE_BASE = 'https://ark.cn-beijing.volces.com/api/v3'
182
-
183
- /**
184
- * Mount the routes and announcement.
185
- * @param ctx - host plugin context carrying webServer/llm/systemPrompt.
186
- * @param config - resolved plugin config (schema defaults applied by the loader).
187
- */
188
- export function apply(ctx: Context, config?: Config): void {
189
- // The live source the routes read: the settings section once the web
190
- // settings surface is served, the composition entry otherwise.
191
- let current: () => Config = () => config ?? {}
192
- const resolve = (): NovelConfig => {
193
- const resolved = resolveConfig(current())
194
- // 书架激活的书优先决定输出目录(settings 仍可改默认值)。
195
- const shelfDir = activeBookOutputDir()
196
- if (shelfDir !== undefined) {
197
- return { ...resolved, outputDir: shelfDir }
198
- }
199
- return resolved
200
- }
201
-
202
- const patchConfig = async (patch: ConfigPatch): Promise<NovelConfig> => {
203
- const next: ConfigPatch = {}
204
- if (patch.outlinePath !== undefined) next.outlinePath = patch.outlinePath
205
- if (patch.outputDir !== undefined) next.outputDir = patch.outputDir
206
- if (patch.provider !== undefined) next.provider = patch.provider
207
- if (patch.model !== undefined) next.model = patch.model
208
- if (patch.reasoningEffort !== undefined) next.reasoningEffort = patch.reasoningEffort
209
- if (patch.analysisReasoning !== undefined) next.analysisReasoning = patch.analysisReasoning
210
- if (patch.chapterChars !== undefined) next.chapterChars = patch.chapterChars
211
- if (patch.maxTokens !== undefined) next.maxTokens = patch.maxTokens
212
- if (patch.reviewPassScore !== undefined) next.reviewPassScore = patch.reviewPassScore
213
- if (patch.autoReview !== undefined) next.autoReview = patch.autoReview
214
- if (patch.autoAuthorReview !== undefined) next.autoAuthorReview = patch.autoAuthorReview
215
- if (patch.autoReviewAfterRevise !== undefined) next.autoReviewAfterRevise = patch.autoReviewAfterRevise
216
- if (patch.imageApiKey !== undefined) next.imageApiKey = patch.imageApiKey
217
- if (patch.imageApiModel !== undefined) next.imageApiModel = patch.imageApiModel
218
- if (patch.imageApiEnabled !== undefined) next.imageApiEnabled = patch.imageApiEnabled
219
- if (patch.themeBackground !== undefined) next.themeBackground = patch.themeBackground
220
- if (patch.themeBackgroundBlur !== undefined) next.themeBackgroundBlur = patch.themeBackgroundBlur
221
- if (patch.themeOpacity !== undefined) next.themeOpacity = patch.themeOpacity
222
- if (patch.enableAdaptMode !== undefined) next.enableAdaptMode = patch.enableAdaptMode
223
- if (patch.imageModels !== undefined) next.imageModels = patch.imageModels
224
- // Persist through the settings seam when available; otherwise keep in memory.
225
- // (ctx.get is the non-strict service access — no inject requirement, same
226
- // pattern installSettingsSection itself uses.)
227
- const settings = ctx.get('settings')
228
- if (settings !== undefined) {
229
- await settings.update(NOVEL_SETTINGS_NAMESPACE, next as Record<string, unknown>)
230
- } else {
231
- current = () => ({ ...current(), ...next })
232
- }
233
- return resolve()
234
- }
235
-
236
- let disposeSection: (() => void) | undefined
237
- let disposeRoutes: (() => void) | undefined
238
-
239
- const sync = (): void => {
240
- if (disposeSection !== undefined) {
241
- disposeSection()
242
- disposeSection = undefined
243
- }
244
- if (disposeRoutes !== undefined) {
245
- disposeRoutes()
246
- disposeRoutes = undefined
247
- }
248
- const value = resolve()
249
- if (!(current().enabled ?? true)) return
250
- if (current().announceToAgent ?? DEFAULT_ANNOUNCE) {
251
- disposeSection = ctx.systemPrompt.section({
252
- name: 'plugin:dsh-novel-forge',
253
- order: SECTION_ORDER,
254
- text: NOVEL_GUIDANCE,
255
- })
256
- }
257
- const routes = makeRoutes({ ctx, getConfig: resolve, patchConfig })
258
- disposeRoutes = ctx.effect(
259
- () => {
260
- const disposers = routes.map(route => ctx.webServer.register(route))
261
- return () => { for (const dispose of disposers) dispose() }
262
- },
263
- 'dsh-novel-forge: routes',
264
- )
265
- void value
266
- }
267
-
268
- ctx.settings.installSection(ctx, NOVEL_SETTINGS_NAMESPACE, Config, config ?? {}, {
269
- setSource: (source) => {
270
- current = source
271
- sync()
272
- },
273
- onChange: sync,
274
- })
275
-
276
- // 运行时 skill:章节批量生产与值守处理(只在本插件环境可用)。
277
- // 通过 ctx.get('skills') 获取注册表(服务存在时注册,缺失则跳过,不影响其他能力)。
278
- const skillsService = ctx.get('skills') as { register?: (skill: { name: string; provider: string; description: string; content: string }) => () => void } | undefined
279
- if (skillsService?.register !== undefined) {
280
- const disposeSkill = skillsService.register({
281
- name: 'novel-forge-chapter-batch',
282
- provider: 'dsh-novel-forge',
283
- description: '批量生成小说章节并值守处理审稿未过的章节(豁免/按意见修订/验证模式/重新生成),依赖 dsh-novel-forge 的 /api/dsh-novel-forge/* 路由。',
284
- content: [
285
- '# 小说章节批量生产与值守处理',
286
- '',
287
- '## 0. 值守纪律(最高优先级,违反即空转)',
288
- '1. 启动后台任务后立即停下,不轮询、不连续 wait、不做无意义动作——后台任务完成时运行时自动通知。',
289
- '2. 只有收到「任务完成」通知或用户新消息时,才继续下一步(读结果→处理未过→汇报)。',
290
- '3. 等待期间可做与当前任务无关的其他有用工作,但不得为等任务而空转。',
291
- '4. 任务因 web 重启中断时:待 3080 恢复后,复位卡死章节(generating/error → reset)再续跑,并向用户说明中断原因。',
292
- '',
293
- '## 1. 前置检查',
294
- '1. `GET /api/dsh-novel-forge/status` 确认服务在跑,读项目章节数。',
295
- '2. 列出目标区间 pending 章节号,避免重复生成已处理章节。',
296
- '3. **串行执行,禁止并行写 project.json**(并发会互相覆盖状态,实测教训)。',
297
- '',
298
- '## 2. 批量生成',
299
- '逐章串行调用 `POST /generate` `{ chapterNo, skipReview: false }`(走完整质量门:生成→摘要+编年录→审稿→复盘)。',
300
- '响应为 NDJSON,找 review 帧取 score/passed。每章 2-5 分钟;失败重试 1 次;后台跑并告知预计时长。',
301
- '用 Node 脚本(fetch 逐章循环),避免 PowerShell 转义坑,用完删除。',
302
- '',
303
- '## 3. 未过章节分级处理',
304
- '### A. 无 high → 豁免通过:`POST /chapter/approve`(主观项不磨)',
305
- '### B. 有 high 且明确 → 按意见修订 + 验证模式:',
306
- '1. 拼指令 `按审稿意见修订(优先处理):\n[severity] item → suggestion`(high 优先,无 high 取前 3 medium)',
307
- '2. `POST /rewrite` 产草稿;3. `POST /chapter/check` 带 `previousReport` 走验证模式(只核对原意见解决+只挑新增 high)',
308
- '4. 判定 `passed || 无 high` 可接受;5. `POST /draft/apply` 带 passed 报告落盘 approved',
309
- '6. 不可接受 → 第二轮修订(指令更精确)→ 再验证;每章最多修 2 轮,仍不过保留草稿待人工',
310
- '### C. 结构性 high(修订改不好)→ `POST /draft/discard` 后 `POST /generate` 重写,剩主观项再走 A',
311
- '### D. error 状态 → `POST /chapter/reset` 后 `POST /generate`',
312
- '注意:approved 但 review 有 high 的保留不动;修订指令越精确越有效(具体数字/行为一次就过)。',
313
- '',
314
- '## 4. 收尾',
315
- '`GET /status` 验证目标区间全 approved;可选刷新剧情线(`POST /plotlines` op=refresh,注意只读最近 8 章摘要);汇报通过/未过/失败与遗留项。',
316
- '',
317
- '## 5. 已知陷阱',
318
- '- 并发写 project.json 互相覆盖 → 必须串行',
319
- '- rewrite 草稿可能偶发不落盘 → 应用前检查 pendingDraft,不存在则重跑',
320
- '- PowerShell 调 API 引号/中文转义是坑 → 用 Node 脚本',
321
- '- 验证模式 500 偶发 → 重试一次',
322
- ].join('\n'),
323
- })
324
- ctx.effect(() => disposeSkill, 'dsh-novel-forge: skill')
325
- }
326
-
327
- // Initial registration from the composition entry.
328
- sync()
329
- }
@@ -1,87 +0,0 @@
1
- /**
2
- * 题材规则库(可插拔)—— 漫剧分镜/提示词生成的「题材专用规则」。
3
- * 参考短剧工业导演规范:不同题材用不同的视觉语言 / 打斗 / 特效规则,
4
- * 按漫剧方案的 genre 注入 generateStoryboardPrompts,避免「一套模板跑所有题材」。
5
- * 每个题材给一组「生成提示词时必须遵守的题材规则」;未选题材则不注入(走通用规则)。
6
- */
7
-
8
- export interface GenreRule {
9
- /** 题材 id。 */
10
- id: string
11
- /** 题材名(展示)。 */
12
- label: string
13
- /** 该题材的生成提示词核心规则(每行一条,注入生成时)。 */
14
- rules: string[]
15
- }
16
-
17
- /** 内置题材(通用题材 default 为空规则)。 */
18
- export const GENRES: GenreRule[] = [
19
- {
20
- id: 'xuanhuan',
21
- label: '玄幻 / 仙侠',
22
- rules: [
23
- '施法必须经法宝媒介(笛/扇/印/笔等实体法宝),写清法宝本体材质+施法动作+特效出口,禁止只写"施法"。',
24
- '每个角色绑定主属性+双色粒子(雷=蓝白+紫电、冰=冰蓝+银白、金=亮金+暖白、火=赤红+暗金、木=粉白+草木青),属性决定术法形态与配色。',
25
- '术法攻防走"罡气→破罡→防御转攻":护体罡气被划开、防御术法炸裂化千万飞刃/剑气,防守转攻是高光点,必写。',
26
- '能量具象化:光柱/雷龙/法相/领域;"光柱"要写成"洪流/弧光/波纹/光丝雨"(禁裸光柱,防呆板发光管)。',
27
- '终招蓄力必写:天地灵韵向角色/法宝汇聚、能量漩涡成型,再接幂击。',
28
- '对军清场:扇形冲击波/剑气暴雨洗地/能量扇镇压大军核心,战场弹坑/碎片/云层撕开反馈。',
29
- ],
30
- },
31
- {
32
- id: 'wuxia',
33
- label: '武侠 / 国风',
34
- rules: [
35
- '打斗用 Hit-Stop 三件套:碰撞瞬间 1~2 帧微停顿 + 接触点火花 + 双刃咬死高频震颤,杜绝滑步/空气假打。',
36
- '武术动作链:起手/攻防/收势,标明具体招式(刀/剑/轻功/擒拿),剑走轻灵、刀走厚重。',
37
- '镜头强化打击感:碰撞点微环绕、贴身横移、命中定格,禁静止对峙。',
38
- '轻功/身法:衣袂翻飞、发丝飘动、残影,身形轻盈不僵硬。',
39
- ],
40
- },
41
- {
42
- id: 'anime',
43
- label: '二次元 / 动漫',
44
- rules: [
45
- '大招三段式:蓄力→释放→爆发,能量形态+爆发特效,段段画质声明复用。',
46
- '双色粒子:每角色一套主色+材质+轨迹,双方互补对冲(冷 vs 暖),防混战混淆。',
47
- '色指定:明确主色调+高光色+特效撞色,防发灰。',
48
- '禁止评价词/裸光效/空泛"粒子";能量写"光丝雨/弧光/波纹"+方向+材质。',
49
- ],
50
- },
51
- {
52
- id: 'urban',
53
- label: '都市 / 现实',
54
- rules: [
55
- '微表情生理递进:眼神/眉心/唇部/鼻翼/喉头/手指,情绪逐层推进,不夸张不脸谱。',
56
- '对白语速 3.5~5 字/秒(台词从声音层按此把控,留 0.3~0.8s 落口发酵)。',
57
- '防棚拍假冷光:用真实光线(自然光/路灯/窗光/霓虹),日景不陰间冷蓝、局部留暖光。',
58
- '场景真实还原(街头/室内/医院等),人物服装生活化,肢体动作自然不律動化。',
59
- ],
60
- },
61
- {
62
- id: 'scifi',
63
- label: '科幻 / 未来',
64
- rules: [
65
- '机甲/能量武器设定明确(颜色/材质/发光部位),能量轨迹具体。',
66
- '霓虹/屏幕光/激光防眩光,用冷色主调+重点发光处。',
67
- '宏大场景(飞船/城市/废墟)用大远景/俯拍,人物相对渺小。',
68
- ],
69
- },
70
- ]
71
-
72
- /** 通用题材(空规则,走通用生成)。 */
73
- export const DEFAULT_GENRE: GenreRule = { id: 'default', label: '通用(不限定)', rules: [] }
74
-
75
- /** 按题材 id 取规则(未找到返回通用)。 */
76
- export function getGenreRules(id?: string): string[] {
77
- if (id === undefined || id === '') return DEFAULT_GENRE.rules
78
- const g = GENRES.find(x => x.id === id)
79
- return g !== undefined ? g.rules : DEFAULT_GENRE.rules
80
- }
81
-
82
- /** 取题材 label(展示用)。 */
83
- export function getGenreLabel(id?: string): string {
84
- if (id === undefined || id === '') return DEFAULT_GENRE.label
85
- const g = GENRES.find(x => x.id === id)
86
- return g !== undefined ? g.label : id
87
- }