@waterwx/dsh-novel-forge 1.10.1 → 2.0.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 (194) hide show
  1. package/README.md +287 -281
  2. package/lib/client.js +19572 -18127
  3. package/lib/index.js +12171 -6932
  4. package/lib/types/action-guard.d.ts +61 -0
  5. package/lib/types/ai-scan.d.ts +30 -0
  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 +137 -21
  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/index.d.ts +1 -1
  14. package/lib/types/client/llmLive.d.ts +31 -0
  15. package/lib/types/client/locales.d.ts +15 -70
  16. package/lib/types/client/mount.d.ts +0 -2
  17. package/lib/types/client/panel/AiTag.d.ts +1 -0
  18. package/lib/types/client/panel/AssistantTab.d.ts +4 -1
  19. package/lib/types/client/panel/AuthorHome.d.ts +13 -9
  20. package/lib/types/client/panel/BookAnalysisView.d.ts +4 -0
  21. package/lib/types/client/panel/CmdPalette.d.ts +12 -0
  22. package/lib/types/client/panel/CreateBookView.d.ts +5 -1
  23. package/lib/types/client/panel/DirectorView.d.ts +7 -0
  24. package/lib/types/client/panel/IdeaInspirationView.d.ts +6 -0
  25. package/lib/types/client/panel/KnowledgeBaseView.d.ts +4 -0
  26. package/lib/types/client/panel/LiveFeedLog.d.ts +13 -0
  27. package/lib/types/client/panel/MarketRadarView.d.ts +5 -0
  28. package/lib/types/client/panel/ModelManager.d.ts +2 -2
  29. package/lib/types/client/panel/NovelPanel.d.ts +6 -1
  30. package/lib/types/client/panel/PageHeader.d.ts +18 -0
  31. package/lib/types/client/panel/PromptSlotsView.d.ts +11 -0
  32. package/lib/types/client/panel/SettingsView.d.ts +12 -7
  33. package/lib/types/client/panel/ShelfView.d.ts +10 -1
  34. package/lib/types/client/panel/SubPage.d.ts +27 -0
  35. package/lib/types/client/panel/TensionView.d.ts +18 -0
  36. package/lib/types/client/panel/TimelineView.d.ts +18 -0
  37. package/lib/types/client/panel/helpers.d.ts +5 -3
  38. package/lib/types/client/panel/market-radar-state.d.ts +56 -0
  39. package/lib/types/client/panel/toast.d.ts +2 -0
  40. package/lib/types/client/panel/views.d.ts +21 -35
  41. package/lib/types/client/run-status.d.ts +21 -0
  42. package/lib/types/client/sidebar-entry.d.ts +0 -2
  43. package/lib/types/docx-core.d.ts +16 -0
  44. package/lib/types/docx.d.ts +2 -3
  45. package/lib/types/engine.d.ts +83 -79
  46. package/lib/types/global-assets.d.ts +6 -0
  47. package/lib/types/home.d.ts +11 -0
  48. package/lib/types/index.d.ts +27 -13
  49. package/lib/types/llm-live.d.ts +70 -0
  50. package/lib/types/llm-retry.d.ts +38 -0
  51. package/lib/types/market-radar-scan.d.ts +18 -0
  52. package/lib/types/market-radar-sources.d.ts +31 -0
  53. package/lib/types/migrate-output.d.ts +25 -0
  54. package/lib/types/model-capability.d.ts +93 -0
  55. package/lib/types/novel-context.d.ts +80 -0
  56. package/lib/types/output-budget.d.ts +86 -0
  57. package/lib/types/prompt-slots.d.ts +57 -0
  58. package/lib/types/prompting.d.ts +10 -0
  59. package/lib/types/protocol.d.ts +829 -522
  60. package/lib/types/revision.d.ts +76 -0
  61. package/lib/types/routes.d.ts +9 -3
  62. package/lib/types/run.d.ts +23 -1
  63. package/lib/types/settings-persist.d.ts +59 -0
  64. package/lib/types/snapshots.d.ts +46 -0
  65. package/lib/types/stage-contract.d.ts +58 -0
  66. package/lib/types/tension.d.ts +53 -0
  67. package/lib/types/timeline.d.ts +37 -0
  68. package/package.json +50 -28
  69. package/src/action-guard.ts +127 -0
  70. package/src/ai-scan.ts +155 -0
  71. package/src/assets.ts +1801 -535
  72. package/src/assistant.ts +1098 -770
  73. package/src/author-assets.ts +131 -147
  74. package/src/bookshelf.ts +193 -167
  75. package/src/client/api.ts +767 -607
  76. package/src/client/chip-prefs.ts +121 -0
  77. package/src/client/docx.ts +32 -69
  78. package/src/client/index.ts +3 -1
  79. package/src/client/llmLive.ts +111 -0
  80. package/src/client/locales.ts +15 -274
  81. package/src/client/mount.tsx +4 -3
  82. package/src/client/panel/AdaptModeView.tsx +535 -520
  83. package/src/client/panel/AiTag.tsx +7 -0
  84. package/src/client/panel/AssetsTab.tsx +448 -458
  85. package/src/client/panel/AssistantTab.tsx +355 -301
  86. package/src/client/panel/AuthorAssetsView.tsx +205 -207
  87. package/src/client/panel/AuthorHome.tsx +309 -202
  88. package/src/client/panel/BookAnalysisView.tsx +63 -0
  89. package/src/client/panel/CmdPalette.tsx +102 -0
  90. package/src/client/panel/CreateBookView.tsx +366 -352
  91. package/src/client/panel/DirectorView.tsx +200 -0
  92. package/src/client/panel/GlobalAssetLibraryView.tsx +168 -172
  93. package/src/client/panel/IdeaInspirationView.tsx +76 -0
  94. package/src/client/panel/ImportModal.tsx +302 -302
  95. package/src/client/panel/KnowledgeBaseView.tsx +125 -0
  96. package/src/client/panel/LiveFeedLog.tsx +204 -0
  97. package/src/client/panel/MarketRadarView.tsx +415 -0
  98. package/src/client/panel/ModelManager.tsx +205 -205
  99. package/src/client/panel/NovelPanel.tsx +5559 -4655
  100. package/src/client/panel/PageHeader.tsx +37 -0
  101. package/src/client/panel/ProgressConsole.tsx +63 -64
  102. package/src/client/panel/PromptSlotsView.tsx +97 -0
  103. package/src/client/panel/ReaderView.tsx +306 -306
  104. package/src/client/panel/RunPanel.tsx +56 -24
  105. package/src/client/panel/SettingsView.tsx +175 -112
  106. package/src/client/panel/ShelfView.tsx +63 -39
  107. package/src/client/panel/SubPage.tsx +42 -0
  108. package/src/client/panel/TensionView.tsx +212 -0
  109. package/src/client/panel/TimelineView.tsx +208 -0
  110. package/src/client/panel/WorldTab.tsx +202 -202
  111. package/src/client/panel/helpers.ts +7 -5
  112. package/src/client/panel/market-radar-state.ts +79 -0
  113. package/src/client/panel/panel.module.css +5767 -4199
  114. package/src/client/panel/toast.ts +51 -0
  115. package/src/client/panel/views.tsx +316 -314
  116. package/src/client/run-status.ts +171 -0
  117. package/src/client/sidebar-entry.ts +3 -3
  118. package/src/docx-core.ts +53 -0
  119. package/src/docx.ts +44 -83
  120. package/src/engine.ts +1610 -1541
  121. package/src/global-assets.ts +58 -0
  122. package/src/home.ts +33 -0
  123. package/src/index.ts +184 -103
  124. package/src/llm-live.ts +245 -0
  125. package/src/llm-retry.ts +77 -0
  126. package/src/market-radar-scan.ts +35 -0
  127. package/src/market-radar-sources.ts +173 -0
  128. package/src/migrate-output.ts +76 -0
  129. package/src/model-capability.ts +215 -0
  130. package/src/novel-context.ts +286 -0
  131. package/src/output-budget.ts +147 -0
  132. package/src/prompt-slots.ts +125 -0
  133. package/src/prompting.ts +26 -0
  134. package/src/protocol.ts +2454 -2148
  135. package/src/revision.ts +283 -0
  136. package/src/routes.ts +3795 -3359
  137. package/src/run.ts +113 -17
  138. package/src/settings-persist.ts +114 -0
  139. package/src/snapshots.ts +174 -0
  140. package/src/stage-contract.ts +186 -0
  141. package/src/tension.ts +251 -0
  142. package/src/timeline.ts +159 -0
  143. package/assets/styles/arcane-thick-3d.webp +0 -0
  144. package/assets/styles/chinese-ink.webp +0 -0
  145. package/assets/styles/clay-stopmotion-3d.webp +0 -0
  146. package/assets/styles/dark-ghibli.webp +0 -0
  147. package/assets/styles/dark-gothic-3d.webp +0 -0
  148. package/assets/styles/film-photo.webp +0 -0
  149. package/assets/styles/guofeng-heavy.webp +0 -0
  150. package/assets/styles/horror-game-3d.webp +0 -0
  151. package/assets/styles/japan-cel-dark.webp +0 -0
  152. package/assets/styles/korean-webtoon.webp +0 -0
  153. package/assets/styles/low-cyberpunk-3d.webp +0 -0
  154. package/assets/styles/nextgen-cg.webp +0 -0
  155. package/assets/styles/noir-film.webp +0 -0
  156. package/assets/styles/openworld-survival.webp +0 -0
  157. package/assets/styles/paper-cut-3d.webp +0 -0
  158. package/assets/styles/pixar-adult-3d.webp +0 -0
  159. package/assets/styles/pop-marvel-2d.webp +0 -0
  160. package/assets/styles/shinkai-anime.webp +0 -0
  161. package/assets/styles/tactical-stealth.webp +0 -0
  162. package/assets/styles/vaporwave-3d.webp +0 -0
  163. package/assets/styles/vhs90.webp +0 -0
  164. package/lib/types/client/panel/BookshelfBar.d.ts +0 -11
  165. package/lib/types/client/panel/FlowGuide.d.ts +0 -21
  166. package/lib/types/client/panel/MangaRoleLibrary.d.ts +0 -18
  167. package/lib/types/client/panel/MangaWorkspace.d.ts +0 -15
  168. package/lib/types/client/panel/ModelPicker.d.ts +0 -11
  169. package/lib/types/client/panel/ProgressHomeView.d.ts +0 -5
  170. package/lib/types/client/panel/SceneLibrary.d.ts +0 -14
  171. package/lib/types/client/panel/StoryboardTab.d.ts +0 -19
  172. package/lib/types/client/panel/StyleCard.d.ts +0 -8
  173. package/lib/types/client/panel/StyleGallery.d.ts +0 -1
  174. package/lib/types/comic-presets.d.ts +0 -12
  175. package/lib/types/shot-language.d.ts +0 -46
  176. package/lib/types/story-beat-language.d.ts +0 -35
  177. package/lib/types/style-library.d.ts +0 -33
  178. package/skills/chapter-batch/SKILL.md +0 -81
  179. package/src/client/mount.tsx._new +0 -97
  180. package/src/client/mount.tsx._nf +0 -97
  181. package/src/client/mount.tsx._tmp +0 -97
  182. package/src/client/panel/BookshelfBar.tsx +0 -170
  183. package/src/client/panel/FlowGuide.tsx +0 -83
  184. package/src/client/panel/MangaRoleLibrary.tsx +0 -810
  185. package/src/client/panel/MangaWorkspace.tsx +0 -359
  186. package/src/client/panel/ProgressHomeView.tsx +0 -87
  187. package/src/client/panel/SceneLibrary.tsx +0 -396
  188. package/src/client/panel/StoryboardTab.tsx +0 -466
  189. package/src/client/panel/StyleCard.tsx +0 -90
  190. package/src/client/panel/StyleGallery.tsx +0 -58
  191. package/src/comic-presets.ts +0 -67
  192. package/src/shot-language.ts +0 -181
  193. package/src/story-beat-language.ts +0 -130
  194. package/src/style-library.ts +0 -78
package/src/protocol.ts CHANGED
@@ -1,2148 +1,2454 @@
1
- /**
2
- * dsh-novel-forge — shared protocol between the host half (Node) and the
3
- * browser half (web GUI). Route paths, request/response shapes, the project
4
- * state file format, and the NDJSON generation stream frames all live here so
5
- * both halves spell exactly one vocabulary.
6
- */
7
- import type {
8
- ShotSizeId,
9
- CameraMoveId,
10
- CompositionId,
11
- LightingId,
12
- } from './shot-language.ts'
13
- import type {
14
- StoryFunctionId,
15
- EmotionId,
16
- } from './story-beat-language.ts'
17
-
18
- /** The /api/dsh-novel-forge route family (same-origin, loopback-fenced). */
19
- export const NOVEL_API = {
20
- status: '/api/dsh-novel-forge/status',
21
- loadOutline: '/api/dsh-novel-forge/load-outline',
22
- saveOutline: '/api/dsh-novel-forge/save-outline',
23
- plan: '/api/dsh-novel-forge/plan',
24
- volumes: '/api/dsh-novel-forge/volumes',
25
- bible: '/api/dsh-novel-forge/bible',
26
- assets: '/api/dsh-novel-forge/assets',
27
- styleEngine: '/api/dsh-novel-forge/style-engine',
28
- generate: '/api/dsh-novel-forge/generate',
29
- review: '/api/dsh-novel-forge/review',
30
- rewrite: '/api/dsh-novel-forge/rewrite',
31
- polish: '/api/dsh-novel-forge/polish',
32
- /** 采纳待确认草稿(润色/重写产物)覆盖正文文件。 */
33
- draftApply: '/api/dsh-novel-forge/draft/apply',
34
- /** 放弃待确认草稿,保留原稿。 */
35
- draftDiscard: '/api/dsh-novel-forge/draft/discard',
36
- summary: '/api/dsh-novel-forge/summary',
37
- foreshadow: '/api/dsh-novel-forge/foreshadow',
38
- exportBook: '/api/dsh-novel-forge/export',
39
- chapter: '/api/dsh-novel-forge/chapter',
40
- /** 审查任意正文文本(作者手动编辑后,不落盘)。 */
41
- chapterCheck: '/api/dsh-novel-forge/chapter/check',
42
- /** 保存手动编辑的正文(自动备份 .bak)。 */
43
- chapterSave: '/api/dsh-novel-forge/chapter/save',
44
- assistant: '/api/dsh-novel-forge/assistant',
45
- assistantHistory: '/api/dsh-novel-forge/assistant-history',
46
- /** 清空助手对话记录。 */
47
- assistantClear: '/api/dsh-novel-forge/assistant/clear',
48
- bookshelf: '/api/dsh-novel-forge/bookshelf',
49
- /** 导入已有项目目录(含 novel-project.json)到书架。 */
50
- bookshelfImportDir: '/api/dsh-novel-forge/bookshelf/import-dir',
51
- /** 导入 txt/md 全本:拆章建项目并登记书架。 */
52
- bookshelfImportText: '/api/dsh-novel-forge/bookshelf/import-text',
53
- /** 导入 txt/md 全本:拆章预览(不落盘)。 */
54
- bookshelfImportTextPreview: '/api/dsh-novel-forge/bookshelf/import-text/preview',
55
- /** 漫剧方案管理:create/remove/activate。 */
56
- manhuaPlans: '/api/dsh-novel-forge/manhua/plans',
57
- /** 漫剧角色库:从分镜提名(规则+LLM两段式)/ 建卡 / 更新 / 删除 / 形象锚点 / 精修提示词。 */
58
- mangaRoles: '/api/dsh-novel-forge/manga/roles',
59
- /** 分镜·编剧级:单章 → 剧情骨架(节拍链)。 */
60
- storyboardSkeleton: '/api/dsh-novel-forge/storyboard/skeleton',
61
- /** 分镜·导演级:骨架 → 分镜表(镜头级)。 */
62
- storyboardTable: '/api/dsh-novel-forge/storyboard/table',
63
- /** 分镜·提示词级:分镜表 → 即梦可粘贴视频提示词。 */
64
- storyboardPrompts: '/api/dsh-novel-forge/storyboard/prompts',
65
- /** 生图接口连通性测试(设置页每个模型条目用)。 */
66
- imageTest: '/api/dsh-novel-forge/image-test',
67
- /** LLM 模型连通性测试:真实最小调用,验证 Key / 端点 / 模型可用。 */
68
- llmTest: '/api/dsh-novel-forge/llm-test',
69
- /** 添加模型:厂商直填 key 或自定义路由,写进 DSH 凭据与 llm-pi-ai 路由。 */
70
- addModel: '/api/dsh-novel-forge/llm-add',
71
- /** 运行时厂商目录(DSH pi-ai 可配置提供方 + 内置适配器)。 */
72
- llmVendors: '/api/dsh-novel-forge/llm-vendors',
73
- /** 查询某个 provider 当前可用的模型(添加成功后可即时刷新)。 */
74
- llmModels: '/api/dsh-novel-forge/llm-models',
75
- /** 已注册的提供方路由列表(提供方管理)。 */
76
- llmProviders: '/api/dsh-novel-forge/llm-providers',
77
- /** 移除一个提供方。 */
78
- llmRemove: '/api/dsh-novel-forge/llm-remove',
79
- /** 重置项目(可选携带新大纲):清空设定/卷/章节/伏笔/资产/事实库。 */
80
- reset: '/api/dsh-novel-forge/reset',
81
- /** 全书一致性质检:LLM 扫描已生成章节,输出矛盾问题清单。 */
82
- audit: '/api/dsh-novel-forge/audit',
83
- /** 角色卡刷新:基于事实库与各章摘要聚合角色当前状态。 */
84
- charactersRefresh: '/api/dsh-novel-forge/characters/refresh',
85
- /** 事实库回填:对历史已生成章节批量抽取事实(旧章节无事实记录时用)。 */
86
- factsBackfill: '/api/dsh-novel-forge/facts/backfill',
87
- /** 设定圣经局部修补(如世界观规则编辑)。 */
88
- biblePatch: '/api/dsh-novel-forge/bible/patch',
89
- /** 小说简介:生成(AI)/补全(AI)/保存。 */
90
- blurb: '/api/dsh-novel-forge/blurb',
91
- /** 重命名当前书(同步项目与书架条目)。 */
92
- rename: '/api/dsh-novel-forge/rename',
93
- /** 大世界:AI 提炼 / 保存结构化数据(境界/区域/势力)。 */
94
- world: '/api/dsh-novel-forge/world',
95
- /** 封面:GET 读取(dataUrl)/ POST 上传或移除。 */
96
- cover: '/api/dsh-novel-forge/blurb/cover',
97
- /** 剧情线管理:增删改 + 关联章节。 */
98
- plotlines: '/api/dsh-novel-forge/plotlines',
99
- /** 角色库:AI 提炼 / 采纳 / 更新 / 删除。 */
100
- roles: '/api/dsh-novel-forge/roles',
101
- scenes: '/api/dsh-novel-forge/scenes',
102
- visualRules: '/api/dsh-novel-forge/visual-rules',
103
- /** 作者复盘补跑:对已写章节补齐 authorReview(全书流式 / 单章 JSON)。 */
104
- reviewBackfill: '/api/dsh-novel-forge/review/backfill',
105
- /** 章节复位:generating 卡死 → pending(可重新生成)。 */
106
- chapterReset: '/api/dsh-novel-forge/chapter/reset',
107
- /** 章节直接通过:作者对 rejected/written 章节行使最终决定权。 */
108
- chapterApprove: '/api/dsh-novel-forge/chapter/approve',
109
- /** 敏感词检查:全书已写章节或指定文本。 */
110
- sensitiveCheck: '/api/dsh-novel-forge/sensitive-check',
111
- /** 开书想法 → AI 补全大纲:输入一句话想法,生成 2-3 个可选大纲方案。 */
112
- outlineSuggest: '/api/dsh-novel-forge/outline/suggest',
113
- /** 反推大纲:从已写章节正文反向生成全书总纲(NDJSON 流)。 */
114
- outlineReverse: '/api/dsh-novel-forge/outline/reverse',
115
- /** 拆书分析:对已写章节做结构/人物/文风/卖点四维体检(两阶段:源笔记→分节分析)。 */
116
- breakdown: '/api/dsh-novel-forge/breakdown',
117
- /** 漫剧分镜生成:章节 → 角色锚点 + 分镜表(可适配豆包/Seedance/SD)。 */
118
- /** 漫剧分集计划:读一卷 → 按故事弧线分集(高潮拆集/过渡并章)。 */
119
- /** 漫画脚本:章节 → 分页分格漫画脚本(含角色视觉锚点)。 */
120
- /** 生产单:启动批量生产(计划补足 + 逐章生成 + 被拒分级处理)。 */
121
- runStart: '/api/dsh-novel-forge/run/start',
122
- /** 生产单控制:pause / resume / stop。 */
123
- runControl: '/api/dsh-novel-forge/run/control',
124
- /** 生产单状态(含进度统计与日志)。 */
125
- runStatus: '/api/dsh-novel-forge/run/status',
126
- config: '/api/dsh-novel-forge/config',
127
- openFolder: '/api/dsh-novel-forge/open-folder',
128
- /** 插件自更新:在 DSH profile 目录拉取最新 npm 版(下载后需重启 DSH 生效)。 */
129
- pluginUpdate: '/api/dsh-novel-forge/plugin/update',
130
- /** 作者资产库/总数据:读取个人跨书资产(笔法/红线/套路/角色模板/世界观模板)。 */
131
- authorAssets: '/api/dsh-novel-forge/author-assets',
132
- /** 作者资产库:新增/更新一条资产(upsert by id)。 */
133
- authorAssetsUpsert: '/api/dsh-novel-forge/author-assets/upsert',
134
- /** 作者资产库:删除一条资产。 */
135
- authorAssetsRemove: '/api/dsh-novel-forge/author-assets/remove',
136
- /** 作者资产库:导入默认(书架书的写作资产/角色 + 内置全局库)批量沉淀。 */
137
- authorAssetsImportDefault: '/api/dsh-novel-forge/author-assets/import-default',
138
- /** 改编模式:上传全文 → 分析 → 原文设定卡片/可改范围矩阵。 */
139
- adaptAnalyze: '/api/dsh-novel-forge/adapt/analyze',
140
- /** 改编模式:确认要改的维度 → 生成映射表/改编规则/联动影响清单。 */
141
- adaptPropose: '/api/dsh-novel-forge/adapt/propose',
142
- /** 改编模式:执行术语替换(全局替换 + 命中统计 + 改编文本预览)。 */
143
- adaptExecute: '/api/dsh-novel-forge/adapt/execute',
144
- /** 改编模式:保存改编全文为新书(原书保留,登记书架)。 */
145
- adaptSave: '/api/dsh-novel-forge/adapt/save',
146
- /** 改编模式:从源全文 + 编辑后方案提炼新书资料并保存为「待写新书」。 */
147
- adaptMaterialize: '/api/dsh-novel-forge/adapt/materialize',
148
- /** 改编模式:rewrite 逐章重写(NDJSON 流式进度)。 */
149
- adaptRewriteStream: '/api/dsh-novel-forge/adapt/rewrite-stream',
150
- /** 改编模式:把预览/微调后的新书资料写入并登记书架。 */
151
- adaptMaterializeSave: '/api/dsh-novel-forge/adapt/materialize-save',
152
- /** 主题自定义背景:上传图片(POST,存盘并返回服务端 URL)。 */
153
- themeBackgroundUpload: '/api/dsh-novel-forge/theme/background',
154
- /** 主题自定义背景:读取已上传文件(GET prefix,/theme/background/<name>)。 */
155
- themeBackgroundGet: '/api/dsh-novel-forge/theme/background',
156
- } as const
157
-
158
- /** 书架:一本书的条目。 */
159
- export interface BookEntry {
160
- /** 稳定 id。 */
161
- id: string
162
- /** 书名。 */
163
- bookName: string
164
- /** 该书输出目录(独立项目目录)。 */
165
- outputDir: string
166
- /** 创建时间。 */
167
- createdAt: string
168
- /** 最后活动时间。 */
169
- updatedAt: string
170
- }
171
-
172
- /** 书架快照(含每本书的进度摘要)。 */
173
- export interface BookshelfSnapshot {
174
- books: Array<BookEntry & { done: number; total: number; hasProject: boolean; hasCover: boolean; blurb?: string }>
175
- /** 当前激活的书 id(无则 null)。 */
176
- activeBookId: string | null
177
- }
178
-
179
- /** POST /bookshelf 请求:创建新书。 */
180
- export interface BookCreateRequest {
181
- bookName: string
182
- outputDir?: string
183
- /** 开书向导:创建时直接导入的大纲文本(提供则立即建立项目)。 */
184
- outline?: string
185
- }
186
-
187
- /** POST /reset 请求:重置项目(可选更新大纲)。 */
188
- export interface ResetRequest {
189
- /** 新大纲文本;提供则替换 outline,否则保留原大纲。 */
190
- outline?: string
191
- }
192
-
193
- /** POST /bookshelf/activate 请求:切换当前书。 */
194
- export interface BookActivateRequest {
195
- id: string
196
- }
197
-
198
- /** POST /bookshelf/remove 请求:移除书架条目。 */
199
- export interface BookRemoveRequest {
200
- id: string
201
- }
202
-
203
- /** POST /bookshelf/import-dir 请求:导入已有项目目录。 */
204
- export interface BookImportDirRequest {
205
- /** 项目目录(须含 novel-project.json)。 */
206
- outputDir: string
207
- }
208
-
209
- /** POST /bookshelf/import-dir 响应。 */
210
- export interface BookImportDirResponse {
211
- book: BookEntry
212
- /** true = 目录已在书架中(本次为重新激活)。 */
213
- existed: boolean
214
- }
215
-
216
- /** POST /bookshelf/import-text 请求:导入 txt/md 全本。两种模式二选一:
217
- * - filePath:服务器本地文件路径;
218
- * - text + fileName:浏览器上传的全文内容(fileName 用于推断书名)。
219
- */
220
- export interface BookImportTextRequest {
221
- /** 模式一:源文件绝对路径(txt 或 md)。 */
222
- filePath?: string
223
- /** 模式二:浏览器上传的全文内容。 */
224
- text?: string
225
- /** 模式二:原文件名(txt/md),用于推断书名与显示。 */
226
- fileName?: string
227
- /** 输出目录;缺省为 ~/.dsh/novels/书名。 */
228
- outputDir?: string
229
- }
230
-
231
- /** POST /bookshelf/import-text 响应。 */
232
- export interface BookImportTextResponse {
233
- bookName: string
234
- /** 成功拆出的章节数。 */
235
- chapters: number
236
- /** 因内容过短被跳过的章节标题列表。 */
237
- skipped: string[]
238
- /** 登记后的书架条目。 */
239
- book: BookEntry
240
- }
241
-
242
- /** POST /bookshelf/import-text/preview 请求:上传全文做拆章预览(不落盘)。 */
243
- export interface BookImportTextPreviewRequest {
244
- text: string
245
- /** 原文件名(txt/md),用于推断书名。 */
246
- fileName?: string
247
- }
248
-
249
- /** POST /bookshelf/import-text/preview 响应。 */
250
- export interface BookImportTextPreviewResponse {
251
- /** 预计书名(fileName 去扩展名)。 */
252
- bookName: string
253
- /** 识别出的章节(已按正文长度过滤过短章节)。 */
254
- chapters: Array<{ no: number; title: string; chars: number }>
255
- /** 因内容过短被跳过的章节标题列表。 */
256
- skipped: string[]
257
- }
258
-
259
- /** 分镜·编剧级:剧情骨架中的一节拍。 */
260
- export interface StoryboardBeat {
261
- /** 节拍 id(如 b1、b2)。 */
262
- id: string
263
- /** 事件一句话(发生了什么)。 */
264
- event: string
265
- /** 情绪走向(情绪词 id 数组,来自 story-beat-language 词库,链式)。 */
266
- emotion: EmotionId[]
267
- /** 叙事功能(枚举 id,来自 story-beat-language 词库)。 */
268
- function: StoryFunctionId
269
- /** 因果:承接上一节拍的原因(可选)。 */
270
- cause?: string
271
- }
272
-
273
- /** 分镜·编剧级:单章剧情骨架。 */
274
- export interface StoryboardSkeleton {
275
- chapterNo: number
276
- /** 本章弧线一句话(起承转合)。 */
277
- arc: string
278
- /** 剧情节拍链(时间顺序,因果连贯)。 */
279
- beats: StoryboardBeat[]
280
- /** 本章全部出镜角色(正文中的确切称谓,去重;漫剧角色库提名地基)。 */
281
- characters?: string[]
282
- }
283
-
284
- /** POST /storyboard/skeleton 请求:生成单章剧情骨架。 */
285
- export interface StoryboardSkeletonRequest {
286
- chapterNo: number
287
- }
288
-
289
- /** POST /storyboard/skeleton 响应。 */
290
- export interface StoryboardSkeletonResponse {
291
- skeleton: StoryboardSkeleton
292
- }
293
-
294
- /** 分镜·导演级:一个镜头。 */
295
- export interface StoryboardShot {
296
- /** 镜头 id(如 s1、s2)。 */
297
- id: string
298
- /** 挂载的节拍 id(骨架中的 b1…)。 */
299
- beatId: string
300
- /** 景别(枚举 id,来自 shot-language 词库)。 */
301
- shot: ShotSizeId
302
- /** 机位与运镜(枚举 id 数组,来自 shot-language 词库)。 */
303
- camera: CameraMoveId[]
304
- /** 构图(可选,枚举 id)。 */
305
- composition?: CompositionId
306
- /** 时长(秒,1-12)。 */
307
- duration: number
308
- /** 画面内容:角色动作 + 表情 + 服装/标志物。 */
309
- visual: string
310
- /** 台词/旁白(无则空字符串)。 */
311
- line: string
312
- /** 音效(无则空字符串)。 */
313
- sound: string
314
- /** 光效(枚举 id 数组,来自 shot-language 词库)。 */
315
- light: LightingId[]
316
- /** 承接上一镜头结尾状态(位置/动作/情绪/服装)。 */
317
- prevState: string
318
- /** 本镜头结束状态。 */
319
- nextState: string
320
- /** 本镜头出镜角色(引用小说库规范名/漫剧卡名,1-4 个;漫剧角色库提名地基)。 */
321
- characters?: string[]
322
- /** 本镜头已绑定漫剧卡的 id(定妆图引用,供出图/生视频时按卡取参考图)。 */
323
- mangaRoleIds?: string[]
324
- }
325
-
326
- /** 分镜·导演级:单章分镜表。 */
327
- export interface StoryboardTable {
328
- chapterNo: number
329
- shots: StoryboardShot[]
330
- /** 生成时注入的场景卡名称(前端标注消费关系)。 */
331
- usedScenes?: string[]
332
- /** 本章全部出镜角色(各镜头 characters 去重汇总;骨架有则兜底)。 */
333
- characters?: string[]
334
- /** 本章已绑定漫剧卡的 id(去重汇总,定妆图引用)。 */
335
- mangaRoleIds?: string[]
336
- }
337
-
338
- /** POST /storyboard/table 请求:骨架 → 分镜表。 */
339
- export interface StoryboardTableRequest {
340
- chapterNo: number
341
- /** 编剧级骨架(前端已生成/编辑后的版本)。 */
342
- skeleton: StoryboardSkeleton
343
- /** 漫剧方案基底风格 id(style-library);提供时按风格措辞画面描述。 */
344
- styleId?: string
345
- /** 可选滤镜风格 id(stackable)。 */
346
- filterId?: string
347
- }
348
-
349
- /** POST /storyboard/table 响应。 */
350
- export interface StoryboardTableResponse {
351
- table: StoryboardTable
352
- }
353
-
354
- /** 分镜·提示词级:一个镜头的即梦视频提示词。 */
355
- export interface StoryboardPrompt {
356
- /** 对应镜头 id(s1…)。 */
357
- shotId: string
358
- /** 即梦/视频模型可粘贴的中文提示词(画面+运镜+光效+风格词块)。 */
359
- text: string
360
- /** 本镜头绑定的漫剧卡 id(定妆图引用:出图/生视频时按卡取 imageUrl/立绘)。 */
361
- mangaRoleIds?: string[]
362
- }
363
-
364
- /** 分镜持久化:单章的分镜产出(骨架 + 分镜表 + 视频提示词,可分别存在)。 */
365
- export interface ChapterStoryboard {
366
- chapterNo: number
367
- skeleton?: StoryboardSkeleton
368
- table?: StoryboardTable
369
- prompts?: StoryboardPrompt[]
370
- updatedAt: string
371
- }
372
-
373
- /** POST /storyboard/prompts 请求:分镜表 → 视频提示词。 */
374
- export interface StoryboardPromptsRequest {
375
- chapterNo: number
376
- /** 分镜表(前端已生成的镜头列表)。 */
377
- table: StoryboardTable
378
- /** 基底风格 id。 */
379
- styleId?: string
380
- /** 可选滤镜风格 id。 */
381
- filterId?: string
382
- }
383
-
384
- /** POST /storyboard/prompts 响应。 */
385
- export interface StoryboardPromptsResponse {
386
- prompts: StoryboardPrompt[]
387
- }
388
-
389
- /** 漫剧方案:同一本书的多套视觉演绎(基底风格 + 可选滤镜)。 */
390
- export interface MangaPlan {
391
- /** 方案 id。 */
392
- id: string
393
- /** 方案名(如《保质期》3D 皮克斯版)。 */
394
- name: string
395
- /** 基底风格 id(style-library 中非 stackable 风格)。 */
396
- styleId: string
397
- /** 可选滤镜风格 id(style-library 中 stackable 风格)。 */
398
- filterId?: string
399
- /** 是否激活(分镜/角色图生成时使用)。 */
400
- active: boolean
401
- createdAt: string
402
- updatedAt: string
403
- }
404
-
405
- /** POST /manhua/plans 请求:漫剧方案管理。 */
406
- export interface MangaPlansRequest {
407
- op: 'create' | 'remove' | 'activate'
408
- /** create:方案名。 */
409
- name?: string
410
- /** create:基底风格 id。 */
411
- styleId?: string
412
- /** create:可选滤镜风格 id。 */
413
- filterId?: string
414
- /** remove/activate:方案 id。 */
415
- id?: string
416
- }
417
-
418
- /** POST /manhua/plans 响应。 */
419
- export interface MangaPlansResponse {
420
- plans: MangaPlan[]
421
- }
422
-
423
- /** 漫剧角色卡:制作角色(要建模/出图/锁一致性的「上镜角色」),与小说角色库弱关联。 */
424
- export interface MangaRoleCard {
425
- /** 稳定 id。 */
426
- id: string
427
- /** 来源小说角色名(只读追溯,非强外键;禁止反向写回小说库)。 */
428
- sourceRoleName?: string
429
- /** 漫剧用名(可短剧化改名)。 */
430
- name: string
431
- /** 身份一句话。 */
432
- identity: string
433
- /** 核心功能:主角/导师/感情线/反派/搭档/线人/功能性。 */
434
- coreFunction: 'protagonist' | 'mentor' | 'love_interest' | 'antagonist' | 'sidekick' | 'informant' | 'functional'
435
- /** 与主角的关系。 */
436
- protagonistRelation: 'enemy' | 'friend' | 'mentor' | 'lover' | 'exploit' | 'neutral'
437
- /** 口头禅/说话方式(配音一致性)。 */
438
- speechStyle: string
439
- /** ≤3 个极致性格标签。 */
440
- traits: string[]
441
- /** 1-2 个辨识度外貌点。 */
442
- appearance: string
443
- /** 3-5 个关键剧情节点。 */
444
- keyScenes: string[]
445
- /** 上场集数(分镜提名导入时记录)。 */
446
- appearsInEpisodes: number[]
447
- /** 待匹配 → 待确认 → 已导入 → 已定妆 → 已归档。 */
448
- status: 'pending_match' | 'pending_confirm' | 'imported' | 'anchored' | 'archived'
449
- /** 形象资产(沿用小说角色库同款结构)。 */
450
- imagePrompt?: RoleRecord['imagePrompt']
451
- /** 情绪表情清单(锚点提炼时产出)。 */
452
- expressions?: string[]
453
- /** 四类精修生图提示词(立绘/四视图/表情/细节)。 */
454
- promptKit?: RoleRecord['promptKit']
455
- /** 角色参考图。 */
456
- imageUrl?: string
457
- /** 图集(图像锚点)。 */
458
- gallery?: RoleImage[]
459
- /** 生成锚点/精修时的方案风格 id(旧风格检测用)。 */
460
- promptStyleId?: string
461
- createdAt: string
462
- updatedAt: string
463
- }
464
-
465
- /** 分镜提名 → 小说角色库匹配的一条候选。 */
466
- export interface MangaRoleCandidate {
467
- /** 分镜里的原始称谓(正文确切用法)。 */
468
- rawName: string
469
- /** matched=命中小说角色;ambiguous=多个候选待定;not_in_library=小说库没有;already_imported=已建漫剧卡(跳过)。 */
470
- verdict: 'matched' | 'ambiguous' | 'not_in_library' | 'already_imported'
471
- /** 规则阶段候选短名单(≤5,精确名优先 + 身份/简称匹配)。 */
472
- matches: Array<{ roleName: string; reason: string }>
473
- /** LLM/规则确认的命中角色名(ambiguous 时可能为空)。 */
474
- matchedRoleName?: string
475
- /** not_in_library 时给出建议:backfill=正文有该称谓但小说库漏提炼(回小说库补);manga_new=漫剧新增角色(直接建卡)。 */
476
- novelHint?: 'backfill' | 'manga_new'
477
- /** 采纳时预填的漫剧卡建议。 */
478
- suggested: {
479
- name: string
480
- identity: string
481
- coreFunction: MangaRoleCard['coreFunction']
482
- protagonistRelation: MangaRoleCard['protagonistRelation']
483
- speechStyle: string
484
- traits: string[]
485
- appearance: string
486
- keyScenes: string[]
487
- }
488
- }
489
-
490
- /** POST /manga/roles 请求:漫剧角色库操作。 */
491
- export interface MangaRolesRequest {
492
- op: 'nominate' | 'adopt' | 'update' | 'remove' | 'visual' | 'promptKit' | 'image' | 'removeImage' | 'imageGenerate' | 'mode'
493
- /** op='mode':短剧精简模式开关。 */
494
- shortDramaMode?: boolean
495
- /** op='nominate':从哪章分镜提名角色。 */
496
- chapterNo?: number
497
- /** op='adopt' / op='update':漫剧角色卡。 */
498
- card?: MangaRoleCard
499
- /** op='remove' / 'visual' / 'promptKit' / 'image' / 'removeImage' / 'imageGenerate':漫剧卡 id。 */
500
- id?: string
501
- /** op='visual' / 'promptKit':漫剧方案基底风格 id。 */
502
- styleId?: string
503
- /** 可选滤镜风格 id。 */
504
- filterId?: string
505
- /** op='image':定妆图 dataURL。 */
506
- dataUrl?: string
507
- /** op='image':图集用途标签(立绘/四视图/表情-x/场景/细节);缺省视为角色参考图(imageUrl)。 */
508
- label?: string
509
- /** op='imageGenerate':漫画风格预设 id(可选)。 */
510
- style?: string
511
- /** op='imageGenerate':生图模型库条目 id(缺省用启用条目)。 */
512
- modelId?: string
513
- }
514
-
515
- /** POST /manga/roles 响应。 */
516
- export interface MangaRolesResponse {
517
- cards: MangaRoleCard[]
518
- /** op='nominate' 时的 AI 提名候选。 */
519
- candidates?: MangaRoleCandidate[]
520
- /** op='visual' 时的形象锚点(已写入漫剧卡)。 */
521
- visual?: RoleRecord['imagePrompt']
522
- /** op='promptKit' 时的四类精修提示词包(已写入漫剧卡)。 */
523
- promptKit?: RoleRecord['promptKit']
524
- /** op='image' / 'imageGenerate' 时的定妆图 dataURL(已写入漫剧卡)。 */
525
- imageUrl?: string
526
- /** op='mode' 时的短剧精简模式状态。 */
527
- shortDramaMode?: boolean
528
- }
529
-
530
-
531
- /** Chapter lifecycle states (the writing pipeline's state machine). */
532
- export type ChapterStatus =
533
- | 'pending' // planned, not started
534
- | 'generating' // LLM writing right now
535
- | 'written' // body on disk, awaiting review
536
- | 'reviewing' // review in progress
537
- | 'approved' // passed review (or user-approved)
538
- | 'rejected' // review found problems
539
- | 'error' // generation failed
540
-
541
- /** One chapter in the plan. */
542
- export interface ChapterPlan {
543
- /** 1-based chapter number (stable identity; files are named from it). */
544
- no: number
545
- /** Volume this chapter belongs to (1-based; 0 = unassigned). */
546
- volume: number
547
- /** Chapter title, decided by the LLM plan step. */
548
- title: string
549
- /** Story beats / plot points for this chapter (model-facing guidance). */
550
- beats: string
551
- /** Target character count (defaults to the configured chapter size). */
552
- targetChars: number
553
- /** Generation/review state. */
554
- status: ChapterStatus
555
- /** 进入 generating 的时间(用于超时自动复位;未在生成时无此字段)。 */
556
- generatingAt?: string
557
- /** Actual character count once generated. */
558
- chars?: number
559
- /** Failure message when status is 'error'. */
560
- error?: string
561
- /** Output file name once generated (relative to the output dir). */
562
- file?: string
563
- /** LLM summary of the chapter (narrative memory for later chapters). */
564
- summary?: string
565
- /** Latest review report (present once reviewed). */
566
- review?: ReviewReport
567
- /** 作者复盘:钩子兑现/结尾钩子/剧情线推进/连续性/节奏趋势(生成后自动)。 */
568
- authorReview?: AuthorReview
569
- /**
570
- * 待确认草稿:润色(去AI味)或整章重写的产物正文。生成时先存这里,
571
- * 用户看过对比后点「采纳」才覆盖正文文件;点「放弃」则丢弃。刷新页面不丢失。
572
- */
573
- pendingDraft?: string
574
- }
575
-
576
- /** 作者复盘:叙事结构层面的逐章检查(钩子/推进/连续性/趋势)。 */
577
- export interface AuthorReview {
578
- /** 上一章结尾钩子是否在本章兑现。 */
579
- hookHonored: boolean
580
- /** 钩子兑现说明(未兑现时给出建议)。 */
581
- hookNote: string
582
- /** 本章结尾钩子强度 0-10。 */
583
- endingHook: number
584
- /** 剧情线推进情况(推进了哪条线/或未推进)。 */
585
- plotlineProgress: string
586
- /** 结构化:本章推进的剧情线名称列表(与项目剧情线 name 精确匹配,复盘后自动关联章节)。 */
587
- advancedLines?: string[]
588
- /** 连续性检查(人物位置/时间/伤势/资源是否与上章衔接)。 */
589
- continuity: string
590
- /** 近期节奏趋势提示(拖沓/爽点密度等)。 */
591
- trend: string
592
- /** 复盘时间。 */
593
- reviewedAt: string
594
- }
595
-
596
- /** One review finding. */
597
- export interface ReviewIssue {
598
- /** Severity: high = must fix, medium = should fix, low = suggestion. */
599
- severity: 'high' | 'medium' | 'low'
600
- /** What the problem is. */
601
- item: string
602
- /** Concrete suggestion for fixing it. */
603
- suggestion: string
604
- }
605
-
606
- /** AI review report for one chapter. */
607
- export interface ReviewReport {
608
- /** Overall score 0-100. */
609
- score: number
610
- /** Pass threshold (config; 70 default). */
611
- passed: boolean
612
- /** One-line verdict. */
613
- verdict: string
614
- /** Individual findings. */
615
- issues: ReviewIssue[]
616
- /** When the review ran. */
617
- reviewedAt: string
618
- }
619
-
620
- /** A volume of the book. */
621
- export interface Volume {
622
- /** 1-based volume number. */
623
- no: number
624
- /** Volume title. */
625
- title: string
626
- /** Volume positioning / summary. */
627
- summary: string
628
- /** First chapter number of this volume. */
629
- chapterStart: number
630
- /** Last chapter number (inclusive). */
631
- chapterEnd: number
632
- }
633
-
634
- /** A character card from the story bible. */
635
- export interface CharacterCard {
636
- name: string
637
- role: 'protagonist' | 'supporting' | 'antagonist' | 'other'
638
- /** Personality / traits (short lines). */
639
- traits: string[]
640
- /** Goals and motivations. */
641
- goals: string
642
- /** Key relations to other characters. */
643
- relations: string
644
- /** 知情度:该角色已经知道的事实/秘密(未列出的信息该角色不知道)。 */
645
- knowledge?: string[]
646
- }
647
-
648
- /** The structured story bible (worldbuilding extracted from the outline). */
649
- export interface StoryBible {
650
- /** Genre + tone tags. */
651
- genre: string
652
- /** Worldbuilding rules (power system, geography, factions...). */
653
- worldRules: string[]
654
- /** Character cards. */
655
- characters: CharacterCard[]
656
- /** Writing red lines (forbidden content / must-avoid tropes). */
657
- redLines: string[]
658
- /** Style guidance (pacing, pov, tone). */
659
- style: string[]
660
- /** When the bible was generated. */
661
- generatedAt?: string
662
- }
663
-
664
- /** A planted/active/resolved foreshadowing thread. */
665
- export interface Foreshadow {
666
- /** Stable id. */
667
- id: string
668
- /** What the foreshadow is. */
669
- description: string
670
- /** Chapter where it was planted (undefined = planned). */
671
- plantedChapter?: number
672
- /** Chapter where it should be paid off. */
673
- targetChapter?: number
674
- /** Lifecycle state. */
675
- status: 'planned' | 'planted' | 'progressing' | 'resolved' | 'abandoned'
676
- /** Resolution note when resolved. */
677
- resolvedNote?: string
678
- }
679
-
680
- /** 一条已确立的叙事事实(事实库/时间线,注入后续章节生成)。 */
681
- export interface ChapterFact {
682
- /** 来源章节号。 */
683
- chapterNo: number
684
- /** 事实文本(人物状态/境界资源/关系变化/伏笔落地等)。 */
685
- text: string
686
- }
687
-
688
- /** 一条全书质检发现的问题(一致性矛盾,定位到章)。 */
689
- export interface AuditIssue {
690
- /** 问题所在章节号(无法定位时 0)。 */
691
- chapterNo: number
692
- severity: 'high' | 'medium' | 'low'
693
- /** 矛盾描述。 */
694
- item: string
695
- /** 修改建议。 */
696
- suggestion: string
697
- }
698
-
699
- /** POST /audit 响应。 */
700
- export interface AuditResponse {
701
- issues: AuditIssue[]
702
- /** 参与质检的章节数。 */
703
- auditedChapters: number
704
- /** 质检时间。 */
705
- auditedAt: string
706
- }
707
-
708
- /** 全书质检的实时状态(通过 /status 暴露给面板/外部读取)。 */
709
- export interface AuditStatus {
710
- status: 'idle' | 'running' | 'done' | 'error'
711
- /** 开始时间(ISO)。 */
712
- startedAt?: string
713
- /** 结束时间(ISO)。 */
714
- finishedAt?: string
715
- /** 总批次数(0 = 尚未开始/无章节)。 */
716
- totalBatches: number
717
- /** 已完成批次数。 */
718
- completedBatches: number
719
- /** 参与质检的章节数。 */
720
- auditedChapters?: number
721
- /** 发现的问题数(done 后有效)。 */
722
- issuesCount?: number
723
- /** 最近一次质检的问题清单(done 后有效;error 时为空)。 */
724
- issues?: AuditIssue[]
725
- /** 失败信息(error 时有效)。 */
726
- error?: string
727
- }
728
-
729
- /** 一条剧情线(主线/支线/人物线/悬念线)。 */
730
- export interface Plotline {
731
- /** 稳定 id。 */
732
- id: string
733
- /** 线名。 */
734
- name: string
735
- /** 类型:主线 / 支线 / 人物线 / 悬念线。 */
736
- kind: 'main' | 'branch' | 'character' | 'mystery'
737
- /** 目标/终点(这条线最终要完成什么)。 */
738
- goal: string
739
- /** 当前进度说明(最近推进到哪)。 */
740
- progress: string
741
- /** 生命周期状态。 */
742
- status: 'active' | 'paused' | 'resolved' | 'abandoned'
743
- /** 关联章节号(推进/落地的章节)。 */
744
- chapters: number[]
745
- /** 创建时间。 */
746
- createdAt: string
747
- }
748
-
749
- /** POST /plotlines 请求:剧情线增删改 + 关联章节 + AI 辅助。 */
750
- export interface PlotlinesRequest {
751
- op: 'add' | 'update' | 'remove' | 'link' | 'suggest' | 'refresh' | 'health' | 'plan'
752
- /** add / update 时传入的完整剧情线。 */
753
- line?: Plotline
754
- /** remove / link / refresh 时的目标线 id。 */
755
- id?: string
756
- /** link 时关联的章节号。 */
757
- chapterNo?: number
758
- }
759
-
760
- /** 剧情线健康检查报告。 */
761
- export interface PlotlineHealthReport {
762
- /** 是否需要新线(需要 / 暂不需要 / 再写 X 章后需要)。 */
763
- verdict: string
764
- /** 建议添加新线的时机说明。 */
765
- timing: string
766
- /** 依据(基于数据的理由,每条一句)。 */
767
- reasons: string[]
768
- /** 各线健康度。 */
769
- lines: Array<{
770
- name: string
771
- /** ok=健康 / warning=预警 / stale=搁置过久。 */
772
- health: 'ok' | 'warning' | 'stale'
773
- note: string
774
- }>
775
- }
776
-
777
- /** AI 剧情方案:下一阶段目标 + 建议新线。 */
778
- export interface PlotlinePlan {
779
- /** 下一阶段(未来 5-10 章)剧情方向。 */
780
- direction: string
781
- /** 建议的新线(可逐条采纳)。 */
782
- suggestions: Plotline[]
783
- }
784
-
785
- /** POST /plotlines 响应。 */
786
- export interface PlotlinesResponse {
787
- plotlines: Plotline[]
788
- /** op=suggest 时的 AI 建议候选线。 */
789
- suggestions?: Plotline[]
790
- /** op=health 时的健康检查报告。 */
791
- health?: PlotlineHealthReport
792
- /** op=plan 时的剧情方案。 */
793
- plan?: PlotlinePlan
794
- }
795
-
796
- /** 一条敏感词命中。 */
797
- export interface SensitiveHit {
798
- /** 命中章节号(文本检测时为 0)。 */
799
- chapterNo: number
800
- /** 命中的违禁词。 */
801
- word: string
802
- /** 类别:政治 / 擦边 / 暴力 / 辱骂 / 广告 / 其他。 */
803
- category: string
804
- /** 出现次数。 */
805
- count: number
806
- }
807
-
808
- /** POST /sensitive-check 请求:检测指定章节/任意文本/全书。 */
809
- export interface SensitiveCheckRequest {
810
- /** 检测该章正文。 */
811
- chapterNo?: number
812
- /** 检测任意文本(优先于 chapterNo)。 */
813
- text?: string
814
- /** 扫描全部已写章节。 */
815
- all?: boolean
816
- }
817
-
818
- /** POST /sensitive-check 响应。 */
819
- export interface SensitiveCheckResponse {
820
- hits: SensitiveHit[]
821
- /** 参与扫描的章节数。 */
822
- scannedChapters: number
823
- }
824
-
825
- /** 开书想法 → AI 大纲方案(一个候选)。 */
826
- export interface OutlineCandidate {
827
- /** 唯一 id(前端暂留/换批用)。 */
828
- id: string
829
- /** 推荐书名。 */
830
- bookName: string
831
- /** 题材(如 仙侠修真 / 都市)。 */
832
- genre: string
833
- /** 核心卖点一句话。 */
834
- sellingPoint: string
835
- /** 完整大纲文本(可直接用作项目大纲,≥800 字)。 */
836
- outline: string
837
- }
838
-
839
- /** POST /outline/suggest 请求:想法 → 2-3 个可选大纲。 */
840
- export interface OutlineSuggestRequest {
841
- /** 作者想法(一两句话,≥50 字)。 */
842
- idea: string
843
- /** 本次要生成的候选数(默认 3,最多 3)。 */
844
- count?: number
845
- /** 已暂留方案的剧情方向摘要(换批时让 LLM 避开,防止与已留方案重复)。 */
846
- exclude?: string[]
847
- }
848
-
849
- /** POST /outline/suggest 响应。 */
850
- export interface OutlineSuggestResponse {
851
- candidates: OutlineCandidate[]
852
- }
853
-
854
- /** 拆书分析:一个分析小节。 */
855
- export interface BreakdownSection {
856
- /** 小节键:overview / plot / character / style / market。 */
857
- key: string
858
- /** 小节标题(如「拆书总览」)。 */
859
- title: string
860
- /** 可读分析稿(markdown)。 */
861
- markdown: string
862
- /** 结构化数据(程序可消费)。 */
863
- structured: Record<string, unknown>
864
- }
865
-
866
- /** 拆书分析:一条证据(结论→原文回溯)。 */
867
- export interface BreakdownEvidence {
868
- label: string
869
- excerpt: string
870
- /** 来源章节号(0 = 未定位)。 */
871
- chapterNo: number
872
- /** 指向的结构化字段。 */
873
- fieldKey?: string
874
- }
875
-
876
- /** POST /breakdown 请求:对已写章节做拆书分析。 */
877
- export interface BreakdownRequest {
878
- /** 分析范围:'recent'=最近 20 章 / 'volume:N'=第 N 卷 / 'all'=全书(默认 recent)。 */
879
- scope?: string
880
- /** 分析档位:'quick'=4 维(总览/剧情/人物/文风)/ 'standard'=5 维(+卖点)。 */
881
- preset?: 'quick' | 'standard'
882
- /** token 预算上限(默认 50000)。 */
883
- budgetTokens?: number
884
- }
885
-
886
- /** POST /breakdown 响应。 */
887
- export interface BreakdownResponse {
888
- sections: BreakdownSection[]
889
- evidence: BreakdownEvidence[]
890
- /** 参与分析的章节数。 */
891
- chaptersScanned: number
892
- /** 估算消耗 token。 */
893
- usedTokens: number
894
- }
895
-
896
- /** 角色卡:角色当前状态(从事实库聚合)。 */
897
- export interface RoleStatusCard {
898
- name: string
899
- /** protagonist / supporting / antagonist / other。 */
900
- role: string
901
- /** 当前状态一句话(境界/资源/伤势/心境)。 */
902
- status: string
903
- /** 最近出场章节。 */
904
- lastChapter: number
905
- /** 出场次数。 */
906
- appearances: number
907
- }
908
-
909
- /** 角色库条目(主表:作者维护 + AI 提炼 + 编年录自动聚合)。 */
910
- export interface RoleRecord {
911
- /** 角色名(唯一键)。 */
912
- name: string
913
- /** 定位:主角 / 女主 / 女配 / 配角 / 反派 / 路人。 */
914
- roleLabel: 'protagonist' | 'female_lead' | 'female_support' | 'support' | 'antagonist' | 'extra'
915
- /** 身份一句话(如:祭族后裔、青云宗杂役)。 */
916
- identity: string
917
- /** 性格标签。 */
918
- traits: string[]
919
- /** 目标与动机。 */
920
- goals: string
921
- /** 关系网:[角色名](关系)。 */
922
- relations: string[]
923
- /** 成长线:阶段 → 说明(可含章节)。 */
924
- arc: string[]
925
- /** 知情度:该角色已经知道的信息。 */
926
- knowledge: string[]
927
- /** 首次出场章节(编年录聚合,可手动修正)。 */
928
- firstChapter?: number
929
- /** 动漫形象描述词(AI 绘图用:中文描述 + 英文标签 + 关键外貌标签)。 */
930
- imagePrompt?: {
931
- /** 中文外貌描述:连贯一段(发色/瞳色/服装/气质/标志物)。 */
932
- zh: string
933
- /** 英文绘图标签:booru 风格逗号分隔。 */
934
- en: string
935
- /** 中文关键标签(发色/瞳色/服装/气质/标志物)。 */
936
- tags: string[]
937
- /** 依据来源说明(哪几章哪些描写)。 */
938
- source?: string
939
- }
940
- /** 角色参考图(dataURL 或 URL)。用于漫画/漫剧出图时锁定角色一致性。 */
941
- imageUrl?: string
942
- /** 角色图集(图像锚点):立绘/四视图/表情/场景/细节等,label 标注用途。 */
943
- gallery?: RoleImage[]
944
- /** 该角色所需的情绪表情清单(提炼时 LLM 补全 6-12 个,如"疲惫/麻木/压抑悲伤")。 */
945
- expressions?: string[]
946
- /** LLM 精修的四类生图提示词包(前端拼装版之外的高质量版,promptKit 接口生成)。 */
947
- promptKit?: {
948
- /** 立绘:全身/半身正视图。 */
949
- portrait: { zh: string; en: string }
950
- /** 四视图:正面/侧面/背面设定表。 */
951
- sheet: { zh: string; en: string }
952
- /** 表情:同一脸部锚换情绪,每表情一段。 */
953
- expressions: { name: string; zh: string; en: string }[]
954
- /** 细节:标志物局部特写。 */
955
- details: { zh: string; en: string }
956
- }
957
- /** 生成形象锚点/精修提示词时的漫剧方案基底风格 id(= 方案 styleId;用于检测旧风格并提示重生成)。 */
958
- promptStyleId?: string
959
- /** 漫画/漫剧重要性:main=必须建卡保证一致;support=有锚点即可;extra=路人随机生成不约束。 */
960
- importance?: 'main' | 'support' | 'extra'
961
- }
962
-
963
- /** 角色图集条目:一张已定型的角色图(图像锚点)。 */
964
- export interface RoleImage {
965
- /** 用途标签:立绘 / 四视图 / 表情-疲惫 / 场景 / 细节 等。 */
966
- label: string
967
- /** dataURL 或 URL。 */
968
- dataUrl: string
969
- }
970
-
971
- /** 场景库条目:从正文提炼的「镜头场景」视觉锚点(漫剧分镜/生图用)。 */
972
- export interface SceneCard {
973
- /** 场景名(唯一键),如「旧茶渡·地下石殿」。 */
974
- name: string
975
- /** 一句话定位:空间/氛围/功能。 */
976
- summary: string
977
- /** 幕归属:第一幕·后场 / 第二幕·卖场 / …(便于按剧情段落组织)。 */
978
- act?: string
979
- /** 时间光态:夜间闭店后 / 雨夜 / 凌晨 / 频闪灯… */
980
- moment?: string
981
- /** 关键情节镜头 1-3 条:该场景拍什么(人物动作+情绪+镜头推进)。 */
982
- beats?: string[]
983
- /** 人物在场状态:主角/关键角色在该场景的状态一句话。 */
984
- characterState?: string
985
- /** 环境构成:空间结构/陈设/标志物。 */
986
- elements: string[]
987
- /** 色调与光影(含 HEX 色板,可空)。 */
988
- palette: string[]
989
- /** 氛围关键词:压抑/神秘/空旷… */
990
- moods: string[]
991
- /** 中文生图提示词(连贯一段,写实电影感)。 */
992
- zh: string
993
- /** 英文生图提示词(逗号分隔标签)。 */
994
- en: string
995
- /** 关键标签。 */
996
- tags: string[]
997
- /** 依据来源(哪几章哪些描写)。 */
998
- source?: string
999
- /** 场景图集(图像锚点):全景/局部/氛围 等。 */
1000
- gallery?: RoleImage[]
1001
- /** 生成时的漫剧方案基底风格 id(场景卡随方案风格措辞)。 */
1002
- styleId?: string
1003
- }
1004
-
1005
- /** POST /scenes 请求:场景库提炼 / 采纳 / 更新 / 删除 / 图集。 */
1006
- export interface ScenesRequest {
1007
- op: 'extract' | 'adopt' | 'update' | 'remove' | 'image' | 'removeImage'
1008
- /** op='extract' 时的漫剧基底风格 id(场景卡按方案风格措辞)。 */
1009
- styleId?: string
1010
- /** op='extract' 时的可选滤镜风格 id。 */
1011
- filterId?: string
1012
- /** adopt / update 时传入的场景卡(adopt 可修改后采纳)。 */
1013
- scene?: SceneCard
1014
- /** remove / image 时的场景名。 */
1015
- name?: string
1016
- /** op='image' 时的图片 dataURL 与用途标签(全景/局部/氛围)。 */
1017
- dataUrl?: string
1018
- label?: string
1019
- }
1020
-
1021
- /** POST /visual-rules 请求:视觉世界观规则提炼 / 保存。 */
1022
- export interface VisualRulesRequest {
1023
- op: 'extract' | 'save'
1024
- /** op=save 时的规则数组。 */
1025
- rules?: string[]
1026
- }
1027
-
1028
- /** POST /visual-rules 响应。 */
1029
- export interface VisualRulesResponse {
1030
- rules: string[]
1031
- }
1032
-
1033
- /** POST /scenes 响应。 */
1034
- export interface ScenesResponse {
1035
- scenes: SceneCard[]
1036
- /** op=extract 时的 AI 候选场景。 */
1037
- candidates?: SceneCard[]
1038
- }
1039
-
1040
- /** POST /roles 请求:角色库增删改 + AI 提炼 + 参考图上传。 */
1041
- export interface RolesRequest {
1042
- op: 'extract' | 'adopt' | 'update' | 'remove' | 'visual' | 'image' | 'removeImage' | 'imageGenerate' | 'promptKit'
1043
- /** adopt / update 时传入的角色(adopt 可修改后采纳)。 */
1044
- role?: RoleRecord
1045
- /** remove 时的角色名。 */
1046
- name?: string
1047
- /** op='image' 时的参考图 dataURL。 */
1048
- dataUrl?: string
1049
- /** op='image' 时的图集用途标签(立绘/四视图/表情-x/场景/细节);缺省视为角色参考图(imageUrl)。 */
1050
- label?: string
1051
- /** op='imageGenerate' 时的漫画风格预设 id(用于统一角色图与漫画页风格)。 */
1052
- style?: string
1053
- /** op='imageGenerate' 时指定生图模型库条目 id(缺省用启用条目)。 */
1054
- modelId?: string
1055
- /** op='visual' / op='promptKit' 时的漫剧基底风格 id(角色图按方案风格重出)。 */
1056
- styleId?: string
1057
- /** op='visual' / op='promptKit' 时的可选滤镜风格 id。 */
1058
- filterId?: string
1059
- }
1060
-
1061
- /** POST /image-test 请求:测一个生图接口的连通性与延迟(不落盘)。 */
1062
- export interface ImageTestRequest {
1063
- /** OpenAI 兼容生图接口地址。 */
1064
- baseURL: string
1065
- /** API Key。 */
1066
- apiKey: string
1067
- /** 模型 id(顺带校验是否在接口模型列表里,可选)。 */
1068
- model?: string
1069
- }
1070
-
1071
- /** POST /image-test 响应。 */
1072
- export interface ImageTestResponse {
1073
- ok: boolean
1074
- /** 连通延迟(毫秒)。 */
1075
- ms?: number
1076
- /** 失败原因。 */
1077
- message?: string
1078
- /** 模型 id 是否出现在接口的模型列表(探测成功时才有)。 */
1079
- modelFound?: boolean
1080
- }
1081
-
1082
- /** POST /llm-test 请求:对选中的提供商/模型发一次最小真实调用。 */
1083
- export interface LlmTestRequest {
1084
- provider: string
1085
- model: string
1086
- }
1087
-
1088
- /** POST /llm-test 响应。 */
1089
- export interface LlmTestResponse {
1090
- ok: boolean
1091
- /** 连通延迟(毫秒)。 */
1092
- ms?: number
1093
- /** 失败原因(已映射为人话)。 */
1094
- message?: string
1095
- /** 稳定错误码(LlmError code),便于排查。 */
1096
- code?: string
1097
- }
1098
-
1099
- /** POST /roles 响应。 */
1100
- export interface RolesResponse {
1101
- roles: RoleRecord[]
1102
- /** op=extract 时的 AI 候选角色。 */
1103
- candidates?: RoleRecord[]
1104
- /** op=visual 时的动漫形象描述词(已写入角色卡)。 */
1105
- visual?: RoleRecord['imagePrompt']
1106
- /** op=promptKit 时的四类提示词精修包(已写入角色卡)。 */
1107
- promptKit?: RoleRecord['promptKit']
1108
- /** op=image 时的角色参考图 dataURL。 */
1109
- imageUrl?: string
1110
- }
1111
-
1112
- /** POST /bible/patch 请求:局部修补设定圣经。 */
1113
- export interface BiblePatchRequest {
1114
- worldRules?: string[]
1115
- redLines?: string[]
1116
- style?: string[]
1117
- /** 角色卡整体替换(人物志编辑知情度等)。 */
1118
- characters?: CharacterCard[]
1119
- }
1120
-
1121
- /** POST /blurb 请求:AI 生成/补全或手动保存小说简介。 */
1122
- export interface BlurbRequest {
1123
- action: 'generate' | 'save'
1124
- /** 已写好的开头(AI 补全时使用;留空 = 全量生成)。 */
1125
- partial?: string
1126
- /** 手动保存的完整简介(action=save 时)。 */
1127
- text?: string
1128
- }
1129
-
1130
- /** POST /chapter/check|save 请求:审查/保存手动编辑的正文。 */
1131
- export interface ChapterTextRequest {
1132
- chapterNo: number
1133
- /** 当前编辑中的正文全文。 */
1134
- text: string
1135
- /** 保存时携带:已在工作区审查过的报告(沿用落盘,不重复审);缺省则保存后自动正式审稿一次。 */
1136
- report?: ReviewReport
1137
- /** 审查/验证时携带:上一轮审稿报告。传入后进入「验证模式」——逐条核对原意见是否解决、
1138
- * 只挑新增 high,不再全新找茬(防止"越修 high 越多")。 */
1139
- previousReport?: ReviewReport
1140
- }
1141
-
1142
- /** POST /chapter/save 响应。 */
1143
- export interface ChapterSaveResponse {
1144
- ok: boolean
1145
- chars: number
1146
- file: string
1147
- /** 落盘的审稿报告(沿用工作区报告或保存后自动审稿)。 */
1148
- report?: ReviewReport
1149
- }
1150
-
1151
- /** POST /cover 请求:上传或移除封面。 */
1152
- export interface CoverRequest {
1153
- action: 'upload' | 'remove'
1154
- /** 上传时:data:image/...;base64,... 格式的图片数据。 */
1155
- dataUrl?: string
1156
- }
1157
-
1158
- /** POST /rename 请求:重命名当前书。 */
1159
- export interface RenameRequest {
1160
- bookName: string
1161
- }
1162
-
1163
- /** 大世界:一个境界等级。 */
1164
- export interface WorldRealm {
1165
- /** 境界名(练气/筑基/金丹…)。 */
1166
- name: string
1167
- /** 描述:突破条件/寿命/标志等。 */
1168
- description: string
1169
- }
1170
-
1171
- /** 大世界:一个地理区域。 */
1172
- export interface WorldRegion {
1173
- name: string
1174
- description: string
1175
- /** 关联势力名(可空)。 */
1176
- faction?: string
1177
- }
1178
-
1179
- /** 大世界:一方势力。 */
1180
- export interface WorldFaction {
1181
- name: string
1182
- /** 类型:宗门/家族/王朝/组织… */
1183
- kind: string
1184
- description: string
1185
- /** 驻地区域(可空)。 */
1186
- region?: string
1187
- }
1188
-
1189
- /** 大世界结构化数据。 */
1190
- export interface WorldState {
1191
- realms: WorldRealm[]
1192
- regions: WorldRegion[]
1193
- factions: WorldFaction[]
1194
- }
1195
-
1196
- /** POST /world 请求:AI 提炼或手动保存。 */
1197
- export interface WorldRequest {
1198
- action: 'generate' | 'save'
1199
- /** action=save 时的完整世界数据。 */
1200
- world?: WorldState
1201
- }
1202
-
1203
- /** GET /cover 响应:封面的 dataUrl(无封面为 null)。 */
1204
- export interface CoverResponse {
1205
- dataUrl: string | null
1206
- }
1207
-
1208
- /** The persisted project: outline + bible + plan + progress. */
1209
- export interface ProjectState {
1210
- /** Book title (first non-empty line of the outline, usually). */
1211
- bookName: string
1212
- /** Full outline text (docx-extracted or pasted). */
1213
- outline: string
1214
- /** Source outline path when loaded from a docx. */
1215
- outlinePath?: string
1216
- /** Structured story bible (worldbuilding), if generated. */
1217
- bible?: StoryBible
1218
- /** Volumes, if planned. */
1219
- volumes?: Volume[]
1220
- /** Chapter plan. */
1221
- chapters: ChapterPlan[]
1222
- /** Foreshadowing threads. */
1223
- foreshadows: Foreshadow[]
1224
- /** 写作资产(题材基底/推进模式/反AI规则/写法资产)。 */
1225
- assets?: ProjectAssets
1226
- /** 事实库/时间线:每章生成后抽取,注入后续章节保持一致性。 */
1227
- facts?: ChapterFact[]
1228
- /** 小说简介(面向读者的作品门面,AI 生成或手动保存)。 */
1229
- blurb?: string
1230
- /** 封面文件名(相对输出目录,如 cover.png)。 */
1231
- coverPath?: string
1232
- /** 大世界结构化数据(境界体系/区域/势力)。 */
1233
- world?: WorldState
1234
- /** 剧情线(主线/支线/人物线/悬念线)。 */
1235
- plotlines?: Plotline[]
1236
- /** 角色库(作者维护 + AI 提炼的主表)。 */
1237
- roles?: RoleRecord[]
1238
- /** 漫剧角色库(制作角色投影:从分镜提名导入,独立于小说角色库)。 */
1239
- mangaRoles?: MangaRoleCard[]
1240
- /** 短剧精简模式:漫剧角色库按 5-8 上镜角色 / 功能标签 / 关系闭环 / 人设极致化约束。 */
1241
- shortDramaMode?: boolean
1242
- /** 场景库(作者维护 + AI 提炼的主表)。 */
1243
- scenes?: SceneCard[]
1244
- /** 视觉世界观规则(生图/生视频必须遵守,从道藏提炼,注入所有提示词)。 */
1245
- visualRules?: string[]
1246
- /** 分镜工作台产出(骨架/分镜表,按章持久化,刷新/切换不丢)。 */
1247
- storyboards?: ChapterStoryboard[]
1248
- /** 漫剧方案列表(同一本书的多套视觉演绎:基底风格 + 可选滤镜)。 */
1249
- mangaPlans?: MangaPlan[]
1250
- /** 人物志:角色当前状态聚合结果(从编年录刷新后存档,打开页面直接显示)。 */
1251
- roleStatus?: RoleStatusCard[]
1252
- /** 漫剧分镜结果缓存:章号 → 分镜(持久化,刷新不丢)。 */
1253
- /** 漫剧分集计划缓存:卷号/0=全书 → 分集计划(持久化,刷新不丢)。 */
1254
- /** 漫画脚本缓存:章号 → 漫画脚本(持久化,刷新不丢)。 */
1255
- /** ISO timestamps. */
1256
- createdAt: string
1257
- updatedAt: string
1258
- }
1259
-
1260
- /** 生图模型配置(模型库条目,可多套并存,启用一条生效)。 */
1261
- export interface ImageModelConfig {
1262
- /** 条目 id(本地唯一)。 */
1263
- id: string
1264
- /** 展示名(如「豆包 Seedream」「即梦」)。 */
1265
- name: string
1266
- /** OpenAI 兼容生图接口地址(如 https://ark.cn-beijing.volces.com/api/v3)。 */
1267
- baseURL: string
1268
- /** API Key。 */
1269
- apiKey: string
1270
- /** 生图模型 id(如 doubao-seedream-5-0-pro-260628)。 */
1271
- model: string
1272
- /** 是否启用(同时只启用一条)。 */
1273
- enabled: boolean
1274
- }
1275
-
1276
- /** Runtime config surface exposed to the panel (subset of plugin Config). */
1277
- /** 手动添加的模型库条目(只存插件内,不改 DSH 全局)。 */
1278
- export interface SavedModel {
1279
- /** 唯一 id(前端生成的短 id)。 */
1280
- id: string
1281
- /** 展示名(可为空,回退到 model)。 */
1282
- name: string
1283
- /** DSH 提供商路由(如 zai-coding-cn)。 */
1284
- provider: string
1285
- /** 模型 id(如 glm-5.3-flash)。 */
1286
- model: string
1287
- }
1288
-
1289
- /** DSH 模型添加:厂商预设(选择厂商,直接填 API Key)。 */
1290
- export interface LlmVendor {
1291
- id: string
1292
- name: string
1293
- /** 该厂商对应的 provider 路由。 */
1294
- route: string
1295
- /** DSH 凭据引用名(写入 .credentials.yaml 的 refs)。 */
1296
- apiKeyEnv: string
1297
- /** 默认模型 id。 */
1298
- defaultModel: string
1299
- /** 建议可选模型 id 列表(下拉 data-list 用)。 */
1300
- models: string[]
1301
- /** 内置适配器(如 deepseek-official),无需注册 pi-ai 路由。 */
1302
- builtin?: boolean
1303
- }
1304
-
1305
- /** 预置的常见厂商(id=provider 路由;添加模型下拉兜底用,其余厂商由运行时目录动态补充)。 */
1306
- export const LLM_VENDORS: LlmVendor[] = [
1307
- { id: 'deepseek-official', name: 'DeepSeek', route: 'deepseek-official', apiKeyEnv: 'DEEPSEEK_API_KEY', defaultModel: 'deepseek-v4-flash', models: ['deepseek-v4-flash', 'deepseek-v4-pro', 'deepseek-chat', 'deepseek-reasoner'], builtin: true },
1308
- { id: 'zai-coding-cn', name: '智谱 GLM', route: 'zai-coding-cn', apiKeyEnv: 'ZAI_CODING_CN_API_KEY', defaultModel: 'glm-5.3-flash', models: ['glm-4.5-air', 'glm-4.7', 'glm-5-turbo', 'glm-5.1', 'glm-5.2', 'glm-5.3', 'glm-5.3-flash', 'glm-5v-turbo'] },
1309
- { id: 'qwen-token-plan-cn', name: '千问百炼', route: 'qwen-token-plan-cn', apiKeyEnv: 'QWEN_TOKEN_PLAN_CN_API_KEY', defaultModel: 'qwen3.7-max', models: ['qwen3.6-flash', 'qwen3.6-plus', 'qwen3.7-max', 'qwen3.7-plus', 'qwen3.8-max', 'qwen3.8-max-preview'] },
1310
- { id: 'openrouter', name: 'OpenRouter', route: 'openrouter', apiKeyEnv: 'OPENROUTER_API_KEY', defaultModel: 'z-ai/glm-5.3-flash', models: ['z-ai/glm-4.6', 'z-ai/glm-4.7', 'z-ai/glm-5', 'z-ai/glm-5-turbo', 'z-ai/glm-5.1', 'z-ai/glm-5.2', 'z-ai/glm-5.3-flash', 'auto', 'deepseek/deepseek-v4-flash', 'anthropic/claude-sonnet-4.6'] },
1311
- ]
1312
-
1313
- /** 运行时厂商目录的一项(添加到模型下拉;由 DSH 的 pi-ai 可配置提供方动态生成)。 */
1314
- export interface LlmVendorOption {
1315
- /** provider 路由 id(也是厂商下拉的值)。 */
1316
- id: string
1317
- /** 展示名。 */
1318
- name: string
1319
- /** 建议模型 id(可为空,用户手填)。 */
1320
- models: string[]
1321
- /** 已知 DSH 凭据引用名;为空时 host 生成 `PI_AI_<ID>_API_KEY`。 */
1322
- apiKeyEnv?: string
1323
- /** 内置适配器(只写凭据,不注册 pi-ai 路由)。 */
1324
- builtin?: boolean
1325
- }
1326
-
1327
- /** GET /llm-vendors 响应。 */
1328
- export interface LlmVendorsResponse {
1329
- vendors: LlmVendorOption[]
1330
- }
1331
-
1332
- /** /llm-models 里的一条模型。 */
1333
- export interface LlmModelOption { id: string; name: string }
1334
-
1335
- /** GET /llm-models?provider=x 响应。 */
1336
- export interface LlmModelsResponse {
1337
- models: LlmModelOption[]
1338
- }
1339
-
1340
- /** GET /llm-providers 响应:当前已注册的提供方路由。 */
1341
- export interface LlmProvidersResponse {
1342
- providers: { id: string; name: string }[]
1343
- }
1344
-
1345
- /** POST /llm-remove 请求:移除一个提供方(unset key + 移除 llm-pi-ai 路由)。 */
1346
- export interface RemoveProviderRequest {
1347
- provider: string
1348
- /** 该提供方对应的 DSH 凭据引用名(用于 unset)。 */
1349
- apiKeyEnv?: string
1350
- }
1351
-
1352
- /** POST /llm-remove 响应。 */
1353
- export interface RemoveProviderResponse {
1354
- ok: boolean
1355
- message?: string
1356
- }
1357
-
1358
- /** GET /llm-providers 响应:当前已注册的提供方路由。 */
1359
- export interface LlmProvidersResponse {
1360
- providers: { id: string; name: string }[]
1361
- }
1362
-
1363
- /** POST /llm-remove 请求:移除一个提供方(unset key + 移除 llm-pi-ai 路由)。 */
1364
- export interface RemoveProviderRequest {
1365
- provider: string
1366
- /** 该提供方对应的 DSH 凭据引用名(用于 unset)。 */
1367
- apiKeyEnv?: string
1368
- }
1369
-
1370
- /** POST /llm-remove 响应。 */
1371
- export interface RemoveProviderResponse {
1372
- ok: boolean
1373
- message?: string
1374
- }
1375
-
1376
- /** POST /llm-add 请求:添加一个模型(厂商直填 key,或自定义路由)。 */
1377
- export interface AddModelRequest {
1378
- mode: 'vendor' | 'custom'
1379
- /** 厂商模式用:provider 路由 id(来自 /llm-vendors)。 */
1380
- vendor?: string
1381
- /** 厂商已知的 DSH 凭据引用名(可选;为空时 host 生成)。 */
1382
- apiKeyEnv?: string
1383
- /** 自定义模式用:provider 路由 id。 */
1384
- provider?: string
1385
- /** 模型 id。 */
1386
- model: string
1387
- /** API Key。 */
1388
- apiKey: string
1389
- /** 展示名(可选)。 */
1390
- name?: string
1391
- /** 自定义模式用:OpenAI 兼容 base URL。 */
1392
- baseURL?: string
1393
- }
1394
-
1395
- /** POST /llm-add 响应。 */
1396
- export interface AddModelResponse {
1397
- ok: boolean
1398
- saved: SavedModel
1399
- provider: string
1400
- message?: string
1401
- }
1402
-
1403
- /** 手动添加的模型库条目(只存插件内,不改 DSH 全局)。 */
1404
- export interface NovelConfig {
1405
- /** Absolute path of the default docx outline to load. */
1406
- outlinePath: string
1407
- /** Absolute output directory for chapters + project state. */
1408
- outputDir: string
1409
- /** LLM provider route (e.g. deepseek-official). */
1410
- provider: string
1411
- /** LLM model id (e.g. deepseek-v4-flash). */
1412
- model: string
1413
- /** LLM reasoning effort: off = no thinking; low/high/max = thinking intensity. */
1414
- reasoningEffort: 'off' | 'low' | 'high' | 'max'
1415
- /** 分析类任务(提炼/拆书/反推大纲等)的推理档位;默认 low,不受上面写作档位影响。 */
1416
- analysisReasoning: 'off' | 'low' | 'high' | 'max'
1417
- /** Target characters per chapter. */
1418
- chapterChars: number
1419
- /** Max output tokens per chapter call. */
1420
- maxTokens: number
1421
- /** Review pass threshold (0-100). */
1422
- reviewPassScore: number
1423
- /** Whether generation auto-runs review after writing. */
1424
- autoReview: boolean
1425
- /** Whether generation auto-runs the author review (hook/continuity/trend) after writing. */
1426
- autoAuthorReview: boolean
1427
- /** 修订/润色产出草稿后是否自动附带一次 AI 审查(工作区显示新稿评分与剩余问题)。 */
1428
- autoReviewAfterRevise: boolean
1429
- /** 生图模型库(多套并存,启用一条生效;旧 imageApiKey/imageApiModel 自动迁移为一条)。 */
1430
- imageModels?: ImageModelConfig[]
1431
- /** 运行时生效的生图接口地址(= 启用条目,兼容旧代码读取)。 */
1432
- imageBaseUrl?: string
1433
- /** 运行时生效的生图 API Key(= 启用条目,兼容旧代码读取)。 */
1434
- imageApiKey?: string
1435
- /** 运行时生效的生图模型 id(= 启用条目,兼容旧代码读取)。 */
1436
- imageApiModel?: string
1437
- /** 是否启用生图(= 存在启用条目)。 */
1438
- imageApiEnabled?: boolean
1439
- /** 自定义背景图(URL 或 dataURL 或服务端路径引用;空 = 使用主题默认背景)。 */
1440
- themeBackground?: string
1441
- /** 自定义背景遮罩/模糊强度 0-80(0 = 不遮罩)。 */
1442
- themeBackgroundBlur?: number
1443
- /** 玻璃透明度 0-100(100=当前原样,越小越透,新拟态/黏土可见背景图)。 */
1444
- themeOpacity?: number
1445
- /** 是否启用改编模式(默认关闭;发布后开启)。 */
1446
- enableAdaptMode?: boolean
1447
- /** 手动添加的模型库(「我的模型」条目;只存插件内)。 */
1448
- savedModels?: SavedModel[]
1449
- }
1450
-
1451
- /** GET /status response. */
1452
- export interface StatusResponse {
1453
- config: NovelConfig
1454
- /** The persisted project, when one exists in the output dir. */
1455
- project?: ProjectState
1456
- /** Chapter files already on disk (basenames, sorted). */
1457
- generatedFiles: string[]
1458
- /** 全书质检实时状态(用于面板/外部读取进度)。 */
1459
- audit?: AuditStatus
1460
- }
1461
-
1462
- /** 生产单状态(生产单 = 区间批量生产执行器:计划补足 + 逐章生成 + 被拒分级处理)。 */
1463
- export interface RunState {
1464
- runId: string
1465
- /** 区间起点(含)。 */
1466
- startNo: number
1467
- /** 区间终点(含)。 */
1468
- endNo: number
1469
- status: 'running' | 'paused' | 'done' | 'stopped' | 'error'
1470
- /** 当前处理到的章号(已 approved 的章会快进)。 */
1471
- currentNo: number
1472
- stats: {
1473
- /** 新生成(含审稿)的章数。 */
1474
- generated: number
1475
- /** 被拒后按意见修订并通过的章数。 */
1476
- revised: number
1477
- /** 被拒后豁免通过(无 high)的章数。 */
1478
- exempted: number
1479
- /** error 后重新生成的章数。 */
1480
- regenerated: number
1481
- /** 生成失败的章数。 */
1482
- error: number
1483
- }
1484
- /** 两轮修订仍不过、保留草稿待人工的章号。 */
1485
- pendingManual: number[]
1486
- /** 运行日志(保留最近 300 条)。 */
1487
- log: Array<{ at: string; text: string }>
1488
- startedAt: string
1489
- updatedAt: string
1490
- error?: string
1491
- }
1492
-
1493
- /** POST /run/start request. */
1494
- export interface RunStartRequest {
1495
- /** 起始章号(默认 1)。 */
1496
- startNo?: number
1497
- /** 结束章号(含;超出计划时自动补计划)。 */
1498
- endNo?: number
1499
- /** 或指定新增章数(从当前最后一章 +1 起)。 */
1500
- count?: number
1501
- }
1502
-
1503
- /** POST /run/control request. */
1504
- export interface RunControlRequest {
1505
- action: 'pause' | 'resume' | 'stop'
1506
- }
1507
-
1508
- /** POST /load-outline request: either a docx path or raw text. */
1509
- export interface LoadOutlineRequest {
1510
- /** Absolute docx path; defaults to the configured outline path. */
1511
- path?: string
1512
- /** Raw outline text (takes precedence over path when present). */
1513
- text?: string
1514
- }
1515
-
1516
- /** POST /load-outline response. */
1517
- export interface LoadOutlineResponse {
1518
- outline: string
1519
- bookName: string
1520
- chars: number
1521
- path?: string
1522
- }
1523
-
1524
- /** POST /plan request. */
1525
- export interface PlanRequest {
1526
- /** Outline to plan from; defaults to the persisted project's outline. */
1527
- outline?: string
1528
- /** Number of chapters to plan (default: 30). */
1529
- chapterCount?: number
1530
- /** Volume to plan (1-based); when given, plans only that volume's chapters. */
1531
- volume?: number
1532
- }
1533
-
1534
- /** POST /plan response. */
1535
- export interface PlanResponse {
1536
- chapters: ChapterPlan[]
1537
- volumes?: Volume[]
1538
- }
1539
-
1540
- /** POST /volumes request/response. */
1541
- export interface VolumesRequest {
1542
- /** Outline to split into volumes; defaults to the project outline. */
1543
- outline?: string
1544
- }
1545
- export interface VolumesResponse {
1546
- volumes: Volume[]
1547
- }
1548
-
1549
- /** POST /bible request/response. */
1550
- export interface BibleRequest {
1551
- /** Outline to extract from; defaults to the project outline. */
1552
- outline?: string
1553
- }
1554
- export interface BibleResponse {
1555
- bible: StoryBible
1556
- }
1557
-
1558
- /** POST /generate request: one chapter of the current project. */
1559
- export interface GenerateRequest {
1560
- chapterNo: number
1561
- /** When true, skips the auto-review step. */
1562
- skipReview?: boolean
1563
- }
1564
-
1565
- /** One NDJSON frame of a generation/review/rewrite stream. */
1566
- export type JobFrame =
1567
- | { type: 'start'; no: number; title: string }
1568
- | { type: 'delta'; text: string }
1569
- | { type: 'progress'; chars: number }
1570
- | { type: 'done'; no: number; file: string; chars: number; title: string }
1571
- | { type: 'review'; no: number; report: ReviewReport }
1572
- | { type: 'author-review'; no: number; review: AuthorReview }
1573
- | { type: 'author-backfill-done'; count: number }
1574
- | { type: 'rewritten'; no: number; file: string; chars: number }
1575
- /** 润色/重写完成,产物作为待确认草稿(尚未覆盖正文)。 */
1576
- | { type: 'drafted'; no: number; chars: number; draft: string }
1577
- | { type: 'outline-progress'; done: number; total: number; phase: string }
1578
- | { type: 'outline-done'; outline: string; chars: number }
1579
- | { type: 'error'; no: number; message: string }
1580
-
1581
- /** POST /review request: review one written chapter. */
1582
- export interface ReviewRequest {
1583
- chapterNo: number
1584
- }
1585
-
1586
- /** POST /rewrite request: rewrite one chapter (optionally per review issues). */
1587
- export interface RewriteRequest {
1588
- chapterNo: number
1589
- /** Free-form instructions; defaults to fixing the review's high issues. */
1590
- instructions?: string
1591
- /**
1592
- * 局部修订:正文中的一段原文(无需完全精确,取一个自然段内的片段即可)。
1593
- * 提供时只重写该段,其余正文保持不变;不提供时整章重写。
1594
- */
1595
- target?: string
1596
- }
1597
-
1598
- /** POST /polish request: de-AI-ify one chapter. */
1599
- export interface PolishRequest {
1600
- chapterNo: number
1601
- }
1602
-
1603
- /** POST /draft/apply | /draft/discard request: 采纳或放弃待确认草稿。 */
1604
- export interface DraftDecisionRequest {
1605
- chapterNo: number
1606
- /** apply 时可携带审查报告(沿用结论定状态;不携带则置 written)。 */
1607
- report?: ReviewReport
1608
- }
1609
-
1610
- /** POST /summary request: (re)generate a chapter summary. */
1611
- export interface SummaryRequest {
1612
- chapterNo: number
1613
- }
1614
-
1615
- /** POST /foreshadow request: create, update, or AI-suggest foreshadows. */
1616
- export interface ForeshadowRequest {
1617
- /** When true, runs the LLM suggestion pass (ignores other fields). */
1618
- suggest?: boolean
1619
- /** When given, updates that foreshadow instead of creating one. */
1620
- id?: string
1621
- description?: string
1622
- plantedChapter?: number
1623
- targetChapter?: number
1624
- status?: Foreshadow['status']
1625
- resolvedNote?: string
1626
- }
1627
- export interface ForeshadowResponse {
1628
- foreshadows: Foreshadow[]
1629
- }
1630
-
1631
- /** GET /chapter response. */
1632
- export interface ChapterResponse {
1633
- no: number
1634
- title: string
1635
- markdown: string
1636
- }
1637
-
1638
- /** POST /export request/response. */
1639
- export interface ExportRequest {
1640
- format: 'txt' | 'md'
1641
- }
1642
- export interface ExportResponse {
1643
- file: string
1644
- chars: number
1645
- chapters: number
1646
- }
1647
-
1648
- /** POST /config request: patch any subset of the runtime config. */
1649
- export interface ConfigPatch {
1650
- outlinePath?: string
1651
- outputDir?: string
1652
- provider?: string
1653
- model?: string
1654
- reasoningEffort?: 'off' | 'low' | 'high' | 'max'
1655
- analysisReasoning?: 'off' | 'low' | 'high' | 'max'
1656
- chapterChars?: number
1657
- maxTokens?: number
1658
- reviewPassScore?: number
1659
- autoReview?: boolean
1660
- autoAuthorReview?: boolean
1661
- autoReviewAfterRevise?: boolean
1662
- imageApiKey?: string
1663
- imageApiModel?: string
1664
- imageApiEnabled?: boolean
1665
- /** 自定义背景图(URL / dataURL / 服务端路径引用)。 */
1666
- themeBackground?: string
1667
- /** 自定义背景遮罩/模糊强度 0-80。 */
1668
- themeBackgroundBlur?: number
1669
- /** 玻璃透明度 0-100(100=当前原样)。 */
1670
- themeOpacity?: number
1671
- enableAdaptMode?: boolean
1672
- /** 生图模型库(完整替换保存)。 */
1673
- imageModels?: ImageModelConfig[]
1674
- /** 手动添加的模型库(完整替换保存)。 */
1675
- savedModels?: SavedModel[]
1676
- }
1677
-
1678
- // ------------------------------------------------------------ assistant
1679
-
1680
- /** One assistant conversation message (persisted per project). */
1681
- export interface AssistantMessage {
1682
- role: 'user' | 'assistant' | 'tool'
1683
- /** Message text (tool messages carry the tool result). */
1684
- content: string
1685
- /** ISO timestamp. */
1686
- ts: string
1687
- /** For tool messages: which tool ran. */
1688
- tool?: string
1689
- }
1690
-
1691
- /** POST /assistant request: one user turn. */
1692
- export interface AssistantRequest {
1693
- message: string
1694
- }
1695
-
1696
- /** One NDJSON frame of the assistant stream. */
1697
- export type AssistantFrame =
1698
- | { type: 'delta'; text: string }
1699
- | { type: 'tool'; name: string; status: 'start' | 'done' | 'error'; detail?: string }
1700
- /** Live output while a tool runs (e.g. chapter text being generated). */
1701
- | { type: 'toolDelta'; name: string; text: string }
1702
- | { type: 'done' }
1703
- | { type: 'error'; message: string }
1704
-
1705
- /** GET /assistant-history response. */
1706
- export interface AssistantHistoryResponse {
1707
- messages: AssistantMessage[]
1708
- }
1709
-
1710
- // ---------------------------------------------------------- writing assets
1711
-
1712
- /** 题材基底库:一本书属于哪个阅读市场。树形(题材→子题材→下级)。 */
1713
- export interface GenreNode {
1714
- /** 题材名称(标签,如「仙侠修真」「都市异能」)。 */
1715
- name: string
1716
- /** 题材特征、常见爽点、叙事重心或读者期待。 */
1717
- description: string
1718
- /** 子题材。 */
1719
- children: GenreNode[]
1720
- }
1721
-
1722
- /** 推进模式库:读者为什么继续看下一章。 */
1723
- export interface ProgressionMode {
1724
- /** 模式名称(如「升级变强」「经营扩张」「解谜揭露」)。 */
1725
- name: string
1726
- /** 核心驱动力:靠什么制造追读动力。 */
1727
- driver: string
1728
- /** 读者期待:每隔几章获得什么变化或回报。 */
1729
- readerExpectation: string
1730
- /** 常见兑现方式(爽点如何落地)。 */
1731
- payoffs: string[]
1732
- /** 节奏风险:最怕什么(重复升级、冲突变弱、谜题拖太久…)。 */
1733
- risks: string[]
1734
- /** 主模式或辅助模式。 */
1735
- primary: boolean
1736
- }
1737
-
1738
- /** 反 AI 规则:一条「要避免的问题 + 修正方向」。 */
1739
- export interface AntiAiRule {
1740
- /** 规则名(如「禁止解释型心理描写」「AI 高频套话」)。 */
1741
- name: string
1742
- /** 要避免的表达问题,具体可检查。 */
1743
- avoid: string
1744
- /** 推荐修正方向。 */
1745
- fix: string
1746
- /** 命中即告警的具体表达模式(用于审稿逐条核对与去 AI 味检测)。 */
1747
- detectPatterns?: string[]
1748
- /** 是否内置全局规则(内置规则随插件发布,项目规则为用户自定义)。 */
1749
- builtin?: boolean
1750
- }
1751
-
1752
- /** 预置写法模板(来自 AI-Novel-Writing-Assistant 内置数据,一键绑定无需样本文本)。 */
1753
- export interface StyleTemplate {
1754
- /** 模板 key(如 power-up-escalation)。 */
1755
- key: string
1756
- /** 模板名(如「爽文递进推进流」)。 */
1757
- name: string
1758
- /** 模板说明。 */
1759
- description: string
1760
- /** 分类(如「爽文流」「悬疑流」)。 */
1761
- category: string
1762
- /** 适用题材。 */
1763
- applicableGenres: string[]
1764
- /** 叙述规则。 */
1765
- proseRules: string[]
1766
- /** 角色/台词规则。 */
1767
- dialogueRules: string[]
1768
- /** 语言规则。 */
1769
- languageRules: string[]
1770
- /** 节奏规则。 */
1771
- rhythmRules: string[]
1772
- /** 该模板默认绑定的反 AI 规则 key(内置规则名)。 */
1773
- defaultAntiAiRuleKeys: string[]
1774
- }
1775
-
1776
- /** 剧情桥段库:可复用的情节套路/桥段(作者阅读经验沉淀,与书内 Plotline 不同层)。 */
1777
- export interface PlotBeatTemplate {
1778
- /** 模板 key(如 face-slap / exit-wedding)。 */
1779
- key: string
1780
- /** 桥段名(如「打脸」「退婚」)。 */
1781
- name: string
1782
- /** 分类(如「装逼打脸」「身份逆袭」)。 */
1783
- category: string
1784
- /** 一句话说明。 */
1785
- summary: string
1786
- /** 适用位置(开局/前期/中期/后期/高潮/结尾)。 */
1787
- position: string
1788
- /** 前置条件。 */
1789
- preconditions: string[]
1790
- /** 爽点来源。 */
1791
- payoffSource: string[]
1792
- /** 常用组合(可搭配的桥段)。 */
1793
- combos: string[]
1794
- /** 禁忌(别用烂/别用死)。 */
1795
- taboos: string[]
1796
- /** 适用题材。 */
1797
- applicableGenres: string[]
1798
- }
1799
-
1800
- /** 写法引擎:从样本文本提取的叙事风格资产。 */
1801
- export interface StyleAsset {
1802
- /** 资产名(如「林越式痞坏」「冷峻猎手风」)。 */
1803
- name: string
1804
- /** 叙述视角与句式节奏。 */
1805
- proseRules: string[]
1806
- /** 角色台词风格。 */
1807
- dialogueRules: string[]
1808
- /** 描写密度与情绪表达。 */
1809
- descriptionRules: string[]
1810
- /** 表达边界(不要做什么)。 */
1811
- boundaries: string[]
1812
- /** 来源样本文本(可空)。 */
1813
- sourceText?: string
1814
- /** 创建时间。 */
1815
- createdAt: string
1816
- }
1817
-
1818
- /** 项目写作资产(题材基底 + 推进模式 + 反 AI 规则 + 写法资产)。 */
1819
- export interface ProjectAssets {
1820
- /** 本书选用的题材(可以是题材基底库中某节点名)。 */
1821
- genre?: GenreNode
1822
- /** 主推进模式。 */
1823
- primaryProgression?: ProgressionMode
1824
- /** 辅助推进模式。 */
1825
- auxiliaryProgressions: ProgressionMode[]
1826
- /** 生效的反 AI 规则(内置 + 自定义)。 */
1827
- antiAiRules: AntiAiRule[]
1828
- /** 绑定的写法资产。 */
1829
- styleAssets: StyleAsset[]
1830
- /** 资产更新时间。 */
1831
- updatedAt?: string
1832
- }
1833
-
1834
- /** GET /assets response(含全局题材库与反 AI 规则库)。 */
1835
- export interface AssetsResponse {
1836
- projectAssets: ProjectAssets
1837
- /** 全局题材基底库(可复用资产,跨书)。 */
1838
- genreLibrary: GenreNode[]
1839
- /** 全局反 AI 规则库(内置默认规则)。 */
1840
- antiAiLibrary: AntiAiRule[]
1841
- /** 预置写法模板(一键绑定,无需样本文本)。 */
1842
- styleTemplates: StyleTemplate[]
1843
- /** 内置推进模式候选。 */
1844
- progressionLibrary: ProgressionMode[]
1845
- /** 内置剧情桥段库(可复用套路)。 */
1846
- plotBeatLibrary: PlotBeatTemplate[]
1847
- }
1848
-
1849
- /** POST /assets request:更新项目写作资产(部分字段可选)。 */
1850
- export interface AssetsPatch {
1851
- genre?: GenreNode
1852
- primaryProgression?: ProgressionMode
1853
- auxiliaryProgressions?: ProgressionMode[]
1854
- antiAiRules?: AntiAiRule[]
1855
- styleAssets?: StyleAsset[]
1856
- }
1857
-
1858
- /** POST /style-engine request:从样本文本提取写法资产。 */
1859
- export interface StyleEngineRequest {
1860
- /** 样本文本(风格来源)。 */
1861
- sampleText: string
1862
- /** 资产名(可选,默认「风格资产 N」)。 */
1863
- name?: string
1864
- }
1865
-
1866
- // ---------------------------------------------------------- author assets (总数据)
1867
-
1868
- /** 作者资产库中一条可跨书复用的资产(笔法/红线/套路/角色模板/世界观模板等)。 */
1869
- export interface AuthorStyleAsset {
1870
- /** 稳定 id(本地唯一)。 */
1871
- id: string
1872
- /** 资产名(如「短句快节奏爽文风」「林越式痞坏角色」)。 */
1873
- name: string
1874
- /** 资产类型。 */
1875
- kind: 'style' | 'antiAi' | 'progression' | 'genre' | 'roleTemplate' | 'worldTemplate' | 'plotBeat' | 'custom'
1876
- /** 一句话摘要。 */
1877
- summary: string
1878
- /** 资产正文内容(按 kind 约定解读的文本/JSON 描述)。 */
1879
- content: string
1880
- /** 结构化载荷(角色模板/世界观模板等可结构化字段;缺省为 null)。 */
1881
- structured?: Record<string, unknown>
1882
- /** 来源书名(哪本书提炼/收藏而来)。 */
1883
- sourceBooks: string[]
1884
- /** 标签。 */
1885
- tags: string[]
1886
- /** 来源样本文本(可选)。 */
1887
- sourceText?: string
1888
- /** 创建时间。 */
1889
- createdAt: string
1890
- /** 更新时间。 */
1891
- updatedAt: string
1892
- }
1893
-
1894
- /** 作者资产库(跨书总数据):按作者维度聚合的可复用资产。 */
1895
- export interface AuthorAssetLibrary {
1896
- /** 货架版本,便于未来迁移。 */
1897
- version: 1
1898
- items: AuthorStyleAsset[]
1899
- }
1900
-
1901
- /** GET /author-assets 响应。 */
1902
- export interface AuthorAssetsResponse {
1903
- assets: AuthorAssetLibrary
1904
- }
1905
-
1906
- /** POST /author-assets/upsert 请求:新增或按 id 更新一条资产。 */
1907
- export interface AuthorAssetUpsertRequest {
1908
- asset: AuthorStyleAsset
1909
- }
1910
-
1911
- /** POST /author-assets/remove 请求:删除一条资产。 */
1912
- export interface AuthorAssetRemoveRequest {
1913
- id: string
1914
- }
1915
-
1916
- // ---------------------------------------------------------- adaptation (改编模式)
1917
-
1918
- /** 改编可改范围的单个维度(矩阵的一行)。 */
1919
- export interface AdaptationDimension {
1920
- /** 维度 key(如 realm/name/goldenFinger…)。 */
1921
- key: string
1922
- /** 维度名(如「大世界」「修为体系」「主角名」「金手指」)。 */
1923
- title: string
1924
- /** 可改度:保留 / 可改影响大 / 可改影响小 / 可自由改 / 仅视觉包装。 */
1925
- mutability: 'locked' | 'big' | 'small' | 'free' | 'visual'
1926
- /** 原文当前值(从正文提炼,附证据)。 */
1927
- current: string
1928
- /** 该值在正文中的出现证据(章节/频次,可空)。 */
1929
- evidence?: string
1930
- /** AI 建议的候选新值(可空)。 */
1931
- candidates?: string[]
1932
- /** 联动影响说明(改了会影响哪些章节/角色/伏笔/术语)。 */
1933
- impact: string
1934
- /** 风险评级。 */
1935
- risk: 'high' | 'medium' | 'low'
1936
- }
1937
-
1938
- /** POST /adapt/analyze 请求:上传全文做改编分析。 */
1939
- export interface AdaptAnalyzeRequest {
1940
- /** 全文文本(优先)。 */
1941
- text: string
1942
- /** 或服务器端全文文件路径。 */
1943
- filePath?: string
1944
- }
1945
-
1946
- /** POST /adapt/analyze 响应。 */
1947
- export interface AdaptAnalyzeResponse {
1948
- /** 识别书名(文件名推断或正文首行)。 */
1949
- bookName: string
1950
- /** 拆出的章节数。 */
1951
- chapters: number
1952
- /** 反推的初始大纲(可空)。 */
1953
- outline?: string
1954
- /** 可改范围矩阵。 */
1955
- dimensions: AdaptationDimension[]
1956
- /** 分析消耗说明。 */
1957
- note?: string
1958
- }
1959
-
1960
- /** 一条改编映射(原值 → 新值)。 */
1961
- export interface AdaptationMapping {
1962
- /** 原值(如「林尘」「练气」「青云宗」)。 */
1963
- source: string
1964
- /** 新值(如「楚风」「凝元」「天渊阁」)。 */
1965
- target: string
1966
- /** 适用范围。 */
1967
- scope: 'name' | 'realm' | 'faction' | 'term' | 'other'
1968
- /** 说明(可空)。 */
1969
- note?: string
1970
- }
1971
-
1972
- /** 改编规则:哪些必须保留、哪些允许改、一致性约束。 */
1973
- export interface AdaptationRules {
1974
- /** 必须保留的要素(骨架/人物动机/伏笔逻辑/爽点结构…)。 */
1975
- preserve: string[]
1976
- /** 允许改变的要素。 */
1977
- change: string[]
1978
- /** 改编红线/一致性要求。 */
1979
- constraints: string[]
1980
- }
1981
-
1982
- /** 一组改编方案(映射表 + 规则 + 联动影响清单)。 */
1983
- export interface AdaptationProposal {
1984
- /** 映射表(原→新)。 */
1985
- mappings: AdaptationMapping[]
1986
- /** 改编规则。 */
1987
- rules: AdaptationRules
1988
- /** 联动影响清单。 */
1989
- impacts: Array<{ item: string; detail: string; risk: 'high' | 'medium' | 'low'; chapters?: number[] }>
1990
- }
1991
-
1992
- /** POST /adapt/propose 请求:由用户勾选的维度 + 新值生成改编方案。 */
1993
- export interface AdaptProposeRequest {
1994
- /** 原文全文(复用,便于 LLM 核对联动影响)。 */
1995
- text: string
1996
- /** 用户确认要改的维度(含原值与新值)。 */
1997
- selections: Array<{ key: string; title: string; current: string; target: string; mutability: string }>
1998
- /** 若已分析过,可携带完整矩阵作为上下文。 */
1999
- dimensions?: AdaptationDimension[]
2000
- }
2001
-
2002
- /** POST /adapt/propose 响应。 */
2003
- export interface AdaptProposeResponse {
2004
- proposal: AdaptationProposal
2005
- }
2006
-
2007
- /** POST /adapt/execute 请求:执行改编(replace=术语替换;rewrite=逐章 LLM 重写)。 */
2008
- export interface AdaptExecuteRequest {
2009
- /** 原文全文。 */
2010
- text: string
2011
- /** 改编映射表。 */
2012
- mappings: AdaptationMapping[]
2013
- /** 改编规则(rewrite 模式生效:保留/允许变/红线)。 */
2014
- rules?: AdaptationRules
2015
- /** 执行模式:replace(术语替换)或 rewrite(逐章重写)。 */
2016
- mode?: 'replace' | 'rewrite'
2017
- /** rewrite 模式:只重写前 N 章(0/缺省 = 全部,且在 startNo/endNo 窗口内)。 */
2018
- maxChapters?: number
2019
- /** rewrite 模式:起始章号(含,默认 1)。 */
2020
- startNo?: number
2021
- /** rewrite 模式:结束章号(含;0/缺省 = 到全书末尾)。 */
2022
- endNo?: number
2023
- }
2024
-
2025
- /** POST /adapt/execute 响应。 */
2026
- export interface AdaptExecuteResponse {
2027
- /** 改编后的全文。 */
2028
- adaptedText: string
2029
- /** 执行的映射数。 */
2030
- mappings: number
2031
- /** 命中统计:每条映射的替换次数。 */
2032
- hits: Array<{ source: string; target: string; count: number }>
2033
- /** 执行模式(replace / rewrite)。 */
2034
- mode?: 'replace' | 'rewrite'
2035
- /** rewrite 模式的逐章结果(no/title/chars)。 */
2036
- rewritten?: Array<{ no: number; title: string; chars: number }>
2037
- /** rewrite 模式下重写失败、保留原章的章节号。 */
2038
- skipped?: number[]
2039
- }
2040
-
2041
- /** POST /adapt/rewrite-stream 的 NDJSON 帧(逐章进度 + 结束结果)。 */
2042
- export type AdaptRewriteFrame =
2043
- | { type: 'progress'; completed: number; total: number; no: number; title: string }
2044
- | { type: 'done'; result: AdaptExecuteResponse }
2045
- | { type: 'error'; message: string }
2046
-
2047
- /** POST /adapt/save 请求:保存改编全文为新书(原书保留,登记书架)。 */
2048
- export interface AdaptSaveRequest {
2049
- /** 改编后的全文。 */
2050
- text: string
2051
- /** 新书名(缺省为「改编新书」;建议用「<原著>·改编版」)。 */
2052
- bookName?: string
2053
- /** 新书输出目录(缺省 ~/.dsh/novels/书名)。 */
2054
- outputDir?: string
2055
- /** 可附带反推大纲(写进新项目,便于后续续写/编辑)。 */
2056
- outline?: string
2057
- }
2058
-
2059
- /** POST /adapt/save 响应。 */
2060
- export interface AdaptSaveResponse {
2061
- /** 登记后的书架条目。 */
2062
- book: BookEntry
2063
- /** 新书名。 */
2064
- bookName: string
2065
- /** 成功拆出的章节数。 */
2066
- chapters: number
2067
- /** 因内容过短被跳过的章节标题列表。 */
2068
- skipped: string[]
2069
- /** 新书输出目录。 */
2070
- outputDir: string
2071
- }
2072
-
2073
- /** POST /adapt/materialize 请求:从源全文 + 用户编辑后的改编方案,提炼新书资料并保存为「待写新书」。 */
2074
- export interface AdaptMaterializeRequest {
2075
- /** 源书全文。 */
2076
- text: string
2077
- /** 新书名(缺省为「<源书名>·改编版」)。 */
2078
- bookName?: string
2079
- /** 新书输出目录(缺省 ~/.dsh/novels/书名)。 */
2080
- outputDir?: string
2081
- /** 反推大纲(来自分析;缺少时用源文章题兜底)。 */
2082
- outline?: string
2083
- /** 用户编辑后的改编方案(映射表 + 规则)。 */
2084
- proposal: AdaptationProposal
2085
- /** 拟规划章节数(缺省 30,可在前端调整)。 */
2086
- chapterCount?: number
2087
- }
2088
-
2089
- /** POST /adapt/materialize 响应:提炼后的新书资料(预览,尚未落盘;保存走 /adapt/materialize-save)。 */
2090
- export interface AdaptMaterializeResponse {
2091
- /** 书架条目(仅在已保存时存在;预览阶段为 undefined)。 */
2092
- book?: BookEntry
2093
- /** 新书名。 */
2094
- bookName: string
2095
- /** 改编后总纲。 */
2096
- outline: string
2097
- /** 改编后设定圣经(道藏)。 */
2098
- bible: StoryBible
2099
- /** 改编后角色库。 */
2100
- roles: RoleRecord[]
2101
- /** 改编后大世界。 */
2102
- world: WorldState
2103
- /** 改编后卷计划。 */
2104
- volumes: Volume[]
2105
- /** 改编后章节计划(status=pending)。 */
2106
- chapters: ChapterPlan[]
2107
- /** 新书输出目录。 */
2108
- outputDir: string
2109
- }
2110
-
2111
- /** POST /adapt/materialize-save 请求:把预览/微调后的新书资料写入并登记书架。 */
2112
- export interface AdaptMaterializeSaveRequest {
2113
- /** 新书名(缺省为「改编版」)。 */
2114
- bookName?: string
2115
- /** 新书输出目录(缺省 ~/.dsh/novels/书名)。 */
2116
- outputDir?: string
2117
- /** 改编后总纲。 */
2118
- outline: string
2119
- /** 改编后设定圣经(道藏)。 */
2120
- bible: StoryBible
2121
- /** 改编后角色库。 */
2122
- roles: RoleRecord[]
2123
- /** 改编后大世界。 */
2124
- world: WorldState
2125
- /** 改编后卷计划。 */
2126
- volumes: Volume[]
2127
- /** 改编后章节计划(status=pending)。 */
2128
- chapters: ChapterPlan[]
2129
- }
2130
-
2131
- /** POST /adapt/materialize-save 响应。 */
2132
- export interface AdaptMaterializeSaveResponse {
2133
- /** 登记后的书架条目。 */
2134
- book: BookEntry
2135
- /** 新书名。 */
2136
- bookName: string
2137
- /** 成功写入的章节数。 */
2138
- chapters: number
2139
- /** 新书输出目录。 */
2140
- outputDir: string
2141
- }
2142
-
2143
- /** POST /plugin/update 响应:插件自更新结果。 */
2144
- export interface PluginUpdateResponse {
2145
- ok: boolean
2146
- /** 更新结果说明(成功/失败/环境提示)。 */
2147
- message: string
2148
- }
1
+ /**
2
+ * dsh-novel-forge — shared protocol between the host half (Node) and the
3
+ * browser half (web GUI). Route paths, request/response shapes, the project
4
+ * state file format, and the NDJSON generation stream frames all live here so
5
+ * both halves spell exactly one vocabulary.
6
+ */
7
+
8
+ /** The /api/dsh-novel-forge route family (same-origin, loopback-fenced). */
9
+ export const NOVEL_API = {
10
+ status: '/api/dsh-novel-forge/status',
11
+ loadOutline: '/api/dsh-novel-forge/load-outline',
12
+ saveOutline: '/api/dsh-novel-forge/save-outline',
13
+ plan: '/api/dsh-novel-forge/plan',
14
+ volumes: '/api/dsh-novel-forge/volumes',
15
+ bible: '/api/dsh-novel-forge/bible',
16
+ assets: '/api/dsh-novel-forge/assets',
17
+ styleEngine: '/api/dsh-novel-forge/style-engine',
18
+ styleFormula: '/api/dsh-novel-forge/style-formula',
19
+ styleDetect: '/api/dsh-novel-forge/style-detect',
20
+ knowledge: '/api/dsh-novel-forge/knowledge',
21
+ bookAnalysis: '/api/dsh-novel-forge/book-analysis',
22
+ ideaInspiration: '/api/dsh-novel-forge/idea-inspiration',
23
+ ideaInspirationMarket: '/api/dsh-novel-forge/idea-inspiration/market',
24
+ director: '/api/dsh-novel-forge/director',
25
+ directorTodos: '/api/dsh-novel-forge/director/todos',
26
+ llmLive: '/api/dsh-novel-forge/llm-live/stream',
27
+ /** 查看某次调用实际发送的 Prompt(按 sessionId)。 */
28
+ llmPrompt: '/api/dsh-novel-forge/llm-live/prompt',
29
+ /** 清零本次运行的用量账本。 */
30
+ usageReset: '/api/dsh-novel-forge/usage/reset',
31
+ /** 章节历史版本(快照)。 */
32
+ snapshot: '/api/dsh-novel-forge/snapshot',
33
+ /** 修订指令合并(POST:汇总审稿/时间线/张力为一轮)。 */
34
+ revisionPlan: '/api/dsh-novel-forge/revision/plan',
35
+ /** 张力曲线(GET 数据 / POST 设置)。 */
36
+ tension: '/api/dsh-novel-forge/tension',
37
+ /** 提示词槽位(GET 列表 / POST 写入)。 */
38
+ promptSlots: '/api/dsh-novel-forge/prompt-slots',
39
+ /** 故事时间线(GET 列表 / POST 操作)。 */
40
+ timeline: '/api/dsh-novel-forge/timeline',
41
+ marketRadar: '/api/dsh-novel-forge/market-radar',
42
+ marketRadarScan: '/api/dsh-novel-forge/market-radar/scan',
43
+ marketRadarApply: '/api/dsh-novel-forge/market-radar/apply',
44
+ marketRadarSync: '/api/dsh-novel-forge/market-radar/foundation-sync',
45
+ marketRadarBrief: '/api/dsh-novel-forge/market-radar/brief',
46
+ generate: '/api/dsh-novel-forge/generate',
47
+ review: '/api/dsh-novel-forge/review',
48
+ rewrite: '/api/dsh-novel-forge/rewrite',
49
+ polish: '/api/dsh-novel-forge/polish',
50
+ /** 采纳待确认草稿(润色/重写产物)覆盖正文文件。 */
51
+ draftApply: '/api/dsh-novel-forge/draft/apply',
52
+ /** 放弃待确认草稿,保留原稿。 */
53
+ draftDiscard: '/api/dsh-novel-forge/draft/discard',
54
+ summary: '/api/dsh-novel-forge/summary',
55
+ foreshadow: '/api/dsh-novel-forge/foreshadow',
56
+ exportBook: '/api/dsh-novel-forge/export',
57
+ chapter: '/api/dsh-novel-forge/chapter',
58
+ /** 审查任意正文文本(作者手动编辑后,不落盘)。 */
59
+ chapterCheck: '/api/dsh-novel-forge/chapter/check',
60
+ /** 保存手动编辑的正文(自动备份 .bak)。 */
61
+ chapterSave: '/api/dsh-novel-forge/chapter/save',
62
+ assistant: '/api/dsh-novel-forge/assistant',
63
+ assistantHistory: '/api/dsh-novel-forge/assistant-history',
64
+ /** 清空助手对话记录。 */
65
+ assistantClear: '/api/dsh-novel-forge/assistant/clear',
66
+ bookshelf: '/api/dsh-novel-forge/bookshelf',
67
+ /** 导入已有项目目录(含 novel-project.json)到书架。 */
68
+ bookshelfImportDir: '/api/dsh-novel-forge/bookshelf/import-dir',
69
+ /** 导入 txt/md 全本:拆章建项目并登记书架。 */
70
+ bookshelfImportText: '/api/dsh-novel-forge/bookshelf/import-text',
71
+ /** 导入 txt/md 全本:拆章预览(不落盘)。 */
72
+ bookshelfImportTextPreview: '/api/dsh-novel-forge/bookshelf/import-text/preview',
73
+ /** LLM 模型连通性测试:真实最小调用,验证 Key / 端点 / 模型可用。 */
74
+ llmTest: '/api/dsh-novel-forge/llm-test',
75
+ /** 添加模型:厂商直填 key 或自定义路由,写进 DSH 凭据与 llm-pi-ai 路由。 */
76
+ addModel: '/api/dsh-novel-forge/llm-add',
77
+ /** 运行时厂商目录(DSH pi-ai 可配置提供方 + 内置适配器)。 */
78
+ llmVendors: '/api/dsh-novel-forge/llm-vendors',
79
+ /** 查询某个 provider 当前可用的模型(添加成功后可即时刷新)。 */
80
+ llmModels: '/api/dsh-novel-forge/llm-models',
81
+ /** 已注册的提供方路由列表(提供方管理)。 */
82
+ llmProviders: '/api/dsh-novel-forge/llm-providers',
83
+ /** 移除一个提供方。 */
84
+ llmRemove: '/api/dsh-novel-forge/llm-remove',
85
+ /** 重置项目(可选携带新大纲):清空设定/卷/章节/伏笔/资产/事实库。 */
86
+ reset: '/api/dsh-novel-forge/reset',
87
+ /** 全书一致性质检:LLM 扫描已生成章节,输出矛盾问题清单。 */
88
+ audit: '/api/dsh-novel-forge/audit',
89
+ /** 角色卡刷新:基于事实库与各章摘要聚合角色当前状态。 */
90
+ charactersRefresh: '/api/dsh-novel-forge/characters/refresh',
91
+ /** 事实库回填:对历史已生成章节批量抽取事实(旧章节无事实记录时用)。 */
92
+ factsBackfill: '/api/dsh-novel-forge/facts/backfill',
93
+ /** 道藏局部修补(如世界观规则编辑)。 */
94
+ biblePatch: '/api/dsh-novel-forge/bible/patch',
95
+ /** 小说简介:生成(AI)/补全(AI)/保存。 */
96
+ blurb: '/api/dsh-novel-forge/blurb',
97
+ /** 重命名当前书(同步项目与书架条目)。 */
98
+ rename: '/api/dsh-novel-forge/rename',
99
+ /** 大世界:提炼 / 保存结构化数据(境界/区域/势力)。 */
100
+ world: '/api/dsh-novel-forge/world',
101
+ /** 封面:GET 读取(dataUrl)/ POST 上传或移除。 */
102
+ cover: '/api/dsh-novel-forge/blurb/cover',
103
+ /** 剧情线管理:增删改 + 关联章节。 */
104
+ plotlines: '/api/dsh-novel-forge/plotlines',
105
+ /** 角色库:提炼 / 采纳 / 更新 / 删除。 */
106
+ roles: '/api/dsh-novel-forge/roles',
107
+ /** 作者复盘补跑:对已写章节补齐 authorReview(全书流式 / 单章 JSON)。 */
108
+ reviewBackfill: '/api/dsh-novel-forge/review/backfill',
109
+ /** 章节复位:generating 卡死 → pending(可重新生成)。 */
110
+ chapterReset: '/api/dsh-novel-forge/chapter/reset',
111
+ /** 章节直接通过:作者对 rejected/written 章节行使最终决定权。 */
112
+ chapterApprove: '/api/dsh-novel-forge/chapter/approve',
113
+ /** 敏感词检查:全书已写章节或指定文本。 */
114
+ sensitiveCheck: '/api/dsh-novel-forge/sensitive-check',
115
+ /** 开书想法 → 补全大纲:输入一句话想法,生成 2-3 个可选大纲方案。 */
116
+ outlineSuggest: '/api/dsh-novel-forge/outline/suggest',
117
+ /** 反推大纲:从已写章节正文反向生成全书总纲(NDJSON 流)。 */
118
+ outlineReverse: '/api/dsh-novel-forge/outline/reverse',
119
+ /** 拆书分析:对已写章节做结构/人物/文风/卖点四维体检(两阶段:源笔记→分节分析)。 */
120
+ breakdown: '/api/dsh-novel-forge/breakdown',
121
+ /** 生产单:启动批量生产(计划补足 + 逐章生成 + 被拒分级处理)。 */
122
+ runStart: '/api/dsh-novel-forge/run/start',
123
+ /** 生产单控制:pause / resume / stop。 */
124
+ runControl: '/api/dsh-novel-forge/run/control',
125
+ /** 生产单状态(含进度统计与日志)。 */
126
+ runStatus: '/api/dsh-novel-forge/run/status',
127
+ config: '/api/dsh-novel-forge/config',
128
+ /** 输出目录迁移:dryRun 预览 / 确认后搬文件并联动配置与书架。 */
129
+ moveOutputDir: '/api/dsh-novel-forge/move-output-dir',
130
+ /** 本书参数:POST {} 读取;POST {patch} 合并保存(存 novel-project.json)。 */
131
+ bookSettings: '/api/dsh-novel-forge/book-settings',
132
+ openFolder: '/api/dsh-novel-forge/open-folder',
133
+ /** 插件自更新:在 DSH profile 目录拉取最新 npm 版(下载后需重启 DSH 生效)。 */
134
+ pluginUpdate: '/api/dsh-novel-forge/plugin/update',
135
+ /** 作者资产库/总数据:读取个人跨书资产(笔法/红线/套路/角色模板/世界观模板)。 */
136
+ authorAssets: '/api/dsh-novel-forge/author-assets',
137
+ /** 作者资产库:新增/更新一条资产(upsert by id)。 */
138
+ authorAssetsUpsert: '/api/dsh-novel-forge/author-assets/upsert',
139
+ /** 作者资产库:删除一条资产。 */
140
+ authorAssetsRemove: '/api/dsh-novel-forge/author-assets/remove',
141
+ /** 作者资产库:导入默认(书架书的写作资产/角色 + 内置全局库)批量沉淀。 */
142
+ authorAssetsImportDefault: '/api/dsh-novel-forge/author-assets/import-default',
143
+ /** 改编模式:上传全文 → 分析 → 原文设定卡片/可改范围矩阵。 */
144
+ adaptAnalyze: '/api/dsh-novel-forge/adapt/analyze',
145
+ /** 改编模式:确认要改的维度 → 生成映射表/改编规则/联动影响清单。 */
146
+ adaptPropose: '/api/dsh-novel-forge/adapt/propose',
147
+ /** 改编模式:执行术语替换(全局替换 + 命中统计 + 改编文本预览)。 */
148
+ adaptExecute: '/api/dsh-novel-forge/adapt/execute',
149
+ /** 改编模式:保存改编全文为新书(原书保留,登记书架)。 */
150
+ adaptSave: '/api/dsh-novel-forge/adapt/save',
151
+ /** 改编模式:从源全文 + 编辑后方案提炼新书资料并保存为「待写新书」。 */
152
+ adaptMaterialize: '/api/dsh-novel-forge/adapt/materialize',
153
+ /** 改编模式:rewrite 逐章重写(NDJSON 流式进度)。 */
154
+ adaptRewriteStream: '/api/dsh-novel-forge/adapt/rewrite-stream',
155
+ /** 改编模式:把预览/微调后的新书资料写入并登记书架。 */
156
+ adaptMaterializeSave: '/api/dsh-novel-forge/adapt/materialize-save',
157
+ /** 主题自定义背景:上传图片(POST,存盘并返回服务端 URL)。 */
158
+ themeBackgroundUpload: '/api/dsh-novel-forge/theme/background',
159
+ /** 主题自定义背景:读取已上传文件(GET prefix,/theme/background/<name>)。 */
160
+ themeBackgroundGet: '/api/dsh-novel-forge/theme/background',
161
+ } as const
162
+
163
+ /** 书架:一本书的条目。 */
164
+ export interface BookEntry {
165
+ /** 稳定 id。 */
166
+ id: string
167
+ /** 书名。 */
168
+ bookName: string
169
+ /** 该书输出目录(独立项目目录)。 */
170
+ outputDir: string
171
+ /** 创建时间。 */
172
+ createdAt: string
173
+ /** 最后活动时间。 */
174
+ updatedAt: string
175
+ }
176
+
177
+ /** 书架快照(含每本书的进度摘要)。 */
178
+ export interface BookshelfSnapshot {
179
+ books: Array<BookEntry & { done: number; total: number; hasProject: boolean; hasCover: boolean; blurb?: string }>
180
+ /** 当前激活的书 id(无则 null)。 */
181
+ activeBookId: string | null
182
+ }
183
+
184
+ /** POST /bookshelf 请求:创建新书。 */
185
+ export interface BookCreateRequest {
186
+ bookName: string
187
+ outputDir?: string
188
+ /** 开书向导:创建时直接导入的大纲文本(提供则立即建立项目)。 */
189
+ outline?: string
190
+ }
191
+
192
+ /** POST /reset 请求:重置项目(可选更新大纲)。 */
193
+ export interface ResetRequest {
194
+ /** 新大纲文本;提供则替换 outline,否则保留原大纲。 */
195
+ outline?: string
196
+ }
197
+
198
+ /** POST /bookshelf/activate 请求:切换当前书。 */
199
+ export interface BookActivateRequest {
200
+ id: string
201
+ }
202
+
203
+ /** POST /bookshelf/remove 请求:移除书架条目。 */
204
+ export interface BookRemoveRequest {
205
+ id: string
206
+ }
207
+
208
+ /** POST /bookshelf/import-dir 请求:导入已有项目目录。 */
209
+ export interface BookImportDirRequest {
210
+ /** 项目目录(须含 novel-project.json)。 */
211
+ outputDir: string
212
+ }
213
+
214
+ /** POST /bookshelf/import-dir 响应。 */
215
+ export interface BookImportDirResponse {
216
+ book: BookEntry
217
+ /** true = 目录已在书架中(本次为重新激活)。 */
218
+ existed: boolean
219
+ }
220
+
221
+ /** POST /bookshelf/import-text 请求:导入 txt/md 全本。两种模式二选一:
222
+ * - filePath:服务器本地文件路径;
223
+ * - text + fileName:浏览器上传的全文内容(fileName 用于推断书名)。
224
+ */
225
+ export interface BookImportTextRequest {
226
+ /** 模式一:源文件绝对路径(txt 或 md)。 */
227
+ filePath?: string
228
+ /** 模式二:浏览器上传的全文内容。 */
229
+ text?: string
230
+ /** 模式二:原文件名(txt/md),用于推断书名与显示。 */
231
+ fileName?: string
232
+ /** 输出目录;缺省为「输出目录」设置下的书名子目录。 */
233
+ outputDir?: string
234
+ }
235
+
236
+ /** POST /bookshelf/import-text 响应。 */
237
+ export interface BookImportTextResponse {
238
+ bookName: string
239
+ /** 成功拆出的章节数。 */
240
+ chapters: number
241
+ /** 因内容过短被跳过的章节标题列表。 */
242
+ skipped: string[]
243
+ /** 登记后的书架条目。 */
244
+ book: BookEntry
245
+ }
246
+
247
+ /** POST /bookshelf/import-text/preview 请求:上传全文做拆章预览(不落盘)。 */
248
+ export interface BookImportTextPreviewRequest {
249
+ text: string
250
+ /** 原文件名(txt/md),用于推断书名。 */
251
+ fileName?: string
252
+ }
253
+
254
+ /** POST /bookshelf/import-text/preview 响应。 */
255
+ export interface BookImportTextPreviewResponse {
256
+ /** 预计书名(fileName 去扩展名)。 */
257
+ bookName: string
258
+ /** 识别出的章节(已按正文长度过滤过短章节)。 */
259
+ chapters: Array<{ no: number; title: string; chars: number }>
260
+ /** 因内容过短被跳过的章节标题列表。 */
261
+ skipped: string[]
262
+ }
263
+
264
+ /** Chapter lifecycle states (the writing pipeline's state machine). */
265
+ export type ChapterStatus =
266
+ | 'pending' // planned, not started
267
+ | 'generating' // LLM writing right now
268
+ | 'written' // body on disk, awaiting review
269
+ | 'reviewing' // review in progress
270
+ | 'approved' // passed review (or user-approved)
271
+ | 'rejected' // review found problems
272
+ | 'error' // generation failed
273
+
274
+ /** One chapter in the plan. */
275
+ export interface ChapterPlan {
276
+ /** 1-based chapter number (stable identity; files are named from it). */
277
+ no: number
278
+ /** Volume this chapter belongs to (1-based; 0 = unassigned). */
279
+ volume: number
280
+ /** Chapter title, decided by the LLM plan step. */
281
+ title: string
282
+ /** Story beats / plot points for this chapter (model-facing guidance). */
283
+ beats: string
284
+ /** Target character count (defaults to the configured chapter size). */
285
+ targetChars: number
286
+ /** 本章必达项(必须推进的局面/关系/信息/风险/决策变化)。 */
287
+ mustAdvance?: string[]
288
+ /** 本章必须保持/不得破坏的项(如人物状态、已有伏笔不提前揭)。 */
289
+ mustPreserve?: string[]
290
+ /** 本章不可违背的人物硬事实(身份/阵营/境界/当前位置/知情度)。 */
291
+ characterHardFacts?: string[]
292
+ /** 伏笔操作指令(seed/touch/pressure/partial_reveal/payoff/forbid)。 */
293
+ payoffDirectives?: Array<{ no?: number; operation?: 'seed' | 'touch' | 'pressure' | 'partial_reveal' | 'payoff' | 'forbid'; text?: string }>
294
+ /** 章末钩子要求(悬念/反转/新线索/未闭合选择)。 */
295
+ endingHook?: string
296
+ /** 本章义务合约(人类可读摘要,供生成与审稿共同锚定)。 */
297
+ obligation?: string
298
+ /** Generation/review state. */
299
+ status: ChapterStatus
300
+ /** 进入 generating 的时间(用于超时自动复位;未在生成时无此字段)。 */
301
+ generatingAt?: string
302
+ /** Actual character count once generated. */
303
+ chars?: number
304
+ /** Failure message when status is 'error'. */
305
+ error?: string
306
+ /** Output file name once generated (relative to the output dir). */
307
+ file?: string
308
+ /** LLM summary of the chapter (narrative memory for later chapters). */
309
+ summary?: string
310
+ /** Latest review report (present once reviewed). */
311
+ review?: ReviewReport
312
+ /** 作者复盘:钩子兑现/结尾钩子/剧情线推进/连续性/节奏趋势(生成后自动)。 */
313
+ authorReview?: AuthorReview
314
+ /** 本章目标张力 0-100(规划或作者设定;用于张力曲线)。 */
315
+ tension?: number
316
+ /** 本章实际张力 0-100(审稿时模型打分;缺省时回落到 review.tension)。 */
317
+ tensionActual?: number
318
+ /**
319
+ * 待确认草稿:润色(去AI味)或整章重写的产物正文。生成时先存这里,
320
+ * 用户看过对比后点「采纳」才覆盖正文文件;点「放弃」则丢弃。刷新页面不丢失。
321
+ */
322
+ pendingDraft?: string
323
+ }
324
+
325
+ /** 作者复盘:叙事结构层面的逐章检查(钩子/推进/连续性/趋势)。 */
326
+ export interface AuthorReview {
327
+ /** 上一章结尾钩子是否在本章兑现。 */
328
+ hookHonored: boolean
329
+ /** 钩子兑现说明(未兑现时给出建议)。 */
330
+ hookNote: string
331
+ /** 本章结尾钩子强度 0-10。 */
332
+ endingHook: number
333
+ /** 剧情线推进情况(推进了哪条线/或未推进)。 */
334
+ plotlineProgress: string
335
+ /** 结构化:本章推进的剧情线名称列表(与项目剧情线 name 精确匹配,复盘后自动关联章节)。 */
336
+ advancedLines?: string[]
337
+ /** 连续性检查(人物位置/时间/伤势/资源是否与上章衔接)。 */
338
+ continuity: string
339
+ /** 近期节奏趋势提示(拖沓/爽点密度等)。 */
340
+ trend: string
341
+ /** 本章发生的关键状态变化(人物状态/世界局面/关系/资源),用于回灌整本与事实库。 */
342
+ stateChanges?: string[]
343
+ /** 本章新引入或升级的冲突(供整本控制层与后续卷节奏参考)。 */
344
+ newConflicts?: string[]
345
+ /** 本章埋下/推进的新线索(供知识与伏笔系统回灌)。 */
346
+ clues?: string[]
347
+ /** 本章缺席但值得注意的角色及风险(卷级职责/缺席风险)。 */
348
+ absentRisks?: string[]
349
+ /** 复盘时间。 */
350
+ reviewedAt: string
351
+ }
352
+
353
+ /** 审稿维度(结构化定位问题类别)。权威清单是 reviewSystemPrompt 里的九条维度。 */
354
+ export type ReviewDimension = 'character' | 'setting' | 'redline' | 'writing' | 'pacing' | 'logic' | 'anti-ai' | 'presentation' | 'compliance'
355
+
356
+ /** One review finding. */
357
+ /** 问题严重度(审稿 / 时间线 / 张力共用)。 */
358
+ export type Severity = 'high' | 'medium' | 'low'
359
+
360
+ export interface ReviewIssue {
361
+ /** Severity: high = must fix, medium = should fix, low = suggestion. */
362
+ severity: Severity
363
+ /** 问题维度(可选;缺省由前端按 item 推断)。 */
364
+ dimension?: ReviewDimension
365
+ /** What the problem is. */
366
+ item: string
367
+ /** Concrete suggestion for fixing it. */
368
+ suggestion: string
369
+ /** 命中的反 AI 规则名(结构化,便于统计)。 */
370
+ ruleName?: string
371
+ /** 规则类别:forbidden / risk / encourage。 */
372
+ ruleType?: 'forbidden' | 'risk' | 'encourage'
373
+ /** 问题细分类(如 套话 句式 段落 心理 设定)。 */
374
+ category?: string
375
+ /** 命中的原文摘录。 */
376
+ excerpt?: string
377
+ /** 判定理由。 */
378
+ reason?: string
379
+ /** 是否可自动改写。 */
380
+ canAutoRewrite?: boolean
381
+ }
382
+
383
+ /** AI review report for one chapter. */
384
+ export interface ReviewReport {
385
+ /** Overall score 0-100. */
386
+ score: number
387
+ /** Pass threshold (config; 70 default). */
388
+ passed: boolean
389
+ /** One-line verdict. */
390
+ verdict: string
391
+ /** Individual findings. */
392
+ issues: ReviewIssue[]
393
+ /** 风险分 0-100(越高越需人工处理;源自 LLM 复核与本地扫描)。 */
394
+ riskScore?: number
395
+ /** 本地 AI 味指数 0-100(越高越像 AI;LLM 复核锚点,供 UI 展示)。 */
396
+ aiFlavor?: number
397
+ /** 本地扫描命中的高频套话(按次数降序,取前若干)。 */
398
+ aiPhrases?: Array<{ word: string; count: number }>
399
+ /** 本章张力 0-100(审稿模型评分;用于张力曲线的"实际"值)。 */
400
+ tension?: number
401
+ /** When the review ran. */
402
+ reviewedAt: string
403
+ }
404
+
405
+ /** A volume of the book. */
406
+ export interface Volume {
407
+ /** 1-based volume number. */
408
+ no: number
409
+ /** Volume title. */
410
+ title: string
411
+ /** Volume positioning / summary. */
412
+ summary: string
413
+ /** First chapter number of this volume. */
414
+ chapterStart: number
415
+ /** Last chapter number (inclusive). */
416
+ chapterEnd: number
417
+ /** 卷级战略(这一卷的定位/承转,如「立威卷」「冲突升级卷」)。 */
418
+ strategy?: string
419
+ /** 卷节奏板(这一卷的节奏安排:起-承-转-合/爽点密度/关键节点)。 */
420
+ pacing?: string
421
+ }
422
+
423
+ /** 开书定盘:面向读者的承诺与流派定位(生成/规划均可引用)。 */
424
+ export interface BookContract {
425
+ /** 一句话卖点/题材承诺。 */
426
+ promise?: string
427
+ /** 主推进模式名(从推进模式库选)。 */
428
+ primaryModeName?: string
429
+ /** 辅助推进模式名。 */
430
+ secondaryModeNames?: string[]
431
+ /** 整体文风基调(一句话)。 */
432
+ tone?: string
433
+ /** 目标平台(如「番茄」)。 */
434
+ targetPlatform?: string
435
+ }
436
+
437
+ /** 书内知识库文档(供生成/规划时检索注入的参考资料)。 */
438
+ export interface KnowledgeDoc {
439
+ id: string
440
+ title: string
441
+ content: string
442
+ updatedAt: string
443
+ }
444
+
445
+ /** POST /knowledge request:增删改知识库文档。 */
446
+ export interface KnowledgeRequest {
447
+ action: 'add' | 'remove' | 'replace'
448
+ doc?: { id?: string; title: string; content: string }
449
+ id?: string
450
+ }
451
+
452
+ /** POST /book-analysis request。 */
453
+ export interface BookAnalysisRequest {
454
+ text: string
455
+ }
456
+
457
+ /** 书分析/拆书结果。 */
458
+ export interface BookAnalysisResult {
459
+ sellingPoints: string[]
460
+ structure: string[]
461
+ lessons: string[]
462
+ risks: string[]
463
+ }
464
+
465
+ /** POST /idea-inspiration request。 */
466
+ export interface IdeaInspirationRequest {
467
+ idea: string
468
+ count?: number
469
+ }
470
+
471
+ /** 创意灵感结果:多方向开书灵感。 */
472
+ export interface IdeaInspirationResult {
473
+ ideas: Array<{ title: string; hook: string; genre: string; pov: string; payoff: string }>
474
+ }
475
+
476
+ /** POST /director request。 */
477
+ export interface DirectorRequest {
478
+ focus?: string
479
+ }
480
+
481
+ /** 自动导演编排建议(下一卷/阶段编排 + 修复再平衡)。 */
482
+ export interface DirectorAdvice {
483
+ summary: string
484
+ nextArc: string[]
485
+ pacing: string
486
+ risks: string[]
487
+ fixes: string[]
488
+ }
489
+
490
+ /** 自动导演「采纳」后生成的书内待办项。 */
491
+ export interface DirectorTodo {
492
+ id: string
493
+ text: string
494
+ /** 来源:风险 或 修复。 */
495
+ source: 'risk' | 'fix'
496
+ done: boolean
497
+ createdAt: string
498
+ }
499
+
500
+ /** 题材雷达:单条市场信号。 */
501
+ export interface MarketRadarSignal {
502
+ id: string
503
+ kind: 'genre' | 'protagonist' | 'advantage' | 'opening' | 'relationship' | 'title_pattern' | 'opportunity' | 'crowding'
504
+ title: string
505
+ detail: string
506
+ /** 趋势:current / rising / stable / falling。 */
507
+ direction?: 'current' | 'rising' | 'stable' | 'falling'
508
+ /** 是否建议优先考虑。 */
509
+ recommended?: boolean
510
+ }
511
+
512
+ /** 题材雷达:生产底座(引用内置题材/推进模式库,或给出新资产)。 */
513
+ export interface ProductionFoundation {
514
+ genre: { existingId?: string; name: string; description: string; template?: string }
515
+ primaryStoryMode: { existingId?: string; name: string; driver: string; readerExpectation: string }
516
+ secondaryStoryMode?: { existingId?: string; name: string; driver: string; readerExpectation: string }
517
+ }
518
+
519
+ /** 题材雷达:开书创意简报(可执行,严禁照搬具体作品/命名)。 */
520
+ export interface MarketCreativeBrief {
521
+ promptBlock: string
522
+ openingIdea: string
523
+ coreAdvantage: string
524
+ bookSellingPoint: string
525
+ first30ChapterPromise: string
526
+ }
527
+
528
+ /** 题材雷达结果。 */
529
+ export interface MarketRadarResult {
530
+ signals: MarketRadarSignal[]
531
+ productionFoundation: ProductionFoundation
532
+ /** 开书创意简报(可选;用「用信号创作」接口单独生成)。 */
533
+ creativeBrief?: MarketCreativeBrief
534
+ /**
535
+ * 本次分析的报告 id(服务端生成)。
536
+ *
537
+ * 前端据此判断「是否换了一份新报告」:只有报告变了才重置信号勾选,否则重渲染/
538
+ * 轮询会把作者手选的信号冲掉。缺省(旧版产物)时前端按「首次看到」处理。
539
+ */
540
+ reportId?: string
541
+ }
542
+
543
+ /** POST /market-radar request。 */
544
+ export interface MarketRadarRequest {
545
+ platform?: string
546
+ genre?: string
547
+ keywords?: string
548
+ feedText?: string
549
+ /** 已扫描的上榜记录(来自真实榜单抓取),用于让分析基于真实榜单证据。 */
550
+ candidates?: Array<{ title: string; author?: string; tags?: string[]; synopsis?: string; category?: string; heatLabel?: string }>
551
+ }
552
+
553
+ /** POST /market-radar/brief request:用选中的信号 + 影响模式生成开书创意。 */
554
+ export interface MarketRadarBriefRequest {
555
+ influenceMode: 'follow_hot' | 'differentiate' | 'light'
556
+ signals: MarketRadarSignal[]
557
+ }
558
+
559
+ /** A character card from the story bible. */
560
+ export interface CharacterCard {
561
+ name: string
562
+ role: 'protagonist' | 'supporting' | 'antagonist' | 'other'
563
+ /** Personality / traits (short lines). */
564
+ traits: string[]
565
+ /** Goals and motivations. */
566
+ goals: string
567
+ /** Key relations to other characters. */
568
+ relations: string
569
+ /** 知情度:该角色已经知道的事实/秘密(未列出的信息该角色不知道)。 */
570
+ knowledge?: string[]
571
+ }
572
+
573
+ /** The structured story bible (worldbuilding extracted from the outline). */
574
+ export interface StoryBible {
575
+ /** Genre + tone tags. */
576
+ genre: string
577
+ /** Worldbuilding rules (power system, geography, factions...). */
578
+ worldRules: string[]
579
+ /** Character cards. */
580
+ characters: CharacterCard[]
581
+ /** Writing red lines (forbidden content / must-avoid tropes). */
582
+ redLines: string[]
583
+ /** Style guidance (pacing, pov, tone). */
584
+ style: string[]
585
+ /** When the bible was generated. */
586
+ generatedAt?: string
587
+ }
588
+
589
+ /** A planted/active/resolved foreshadowing thread. */
590
+ /** 修订建议来源:审稿 / 时间线 / 张力。 */
591
+ export type RevisionSource = 'review' | 'timeline' | 'tension'
592
+
593
+ /** 一条待修订条目(合并层排序后的最小单位)。 */
594
+ export interface RevisionItem {
595
+ /** 稳定 id(source:chapter:index)。 */
596
+ id: string
597
+ source: RevisionSource
598
+ severity: Severity
599
+ /** 归属章节号(0 = 全书级)。 */
600
+ chapterNo: number
601
+ item: string
602
+ suggestion: string
603
+ /** 去重时合并掉的同类条数(>=2 时展示)。 */
604
+ count?: number
605
+ }
606
+
607
+ /** POST /revision/plan 请求:把该章三类建议合并成一份修订指令。 */
608
+ export interface RevisionPlanRequest {
609
+ op: 'plan'
610
+ chapterNo?: number
611
+ /** 显式指定的审稿意见(面板勾选后传入;缺省取已落盘报告)。 */
612
+ reviewIssues?: ReviewIssue[]
613
+ includeTimeline?: boolean
614
+ includeTension?: boolean
615
+ bookId?: string
616
+ }
617
+
618
+ /** POST /revision/plan 响应。 */
619
+ export interface RevisionPlanResponse {
620
+ chapterNo: number
621
+ items: RevisionItem[]
622
+ /** 唯一修订指令(面板直接把它交给 /rewrite)。 */
623
+ instruction: string
624
+ counts: Record<RevisionSource, number>
625
+ /** 因上限被截断的条数。 */
626
+ omitted: number
627
+ /** 验证基准(复核时逐条核对本轮下发的全部条目)。 */
628
+ baseline: ReviewReport
629
+ /** 一行摘要。 */
630
+ summary: string
631
+ }
632
+
633
+ /**
634
+ * 张力曲线形状预设:
635
+ * `escalation` 递进爬升 / `suspense` 悬疑加压 / `wave` 波浪呼吸 /
636
+ * `frontLoad` 前紧后稳 / `flat` 平稳推进 / `custom` 自定义。
637
+ */
638
+ export type TensionCurvePreset = 'escalation' | 'suspense' | 'wave' | 'frontLoad' | 'flat' | 'custom'
639
+
640
+ /** 张力曲线配置(随项目保存)。 */
641
+ export interface TensionCurveConfig {
642
+ preset: TensionCurvePreset
643
+ /** preset=custom 时的逐章采样(0-100;缺省按章节数取默认值)。 */
644
+ custom?: number[]
645
+ }
646
+
647
+ /** 张力曲线的一条问题(实际 vs 目标 / 曲线形状)。 */
648
+ export interface TensionIssue {
649
+ severity: 'high' | 'medium' | 'low'
650
+ chapters: number[]
651
+ item: string
652
+ suggestion: string
653
+ }
654
+
655
+ /** 张力曲线数据点(面板绘图用)。 */
656
+ export interface TensionCurvePoint {
657
+ no: number
658
+ title: string
659
+ /** 目标张力。 */
660
+ target?: number
661
+ /** 实际张力(审稿打分)。 */
662
+ actual?: number
663
+ /** 参考曲线在此处的取值。 */
664
+ reference?: number
665
+ }
666
+
667
+ /** GET /tension 响应。 */
668
+ export interface TensionResponse {
669
+ preset: TensionCurvePreset
670
+ points: TensionCurvePoint[]
671
+ /** 规则核对发现的问题。 */
672
+ issues: TensionIssue[]
673
+ }
674
+
675
+ /** POST /tension 请求。 */
676
+ export interface TensionRequest {
677
+ op: 'preset' | 'set' | 'clear'
678
+ preset?: TensionCurvePreset
679
+ chapterNo?: number
680
+ /** op=set 时的目标张力(0-100)。 */
681
+ tension?: number
682
+ }
683
+
684
+ /** 允许作者编辑的提示词槽位 id(白名单)。 */
685
+ export type PromptSlotId = 'styleExtra' | 'antiAiExtra' | 'dialogueExtra' | 'endingHookExtra'
686
+
687
+ /** 一个提示词槽位的当前内容。 */
688
+ export interface PromptSlotState {
689
+ id: PromptSlotId
690
+ label: string
691
+ hint: string
692
+ placeholder: string
693
+ maxChars: number
694
+ value: string
695
+ }
696
+
697
+ /** GET /prompt-slots 响应。 */
698
+ export interface PromptSlotsResponse {
699
+ slots: PromptSlotState[]
700
+ }
701
+
702
+ /** POST /prompt-slots 请求:设置或清空一个槽位。 */
703
+ export interface PromptSlotsRequest {
704
+ id: PromptSlotId
705
+ /** 空串 = 清空该槽位(恢复默认)。 */
706
+ value: string
707
+ }
708
+
709
+ /**
710
+ * 故事时间线事件:从章节正文抽取的「故事内时间点 + 地点 + 参与角色 + 事件」。
711
+ * 用途:后续章节的时间连续性与地点衔接(比编年录更强调"顺序")。
712
+ */
713
+ export interface TimelineEvent {
714
+ /** 稳定 id(时间线内唯一)。 */
715
+ id: string
716
+ /** 所属章节号。 */
717
+ chapterNo: number
718
+ /** 故事内时间点(如「第三日黄昏」「入宗三个月后」「同日夜」)。 */
719
+ time: string
720
+ /** 相对顺序(同书内递增;无法判断时缺省)。用于检测时间倒流。 */
721
+ order?: number
722
+ /** 地点。 */
723
+ place: string
724
+ /** 参与角色(角色名)。 */
725
+ characters: string[]
726
+ /** 事件一句话。 */
727
+ event: string
728
+ /** 来源:模型抽取 / 作者手改。 */
729
+ source: 'extracted' | 'manual'
730
+ createdAt: string
731
+ }
732
+
733
+ /** 时间线矛盾(规则初筛 + AI 复核)。 */
734
+ export interface TimelineIssue {
735
+ severity: 'high' | 'medium' | 'low'
736
+ /** 定位到的章节(可多个)。 */
737
+ chapters: number[]
738
+ /** 问题描述。 */
739
+ item: string
740
+ /** 建议修法。 */
741
+ suggestion: string
742
+ }
743
+
744
+ /** GET /timeline 响应。 */
745
+ export interface TimelineResponse {
746
+ events: TimelineEvent[]
747
+ /** 规则初筛发现的问题(瞬时计算,不落盘)。 */
748
+ issues?: TimelineIssue[]
749
+ }
750
+
751
+ /** POST /timeline 请求:op=extract 抽单章 / check 全量检查 / update 手改 / remove 删除 / clear 清空。 */
752
+ export interface TimelineRequest {
753
+ op: 'extract' | 'check' | 'update' | 'remove' | 'clear'
754
+ chapterNo?: number
755
+ event?: TimelineEvent
756
+ id?: string
757
+ }
758
+
759
+ export interface Foreshadow {
760
+ /** Stable id. */
761
+ id: string
762
+ /** What the foreshadow is. */
763
+ description: string
764
+ /** Chapter where it was planted (undefined = planned). */
765
+ plantedChapter?: number
766
+ /** Chapter where it should be paid off. */
767
+ targetChapter?: number
768
+ /** Lifecycle state. */
769
+ status: 'planned' | 'planted' | 'progressing' | 'resolved' | 'abandoned'
770
+ /** Resolution note when resolved. */
771
+ resolvedNote?: string
772
+ }
773
+
774
+ /** 一条已确立的叙事事实(事实库/时间线,注入后续章节生成)。 */
775
+ export interface ChapterFact {
776
+ /** 来源章节号。 */
777
+ chapterNo: number
778
+ /** 事实文本(人物状态/境界资源/关系变化/伏笔落地等)。 */
779
+ text: string
780
+ }
781
+
782
+ /** 一条全书质检发现的问题(一致性矛盾,定位到章)。 */
783
+ export interface AuditIssue {
784
+ /** 问题所在章节号(无法定位时 0)。 */
785
+ chapterNo: number
786
+ severity: 'high' | 'medium' | 'low'
787
+ /** 矛盾描述。 */
788
+ item: string
789
+ /** 修改建议。 */
790
+ suggestion: string
791
+ }
792
+
793
+ /** POST /audit 响应。 */
794
+ export interface AuditResponse {
795
+ issues: AuditIssue[]
796
+ /** 参与质检的章节数。 */
797
+ auditedChapters: number
798
+ /** 质检时间。 */
799
+ auditedAt: string
800
+ /** 本次质检使用的模型(auditModel 或全局 model)。 */
801
+ model?: string
802
+ }
803
+
804
+ /** 全书质检的实时状态(通过 /status 暴露给面板/外部读取)。 */
805
+ export interface AuditStatus {
806
+ status: 'idle' | 'running' | 'done' | 'error'
807
+ /** 开始时间(ISO)。 */
808
+ startedAt?: string
809
+ /** 结束时间(ISO)。 */
810
+ finishedAt?: string
811
+ /** 总批次数(0 = 尚未开始/无章节)。 */
812
+ totalBatches: number
813
+ /** 已完成批次数。 */
814
+ completedBatches: number
815
+ /** 参与质检的章节数。 */
816
+ auditedChapters?: number
817
+ /** 发现的问题数(done 后有效)。 */
818
+ issuesCount?: number
819
+ /** 最近一次质检的问题清单(done 后有效;error 时为空)。 */
820
+ issues?: AuditIssue[]
821
+ /** 失败信息(error 时有效)。 */
822
+ error?: string
823
+ }
824
+
825
+ /** 一条剧情线(主线/支线/人物线/悬念线)。 */
826
+ export interface Plotline {
827
+ /** 稳定 id。 */
828
+ id: string
829
+ /** 线名。 */
830
+ name: string
831
+ /** 类型:主线 / 支线 / 人物线 / 悬念线。 */
832
+ kind: 'main' | 'branch' | 'character' | 'mystery'
833
+ /** 目标/终点(这条线最终要完成什么)。 */
834
+ goal: string
835
+ /** 当前进度说明(最近推进到哪)。 */
836
+ progress: string
837
+ /** 生命周期状态。 */
838
+ status: 'active' | 'paused' | 'resolved' | 'abandoned'
839
+ /** 关联章节号(推进/落地的章节)。 */
840
+ chapters: number[]
841
+ /** 创建时间。 */
842
+ createdAt: string
843
+ }
844
+
845
+ /** POST /plotlines 请求:剧情线增删改 + 关联章节 + AI 辅助。 */
846
+ export interface PlotlinesRequest {
847
+ op: 'add' | 'update' | 'remove' | 'link' | 'suggest' | 'refresh' | 'health' | 'plan'
848
+ /** add / update 时传入的完整剧情线。 */
849
+ line?: Plotline
850
+ /** remove / link / refresh 时的目标线 id。 */
851
+ id?: string
852
+ /** link 时关联的章节号。 */
853
+ chapterNo?: number
854
+ }
855
+
856
+ /** 剧情线健康检查报告。 */
857
+ export interface PlotlineHealthReport {
858
+ /** 是否需要新线(需要 / 暂不需要 / 再写 X 章后需要)。 */
859
+ verdict: string
860
+ /** 建议添加新线的时机说明。 */
861
+ timing: string
862
+ /** 依据(基于数据的理由,每条一句)。 */
863
+ reasons: string[]
864
+ /** 各线健康度。 */
865
+ lines: Array<{
866
+ name: string
867
+ /** ok=健康 / warning=预警 / stale=搁置过久。 */
868
+ health: 'ok' | 'warning' | 'stale'
869
+ note: string
870
+ }>
871
+ }
872
+
873
+ /** 剧情方案:下一阶段目标 + 建议新线。 */
874
+ export interface PlotlinePlan {
875
+ /** 下一阶段(未来 5-10 章)剧情方向。 */
876
+ direction: string
877
+ /** 建议的新线(可逐条采纳)。 */
878
+ suggestions: Plotline[]
879
+ }
880
+
881
+ /** POST /plotlines 响应。 */
882
+ export interface PlotlinesResponse {
883
+ plotlines: Plotline[]
884
+ /** op=suggest 时的 建议候选线。 */
885
+ suggestions?: Plotline[]
886
+ /** op=health 时的健康检查报告。 */
887
+ health?: PlotlineHealthReport
888
+ /** op=plan 时的剧情方案。 */
889
+ plan?: PlotlinePlan
890
+ }
891
+
892
+ /** 一条敏感词命中。 */
893
+ export interface SensitiveHit {
894
+ /** 命中章节号(文本检测时为 0)。 */
895
+ chapterNo: number
896
+ /** 命中的违禁词。 */
897
+ word: string
898
+ /** 类别:政治 / 擦边 / 暴力 / 辱骂 / 广告 / 其他。 */
899
+ category: string
900
+ /** 出现次数。 */
901
+ count: number
902
+ }
903
+
904
+ /** POST /sensitive-check 请求:检测指定章节/任意文本/全书。 */
905
+ export interface SensitiveCheckRequest {
906
+ /** 检测该章正文。 */
907
+ chapterNo?: number
908
+ /** 检测任意文本(优先于 chapterNo)。 */
909
+ text?: string
910
+ /** 扫描全部已写章节。 */
911
+ all?: boolean
912
+ }
913
+
914
+ /** POST /sensitive-check 响应。 */
915
+ export interface SensitiveCheckResponse {
916
+ hits: SensitiveHit[]
917
+ /** 参与扫描的章节数。 */
918
+ scannedChapters: number
919
+ }
920
+
921
+ /** 开书想法 → AI 大纲方案(一个候选)。 */
922
+ export interface OutlineCandidate {
923
+ /** 唯一 id(前端暂留/换批用)。 */
924
+ id: string
925
+ /** 推荐书名。 */
926
+ bookName: string
927
+ /** 题材(如 仙侠修真 / 都市)。 */
928
+ genre: string
929
+ /** 核心卖点一句话。 */
930
+ sellingPoint: string
931
+ /** 完整大纲文本(可直接用作项目大纲,≥800 字)。 */
932
+ outline: string
933
+ }
934
+
935
+ /** POST /outline/suggest 请求:想法 → 2-3 个可选大纲。 */
936
+ export interface OutlineSuggestRequest {
937
+ /** 作者想法(一两句话,≥50 字)。 */
938
+ idea: string
939
+ /** 本次要生成的候选数(默认 3,最多 3)。 */
940
+ count?: number
941
+ /** 已暂留方案的剧情方向摘要(换批时让 LLM 避开,防止与已留方案重复)。 */
942
+ exclude?: string[]
943
+ }
944
+
945
+ /** POST /outline/suggest 响应。 */
946
+ export interface OutlineSuggestResponse {
947
+ candidates: OutlineCandidate[]
948
+ }
949
+
950
+ /** 拆书分析:一个分析小节。 */
951
+ export interface BreakdownSection {
952
+ /** 小节键:overview / plot / character / style / market。 */
953
+ key: string
954
+ /** 小节标题(如「拆书总览」)。 */
955
+ title: string
956
+ /** 可读分析稿(markdown)。 */
957
+ markdown: string
958
+ /** 结构化数据(程序可消费)。 */
959
+ structured: Record<string, unknown>
960
+ }
961
+
962
+ /** 拆书分析:一条证据(结论→原文回溯)。 */
963
+ export interface BreakdownEvidence {
964
+ label: string
965
+ excerpt: string
966
+ /** 来源章节号(0 = 未定位)。 */
967
+ chapterNo: number
968
+ /** 指向的结构化字段。 */
969
+ fieldKey?: string
970
+ }
971
+
972
+ /** POST /breakdown 请求:对已写章节做拆书分析。 */
973
+ export interface BreakdownRequest {
974
+ /** 分析范围:'recent'=最近 20 章 / 'volume:N'=第 N 卷 / 'all'=全书(默认 recent)。 */
975
+ scope?: string
976
+ /** 分析档位:'quick'=4 维(总览/剧情/人物/文风)/ 'standard'=5 维(+卖点)。 */
977
+ preset?: 'quick' | 'standard'
978
+ /** token 预算上限(默认 50000)。 */
979
+ budgetTokens?: number
980
+ }
981
+
982
+ /** POST /breakdown 响应。 */
983
+ export interface BreakdownResponse {
984
+ sections: BreakdownSection[]
985
+ evidence: BreakdownEvidence[]
986
+ /** 参与分析的章节数。 */
987
+ chaptersScanned: number
988
+ /** 估算消耗 token。 */
989
+ usedTokens: number
990
+ }
991
+
992
+ /** 角色卡:角色当前状态(从事实库聚合)。 */
993
+ export interface RoleStatusCard {
994
+ name: string
995
+ /** protagonist / supporting / antagonist / other。 */
996
+ role: string
997
+ /** 当前状态一句话(境界/资源/伤势/心境)。 */
998
+ status: string
999
+ /** 最近出场章节。 */
1000
+ lastChapter: number
1001
+ /** 出场次数。 */
1002
+ appearances: number
1003
+ }
1004
+
1005
+ /** 角色库条目(主表:作者维护 + 提炼 + 编年录自动聚合)。 */
1006
+ export interface RoleRecord {
1007
+ /** 角色名(唯一键)。 */
1008
+ name: string
1009
+ /** 定位:主角 / 女主 / 女配 / 配角 / 反派 / 路人。 */
1010
+ roleLabel: 'protagonist' | 'female_lead' | 'female_support' | 'support' | 'antagonist' | 'extra'
1011
+ /** 身份一句话(如:祭族后裔、青云宗杂役)。 */
1012
+ identity: string
1013
+ /** 性格标签。 */
1014
+ traits: string[]
1015
+ /** 目标与动机。 */
1016
+ goals: string
1017
+ /** 关系网:[角色名](关系)。 */
1018
+ relations: string[]
1019
+ /** 成长线:阶段 → 说明(可含章节)。 */
1020
+ arc: string[]
1021
+ /** 知情度:该角色已经知道的信息。 */
1022
+ knowledge: string[]
1023
+ /** 首次出场章节(编年录聚合,可手动修正)。 */
1024
+ firstChapter?: number
1025
+ }
1026
+
1027
+ /** POST /roles 请求:角色库增删改 + 提炼 + 参考图上传。 */
1028
+ export interface RolesRequest {
1029
+ op: 'extract' | 'adopt' | 'update' | 'remove'
1030
+ /** adopt / update 时传入的角色(adopt 可修改后采纳)。 */
1031
+ role?: RoleRecord
1032
+ /** remove 时的角色名。 */
1033
+ name?: string
1034
+ }
1035
+
1036
+
1037
+ /** POST /llm-test 请求:对选中的提供商/模型发一次最小真实调用。 */
1038
+ export interface LlmTestRequest {
1039
+ provider: string
1040
+ model: string
1041
+ }
1042
+
1043
+ /** POST /llm-test 响应。 */
1044
+ export interface LlmTestResponse {
1045
+ ok: boolean
1046
+ /** 连通延迟(毫秒)。 */
1047
+ ms?: number
1048
+ /** 失败原因(已映射为人话)。 */
1049
+ message?: string
1050
+ /** 稳定错误码(LlmError code),便于排查。 */
1051
+ code?: string
1052
+ }
1053
+
1054
+ /** POST /roles 响应。 */
1055
+ export interface RolesResponse {
1056
+ roles: RoleRecord[]
1057
+ /** op=extract 时的 AI 候选角色。 */
1058
+ candidates?: RoleRecord[]
1059
+ }
1060
+
1061
+ /** POST /bible/patch 请求:局部修补道藏。 */
1062
+ export interface BiblePatchRequest {
1063
+ worldRules?: string[]
1064
+ redLines?: string[]
1065
+ style?: string[]
1066
+ /** 角色卡整体替换(人物志编辑知情度等)。 */
1067
+ characters?: CharacterCard[]
1068
+ }
1069
+
1070
+ /** POST /blurb 请求:生成/补全或手动保存小说简介。 */
1071
+ export interface BlurbRequest {
1072
+ action: 'generate' | 'save'
1073
+ /** 已写好的开头(补全时使用;留空 = 全量生成)。 */
1074
+ partial?: string
1075
+ /** 手动保存的完整简介(action=save 时)。 */
1076
+ text?: string
1077
+ }
1078
+
1079
+ /** POST /chapter/check|save 请求:审查/保存手动编辑的正文。 */
1080
+ export interface ChapterTextRequest {
1081
+ chapterNo: number
1082
+ /** 当前编辑中的正文全文。 */
1083
+ text: string
1084
+ /** 保存时携带:已在工作区审查过的报告(沿用落盘,不重复审);缺省则保存后自动正式审稿一次。 */
1085
+ report?: ReviewReport
1086
+ /** 审查/验证时携带:上一轮审稿报告。传入后进入「验证模式」——逐条核对原意见是否解决、
1087
+ * 只挑新增 high,不再全新找茬(防止"越修 high 越多")。 */
1088
+ previousReport?: ReviewReport
1089
+ }
1090
+
1091
+ /** POST /chapter/save 响应。 */
1092
+ export interface ChapterSaveResponse {
1093
+ ok: boolean
1094
+ chars: number
1095
+ file: string
1096
+ /** 落盘的审稿报告(沿用工作区报告或保存后自动审稿)。 */
1097
+ report?: ReviewReport
1098
+ }
1099
+
1100
+ /** POST /cover 请求:上传或移除封面。 */
1101
+ export interface CoverRequest {
1102
+ action: 'upload' | 'remove'
1103
+ /** 上传时:data:image/...;base64,... 格式的图片数据。 */
1104
+ dataUrl?: string
1105
+ }
1106
+
1107
+ /** POST /rename 请求:重命名当前书。 */
1108
+ export interface RenameRequest {
1109
+ bookName: string
1110
+ }
1111
+
1112
+ /** 大世界:一个境界等级。 */
1113
+ export interface WorldRealm {
1114
+ /** 境界名(练气/筑基/金丹…)。 */
1115
+ name: string
1116
+ /** 描述:突破条件/寿命/标志等。 */
1117
+ description: string
1118
+ }
1119
+
1120
+ /** 大世界:一个地理区域。 */
1121
+ export interface WorldRegion {
1122
+ name: string
1123
+ description: string
1124
+ /** 关联势力名(可空)。 */
1125
+ faction?: string
1126
+ }
1127
+
1128
+ /** 大世界:一方势力。 */
1129
+ export interface WorldFaction {
1130
+ name: string
1131
+ /** 类型:宗门/家族/王朝/组织… */
1132
+ kind: string
1133
+ description: string
1134
+ /** 驻地区域(可空)。 */
1135
+ region?: string
1136
+ }
1137
+
1138
+ /** 大世界结构化数据。 */
1139
+ export interface WorldState {
1140
+ realms: WorldRealm[]
1141
+ regions: WorldRegion[]
1142
+ factions: WorldFaction[]
1143
+ }
1144
+
1145
+ /** POST /world 请求:提炼或手动保存。 */
1146
+ export interface WorldRequest {
1147
+ action: 'generate' | 'save'
1148
+ /** action=save 时的完整世界数据。 */
1149
+ world?: WorldState
1150
+ }
1151
+
1152
+ /** GET /cover 响应:封面的 dataUrl(无封面为 null)。 */
1153
+ export interface CoverResponse {
1154
+ dataUrl: string | null
1155
+ }
1156
+
1157
+ /** The persisted project: outline + bible + plan + progress. */
1158
+ export interface ProjectState {
1159
+ /** Book title (first non-empty line of the outline, usually). */
1160
+ bookName: string
1161
+ /** Full outline text (docx-extracted or pasted). */
1162
+ outline: string
1163
+ /** Source outline path when loaded from a docx. */
1164
+ outlinePath?: string
1165
+ /** Structured story bible (worldbuilding), if generated. */
1166
+ bible?: StoryBible
1167
+ /** Volumes, if planned. */
1168
+ volumes?: Volume[]
1169
+ /** Chapter plan. */
1170
+ chapters: ChapterPlan[]
1171
+ /** Foreshadowing threads. */
1172
+ foreshadows: Foreshadow[]
1173
+ /** 写作资产(题材基底/推进模式/反AI规则/写法资产)。 */
1174
+ assets?: ProjectAssets
1175
+ /** 事实库/时间线:每章生成后抽取,注入后续章节保持一致性。 */
1176
+ facts?: ChapterFact[]
1177
+ /** 书内知识库文档(可检索资料/设定/参考)。 */
1178
+ knowledgeDocs?: KnowledgeDoc[]
1179
+ /** 自动导演待办:风险/修复「采纳」后生成的随手清单。 */
1180
+ todos?: DirectorTodo[]
1181
+ /** 小说简介(面向读者的作品门面,生成或手动保存)。 */
1182
+ blurb?: string
1183
+ /** 开书定盘:书籍级承诺与流派定位(前30章承诺/主副模式/文风/平台)。 */
1184
+ bookContract?: BookContract
1185
+ /** 封面文件名(相对输出目录,如 cover.png)。 */
1186
+ coverPath?: string
1187
+ /** 大世界结构化数据(境界体系/区域/势力)。 */
1188
+ world?: WorldState
1189
+ /** 剧情线(主线/支线/人物线/悬念线)。 */
1190
+ plotlines?: Plotline[]
1191
+ /** 角色库(作者维护 + 提炼的主表)。 */
1192
+ roles?: RoleRecord[]
1193
+ /** 人物志:角色当前状态聚合结果(从编年录刷新后存档,打开页面直接显示)。 */
1194
+ roleStatus?: RoleStatusCard[]
1195
+ /** 故事时间线(逐章抽取:时间点 / 地点 / 参与角色 / 事件)。 */
1196
+ timeline?: TimelineEvent[]
1197
+ /** 张力曲线配置(形状预设 + 自定义采样)。 */
1198
+ tensionCurve?: TensionCurveConfig
1199
+ /** 作者自定义的提示词槽位(白名单见 prompt-slots.ts)。 */
1200
+ promptSlots?: Partial<Record<PromptSlotId, string>>
1201
+ /** 本书参数(写作/审稿/推理/模型快切;未设字段回退全局 config)。 */
1202
+ bookSettings?: BookSettings
1203
+ /** ISO timestamps. */
1204
+ createdAt: string
1205
+ updatedAt: string
1206
+ }
1207
+
1208
+ /** 本书参数(存 novel-project.json.bookSettings;未设字段回退全局 config)。 */
1209
+ export interface BookSettings {
1210
+ /** 本书使用的提供方路由(快切器写入)。 */
1211
+ provider?: string
1212
+ /** 本书使用的主模型 id。 */
1213
+ model?: string
1214
+ /** 本书写作推理档位。 */
1215
+ reasoningEffort?: 'off' | 'low' | 'high' | 'max'
1216
+ /** 本书分析类任务推理档位。 */
1217
+ analysisReasoning?: 'off' | 'low' | 'high' | 'max'
1218
+ /** 本书每章目标字数。 */
1219
+ chapterChars?: number
1220
+ /** 本书单章最大输出 tokens。 */
1221
+ maxTokens?: number
1222
+ /** 本书审稿通过分。 */
1223
+ reviewPassScore?: number
1224
+ /** 本书是否写完自动审稿。 */
1225
+ autoReview?: boolean
1226
+ /** 本书是否自动作者复盘。 */
1227
+ autoAuthorReview?: boolean
1228
+ /** 本书是否修稿后自动复审。 */
1229
+ autoReviewAfterRevise?: boolean
1230
+ }
1231
+
1232
+ /** 手动添加的模型库条目(只存插件内,不改 DSH 全局)。 */
1233
+ export interface SavedModel {
1234
+ /** 唯一 id(前端生成的短 id)。 */
1235
+ id: string
1236
+ /** 展示名(可为空,回退到 model)。 */
1237
+ name: string
1238
+ /** DSH 提供商路由(如 zai-coding-cn)。 */
1239
+ provider: string
1240
+ /** 模型 id(如 glm-5.3-flash)。 */
1241
+ model: string
1242
+ }
1243
+
1244
+ /** DSH 模型添加:厂商预设(选择厂商,直接填 API Key)。 */
1245
+ export interface LlmVendor {
1246
+ id: string
1247
+ name: string
1248
+ /** 该厂商对应的 provider 路由。 */
1249
+ route: string
1250
+ /** DSH 凭据引用名(写入 .credentials.yaml 的 refs)。 */
1251
+ apiKeyEnv: string
1252
+ /** 默认模型 id。 */
1253
+ defaultModel: string
1254
+ /** 建议可选模型 id 列表(下拉 data-list 用)。 */
1255
+ models: string[]
1256
+ /** 内置适配器(如 deepseek-official),无需注册 pi-ai 路由。 */
1257
+ builtin?: boolean
1258
+ }
1259
+
1260
+ /** 预置的常见厂商(id=provider 路由;添加模型下拉兜底用,其余厂商由运行时目录动态补充)。 */
1261
+ export const LLM_VENDORS: LlmVendor[] = [
1262
+ // 注意:本列表只是「运行时目录不可用」时的兜底建议值;实际以 ctx.llm.listModels() 为准
1263
+ // (见 engine.ts listLlmVendors),避免 DSH 侧模型改名后这里的条目过期。
1264
+ { id: 'deepseek-official', name: 'DeepSeek', route: 'deepseek-official', apiKeyEnv: 'DEEPSEEK_API_KEY', defaultModel: 'deepseek-flash', models: ['deepseek-flash', 'deepseek-v4-pro'], builtin: true },
1265
+ { id: 'zai-coding-cn', name: '智谱 GLM', route: 'zai-coding-cn', apiKeyEnv: 'ZAI_CODING_CN_API_KEY', defaultModel: 'glm-5.3-flash', models: ['glm-4.5-air', 'glm-4.7', 'glm-5-turbo', 'glm-5.1', 'glm-5.2', 'glm-5.3', 'glm-5.3-flash', 'glm-5v-turbo'] },
1266
+ { id: 'qwen-token-plan-cn', name: '千问百炼', route: 'qwen-token-plan-cn', apiKeyEnv: 'QWEN_TOKEN_PLAN_CN_API_KEY', defaultModel: 'qwen3.7-max', models: ['qwen3.6-flash', 'qwen3.6-plus', 'qwen3.7-max', 'qwen3.7-plus', 'qwen3.8-max', 'qwen3.8-max-preview'] },
1267
+ { id: 'openrouter', name: 'OpenRouter', route: 'openrouter', apiKeyEnv: 'OPENROUTER_API_KEY', defaultModel: 'z-ai/glm-5.3-flash', models: ['z-ai/glm-4.6', 'z-ai/glm-4.7', 'z-ai/glm-5', 'z-ai/glm-5-turbo', 'z-ai/glm-5.1', 'z-ai/glm-5.2', 'z-ai/glm-5.3-flash', 'auto', 'deepseek/deepseek-v4-flash', 'anthropic/claude-sonnet-4.6'] },
1268
+ ]
1269
+
1270
+ /** 运行时厂商目录的一项(添加到模型下拉;由 DSH 的 pi-ai 可配置提供方动态生成)。 */
1271
+ export interface LlmVendorOption {
1272
+ /** provider 路由 id(也是厂商下拉的值)。 */
1273
+ id: string
1274
+ /** 展示名。 */
1275
+ name: string
1276
+ /** 建议模型 id(可为空,用户手填)。 */
1277
+ models: string[]
1278
+ /** 已知 DSH 凭据引用名;为空时 host 生成 `PI_AI_<ID>_API_KEY`。 */
1279
+ apiKeyEnv?: string
1280
+ /** 内置适配器(只写凭据,不注册 pi-ai 路由)。 */
1281
+ builtin?: boolean
1282
+ }
1283
+
1284
+ /** GET /llm-vendors 响应。 */
1285
+ export interface LlmVendorsResponse {
1286
+ vendors: LlmVendorOption[]
1287
+ }
1288
+
1289
+ /** /llm-models 里的一条模型。 */
1290
+ export interface LlmModelOption { id: string; name: string }
1291
+
1292
+ /** GET /llm-models?provider=x 响应。 */
1293
+ export interface LlmModelsResponse {
1294
+ models: LlmModelOption[]
1295
+ }
1296
+
1297
+ /** GET /llm-providers 响应:当前已注册的提供方路由。 */
1298
+ export interface LlmProvidersResponse {
1299
+ providers: { id: string; name: string }[]
1300
+ }
1301
+
1302
+ /** POST /llm-remove 请求:移除一个提供方(unset key + 移除 llm-pi-ai 路由)。 */
1303
+ export interface RemoveProviderRequest {
1304
+ provider: string
1305
+ /** 该提供方对应的 DSH 凭据引用名(用于 unset)。 */
1306
+ apiKeyEnv?: string
1307
+ }
1308
+
1309
+ /** POST /llm-remove 响应。 */
1310
+ export interface RemoveProviderResponse {
1311
+ ok: boolean
1312
+ message?: string
1313
+ }
1314
+
1315
+ /** POST /llm-add 请求:添加一个模型(厂商直填 key,或自定义路由)。 */
1316
+ export interface AddModelRequest {
1317
+ mode: 'vendor' | 'custom'
1318
+ /** 厂商模式用:provider 路由 id(来自 /llm-vendors)。 */
1319
+ vendor?: string
1320
+ /** 厂商已知的 DSH 凭据引用名(可选;为空时 host 生成)。 */
1321
+ apiKeyEnv?: string
1322
+ /** 自定义模式用:provider 路由 id。 */
1323
+ provider?: string
1324
+ /** 模型 id。 */
1325
+ model: string
1326
+ /** API Key。 */
1327
+ apiKey: string
1328
+ /** 展示名(可选)。 */
1329
+ name?: string
1330
+ /** 自定义模式用:OpenAI 兼容 base URL。 */
1331
+ baseURL?: string
1332
+ }
1333
+
1334
+ /** POST /llm-add 响应。 */
1335
+ export interface AddModelResponse {
1336
+ ok: boolean
1337
+ saved: SavedModel
1338
+ provider: string
1339
+ message?: string
1340
+ }
1341
+
1342
+ /** 手动添加的模型库条目(只存插件内,不改 DSH 全局)。 */
1343
+ export interface NovelConfig {
1344
+ /** Absolute path of the default docx outline to load. */
1345
+ outlinePath: string
1346
+ /** Absolute output directory for chapters + project state. */
1347
+ outputDir: string
1348
+ /** LLM provider route (e.g. deepseek-official). */
1349
+ provider: string
1350
+ /** LLM model id (e.g. deepseek-flash). */
1351
+ model: string
1352
+ /** 生成正文用模型(缺省用 model)。 */
1353
+ generateModel?: string
1354
+ /** 审稿用模型(缺省用 model;建议用更强的 reasoner/pro)。 */
1355
+ reviewModel?: string
1356
+ /** 全书质检(审计)用模型(缺省用 model)。 */
1357
+ auditModel?: string
1358
+ /**
1359
+ * 备用模型:主模型调用失败(网络/限流/额度/服务不可用)时自动切换重试一次。
1360
+ * 留空表示不切换。批量连写时能显著减少"整批中断"。
1361
+ */
1362
+ fallbackModel?: string
1363
+ /** 是否在出章后自动抽取故事时间线(失败不阻断出章)。默认开。 */
1364
+ autoTimeline?: boolean
1365
+ /** LLM reasoning effort: off = no thinking; low/high/max = thinking intensity. */
1366
+ reasoningEffort: 'off' | 'low' | 'high' | 'max'
1367
+ /** 分析类任务(提炼/拆书/反推大纲等)的推理档位;默认 low,不受上面写作档位影响。 */
1368
+ analysisReasoning: 'off' | 'low' | 'high' | 'max'
1369
+ /** Target characters per chapter. */
1370
+ chapterChars: number
1371
+ /** Max output tokens per chapter call. */
1372
+ maxTokens: number
1373
+ /** Review pass threshold (0-100). */
1374
+ reviewPassScore: number
1375
+ /** Whether generation auto-runs review after writing. */
1376
+ autoReview: boolean
1377
+ /** Whether generation auto-runs the author review (hook/continuity/trend) after writing. */
1378
+ autoAuthorReview: boolean
1379
+ /** 修订/润色产出草稿后是否自动附带一次 AI 审查(工作区显示新稿评分与剩余问题)。 */
1380
+ autoReviewAfterRevise: boolean
1381
+ /** 自定义背景图(URL 或 dataURL 或服务端路径引用;空 = 使用主题默认背景)。 */
1382
+ themeBackground?: string
1383
+ /** 自定义背景遮罩/模糊强度 0-80(0 = 不遮罩)。 */
1384
+ themeBackgroundBlur?: number
1385
+ /** 玻璃透明度 0-100(100=当前原样,越小越透,新拟态/黏土可见背景图)。 */
1386
+ themeOpacity?: number
1387
+ /** 是否启用改编模式(默认关闭;发布后开启)。 */
1388
+ enableAdaptMode?: boolean
1389
+ /** 手动添加的模型库(「我的模型」条目;只存插件内)。 */
1390
+ savedModels?: SavedModel[]
1391
+ }
1392
+
1393
+ /** POST /move-output-dir request:dryRun=true 仅预览;确认时须带 to。 */
1394
+ export interface MoveOutputDirRequest {
1395
+ /** 新输出目录(绝对路径)。 */
1396
+ to?: string
1397
+ /** 只列出当前目录内容,不搬移。 */
1398
+ dryRun?: boolean
1399
+ }
1400
+
1401
+ /** POST /move-output-dir response。 */
1402
+ export interface MoveOutputDirResponse {
1403
+ from: string
1404
+ to?: string
1405
+ /** 当前(或迁移后)目录内容清单。 */
1406
+ files: string[]
1407
+ bytes: number
1408
+ /** 联动重指向的书架条目数。 */
1409
+ movedBooks: number
1410
+ /** settings 默认输出目录是否同步更新。 */
1411
+ defaultUpdated: boolean
1412
+ }
1413
+
1414
+ /** POST /book-settings request:patch 省略 = 读取;字段传 null = 删除本书覆盖(回退全局)。 */
1415
+ export interface BookSettingsRequest {
1416
+ patch?: { [K in keyof BookSettings]?: BookSettings[K] | null }
1417
+ }
1418
+
1419
+ /** POST /book-settings response。 */
1420
+ export interface BookSettingsResponse {
1421
+ /** 本书已设置的参数(未设字段缺省 = 回退全局)。 */
1422
+ settings: BookSettings
1423
+ /** 应用回退链后的生效配置(全局 + 本书覆盖)。 */
1424
+ effective: NovelConfig
1425
+ /** 当前是否有打开的书。 */
1426
+ hasBook: boolean
1427
+ }
1428
+
1429
+ /** GET /status response. */
1430
+ /**
1431
+ * 创作阶段契约(宿主计算的「当前阶段 → 本轮允许的动作」)。
1432
+ * 计算逻辑在 stage-contract.ts;这里是宿主与面板/助手共享的线上形状。
1433
+ */
1434
+ export interface StageInfo {
1435
+ /** 阶段标识。 */
1436
+ id: 'outline' | 'bible' | 'plan' | 'write' | 'wait' | 'review' | 'revise' | 'export'
1437
+ /** 中文阶段名。 */
1438
+ label: string
1439
+ /** 建议的下一步动作(助手工具名;无对应工具时为空数组)。 */
1440
+ recommend: string[]
1441
+ /** 本阶段允许的写操作(作者只说了「继续」时的唯一命令集)。 */
1442
+ allow: string[]
1443
+ /** 为什么处于该阶段。 */
1444
+ reason: string
1445
+ }
1446
+
1447
+ // ------------------------------------------------------------ LLM 实况 / 用量
1448
+
1449
+ /** 单次 LLM 调用的 token 用量(来自 dsh-llm 的 usage chunk)。 */
1450
+ export interface LlmTokenUsage {
1451
+ inputTokens: number
1452
+ outputTokens: number
1453
+ /** 供应商给出的总用量(缺失时由输入+输出推导)。 */
1454
+ totalTokens?: number
1455
+ /** 思考(reasoning)通道用量。 */
1456
+ reasoningTokens?: number
1457
+ /** 命中缓存的输入用量。 */
1458
+ cacheReadTokens?: number
1459
+ }
1460
+
1461
+ /** LLM 实况帧:宿主 → 浏览器的 SSE 事件(每次调用一组 session_* 事件)。 */
1462
+ export interface LlmLiveFrame {
1463
+ type: 'session_started' | 'output_delta' | 'reasoning_delta' | 'phase_changed' | 'session_completed'
1464
+ /** 宿主生成,形如 ll-<base36>-<n>。 */
1465
+ sessionId: string
1466
+ /** 本次调用用途(如 正文生成/审稿/章节规划)。 */
1467
+ label?: string
1468
+ /** 使用模型。 */
1469
+ model?: string
1470
+ /** 事件时间(ISO)。 */
1471
+ at: string
1472
+ /** session_started:交互上下文。 */
1473
+ context?: { taskId?: string; interactionId: string }
1474
+ /** output_delta / reasoning_delta:本次增量文本。 */
1475
+ content?: string
1476
+ /** session 累计字符数。 */
1477
+ totalChars?: number
1478
+ /** reasoning 累计字符数。 */
1479
+ totalReasoningChars?: number
1480
+ /** phase_changed:新阶段。 */
1481
+ phase?: 'requesting' | 'streaming' | 'completed' | 'failed'
1482
+ /** phase_changed:阶段描述。 */
1483
+ phaseMessage?: string
1484
+ /** session_completed:最终预览(截断)。 */
1485
+ preview?: string
1486
+ /** session_completed:失败信息。 */
1487
+ error?: string
1488
+ /** session_completed:本次用量(供应商未上报时缺省)。 */
1489
+ usage?: LlmTokenUsage
1490
+ /** session_completed:本次调用耗时(毫秒)。 */
1491
+ elapsedMs?: number
1492
+ /** session_completed:首字耗时(毫秒;未拿到文本时缺省)。 */
1493
+ firstTokenMs?: number
1494
+ /** session_started:是否已记录可查看的 Prompt(面板据此显示「查看 Prompt」)。 */
1495
+ hasPrompt?: boolean
1496
+ /** session_started:Prompt 字符数(system + user)。 */
1497
+ promptChars?: number
1498
+ }
1499
+
1500
+ /** 按用途分组的用量。 */
1501
+ export interface LlmUsageBucket {
1502
+ label: string
1503
+ calls: number
1504
+ failed: number
1505
+ inputTokens: number
1506
+ outputTokens: number
1507
+ reasoningTokens: number
1508
+ elapsedMs: number
1509
+ }
1510
+
1511
+ /** 本次运行(进程内,重启归零)的 LLM 用量汇总。 */
1512
+ export interface LlmUsageSummary {
1513
+ calls: number
1514
+ failed: number
1515
+ inputTokens: number
1516
+ outputTokens: number
1517
+ reasoningTokens: number
1518
+ totalTokens: number
1519
+ elapsedMs: number
1520
+ /** 供应商未上报 usage 的调用次数(用于说明数据为何不完整)。 */
1521
+ callsWithoutUsage: number
1522
+ byLabel: LlmUsageBucket[]
1523
+ }
1524
+
1525
+ /** 一次调用的 Prompt 记录(供面板查看「实际发送了什么」)。 */
1526
+ export interface LlmPromptRecord {
1527
+ sessionId: string
1528
+ label?: string
1529
+ model?: string
1530
+ at: string
1531
+ system?: string
1532
+ user?: string
1533
+ /** system + user 的字符数(记录被截断时仍给出原始长度)。 */
1534
+ chars: number
1535
+ /** 记录本身是否被截断。 */
1536
+ truncated?: boolean
1537
+ }
1538
+
1539
+ /** 章节历史版本(快照):覆盖写入前自动留存,可回滚。 */
1540
+ export interface ChapterSnapshot {
1541
+ id: string
1542
+ chapterNo: number
1543
+ /** 快照文件(相对书目录)。 */
1544
+ file: string
1545
+ /** 留存原因(生成覆盖 / 采纳草稿 / 修订 / 手工)。 */
1546
+ reason: string
1547
+ chars: number
1548
+ at: string
1549
+ }
1550
+
1551
+ /** GET /snapshot 响应。 */
1552
+ export interface SnapshotResponse {
1553
+ snapshots: ChapterSnapshot[]
1554
+ /** 快照占用字节数。 */
1555
+ bytes: number
1556
+ }
1557
+
1558
+ /** POST /snapshot 请求:op=create 手工存档 / restore 回滚 / remove 删除 / prune 只留最近 N 个。 */
1559
+ export interface SnapshotRequest {
1560
+ op: 'create' | 'restore' | 'remove' | 'prune'
1561
+ chapterNo?: number
1562
+ id?: string
1563
+ /** prune:每章保留数量。 */
1564
+ keep?: number
1565
+ }
1566
+
1567
+ export interface StatusResponse {
1568
+ config: NovelConfig
1569
+ /** The persisted project, when one exists in the output dir. */
1570
+ project?: ProjectState
1571
+ /** Chapter files already on disk (basenames, sorted). */
1572
+ generatedFiles: string[]
1573
+ /** 全书质检实时状态(用于面板/外部读取进度)。 */
1574
+ audit?: AuditStatus
1575
+ /** 宿主按项目真实状态算出的创作阶段(面板角标 / 外部自动化共用)。 */
1576
+ stage?: StageInfo
1577
+ /** 本次运行(进程内)的 LLM 用量汇总:调用次数 / 输入·输出·思考 token / 耗时。 */
1578
+ usage?: LlmUsageSummary
1579
+ /**
1580
+ * 截断声明:本次响应中被裁掉的字段说明(如「编年录:共 320 条,仅返回最近 80 条」)。
1581
+ * 消费方不得把缺失字段当作"不存在",需要完整数据时走专用接口。
1582
+ */
1583
+ truncations?: string[]
1584
+ }
1585
+
1586
+ /** 生产单状态(生产单 = 区间批量生产执行器:计划补足 + 逐章生成 + 被拒分级处理)。 */
1587
+ export interface RunState {
1588
+ runId: string
1589
+ /**
1590
+ * 本批次归属的书名(可选,兼容旧 run-state.json)。
1591
+ * 生产单是全局单实例,而 /run/status 恢复时会扫书架取第一个有 run-state 的目录,
1592
+ * 因此"这是哪本书的批次"必须显式带上,否则芯片/面板只能显示一个无法归属的状态。
1593
+ */
1594
+ bookName?: string
1595
+ /** 区间起点(含)。 */
1596
+ startNo: number
1597
+ /** 区间终点(含)。 */
1598
+ endNo: number
1599
+ status: 'running' | 'paused' | 'done' | 'stopped' | 'error'
1600
+ /** 当前处理到的章号(已 approved 的章会快进)。 */
1601
+ currentNo: number
1602
+ stats: {
1603
+ /** 新生成(含审稿)的章数。 */
1604
+ generated: number
1605
+ /** 被拒后按意见修订并通过的章数。 */
1606
+ revised: number
1607
+ /** 被拒后豁免通过(无 high)的章数。 */
1608
+ exempted: number
1609
+ /** error 后重新生成的章数。 */
1610
+ regenerated: number
1611
+ /** 生成失败的章数。 */
1612
+ error: number
1613
+ }
1614
+ /** 两轮修订仍不过、保留草稿待人工的章号。 */
1615
+ pendingManual: number[]
1616
+ /** 运行日志(保留最近 300 条)。 */
1617
+ log: Array<{ at: string; text: string }>
1618
+ startedAt: string
1619
+ updatedAt: string
1620
+ error?: string
1621
+ }
1622
+
1623
+ /** POST /run/start request. */
1624
+ export interface RunStartRequest {
1625
+ /** 起始章号(默认 1)。 */
1626
+ startNo?: number
1627
+ /** 结束章号(含;超出计划时自动补计划)。 */
1628
+ endNo?: number
1629
+ /** 或指定新增章数(从当前最后一章 +1 起)。 */
1630
+ count?: number
1631
+ }
1632
+
1633
+ /** POST /run/control request. */
1634
+ export interface RunControlRequest {
1635
+ action: 'pause' | 'resume' | 'stop'
1636
+ }
1637
+
1638
+ /** POST /load-outline request: either a docx path or raw text. */
1639
+ export interface LoadOutlineRequest {
1640
+ /** Absolute docx path; defaults to the configured outline path. */
1641
+ path?: string
1642
+ /** Raw outline text (takes precedence over path when present). */
1643
+ text?: string
1644
+ }
1645
+
1646
+ /** POST /load-outline response. */
1647
+ export interface LoadOutlineResponse {
1648
+ outline: string
1649
+ bookName: string
1650
+ chars: number
1651
+ path?: string
1652
+ }
1653
+
1654
+ /** POST /plan request. */
1655
+ export interface PlanRequest {
1656
+ /** Outline to plan from; defaults to the persisted project's outline. */
1657
+ outline?: string
1658
+ /** Number of chapters to plan (default: 30). */
1659
+ chapterCount?: number
1660
+ /** Volume to plan (1-based); when given, plans only that volume's chapters. */
1661
+ volume?: number
1662
+ }
1663
+
1664
+ /** POST /plan response. */
1665
+ export interface PlanResponse {
1666
+ chapters: ChapterPlan[]
1667
+ volumes?: Volume[]
1668
+ }
1669
+
1670
+ /** POST /volumes request/response. */
1671
+ export interface VolumesRequest {
1672
+ /** Outline to split into volumes; defaults to the project outline. */
1673
+ outline?: string
1674
+ }
1675
+ export interface VolumesResponse {
1676
+ volumes: Volume[]
1677
+ }
1678
+
1679
+ /** POST /bible request/response. */
1680
+ export interface BibleRequest {
1681
+ /** Outline to extract from; defaults to the project outline. */
1682
+ outline?: string
1683
+ }
1684
+ export interface BibleResponse {
1685
+ bible: StoryBible
1686
+ }
1687
+
1688
+ /** POST /generate request: one chapter of the current project. */
1689
+ export interface GenerateRequest {
1690
+ chapterNo: number
1691
+ /** When true, skips the auto-review step. */
1692
+ skipReview?: boolean
1693
+ }
1694
+
1695
+ /** One NDJSON frame of a generation/review/rewrite stream. */
1696
+ export type JobFrame =
1697
+ | { type: 'start'; no: number; title: string }
1698
+ | { type: 'delta'; text: string }
1699
+ | { type: 'progress'; chars: number }
1700
+ | { type: 'done'; no: number; file: string; chars: number; title: string; warn?: string }
1701
+ | { type: 'review'; no: number; report: ReviewReport }
1702
+ | { type: 'author-review'; no: number; review: AuthorReview }
1703
+ | { type: 'author-backfill-done'; count: number }
1704
+ | { type: 'rewritten'; no: number; file: string; chars: number }
1705
+ /** 润色/重写完成,产物作为待确认草稿(尚未覆盖正文)。 */
1706
+ | { type: 'drafted'; no: number; chars: number; draft: string }
1707
+ | { type: 'outline-progress'; done: number; total: number; phase: string }
1708
+ | { type: 'outline-done'; outline: string; chars: number }
1709
+ | { type: 'error'; no: number; message: string }
1710
+
1711
+ /** POST /review request: review one written chapter. */
1712
+ export interface ReviewRequest {
1713
+ chapterNo: number
1714
+ }
1715
+
1716
+ /** POST /rewrite request: rewrite one chapter (optionally per review issues). */
1717
+ export interface RewriteRequest {
1718
+ chapterNo: number
1719
+ /** Free-form instructions; defaults to fixing the review's high issues. */
1720
+ instructions?: string
1721
+ /**
1722
+ * 局部修订:正文中的一段原文(无需完全精确,取一个自然段内的片段即可)。
1723
+ * 提供时只重写该段,其余正文保持不变;不提供时整章重写。
1724
+ */
1725
+ target?: string
1726
+ }
1727
+
1728
+ /** POST /polish request: de-AI-ify one chapter. */
1729
+ export interface PolishRequest {
1730
+ chapterNo: number
1731
+ }
1732
+
1733
+ /** POST /draft/apply | /draft/discard request: 采纳或放弃待确认草稿。 */
1734
+ export interface DraftDecisionRequest {
1735
+ chapterNo: number
1736
+ /** apply 时可携带审查报告(沿用结论定状态;不携带则置 written)。 */
1737
+ report?: ReviewReport
1738
+ }
1739
+
1740
+ /** POST /summary request: (re)generate a chapter summary. */
1741
+ export interface SummaryRequest {
1742
+ chapterNo: number
1743
+ }
1744
+
1745
+ /** POST /foreshadow request: create, update, or AI-suggest foreshadows. */
1746
+ export interface ForeshadowRequest {
1747
+ /** When true, runs the LLM suggestion pass (ignores other fields). */
1748
+ suggest?: boolean
1749
+ /** When given, updates that foreshadow instead of creating one. */
1750
+ id?: string
1751
+ description?: string
1752
+ plantedChapter?: number
1753
+ targetChapter?: number
1754
+ status?: Foreshadow['status']
1755
+ resolvedNote?: string
1756
+ }
1757
+ export interface ForeshadowResponse {
1758
+ foreshadows: Foreshadow[]
1759
+ }
1760
+
1761
+ /** GET /chapter response. */
1762
+ export interface ChapterResponse {
1763
+ no: number
1764
+ title: string
1765
+ markdown: string
1766
+ }
1767
+
1768
+ /** POST /export request/response. */
1769
+ /**
1770
+ * 导出范围:
1771
+ * - `book` 整本正文(txt / md)
1772
+ * - `settings` 项目设定(总纲 / 道藏 / 大世界 / 写作资产 / 卷首语)
1773
+ * - `plan` 规划(卷计划 + 章节计划,含每章目标/要点/钩子/硬事实)
1774
+ * - `characters` 角色(角色库 + 人物志当前状态)
1775
+ * - `review` 质检记录(逐章审稿 + 作者复盘 + 伏笔/剧情线状态)
1776
+ * - `project` 项目 JSON(完整状态,用于备份/迁移;仅 json 格式)
1777
+ */
1778
+ export type ExportScope = 'book' | 'settings' | 'plan' | 'characters' | 'review' | 'project'
1779
+
1780
+ /** 导出范围全集(宿主校验用;顺序即 UI 展示顺序)。 */
1781
+ export const EXPORT_SCOPE_VALUES: readonly ExportScope[] = ['book', 'settings', 'plan', 'characters', 'review', 'project']
1782
+
1783
+ /** 导出范围的中文标签。 */
1784
+ export const EXPORT_SCOPE_LABELS: Record<ExportScope, string> = {
1785
+ book: '整本正文',
1786
+ settings: '项目设定',
1787
+ plan: '规划(卷/章节)',
1788
+ characters: '角色',
1789
+ review: '质检记录',
1790
+ project: '项目备份 JSON',
1791
+ }
1792
+
1793
+ export interface ExportRequest {
1794
+ format: 'txt' | 'md' | 'json'
1795
+ /** 缺省 `book`(兼容旧调用)。 */
1796
+ scope?: ExportScope
1797
+ }
1798
+ export interface ExportResponse {
1799
+ file: string
1800
+ chars: number
1801
+ chapters: number
1802
+ scope: ExportScope
1803
+ format: 'txt' | 'md' | 'json'
1804
+ }
1805
+
1806
+ /** POST /config request: patch any subset of the runtime config. */
1807
+ export interface ConfigPatch {
1808
+ outlinePath?: string
1809
+ outputDir?: string
1810
+ provider?: string
1811
+ model?: string
1812
+ generateModel?: string
1813
+ reviewModel?: string
1814
+ auditModel?: string
1815
+ /** 备用模型(主模型失败时自动切换重试一次;空串 = 关闭)。 */
1816
+ fallbackModel?: string
1817
+ /** 出章后自动抽取故事时间线(默认开)。 */
1818
+ autoTimeline?: boolean
1819
+ reasoningEffort?: 'off' | 'low' | 'high' | 'max'
1820
+ analysisReasoning?: 'off' | 'low' | 'high' | 'max'
1821
+ chapterChars?: number
1822
+ maxTokens?: number
1823
+ reviewPassScore?: number
1824
+ autoReview?: boolean
1825
+ autoAuthorReview?: boolean
1826
+ autoReviewAfterRevise?: boolean
1827
+ /** 自定义背景图(URL / dataURL / 服务端路径引用)。 */
1828
+ themeBackground?: string
1829
+ /** 自定义背景遮罩/模糊强度 0-80。 */
1830
+ themeBackgroundBlur?: number
1831
+ /** 玻璃透明度 0-100(100=当前原样)。 */
1832
+ themeOpacity?: number
1833
+ enableAdaptMode?: boolean
1834
+ /** 手动添加的模型库(完整替换保存)。 */
1835
+ savedModels?: SavedModel[]
1836
+ }
1837
+
1838
+ /** POST /config response: the config the host will read next, plus persistence caveats. */
1839
+ export interface ConfigResponse {
1840
+ config: NovelConfig
1841
+ /**
1842
+ * 已生效但**未持久化**时的说明(宿主 settings 段不可寻址:段 id 未知或宿主
1843
+ * 未登记)。有值时设置只在本次进程内有效,重启回退,面板照此提示用户。
1844
+ */
1845
+ settingsWarning?: string
1846
+ }
1847
+
1848
+ // ------------------------------------------------------------ assistant
1849
+
1850
+ /** One assistant conversation message (persisted per project). */
1851
+ export interface AssistantMessage {
1852
+ role: 'user' | 'assistant' | 'tool'
1853
+ /** Message text (tool messages carry the tool result). */
1854
+ content: string
1855
+ /** ISO timestamp. */
1856
+ ts: string
1857
+ /** For tool messages: which tool ran. */
1858
+ tool?: string
1859
+ }
1860
+
1861
+ /** POST /assistant request: one user turn. */
1862
+ export interface AssistantRequest {
1863
+ message: string
1864
+ }
1865
+
1866
+ /** One NDJSON frame of the assistant stream. */
1867
+ export type AssistantFrame =
1868
+ | { type: 'delta'; text: string }
1869
+ | { type: 'tool'; name: string; status: 'start' | 'done' | 'error'; detail?: string }
1870
+ /** Live output while a tool runs (e.g. chapter text being generated). */
1871
+ | { type: 'toolDelta'; name: string; text: string }
1872
+ /** 工具完整结果(供前端渲染成结构化卡片,如拆书/导演)。 */
1873
+ | { type: 'toolResult'; name: string; text: string }
1874
+ | { type: 'done' }
1875
+ | { type: 'error'; message: string }
1876
+
1877
+ /** GET /assistant-history response. */
1878
+ export interface AssistantHistoryResponse {
1879
+ messages: AssistantMessage[]
1880
+ }
1881
+
1882
+ // ---------------------------------------------------------- writing assets
1883
+
1884
+ /** 题材基底库:一本书属于哪个阅读市场。树形(题材→子题材→下级)。 */
1885
+ export interface GenreNode {
1886
+ /** 稳定标识(内置库交叉引用)。 */
1887
+ id?: string
1888
+ /** 题材名称(标签,如「仙侠修真」「都市异能」)。 */
1889
+ name: string
1890
+ /** 题材特征、常见爽点、叙事重心或读者期待。 */
1891
+ description: string
1892
+ /** 该题材的写法指引(开书定盘/卷计划用,区别于「读者期待」)。 */
1893
+ template?: string
1894
+ /** 子题材。 */
1895
+ children: GenreNode[]
1896
+ }
1897
+
1898
+ /** 推进模式库:读者为什么继续看下一章。 */
1899
+ export interface ProgressionMode {
1900
+ /** 稳定标识(与内置库交叉引用)。 */
1901
+ key?: string
1902
+ /** 模式名称(如「升级变强」「经营扩张」「解谜揭露」)。 */
1903
+ name: string
1904
+ /** 核心驱动力:靠什么制造追读动力。 */
1905
+ driver: string
1906
+ /** 读者期待:每隔几章获得什么变化或回报。 */
1907
+ readerExpectation: string
1908
+ /** 常见兑现方式(爽点如何落地)。 */
1909
+ payoffs: string[]
1910
+ /** 节奏风险:最怕什么(重复升级、冲突变弱、谜题拖太久…)。 */
1911
+ risks: string[]
1912
+ /** 主模式或辅助模式。 */
1913
+ primary: boolean
1914
+ /** 该模式的写法指引(开书定盘/卷计划用)。 */
1915
+ template?: string
1916
+ /** 推进单位序列(每章如何推进,如「立威→打破质疑→扩大影响→碾压」)。 */
1917
+ progressionUnits?: string[]
1918
+ /** 允许出现的冲突形态。 */
1919
+ allowedConflictForms?: string[]
1920
+ /** 应避免的冲突形态(跑偏信号)。 */
1921
+ forbiddenConflictForms?: string[]
1922
+ /** 冲突烈度上限(low/medium/high),用于卷/章计划和审稿对齐。 */
1923
+ conflictCeiling?: 'low' | 'medium' | 'high'
1924
+ /** 单章推进单位说明。 */
1925
+ chapterUnit?: string
1926
+ /** 卷末应兑现的回报。 */
1927
+ volumeReward?: string
1928
+ /** 主驱动必须持续出现的信号(读者期待确认)。 */
1929
+ mandatorySignals?: string[]
1930
+ /** 反信号:出现即跑偏。 */
1931
+ antiSignals?: string[]
1932
+ /** 优先用的问题解决方式。 */
1933
+ resolutionStyle?: string
1934
+ }
1935
+
1936
+ /** 反 AI 规则:一条「要避免的问题 + 修正方向」。 */
1937
+ export interface AntiAiRule {
1938
+ /** 规则名(如「禁止解释型心理描写」「AI 高频套话」)。 */
1939
+ name: string
1940
+ /** 稳定标识(与 defaultAntiAiRuleKeys 交叉引用;缺省用 name)。 */
1941
+ key?: string
1942
+ /** 要避免的表达问题,具体可检查。 */
1943
+ avoid: string
1944
+ /** 推荐修正方向。 */
1945
+ fix: string
1946
+ /** 命中即告警的具体表达模式(用于审稿逐条核对与去 AI 味检测)。 */
1947
+ detectPatterns?: string[]
1948
+ /** 是否内置全局规则(内置规则随插件发布,项目规则为用户自定义)。 */
1949
+ builtin?: boolean
1950
+ /** 规则类别:forbidden=禁止类(命中即问题)/ risk=风险类(需注意但不硬伤)/ encourage=鼓励类(不命中不算错,只作建议)。 */
1951
+ severity?: 'forbidden' | 'risk' | 'encourage'
1952
+ /** 问题严重度(用于审稿优先级;缺省按类别推断)。 */
1953
+ riskLevel?: 'low' | 'medium' | 'high'
1954
+ /** 生成时直接注入的约束指令(缺失时回退到 avoid)。 */
1955
+ promptInstruction?: string
1956
+ /** 是否允许自动改写(risk 类通常 false)。 */
1957
+ autoRewrite?: boolean
1958
+ /** 是否为全局基线规则(新书默认启用,防止规则丢失后降级)。 */
1959
+ globalBaselineEnabled?: boolean
1960
+ /** 是否启用(缺省 true)。 */
1961
+ enabled?: boolean
1962
+ /** 作用域(缺省 all)。 */
1963
+ scope?: Array<'writing' | 'review' | 'polish' | 'all'>
1964
+ }
1965
+
1966
+ /** 预置叙事风格模板(一键绑定无需样本文本)。 */
1967
+ export interface StyleTemplateNarrativeRules {
1968
+ progressionMode?: string
1969
+ sceneUnitPattern?: string[]
1970
+ multiPov?: boolean
1971
+ looping?: boolean
1972
+ endingStyle?: string
1973
+ povSwitchStyle?: string
1974
+ summary?: string
1975
+ }
1976
+
1977
+ export interface StyleTemplateCharacterRules {
1978
+ allowSelfReflection?: boolean
1979
+ emotionExpression?: string
1980
+ defenseMechanisms?: string[]
1981
+ facePriority?: boolean
1982
+ dialogueStyle?: string
1983
+ summary?: string
1984
+ }
1985
+
1986
+ export interface StyleTemplateLanguageRules {
1987
+ register?: string
1988
+ roughness?: number
1989
+ allowIncompleteSentences?: boolean
1990
+ allowSwearing?: boolean
1991
+ sentenceVariation?: string
1992
+ allowUselessDetails?: boolean
1993
+ summary?: string
1994
+ }
1995
+
1996
+ export interface StyleTemplateRhythmRules {
1997
+ pace?: string
1998
+ paragraphDensity?: string
1999
+ allowFragmentedFlow?: boolean
2000
+ actionOverExplanation?: boolean
2001
+ summary?: string
2002
+ }
2003
+
2004
+ export interface StyleTemplate {
2005
+ /** 模板 key(如 power-up-escalation)。 */
2006
+ key: string
2007
+ /** 模板名(如「爽文递进推进流」)。 */
2008
+ name: string
2009
+ /** 模板说明。 */
2010
+ description: string
2011
+ /** 分类(如「爽文流」「悬疑流」)。 */
2012
+ category: string
2013
+ /** 适用题材。 */
2014
+ applicableGenres: string[]
2015
+ /** 标签(便于筛选)。 */
2016
+ tags?: string[]
2017
+ /** 一句话分析(模板定位说明)。 */
2018
+ analysisMarkdown?: string
2019
+ /** 叙述规则(结构化)。 */
2020
+ narrative?: StyleTemplateNarrativeRules
2021
+ /** 角色规则(结构化)。 */
2022
+ character?: StyleTemplateCharacterRules
2023
+ /** 语言规则(结构化)。 */
2024
+ language?: StyleTemplateLanguageRules
2025
+ /** 节奏规则(结构化)。 */
2026
+ rhythm?: StyleTemplateRhythmRules
2027
+ /** 叙述规则(扁平,兼容旧数据)。 */
2028
+ proseRules: string[]
2029
+ /** 角色/台词规则(扁平,兼容旧数据)。 */
2030
+ dialogueRules: string[]
2031
+ /** 语言规则(扁平,兼容旧数据)。 */
2032
+ languageRules: string[]
2033
+ /** 节奏规则(扁平,兼容旧数据)。 */
2034
+ rhythmRules: string[]
2035
+ /** 该模板默认绑定的反 AI 规则 key(内置规则名)。 */
2036
+ defaultAntiAiRuleKeys: string[]
2037
+ }
2038
+
2039
+ /** 起始风格画像:无样本文本也能快速绑定一套写法。 */
2040
+ export interface StarterStyleProfile {
2041
+ /** stable key(如 starter-power-up)。 */
2042
+ key: string
2043
+ /** 绑定到的写法模板 key。 */
2044
+ templateKey: string
2045
+ /** 画像名。 */
2046
+ name: string
2047
+ /** 画像说明。 */
2048
+ description: string
2049
+ }
2050
+
2051
+ /** 剧情桥段库:可复用的情节套路/桥段(作者阅读经验沉淀,与书内 Plotline 不同层)。 */
2052
+ export interface PlotBeatTemplate {
2053
+ /** 模板 key(如 face-slap / exit-wedding)。 */
2054
+ key: string
2055
+ /** 桥段名(如「打脸」「退婚」)。 */
2056
+ name: string
2057
+ /** 分类(如「装逼打脸」「身份逆袭」)。 */
2058
+ category: string
2059
+ /** 一句话说明。 */
2060
+ summary: string
2061
+ /** 适用位置(开局/前期/中期/后期/高潮/结尾)。 */
2062
+ position: string
2063
+ /** 前置条件。 */
2064
+ preconditions: string[]
2065
+ /** 爽点来源。 */
2066
+ payoffSource: string[]
2067
+ /** 常用组合(可搭配的桥段)。 */
2068
+ combos: string[]
2069
+ /** 禁忌(别用烂/别用死)。 */
2070
+ taboos: string[]
2071
+ /** 适用题材。 */
2072
+ applicableGenres: string[]
2073
+ }
2074
+
2075
+ /** 写法引擎:从样本文本提取的叙事风格资产。 */
2076
+ export interface StyleAsset {
2077
+ /** 资产名(如「林越式痞坏」「冷峻猎手风」)。 */
2078
+ name: string
2079
+ /** 叙述视角与句式节奏。 */
2080
+ proseRules: string[]
2081
+ /** 角色台词风格。 */
2082
+ dialogueRules: string[]
2083
+ /** 描写密度与情绪表达。 */
2084
+ descriptionRules: string[]
2085
+ /** 表达边界(不要做什么)。 */
2086
+ boundaries: string[]
2087
+ /** 来源样本文本(可空)。 */
2088
+ sourceText?: string
2089
+ /** 仿写预设:imitate=高保真仿写 / balanced=平衡 / transfer=迁移(去指纹)。 */
2090
+ preset?: 'imitate' | 'balanced' | 'transfer'
2091
+ /** 指纹风险:仿写时照搬原作独特表达的风险。 */
2092
+ fingerprintRisk?: 'low' | 'medium' | 'high'
2093
+ /** 净化后的写作指引(可安全用于生成,去掉了会暴露来源的具体细节)。 */
2094
+ writingGuidance?: string[]
2095
+ /** 禁止照搬的原作特有实体(人名/地名/核心设定句式),生成时需避开。 */
2096
+ forbiddenEntities?: string[]
2097
+ /** 创建时间。 */
2098
+ createdAt: string
2099
+ }
2100
+
2101
+ /** 写作公式(从样本文本分层提取的"这套文怎么写"浓缩,供生成/改写复用)。 */
2102
+ export interface StyleFormula {
2103
+ /** 稳定 key。 */
2104
+ key: string
2105
+ /** 公式名。 */
2106
+ name: string
2107
+ /** 提取深度:basic=骨架 / standard=完整 / deep=逐句细化。 */
2108
+ depth: 'basic' | 'standard' | 'deep'
2109
+ /** 重点聚焦域(如 开场/对话/节奏/爽点密度)。 */
2110
+ focusAreas: string[]
2111
+ /** 公式正文(Markdown)。 */
2112
+ formula: string
2113
+ /** 应用指引(生成/改写时如何套用)。 */
2114
+ applyGuidance: string
2115
+ /** 创建时间。 */
2116
+ createdAt: string
2117
+ }
2118
+
2119
+ /** 项目写作资产(题材基底 + 推进模式 + 反 AI 规则 + 写法资产)。 */
2120
+ export interface ProjectAssets {
2121
+ /** 本书选用的题材(可以是题材基底库中某节点名)。 */
2122
+ genre?: GenreNode
2123
+ /** 主推进模式。 */
2124
+ primaryProgression?: ProgressionMode
2125
+ /** 辅助推进模式。 */
2126
+ auxiliaryProgressions: ProgressionMode[]
2127
+ /** 生效的反 AI 规则(内置 + 自定义)。 */
2128
+ antiAiRules: AntiAiRule[]
2129
+ /** 绑定的写法资产。 */
2130
+ styleAssets: StyleAsset[]
2131
+ /** 写作公式(分层提取:basic/standard/deep)。 */
2132
+ styleFormulas?: StyleFormula[]
2133
+ /** 资产更新时间。 */
2134
+ updatedAt?: string
2135
+ }
2136
+
2137
+ /** GET /assets response(含全局题材库与反 AI 规则库)。 */
2138
+ export interface AssetsResponse {
2139
+ projectAssets: ProjectAssets
2140
+ /** 全局题材基底库(可复用资产,跨书)。 */
2141
+ genreLibrary: GenreNode[]
2142
+ /** 全局反 AI 规则库(内置默认规则)。 */
2143
+ antiAiLibrary: AntiAiRule[]
2144
+ /** 预置写法模板(一键绑定,无需样本文本)。 */
2145
+ styleTemplates: StyleTemplate[]
2146
+ /** 内置推进模式候选。 */
2147
+ progressionLibrary: ProgressionMode[]
2148
+ /** 起始风格画像(无样本文本快速绑定写法)。 */
2149
+ starterStyleProfiles: StarterStyleProfile[]
2150
+ /** 内置剧情桥段库(可复用套路)。 */
2151
+ plotBeatLibrary: PlotBeatTemplate[]
2152
+ }
2153
+
2154
+ /** POST /assets request:更新项目写作资产(部分字段可选)。 */
2155
+ export interface AssetsPatch {
2156
+ genre?: GenreNode
2157
+ primaryProgression?: ProgressionMode
2158
+ auxiliaryProgressions?: ProgressionMode[]
2159
+ antiAiRules?: AntiAiRule[]
2160
+ styleAssets?: StyleAsset[]
2161
+ styleFormulas?: StyleFormula[]
2162
+ }
2163
+
2164
+ /** POST /style-engine request:从样本文本提取写法资产。 */
2165
+ export interface StyleEngineRequest {
2166
+ /** 样本文本(风格来源)。 */
2167
+ sampleText: string
2168
+ /** 资产名(可选,默认「风格资产 N」)。 */
2169
+ name?: string
2170
+ }
2171
+
2172
+ // ---------------------------------------------------------- author assets (总数据)
2173
+
2174
+ /** 作者资产库中一条可跨书复用的资产(笔法/红线/套路/角色模板/世界观模板等)。 */
2175
+ export interface AuthorStyleAsset {
2176
+ /** 稳定 id(本地唯一)。 */
2177
+ id: string
2178
+ /** 资产名(如「短句快节奏爽文风」「林越式痞坏角色」)。 */
2179
+ name: string
2180
+ /** 资产类型。 */
2181
+ kind: 'style' | 'antiAi' | 'progression' | 'genre' | 'roleTemplate' | 'worldTemplate' | 'plotBeat' | 'custom'
2182
+ /** 一句话摘要。 */
2183
+ summary: string
2184
+ /** 资产正文内容(按 kind 约定解读的文本/JSON 描述)。 */
2185
+ content: string
2186
+ /** 结构化载荷(角色模板/世界观模板等可结构化字段;缺省为 null)。 */
2187
+ structured?: Record<string, unknown>
2188
+ /** 来源书名(哪本书提炼/收藏而来)。 */
2189
+ sourceBooks: string[]
2190
+ /** 标签。 */
2191
+ tags: string[]
2192
+ /** 来源样本文本(可选)。 */
2193
+ sourceText?: string
2194
+ /** 创建时间。 */
2195
+ createdAt: string
2196
+ /** 更新时间。 */
2197
+ updatedAt: string
2198
+ }
2199
+
2200
+ /** 作者资产库(跨书总数据):按作者维度聚合的可复用资产。 */
2201
+ export interface AuthorAssetLibrary {
2202
+ /** 货架版本,便于未来迁移。 */
2203
+ version: 1
2204
+ items: AuthorStyleAsset[]
2205
+ }
2206
+
2207
+ /** GET /author-assets 响应。 */
2208
+ export interface AuthorAssetsResponse {
2209
+ assets: AuthorAssetLibrary
2210
+ }
2211
+
2212
+ /** POST /author-assets/upsert 请求:新增或按 id 更新一条资产。 */
2213
+ export interface AuthorAssetUpsertRequest {
2214
+ asset: AuthorStyleAsset
2215
+ }
2216
+
2217
+ /** POST /author-assets/remove 请求:删除一条资产。 */
2218
+ export interface AuthorAssetRemoveRequest {
2219
+ id: string
2220
+ }
2221
+
2222
+ // ---------------------------------------------------------- adaptation (改编模式)
2223
+
2224
+ /** 改编可改范围的单个维度(矩阵的一行)。 */
2225
+ export interface AdaptationDimension {
2226
+ /** 维度 key(如 realm/name/goldenFinger…)。 */
2227
+ key: string
2228
+ /** 维度名(如「大世界」「修为体系」「主角名」「金手指」)。 */
2229
+ title: string
2230
+ /** 可改度:保留 / 可改影响大 / 可改影响小 / 可自由改 / 仅视觉包装。 */
2231
+ mutability: 'locked' | 'big' | 'small' | 'free' | 'visual'
2232
+ /** 原文当前值(从正文提炼,附证据)。 */
2233
+ current: string
2234
+ /** 该值在正文中的出现证据(章节/频次,可空)。 */
2235
+ evidence?: string
2236
+ /** 建议的候选新值(可空,每套含名称与一句话说明)。 */
2237
+ candidates?: Array<{ name: string; desc?: string }>
2238
+ /** 联动影响说明(改了会影响哪些章节/角色/伏笔/术语)。 */
2239
+ impact: string
2240
+ /** 风险评级。 */
2241
+ risk: 'high' | 'medium' | 'low'
2242
+ }
2243
+
2244
+ /** POST /adapt/analyze 请求:上传全文做改编分析。 */
2245
+ export interface AdaptAnalyzeRequest {
2246
+ /** 全文文本(优先)。 */
2247
+ text: string
2248
+ /** 或服务器端全文文件路径。 */
2249
+ filePath?: string
2250
+ }
2251
+
2252
+ /** POST /adapt/analyze 响应。 */
2253
+ export interface AdaptAnalyzeResponse {
2254
+ /** 识别书名(文件名推断或正文首行)。 */
2255
+ bookName: string
2256
+ /** 拆出的章节数。 */
2257
+ chapters: number
2258
+ /** 反推的初始大纲(可空)。 */
2259
+ outline?: string
2260
+ /** 可改范围矩阵。 */
2261
+ dimensions: AdaptationDimension[]
2262
+ /** 分析消耗说明。 */
2263
+ note?: string
2264
+ }
2265
+
2266
+ /** 一条改编映射(原值 → 新值)。 */
2267
+ export interface AdaptationMapping {
2268
+ /** 原值(如「林尘」「练气」「青云宗」)。 */
2269
+ source: string
2270
+ /** 新值(如「楚风」「凝元」「天渊阁」)。 */
2271
+ target: string
2272
+ /** 适用范围。 */
2273
+ scope: 'name' | 'realm' | 'faction' | 'term' | 'other'
2274
+ /** 说明(可空)。 */
2275
+ note?: string
2276
+ }
2277
+
2278
+ /** 改编规则:哪些必须保留、哪些允许改、一致性约束。 */
2279
+ export interface AdaptationRules {
2280
+ /** 必须保留的要素(骨架/人物动机/伏笔逻辑/爽点结构…)。 */
2281
+ preserve: string[]
2282
+ /** 允许改变的要素。 */
2283
+ change: string[]
2284
+ /** 改编红线/一致性要求。 */
2285
+ constraints: string[]
2286
+ }
2287
+
2288
+ /** 一组改编方案(映射表 + 规则 + 联动影响清单)。 */
2289
+ export interface AdaptationProposal {
2290
+ /** 映射表(原→新)。 */
2291
+ mappings: AdaptationMapping[]
2292
+ /** 改编规则。 */
2293
+ rules: AdaptationRules
2294
+ /** 联动影响清单。 */
2295
+ impacts: Array<{ item: string; detail: string; risk: 'high' | 'medium' | 'low'; chapters?: number[] }>
2296
+ }
2297
+
2298
+ /** POST /adapt/propose 请求:由用户勾选的维度 + 新值生成改编方案。 */
2299
+ export interface AdaptProposeRequest {
2300
+ /** 原文全文(复用,便于 LLM 核对联动影响)。 */
2301
+ text: string
2302
+ /** 用户确认要改的维度(含原值与新值)。 */
2303
+ selections: Array<{ key: string; title: string; current: string; target: string; mutability: string }>
2304
+ /** 若已分析过,可携带完整矩阵作为上下文。 */
2305
+ dimensions?: AdaptationDimension[]
2306
+ }
2307
+
2308
+ /** POST /adapt/propose 响应。 */
2309
+ export interface AdaptProposeResponse {
2310
+ proposal: AdaptationProposal
2311
+ }
2312
+
2313
+ /** POST /adapt/execute 请求:执行改编(replace=术语替换;rewrite=逐章 LLM 重写)。 */
2314
+ export interface AdaptExecuteRequest {
2315
+ /** 原文全文。 */
2316
+ text: string
2317
+ /** 改编映射表。 */
2318
+ mappings: AdaptationMapping[]
2319
+ /** 改编规则(rewrite 模式生效:保留/允许变/红线)。 */
2320
+ rules?: AdaptationRules
2321
+ /** 执行模式:replace(术语替换)或 rewrite(逐章重写)。 */
2322
+ mode?: 'replace' | 'rewrite'
2323
+ /** rewrite 模式:只重写前 N 章(0/缺省 = 全部,且在 startNo/endNo 窗口内)。 */
2324
+ maxChapters?: number
2325
+ /** rewrite 模式:起始章号(含,默认 1)。 */
2326
+ startNo?: number
2327
+ /** rewrite 模式:结束章号(含;0/缺省 = 到全书末尾)。 */
2328
+ endNo?: number
2329
+ }
2330
+
2331
+ /** POST /adapt/execute 响应。 */
2332
+ export interface AdaptExecuteResponse {
2333
+ /** 改编后的全文。 */
2334
+ adaptedText: string
2335
+ /** 执行的映射数。 */
2336
+ mappings: number
2337
+ /** 命中统计:每条映射的替换次数。 */
2338
+ hits: Array<{ source: string; target: string; count: number }>
2339
+ /** 执行模式(replace / rewrite)。 */
2340
+ mode?: 'replace' | 'rewrite'
2341
+ /** rewrite 模式的逐章结果(no/title/chars)。 */
2342
+ rewritten?: Array<{ no: number; title: string; chars: number }>
2343
+ /** rewrite 模式下重写失败、保留原章的章节号。 */
2344
+ skipped?: number[]
2345
+ }
2346
+
2347
+ /** POST /adapt/rewrite-stream 的 NDJSON 帧(逐章进度 + 结束结果)。 */
2348
+ export type AdaptRewriteFrame =
2349
+ | { type: 'progress'; completed: number; total: number; no: number; title: string }
2350
+ | { type: 'done'; result: AdaptExecuteResponse }
2351
+ | { type: 'error'; message: string }
2352
+
2353
+ /** POST /adapt/save 请求:保存改编全文为新书(原书保留,登记书架)。 */
2354
+ export interface AdaptSaveRequest {
2355
+ /** 改编后的全文。 */
2356
+ text: string
2357
+ /** 新书名(缺省为「改编新书」;建议用「<原著>·改编版」)。 */
2358
+ bookName?: string
2359
+ /** 新书输出目录(缺省为「输出目录」设置下的书名子目录)。 */
2360
+ outputDir?: string
2361
+ /** 可附带反推大纲(写进新项目,便于后续续写/编辑)。 */
2362
+ outline?: string
2363
+ }
2364
+
2365
+ /** POST /adapt/save 响应。 */
2366
+ export interface AdaptSaveResponse {
2367
+ /** 登记后的书架条目。 */
2368
+ book: BookEntry
2369
+ /** 新书名。 */
2370
+ bookName: string
2371
+ /** 成功拆出的章节数。 */
2372
+ chapters: number
2373
+ /** 因内容过短被跳过的章节标题列表。 */
2374
+ skipped: string[]
2375
+ /** 新书输出目录。 */
2376
+ outputDir: string
2377
+ }
2378
+
2379
+ /** POST /adapt/materialize 请求:从源全文 + 用户编辑后的改编方案,提炼新书资料并保存为「待写新书」。 */
2380
+ export interface AdaptMaterializeRequest {
2381
+ /** 源书全文。 */
2382
+ text: string
2383
+ /** 新书名(缺省为「<源书名>·改编版」)。 */
2384
+ bookName?: string
2385
+ /** 新书输出目录(缺省为「输出目录」设置下的书名子目录)。 */
2386
+ outputDir?: string
2387
+ /** 反推大纲(来自分析;缺少时用源文章题兜底)。 */
2388
+ outline?: string
2389
+ /** 用户编辑后的改编方案(映射表 + 规则)。 */
2390
+ proposal: AdaptationProposal
2391
+ /** 拟规划章节数(缺省 30,可在前端调整)。 */
2392
+ chapterCount?: number
2393
+ }
2394
+
2395
+ /** POST /adapt/materialize 响应:提炼后的新书资料(预览,尚未落盘;保存走 /adapt/materialize-save)。 */
2396
+ export interface AdaptMaterializeResponse {
2397
+ /** 书架条目(仅在已保存时存在;预览阶段为 undefined)。 */
2398
+ book?: BookEntry
2399
+ /** 新书名。 */
2400
+ bookName: string
2401
+ /** 改编后总纲。 */
2402
+ outline: string
2403
+ /** 改编后道藏。 */
2404
+ bible: StoryBible
2405
+ /** 改编后角色库。 */
2406
+ roles: RoleRecord[]
2407
+ /** 改编后大世界。 */
2408
+ world: WorldState
2409
+ /** 改编后卷计划。 */
2410
+ volumes: Volume[]
2411
+ /** 改编后章节计划(status=pending)。 */
2412
+ chapters: ChapterPlan[]
2413
+ /** 新书输出目录。 */
2414
+ outputDir: string
2415
+ }
2416
+
2417
+ /** POST /adapt/materialize-save 请求:把预览/微调后的新书资料写入并登记书架。 */
2418
+ export interface AdaptMaterializeSaveRequest {
2419
+ /** 新书名(缺省为「改编版」)。 */
2420
+ bookName?: string
2421
+ /** 新书输出目录(缺省为「输出目录」设置下的书名子目录)。 */
2422
+ outputDir?: string
2423
+ /** 改编后总纲。 */
2424
+ outline: string
2425
+ /** 改编后道藏。 */
2426
+ bible: StoryBible
2427
+ /** 改编后角色库。 */
2428
+ roles: RoleRecord[]
2429
+ /** 改编后大世界。 */
2430
+ world: WorldState
2431
+ /** 改编后卷计划。 */
2432
+ volumes: Volume[]
2433
+ /** 改编后章节计划(status=pending)。 */
2434
+ chapters: ChapterPlan[]
2435
+ }
2436
+
2437
+ /** POST /adapt/materialize-save 响应。 */
2438
+ export interface AdaptMaterializeSaveResponse {
2439
+ /** 登记后的书架条目。 */
2440
+ book: BookEntry
2441
+ /** 新书名。 */
2442
+ bookName: string
2443
+ /** 成功写入的章节数。 */
2444
+ chapters: number
2445
+ /** 新书输出目录。 */
2446
+ outputDir: string
2447
+ }
2448
+
2449
+ /** POST /plugin/update 响应:插件自更新结果。 */
2450
+ export interface PluginUpdateResponse {
2451
+ ok: boolean
2452
+ /** 更新结果说明(成功/失败/环境提示)。 */
2453
+ message: string
2454
+ }