@waterwx/dsh-novel-forge 2.4.0 → 2.5.1

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.
@@ -2,13 +2,13 @@
2
2
  * Writing assets — 题材基底库 / 推进模式库 / 反 AI 规则 / 写法引擎.
3
3
  *
4
4
  * 内置种子数据(本项目自研表述;结构参考了同类工具的功能划分):
5
- * - 8 套预置叙事风格模板
6
- * - 12 条带命中模式的反 AI 规则
5
+ * - 预置叙事风格模板(数量以 {@link BUILTIN_STYLE_TEMPLATES} 数组为准)
6
+ * - 带命中模式的反 AI 规则(数量以 ANTI_AI_RULES 数组为准)
7
7
  * - 题材树 + 推进模式种子
8
8
  * Assets persist with the project (novel-project.json) and are injected into
9
9
  * generation / planning / review prompts, and available to the AI assistant.
10
10
  */
11
- import type { AntiAiRule, GenreNode, PlotBeatTemplate, ProgressionMode, ProjectAssets, StarterStyleProfile, StyleAsset, StyleTemplate } from './protocol.ts';
11
+ import type { AntiAiRule, GenreNode, PlotBeatTemplate, ProgressionMode, ProjectAssets, StarterStyleProfile, StyleAsset, StyleProfile, StyleTemplate } from './protocol.ts';
12
12
  /** 预置叙事风格模板(8 套,一键绑定无需样本文本)。 */
13
13
  export declare const BUILTIN_STYLE_TEMPLATES: StyleTemplate[];
14
14
  /** 内置全局反 AI 规则(12 条,随插件发布;项目可叠加自定义规则)。 */
@@ -31,9 +31,9 @@ export declare function renderAntiAiRules(assets: ProjectAssets | undefined): st
31
31
  /** 渲染题材与推进模式提示词块。 */
32
32
  export declare function renderGenreAndProgression(assets: ProjectAssets | undefined): string;
33
33
  /** 渲染写法资产提示词块(规则去重,省 token)。 */
34
- export declare function renderStyleAssets(assets: ProjectAssets | undefined): string;
34
+ export declare function renderStyleAssets(assets: ProjectAssets | undefined, profile?: StyleProfile): string;
35
35
  /** 渲染全部写作资产提示词(供生成/规划/审稿注入)。 */
36
- export declare function renderAllAssets(assets: ProjectAssets | undefined): string;
36
+ export declare function renderAllAssets(assets: ProjectAssets | undefined, profile?: StyleProfile): string;
37
37
  /** 预置写法模板 → 可直接绑定的 StyleAsset。 */
38
38
  export declare function styleTemplateToAsset(template: StyleTemplate): StyleAsset;
39
39
  /** 起始风格画像库:无样本文本也能快速绑定一套写法(4 档起步写法)。 */
@@ -292,8 +292,26 @@ export declare class NovelApi {
292
292
  promptSlots(): Promise<import('../protocol.ts').PromptSlotsResponse>;
293
293
  /** 写入一个提示词槽位(空串 = 清空)。 */
294
294
  promptSlotSet(id: import('../protocol.ts').PromptSlotId, value: string): Promise<void>;
295
+ /** 取名器:本书名字库。 */
296
+ nameForgeBank(): Promise<import('../protocol.ts').NameForgeBankResponse>;
297
+ /** 取名器:生成一批候选(不落盘)。 */
298
+ nameForgeGenerate(category: import('../protocol.ts').NameCategory, count: number, hint: string): Promise<import('../protocol.ts').NameForgeGenerateResponse>;
299
+ /** 取名器:采纳候选入名字库。 */
300
+ nameForgeAdopt(category: import('../protocol.ts').NameCategory, candidates: import('../protocol.ts').NameForgeCandidate[]): Promise<import('../protocol.ts').NameForgeMutateResponse>;
301
+ /** 取名器:从名字库移除一条。 */
302
+ nameForgeDiscard(id: string): Promise<import('../protocol.ts').NameForgeMutateResponse>;
295
303
  /** 故事时间线:列表(含规则初筛问题)。 */
296
304
  timeline(): Promise<import('../protocol.ts').TimelineResponse>;
305
+ /** 风格目标卡:当前卡 + 生效说明 + 可蒸馏章数。 */
306
+ styleProfile(): Promise<import('../protocol.ts').StyleProfileResponse>;
307
+ /** 蒸馏风格目标卡(archived = 本书已过审章节中位数;sample = 参考样文本)。 */
308
+ styleProfileDistill(action: 'distill-archived' | 'distill-sample', text?: string): Promise<{
309
+ profile: import('../protocol.ts').StyleProfile | null;
310
+ }>;
311
+ /** 清除风格目标卡(回落绑定资产的样本文本)。 */
312
+ styleProfileClear(): Promise<{
313
+ profile: null;
314
+ }>;
297
315
  /** 抽取某一章的时间线事件。 */
298
316
  timelineExtract(chapterNo: number): Promise<{
299
317
  events: import('../protocol.ts').TimelineEvent[];
@@ -34,7 +34,6 @@ export declare const zh: {
34
34
  readonly 'plan.pending': "待生成";
35
35
  readonly 'plan.generating': "生成中";
36
36
  readonly 'plan.written': "待审稿";
37
- readonly 'plan.reviewing': "审稿中";
38
37
  readonly 'plan.approved': "已通过";
39
38
  readonly 'plan.rejected': "待修订";
40
39
  readonly 'plan.error': "失败";
@@ -0,0 +1,69 @@
1
+ import type { ReactElement } from 'react';
2
+ import type { NovelApi } from '../api.ts';
3
+ import type { ChapterPlan, ChapterSnapshot, Plotline, ReviewReport } from '../../protocol.ts';
4
+ /** 审稿维度中文名(工作台与主面板共用)。 */
5
+ export declare const REVIEW_DIM_ZH: Record<string, string>;
6
+ export declare function statusBadge(chapter: ChapterPlan): {
7
+ cls: string;
8
+ label: string;
9
+ };
10
+ /** One review issue line (severity-colored, theme-aware). */
11
+ export declare function severityColor(severity: string): string;
12
+ /** 把章节 beats 按结构标签渲染的实现见 ChapterPlanPanel.renderBeats(左栏与计划抽屉共用)。 */
13
+ /** The diff list of a draft-vs-original comparison (scrollable). */
14
+ export declare function DiffList({ original, draft, fontSize }: {
15
+ original: string;
16
+ draft: string;
17
+ fontSize?: number;
18
+ }): ReactElement;
19
+ /** 章节工作台右侧页签:对比(草稿 diff)/ 审稿(AI 审稿报告)/ 复盘(作者复盘)。 */
20
+ export type ChapterSideTab = 'diff' | 'review' | 'author' | 'versions';
21
+ /** 章节工作台(独立全页)需要的全部输入;所有数据来自真实 project.chapters。 */
22
+ interface ChapterWorkbenchProps {
23
+ chapter: ChapterPlan;
24
+ bookKey: string;
25
+ /** 已加载的正文 markdown;'' 表示未加载 / 尚未生成。 */
26
+ text: string;
27
+ /** 润色 / 修订草稿;存在时「对比」页可做逐段 diff。 */
28
+ draft?: string;
29
+ fontSize: number;
30
+ busy: boolean;
31
+ busyAny: boolean;
32
+ onBack: () => void;
33
+ onWrite: () => void;
34
+ onReview: () => void;
35
+ onApprove: () => void;
36
+ onEdit: () => void;
37
+ /** 按作者勾选的审稿意见修订(不传则内部自动挑 high)。 */
38
+ onRevisePicked: (issues: ReviewReport['issues']) => void;
39
+ onReset: () => void;
40
+ onRegenerate: () => void;
41
+ onBackfillAuthor: () => void;
42
+ /** 右栏当前页签(受控:修订完成后由外层自动切到「对比」)。 */
43
+ tab: ChapterSideTab;
44
+ onTabChange: (tab: ChapterSideTab) => void;
45
+ /** 草稿审查报告(验证模式产物,针对草稿本身);null = 还没审查过。 */
46
+ draftReport: ReviewReport | null;
47
+ onApplyDraft: () => void;
48
+ onDiscardDraft: () => void;
49
+ onCheckDraft: () => void;
50
+ /** 本章历史版本(快照)与回滚/存档动作。 */
51
+ snapshots: ChapterSnapshot[];
52
+ onRestoreSnapshot: (id: string) => void;
53
+ onCreateSnapshot: () => void;
54
+ /** 左栏「本章计划」:剧情线用于关联项,api + onPlanSaved 提供就地补写通道。 */
55
+ plotlines: Plotline[];
56
+ api: NovelApi;
57
+ onPlanSaved: (chapter: ChapterPlan) => void;
58
+ /** 截断声明汇入外层进度台。 */
59
+ onNotice: (message: string) => void;
60
+ onLinkLines: () => void;
61
+ /** 失败态的出路之一:打开「AI 进度」浮窗看这一章的运行详情(Prompt / 耗时 / 原始错误)。 */
62
+ onOpenRunLog: () => void;
63
+ }
64
+ /**
65
+ * 章节工作台:**独立全页**(不塞进抽屉或主从布局,内容太重)。
66
+ * 三栏并发 —— 左:本章计划(六项固定分组,见 ChapterPlanPanel);中:正文;右:对比 / 审稿 / 复盘 / 历史。
67
+ */
68
+ export declare function ChapterWorkbench({ chapter, bookKey, text, draft, fontSize, busy, busyAny, onBack, onWrite, onReview, onApprove, onEdit, onRevisePicked, onReset, onRegenerate, onBackfillAuthor, tab, onTabChange, draftReport, onApplyDraft, onDiscardDraft, onCheckDraft, snapshots, onRestoreSnapshot, onCreateSnapshot, plotlines, api, onPlanSaved, onNotice, onLinkLines, onOpenRunLog, }: ChapterWorkbenchProps): ReactElement;
69
+ export {};
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 取名器:按类别批量生成专有名字,逐条采纳入本书名字库。
3
+ *
4
+ * 边界写在界面上:候选不落盘,采纳后才注入写作提示词(本书层「已定名资产」块);
5
+ * 库有容量上限(每类 60 / 全书 200),满了会明确报错而不是静默丢弃。
6
+ */
7
+ import type { NovelApi } from '../api.ts';
8
+ export interface NameForgeViewProps {
9
+ api: NovelApi;
10
+ }
11
+ export default function NameForgeView({ api }: NameForgeViewProps): JSX.Element;
@@ -14,5 +14,4 @@ export interface NovelPanelProps {
14
14
  /** The API client every tab operates through. */
15
15
  api: NovelApi;
16
16
  }
17
- /** The novel-forge panel. */
18
17
  export declare function NovelPanel({ controller, api }: NovelPanelProps): import("react").JSX.Element;
@@ -9,6 +9,10 @@
9
9
  * 若各画各的,作者会看到两个不一致的结论。
10
10
  * 2. **数值即时算、不落盘** —— 数据源就是章节文件本身,存一份快照只会带来陈旧问题。
11
11
  *
12
+ * 页面分两截,各管一把尺子:
13
+ * - **风格目标卡**(上):生成端的锚点,作者显式蒸馏后落盘;审稿不读它;
14
+ * - **漂移曲线**(下):审稿端的自适应尺子,实时算。两者刻意分开,见 style-profile.ts 文件头。
15
+ *
12
16
  * 只画四项长度/比率指标:句长起伏与意象密度是诊断用的,画成曲线反而难读。
13
17
  */
14
18
  import type { NovelApi } from '../api.ts';
@@ -0,0 +1,51 @@
1
+ /**
2
+ * 润色 / 修订工作区(全页受控组件)。
3
+ *
4
+ * 从 NovelPanel.tsx 抽出(2026-10 重构第二步):它是一整页编辑器,原先直接嵌在
5
+ * 5600 行主组件的 return 里,任何一处改动都要翻过上百行 JSX。这里只做**受控渲染**:
6
+ * 状态与请求逻辑仍留在面板(它要驱动全局 busy / 进度台 / 刷新),视图只负责把
7
+ * props 接上——纯搬家,不搬行为。
8
+ */
9
+ import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
10
+ import type { ReactElement } from 'react';
11
+ import type { ReviewReport } from '../../protocol.ts';
12
+ /** 工作区状态(面板持有)。 */
13
+ export interface WorkspaceState {
14
+ no: number;
15
+ title: string;
16
+ original: string;
17
+ instruction: string;
18
+ draft: string | null;
19
+ /** 打开工作区时的正文基线(用于判断"有未保存修改")。 */
20
+ baseline: string;
21
+ /** 已采纳草稿(原地结论态):显示已采纳横幅 + 自动审稿结果,返回时才关闭工作区。 */
22
+ applied?: boolean;
23
+ }
24
+ /** 工作区视图的全部输入;状态与副作用都由面板提供。 */
25
+ export interface WorkspaceViewProps {
26
+ workspace: WorkspaceState;
27
+ onWorkspaceChange: (next: WorkspaceState) => void;
28
+ onClose: () => void;
29
+ onGotoChapter: (no: number) => void;
30
+ backTo: string;
31
+ editorFontSize: number;
32
+ onEditorFontSizeChange: (n: number) => void;
33
+ editorRef: MutableRefObject<HTMLTextAreaElement | null>;
34
+ selected: string;
35
+ onCaptureSelection: () => void;
36
+ checkReport: ReviewReport | null;
37
+ checked: number[];
38
+ onCheckedChange: Dispatch<SetStateAction<number[]>>;
39
+ showDiff: boolean;
40
+ onShowDiffChange: (next: boolean) => void;
41
+ resultMode: boolean;
42
+ busy: boolean;
43
+ onReviseByReport: () => void;
44
+ onRewrite: (whole: boolean) => void;
45
+ onPolish: () => void;
46
+ onSave: () => void;
47
+ onCheck: () => void;
48
+ onDiscardDraft: (no: number) => void;
49
+ }
50
+ /** 工作区全页:左栏原文(可选中局部目标)+ 右栏指令 / 预览 / 应用。 */
51
+ export declare function WorkspaceView({ workspace, onWorkspaceChange, onClose, onGotoChapter, backTo, editorFontSize, onEditorFontSizeChange, editorRef, selected, onCaptureSelection, checkReport, checked, onCheckedChange, showDiff, onShowDiffChange, resultMode, busy, onReviseByReport, onRewrite, onPolish, onSave, onCheck, onDiscardDraft, }: WorkspaceViewProps): ReactElement;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * 总编台(首页)的纯计算层。
3
+ *
4
+ * 从 NovelPanel.tsx 抽出(2026-10 重构):这些数字原先散在 6000+ 行组件的
5
+ * useMemo 里,既没法单测,也让「同一件事在面板里说两遍」难以发现。抽成纯函数后:
6
+ * - 输入只有 project / chapters,输出是确定的结构;
7
+ * - 面板只负责渲染,数字口径集中在这里改;
8
+ * - `tests/home-model.test.ts` 直接覆盖边界(空书、全过审、生成中)。
9
+ */
10
+ import type { ChapterPlan, ProjectState } from '../../protocol.ts';
11
+ /** 总编台用的章节统计(一次遍历算完,避免面板里重复过滤)。 */
12
+ export interface ChapterStats {
13
+ /** 有正文的章数(approved / written / rejected)。 */
14
+ done: number;
15
+ /** 待处理章数(pending / error)。 */
16
+ pending: number;
17
+ /** 已过审章数。 */
18
+ approved: number;
19
+ /** 待审章数(written / rejected)。 */
20
+ reviewPending: number;
21
+ /** 全书已写字数(汉字口径,来自 chapter.chars)。 */
22
+ totalChars: number;
23
+ /** 正在生成的章(同刻至多一章;undefined = 没有)。 */
24
+ writingNow: ChapterPlan | undefined;
25
+ /** 逐章字数序列(Sparkline 用;顺序 = 章节数组顺序)。 */
26
+ charSeries: Array<{
27
+ no: number;
28
+ chars: number;
29
+ approved: boolean;
30
+ }>;
31
+ }
32
+ /**
33
+ * 单次遍历统计全书章节。
34
+ * @param chapters 全书章节计划(顺序无关,按数组顺序输出 charSeries)。
35
+ */
36
+ export declare function computeChapterStats(chapters: ChapterPlan[]): ChapterStats;
37
+ /** 创作旅程的一个阶段。 */
38
+ export interface JourneyStage {
39
+ id: string;
40
+ label: string;
41
+ done: boolean;
42
+ }
43
+ /**
44
+ * 创作旅程 6 阶段(大纲 → 设定 → 卷计划 → 章节计划 → 正文 → 审稿)。
45
+ *
46
+ * 「完成」的判定只看项目真实数据,不参考 UI 当前所在页;否则作者在
47
+ * 「总纲」页多停留一会儿,旅程条就会自己变。
48
+ *
49
+ * @param project 当前书(undefined = 没有书)。
50
+ * @param chapters 章节计划。
51
+ * @param approvedCount 已过审章数(来自 {@link computeChapterStats})。
52
+ */
53
+ export declare function computeJourneyStages(project: ProjectState | undefined, chapters: ChapterPlan[], approvedCount: number): JourneyStage[];
@@ -12,7 +12,7 @@ import type { Context } from '@deepseek-ai/cordis';
12
12
  import { type StyleFingerprint } from './style-fingerprint.ts';
13
13
  import { fullTextBudget } from './model-capability.ts';
14
14
  import { applyModelCapability } from './model-request.ts';
15
- import type { AdaptationDimension, AdaptAnalyzeResponse, AdaptationMapping, AdaptationRules, AdaptProposeResponse, AuditIssue, AuthorReview, ExportScope, TimelineEvent, TimelineIssue, BreakdownResponse, ChapterPlan, Foreshadow, NovelConfig, OutlineCandidate, Plotline, PlotlineHealthReport, PlotlinePlan, ProjectState, ReviewReport, RoleRecord, RoleStatusCard, StoryBible, AddModelRequest, AddModelResponse, LlmModelsResponse, LlmVendorsResponse, LlmProvidersResponse, RemoveProviderRequest, RemoveProviderResponse, LlmTestResponse, Volume, WorldState, AdaptMaterializeRequest, AdaptMaterializeResponse, AdaptMaterializeSaveRequest, AdaptMaterializeSaveResponse, MarketRadarRequest, MarketRadarResult, MarketRadarSignal, MarketRadarBriefRequest, ProductionFoundation, MarketCreativeBrief, BookAnalysisRequest, BookAnalysisResult, IdeaInspirationRequest, IdeaInspirationResult, DirectorRequest, DirectorAdvice } from './protocol.ts';
15
+ import type { AdaptationDimension, AdaptAnalyzeResponse, AdaptationMapping, AdaptationRules, AdaptProposeResponse, AuditIssue, AuthorReview, ExportScope, TimelineEvent, TimelineIssue, BreakdownResponse, ChapterPlan, Foreshadow, NovelConfig, OutlineCandidate, Plotline, PlotlineHealthReport, PlotlinePlan, ProjectState, ReviewReport, RoleRecord, RoleStatusCard, StoryBible, AddModelRequest, AddModelResponse, LlmModelsResponse, LlmVendorsResponse, LlmProvidersResponse, RemoveProviderRequest, RemoveProviderResponse, LlmTestResponse, Volume, WorldState, AdaptMaterializeRequest, AdaptMaterializeResponse, AdaptMaterializeSaveRequest, AdaptMaterializeSaveResponse, MarketRadarRequest, MarketRadarResult, MarketRadarSignal, MarketRadarBriefRequest, ProductionFoundation, MarketCreativeBrief, BookAnalysisRequest, BookAnalysisResult, IdeaInspirationRequest, IdeaInspirationResult, NameCategory, NameForgeCandidate, StyleProfile, DirectorRequest, DirectorAdvice } from './protocol.ts';
16
16
  /** Project state file name inside the output dir. */
17
17
  export declare const PROJECT_FILE = "novel-project.json";
18
18
  /** Chapter output file name, e.g. 第001章_开篇.md */
@@ -112,6 +112,27 @@ export interface StyleBaseline {
112
112
  * @returns 基线;既无已过审章节也无带样本文本的写法资产时返回 undefined。
113
113
  */
114
114
  export declare function styleBaseline(outputDir: string | undefined, project: ProjectState): StyleBaseline | undefined;
115
+ /**
116
+ * 从本书**已过审章节**等距抽样算风格指纹(中位数)。
117
+ *
118
+ * 审稿尺子(styleBaseline)与蒸馏卡(distillStyleProfile)共用这一份采样——
119
+ * 两条路必须同源,否则「审稿说没偏离、生成目标却是另一个方向」。
120
+ * @returns 抽样指纹与参与章数;不足 {@link STYLE_BASELINE_MIN_CHAPTERS} 章时返回 undefined。
121
+ */
122
+ export declare function sampleArchivedFingerprint(outputDir: string | undefined, project: ProjectState): {
123
+ fingerprint: StyleFingerprint;
124
+ count: number;
125
+ } | undefined;
126
+ /**
127
+ * 蒸馏一张风格目标卡(作者显式动作,落 project.styleProfile)。
128
+ *
129
+ * archived:本书已过审章节的中位数(把「我现在实际写出来的样子」固化成目标);
130
+ * sample:作者粘贴的参考样文本(开书定调)。
131
+ *
132
+ * 与审稿尺子刻意分工:见 style-profile.ts 文件头「棘轮效应」说明。
133
+ * @throws 数据不足时抛错(路由转 400)。
134
+ */
135
+ export declare function distillStyleProfile(outputDir: string | undefined, project: ProjectState, source: 'archived' | 'sample', sampleText?: string): StyleProfile;
115
136
  /** Run the AI review on one chapter. */
116
137
  export declare function reviewChapter(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, chapterNo: number): Promise<ReviewReport>;
117
138
  /**
@@ -437,6 +458,17 @@ export declare function runMarketCreativeBrief(ctx: Context, config: NovelConfig
437
458
  export declare function runBookAnalysis(ctx: Context, config: NovelConfig, req: BookAnalysisRequest): Promise<BookAnalysisResult>;
438
459
  /** 创意灵感:一句话/题材 → 多方向开书灵感。 */
439
460
  export declare function runIdeaInspiration(ctx: Context, config: NovelConfig, req: IdeaInspirationRequest): Promise<IdeaInspirationResult>;
461
+ /**
462
+ * 取名器:按类别批量生成专有名字(题材感知 + 世界观避重 + 库内避重)。
463
+ *
464
+ * 候选**不落盘**——作者在面板逐条采纳后才进名字库(走 nameForgeRoute 的
465
+ * adopt 动作)。生成失败(含模型输出无法解析)抛错,由路由转 500。
466
+ */
467
+ export declare function runNameForge(ctx: Context, config: NovelConfig, project: ProjectState, req: {
468
+ category: NameCategory;
469
+ count?: number;
470
+ hint?: string;
471
+ }): Promise<NameForgeCandidate[]>;
440
472
  /** 雷达→灵感:基于市场信号/生产底座/创意简报,生成贴合市场的开书灵感。 */
441
473
  export declare function runMarketIdeaInspiration(ctx: Context, config: NovelConfig, req: {
442
474
  signals?: MarketRadarSignal[];
@@ -470,11 +502,18 @@ export declare function extractTimelineForChapter(ctx: Context, config: NovelCon
470
502
  * @returns 模型给出的问题清单(与规则初筛结果合并由调用方决定)。
471
503
  */
472
504
  export declare function reviewTimeline(ctx: Context, config: NovelConfig, project: ProjectState): Promise<TimelineIssue[]>;
473
- /** Export the whole book as one txt/md file. */
505
+ /**
506
+ * Export the whole book as one txt/md file.
507
+ *
508
+ * 只收真实存在且非空的章节文件:`chapter.file` 有值不等于文件没被手删/清空,
509
+ * 旧实现会把它们当空串拼进去,导出件看起来完整、实际缺章。跳过的章号随
510
+ * `skipped` 一起返回,由面板如实提示。
511
+ */
474
512
  export declare function exportBook(outputDir: string, project: ProjectState, format: 'txt' | 'md'): {
475
513
  file: string;
476
514
  chars: number;
477
515
  chapters: number;
516
+ skipped?: number[];
478
517
  };
479
518
  /**
480
519
  * 按范围导出:整本正文 / 设定 / 规划 / 角色 / 质检记录 / 项目 JSON。
@@ -489,4 +528,5 @@ export declare function exportScope(outputDir: string, project: ProjectState, sc
489
528
  file: string;
490
529
  chars: number;
491
530
  chapters: number;
531
+ skipped?: number[];
492
532
  };
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import type { Context } from '@deepseek-ai/cordis';
10
10
  import z from 'schemastery';
11
- import type { NovelConfig } from './protocol.ts';
11
+ import type { NovelConfig, SavedModel } from './protocol.ts';
12
12
  /** Stable cordis plugin name. */
13
13
  export declare const name = "novel-forge";
14
14
  /** Services required before the novel-forge surfaces can mount. */
@@ -47,6 +47,8 @@ export interface Config {
47
47
  auditModel?: string;
48
48
  /** 备用模型:主模型失败时自动切换重试一次(留空 = 不切换)。 */
49
49
  fallbackModel?: string;
50
+ /** 备用模型的输出 token 上限(仅在设了 fallbackModel 时有意义;0/空 = 沿用主模型预算)。 */
51
+ fallbackMaxTokens?: number;
50
52
  /** 出章后自动抽取故事时间线(默认开)。 */
51
53
  autoTimeline?: boolean;
52
54
  /** LLM reasoning effort (off/low/high/max). */
@@ -73,6 +75,8 @@ export interface Config {
73
75
  themeOpacity?: number;
74
76
  /** 是否启用改编模式(默认关闭)。 */
75
77
  enableAdaptMode?: boolean;
78
+ /** 手动添加的模型库(「我的模型」条目;只存插件内)。 */
79
+ savedModels?: SavedModel[];
76
80
  }
77
81
  /**
78
82
  * Plugin config schema.
@@ -0,0 +1,110 @@
1
+ /**
2
+ * 取名器:按类别批量生成中文网文专有名字,入每书「名字库」,采纳后注入写作提示词。
3
+ *
4
+ * 设计边界(与提示词槽位同一家风):
5
+ * * 取名是**辅助资产**:候选由模型生成,作者逐条采纳才进库;未采纳的候选
6
+ * 不落盘、不注入——作者保有最终决定权;
7
+ * * 库有容量上限(每类 60 / 全书 200 条),超限拒绝写入并要求先清理,防止
8
+ * 「生成很爽、库变垃圾场」;
9
+ * * 注入写作提示词的名字块只列**已采纳**名字,且声明「新角色/地点优先
10
+ * 使用下表;表外创新名须与下表气质一致」——不锁死创作,只防跑偏。
11
+ */
12
+ import type { NameCategory, NameForgeCandidate, NameForgeEntry, ProjectState } from './protocol.ts';
13
+ /** 一个取名类别。 */
14
+ export interface NameCategorySpec {
15
+ id: NameCategory;
16
+ /** 面板显示名。 */
17
+ label: string;
18
+ /** 面板上的一句话说明。 */
19
+ hint: string;
20
+ /** 送模型的类别定义(Prompt 内使用)。 */
21
+ brief: string;
22
+ /** 示例(占位符)。 */
23
+ placeholder: string;
24
+ /** 单次生成上限。 */
25
+ maxCount: number;
26
+ }
27
+ /** 取名类别表(顺序即面板顺序)。 */
28
+ export declare const NAME_CATEGORIES: readonly NameCategorySpec[];
29
+ /** 取一个类别规格;未知 id 抛错(路由层转 400)。 */
30
+ export declare function categorySpec(id: string): NameCategorySpec;
31
+ /**
32
+ * 名字库容量纪律:单类 ≤ 60、全书 ≤ 200。
33
+ *
34
+ * 全书上限必须**小于**「类数 × 单类上限」(5×60=300)否则永远先被单类规则
35
+ * 挡住、成为死代码——200 逼作者在囤积前清理,也足够一部 600 章的书用。
36
+ */
37
+ export declare const NAME_BANK_MAX_PER_CATEGORY = 60;
38
+ export declare const NAME_BANK_MAX_TOTAL = 200;
39
+ /** 归一化一条候选/入库条目(裁剪 + 截断;去重由调用方处理)。 */
40
+ export declare function normalizeNameEntry(raw: {
41
+ name?: unknown;
42
+ note?: unknown;
43
+ }): {
44
+ name: string;
45
+ note: string;
46
+ };
47
+ /**
48
+ * 解析取名 LLM 输出为候选列表。
49
+ *
50
+ * 宽容度分级:标准 JSON → 去围栏 → 截取首尾花括号;仍失败返回空数组(由
51
+ * 调用方决定重试或报错),绝不把模型废话当名字。
52
+ *
53
+ * @param text 模型原始输出。
54
+ * @param category 目标类别(用于校验字段完整性)。
55
+ * @param count 期望条数(上限)。
56
+ * @returns 候选列表(已去重、去空、截断)。
57
+ */
58
+ export declare function parseNameCandidates(text: string, count: number): NameForgeCandidate[];
59
+ /**
60
+ * 构造取名请求的 user 提示词。
61
+ *
62
+ * 书籍语境三件套:题材基调、世界设定(境界/区域/势力既有名)、已入库名字
63
+ * (避重)——三者都可缺省,缺省时明确告诉模型「无既有设定,自由发挥」。
64
+ *
65
+ * @param category 类别规格。
66
+ * @param count 期望条数。
67
+ * @param hint 作者补充要求(可空)。
68
+ * @param context 书籍语境。
69
+ */
70
+ export declare function buildNameForgeUserPrompt(category: NameCategorySpec, count: number, hint: string, context: {
71
+ genre?: string;
72
+ worldNames?: string[];
73
+ bankNames?: string[];
74
+ }): string;
75
+ /** 从项目状态收集取名语境(题材 + 世界既有名 + 已入库名字)。 */
76
+ export declare function collectNameForgeContext(project: ProjectState): {
77
+ genre: string;
78
+ worldNames: string[];
79
+ bankNames: string[];
80
+ };
81
+ /** 读取并规整名字库(按类别分组返回前先做一致性校验;非法条目丢弃)。 */
82
+ export declare function readNameBank(project: ProjectState): NameForgeEntry[];
83
+ /**
84
+ * 写入名字库(采纳候选 / 弃用单条 / 清空)。
85
+ *
86
+ * 容量纪律:单类 ≤ 60、总数 ≤ 200;超限抛错由路由转 400,**不做静默截断**——
87
+ * 让作者明确知道库满了,而不是疑惑「我刚取的名字去哪了」。
88
+ */
89
+ export declare function mutateNameBank(project: ProjectState, op: {
90
+ kind: 'adopt';
91
+ category: NameCategory;
92
+ candidates: Array<{
93
+ name: string;
94
+ note?: string;
95
+ }>;
96
+ } | {
97
+ kind: 'discard';
98
+ id: string;
99
+ } | {
100
+ kind: 'clear';
101
+ }): NameForgeEntry[];
102
+ /**
103
+ * 把已采纳名字渲染成写作提示词块(本书层注入)。
104
+ *
105
+ * 声明边界:优先使用、不锁死——「表外创新名须与下表气质一致」。
106
+ *
107
+ * @param project 项目状态。
108
+ * @returns 提示词片段;无库时返回空串。
109
+ */
110
+ export declare function renderNameBank(project: ProjectState): string;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 取名域:按类别批量生成中文网文专有名字(人名 / 地名 / 功法 / 势力 / 宝物)。
3
+ *
4
+ * 本文件同时是提示词注册表的域模块之一(见 catalog.ts)。
5
+ *
6
+ * 设计边界:
7
+ * * 取名是**辅助资产**,产出进「名字库」供作者采纳;采纳后的名字才注入
8
+ * 写作提示词(书名库渲染在 prompts/writing.ts 的本书层);
9
+ * * 提示词只描述「怎么取名」,不写死任何名字——所有候选来自模型按本书
10
+ * 语境(题材 / 世界设定 / 已有名字避重)的实时生成。
11
+ */
12
+ import type { PromptEntry } from './catalog.ts';
13
+ /** 取名系统提示词:类别感知 + 避重 + 结构化 JSON 输出。 */
14
+ export declare function nameForgeSystemPrompt(): string;
15
+ /** 本域提示词登记(注册表消费)。 */
16
+ export declare const entries: PromptEntry[];