@waterwx/dsh-novel-forge 2.1.2-alpha → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/README.md +278 -368
  2. package/lib/client.js +19568 -21381
  3. package/lib/index.js +5158 -3958
  4. package/lib/types/action-guard.d.ts +61 -0
  5. package/lib/types/ai-scan.d.ts +80 -12
  6. package/lib/types/assets.d.ts +7 -9
  7. package/lib/types/assistant.d.ts +25 -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 +49 -29
  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 +12 -14
  14. package/lib/types/client/locales.d.ts +12 -67
  15. package/lib/types/client/mount.d.ts +0 -2
  16. package/lib/types/client/panel/AdaptModeView.d.ts +1 -1
  17. package/lib/types/client/panel/AiTag.d.ts +1 -0
  18. package/lib/types/client/panel/AssetsTab.d.ts +1 -1
  19. package/lib/types/client/panel/AssistantTab.d.ts +4 -1
  20. package/lib/types/client/panel/AuthorAssetsView.d.ts +1 -1
  21. package/lib/types/client/panel/AuthorHome.d.ts +12 -12
  22. package/lib/types/client/panel/CmdPalette.d.ts +12 -0
  23. package/lib/types/client/panel/CreateBookView.d.ts +1 -1
  24. package/lib/types/client/panel/GlobalAssetLibraryView.d.ts +1 -1
  25. package/lib/types/client/panel/ImportModal.d.ts +1 -1
  26. package/lib/types/client/panel/LiveFeedLog.d.ts +8 -0
  27. package/lib/types/client/panel/ModelManager.d.ts +2 -2
  28. package/lib/types/client/panel/NovelPanel.d.ts +7 -2
  29. package/lib/types/client/panel/PageHeader.d.ts +18 -0
  30. package/lib/types/client/panel/ProgressConsole.d.ts +1 -1
  31. package/lib/types/client/panel/PromptSlotsView.d.ts +11 -0
  32. package/lib/types/client/panel/ReaderView.d.ts +1 -1
  33. package/lib/types/client/panel/RunPanel.d.ts +1 -1
  34. package/lib/types/client/panel/SettingsView.d.ts +13 -10
  35. package/lib/types/client/panel/ShelfView.d.ts +11 -2
  36. package/lib/types/client/panel/SubPage.d.ts +27 -0
  37. package/lib/types/client/panel/TensionView.d.ts +18 -0
  38. package/lib/types/client/panel/TimelineView.d.ts +18 -0
  39. package/lib/types/client/panel/WorldTab.d.ts +1 -1
  40. package/lib/types/client/panel/helpers.d.ts +5 -3
  41. package/lib/types/client/panel/market-radar-state.d.ts +56 -0
  42. package/lib/types/client/panel/outline-markdown.d.ts +112 -0
  43. package/lib/types/client/panel/status-badge.d.ts +13 -0
  44. package/lib/types/client/panel/storage-parse.d.ts +46 -0
  45. package/lib/types/client/panel/toast.d.ts +2 -0
  46. package/lib/types/client/panel/usePersistentState.d.ts +17 -0
  47. package/lib/types/client/panel/views.d.ts +21 -35
  48. package/lib/types/client/run-status.d.ts +21 -0
  49. package/lib/types/client/sidebar-entry.d.ts +0 -2
  50. package/lib/types/digest-parse.d.ts +29 -0
  51. package/lib/types/docx-core.d.ts +16 -0
  52. package/lib/types/docx.d.ts +2 -3
  53. package/lib/types/engine.d.ts +122 -103
  54. package/lib/types/home.d.ts +11 -0
  55. package/lib/types/index.d.ts +21 -13
  56. package/lib/types/llm-live.d.ts +62 -36
  57. package/lib/types/llm-retry.d.ts +38 -0
  58. package/lib/types/market-radar-scan.d.ts +0 -1
  59. package/lib/types/market-radar-sources.d.ts +1 -1
  60. package/lib/types/migrate-output.d.ts +25 -0
  61. package/lib/types/model-capability.d.ts +119 -0
  62. package/lib/types/model-request.d.ts +36 -0
  63. package/lib/types/output-budget.d.ts +86 -0
  64. package/lib/types/plotline-align.d.ts +35 -0
  65. package/lib/types/prompt-slots.d.ts +57 -0
  66. package/lib/types/prompting.d.ts +2 -27
  67. package/lib/types/protocol.d.ts +479 -595
  68. package/lib/types/revision.d.ts +76 -0
  69. package/lib/types/routes.d.ts +9 -3
  70. package/lib/types/run-selection.d.ts +51 -0
  71. package/lib/types/run.d.ts +31 -0
  72. package/lib/types/settings-persist.d.ts +59 -0
  73. package/lib/types/snapshots.d.ts +46 -0
  74. package/lib/types/stage-contract.d.ts +58 -0
  75. package/lib/types/stream-fallback.d.ts +60 -0
  76. package/lib/types/strip-headings.d.ts +33 -0
  77. package/lib/types/style-fingerprint.d.ts +78 -0
  78. package/lib/types/tension.d.ts +53 -0
  79. package/lib/types/timeline.d.ts +37 -0
  80. package/package.json +41 -28
  81. package/assets/styles/arcane-thick-3d.webp +0 -0
  82. package/assets/styles/chinese-ink.webp +0 -0
  83. package/assets/styles/clay-stopmotion-3d.webp +0 -0
  84. package/assets/styles/dark-ghibli.webp +0 -0
  85. package/assets/styles/dark-gothic-3d.webp +0 -0
  86. package/assets/styles/film-photo.webp +0 -0
  87. package/assets/styles/guofeng-heavy.webp +0 -0
  88. package/assets/styles/guoman-2d-gufeng.webp +0 -0
  89. package/assets/styles/guoman-3d-tianyuan.webp +0 -0
  90. package/assets/styles/guoman-3d-xuanhuan.webp +0 -0
  91. package/assets/styles/horror-game-3d.webp +0 -0
  92. package/assets/styles/hyperreal-3d.webp +0 -0
  93. package/assets/styles/japan-cel-dark.webp +0 -0
  94. package/assets/styles/korean-webtoon.webp +0 -0
  95. package/assets/styles/low-cyberpunk-3d.webp +0 -0
  96. package/assets/styles/nextgen-cg.webp +0 -0
  97. package/assets/styles/noir-film.webp +0 -0
  98. package/assets/styles/openworld-survival.webp +0 -0
  99. package/assets/styles/paper-cut-3d.webp +0 -0
  100. package/assets/styles/pixar-adult-3d.webp +0 -0
  101. package/assets/styles/pop-marvel-2d.webp +0 -0
  102. package/assets/styles/sandiao-qban.webp +0 -0
  103. package/assets/styles/shinkai-anime.webp +0 -0
  104. package/assets/styles/tactical-stealth.webp +0 -0
  105. package/assets/styles/urban-lightreal-3d.webp +0 -0
  106. package/assets/styles/vaporwave-3d.webp +0 -0
  107. package/assets/styles/vhs90.webp +0 -0
  108. package/lib/types/client/panel/BookshelfBar.d.ts +0 -11
  109. package/lib/types/client/panel/FlowGuide.d.ts +0 -22
  110. package/lib/types/client/panel/MangaRoleLibrary.d.ts +0 -20
  111. package/lib/types/client/panel/MangaWorkspace.d.ts +0 -12
  112. package/lib/types/client/panel/ModelPicker.d.ts +0 -11
  113. package/lib/types/client/panel/ProgressHomeView.d.ts +0 -5
  114. package/lib/types/client/panel/PropLibrary.d.ts +0 -8
  115. package/lib/types/client/panel/SceneLibrary.d.ts +0 -16
  116. package/lib/types/client/panel/StoryboardTab.d.ts +0 -19
  117. package/lib/types/client/panel/StyleCard.d.ts +0 -8
  118. package/lib/types/client/panel/StyleGallery.d.ts +0 -1
  119. package/lib/types/comic-presets.d.ts +0 -12
  120. package/lib/types/manga-genre-rules.d.ts +0 -22
  121. package/lib/types/prompt-utils.d.ts +0 -35
  122. package/lib/types/review-policy.d.ts +0 -97
  123. package/lib/types/shot-language.d.ts +0 -46
  124. package/lib/types/src/ai-scan.d.ts +0 -36
  125. package/lib/types/src/assets.d.ts +0 -37
  126. package/lib/types/src/assistant.d.ts +0 -45
  127. package/lib/types/src/author-assets.d.ts +0 -25
  128. package/lib/types/src/bookshelf.d.ts +0 -42
  129. package/lib/types/src/client/api.d.ts +0 -234
  130. package/lib/types/src/client/docx.d.ts +0 -15
  131. package/lib/types/src/client/index.d.ts +0 -14
  132. package/lib/types/src/client/locales.d.ts +0 -212
  133. package/lib/types/src/client/mount.d.ts +0 -9
  134. package/lib/types/src/client/panel/AdaptModeView.d.ts +0 -5
  135. package/lib/types/src/client/panel/AssetsTab.d.ts +0 -12
  136. package/lib/types/src/client/panel/AssistantTab.d.ts +0 -7
  137. package/lib/types/src/client/panel/AuthorAssetsView.d.ts +0 -4
  138. package/lib/types/src/client/panel/AuthorHome.d.ts +0 -32
  139. package/lib/types/src/client/panel/BookshelfBar.d.ts +0 -11
  140. package/lib/types/src/client/panel/CreateBookView.d.ts +0 -9
  141. package/lib/types/src/client/panel/FlowGuide.d.ts +0 -22
  142. package/lib/types/src/client/panel/GlobalAssetLibraryView.d.ts +0 -4
  143. package/lib/types/src/client/panel/ImportModal.d.ts +0 -7
  144. package/lib/types/src/client/panel/MangaRoleLibrary.d.ts +0 -20
  145. package/lib/types/src/client/panel/MangaWorkspace.d.ts +0 -12
  146. package/lib/types/src/client/panel/ModelManager.d.ts +0 -14
  147. package/lib/types/src/client/panel/NovelPanel.d.ts +0 -13
  148. package/lib/types/src/client/panel/ProgressConsole.d.ts +0 -17
  149. package/lib/types/src/client/panel/ProgressHomeView.d.ts +0 -5
  150. package/lib/types/src/client/panel/PropLibrary.d.ts +0 -8
  151. package/lib/types/src/client/panel/ReaderView.d.ts +0 -8
  152. package/lib/types/src/client/panel/ReasoningSection.d.ts +0 -10
  153. package/lib/types/src/client/panel/RunPanel.d.ts +0 -5
  154. package/lib/types/src/client/panel/SceneLibrary.d.ts +0 -16
  155. package/lib/types/src/client/panel/SettingsView.d.ts +0 -16
  156. package/lib/types/src/client/panel/ShelfView.d.ts +0 -15
  157. package/lib/types/src/client/panel/StoryboardTab.d.ts +0 -19
  158. package/lib/types/src/client/panel/StyleCard.d.ts +0 -8
  159. package/lib/types/src/client/panel/StyleGallery.d.ts +0 -1
  160. package/lib/types/src/client/panel/WorldTab.d.ts +0 -10
  161. package/lib/types/src/client/panel/controller.d.ts +0 -19
  162. package/lib/types/src/client/panel/helpers.d.ts +0 -18
  163. package/lib/types/src/client/panel/views.d.ts +0 -77
  164. package/lib/types/src/client/sidebar-entry.d.ts +0 -13
  165. package/lib/types/src/client/text.d.ts +0 -9
  166. package/lib/types/src/comic-presets.d.ts +0 -12
  167. package/lib/types/src/docx.d.ts +0 -19
  168. package/lib/types/src/engine.d.ts +0 -402
  169. package/lib/types/src/index.d.ts +0 -79
  170. package/lib/types/src/manga-genre-rules.d.ts +0 -22
  171. package/lib/types/src/novel-context.d.ts +0 -80
  172. package/lib/types/src/prompt-utils.d.ts +0 -35
  173. package/lib/types/src/protocol.d.ts +0 -2176
  174. package/lib/types/src/review-policy.d.ts +0 -97
  175. package/lib/types/src/routes.d.ts +0 -29
  176. package/lib/types/src/run.d.ts +0 -32
  177. package/lib/types/src/shot-language.d.ts +0 -46
  178. package/lib/types/src/story-beat-language.d.ts +0 -35
  179. package/lib/types/src/style-library.d.ts +0 -33
  180. package/lib/types/story-beat-language.d.ts +0 -35
  181. package/lib/types/style-library.d.ts +0 -33
  182. package/src/ai-scan.ts +0 -179
  183. package/src/assets.ts +0 -1774
  184. package/src/assistant.ts +0 -915
  185. package/src/author-assets.ts +0 -147
  186. package/src/bookshelf.ts +0 -167
  187. package/src/client/api.ts +0 -716
  188. package/src/client/css-modules.d.ts +0 -8
  189. package/src/client/docx.ts +0 -69
  190. package/src/client/index.ts +0 -34
  191. package/src/client/llmLive.ts +0 -101
  192. package/src/client/locales.ts +0 -418
  193. package/src/client/mount.tsx +0 -97
  194. package/src/client/mount.tsx._new +0 -97
  195. package/src/client/mount.tsx._nf +0 -97
  196. package/src/client/mount.tsx._tmp +0 -97
  197. package/src/client/panel/AdaptModeView.tsx +0 -535
  198. package/src/client/panel/AssetsTab.tsx +0 -458
  199. package/src/client/panel/AssistantTab.tsx +0 -339
  200. package/src/client/panel/AuthorAssetsView.tsx +0 -208
  201. package/src/client/panel/AuthorHome.tsx +0 -234
  202. package/src/client/panel/BookAnalysisView.tsx +0 -60
  203. package/src/client/panel/BookshelfBar.tsx +0 -170
  204. package/src/client/panel/CreateBookView.tsx +0 -371
  205. package/src/client/panel/DirectorView.tsx +0 -200
  206. package/src/client/panel/FlowGuide.tsx +0 -84
  207. package/src/client/panel/GlobalAssetLibraryView.tsx +0 -172
  208. package/src/client/panel/IdeaInspirationView.tsx +0 -71
  209. package/src/client/panel/ImportModal.tsx +0 -303
  210. package/src/client/panel/KnowledgeBaseView.tsx +0 -73
  211. package/src/client/panel/LiveFeedLog.tsx +0 -76
  212. package/src/client/panel/MangaRoleLibrary.tsx +0 -1002
  213. package/src/client/panel/MangaWorkspace.tsx +0 -715
  214. package/src/client/panel/MarketRadarView.tsx +0 -374
  215. package/src/client/panel/ModelManager.tsx +0 -205
  216. package/src/client/panel/NovelPanel.tsx +0 -4721
  217. package/src/client/panel/ProgressConsole.tsx +0 -63
  218. package/src/client/panel/ProgressHomeView.tsx +0 -87
  219. package/src/client/panel/PropLibrary.tsx +0 -175
  220. package/src/client/panel/ReaderView.tsx +0 -306
  221. package/src/client/panel/ReasoningSection.tsx +0 -31
  222. package/src/client/panel/RunPanel.tsx +0 -204
  223. package/src/client/panel/SceneLibrary.tsx +0 -453
  224. package/src/client/panel/SettingsView.tsx +0 -289
  225. package/src/client/panel/ShelfView.tsx +0 -242
  226. package/src/client/panel/StoryboardTab.tsx +0 -472
  227. package/src/client/panel/StyleCard.tsx +0 -90
  228. package/src/client/panel/StyleGallery.tsx +0 -58
  229. package/src/client/panel/WorldTab.tsx +0 -202
  230. package/src/client/panel/controller.ts +0 -45
  231. package/src/client/panel/helpers.ts +0 -67
  232. package/src/client/panel/panel.module.css +0 -4359
  233. package/src/client/panel/views.tsx +0 -314
  234. package/src/client/sidebar-entry.ts +0 -122
  235. package/src/client/text.ts +0 -28
  236. package/src/comic-presets.ts +0 -67
  237. package/src/docx.ts +0 -83
  238. package/src/engine.ts +0 -5636
  239. package/src/global-assets.ts +0 -59
  240. package/src/index.ts +0 -346
  241. package/src/llm-live.ts +0 -68
  242. package/src/manga-genre-rules.ts +0 -87
  243. package/src/market-radar-scan.ts +0 -41
  244. package/src/market-radar-sources.ts +0 -173
  245. package/src/novel-context.ts +0 -287
  246. package/src/prompt-utils.ts +0 -73
  247. package/src/prompting.ts +0 -159
  248. package/src/protocol.ts +0 -2565
  249. package/src/review-policy.ts +0 -161
  250. package/src/routes.ts +0 -3939
  251. package/src/run.ts +0 -338
  252. package/src/shot-language.ts +0 -181
  253. package/src/story-beat-language.ts +0 -130
  254. package/src/style-library.ts +0 -84
@@ -1,147 +0,0 @@
1
- /**
2
- * 作者资产库/总数据(跨书)— 按作者维度聚合的可复用资产。
3
- * 与书架同惯例持久化到 ~/.dsh/dsh-novel-forge-author-assets.json。
4
- * 提供读取/持久化/新增或更新/删除,以及「导入默认」:把书架书的写作资产/角色 +
5
- * 内置全局库(题材/反AI规则/风格模板/推进模式)批量沉淀成资产条目(默认库)。
6
- */
7
-
8
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
9
- import { homedir } from 'node:os'
10
- import { join } from 'node:path'
11
- import { randomBytes } from 'node:crypto'
12
- import type { AuthorAssetLibrary, AuthorStyleAsset, GenreNode, AntiAiRule, StyleTemplate, ProgressionMode } from './protocol.ts'
13
-
14
- import { loadBookshelf } from './bookshelf.ts'
15
- import { loadProject } from './engine.ts'
16
-
17
- /** 作者资产库配置文件路径。 */
18
- export function authorAssetsFile(): string {
19
- return join(homedir(), '.dsh', 'dsh-novel-forge-author-assets.json')
20
- }
21
-
22
- /** 默认空资产库。 */
23
- function defaultLibrary(): AuthorAssetLibrary {
24
- return { version: 1, items: [] }
25
- }
26
-
27
- /** 读取作者资产库(不存在/损坏则返回空库,不抛错)。 */
28
- export function loadAuthorAssets(): AuthorAssetLibrary {
29
- const file = authorAssetsFile()
30
- if (!existsSync(file)) return defaultLibrary()
31
- try {
32
- let raw = readFileSync(file, 'utf8')
33
- if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1)
34
- const parsed = JSON.parse(raw) as Partial<AuthorAssetLibrary>
35
- if (!Array.isArray(parsed.items)) return defaultLibrary()
36
- return { version: 1, items: parsed.items }
37
- } catch {
38
- return defaultLibrary()
39
- }
40
- }
41
-
42
- /** 持久化作者资产库。 */
43
- export function saveAuthorAssets(library: AuthorAssetLibrary): void {
44
- const file = authorAssetsFile()
45
- mkdirSync(join(homedir(), '.dsh'), { recursive: true })
46
- writeFileSync(file, JSON.stringify(library, null, 2), 'utf8')
47
- }
48
-
49
- /** 新建一条资产(自动生成 id 与时间戳)。 */
50
- export function createAuthorAsset(input: Omit<AuthorStyleAsset, 'id' | 'createdAt' | 'updatedAt'>): AuthorStyleAsset {
51
- const now = new Date().toISOString()
52
- const asset: AuthorStyleAsset = {
53
- ...input,
54
- id: 'aa-' + Date.now().toString(36) + '-' + randomBytes(3).toString('hex'),
55
- sourceBooks: input.sourceBooks ?? [],
56
- tags: input.tags ?? [],
57
- createdAt: now,
58
- updatedAt: now,
59
- }
60
- const library = loadAuthorAssets()
61
- library.items.push(asset)
62
- saveAuthorAssets(library)
63
- return asset
64
- }
65
-
66
- /** 按 id 更新一条资产;不存在则追加。 */
67
- export function upsertAuthorAsset(input: AuthorStyleAsset): AuthorAssetLibrary {
68
- const library = loadAuthorAssets()
69
- const idx = library.items.findIndex(a => a.id === input.id)
70
- const now = new Date().toISOString()
71
- if (idx >= 0) {
72
- const prev = library.items[idx]
73
- if (prev !== undefined) {
74
- library.items[idx] = {
75
- ...prev,
76
- ...input,
77
- id: prev.id,
78
- createdAt: prev.createdAt,
79
- updatedAt: now,
80
- }
81
- }
82
- } else {
83
- library.items.push({ ...input, createdAt: input.createdAt !== '' ? input.createdAt : now, updatedAt: now })
84
- }
85
- saveAuthorAssets(library)
86
- return library
87
- }
88
-
89
- /** 删除一条资产;返回更新后的资产库。 */
90
- export function removeAuthorAsset(id: string): AuthorAssetLibrary {
91
- const library = loadAuthorAssets()
92
- library.items = library.items.filter(a => a.id !== id)
93
- saveAuthorAssets(library)
94
- return library
95
- }
96
-
97
- /**
98
- * 导入默认:把书架所有书的写作资产/角色 + 内置全局库批量沉淀到作者资产库。
99
- * 按 `kind:name` 去重(已存在则跳过),不覆盖用户已有条目。
100
- * @returns 更新后的资产库。
101
- */
102
- export function importDefaultAuthorAssets(): AuthorAssetLibrary {
103
- const library = loadAuthorAssets()
104
- const seen = new Set(library.items.map(a => a.kind + ':' + a.name))
105
- const now = new Date().toISOString()
106
- const push = (kind: AuthorStyleAsset['kind'], name: string, summary: string, content: string, tags: string[], sourceBooks: string[], structured?: Record<string, unknown>): void => {
107
- const key = kind + ':' + name.trim()
108
- if (name.trim() === '' || seen.has(key)) return
109
- seen.add(key)
110
- library.items.push({
111
- id: 'aa-' + Date.now().toString(36) + '-' + randomBytes(3).toString('hex'),
112
- kind, name: name.trim(), summary: summary.trim(), content: content.trim(),
113
- sourceBooks, tags, structured, createdAt: now, updatedAt: now,
114
- });
115
- };
116
-
117
- // 1) 清理内置公共库重复沉淀:作者库只保留个人沉淀,不再收录内置公共资产。
118
- const builtinKinds = new Set<AuthorStyleAsset['kind']>(['genre', 'antiAi', 'progression', 'style', 'plotBeat'])
119
- library.items = library.items.filter(a => !(a.tags.includes('内置') && builtinKinds.has(a.kind) && (a.sourceBooks ?? []).length === 0))
120
-
121
- // 2) 书架里的书:写作资产 + 角色模板
122
- const shelf = loadBookshelf()
123
- for (const book of shelf.books) {
124
- const project = loadProject(book.outputDir)
125
- if (project === undefined) continue
126
- const src = [project.bookName]
127
- const assets = project.assets
128
- if (assets !== undefined) {
129
- if (assets.genre !== undefined) push('genre', assets.genre.name, assets.genre.description, assets.genre.description, ['书', '题材'], src, { description: assets.genre.description });
130
- if (assets.primaryProgression !== undefined) push('progression', assets.primaryProgression.name, assets.primaryProgression.driver, '驱动:' + assets.primaryProgression.driver + '\n期待:' + assets.primaryProgression.readerExpectation, src, [], { driver: assets.primaryProgression.driver, primary: true });
131
- for (const p of assets.auxiliaryProgressions ?? []) push('progression', p.name, p.driver, '驱动:' + p.driver + '\n期待:' + p.readerExpectation, src, [], { driver: p.driver, primary: false });
132
- for (const r of assets.antiAiRules ?? []) push('antiAi', r.name, r.avoid, '避免:' + r.avoid + '\n修正:' + r.fix, src, [], { avoid: r.avoid, fix: r.fix, detectPatterns: r.detectPatterns });
133
- for (const s of assets.styleAssets ?? []) push('style', s.name, s.proseRules.join(';'),
134
- '叙述:' + s.proseRules.join(';') + '\n台词:' + s.dialogueRules.join(';') + '\n描写:' + s.descriptionRules.join(';') + '\n边界:' + s.boundaries.join(';'), src, [], { sourceText: s.sourceText });
135
- }
136
- // 作者库角色模板只收男主/女主(可复用原型),其余角色/路人不入库,避免刷屏。
137
- for (const role of project.roles ?? []) {
138
- if (role.roleLabel !== 'protagonist' && role.roleLabel !== 'female_lead') continue
139
- const persona = ('定位:' + role.roleLabel + '\n身份:' + role.identity + '\n性格:' + role.traits.join('、') + '\n目标:' + role.goals + '\n关系:' + role.relations.join('、') + '\n成长线:' + (role.arc.length > 0 ? role.arc.join(' > ') : '—') + '\n知情度:' + role.knowledge.join('、')).trim();
140
- push('roleTemplate', role.name, role.identity, persona, src, [], { roleLabel: role.roleLabel, traits: role.traits, relations: role.relations, arc: role.arc, knowledge: role.knowledge });
141
- }
142
- }
143
-
144
- saveAuthorAssets(library)
145
- return library
146
- }
147
-
package/src/bookshelf.ts DELETED
@@ -1,167 +0,0 @@
1
- /**
2
- * 书架(Bookshelf)— 多书管理:一本书记录一个独立输出目录。
3
- * 状态持久化到 ~/.dsh/dsh-novel-forge-bookshelf.json(跟随 dsh 配置惯例)。
4
- */
5
-
6
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
7
- import { homedir } from 'node:os'
8
- import { join } from 'node:path'
9
- import { randomBytes } from 'node:crypto'
10
- import type { BookEntry, BookshelfSnapshot } from './protocol.ts'
11
- import { loadProject } from './engine.ts'
12
-
13
- /** 书架配置文件路径。 */
14
- export function bookshelfFile(): string {
15
- return join(homedir(), '.dsh', 'dsh-novel-forge-bookshelf.json')
16
- }
17
-
18
- interface BookshelfStore {
19
- books: BookEntry[]
20
- activeBookId: string | null
21
- }
22
-
23
- function defaultStore(): BookshelfStore {
24
- return { books: [], activeBookId: null }
25
- }
26
-
27
- /** 读取书架(无则返回空)。 */
28
- export function loadBookshelf(): BookshelfStore {
29
- const file = bookshelfFile()
30
- if (!existsSync(file)) return defaultStore()
31
- try {
32
- let raw = readFileSync(file, 'utf8')
33
- if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1)
34
- const parsed = JSON.parse(raw) as BookshelfStore
35
- if (!Array.isArray(parsed.books)) return defaultStore()
36
- return { books: parsed.books, activeBookId: parsed.activeBookId ?? null }
37
- } catch {
38
- return defaultStore()
39
- }
40
- }
41
-
42
- /** 持久化书架。 */
43
- function saveBookshelf(store: BookshelfStore): void {
44
- const file = bookshelfFile()
45
- mkdirSync(join(homedir(), '.dsh'), { recursive: true })
46
- writeFileSync(file, JSON.stringify(store, null, 2), 'utf8')
47
- }
48
-
49
- /** 当前激活的书。 */
50
- export function activeBook(store: BookshelfStore): BookEntry | undefined {
51
- return store.books.find(b => b.id === store.activeBookId)
52
- }
53
-
54
- /** 书架快照(含每本书的进度摘要)。 */
55
- export function bookshelfSnapshot(store: BookshelfStore): BookshelfSnapshot {
56
- return {
57
- books: store.books.map(book => {
58
- const project = loadProject(book.outputDir)
59
- const done = project === undefined ? 0 : project.chapters.filter(c => c.status === 'approved' || c.status === 'written' || c.status === 'rejected').length
60
- const hasCover = project?.coverPath !== undefined && project.coverPath !== '' && existsSync(join(book.outputDir, project.coverPath))
61
- return {
62
- ...book,
63
- done,
64
- total: project?.chapters.length ?? 0,
65
- hasProject: project !== undefined,
66
- hasCover,
67
- blurb: project?.blurb,
68
- }
69
- }),
70
- activeBookId: store.activeBookId,
71
- }
72
- }
73
-
74
- /** 新建一本书(自动成为当前书)。 */
75
- export function createBook(bookName: string, outputDir: string): BookEntry {
76
- const store = loadBookshelf()
77
- const id = `book-${Date.now().toString(36)}-${randomBytes(3).toString('hex')}`
78
- const now = new Date().toISOString()
79
- const book: BookEntry = { id, bookName, outputDir, createdAt: now, updatedAt: now }
80
- store.books.push(book)
81
- store.activeBookId = id
82
- saveBookshelf(store)
83
- return book
84
- }
85
-
86
- /** 更新某本书的书名(开书向导导入大纲后书名以大纲首行为准)。 */
87
- export function renameBook(id: string, bookName: string): boolean {
88
- const store = loadBookshelf()
89
- const book = store.books.find(b => b.id === id)
90
- if (book === undefined) return false
91
- book.bookName = bookName
92
- book.updatedAt = new Date().toISOString()
93
- saveBookshelf(store)
94
- return true
95
- }
96
-
97
- /**
98
- * 播种:书架为空时,把指定输出目录下已有的项目自动登记为第一本书。
99
- * 兼容升级场景 —— 旧版插件直接在输出目录写项目,从未登记书架。
100
- * @param outputDir - 候选输出目录(通常为 settings 的默认输出目录)。
101
- * @returns 是否发生了播种。
102
- */
103
- export function seedBookshelfFromOutputDir(outputDir: string): boolean {
104
- const store = loadBookshelf()
105
- if (store.books.length > 0) return false
106
- if (!existsSync(outputDir)) return false
107
- // 有项目文件,或至少有章节文件,才视为"已有的书"。
108
- const hasProject = existsSync(join(outputDir, 'novel-project.json'))
109
- const hasChapters = existsSync(outputDir)
110
- if (!hasProject && !hasChapters) return false
111
- const project = loadProject(outputDir)
112
- const bookName = project?.bookName ?? outputDir.split(/[\\/]/).pop() ?? '未命名小说'
113
- createBook(bookName, outputDir)
114
- return true
115
- }
116
-
117
- /** 导入已有项目目录到书架:校验 novel-project.json,已存在则直接激活。 */
118
- export function importDir(outputDir: string): { book: BookEntry; existed: boolean } {
119
- const project = loadProject(outputDir)
120
- if (project === undefined) throw new Error(`目录中未找到有效的 novel-project.json:${outputDir}`)
121
- const store = loadBookshelf()
122
- const existed = store.books.find(b => b.outputDir === outputDir)
123
- if (existed !== undefined) {
124
- store.activeBookId = existed.id
125
- saveBookshelf(store)
126
- return { book: existed, existed: true }
127
- }
128
- const bookName = project.bookName !== '' ? project.bookName : (outputDir.split(/[\\/]/).pop() ?? '未命名小说')
129
- const book = createBook(bookName, outputDir)
130
- return { book, existed: false }
131
- }
132
-
133
- /** 激活一本书。 */
134
- export function activateBook(id: string): BookEntry | undefined {
135
- const store = loadBookshelf()
136
- const book = store.books.find(b => b.id === id)
137
- if (book === undefined) return undefined
138
- store.activeBookId = id
139
- book.updatedAt = new Date().toISOString()
140
- saveBookshelf(store)
141
- return book
142
- }
143
-
144
- /** 移除一本书。 */
145
- export function removeBook(id: string): boolean {
146
- const store = loadBookshelf()
147
- const idx = store.books.findIndex(b => b.id === id)
148
- if (idx === -1) return false
149
- store.books.splice(idx, 1)
150
- if (store.activeBookId === id) {
151
- store.activeBookId = store.books[0]?.id ?? null
152
- }
153
- saveBookshelf(store)
154
- return true
155
- }
156
-
157
- /** 当前书输出目录(无书架则 undefined,回退 settings)。 */
158
- export function activeBookOutputDir(): string | undefined {
159
- const book = activeBook(loadBookshelf())
160
- return book?.outputDir
161
- }
162
-
163
- /** 默认输出目录推断:~/.dsh/novels/书名。 */
164
- export function defaultOutputDirFor(bookName: string): string {
165
- const clean = bookName.replace(/[\\/:*?"<>|]/g, '').trim().slice(0, 40) || '未命名小说'
166
- return join(homedir(), '.dsh', 'novels', clean)
167
- }