@waterwx/dsh-novel-forge 2.0.1-alpha → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/README.md +368 -362
  2. package/lib/client.js +20340 -19622
  3. package/lib/index.js +11313 -7285
  4. package/lib/types/action-guard.d.ts +61 -0
  5. package/lib/types/ai-scan.d.ts +0 -6
  6. package/lib/types/assets.d.ts +20 -9
  7. package/lib/types/assistant.d.ts +29 -0
  8. package/lib/types/author-assets.d.ts +1 -3
  9. package/lib/types/bookshelf.d.ts +13 -3
  10. package/lib/types/client/api.d.ts +136 -27
  11. package/lib/types/client/chip-prefs.d.ts +36 -0
  12. package/lib/types/client/docx.d.ts +2 -2
  13. package/lib/types/client/llmLive.d.ts +31 -0
  14. package/lib/types/client/locales.d.ts +15 -70
  15. package/lib/types/client/mount.d.ts +0 -2
  16. package/lib/types/client/panel/AiTag.d.ts +1 -0
  17. package/lib/types/client/panel/AssistantTab.d.ts +4 -1
  18. package/lib/types/client/panel/AuthorHome.d.ts +13 -11
  19. package/lib/types/client/panel/BookAnalysisView.d.ts +4 -0
  20. package/lib/types/client/panel/CmdPalette.d.ts +12 -0
  21. package/lib/types/client/panel/CreateBookView.d.ts +5 -1
  22. package/lib/types/client/panel/DirectorView.d.ts +7 -0
  23. package/lib/types/client/panel/IdeaInspirationView.d.ts +6 -0
  24. package/lib/types/client/panel/KnowledgeBaseView.d.ts +4 -0
  25. package/lib/types/client/panel/LiveFeedLog.d.ts +13 -0
  26. package/lib/types/client/panel/MarketRadarView.d.ts +5 -0
  27. package/lib/types/client/panel/ModelManager.d.ts +2 -2
  28. package/lib/types/client/panel/NovelPanel.d.ts +6 -1
  29. package/lib/types/client/panel/PageHeader.d.ts +18 -0
  30. package/lib/types/client/panel/PromptSlotsView.d.ts +11 -0
  31. package/lib/types/client/panel/SettingsView.d.ts +12 -9
  32. package/lib/types/client/panel/ShelfView.d.ts +10 -1
  33. package/lib/types/client/panel/SubPage.d.ts +27 -0
  34. package/lib/types/client/panel/TensionView.d.ts +18 -0
  35. package/lib/types/client/panel/TimelineView.d.ts +18 -0
  36. package/lib/types/client/panel/helpers.d.ts +5 -3
  37. package/lib/types/client/panel/market-radar-state.d.ts +56 -0
  38. package/lib/types/client/panel/outline-markdown.d.ts +112 -0
  39. package/lib/types/client/panel/status-badge.d.ts +13 -0
  40. package/lib/types/client/panel/storage-parse.d.ts +46 -0
  41. package/lib/types/client/panel/toast.d.ts +2 -0
  42. package/lib/types/client/panel/usePersistentState.d.ts +17 -0
  43. package/lib/types/client/panel/views.d.ts +21 -35
  44. package/lib/types/client/run-status.d.ts +21 -0
  45. package/lib/types/client/sidebar-entry.d.ts +0 -2
  46. package/lib/types/digest-parse.d.ts +29 -0
  47. package/lib/types/docx-core.d.ts +16 -0
  48. package/lib/types/docx.d.ts +2 -3
  49. package/lib/types/engine.d.ts +150 -103
  50. package/lib/types/global-assets.d.ts +6 -0
  51. package/lib/types/home.d.ts +11 -0
  52. package/lib/types/index.d.ts +26 -12
  53. package/lib/types/llm-live.d.ts +70 -0
  54. package/lib/types/llm-retry.d.ts +38 -0
  55. package/lib/types/market-radar-scan.d.ts +18 -0
  56. package/lib/types/market-radar-sources.d.ts +31 -0
  57. package/lib/types/migrate-output.d.ts +25 -0
  58. package/lib/types/model-capability.d.ts +119 -0
  59. package/lib/types/model-request.d.ts +36 -0
  60. package/lib/types/output-budget.d.ts +86 -0
  61. package/lib/types/plotline-align.d.ts +35 -0
  62. package/lib/types/prompt-slots.d.ts +57 -0
  63. package/lib/types/prompting.d.ts +10 -0
  64. package/lib/types/protocol.d.ts +841 -601
  65. package/lib/types/revision.d.ts +76 -0
  66. package/lib/types/routes.d.ts +9 -3
  67. package/lib/types/run-selection.d.ts +51 -0
  68. package/lib/types/run.d.ts +32 -1
  69. package/lib/types/settings-persist.d.ts +59 -0
  70. package/lib/types/snapshots.d.ts +46 -0
  71. package/lib/types/stage-contract.d.ts +58 -0
  72. package/lib/types/stream-fallback.d.ts +60 -0
  73. package/lib/types/strip-headings.d.ts +33 -0
  74. package/lib/types/tension.d.ts +53 -0
  75. package/lib/types/timeline.d.ts +37 -0
  76. package/package.json +50 -27
  77. package/assets/styles/arcane-thick-3d.webp +0 -0
  78. package/assets/styles/chinese-ink.webp +0 -0
  79. package/assets/styles/clay-stopmotion-3d.webp +0 -0
  80. package/assets/styles/dark-ghibli.webp +0 -0
  81. package/assets/styles/dark-gothic-3d.webp +0 -0
  82. package/assets/styles/film-photo.webp +0 -0
  83. package/assets/styles/guofeng-heavy.webp +0 -0
  84. package/assets/styles/guoman-2d-gufeng.webp +0 -0
  85. package/assets/styles/guoman-3d-tianyuan.webp +0 -0
  86. package/assets/styles/guoman-3d-xuanhuan.webp +0 -0
  87. package/assets/styles/horror-game-3d.webp +0 -0
  88. package/assets/styles/hyperreal-3d.webp +0 -0
  89. package/assets/styles/japan-cel-dark.webp +0 -0
  90. package/assets/styles/korean-webtoon.webp +0 -0
  91. package/assets/styles/low-cyberpunk-3d.webp +0 -0
  92. package/assets/styles/nextgen-cg.webp +0 -0
  93. package/assets/styles/noir-film.webp +0 -0
  94. package/assets/styles/openworld-survival.webp +0 -0
  95. package/assets/styles/paper-cut-3d.webp +0 -0
  96. package/assets/styles/pixar-adult-3d.webp +0 -0
  97. package/assets/styles/pop-marvel-2d.webp +0 -0
  98. package/assets/styles/sandiao-qban.webp +0 -0
  99. package/assets/styles/shinkai-anime.webp +0 -0
  100. package/assets/styles/tactical-stealth.webp +0 -0
  101. package/assets/styles/urban-lightreal-3d.webp +0 -0
  102. package/assets/styles/vaporwave-3d.webp +0 -0
  103. package/assets/styles/vhs90.webp +0 -0
  104. package/lib/types/client/panel/BookshelfBar.d.ts +0 -11
  105. package/lib/types/client/panel/FlowGuide.d.ts +0 -22
  106. package/lib/types/client/panel/MangaRoleLibrary.d.ts +0 -20
  107. package/lib/types/client/panel/MangaWorkspace.d.ts +0 -12
  108. package/lib/types/client/panel/ModelPicker.d.ts +0 -11
  109. package/lib/types/client/panel/ProgressHomeView.d.ts +0 -5
  110. package/lib/types/client/panel/PropLibrary.d.ts +0 -8
  111. package/lib/types/client/panel/SceneLibrary.d.ts +0 -16
  112. package/lib/types/client/panel/StoryboardTab.d.ts +0 -19
  113. package/lib/types/client/panel/StyleCard.d.ts +0 -8
  114. package/lib/types/client/panel/StyleGallery.d.ts +0 -1
  115. package/lib/types/comic-presets.d.ts +0 -12
  116. package/lib/types/manga-genre-rules.d.ts +0 -22
  117. package/lib/types/prompt-utils.d.ts +0 -35
  118. package/lib/types/review-policy.d.ts +0 -97
  119. package/lib/types/shot-language.d.ts +0 -46
  120. package/lib/types/story-beat-language.d.ts +0 -35
  121. package/lib/types/style-library.d.ts +0 -33
  122. package/skills/chapter-batch/SKILL.md +0 -81
  123. package/src/ai-scan.ts +0 -179
  124. package/src/assets.ts +0 -879
  125. package/src/assistant.ts +0 -770
  126. package/src/author-assets.ts +0 -147
  127. package/src/bookshelf.ts +0 -167
  128. package/src/client/api.ts +0 -617
  129. package/src/client/css-modules.d.ts +0 -8
  130. package/src/client/docx.ts +0 -69
  131. package/src/client/index.ts +0 -34
  132. package/src/client/locales.ts +0 -418
  133. package/src/client/mount.tsx +0 -97
  134. package/src/client/mount.tsx._new +0 -97
  135. package/src/client/mount.tsx._nf +0 -97
  136. package/src/client/mount.tsx._tmp +0 -97
  137. package/src/client/panel/AdaptModeView.tsx +0 -520
  138. package/src/client/panel/AssetsTab.tsx +0 -458
  139. package/src/client/panel/AssistantTab.tsx +0 -301
  140. package/src/client/panel/AuthorAssetsView.tsx +0 -208
  141. package/src/client/panel/AuthorHome.tsx +0 -204
  142. package/src/client/panel/BookshelfBar.tsx +0 -170
  143. package/src/client/panel/CreateBookView.tsx +0 -352
  144. package/src/client/panel/FlowGuide.tsx +0 -84
  145. package/src/client/panel/GlobalAssetLibraryView.tsx +0 -172
  146. package/src/client/panel/ImportModal.tsx +0 -303
  147. package/src/client/panel/MangaRoleLibrary.tsx +0 -1002
  148. package/src/client/panel/MangaWorkspace.tsx +0 -715
  149. package/src/client/panel/ModelManager.tsx +0 -205
  150. package/src/client/panel/NovelPanel.tsx +0 -4620
  151. package/src/client/panel/ProgressConsole.tsx +0 -64
  152. package/src/client/panel/ProgressHomeView.tsx +0 -87
  153. package/src/client/panel/PropLibrary.tsx +0 -175
  154. package/src/client/panel/ReaderView.tsx +0 -306
  155. package/src/client/panel/ReasoningSection.tsx +0 -31
  156. package/src/client/panel/RunPanel.tsx +0 -204
  157. package/src/client/panel/SceneLibrary.tsx +0 -453
  158. package/src/client/panel/SettingsView.tsx +0 -286
  159. package/src/client/panel/ShelfView.tsx +0 -242
  160. package/src/client/panel/StoryboardTab.tsx +0 -472
  161. package/src/client/panel/StyleCard.tsx +0 -90
  162. package/src/client/panel/StyleGallery.tsx +0 -58
  163. package/src/client/panel/WorldTab.tsx +0 -202
  164. package/src/client/panel/controller.ts +0 -45
  165. package/src/client/panel/helpers.ts +0 -67
  166. package/src/client/panel/panel.module.css +0 -4360
  167. package/src/client/panel/views.tsx +0 -314
  168. package/src/client/sidebar-entry.ts +0 -122
  169. package/src/client/text.ts +0 -28
  170. package/src/comic-presets.ts +0 -67
  171. package/src/docx.ts +0 -83
  172. package/src/engine.ts +0 -5200
  173. package/src/index.ts +0 -329
  174. package/src/manga-genre-rules.ts +0 -87
  175. package/src/novel-context.ts +0 -287
  176. package/src/prompt-utils.ts +0 -73
  177. package/src/protocol.ts +0 -2233
  178. package/src/review-policy.ts +0 -161
  179. package/src/routes.ts +0 -3419
  180. package/src/run.ts +0 -331
  181. package/src/shot-language.ts +0 -181
  182. package/src/story-beat-language.ts +0 -130
  183. package/src/style-library.ts +0 -84
package/src/client/api.ts DELETED
@@ -1,617 +0,0 @@
1
- /**
2
- * Browser-side API client for the /api/dsh-novel-forge route family. Plain
3
- * fetch, same origin; generation/rewrite/polish ride NDJSON streams read
4
- * incrementally.
5
- */
6
-
7
- import {
8
- NOVEL_API,
9
- type AssetsPatch,
10
- type AssetsResponse,
11
- type AddModelRequest,
12
- type AddModelResponse,
13
- type LlmModelsResponse,
14
- type LlmProvidersResponse,
15
- type LlmVendorsResponse,
16
- type RemoveProviderRequest,
17
- type RemoveProviderResponse,
18
- type BibleResponse,
19
- type ChapterResponse,
20
- type ConfigPatch,
21
- type ExportResponse,
22
- type ForeshadowRequest,
23
- type ForeshadowResponse,
24
- type JobFrame,
25
- type LoadOutlineResponse,
26
- type AdaptExecuteRequest,
27
- type AdaptExecuteResponse,
28
- type AdaptRewriteFrame,
29
- type AdaptMaterializeSaveRequest,
30
- type AdaptMaterializeSaveResponse,
31
- type PluginUpdateResponse,
32
- type LlmTestResponse,
33
- type NovelConfig,
34
- type PlanResponse,
35
- type ReviewReport,
36
- type StatusResponse,
37
- type StyleEngineRequest,
38
- type StyleAsset,
39
- type VolumesResponse,
40
- } from '../protocol.ts'
41
-
42
- /** Error carrying the route's JSON error message. */
43
- export class NovelApiError extends Error {
44
- constructor(message: string) {
45
- super(message)
46
- this.name = 'NovelApiError'
47
- }
48
- }
49
-
50
- /** Parse a JSON response or throw a NovelApiError. */
51
- async function readJson<T>(response: Response): Promise<T> {
52
- let body: unknown
53
- try {
54
- body = await response.json()
55
- } catch {
56
- throw new NovelApiError(`HTTP ${response.status}: invalid JSON response`)
57
- }
58
- if (!response.ok) {
59
- const message = typeof body === 'object' && body !== null && typeof (body as { error?: unknown }).error === 'string'
60
- ? (body as { error: string }).error
61
- : `HTTP ${response.status}`
62
- throw new NovelApiError(message)
63
- }
64
- return body as T
65
- }
66
-
67
- /** POST JSON, return parsed JSON. */
68
- async function postJson<T>(path: string, payload: unknown): Promise<T> {
69
- const response = await fetch(path, {
70
- method: 'POST',
71
- headers: { 'content-type': 'application/json' },
72
- body: JSON.stringify(payload),
73
- })
74
- return readJson<T>(response)
75
- }
76
-
77
- /** The browser half's only data entry point. */
78
- export class NovelApi {
79
- async status(): Promise<StatusResponse> {
80
- const response = await fetch(NOVEL_API.status)
81
- return readJson<StatusResponse>(response)
82
- }
83
-
84
- async loadOutline(path?: string, text?: string): Promise<LoadOutlineResponse> {
85
- return postJson<LoadOutlineResponse>(NOVEL_API.loadOutline, { path, text })
86
- }
87
-
88
- async saveOutline(text: string): Promise<{ ok: boolean; bookName: string }> {
89
- return postJson<{ ok: boolean; bookName: string }>(NOVEL_API.saveOutline, { text })
90
- }
91
-
92
- /** 反推大纲:从已写章节正文反向生成全书总纲(NDJSON 流)。 */
93
- async outlineReverse(onFrame: (frame: JobFrame) => void): Promise<void> {
94
- await this.streamJob(NOVEL_API.outlineReverse, {}, onFrame)
95
- }
96
-
97
- /** 分镜·导演级:骨架 → 分镜表(镜头级)。 */
98
- async storyboardTable(chapterNo: number, skeleton: import('../protocol.ts').StoryboardSkeleton, styleId?: string, filterId?: string): Promise<import('../protocol.ts').StoryboardTableResponse> {
99
- return postJson<import('../protocol.ts').StoryboardTableResponse>(NOVEL_API.storyboardTable, { chapterNo, skeleton, styleId, filterId })
100
- }
101
-
102
- /** 漫剧方案管理:create / remove / activate。 */
103
- async manhuaPlans(req: import('../protocol.ts').MangaPlansRequest): Promise<import('../protocol.ts').MangaPlansResponse> {
104
- return postJson<import('../protocol.ts').MangaPlansResponse>(NOVEL_API.manhuaPlans, req)
105
- }
106
-
107
- /** 分镜·提示词级:分镜表 → 即梦可粘贴视频提示词。 */
108
- async storyboardPrompts(chapterNo: number, table: import('../protocol.ts').StoryboardTable, styleId?: string, filterId?: string): Promise<import('../protocol.ts').StoryboardPromptsResponse> {
109
- return postJson<import('../protocol.ts').StoryboardPromptsResponse>(NOVEL_API.storyboardPrompts, { chapterNo, table, styleId, filterId })
110
- }
111
-
112
- /** 分镜·编剧级:单章 → 剧情骨架(节拍链)。 */
113
- async storyboardSkeleton(chapterNo: number): Promise<import('../protocol.ts').StoryboardSkeletonResponse> {
114
- return postJson<import('../protocol.ts').StoryboardSkeletonResponse>(NOVEL_API.storyboardSkeleton, { chapterNo })
115
- }
116
-
117
- /** 开书想法 → AI 大纲:生成 count 个方案(换批时传 exclude 避开已暂留方向)。 */
118
- async outlineSuggest(idea: string, count?: number, exclude?: string[]): Promise<import('../protocol.ts').OutlineSuggestResponse> {
119
- return postJson<import('../protocol.ts').OutlineSuggestResponse>(NOVEL_API.outlineSuggest, { idea, count, exclude })
120
- }
121
-
122
- /** 拆书分析:对已写章节做结构/人物/文风/卖点体检。 */
123
- async breakdown(scope?: string, preset?: 'quick' | 'standard', budgetTokens?: number): Promise<import('../protocol.ts').BreakdownResponse> {
124
- return postJson<import('../protocol.ts').BreakdownResponse>(NOVEL_API.breakdown, { scope, preset, budgetTokens })
125
- }
126
-
127
- async plan(outline?: string, chapterCount?: number, volume?: number): Promise<PlanResponse> {
128
- return postJson<PlanResponse>(NOVEL_API.plan, { outline, chapterCount, volume })
129
- }
130
-
131
- async volumes(outline?: string): Promise<VolumesResponse> {
132
- return postJson<VolumesResponse>(NOVEL_API.volumes, { outline })
133
- }
134
-
135
- async bible(outline?: string): Promise<BibleResponse> {
136
- return postJson<BibleResponse>(NOVEL_API.bible, { outline })
137
- }
138
-
139
- async review(chapterNo: number): Promise<{ report: ReviewReport }> {
140
- return postJson<{ report: ReviewReport }>(NOVEL_API.review, { chapterNo })
141
- }
142
-
143
- async summarize(chapterNo: number): Promise<{ summary: string }> {
144
- return postJson<{ summary: string }>(NOVEL_API.summary, { chapterNo })
145
- }
146
-
147
- async foreshadow(req: ForeshadowRequest): Promise<ForeshadowResponse> {
148
- return postJson<ForeshadowResponse>(NOVEL_API.foreshadow, req)
149
- }
150
-
151
- async exportBook(format: 'txt' | 'md'): Promise<ExportResponse> {
152
- return postJson<ExportResponse>(NOVEL_API.exportBook, { format })
153
- }
154
-
155
- async chapter(no: number): Promise<ChapterResponse> {
156
- const response = await fetch(`${NOVEL_API.chapter}?no=${no}`)
157
- return readJson<ChapterResponse>(response)
158
- }
159
-
160
- /** 审查手动编辑的正文(不落盘)。previousReport 传入时走「验证模式」(核对原意见解决 + 只挑新增 high)。 */
161
- async chapterCheck(no: number, text: string, previousReport?: ReviewReport): Promise<{ report: ReviewReport }> {
162
- return postJson<{ report: ReviewReport }>(NOVEL_API.chapterCheck, { chapterNo: no, text, previousReport })
163
- }
164
-
165
- /** 保存手动编辑的正文(自动备份 .bak;带报告则沿用落盘,否则保存后自动审稿)。 */
166
- async chapterSave(no: number, text: string, report?: ReviewReport): Promise<import('../protocol.ts').ChapterSaveResponse> {
167
- return postJson<import('../protocol.ts').ChapterSaveResponse>(NOVEL_API.chapterSave, { chapterNo: no, text, report })
168
- }
169
-
170
- async patchConfig(patch: ConfigPatch): Promise<{ config: NovelConfig }> {
171
- return postJson<{ config: NovelConfig }>(NOVEL_API.config, patch)
172
- }
173
-
174
- async openFolder(): Promise<void> {
175
- await fetch(NOVEL_API.openFolder, { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' })
176
- }
177
-
178
- /** 插件自更新:在 DSH profile 目录拉取最新 npm 版(需重启 DSH 生效)。 */
179
- async pluginUpdate(): Promise<PluginUpdateResponse> {
180
- return postJson<PluginUpdateResponse>(NOVEL_API.pluginUpdate, {})
181
- }
182
-
183
- /** 书架快照。 */
184
- async bookshelf(): Promise<import('../protocol.ts').BookshelfSnapshot> {
185
- const response = await fetch(NOVEL_API.bookshelf)
186
- return readJson<import('../protocol.ts').BookshelfSnapshot>(response)
187
- }
188
-
189
- /** 新建书并激活(开书向导:可携带大纲文本,创建即建项目)。 */
190
- async bookCreate(bookName: string, outputDir?: string, outline?: string): Promise<import('../protocol.ts').BookshelfSnapshot> {
191
- return postJson<import('../protocol.ts').BookshelfSnapshot>(NOVEL_API.bookshelf, { bookName, outputDir, outline })
192
- }
193
-
194
- /** 重置项目(清空进度;可携带新大纲)。 */
195
- async reset(outline?: string): Promise<{ ok: boolean; bookName: string }> {
196
- return postJson<{ ok: boolean; bookName: string }>(NOVEL_API.reset, { outline })
197
- }
198
-
199
- /** 全书一致性质检。 */
200
- async audit(): Promise<import('../protocol.ts').AuditResponse> {
201
- return postJson<import('../protocol.ts').AuditResponse>(NOVEL_API.audit, {})
202
- }
203
-
204
- /** 角色卡刷新(基于事实库聚合)。 */
205
- async charactersRefresh(): Promise<{ cards: import('../protocol.ts').RoleStatusCard[] }> {
206
- return postJson<{ cards: import('../protocol.ts').RoleStatusCard[] }>(NOVEL_API.charactersRefresh, {})
207
- }
208
-
209
- /** 事实库回填:对历史已生成章节批量抽取事实。 */
210
- async factsBackfill(): Promise<{ ok: boolean; filled: number }> {
211
- return postJson<{ ok: boolean; filled: number }>(NOVEL_API.factsBackfill, {})
212
- }
213
-
214
- /** 道藏局部修补。 */
215
- async biblePatch(patch: import('../protocol.ts').BiblePatchRequest): Promise<{ bible: import('../protocol.ts').StoryBible }> {
216
- return postJson<{ bible: import('../protocol.ts').StoryBible }>(NOVEL_API.biblePatch, patch)
217
- }
218
-
219
- /** 剧情线管理:增删改 + 关联章节。 */
220
- async plotlines(req: import('../protocol.ts').PlotlinesRequest): Promise<import('../protocol.ts').PlotlinesResponse> {
221
- return postJson<import('../protocol.ts').PlotlinesResponse>(NOVEL_API.plotlines, req)
222
- }
223
-
224
- /** 敏感词检查:指定章节 / 任意文本 / 全书。 */
225
- async sensitiveCheck(req: import('../protocol.ts').SensitiveCheckRequest): Promise<import('../protocol.ts').SensitiveCheckResponse> {
226
- return postJson<import('../protocol.ts').SensitiveCheckResponse>(NOVEL_API.sensitiveCheck, req)
227
- }
228
-
229
- /** 作者复盘补跑:单章(JSON)。 */
230
- async reviewBackfillChapter(no: number): Promise<{ no: number; review: import('../protocol.ts').AuthorReview }> {
231
- return postJson<{ no: number; review: import('../protocol.ts').AuthorReview }>(NOVEL_API.reviewBackfill, { chapterNo: no })
232
- }
233
-
234
- /** 作者复盘补跑:全书缺失章节(NDJSON 流)。 */
235
- async reviewBackfillAll(onFrame: (frame: JobFrame) => void): Promise<void> {
236
- await this.streamJob(NOVEL_API.reviewBackfill, {}, onFrame)
237
- }
238
-
239
- /** 章节复位:generating 卡死 → pending。 */
240
- async chapterReset(no: number): Promise<{ ok: boolean; no: number }> {
241
- return postJson<{ ok: boolean; no: number }>(NOVEL_API.chapterReset, { chapterNo: no })
242
- }
243
-
244
- /** 章节直接通过(作者行使最终决定权)。 */
245
- async chapterApprove(no: number): Promise<{ ok: boolean; no: number }> {
246
- return postJson<{ ok: boolean; no: number }>(NOVEL_API.chapterApprove, { chapterNo: no })
247
- }
248
-
249
- /** 角色库:AI 提炼 / 采纳 / 更新 / 删除。 */
250
- async imageTest(req: import('../protocol.ts').ImageTestRequest): Promise<import('../protocol.ts').ImageTestResponse> {
251
- return postJson<import('../protocol.ts').ImageTestResponse>(NOVEL_API.imageTest, req)
252
- }
253
-
254
- /** 对选中的提供商/模型发一次最小真实调用,验证连通性。 */
255
- async llmTest(provider: string, model: string): Promise<LlmTestResponse> {
256
- return postJson<LlmTestResponse>(NOVEL_API.llmTest, { provider, model })
257
- }
258
-
259
- /** 添加模型:厂商直填 key,或自定义 OpenAI 兼容路由(写 DSH 凭据 + 注册路由)。 */
260
- async addModel(req: AddModelRequest): Promise<AddModelResponse> {
261
- return postJson<AddModelResponse>(NOVEL_API.addModel, req)
262
- }
263
-
264
- /** 运行时厂商目录(DSH pi-ai 可配置提供方 + 内置适配器)。 */
265
- async llmVendors(): Promise<LlmVendorsResponse> {
266
- const response = await fetch(NOVEL_API.llmVendors)
267
- return readJson<LlmVendorsResponse>(response)
268
- }
269
-
270
- /** 查询某个 provider 当前可用的模型(添加成功后可即时刷新)。 */
271
- async llmModels(provider: string): Promise<LlmModelsResponse> {
272
- const response = await fetch(NOVEL_API.llmModels + '?provider=' + encodeURIComponent(provider))
273
- return readJson<LlmModelsResponse>(response)
274
- }
275
-
276
- /** 已注册的提供方路由列表(提供方管理卡片)。 */
277
- async llmProviders(): Promise<LlmProvidersResponse> {
278
- const response = await fetch(NOVEL_API.llmProviders)
279
- return readJson<LlmProvidersResponse>(response)
280
- }
281
-
282
- /** 移除一个提供方(unset key + 移除 llm-pi-ai 路由)。 */
283
- async removeProvider(req: RemoveProviderRequest): Promise<RemoveProviderResponse> {
284
- return postJson<RemoveProviderResponse>(NOVEL_API.llmRemove, req)
285
- }
286
-
287
- async roles(req: import('../protocol.ts').RolesRequest): Promise<import('../protocol.ts').RolesResponse> {
288
- return postJson<import('../protocol.ts').RolesResponse>(NOVEL_API.roles, req)
289
- }
290
-
291
- /** 漫剧角色库:从分镜提名 / 建卡 / 更新 / 删除 / 形象锚点 / 精修提示词。 */
292
- async mangaRoles(req: import('../protocol.ts').MangaRolesRequest): Promise<import('../protocol.ts').MangaRolesResponse> {
293
- return postJson<import('../protocol.ts').MangaRolesResponse>(NOVEL_API.mangaRoles, req)
294
- }
295
-
296
- /** 导出「即梦素材包」落盘到资产库 manga-assets/素材包/。 */
297
- async exportPackage(chapterNo: number, title: string, markdown: string): Promise<{ ok: boolean; file: string }> {
298
- return postJson<{ ok: boolean; file: string }>(NOVEL_API.exportPackage, { chapterNo, title, markdown })
299
- }
300
-
301
- /** 场景库:AI 提炼 / 采纳 / 更新 / 删除 / 图集。 */
302
- async scenes(req: import('../protocol.ts').ScenesRequest): Promise<import('../protocol.ts').ScenesResponse> {
303
- return postJson<import('../protocol.ts').ScenesResponse>(NOVEL_API.scenes, req)
304
- }
305
-
306
- /** 视觉世界观规则:提炼 / 保存。 */
307
- async visualRules(req: import('../protocol.ts').VisualRulesRequest): Promise<import('../protocol.ts').VisualRulesResponse> {
308
- return postJson<import('../protocol.ts').VisualRulesResponse>(NOVEL_API.visualRules, req)
309
- }
310
-
311
- /** 道具库:从已写章节提炼常驻道具 / 保存清单。 */
312
- async mangaProps(req: import('../protocol.ts').MangaPropsRequest): Promise<import('../protocol.ts').MangaPropsResponse> {
313
- return postJson<import('../protocol.ts').MangaPropsResponse>(NOVEL_API.mangaProps, req)
314
- }
315
-
316
- /** 小说简介:AI 生成/补全(partial 留空 = 全量),或手动保存。 */
317
- async blurb(action: 'generate' | 'save', text?: string, partial?: string): Promise<{ blurb: string }> {
318
- return postJson<{ blurb: string }>(NOVEL_API.blurb, { action, text, partial })
319
- }
320
-
321
- /** 封面:读取(dataUrl;dir 指定某本书的输出目录,省略为当前书)。 */
322
- async coverGet(dir?: string): Promise<import('../protocol.ts').CoverResponse> {
323
- const query = dir !== undefined ? `?dir=${encodeURIComponent(dir)}` : ''
324
- const response = await fetch(NOVEL_API.cover + query)
325
- return readJson<import('../protocol.ts').CoverResponse>(response)
326
- }
327
-
328
- /** 封面:上传(base64 data URL)或移除。 */
329
- async coverPost(action: 'upload' | 'remove', dataUrl?: string): Promise<{ ok: boolean; coverPath?: string | null }> {
330
- return postJson<{ ok: boolean; coverPath?: string | null }>(NOVEL_API.cover, { action, dataUrl })
331
- }
332
-
333
- /** 重命名当前书(同步项目与书架条目)。 */
334
- async rename(bookName: string): Promise<{ bookName: string }> {
335
- return postJson<{ bookName: string }>(NOVEL_API.rename, { bookName })
336
- }
337
-
338
- /** 大世界:AI 提炼(generate)或手动保存(save)。 */
339
- async world(action: 'generate' | 'save', world?: import('../protocol.ts').WorldState): Promise<{ world: import('../protocol.ts').WorldState }> {
340
- return postJson<{ world: import('../protocol.ts').WorldState }>(NOVEL_API.world, { action, world })
341
- }
342
-
343
- /** 切换当前书。 */
344
- async bookActivate(id: string): Promise<import('../protocol.ts').BookshelfSnapshot> {
345
- return postJson<import('../protocol.ts').BookshelfSnapshot>('/api/dsh-novel-forge/bookshelf/activate', { id })
346
- }
347
-
348
- /** 移除书架条目。 */
349
- async bookRemove(id: string): Promise<import('../protocol.ts').BookshelfSnapshot> {
350
- return postJson<import('../protocol.ts').BookshelfSnapshot>('/api/dsh-novel-forge/bookshelf/remove', { id })
351
- }
352
-
353
- /** 导入已有项目目录(Mode A):校验 novel-project.json,登记/激活书架。 */
354
- async bookImportDir(outputDir: string): Promise<import('../protocol.ts').BookImportDirResponse> {
355
- return postJson<import('../protocol.ts').BookImportDirResponse>(NOVEL_API.bookshelfImportDir, { outputDir })
356
- }
357
-
358
- /** 导入 txt/md 全本(Mode B):服务器本地文件路径模式。 */
359
- async bookImportText(filePath: string, outputDir?: string): Promise<import('../protocol.ts').BookImportTextResponse> {
360
- return postJson<import('../protocol.ts').BookImportTextResponse>(NOVEL_API.bookshelfImportText, { filePath, outputDir })
361
- }
362
-
363
- /** 拆章预览(浏览器上传全文,不落盘):返回识别到的章节与跳过清单。 */
364
- async bookImportTextPreview(text: string, fileName?: string): Promise<import('../protocol.ts').BookImportTextPreviewResponse> {
365
- return postJson<import('../protocol.ts').BookImportTextPreviewResponse>(NOVEL_API.bookshelfImportTextPreview, { text, fileName })
366
- }
367
-
368
- /** 导入 txt/md 全本(Mode B):浏览器上传全文内容模式。 */
369
- async bookImportTextContent(text: string, fileName: string, outputDir?: string): Promise<import('../protocol.ts').BookImportTextResponse> {
370
- return postJson<import('../protocol.ts').BookImportTextResponse>(NOVEL_API.bookshelfImportText, { text, fileName, outputDir })
371
- }
372
-
373
- /** 生产单:启动批量生产(区间或新增 N 章;计划不足自动补)。 */
374
- async runStart(req: import('../protocol.ts').RunStartRequest): Promise<import('../protocol.ts').RunState> {
375
- return postJson<import('../protocol.ts').RunState>(NOVEL_API.runStart, req)
376
- }
377
-
378
- /** 生产单控制:pause / resume / stop。 */
379
- async runControl(action: 'pause' | 'resume' | 'stop'): Promise<import('../protocol.ts').RunState | null> {
380
- const response = await fetch(NOVEL_API.runControl, {
381
- method: 'POST',
382
- headers: { 'Content-Type': 'application/json' },
383
- body: JSON.stringify({ action }),
384
- })
385
- if (response.status === 400) return null
386
- return readJson<import('../protocol.ts').RunState>(response)
387
- }
388
-
389
- /** 生产单状态(无生产单返回 null)。 */
390
- async runStatus(): Promise<import('../protocol.ts').RunState | null> {
391
- const response = await fetch(NOVEL_API.runStatus)
392
- if (response.status === 404) return null
393
- return readJson<import('../protocol.ts').RunState | null>(response)
394
- }
395
-
396
- /** Get project writing assets + built-in libraries. */
397
- async assets(): Promise<AssetsResponse> {
398
- const response = await fetch(NOVEL_API.assets)
399
- return readJson<AssetsResponse>(response)
400
- }
401
-
402
- /** Patch project writing assets. */
403
- async patchAssets(patch: AssetsPatch): Promise<AssetsResponse> {
404
- return postJson<AssetsResponse>(NOVEL_API.assets, patch)
405
- }
406
-
407
- /** Extract a style asset from sample text. */
408
- async styleEngine(req: StyleEngineRequest): Promise<{ styleAsset: StyleAsset }> {
409
- return postJson<{ styleAsset: StyleAsset }>(NOVEL_API.styleEngine, req)
410
- }
411
-
412
- /**
413
- * Consume an NDJSON job stream (generate / rewrite / polish).
414
- * @param path - the route to POST to.
415
- * @param payload - the JSON body.
416
- * @param onFrame - receives every frame as it lands.
417
- */
418
- private async streamJob(path: string, payload: unknown, onFrame: (frame: JobFrame) => void): Promise<void> {
419
- const response = await fetch(path, {
420
- method: 'POST',
421
- headers: { 'content-type': 'application/json' },
422
- body: JSON.stringify(payload),
423
- })
424
- if (!response.ok) {
425
- await readJson<{ error?: string }>(response)
426
- return
427
- }
428
- if (response.body === null) throw new NovelApiError('job: no response body')
429
- const reader = response.body.getReader()
430
- const decoder = new TextDecoder()
431
- let buffer = ''
432
- for (;;) {
433
- const { done, value } = await reader.read()
434
- if (done) break
435
- buffer += decoder.decode(value, { stream: true })
436
- const lines = buffer.split('\n')
437
- buffer = lines.pop() ?? ''
438
- for (const line of lines) {
439
- if (line.trim() === '') continue
440
- let frame: JobFrame
441
- try {
442
- frame = JSON.parse(line) as JobFrame
443
- } catch {
444
- continue
445
- }
446
- onFrame(frame)
447
- if (frame.type === 'error') {
448
- throw new NovelApiError(frame.message)
449
- }
450
- }
451
- }
452
- }
453
-
454
- /** Generate one chapter. */
455
- async generate(chapterNo: number, skipReview: boolean, onFrame: (frame: JobFrame) => void): Promise<void> {
456
- await this.streamJob(NOVEL_API.generate, { chapterNo, skipReview }, onFrame)
457
- }
458
-
459
- /** Rewrite one chapter (whole-chapter, or local when `target` is given). */
460
- async rewrite(chapterNo: number, instructions: string, target: string, onFrame: (frame: JobFrame) => void): Promise<void> {
461
- await this.streamJob(NOVEL_API.rewrite, { chapterNo, instructions, target }, onFrame)
462
- }
463
-
464
- /** Polish (de-AI-ify) one chapter. */
465
- async polish(chapterNo: number, onFrame: (frame: JobFrame) => void): Promise<void> {
466
- await this.streamJob(NOVEL_API.polish, { chapterNo }, onFrame)
467
- }
468
-
469
- /** 采纳待确认草稿(润色/重写产物),覆盖正文文件。返回采纳后的新正文(markdown)。
470
- * 可携带审查报告(沿用结论定状态:通过 → approved)。 */
471
- async draftApply(chapterNo: number, report?: import('../protocol.ts').ReviewReport): Promise<{ ok: boolean; chars: number; file: string; markdown: string }> {
472
- return postJson<{ ok: boolean; chars: number; file: string; markdown: string }>(NOVEL_API.draftApply, { chapterNo, report })
473
- }
474
-
475
- /** 放弃待确认草稿,保留原稿。 */
476
- async draftDiscard(chapterNo: number): Promise<{ ok: boolean }> {
477
- return postJson<{ ok: boolean }>(NOVEL_API.draftDiscard, { chapterNo })
478
- }
479
-
480
- /** Run one assistant turn (NDJSON stream). */
481
- async assistant(message: string, onFrame: (frame: import('../protocol.ts').AssistantFrame) => void): Promise<void> {
482
- const response = await fetch(NOVEL_API.assistant, {
483
- method: 'POST',
484
- headers: { 'content-type': 'application/json' },
485
- body: JSON.stringify({ message }),
486
- })
487
- if (!response.ok) {
488
- await readJson<{ error?: string }>(response)
489
- return
490
- }
491
- if (response.body === null) throw new NovelApiError('assistant: no response body')
492
- const reader = response.body.getReader()
493
- const decoder = new TextDecoder()
494
- let buffer = ''
495
- for (;;) {
496
- const { done, value } = await reader.read()
497
- if (done) break
498
- buffer += decoder.decode(value, { stream: true })
499
- const lines = buffer.split('\n')
500
- buffer = lines.pop() ?? ''
501
- for (const line of lines) {
502
- if (line.trim() === '') continue
503
- let frame: import('../protocol.ts').AssistantFrame
504
- try {
505
- frame = JSON.parse(line) as import('../protocol.ts').AssistantFrame
506
- } catch {
507
- continue
508
- }
509
- onFrame(frame)
510
- if (frame.type === 'error') throw new NovelApiError(frame.message)
511
- }
512
- }
513
- }
514
-
515
- /** Load the persisted assistant conversation. */
516
- async assistantHistory(): Promise<import('../protocol.ts').AssistantMessage[]> {
517
- const response = await fetch(NOVEL_API.assistantHistory)
518
- const body = await readJson<{ messages: import('../protocol.ts').AssistantMessage[] }>(response)
519
- return body.messages
520
- }
521
-
522
- /** 清空助手对话记录。 */
523
- async assistantClear(): Promise<{ ok: boolean }> {
524
- return postJson<{ ok: boolean }>(NOVEL_API.assistantClear, {})
525
- }
526
-
527
- /** 作者资产库/总数据:读取跨书可复用资产。 */
528
- async authorAssets(): Promise<import('../protocol.ts').AuthorAssetsResponse> {
529
- const response = await fetch(NOVEL_API.authorAssets)
530
- return readJson<import('../protocol.ts').AuthorAssetsResponse>(response)
531
- }
532
-
533
- /** 作者资产库:新增/更新一条资产(upsert by id)。 */
534
- async authorAssetsUpsert(asset: import('../protocol.ts').AuthorStyleAsset): Promise<import('../protocol.ts').AuthorAssetsResponse> {
535
- return postJson<import('../protocol.ts').AuthorAssetsResponse>(NOVEL_API.authorAssetsUpsert, { asset })
536
- }
537
-
538
- /** 作者资产库:删除一条资产。 */
539
- async authorAssetsRemove(id: string): Promise<import('../protocol.ts').AuthorAssetsResponse> {
540
- return postJson<import('../protocol.ts').AuthorAssetsResponse>(NOVEL_API.authorAssetsRemove, { id })
541
- }
542
-
543
- /** 作者资产库:导入默认(书架书的写作资产/角色 + 内置全局库)批量沉淀。 */
544
- async authorAssetsImportDefault(): Promise<import('../protocol.ts').AuthorAssetsResponse> {
545
- return postJson<import('../protocol.ts').AuthorAssetsResponse>(NOVEL_API.authorAssetsImportDefault, {})
546
- }
547
-
548
- /** 改编模式 P0:上传全文 → 原文设定卡片 / 可改范围矩阵。 */
549
- async adaptAnalyze(text: string, filePath?: string): Promise<import('../protocol.ts').AdaptAnalyzeResponse> {
550
- return postJson<import('../protocol.ts').AdaptAnalyzeResponse>(NOVEL_API.adaptAnalyze, { text, filePath })
551
- }
552
-
553
- /** 改编模式 P1:确认要改的维度 → 生成映射表/改编规则/联动影响清单。 */
554
- async adaptPropose(req: import('../protocol.ts').AdaptProposeRequest): Promise<import('../protocol.ts').AdaptProposeResponse> {
555
- return postJson<import('../protocol.ts').AdaptProposeResponse>(NOVEL_API.adaptPropose, req)
556
- }
557
-
558
- /** 改编模式 P2:执行术语替换(全局替换 + 命中统计 + 改编文本预览)。 */
559
- async adaptExecute(req: import('../protocol.ts').AdaptExecuteRequest): Promise<import('../protocol.ts').AdaptExecuteResponse> {
560
- return postJson<import('../protocol.ts').AdaptExecuteResponse>(NOVEL_API.adaptExecute, req)
561
- }
562
-
563
- /** 改编模式 P3:保存改编全文为新书(原书保留,登记书架)。 */
564
- async adaptSave(req: import('../protocol.ts').AdaptSaveRequest): Promise<import('../protocol.ts').AdaptSaveResponse> {
565
- return postJson<import('../protocol.ts').AdaptSaveResponse>(NOVEL_API.adaptSave, req)
566
- }
567
-
568
- /** 改编模式 P4:从源全文 + 编辑后方案提炼新书资料并保存为「待写新书」。 */
569
- async adaptMaterialize(req: import('../protocol.ts').AdaptMaterializeRequest): Promise<import('../protocol.ts').AdaptMaterializeResponse> {
570
- return postJson<import('../protocol.ts').AdaptMaterializeResponse>(NOVEL_API.adaptMaterialize, req)
571
- }
572
-
573
- /** 改编模式:保存预览/微调后的新书资料为新书(原书保留,登记书架)。 */
574
- async adaptMaterializeSave(req: AdaptMaterializeSaveRequest): Promise<AdaptMaterializeSaveResponse> {
575
- return postJson<AdaptMaterializeSaveResponse>(NOVEL_API.adaptMaterializeSave, req)
576
- }
577
-
578
- /** 改编模式:rewrite 逐章重写(NDJSON 流式进度,支持分段 startNo/endNo)。 */
579
- async adaptRewriteStream(req: AdaptExecuteRequest, onFrame: (frame: AdaptRewriteFrame) => void): Promise<void> {
580
- const response = await fetch(NOVEL_API.adaptRewriteStream, {
581
- method: 'POST',
582
- headers: { 'content-type': 'application/json' },
583
- body: JSON.stringify(req),
584
- })
585
- if (!response.ok) {
586
- await readJson<{ error?: string }>(response)
587
- return
588
- }
589
- if (response.body === null) throw new NovelApiError('adapt rewrite: no response body')
590
- const reader = response.body.getReader()
591
- const decoder = new TextDecoder()
592
- let buffer = ''
593
- for (;;) {
594
- const { done, value } = await reader.read()
595
- if (done) break
596
- buffer += decoder.decode(value, { stream: true })
597
- const lines = buffer.split('\n')
598
- buffer = lines.pop() ?? ''
599
- for (const line of lines) {
600
- if (line.trim() === '') continue
601
- let frame: AdaptRewriteFrame
602
- try {
603
- frame = JSON.parse(line) as AdaptRewriteFrame
604
- } catch {
605
- continue
606
- }
607
- onFrame(frame)
608
- if (frame.type === 'error') throw new NovelApiError(frame.message)
609
- }
610
- }
611
- }
612
-
613
- /** 主题自定义背景:上传图片,服务端存盘并返回可访问 URL。 */
614
- async themeBackgroundUpload(dataUrl: string): Promise<{ url: string }> {
615
- return postJson<{ url: string }>(NOVEL_API.themeBackgroundUpload, { dataUrl })
616
- }
617
- }
@@ -1,8 +0,0 @@
1
- /**
2
- * CSS module type shim (bundler injects the class map at build time).
3
- */
4
-
5
- declare module '*.module.css' {
6
- const classes: Record<string, string>
7
- export default classes
8
- }