@waterwx/dsh-novel-forge 0.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.
- package/LICENSE +202 -0
- package/README.md +180 -0
- package/cordis.patch.yml +13 -0
- package/lib/client.js +3924 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +3120 -0
- package/lib/index.js.map +1 -0
- package/lib/types/assets.d.ts +35 -0
- package/lib/types/assistant.d.ts +43 -0
- package/lib/types/bookshelf.d.ts +35 -0
- package/lib/types/client/api.d.ts +68 -0
- package/lib/types/client/docx.d.ts +15 -0
- package/lib/types/client/index.d.ts +14 -0
- package/lib/types/client/locales.d.ts +139 -0
- package/lib/types/client/mount.d.ts +9 -0
- package/lib/types/client/panel/AssetsTab.d.ts +7 -0
- package/lib/types/client/panel/AssistantTab.d.ts +7 -0
- package/lib/types/client/panel/BookshelfBar.d.ts +11 -0
- package/lib/types/client/panel/NovelPanel.d.ts +13 -0
- package/lib/types/client/panel/controller.d.ts +19 -0
- package/lib/types/client/panel/helpers.d.ts +8 -0
- package/lib/types/client/sidebar-entry.d.ts +13 -0
- package/lib/types/docx.d.ts +19 -0
- package/lib/types/engine.d.ts +95 -0
- package/lib/types/index.d.ts +55 -0
- package/lib/types/protocol.d.ts +521 -0
- package/lib/types/routes.d.ts +29 -0
- package/package.json +105 -0
- package/src/assets.ts +518 -0
- package/src/assistant.ts +547 -0
- package/src/bookshelf.ts +137 -0
- package/src/client/api.ts +254 -0
- package/src/client/css-modules.d.ts +8 -0
- package/src/client/docx.ts +69 -0
- package/src/client/index.ts +34 -0
- package/src/client/locales.ts +271 -0
- package/src/client/mount.tsx +97 -0
- package/src/client/panel/AssetsTab.tsx +341 -0
- package/src/client/panel/AssistantTab.tsx +188 -0
- package/src/client/panel/BookshelfBar.tsx +116 -0
- package/src/client/panel/NovelPanel.tsx +990 -0
- package/src/client/panel/controller.ts +45 -0
- package/src/client/panel/helpers.ts +17 -0
- package/src/client/panel/panel.module.css +894 -0
- package/src/client/sidebar-entry.ts +122 -0
- package/src/docx.ts +83 -0
- package/src/engine.ts +1019 -0
- package/src/index.ts +184 -0
- package/src/protocol.ts +539 -0
- package/src/routes.ts +955 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writing assets — 题材基底库 / 推进模式库 / 反 AI 规则 / 写法引擎.
|
|
3
|
+
*
|
|
4
|
+
* Ported from AI-Novel-Writing-Assistant (Apache-2.0) built-in seed data:
|
|
5
|
+
* - 8 preset style templates (DEFAULT_STYLE_TEMPLATES)
|
|
6
|
+
* - 12 anti-AI rules with concrete detect patterns (DEFAULT_ANTI_AI_RULES)
|
|
7
|
+
* - genre tree + progression mode seeds
|
|
8
|
+
* Assets persist with the project (novel-project.json) and are injected into
|
|
9
|
+
* generation / planning / review prompts, and available to the AI assistant.
|
|
10
|
+
*/
|
|
11
|
+
import type { AntiAiRule, GenreNode, ProgressionMode, ProjectAssets, StyleAsset, StyleTemplate } from './protocol.ts';
|
|
12
|
+
/** 预置写法模板(来自 AI-Novel-Writing-Assistant 内置 DEFAULT_STYLE_TEMPLATES)。 */
|
|
13
|
+
export declare const BUILTIN_STYLE_TEMPLATES: StyleTemplate[];
|
|
14
|
+
/** 内置全局反 AI 规则(来自 AI-Novel-Writing-Assistant 内置 DEFAULT_ANTI_AI_RULES)。 */
|
|
15
|
+
export declare const BUILTIN_ANTI_AI_RULES: AntiAiRule[];
|
|
16
|
+
/** 内置题材基底库(常用网文题材树,跨书复用)。 */
|
|
17
|
+
export declare const BUILTIN_GENRE_LIBRARY: GenreNode[];
|
|
18
|
+
/** 内置常用推进模式。 */
|
|
19
|
+
export declare const BUILTIN_PROGRESSION_MODES: ProgressionMode[];
|
|
20
|
+
/** 默认(空)项目写作资产。 */
|
|
21
|
+
export declare function emptyProjectAssets(): ProjectAssets;
|
|
22
|
+
/** 合并项目资产与内置库:返回「生效的反 AI 规则」(内置全局 + 项目自定义)。 */
|
|
23
|
+
export declare function effectiveAntiAiRules(assets: ProjectAssets | undefined): AntiAiRule[];
|
|
24
|
+
/** 把生效规则渲染成提示词块。 */
|
|
25
|
+
export declare function renderAntiAiRules(assets: ProjectAssets | undefined): string;
|
|
26
|
+
/** 渲染题材与推进模式提示词块。 */
|
|
27
|
+
export declare function renderGenreAndProgression(assets: ProjectAssets | undefined): string;
|
|
28
|
+
/** 渲染写法资产提示词块。 */
|
|
29
|
+
export declare function renderStyleAssets(assets: ProjectAssets | undefined): string;
|
|
30
|
+
/** 渲染全部写作资产提示词(供生成/规划/审稿注入)。 */
|
|
31
|
+
export declare function renderAllAssets(assets: ProjectAssets | undefined): string;
|
|
32
|
+
/** 预置写法模板 → 可直接绑定的 StyleAsset。 */
|
|
33
|
+
export declare function styleTemplateToAsset(template: StyleTemplate): StyleAsset;
|
|
34
|
+
/** 写法引擎:从样本文本提取风格资产的系统提示词。 */
|
|
35
|
+
export declare function styleEngineSystemPrompt(): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI assistant engine — a conversational editor over the novel project.
|
|
3
|
+
*
|
|
4
|
+
* The user talks to the assistant about plot, characters, settings; the
|
|
5
|
+
* assistant can reply in prose AND emit action directives that the host
|
|
6
|
+
* executes (rewrite a paragraph, edit the bible, regenerate a chapter,
|
|
7
|
+
* export the book, ...). Conversation history persists next to the project
|
|
8
|
+
* as NDJSON, so a reload keeps the thread.
|
|
9
|
+
*
|
|
10
|
+
* Action protocol: the model emits a line of the form
|
|
11
|
+
* <dsh-action name="toolName">{jsonArgs}</dsh-action>
|
|
12
|
+
* anywhere in its reply. The host strips it, executes the tool, appends the
|
|
13
|
+
* result as a tool-role message, and continues the loop (bounded rounds).
|
|
14
|
+
*/
|
|
15
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
16
|
+
import type { AssistantMessage, NovelConfig, ProjectState } from './protocol.ts';
|
|
17
|
+
import { chapterFileName } from './engine.ts';
|
|
18
|
+
/** History file name inside the output dir. */
|
|
19
|
+
export declare const ASSISTANT_HISTORY_FILE = "novel-assistant.jsonl";
|
|
20
|
+
/** Load the persisted conversation (empty when none). */
|
|
21
|
+
export declare function loadAssistantHistory(outputDir: string): AssistantMessage[];
|
|
22
|
+
/** Execute one action directive. Returns a text result (or throws). */
|
|
23
|
+
/**
|
|
24
|
+
* Execute one action directive as an async generator: yields live progress
|
|
25
|
+
* text (chapter text being generated/rewritten), then yields the final result
|
|
26
|
+
* string. Throws on failure.
|
|
27
|
+
*/
|
|
28
|
+
export declare function executeAction(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, name: string, args: Record<string, unknown>): AsyncGenerator<string, string, unknown>;
|
|
29
|
+
/** Run one user turn. Yields stream frames; persists history. */
|
|
30
|
+
export declare function runAssistantTurn(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, userMessage: string): AsyncGenerator<{
|
|
31
|
+
frame: 'delta';
|
|
32
|
+
text: string;
|
|
33
|
+
} | {
|
|
34
|
+
frame: 'tool';
|
|
35
|
+
name: string;
|
|
36
|
+
status: 'start' | 'done' | 'error';
|
|
37
|
+
detail?: string;
|
|
38
|
+
} | {
|
|
39
|
+
frame: 'toolDelta';
|
|
40
|
+
name: string;
|
|
41
|
+
text: string;
|
|
42
|
+
}, void, unknown>;
|
|
43
|
+
export { chapterFileName };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 书架(Bookshelf)— 多书管理:一本书记录一个独立输出目录。
|
|
3
|
+
* 状态持久化到 ~/.dsh/dsh-novel-forge-bookshelf.json(跟随 dsh 配置惯例)。
|
|
4
|
+
*/
|
|
5
|
+
import type { BookEntry, BookshelfSnapshot } from './protocol.ts';
|
|
6
|
+
/** 书架配置文件路径。 */
|
|
7
|
+
export declare function bookshelfFile(): string;
|
|
8
|
+
interface BookshelfStore {
|
|
9
|
+
books: BookEntry[];
|
|
10
|
+
activeBookId: string | null;
|
|
11
|
+
}
|
|
12
|
+
/** 读取书架(无则返回空)。 */
|
|
13
|
+
export declare function loadBookshelf(): BookshelfStore;
|
|
14
|
+
/** 当前激活的书。 */
|
|
15
|
+
export declare function activeBook(store: BookshelfStore): BookEntry | undefined;
|
|
16
|
+
/** 书架快照(含每本书的进度摘要)。 */
|
|
17
|
+
export declare function bookshelfSnapshot(store: BookshelfStore): BookshelfSnapshot;
|
|
18
|
+
/** 新建一本书(自动成为当前书)。 */
|
|
19
|
+
export declare function createBook(bookName: string, outputDir: string): BookEntry;
|
|
20
|
+
/**
|
|
21
|
+
* 播种:书架为空时,把指定输出目录下已有的项目自动登记为第一本书。
|
|
22
|
+
* 兼容升级场景 —— 旧版插件直接在输出目录写项目,从未登记书架。
|
|
23
|
+
* @param outputDir - 候选输出目录(通常为 settings 的默认输出目录)。
|
|
24
|
+
* @returns 是否发生了播种。
|
|
25
|
+
*/
|
|
26
|
+
export declare function seedBookshelfFromOutputDir(outputDir: string): boolean;
|
|
27
|
+
/** 激活一本书。 */
|
|
28
|
+
export declare function activateBook(id: string): BookEntry | undefined;
|
|
29
|
+
/** 移除一本书。 */
|
|
30
|
+
export declare function removeBook(id: string): boolean;
|
|
31
|
+
/** 当前书输出目录(无书架则 undefined,回退 settings)。 */
|
|
32
|
+
export declare function activeBookOutputDir(): string | undefined;
|
|
33
|
+
/** 默认输出目录推断:桌面/书名。 */
|
|
34
|
+
export declare function defaultOutputDirFor(bookName: string): string;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
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
|
+
import { type AssetsPatch, type AssetsResponse, type BibleResponse, type ChapterResponse, type ConfigPatch, type ExportResponse, type ForeshadowRequest, type ForeshadowResponse, type JobFrame, type LoadOutlineResponse, type NovelConfig, type PlanResponse, type ReviewReport, type StatusResponse, type StyleEngineRequest, type StyleAsset, type VolumesResponse } from '../protocol.ts';
|
|
7
|
+
/** Error carrying the route's JSON error message. */
|
|
8
|
+
export declare class NovelApiError extends Error {
|
|
9
|
+
constructor(message: string);
|
|
10
|
+
}
|
|
11
|
+
/** The browser half's only data entry point. */
|
|
12
|
+
export declare class NovelApi {
|
|
13
|
+
status(): Promise<StatusResponse>;
|
|
14
|
+
loadOutline(path?: string, text?: string): Promise<LoadOutlineResponse>;
|
|
15
|
+
saveOutline(text: string): Promise<{
|
|
16
|
+
ok: boolean;
|
|
17
|
+
bookName: string;
|
|
18
|
+
}>;
|
|
19
|
+
plan(outline?: string, chapterCount?: number, volume?: number): Promise<PlanResponse>;
|
|
20
|
+
volumes(outline?: string): Promise<VolumesResponse>;
|
|
21
|
+
bible(outline?: string): Promise<BibleResponse>;
|
|
22
|
+
review(chapterNo: number): Promise<{
|
|
23
|
+
report: ReviewReport;
|
|
24
|
+
}>;
|
|
25
|
+
summarize(chapterNo: number): Promise<{
|
|
26
|
+
summary: string;
|
|
27
|
+
}>;
|
|
28
|
+
foreshadow(req: ForeshadowRequest): Promise<ForeshadowResponse>;
|
|
29
|
+
exportBook(format: 'txt' | 'md'): Promise<ExportResponse>;
|
|
30
|
+
chapter(no: number): Promise<ChapterResponse>;
|
|
31
|
+
patchConfig(patch: ConfigPatch): Promise<{
|
|
32
|
+
config: NovelConfig;
|
|
33
|
+
}>;
|
|
34
|
+
openFolder(): Promise<void>;
|
|
35
|
+
/** 书架快照。 */
|
|
36
|
+
bookshelf(): Promise<import('../protocol.ts').BookshelfSnapshot>;
|
|
37
|
+
/** 新建书并激活。 */
|
|
38
|
+
bookCreate(bookName: string, outputDir?: string): Promise<import('../protocol.ts').BookshelfSnapshot>;
|
|
39
|
+
/** 切换当前书。 */
|
|
40
|
+
bookActivate(id: string): Promise<import('../protocol.ts').BookshelfSnapshot>;
|
|
41
|
+
/** 移除书架条目。 */
|
|
42
|
+
bookRemove(id: string): Promise<import('../protocol.ts').BookshelfSnapshot>;
|
|
43
|
+
/** Get project writing assets + built-in libraries. */
|
|
44
|
+
assets(): Promise<AssetsResponse>;
|
|
45
|
+
/** Patch project writing assets. */
|
|
46
|
+
patchAssets(patch: AssetsPatch): Promise<AssetsResponse>;
|
|
47
|
+
/** Extract a style asset from sample text. */
|
|
48
|
+
styleEngine(req: StyleEngineRequest): Promise<{
|
|
49
|
+
styleAsset: StyleAsset;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Consume an NDJSON job stream (generate / rewrite / polish).
|
|
53
|
+
* @param path - the route to POST to.
|
|
54
|
+
* @param payload - the JSON body.
|
|
55
|
+
* @param onFrame - receives every frame as it lands.
|
|
56
|
+
*/
|
|
57
|
+
private streamJob;
|
|
58
|
+
/** Generate one chapter. */
|
|
59
|
+
generate(chapterNo: number, skipReview: boolean, onFrame: (frame: JobFrame) => void): Promise<void>;
|
|
60
|
+
/** Rewrite one chapter (whole-chapter, or local when `target` is given). */
|
|
61
|
+
rewrite(chapterNo: number, instructions: string, target: string, onFrame: (frame: JobFrame) => void): Promise<void>;
|
|
62
|
+
/** Polish (de-AI-ify) one chapter. */
|
|
63
|
+
polish(chapterNo: number, onFrame: (frame: JobFrame) => void): Promise<void>;
|
|
64
|
+
/** Run one assistant turn (NDJSON stream). */
|
|
65
|
+
assistant(message: string, onFrame: (frame: import('../protocol.ts').AssistantFrame) => void): Promise<void>;
|
|
66
|
+
/** Load the persisted assistant conversation. */
|
|
67
|
+
assistantHistory(): Promise<import('../protocol.ts').AssistantMessage[]>;
|
|
68
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-side docx outline extraction: a .docx is a zip whose
|
|
3
|
+
* word/document.xml holds the body text in <w:t> runs inside <w:p> paragraphs.
|
|
4
|
+
* Uses fflate (inlined into the client bundle) so the user can pick or drag a
|
|
5
|
+
* docx without any server upload.
|
|
6
|
+
*
|
|
7
|
+
* Import from 'fflate/browser' (not 'fflate'): the default entry resolves to
|
|
8
|
+
* the Node build (esm/index.mjs), which calls module.createRequire() for the
|
|
9
|
+
* optional worker_threads path — inlining that into the browser bundle leaves
|
|
10
|
+
* a bare require("module") the client-modules table cannot answer.
|
|
11
|
+
*/
|
|
12
|
+
/** Extract plain text from a docx buffer: one line per <w:p> paragraph. */
|
|
13
|
+
export declare function extractDocxTextFromBuffer(buffer: ArrayBuffer | Uint8Array): string;
|
|
14
|
+
/** Read a File as ArrayBuffer. */
|
|
15
|
+
export declare function readFileAsArrayBuffer(file: File): Promise<ArrayBuffer>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-half entry for the dsh-novel-forge plugin — runs inside the dsh web
|
|
3
|
+
* GUI. Registers the sidebar entry row and the workbench panel. DOM mounting
|
|
4
|
+
* problems are logged, never thrown — the web shell fails the whole boot when
|
|
5
|
+
* a plugin apply throws.
|
|
6
|
+
*/
|
|
7
|
+
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
|
|
8
|
+
/** Required services (fiber inject waiting). */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Mount the novel-forge workbench.
|
|
12
|
+
* @param ctx - client root context.
|
|
13
|
+
*/
|
|
14
|
+
export declare function apply(ctx: ClientContext): void;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-novel-forge — locale dictionaries (zh / en).
|
|
3
|
+
*/
|
|
4
|
+
/** zh dictionary. */
|
|
5
|
+
export declare const zh: {
|
|
6
|
+
readonly 'entry.label': "小说工坊";
|
|
7
|
+
readonly 'entry.tooltip': "AI 编译小说工作台:大纲 → 设定圣经 → 卷计划 → 章节计划 → 逐章生成+审稿";
|
|
8
|
+
readonly 'panel.title': "小说工坊";
|
|
9
|
+
readonly 'common.close': "关闭";
|
|
10
|
+
readonly 'common.loading': "加载中…";
|
|
11
|
+
readonly 'common.save': "保存";
|
|
12
|
+
readonly 'common.error': "错误";
|
|
13
|
+
readonly 'common.success': "成功";
|
|
14
|
+
readonly 'common.generating': "生成中…";
|
|
15
|
+
readonly 'common.chars': "字";
|
|
16
|
+
readonly 'tab.workflow': "工作流";
|
|
17
|
+
readonly 'tab.overview': "大纲";
|
|
18
|
+
readonly 'tab.plan': "章节";
|
|
19
|
+
readonly 'tab.bible': "设定库";
|
|
20
|
+
readonly 'tab.foreshadow': "伏笔";
|
|
21
|
+
readonly 'tab.assistant': "AI 助手";
|
|
22
|
+
readonly 'tab.settings': "设置";
|
|
23
|
+
readonly 'workflow.title': "创作工作流";
|
|
24
|
+
readonly 'workflow.step1': "① 加载大纲";
|
|
25
|
+
readonly 'workflow.step2': "② 提炼设定圣经";
|
|
26
|
+
readonly 'workflow.step3': "③ 规划卷";
|
|
27
|
+
readonly 'workflow.step4': "④ 生成章节计划";
|
|
28
|
+
readonly 'workflow.step5': "⑤ 逐章写作 + AI 审稿";
|
|
29
|
+
readonly 'workflow.step6': "⑥ 润色 / 导出";
|
|
30
|
+
readonly 'workflow.loadOutline': "读取大纲";
|
|
31
|
+
readonly 'workflow.genBible': "提炼设定圣经";
|
|
32
|
+
readonly 'workflow.genVolumes': "生成卷计划";
|
|
33
|
+
readonly 'workflow.genPlan': "生成章节计划";
|
|
34
|
+
readonly 'workflow.done': "已完成";
|
|
35
|
+
readonly 'workflow.todo': "待办";
|
|
36
|
+
readonly 'workflow.bibleDone': "设定圣经已生成({n} 条规则 / {c} 个角色 / {r} 条红线)";
|
|
37
|
+
readonly 'workflow.volumesDone': "卷计划已生成({n} 卷)";
|
|
38
|
+
readonly 'workflow.planDone': "章节计划已生成({n} 章)";
|
|
39
|
+
readonly 'workflow.progress': "进度:大纲 ✓ · 设定 {bible} · 卷 {volumes} · 计划 {plan} · 已完成 {done}/{total} 章";
|
|
40
|
+
readonly 'overview.loadDocx': "从 docx 读取大纲";
|
|
41
|
+
readonly 'overview.loadDocxDefault': "读取默认大纲";
|
|
42
|
+
readonly 'overview.loadingOutline': "正在解析 docx…";
|
|
43
|
+
readonly 'overview.outlineHint': "大纲文本(可编辑)";
|
|
44
|
+
readonly 'overview.outlineChars': "大纲字数";
|
|
45
|
+
readonly 'overview.saveOutline': "保存大纲";
|
|
46
|
+
readonly 'overview.saved': "大纲已保存";
|
|
47
|
+
readonly 'overview.bookName': "书名";
|
|
48
|
+
readonly 'overview.loadCustom': "指定 docx 路径";
|
|
49
|
+
readonly 'overview.loadCustomHint': "绝对路径,留空使用默认";
|
|
50
|
+
readonly 'plan.generate': "生成章节计划";
|
|
51
|
+
readonly 'plan.generateHint': "章节数量";
|
|
52
|
+
readonly 'plan.count': "章";
|
|
53
|
+
readonly 'plan.empty': "暂无章节计划,请先生成";
|
|
54
|
+
readonly 'plan.chapter': "章";
|
|
55
|
+
readonly 'plan.pending': "待生成";
|
|
56
|
+
readonly 'plan.generating': "生成中";
|
|
57
|
+
readonly 'plan.written': "待审稿";
|
|
58
|
+
readonly 'plan.reviewing': "审稿中";
|
|
59
|
+
readonly 'plan.approved': "已通过";
|
|
60
|
+
readonly 'plan.rejected': "待修订";
|
|
61
|
+
readonly 'plan.error': "失败";
|
|
62
|
+
readonly 'plan.write': "生成本章";
|
|
63
|
+
readonly 'plan.rewrite': "修订";
|
|
64
|
+
readonly 'plan.review': "审稿";
|
|
65
|
+
readonly 'plan.polish': "去AI味";
|
|
66
|
+
readonly 'plan.writeAll': "批量生成全部";
|
|
67
|
+
readonly 'plan.writeAllPending': "批量生成剩余";
|
|
68
|
+
readonly 'plan.generated': "已生成";
|
|
69
|
+
readonly 'plan.progress': "进度";
|
|
70
|
+
readonly 'plan.beats': "剧情要点";
|
|
71
|
+
readonly 'plan.reviewReport': "审稿报告";
|
|
72
|
+
readonly 'plan.reviewScore': "评分";
|
|
73
|
+
readonly 'plan.reviewVerdict': "总评";
|
|
74
|
+
readonly 'plan.reviewIssues': "问题清单";
|
|
75
|
+
readonly 'plan.reviewPass': "通过";
|
|
76
|
+
readonly 'plan.reviewFail': "未通过";
|
|
77
|
+
readonly 'plan.approve': "手动通过";
|
|
78
|
+
readonly 'plan.summary': "章节摘要";
|
|
79
|
+
readonly 'plan.volumes': "卷";
|
|
80
|
+
readonly 'plan.noVolume': "未分卷";
|
|
81
|
+
readonly 'bible.title': "设定圣经";
|
|
82
|
+
readonly 'bible.gen': "AI 提炼设定圣经";
|
|
83
|
+
readonly 'bible.genre': "题材基调";
|
|
84
|
+
readonly 'bible.worldRules': "世界规则";
|
|
85
|
+
readonly 'bible.characters': "角色卡";
|
|
86
|
+
readonly 'bible.redLines': "写作红线";
|
|
87
|
+
readonly 'bible.style': "风格要求";
|
|
88
|
+
readonly 'bible.none': "尚未生成设定圣经。生成后写作会严格遵守人设与金手指规则,审稿也会按红线检查。";
|
|
89
|
+
readonly 'foreshadow.title': "伏笔管理";
|
|
90
|
+
readonly 'foreshadow.suggest': "AI 建议伏笔";
|
|
91
|
+
readonly 'foreshadow.none': "暂无伏笔";
|
|
92
|
+
readonly 'foreshadow.status': "状态";
|
|
93
|
+
readonly 'foreshadow.planned': "计划中";
|
|
94
|
+
readonly 'foreshadow.planted': "已埋设";
|
|
95
|
+
readonly 'foreshadow.progressing': "推进中";
|
|
96
|
+
readonly 'foreshadow.resolved': "已回收";
|
|
97
|
+
readonly 'foreshadow.abandoned': "已放弃";
|
|
98
|
+
readonly 'foreshadow.target': "预计回收";
|
|
99
|
+
readonly 'foreshadow.plantedAt': "埋设于";
|
|
100
|
+
readonly 'foreshadow.setPlanted': "标记已埋设";
|
|
101
|
+
readonly 'foreshadow.setResolved': "标记已回收";
|
|
102
|
+
readonly 'settings.title': "设置";
|
|
103
|
+
readonly 'settings.outlinePath': "默认大纲路径";
|
|
104
|
+
readonly 'settings.outputDir': "输出目录";
|
|
105
|
+
readonly 'settings.provider': "模型提供商";
|
|
106
|
+
readonly 'settings.model': "模型";
|
|
107
|
+
readonly 'settings.chapterChars': "每章目标字数";
|
|
108
|
+
readonly 'settings.maxTokens': "单章最大输出 tokens";
|
|
109
|
+
readonly 'settings.reviewPassScore': "审稿通过分数(0-100)";
|
|
110
|
+
readonly 'settings.autoReview': "生成后自动审稿";
|
|
111
|
+
readonly 'settings.save': "保存设置";
|
|
112
|
+
readonly 'settings.saved': "设置已保存";
|
|
113
|
+
readonly 'settings.openFolder': "打开输出文件夹";
|
|
114
|
+
readonly 'settings.export': "导出";
|
|
115
|
+
readonly 'settings.exportTxt': "导出 TXT";
|
|
116
|
+
readonly 'settings.exportMd': "导出 Markdown";
|
|
117
|
+
readonly 'settings.exported': "已导出:{file}({chars} 字,{chapters} 章)";
|
|
118
|
+
readonly 'progress.generating': "正在生成第 {no} 章《{title}》…";
|
|
119
|
+
readonly 'progress.done': "第 {no} 章完成({chars} 字)→ {file}";
|
|
120
|
+
readonly 'progress.reviewed': "第 {no} 章审稿:{score} 分 — {verdict}";
|
|
121
|
+
readonly 'progress.error': "第 {no} 章失败:{message}";
|
|
122
|
+
readonly 'progress.rewriting': "正在修订第 {no} 章…";
|
|
123
|
+
readonly 'progress.polishing': "正在润色第 {no} 章…";
|
|
124
|
+
readonly 'progress.empty': "生成/审稿进度将显示在这里";
|
|
125
|
+
readonly 'assistant.hint': "和 AI 编辑讨论剧情、人设、伏笔;达成一致后可让它直接修改大纲、设定圣经、章节内容。";
|
|
126
|
+
readonly 'assistant.placeholder': "例如:我想让第 2 章结尾加一个悬念——墟境里传来爷爷的声音…";
|
|
127
|
+
readonly 'assistant.send': "发送";
|
|
128
|
+
readonly 'assistant.toolStart': "⚙ 执行操作:{name}…";
|
|
129
|
+
readonly 'assistant.toolDone': "✓ {name} 完成:{detail}";
|
|
130
|
+
readonly 'assistant.toolError': "✗ {name} 失败:{detail}";
|
|
131
|
+
readonly 'assistant.empty': "还没有对话。和 AI 编辑聊聊剧情吧。";
|
|
132
|
+
readonly 'status.projectNone': "输出目录中还没有项目。请先加载大纲。";
|
|
133
|
+
readonly 'status.files': "已生成文件";
|
|
134
|
+
readonly 'api.error': "请求失败";
|
|
135
|
+
};
|
|
136
|
+
/** en dictionary (fallback). */
|
|
137
|
+
export declare const en: Record<string, string>;
|
|
138
|
+
/** Keys type for the zh dictionary. */
|
|
139
|
+
export type NovelKey = keyof typeof zh;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { NovelApi } from './api.ts';
|
|
2
|
+
import type { PanelController } from './panel/controller.ts';
|
|
3
|
+
/** The injected panel container. */
|
|
4
|
+
export declare const PANEL_VIEW_SELECTOR = "[data-dsh-novelforge-view]";
|
|
5
|
+
/**
|
|
6
|
+
* Mount the panel React tree into the center column and bind visibility to
|
|
7
|
+
* the controller.
|
|
8
|
+
*/
|
|
9
|
+
export declare function mountPanel(controller: PanelController, api: NovelApi): () => void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { NovelApi } from '../api.ts';
|
|
2
|
+
import type { BookshelfSnapshot } from '../../protocol.ts';
|
|
3
|
+
/** Props. */
|
|
4
|
+
export interface BookshelfBarProps {
|
|
5
|
+
api: NovelApi;
|
|
6
|
+
shelf: BookshelfSnapshot;
|
|
7
|
+
/** 刷新整个面板(切换书后重新拉状态)。 */
|
|
8
|
+
onSwitch: () => void;
|
|
9
|
+
}
|
|
10
|
+
/** 书架条。 */
|
|
11
|
+
export declare function BookshelfBar({ api, shelf, onSwitch }: BookshelfBarProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { NovelApi } from '../api.ts';
|
|
2
|
+
import type { PanelController } from './controller.ts';
|
|
3
|
+
/** The panel's tab identifiers. */
|
|
4
|
+
export type NovelTab = 'workflow' | 'overview' | 'plan' | 'bible' | 'assets' | 'foreshadow' | 'assistant' | 'settings';
|
|
5
|
+
/** Panel shell props. */
|
|
6
|
+
export interface NovelPanelProps {
|
|
7
|
+
/** The panel state owner (open/close/toggle). */
|
|
8
|
+
controller: PanelController;
|
|
9
|
+
/** The API client every tab operates through. */
|
|
10
|
+
api: NovelApi;
|
|
11
|
+
}
|
|
12
|
+
/** The novel-forge panel. */
|
|
13
|
+
export declare function NovelPanel({ controller, api }: NovelPanelProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Novel-forge panel controller: the single owner of the panel's open/closed
|
|
3
|
+
* state (framework-free, mirroring the family plugins' controllers).
|
|
4
|
+
*/
|
|
5
|
+
/** Immutable controller snapshot for UI subscriptions. */
|
|
6
|
+
export interface PanelControllerSnapshot {
|
|
7
|
+
panelOpen: boolean;
|
|
8
|
+
}
|
|
9
|
+
/** The panel state owner the sidebar entry toggles and the view renders from. */
|
|
10
|
+
export declare class PanelController {
|
|
11
|
+
private panelOpen;
|
|
12
|
+
private listeners;
|
|
13
|
+
getSnapshot(): PanelControllerSnapshot;
|
|
14
|
+
subscribe(fn: () => void): () => void;
|
|
15
|
+
open(): void;
|
|
16
|
+
close(): void;
|
|
17
|
+
toggle(): void;
|
|
18
|
+
private notify;
|
|
19
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny translation helper for the panel: reads the zh dict with the en dict
|
|
3
|
+
* as fallback (the family plugins use a full locale registry; the panel keeps
|
|
4
|
+
* a dependency-free helper so the client bundle stays self-contained).
|
|
5
|
+
*/
|
|
6
|
+
import { type NovelKey } from '../locales.ts';
|
|
7
|
+
/** Translate one key with optional {placeholder} substitution. */
|
|
8
|
+
export declare function tt(key: NovelKey, params?: Record<string, string | number>): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidebar entry injection — mirrors the family plugins' DOM-level pattern:
|
|
3
|
+
* the shell exposes no external slot, so the entry row is injected after the
|
|
4
|
+
* sibling plugin entries and self-heals via MutationObserver.
|
|
5
|
+
*/
|
|
6
|
+
import type { PanelController } from './panel/controller.ts';
|
|
7
|
+
/** Stable data attribute identifying the injected entry row. */
|
|
8
|
+
export declare const ENTRY_SELECTOR = "[data-dsh-novelforge-entry]";
|
|
9
|
+
/**
|
|
10
|
+
* Mount the sidebar entry, waiting for the shell and self-healing on
|
|
11
|
+
* re-renders.
|
|
12
|
+
*/
|
|
13
|
+
export declare function mountSidebarEntry(controller: PanelController): () => void;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docx outline extraction: a .docx is a zip whose word/document.xml holds the
|
|
3
|
+
* body text in <w:t> runs inside <w:p> paragraphs. We unzip with fflate and
|
|
4
|
+
* walk the XML with a tiny tokenizer — no heavyweight XML/DOM dependency.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Extract plain text from a docx buffer: one line per <w:p> paragraph, with
|
|
8
|
+
* <w:tab>/<w:br> preserved as whitespace. Tables and nested structures are
|
|
9
|
+
* flattened in document order (their paragraphs are just <w:p> too).
|
|
10
|
+
* @param buffer - the raw .docx bytes.
|
|
11
|
+
* @returns the body text.
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractDocxText(buffer: Uint8Array): string;
|
|
14
|
+
/**
|
|
15
|
+
* Read and extract a docx outline from disk.
|
|
16
|
+
* @param path - absolute path to the .docx file.
|
|
17
|
+
* @returns the extracted outline text.
|
|
18
|
+
*/
|
|
19
|
+
export declare function readOutlineFromDocx(path: string): string;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Novel engine — the host half's core: LLM-driven story-bible extraction,
|
|
3
|
+
* volume planning, chapter planning, chapter-by-chapter writing with
|
|
4
|
+
* auto-review + rewrite, polish (de-AI-ify), narrative summaries, foreshadow
|
|
5
|
+
* tracking, project persistence, and whole-book export. Pure Node (no
|
|
6
|
+
* web-server dependencies), so routes stay thin and logic is testable.
|
|
7
|
+
*/
|
|
8
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
9
|
+
import type { ChapterPlan, Foreshadow, NovelConfig, ProjectState, ReviewReport, StoryBible, Volume } from './protocol.ts';
|
|
10
|
+
/** Project state file name inside the output dir. */
|
|
11
|
+
export declare const PROJECT_FILE = "novel-project.json";
|
|
12
|
+
/** Chapter output file name, e.g. 第001章_开篇.md */
|
|
13
|
+
export declare function chapterFileName(chapter: ChapterPlan): string;
|
|
14
|
+
/** Infer a book name from the outline's first non-empty line. */
|
|
15
|
+
export declare function inferBookName(outline: string): string;
|
|
16
|
+
/** Read the persisted project from the output dir (undefined when absent). */
|
|
17
|
+
export declare function loadProject(outputDir: string): ProjectState | undefined;
|
|
18
|
+
/** Persist the project state next to the chapters. */
|
|
19
|
+
export declare function saveProject(outputDir: string, project: ProjectState): void;
|
|
20
|
+
/** List generated chapter files in the output dir (sorted). */
|
|
21
|
+
export declare function listChapterFiles(outputDir: string): string[];
|
|
22
|
+
/** Re-sync chapter status against files on disk (a file may exist without state). */
|
|
23
|
+
export declare function syncProjectWithDisk(project: ProjectState, outputDir: string): void;
|
|
24
|
+
/** Read a chapter's markdown body from disk (undefined when missing). */
|
|
25
|
+
export declare function readChapterFile(outputDir: string, chapter: ChapterPlan): string | undefined;
|
|
26
|
+
/** Create a fresh project from an outline. */
|
|
27
|
+
export declare function createProject(outline: string, outlinePath?: string): ProjectState;
|
|
28
|
+
/** Extract the story bible from an outline. */
|
|
29
|
+
export declare function extractBible(ctx: Context, config: NovelConfig, outline: string): Promise<StoryBible>;
|
|
30
|
+
/** Plan volumes from an outline. */
|
|
31
|
+
export declare function planVolumes(ctx: Context, config: NovelConfig, outline: string): Promise<Volume[]>;
|
|
32
|
+
/**
|
|
33
|
+
* Plan chapters from an outline (optionally for one volume).
|
|
34
|
+
*/
|
|
35
|
+
export declare function planChapters(ctx: Context, config: NovelConfig, project: ProjectState, chapterCount: number, volumeNo?: number): Promise<ChapterPlan[]>;
|
|
36
|
+
/** Run the AI review on one chapter. */
|
|
37
|
+
export declare function reviewChapter(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, chapterNo: number): Promise<ReviewReport>;
|
|
38
|
+
/**
|
|
39
|
+
* Stream a chapter rewrite. With `target` (a passage of the body), only that
|
|
40
|
+
* passage's paragraph is rewritten and spliced back — everything else stays
|
|
41
|
+
* untouched (local revision). Without `target`, the whole chapter is
|
|
42
|
+
* rewritten. Yields delta text; persists when done.
|
|
43
|
+
*/
|
|
44
|
+
export declare function rewriteChapterStream(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, chapterNo: number, instructions: string, target?: string): AsyncGenerator<{
|
|
45
|
+
frame: 'start';
|
|
46
|
+
} | {
|
|
47
|
+
frame: 'delta';
|
|
48
|
+
text: string;
|
|
49
|
+
} | {
|
|
50
|
+
frame: 'done';
|
|
51
|
+
file: string;
|
|
52
|
+
chars: number;
|
|
53
|
+
}, void, unknown>;
|
|
54
|
+
/** Stream a chapter polish (de-AI-ify). */
|
|
55
|
+
export declare function polishChapterStream(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, chapterNo: number): AsyncGenerator<{
|
|
56
|
+
frame: 'start';
|
|
57
|
+
} | {
|
|
58
|
+
frame: 'delta';
|
|
59
|
+
text: string;
|
|
60
|
+
} | {
|
|
61
|
+
frame: 'done';
|
|
62
|
+
file: string;
|
|
63
|
+
chars: number;
|
|
64
|
+
}, void, unknown>;
|
|
65
|
+
/** Generate one chapter (streaming). Yields progress frames; persists when done. */
|
|
66
|
+
export declare function generateChapterStream(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, chapterNo: number): AsyncGenerator<{
|
|
67
|
+
frame: 'start';
|
|
68
|
+
} | {
|
|
69
|
+
frame: 'delta';
|
|
70
|
+
text: string;
|
|
71
|
+
} | {
|
|
72
|
+
frame: 'done';
|
|
73
|
+
file: string;
|
|
74
|
+
chars: number;
|
|
75
|
+
}, void, unknown>;
|
|
76
|
+
/** Generate a chapter summary (narrative memory). */
|
|
77
|
+
export declare function summarizeChapter(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, chapterNo: number): Promise<string>;
|
|
78
|
+
/** Suggest foreshadows from the outline + plan. */
|
|
79
|
+
export declare function suggestForeshadows(ctx: Context, config: NovelConfig, project: ProjectState): Promise<Foreshadow[]>;
|
|
80
|
+
/**
|
|
81
|
+
* 写法引擎:从样本文本提取一份写法资产(叙事风格规则)。
|
|
82
|
+
* @returns 提取出的风格规则(未持久化,由调用方存入 project.assets)。
|
|
83
|
+
*/
|
|
84
|
+
export declare function extractStyleAsset(ctx: Context, config: NovelConfig, sampleText: string): Promise<{
|
|
85
|
+
proseRules: string[];
|
|
86
|
+
dialogueRules: string[];
|
|
87
|
+
descriptionRules: string[];
|
|
88
|
+
boundaries: string[];
|
|
89
|
+
}>;
|
|
90
|
+
/** Export the whole book as one txt/md file. */
|
|
91
|
+
export declare function exportBook(outputDir: string, project: ProjectState, format: 'txt' | 'md'): {
|
|
92
|
+
file: string;
|
|
93
|
+
chars: number;
|
|
94
|
+
chapters: number;
|
|
95
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-novel-forge — host half. Mounts the AI novel-forge workbench: docx
|
|
3
|
+
* outline import, LLM chapter planning, chapter-by-chapter generation
|
|
4
|
+
* (3000-4000 chars each), Markdown output into your chosen folder, and the
|
|
5
|
+
* /api/dsh-novel-forge route family. The browser half (./client) renders the
|
|
6
|
+
* workbench panel. Everything rides official NPM SDK packages — no dsh source
|
|
7
|
+
* changes.
|
|
8
|
+
*/
|
|
9
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
10
|
+
import z from 'schemastery';
|
|
11
|
+
import type { NovelConfig } from './protocol.ts';
|
|
12
|
+
/** Stable cordis plugin name. */
|
|
13
|
+
export declare const name = "novel-forge";
|
|
14
|
+
/** Services required before the novel-forge surfaces can mount. */
|
|
15
|
+
export declare const inject: string[];
|
|
16
|
+
/**
|
|
17
|
+
* Settings namespace of the novel-forge capability — the section the web
|
|
18
|
+
* settings surface edits. Spelled here rather than imported: the browser half
|
|
19
|
+
* spells the same value and must not depend on a Host package.
|
|
20
|
+
*/
|
|
21
|
+
export declare const NOVEL_SETTINGS_NAMESPACE: import("@deepseek-ai/dsh-settings").SettingsNamespace;
|
|
22
|
+
/** Plugin config, validated by the same-named schemastery schema. */
|
|
23
|
+
export interface Config {
|
|
24
|
+
/** When true (default), a system-prompt section announces the plugin to every agent. */
|
|
25
|
+
announceToAgent?: boolean;
|
|
26
|
+
/** Master switch for the plugin (routes, prompt section). */
|
|
27
|
+
enabled?: boolean;
|
|
28
|
+
/** Absolute path of the default docx outline to load. */
|
|
29
|
+
outlinePath?: string;
|
|
30
|
+
/** Absolute output directory for chapters + project state. */
|
|
31
|
+
outputDir?: string;
|
|
32
|
+
/** LLM provider route. */
|
|
33
|
+
provider?: string;
|
|
34
|
+
/** LLM model id. */
|
|
35
|
+
model?: string;
|
|
36
|
+
/** Target characters per chapter. */
|
|
37
|
+
chapterChars?: number;
|
|
38
|
+
/** Max output tokens per chapter call. */
|
|
39
|
+
maxTokens?: number;
|
|
40
|
+
/** Review pass threshold (0-100). */
|
|
41
|
+
reviewPassScore?: number;
|
|
42
|
+
/** Whether generation auto-runs review after writing. */
|
|
43
|
+
autoReview?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export declare const Config: z<Config>;
|
|
46
|
+
/** Model-facing announcement: plugin presence, capabilities, and limits. */
|
|
47
|
+
export declare const NOVEL_GUIDANCE = "\u672C\u673A\u5DF2\u5B89\u88C5 dsh-novel-forge \u63D2\u4EF6\uFF08AI \u7F16\u8BD1\u5C0F\u8BF4\u5DE5\u4F5C\u53F0\uFF09\uFF1A\u4FA7\u8FB9\u680F\u300C\u5C0F\u8BF4\u5DE5\u574A\u300D\u5165\u53E3\u3002\u80FD\u529B\uFF1A\u8BFB\u53D6 docx \u5927\u7EB2\uFF08\u9ED8\u8BA4\u684C\u9762\u300A\u5F52\u589F\u7389\u4E3B\u300B\u5927\u7EB2\uFF09\u6216\u7C98\u8D34\u5927\u7EB2\u6587\u672C\uFF1B\u7528 LLM \u63D0\u70BC\u8BBE\u5B9A\u5723\u7ECF\uFF08\u4EBA\u8BBE/\u4E16\u754C\u89C2/\u91D1\u624B\u6307\u89C4\u5219/\u5199\u4F5C\u7EA2\u7EBF\uFF09\uFF1B\u751F\u6210\u5377\u8BA1\u5212\u4E0E\u7AE0\u8282\u8BA1\u5212\uFF1B\u9010\u7AE0\u8C03\u7528 LLM \u751F\u6210 3000-4000 \u5B57\u6B63\u6587\u5E76\u4FDD\u5B58\u4E3A Markdown\uFF08\u9ED8\u8BA4\u8F93\u51FA\u5230 \u684C\u9762\\\u5F52\u589F\u7389\u4E3B\uFF09\uFF1B\u6BCF\u7AE0\u81EA\u52A8\u751F\u6210\u6458\u8981\uFF08\u53D9\u4E8B\u8BB0\u5FC6\uFF09\u3001\u81EA\u52A8 AI \u5BA1\u7A3F\uFF08\u4EBA\u8BBE/\u8BBE\u5B9A/\u7EA2\u7EBF/\u6587\u7B14/\u723D\u70B9/\u903B\u8F91\uFF09\uFF0C\u652F\u6301\u6309\u5BA1\u7A3F\u610F\u89C1\u91CD\u5199\u3001\u53BB AI \u5473\u6DA6\u8272\u3001\u4F0F\u7B14\u7BA1\u7406\u3001\u6279\u91CF\u8FDE\u5199\u4E0E\u5168\u672C\u5BFC\u51FA\uFF08txt/md\uFF09\u3002\u9650\u5236\uFF1A\u751F\u6210\u6D88\u8017 LLM API \u989D\u5EA6\uFF1B\u8F93\u51FA\u76EE\u5F55\u4E0E\u6A21\u578B\u53EF\u5728\u63D2\u4EF6\u8BBE\u7F6E\u4E2D\u4FEE\u6539\uFF1B\u7AE0\u8282\u6B63\u6587\u8D28\u91CF\u53D6\u51B3\u4E8E\u5927\u7EB2\u5B8C\u6574\u5EA6\u3002\u7528\u6237\u63D0\u5230\u300C\u5C0F\u8BF4 / \u5927\u7EB2 / \u5199\u5C0F\u8BF4 / \u7AE0\u8282 / \u5BA1\u7A3F / \u4F0F\u7B14 / \u6DA6\u8272 / \u5F52\u589F\u7389\u4E3B\u300D\u65F6\u5373\u6307\u672C\u63D2\u4EF6\uFF0C\u8BF7\u636E\u6B64\u534F\u4F5C\u3002";
|
|
48
|
+
/** Resolve a config-like value into the full runtime config. */
|
|
49
|
+
export declare function resolveConfig(value: Partial<Config> | undefined): NovelConfig;
|
|
50
|
+
/**
|
|
51
|
+
* Mount the routes and announcement.
|
|
52
|
+
* @param ctx - host plugin context carrying webServer/llm/systemPrompt.
|
|
53
|
+
* @param config - resolved plugin config (schema defaults applied by the loader).
|
|
54
|
+
*/
|
|
55
|
+
export declare function apply(ctx: Context, config?: Config): void;
|