@waterwx/dsh-novel-forge 1.3.1 → 1.3.2-alpha

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 (161) hide show
  1. package/README.md +288 -279
  2. package/lib/client.js +56309 -12221
  3. package/lib/index.js +14239 -5595
  4. package/lib/types/action-guard.d.ts +61 -0
  5. package/lib/types/ai-scan.d.ts +36 -0
  6. package/lib/types/assets.d.ts +24 -9
  7. package/lib/types/assistant.d.ts +29 -0
  8. package/lib/types/author-assets.d.ts +25 -0
  9. package/lib/types/bookshelf.d.ts +11 -1
  10. package/lib/types/client/api.d.ts +186 -10
  11. package/lib/types/client/chip-prefs.d.ts +36 -0
  12. package/lib/types/client/docx.d.ts +2 -0
  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 +28 -67
  16. package/lib/types/client/panel/AdaptModeView.d.ts +5 -0
  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/AuthorAssetsView.d.ts +4 -0
  20. package/lib/types/client/panel/AuthorHome.d.ts +34 -0
  21. package/lib/types/client/panel/BookAnalysisView.d.ts +4 -0
  22. package/lib/types/client/panel/CmdPalette.d.ts +12 -0
  23. package/lib/types/client/panel/CreateBookView.d.ts +5 -1
  24. package/lib/types/client/panel/DirectorView.d.ts +7 -0
  25. package/lib/types/client/panel/GlobalAssetLibraryView.d.ts +4 -0
  26. package/lib/types/client/panel/IdeaInspirationView.d.ts +6 -0
  27. package/lib/types/client/panel/ImportModal.d.ts +7 -0
  28. package/lib/types/client/panel/KnowledgeBaseView.d.ts +4 -0
  29. package/lib/types/client/panel/LiveFeedLog.d.ts +13 -0
  30. package/lib/types/client/panel/MarketRadarView.d.ts +5 -0
  31. package/lib/types/client/panel/ModelManager.d.ts +14 -0
  32. package/lib/types/client/panel/NovelPanel.d.ts +6 -1
  33. package/lib/types/client/panel/PageHeader.d.ts +18 -0
  34. package/lib/types/client/panel/ProgressConsole.d.ts +17 -0
  35. package/lib/types/client/panel/ProgressHomeView.d.ts +5 -0
  36. package/lib/types/client/panel/PromptSlotsView.d.ts +11 -0
  37. package/lib/types/client/panel/ReasoningSection.d.ts +10 -0
  38. package/lib/types/client/panel/SettingsView.d.ts +19 -0
  39. package/lib/types/client/panel/ShelfView.d.ts +12 -1
  40. package/lib/types/client/panel/SubPage.d.ts +27 -0
  41. package/lib/types/client/panel/TensionView.d.ts +18 -0
  42. package/lib/types/client/panel/TimelineView.d.ts +18 -0
  43. package/lib/types/client/panel/helpers.d.ts +5 -3
  44. package/lib/types/client/panel/toast.d.ts +2 -0
  45. package/lib/types/client/panel/views.d.ts +25 -7
  46. package/lib/types/client/run-status.d.ts +21 -0
  47. package/lib/types/client/text.d.ts +9 -0
  48. package/lib/types/docx-core.d.ts +16 -0
  49. package/lib/types/docx.d.ts +2 -3
  50. package/lib/types/engine.d.ts +186 -45
  51. package/lib/types/global-assets.d.ts +6 -0
  52. package/lib/types/index.d.ts +22 -8
  53. package/lib/types/llm-live.d.ts +75 -0
  54. package/lib/types/llm-retry.d.ts +38 -0
  55. package/lib/types/market-radar-scan.d.ts +19 -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/novel-context.d.ts +80 -0
  59. package/lib/types/prompt-slots.d.ts +57 -0
  60. package/lib/types/prompt-utils.d.ts +35 -0
  61. package/lib/types/prompting.d.ts +10 -0
  62. package/lib/types/protocol.d.ts +1362 -166
  63. package/lib/types/review-policy.d.ts +97 -0
  64. package/lib/types/revision.d.ts +76 -0
  65. package/lib/types/routes.d.ts +4 -0
  66. package/lib/types/run.d.ts +23 -1
  67. package/lib/types/snapshots.d.ts +46 -0
  68. package/lib/types/stage-contract.d.ts +60 -0
  69. package/lib/types/tension.d.ts +53 -0
  70. package/lib/types/timeline.d.ts +37 -0
  71. package/package.json +52 -28
  72. package/src/action-guard.ts +127 -0
  73. package/src/ai-scan.ts +179 -0
  74. package/src/assets.ts +1806 -520
  75. package/src/assistant.ts +1098 -770
  76. package/src/author-assets.ts +149 -0
  77. package/src/bookshelf.ts +187 -151
  78. package/src/client/api.ts +378 -21
  79. package/src/client/chip-prefs.ts +121 -0
  80. package/src/client/docx.ts +37 -69
  81. package/src/client/index.ts +3 -1
  82. package/src/client/llmLive.ts +111 -0
  83. package/src/client/locales.ts +28 -253
  84. package/src/client/mount.tsx +1 -1
  85. package/src/client/panel/AdaptModeView.tsx +535 -0
  86. package/src/client/panel/AiTag.tsx +7 -0
  87. package/src/client/panel/AssetsTab.tsx +448 -458
  88. package/src/client/panel/AssistantTab.tsx +355 -301
  89. package/src/client/panel/AuthorAssetsView.tsx +206 -0
  90. package/src/client/panel/AuthorHome.tsx +309 -0
  91. package/src/client/panel/BookAnalysisView.tsx +63 -0
  92. package/src/client/panel/CmdPalette.tsx +102 -0
  93. package/src/client/panel/CreateBookView.tsx +366 -348
  94. package/src/client/panel/DirectorView.tsx +200 -0
  95. package/src/client/panel/GlobalAssetLibraryView.tsx +168 -0
  96. package/src/client/panel/IdeaInspirationView.tsx +76 -0
  97. package/src/client/panel/ImportModal.tsx +303 -0
  98. package/src/client/panel/KnowledgeBaseView.tsx +125 -0
  99. package/src/client/panel/LiveFeedLog.tsx +204 -0
  100. package/src/client/panel/MarketRadarView.tsx +377 -0
  101. package/src/client/panel/ModelManager.tsx +205 -0
  102. package/src/client/panel/NovelPanel.tsx +3135 -2651
  103. package/src/client/panel/PageHeader.tsx +37 -0
  104. package/src/client/panel/ProgressConsole.tsx +63 -0
  105. package/src/client/panel/PromptSlotsView.tsx +97 -0
  106. package/src/client/panel/ReaderView.tsx +306 -306
  107. package/src/client/panel/ReasoningSection.tsx +31 -0
  108. package/src/client/panel/RunPanel.tsx +64 -32
  109. package/src/client/panel/SettingsView.tsx +354 -0
  110. package/src/client/panel/ShelfView.tsx +266 -236
  111. package/src/client/panel/SubPage.tsx +42 -0
  112. package/src/client/panel/TensionView.tsx +212 -0
  113. package/src/client/panel/TimelineView.tsx +208 -0
  114. package/src/client/panel/WorldTab.tsx +202 -202
  115. package/src/client/panel/helpers.ts +7 -5
  116. package/src/client/panel/panel.module.css +4481 -1655
  117. package/src/client/panel/toast.ts +51 -0
  118. package/src/client/panel/views.tsx +401 -314
  119. package/src/client/run-status.ts +171 -0
  120. package/src/client/sidebar-entry.ts +1 -1
  121. package/src/client/text.ts +28 -0
  122. package/src/docx-core.ts +53 -0
  123. package/src/docx.ts +44 -83
  124. package/src/engine.ts +4672 -2943
  125. package/src/global-assets.ts +59 -0
  126. package/src/index.ts +89 -33
  127. package/src/llm-live.ts +260 -0
  128. package/src/llm-retry.ts +77 -0
  129. package/src/market-radar-scan.ts +41 -0
  130. package/src/market-radar-sources.ts +173 -0
  131. package/src/migrate-output.ts +76 -0
  132. package/src/novel-context.ts +286 -0
  133. package/src/prompt-slots.ts +125 -0
  134. package/src/prompting.ts +26 -0
  135. package/src/protocol.ts +1388 -158
  136. package/src/review-policy.ts +161 -0
  137. package/src/revision.ts +283 -0
  138. package/src/routes.ts +1934 -434
  139. package/src/run.ts +118 -21
  140. package/src/snapshots.ts +174 -0
  141. package/src/stage-contract.ts +189 -0
  142. package/src/tension.ts +251 -0
  143. package/src/timeline.ts +159 -0
  144. package/lib/client.js.map +0 -1
  145. package/lib/index.js.map +0 -1
  146. package/lib/types/comic-presets.d.ts +0 -12
  147. package/scripts/assistant-frames.txt +0 -8
  148. package/scripts/diagnose-adapter.mts +0 -81
  149. package/scripts/diagnose-assistant.mjs +0 -58
  150. package/scripts/diagnose-bible.mjs +0 -72
  151. package/scripts/diagnose-harness.mts +0 -75
  152. package/scripts/novel-forge-restart.log +0 -10
  153. package/scripts/novel-forge-web.stderr.log +0 -2
  154. package/scripts/novel-forge-web.stdout.log +0 -1
  155. package/scripts/outline-sample.txt +0 -449
  156. package/scripts/probe.mjs +0 -6
  157. package/scripts/restart-web.ps1 +0 -88
  158. package/scripts/smoke.mts +0 -72
  159. package/scripts/upload-github.ps1 +0 -51
  160. package/src/client/panel/BookshelfBar.tsx +0 -170
  161. package/src/comic-presets.ts +0 -67
@@ -0,0 +1,37 @@
1
+ /** 墨案统一页头:eyebrow(11 大写窄) + 衬线大标题 + 一句说明 + 主/次动作。
2
+ * 每个视图只用一个 PageHeader,消灭"各自为政"的页面标题。
3
+ * 图标用 lucide 16 (单色),标题旁禁止 emoji;标题用衬线 Display(书卷感)。 */
4
+ import type { ReactNode } from 'react'
5
+ import css from './panel.module.css'
6
+
7
+ export function PageHeader({ eyebrow, title, icon, sub, actions, right }: {
8
+ /** 页眉小标(大写窄,可选,如 "BOOKSHELF")。 */
9
+ eyebrow?: string
10
+ /** 页面大标题(衬线 Display)。 */
11
+ title: string
12
+ /** lucide 图标(单色,16px),可选。 */
13
+ icon?: ReactNode
14
+ /** 一句话辅助说明(meta)。 */
15
+ sub?: string
16
+ /** 右侧主/次按钮组。 */
17
+ actions?: ReactNode
18
+ /** 标题右上(如 AI 微签)。 */
19
+ right?: ReactNode
20
+ }): JSX.Element {
21
+ return (
22
+ <div className={css.pageHeader}>
23
+ <div className={css.pageHeaderMain}>
24
+ {eyebrow !== undefined && eyebrow !== '' && (
25
+ <div className={css.pageHeaderEyebrow}>{eyebrow}</div>
26
+ )}
27
+ <div className={css.pageHeaderTitle}>
28
+ {icon}
29
+ {title}
30
+ {right}
31
+ </div>
32
+ {sub !== undefined && sub !== '' && <div className={css.pageHeaderSub}>{sub}</div>}
33
+ </div>
34
+ {actions !== undefined && actions !== null && <div className={css.pageHeaderActions}>{actions}</div>}
35
+ </div>
36
+ )
37
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * 共享「AI 进度」实时控制台:当前任务大进度条 + 全量活动日志。
3
+ * 书内与首页共用一个表现,内容来自同一份进度状态。
4
+ */
5
+ import { useEffect, useRef } from 'react'
6
+ import css from './panel.module.css'
7
+
8
+ export interface ProgressLine {
9
+ id: number;
10
+ text: string;
11
+ kind: 'info' | 'done' | 'error';
12
+ live?: boolean;
13
+ ratio?: number;
14
+ }
15
+
16
+ export function ProgressConsole({ progress, busy, busyLabel, liveBar, onClear }: {
17
+ progress: ProgressLine[];
18
+ busy: boolean;
19
+ busyLabel: string;
20
+ liveBar: { text: string; ratio?: number } | null;
21
+ onClear: () => void;
22
+ }) {
23
+ const endRef = useRef<HTMLDivElement | null>(null);
24
+ useEffect(() => {
25
+ endRef.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
26
+ }, [progress]);
27
+
28
+ return (
29
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--nf-space-10)', minHeight: 0 }}>
30
+ <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
31
+ <span style={{ fontWeight: 600 }}> AI 进度</span>
32
+ <button type="button" className={css.button + ' ' + css.buttonSmall} onClick={onClear} title="清空活动记录">清空</button>
33
+ </div>
34
+ {(busy && (busyLabel !== '' || liveBar !== null)) && (
35
+ <div style={{ border: '1px solid var(--nf-accent)', borderRadius: 'var(--nf-radius-10)', padding: 'var(--nf-space-8) var(--nf-space-12)', display: 'flex', flexDirection: 'column', gap: 'var(--nf-space-6)', background: 'color-mix(in srgb, var(--nf-accent) 6%, transparent)' }}>
36
+ <span style={{ fontSize: 'var(--nf-fs-12)', fontWeight: 600, color: 'var(--nf-accent)' }}> {busyLabel !== '' ? busyLabel : (liveBar?.text ?? '任务进行中')}…</span>
37
+ {liveBar?.ratio !== undefined && (
38
+ <div className={css.bigProgressBar}><div className={css.bigProgressBarFill} style={{ width: Math.round(liveBar.ratio * 100) + '%' }} /></div>
39
+ )}
40
+ {liveBar?.text !== undefined && <span className={css.liveText}>{liveBar.text}</span>}
41
+ </div>
42
+ )}
43
+ <div className={css.progress} style={{ flex: '0 1 auto', maxHeight: '42%', minHeight: 0, overflowY: 'auto', border: '1px solid var(--nf-border)', borderRadius: 'var(--nf-radius-10)', background: 'var(--nf-bg-inset)', padding: 'var(--nf-space-8)', display: 'flex', flexDirection: 'column' }}>
44
+ {progress.length === 0 ? (
45
+ <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--nf-space-6)', color: 'var(--nf-text-3)', fontSize: 'var(--nf-fs-12)', padding: 'var(--nf-space-4) 2px' }}>
46
+ <span></span>
47
+ <span>暂无活动记录,生成、审稿等操作会显示在这里</span>
48
+ </div>
49
+ ) : (
50
+ progress.map(line => (
51
+ <div key={line.id} className={line.kind === 'done' ? css.progressLineDone : line.kind === 'error' ? css.progressLineError : line.live === true ? css.progressLineLive : css.progressLine}>
52
+ {line.live === true && (
53
+ <span className={css.progressBar}><span className={css.progressBarFill} style={{ width: Math.round((line.ratio ?? 0) * 100) + '%' }} /></span>
54
+ )}
55
+ {line.text}
56
+ </div>
57
+ ))
58
+ )}
59
+ <div ref={endRef} />
60
+ </div>
61
+ </div>
62
+ );
63
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * 提示词槽位:给作者留几个**安全可改**的位置来微调本书表达偏好。
3
+ *
4
+ * 边界写在界面上:槽位只**追加偏好**,不能覆盖道藏、写作红线、九条内容合规红线、
5
+ * 反 AI 规则与阶段契约 —— 这些由宿主锁定。清空即恢复默认。
6
+ */
7
+
8
+ import { useCallback, useEffect, useState } from 'react'
9
+ import type { NovelApi } from '../api.ts'
10
+ import type { PromptSlotId, PromptSlotState } from '../../protocol.ts'
11
+ import css from './panel.module.css'
12
+
13
+ export interface PromptSlotsViewProps {
14
+ api: NovelApi
15
+ }
16
+
17
+ export default function PromptSlotsView({ api }: PromptSlotsViewProps): JSX.Element {
18
+ const [slots, setSlots] = useState<PromptSlotState[]>([])
19
+ const [drafts, setDrafts] = useState<Record<string, string>>({})
20
+ const [busy, setBusy] = useState(false)
21
+ const [error, setError] = useState('')
22
+ const [notice, setNotice] = useState('')
23
+
24
+ const refresh = useCallback(async (showError = true): Promise<void> => {
25
+ try {
26
+ const r = await api.promptSlots()
27
+ setSlots(r.slots)
28
+ setDrafts(Object.fromEntries(r.slots.map(s => [s.id, s.value])))
29
+ } catch (err) {
30
+ if (showError) setError((err as Error).message)
31
+ }
32
+ }, [api])
33
+
34
+ useEffect(() => { void refresh(false) }, [refresh])
35
+
36
+ const save = useCallback(async (id: PromptSlotId): Promise<void> => {
37
+ setBusy(true); setError(''); setNotice('')
38
+ try {
39
+ await api.promptSlotSet(id, drafts[id] ?? '')
40
+ await refresh()
41
+ setNotice((drafts[id] ?? '').trim() === '' ? '已清空该槽位(恢复默认)' : '已保存,下一次生成/审稿生效')
42
+ } catch (err) {
43
+ setError((err as Error).message)
44
+ } finally {
45
+ setBusy(false)
46
+ }
47
+ }, [api, drafts, refresh])
48
+
49
+ const dirty = (slot: PromptSlotState): boolean => (drafts[slot.id] ?? '') !== slot.value
50
+
51
+ return (
52
+ <div className={css.card} style={{ gap: 'var(--nf-space-12)' }}>
53
+ <div className={css.row} style={{ justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 'var(--nf-space-8)' }}>
54
+ <span className={css.cardTitle}>提示词槽位(本书)</span>
55
+ <span className={css.meta}>只追加偏好,不覆盖道藏 / 红线 / 合规</span>
56
+ </div>
57
+ <span className={css.meta}>
58
+ 这里的文字会追加到写作提示词末尾,用来微调表达方式。**规则类内容不可改**:
59
+ 道藏、写作红线、内容合规红线、反 AI 规则、阶段契约由宿主锁定,槽位碰不到。
60
+ </span>
61
+
62
+ {notice !== '' && <span style={{ color: 'var(--nf-success)', fontSize: 'var(--nf-text-12)' }}>{notice}</span>}
63
+ {error !== '' && <span style={{ color: 'var(--nf-error)', fontSize: 'var(--nf-text-12)' }}>{error}</span>}
64
+
65
+ {slots.map(slot => {
66
+ const value = drafts[slot.id] ?? ''
67
+ const over = value.length > slot.maxChars
68
+ return (
69
+ <div key={slot.id} style={{ border: '1px solid var(--nf-border)', borderRadius: 8, padding: 8, display: 'flex', flexDirection: 'column', gap: 6 }}>
70
+ <div className={css.row} style={{ justifyContent: 'space-between', alignItems: 'baseline', gap: 'var(--nf-space-8)' }}>
71
+ <b style={{ fontSize: 'var(--nf-fs-12)' }}>{slot.label}</b>
72
+ <span className={css.meta} style={{ color: over ? 'var(--nf-error)' : undefined }}>
73
+ {value.length} / {slot.maxChars}
74
+ </span>
75
+ </div>
76
+ <span className={css.meta}>{slot.hint}</span>
77
+ <textarea
78
+ className={css.textarea}
79
+ rows={3}
80
+ value={value}
81
+ placeholder={slot.placeholder}
82
+ onChange={e => setDrafts(prev => ({ ...prev, [slot.id]: e.target.value }))}
83
+ />
84
+ <div className={css.row} style={{ justifyContent: 'flex-end', gap: 6 }}>
85
+ <button type="button" className={css.button} disabled={busy || value === ''} onClick={() => { void save(slot.id) }}>
86
+ 清空
87
+ </button>
88
+ <button type="button" className={css.button + ' ' + css.buttonPrimary} disabled={busy || !dirty(slot)} onClick={() => { void save(slot.id) }}>
89
+ 保存
90
+ </button>
91
+ </div>
92
+ </div>
93
+ )
94
+ })}
95
+ </div>
96
+ )
97
+ }