@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
@@ -1,303 +0,0 @@
1
- /**
2
- * 导入小说弹窗:两种模式 ——
3
- * A) 已有项目目录(含 novel-project.json)→ 登记/激活书架(粘贴服务器本地路径);
4
- * B) txt/md 全本 → 点击选择文件,浏览器读取内容 → 服务器拆章预览 → 确认后导入。
5
- * Mode B 也保留「服务器本地路径」高级选项(大文件或服务器端已有文件时用)。
6
- */
7
- import { useEffect, useRef, useState } from 'react'
8
- import type { NovelApi } from '../api.ts'
9
- import type { BookImportTextPreviewResponse } from '../../protocol.ts'
10
- import { readFileTextSmart } from '../text.ts'
11
- import css from './panel.module.css'
12
-
13
- type ImportMode = 'dir' | 'text'
14
-
15
- /** 导入结果(成功态展示)。 */
16
- interface ImportResult {
17
- kind: 'dir' | 'text'
18
- bookName: string
19
- existed?: boolean
20
- chapters?: number
21
- skipped?: string[]
22
- }
23
-
24
- export function ImportModal({
25
- api,
26
- onClose,
27
- onImported,
28
- }: {
29
- api: NovelApi
30
- onClose: () => void
31
- /** 导入成功并已激活该书后回调(刷新书架)。 */
32
- onImported: () => void | Promise<void>
33
- }) {
34
- const [mode, setMode] = useState<ImportMode>('dir')
35
- // Mode A
36
- const [dir, setDir] = useState('')
37
- // Mode B:文件选择 + 预览
38
- const fileInputRef = useRef<HTMLInputElement | null>(null)
39
- const [fileName, setFileName] = useState('')
40
- const [fileText, setFileText] = useState<string | null>(null)
41
- const [previewing, setPreviewing] = useState(false)
42
- const [preview, setPreview] = useState<BookImportTextPreviewResponse | null>(null)
43
- // Mode B:服务器本地路径(高级)
44
- const [showPath, setShowPath] = useState(false)
45
- const [filePath, setFilePath] = useState('')
46
- // 通用
47
- const [outDir, setOutDir] = useState('')
48
- const [busy, setBusy] = useState(false)
49
- const [error, setError] = useState('')
50
- const [result, setResult] = useState<ImportResult | null>(null)
51
-
52
- /** 选择文件 → 读取内容 → 调服务器预览拆章。 */
53
- const onPickFile = async (file: File | undefined) => {
54
- if (file === undefined) return
55
- setError('')
56
- setResult(null)
57
- setPreview(null)
58
- setFileName(file.name)
59
- setPreviewing(true)
60
- try {
61
- const text = await readFileTextSmart(file)
62
- setFileText(text)
63
- const p = await api.bookImportTextPreview(text, file.name)
64
- setPreview(p)
65
- } catch (err) {
66
- setError((err as Error).message)
67
- } finally {
68
- setPreviewing(false)
69
- }
70
- }
71
-
72
- const runImport = async () => {
73
- setError('')
74
- setResult(null)
75
- if (mode === 'dir') {
76
- const d = dir.trim()
77
- if (d === '') { setError('请输入项目目录(含 novel-project.json 的文件夹)'); return }
78
- setBusy(true)
79
- try {
80
- const r = await api.bookImportDir(d)
81
- setResult({ kind: 'dir', bookName: r.book.bookName, existed: r.existed })
82
- await onImported()
83
- } catch (err) {
84
- setError((err as Error).message)
85
- } finally {
86
- setBusy(false)
87
- }
88
- return
89
- }
90
- // Mode B:优先上传内容;未选文件时退回服务器路径
91
- if (fileText !== null && fileText.length > 0) {
92
- setBusy(true)
93
- try {
94
- const o = outDir.trim()
95
- const r = await api.bookImportTextContent(fileText, fileName, o !== '' ? o : undefined)
96
- setResult({ kind: 'text', bookName: r.bookName, chapters: r.chapters, skipped: r.skipped })
97
- await onImported()
98
- } catch (err) {
99
- setError((err as Error).message)
100
- } finally {
101
- setBusy(false)
102
- }
103
- return
104
- }
105
- const f = filePath.trim()
106
- if (f === '') { setError('请先选择文件,或输入服务器本地文件路径'); return }
107
- setBusy(true)
108
- try {
109
- const o = outDir.trim()
110
- const r = await api.bookImportText(f, o !== '' ? o : undefined)
111
- setResult({ kind: 'text', bookName: r.bookName, chapters: r.chapters, skipped: r.skipped })
112
- await onImported()
113
- } catch (err) {
114
- setError((err as Error).message)
115
- } finally {
116
- setBusy(false)
117
- }
118
- }
119
-
120
- const switchMode = (m: ImportMode) => { setMode(m); setError(''); setResult(null); setPreview(null) }
121
-
122
- // Esc 关闭弹窗。
123
- useEffect(() => {
124
- const onKey = (e: KeyboardEvent): void => {
125
- if (e.key === 'Escape') onClose()
126
- }
127
- window.addEventListener('keydown', onKey)
128
- return () => { window.removeEventListener('keydown', onKey) }
129
- }, [onClose])
130
-
131
- return (
132
- <div className={css.importModalOverlay} role="dialog" aria-modal="true" aria-label="导入小说" onClick={e => { if (e.target === e.currentTarget) onClose() }}>
133
- <div className={css.importModal}>
134
- <div className={css.importModalHead}>
135
- <span className={css.panelTitle} style={{ margin: 0 }}>📥 导入小说</span>
136
- <button type="button" className={`${css.button} ${css.buttonSmall}`} onClick={onClose} title="关闭">✕</button>
137
- </div>
138
-
139
- <div className={css.importModalTabs} role="tablist">
140
- <button
141
- type="button"
142
- role="tab"
143
- aria-selected={mode === 'dir'}
144
- className={`${css.button} ${mode === 'dir' ? css.buttonPrimary : ''}`}
145
- onClick={() => { switchMode('dir') }}
146
- >
147
- 📂 A · 已有项目目录
148
- </button>
149
- <button
150
- type="button"
151
- role="tab"
152
- aria-selected={mode === 'text'}
153
- className={`${css.button} ${mode === 'text' ? css.buttonPrimary : ''}`}
154
- onClick={() => { switchMode('text') }}
155
- >
156
- 📄 B · txt/md 全本
157
- </button>
158
- </div>
159
-
160
- <div className={css.importModalBody}>
161
- {mode === 'dir' ? (
162
- <>
163
- <label className={css.importField}>
164
- <span>项目目录(绝对路径)</span>
165
- <input
166
- className={css.input}
167
- type="text"
168
- placeholder="例如 D:\novels\我的小说"
169
- value={dir}
170
- onChange={e => { setDir(e.target.value) }}
171
- />
172
- </label>
173
- <div className={css.importHint}>
174
- 目录需含 novel-project.json。已在书架中的目录会直接切换激活,不会重复登记。
175
- </div>
176
- </>
177
- ) : (
178
- <>
179
- {/* 文件选择 + 预览 */}
180
- <input
181
- ref={fileInputRef}
182
- type="file"
183
- accept=".txt,.md,text/plain,text/markdown"
184
- style={{ display: 'none' }}
185
- onChange={e => { void onPickFile(e.target.files?.[0]); e.target.value = '' }}
186
- />
187
- <div className={css.importField}>
188
- <span>全本文本文件(txt / md)</span>
189
- <button
190
- type="button"
191
- className={`${css.button} ${css.buttonPrimary}`}
192
- onClick={() => { fileInputRef.current?.click() }}
193
- >
194
- 📄 选择文件
195
- </button>
196
- </div>
197
- {fileName !== '' && (
198
- <div className={css.importFileInfo}>
199
- <span>已选择:{fileName}</span>
200
- {previewing && <span className={css.meta}>正在拆章预览…</span>}
201
- </div>
202
- )}
203
- {preview !== null && (
204
- <div className={css.importPreview}>
205
- <span>📖 《{preview.bookName}》 · 识别到 {preview.chapters.length} 章</span>
206
- {preview.chapters.length > 0 && (
207
- <ul className={css.importPreviewList}>
208
- {preview.chapters.slice(0, 5).map(c => (
209
- <li key={c.no}>第{c.no}章 {c.title}({c.chars} 字)</li>
210
- ))}
211
- {preview.chapters.length > 5 && <li className={css.meta}>… 共 {preview.chapters.length} 章</li>}
212
- </ul>
213
- )}
214
- {preview.skipped.length > 0 && (
215
- <span className={css.meta}>
216
- 跳过 {preview.skipped.length} 个过短章节:{preview.skipped.slice(0, 5).join('、')}
217
- {preview.skipped.length > 5 ? ' 等' : ''}
218
- </span>
219
- )}
220
- </div>
221
- )}
222
-
223
- {/* 输出目录 + 高级路径选项 */}
224
- <label className={css.importField}>
225
- <span>输出目录(可选,默认 ~/.dsh/novels/书名)</span>
226
- <input
227
- className={css.input}
228
- type="text"
229
- placeholder="留空使用默认目录"
230
- value={outDir}
231
- onChange={e => { setOutDir(e.target.value) }}
232
- />
233
- </label>
234
- <button
235
- type="button"
236
- className={`${css.button} ${css.buttonSmall}`}
237
- onClick={() => { setShowPath(!showPath) }}
238
- >
239
- {showPath ? '▾ 收起高级选项' : '▸ 高级:使用服务器本地文件路径'}
240
- </button>
241
- {showPath && (
242
- <label className={css.importField}>
243
- <span>服务器本地文件绝对路径(大文件或服务器端已有文件时用)</span>
244
- <input
245
- className={css.input}
246
- type="text"
247
- placeholder="例如 D:\novels\全本.txt"
248
- value={filePath}
249
- onChange={e => { setFilePath(e.target.value) }}
250
- />
251
- </label>
252
- )}
253
- <div className={css.importHint}>
254
- 服务器按「第X章/第X回/第X节/第X卷」、中文数字章节(一、二、三…)、序章/楔子/尾声、英文 Chapter N 拆章;正文过短(&lt;50 字)的章节会跳过并列出。
255
- </div>
256
- </>
257
- )}
258
-
259
- {error !== '' && <div className={css.importError}>{error}</div>}
260
-
261
- {result !== null && (
262
- <div className={css.importResult}>
263
- {result.kind === 'dir' ? (
264
- <>
265
- <span>✅ 已{result.existed === true ? '重新激活' : '登记'}《{result.bookName}》</span>
266
- <span className={css.meta}>
267
- {result.existed === true
268
- ? '该目录已在书架中,现已切换为当前书;工作台数据按该书目录加载。'
269
- : '已加入书架并设为当前书,进入工作台即可看到全部模块。'
270
- }
271
- </span>
272
- </>
273
- ) : (
274
- <>
275
- <span>✅ 《{result.bookName}》导入完成:{result.chapters} 章</span>
276
- {(result.skipped ?? []).length > 0 && (
277
- <span className={css.meta}>
278
- 跳过 {result.skipped!.length} 个过短章节:{result.skipped!.slice(0, 8).join('、')}
279
- {result.skipped!.length > 8 ? ` 等 ${result.skipped!.length} 个` : ''}
280
- </span>
281
- )}
282
- <span className={css.meta}>章节已按「written」登记,进入工作台后逐章审稿/补设定即可。</span>
283
- </>
284
- )}
285
- </div>
286
- )}
287
- </div>
288
-
289
- <div className={css.importModalActions}>
290
- <button type="button" className={`${css.button} ${css.buttonSmall}`} onClick={onClose}>关闭</button>
291
- <button
292
- type="button"
293
- className={`${css.button} ${css.buttonPrimary}`}
294
- disabled={busy}
295
- onClick={runImport}
296
- >
297
- {busy ? '导入中…' : '开始导入'}
298
- </button>
299
- </div>
300
- </div>
301
- </div>
302
- )
303
- }