@waterwx/dsh-novel-forge 1.3.2 → 1.4.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/README.md +2 -2
- package/lib/client.js +548 -267
- package/lib/client.js.map +1 -1
- package/lib/index.js +183 -9
- package/lib/index.js.map +1 -1
- package/lib/types/bookshelf.d.ts +6 -1
- package/lib/types/client/api.d.ts +4 -0
- package/lib/types/client/panel/ImportModal.d.ts +7 -0
- package/lib/types/client/panel/ShelfView.d.ts +3 -1
- package/lib/types/engine.d.ts +6 -0
- package/lib/types/index.d.ts +1 -1
- package/lib/types/protocol.d.ts +32 -0
- package/package.json +97 -97
- package/src/bookshelf.ts +18 -2
- package/src/client/api.ts +420 -410
- package/src/client/panel/ImportModal.tsx +191 -0
- package/src/client/panel/NovelPanel.tsx +5058 -5046
- package/src/client/panel/ShelfView.tsx +249 -236
- package/src/client/panel/panel.module.css +3037 -2941
- package/src/engine.ts +3001 -2943
- package/src/index.ts +7 -5
- package/src/protocol.ts +1244 -1207
- package/src/routes.ts +2332 -2272
- package/scripts/assistant-frames.txt +0 -8
- package/scripts/diagnose-adapter.mts +0 -81
- package/scripts/diagnose-assistant.mjs +0 -58
- package/scripts/diagnose-bible.mjs +0 -72
- package/scripts/diagnose-harness.mts +0 -75
- package/scripts/novel-forge-restart.log +0 -10
- package/scripts/novel-forge-web.stderr.log +0 -2
- package/scripts/novel-forge-web.stdout.log +0 -1
- package/scripts/outline-sample.txt +0 -449
- package/scripts/probe.mjs +0 -6
- package/scripts/restart-web.ps1 +0 -88
- package/scripts/smoke.mts +0 -72
- package/scripts/upload-github.ps1 +0 -51
package/lib/types/bookshelf.d.ts
CHANGED
|
@@ -26,12 +26,17 @@ export declare function renameBook(id: string, bookName: string): boolean;
|
|
|
26
26
|
* @returns 是否发生了播种。
|
|
27
27
|
*/
|
|
28
28
|
export declare function seedBookshelfFromOutputDir(outputDir: string): boolean;
|
|
29
|
+
/** 导入已有项目目录到书架:校验 novel-project.json,已存在则直接激活。 */
|
|
30
|
+
export declare function importDir(outputDir: string): {
|
|
31
|
+
book: BookEntry;
|
|
32
|
+
existed: boolean;
|
|
33
|
+
};
|
|
29
34
|
/** 激活一本书。 */
|
|
30
35
|
export declare function activateBook(id: string): BookEntry | undefined;
|
|
31
36
|
/** 移除一本书。 */
|
|
32
37
|
export declare function removeBook(id: string): boolean;
|
|
33
38
|
/** 当前书输出目录(无书架则 undefined,回退 settings)。 */
|
|
34
39
|
export declare function activeBookOutputDir(): string | undefined;
|
|
35
|
-
/**
|
|
40
|
+
/** 默认输出目录推断:~/.dsh/novels/书名。 */
|
|
36
41
|
export declare function defaultOutputDirFor(bookName: string): string;
|
|
37
42
|
export {};
|
|
@@ -116,6 +116,10 @@ export declare class NovelApi {
|
|
|
116
116
|
bookActivate(id: string): Promise<import('../protocol.ts').BookshelfSnapshot>;
|
|
117
117
|
/** 移除书架条目。 */
|
|
118
118
|
bookRemove(id: string): Promise<import('../protocol.ts').BookshelfSnapshot>;
|
|
119
|
+
/** 导入已有项目目录(Mode A):校验 novel-project.json,登记/激活书架。 */
|
|
120
|
+
bookImportDir(outputDir: string): Promise<import('../protocol.ts').BookImportDirResponse>;
|
|
121
|
+
/** 导入 txt/md 全本(Mode B):拆章建项目并登记书架。 */
|
|
122
|
+
bookImportText(filePath: string, outputDir?: string): Promise<import('../protocol.ts').BookImportTextResponse>;
|
|
119
123
|
/** 生产单:启动批量生产(区间或新增 N 章;计划不足自动补)。 */
|
|
120
124
|
runStart(req: import('../protocol.ts').RunStartRequest): Promise<import('../protocol.ts').RunState>;
|
|
121
125
|
/** 生产单控制:pause / resume / stop。 */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { NovelApi } from '../api.ts';
|
|
2
2
|
import type { BookshelfSnapshot } from '../../protocol.ts';
|
|
3
3
|
/** 书架首页。 */
|
|
4
|
-
export declare function ShelfView({ api, shelf, onOpenBook, onReadBook, onAddBook, }: {
|
|
4
|
+
export declare function ShelfView({ api, shelf, onOpenBook, onReadBook, onAddBook, onImportBook, }: {
|
|
5
5
|
api: NovelApi;
|
|
6
6
|
shelf: BookshelfSnapshot;
|
|
7
7
|
/** 点击书卡:激活该书并进入工作台。 */
|
|
@@ -10,4 +10,6 @@ export declare function ShelfView({ api, shelf, onOpenBook, onReadBook, onAddBoo
|
|
|
10
10
|
onReadBook: (id: string) => void;
|
|
11
11
|
/** 点击+:进入开书向导页。 */
|
|
12
12
|
onAddBook: () => void;
|
|
13
|
+
/** 点击「导入」:打开导入弹窗(已有项目目录 / txt/md 全本)。 */
|
|
14
|
+
onImportBook: () => void;
|
|
13
15
|
}): import("react").JSX.Element;
|
package/lib/types/engine.d.ts
CHANGED
|
@@ -71,6 +71,12 @@ export declare function refreshPlotlineProgress(ctx: Context, config: NovelConfi
|
|
|
71
71
|
export declare function extractRoles(ctx: Context, config: NovelConfig, project: ProjectState): Promise<RoleRecord[]>;
|
|
72
72
|
/** ✨ AI 从全书提炼场景库:正文/编年录 → 高频重要场景的结构化视觉锚点。 */
|
|
73
73
|
export declare function extractScenes(ctx: Context, config: NovelConfig, project: ProjectState): Promise<SceneCard[]>;
|
|
74
|
+
/** 从 txt/md 全本拆分章节并建立项目:正文落盘为章节文件,status=written(待审稿)。 */
|
|
75
|
+
export declare function importBookText(filePath: string, outputDir: string): {
|
|
76
|
+
bookName: string;
|
|
77
|
+
chapters: number;
|
|
78
|
+
skipped: string[];
|
|
79
|
+
};
|
|
74
80
|
/** 动漫形象描述词(中文描述 + 英文 booru 标签 + 关键外貌标签)。 */
|
|
75
81
|
export interface RoleVisualPrompt {
|
|
76
82
|
zh: string;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -56,7 +56,7 @@ export interface Config {
|
|
|
56
56
|
}
|
|
57
57
|
export declare const Config: z<Config>;
|
|
58
58
|
/** Model-facing announcement: plugin presence, capabilities, and limits. */
|
|
59
|
-
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\
|
|
59
|
+
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\u6216\u7C98\u8D34\u5927\u7EB2\u6587\u672C\uFF1B\u7528 LLM \u63D0\u70BC\u9053\u85CF\uFF08\u4EBA\u8BBE/\u4E16\u754C\u89C2/\u91D1\u624B\u6307\u89C4\u5219/\u5199\u4F5C\u7EA2\u7EBF\uFF0C\u5373\u8BBE\u5B9A\u5723\u7ECF\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\u7528\u6237\u4E3B\u76EE\u5F55 ~/.dsh/novels\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\u6697\u7EBF\uFF08\u4F0F\u7B14\uFF09\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 / \u6DA6\u8272\u300D\u65F6\u5373\u6307\u672C\u63D2\u4EF6\uFF0C\u8BF7\u636E\u6B64\u534F\u4F5C\u3002";
|
|
60
60
|
/** Resolve a config-like value into the full runtime config. */
|
|
61
61
|
export declare function resolveConfig(value: Partial<Config> | undefined): NovelConfig;
|
|
62
62
|
/**
|
package/lib/types/protocol.d.ts
CHANGED
|
@@ -35,6 +35,10 @@ export declare const NOVEL_API: {
|
|
|
35
35
|
/** 清空助手对话记录。 */
|
|
36
36
|
readonly assistantClear: "/api/dsh-novel-forge/assistant/clear";
|
|
37
37
|
readonly bookshelf: "/api/dsh-novel-forge/bookshelf";
|
|
38
|
+
/** 导入已有项目目录(含 novel-project.json)到书架。 */
|
|
39
|
+
readonly bookshelfImportDir: "/api/dsh-novel-forge/bookshelf/import-dir";
|
|
40
|
+
/** 导入 txt/md 全本:拆章建项目并登记书架。 */
|
|
41
|
+
readonly bookshelfImportText: "/api/dsh-novel-forge/bookshelf/import-text";
|
|
38
42
|
/** 重置项目(可选携带新大纲):清空设定/卷/章节/伏笔/资产/事实库。 */
|
|
39
43
|
readonly reset: "/api/dsh-novel-forge/reset";
|
|
40
44
|
/** 全书一致性质检:LLM 扫描已生成章节,输出矛盾问题清单。 */
|
|
@@ -128,6 +132,34 @@ export interface BookActivateRequest {
|
|
|
128
132
|
export interface BookRemoveRequest {
|
|
129
133
|
id: string;
|
|
130
134
|
}
|
|
135
|
+
/** POST /bookshelf/import-dir 请求:导入已有项目目录。 */
|
|
136
|
+
export interface BookImportDirRequest {
|
|
137
|
+
/** 项目目录(须含 novel-project.json)。 */
|
|
138
|
+
outputDir: string;
|
|
139
|
+
}
|
|
140
|
+
/** POST /bookshelf/import-dir 响应。 */
|
|
141
|
+
export interface BookImportDirResponse {
|
|
142
|
+
book: BookEntry;
|
|
143
|
+
/** true = 目录已在书架中(本次为重新激活)。 */
|
|
144
|
+
existed: boolean;
|
|
145
|
+
}
|
|
146
|
+
/** POST /bookshelf/import-text 请求:导入 txt/md 全本。 */
|
|
147
|
+
export interface BookImportTextRequest {
|
|
148
|
+
/** 源文件绝对路径(txt 或 md)。 */
|
|
149
|
+
filePath: string;
|
|
150
|
+
/** 输出目录;缺省为 ~/.dsh/novels/书名。 */
|
|
151
|
+
outputDir?: string;
|
|
152
|
+
}
|
|
153
|
+
/** POST /bookshelf/import-text 响应。 */
|
|
154
|
+
export interface BookImportTextResponse {
|
|
155
|
+
bookName: string;
|
|
156
|
+
/** 成功拆出的章节数。 */
|
|
157
|
+
chapters: number;
|
|
158
|
+
/** 因内容过短被跳过的章节标题列表。 */
|
|
159
|
+
skipped: string[];
|
|
160
|
+
/** 登记后的书架条目。 */
|
|
161
|
+
book: BookEntry;
|
|
162
|
+
}
|
|
131
163
|
/** Chapter lifecycle states (the writing pipeline's state machine). */
|
|
132
164
|
export type ChapterStatus = 'pending' | 'generating' | 'written' | 'reviewing' | 'approved' | 'rejected' | 'error';
|
|
133
165
|
/** One chapter in the plan. */
|
package/package.json
CHANGED
|
@@ -1,97 +1,97 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@waterwx/dsh-novel-forge",
|
|
3
|
-
"description": "AI 编译小说工作台 for the dsh web GUI: import a novel outline (docx/text), plan chapters with LLM, generate chapter by chapter (3000-4000 chars each), and save every chapter as Markdown into your chosen output folder.",
|
|
4
|
-
"version": "1.
|
|
5
|
-
"type": "module",
|
|
6
|
-
"engines": {
|
|
7
|
-
"node": "^22.19.0 || >=24.0.0"
|
|
8
|
-
},
|
|
9
|
-
"main": "lib/index.js",
|
|
10
|
-
"types": "lib/types/index.d.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"types": "./lib/types/index.d.ts",
|
|
14
|
-
"default": "./lib/index.js"
|
|
15
|
-
},
|
|
16
|
-
"./client": {
|
|
17
|
-
"types": "./lib/types/client/index.d.ts",
|
|
18
|
-
"default": "./lib/client.js"
|
|
19
|
-
},
|
|
20
|
-
"./src/*": "./src/*",
|
|
21
|
-
"./package.json": "./package.json"
|
|
22
|
-
},
|
|
23
|
-
"dsh": {
|
|
24
|
-
"bundle": {
|
|
25
|
-
"patch": "./cordis.patch.yml"
|
|
26
|
-
},
|
|
27
|
-
"client": {
|
|
28
|
-
"inject": [
|
|
29
|
-
"@deepseek-ai/dsh-client-runtime",
|
|
30
|
-
"@deepseek-ai/dsh-client-connection",
|
|
31
|
-
"@deepseek-ai/dsh-client-ui-settings"
|
|
32
|
-
],
|
|
33
|
-
"platform": "web"
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
"dependencies": {
|
|
37
|
-
"fflate": "^0.8.2",
|
|
38
|
-
"schemastery": "^3.18.0"
|
|
39
|
-
},
|
|
40
|
-
"peerDependencies": {
|
|
41
|
-
"@deepseek-ai/dsh-client-connection": "^0.1.0-rc.5",
|
|
42
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.5",
|
|
43
|
-
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.5",
|
|
44
|
-
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.5",
|
|
45
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.5",
|
|
46
|
-
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.5",
|
|
47
|
-
"@deepseek-ai/dsh-llm": "^0.1.0-rc.5",
|
|
48
|
-
"@deepseek-ai/dsh-settings": "^0.1.0-rc.5",
|
|
49
|
-
"@deepseek-ai/dsh-skill": "^0.1.0-rc.5",
|
|
50
|
-
"@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.5",
|
|
51
|
-
"@deepseek-ai/dsh-tools": "^0.1.0-rc.5",
|
|
52
|
-
"react": "^18.2.0",
|
|
53
|
-
"react-dom": "^18.2.0"
|
|
54
|
-
},
|
|
55
|
-
"devDependencies": {
|
|
56
|
-
"@deepseek-ai/cordis": "^4.0.1",
|
|
57
|
-
"@deepseek-ai/dsh-client-connection": "^0.1.0-rc.5",
|
|
58
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.5",
|
|
59
|
-
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.5",
|
|
60
|
-
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.5",
|
|
61
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.5",
|
|
62
|
-
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.5",
|
|
63
|
-
"@deepseek-ai/dsh-llm": "^0.1.0-rc.5",
|
|
64
|
-
"@deepseek-ai/dsh-settings": "^0.1.0-rc.5",
|
|
65
|
-
"@deepseek-ai/dsh-skill": "^0.1.0-rc.5",
|
|
66
|
-
"@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.5",
|
|
67
|
-
"@deepseek-ai/dsh-tools": "^0.1.0-rc.5",
|
|
68
|
-
"@types/node": "^22.20.0",
|
|
69
|
-
"@types/react": "~18.3.1",
|
|
70
|
-
"@types/react-dom": "^18.3.5",
|
|
71
|
-
"lightningcss": "1.32.0",
|
|
72
|
-
"react": "^18.3.1",
|
|
73
|
-
"react-dom": "^18.3.1",
|
|
74
|
-
"tsdown": "0.22.2",
|
|
75
|
-
"typescript": "~5.7.2",
|
|
76
|
-
"vitest": "^3.0.0"
|
|
77
|
-
},
|
|
78
|
-
"files": [
|
|
79
|
-
"lib/**/*.js",
|
|
80
|
-
"lib/**/*.js.map",
|
|
81
|
-
"lib/**/*.d.ts",
|
|
82
|
-
"lib/**/*.d.ts.map",
|
|
83
|
-
"src",
|
|
84
|
-
"scripts",
|
|
85
|
-
"cordis.patch.yml",
|
|
86
|
-
"README.md"
|
|
87
|
-
],
|
|
88
|
-
"license": "Apache-2.0",
|
|
89
|
-
"scripts": {
|
|
90
|
-
"postinstall": "node scripts/patch-schemastery.mjs",
|
|
91
|
-
"build": "tsc -p tsconfig.build.json && tsdown",
|
|
92
|
-
"bundle": "tsdown",
|
|
93
|
-
"watch": "tsdown --watch",
|
|
94
|
-
"typecheck": "tsc --noEmit",
|
|
95
|
-
"test": "vitest run"
|
|
96
|
-
}
|
|
97
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@waterwx/dsh-novel-forge",
|
|
3
|
+
"description": "AI 编译小说工作台 for the dsh web GUI: import a novel outline (docx/text), plan chapters with LLM, generate chapter by chapter (3000-4000 chars each), and save every chapter as Markdown into your chosen output folder.",
|
|
4
|
+
"version": "1.4.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
8
|
+
},
|
|
9
|
+
"main": "lib/index.js",
|
|
10
|
+
"types": "lib/types/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./lib/types/index.d.ts",
|
|
14
|
+
"default": "./lib/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./client": {
|
|
17
|
+
"types": "./lib/types/client/index.d.ts",
|
|
18
|
+
"default": "./lib/client.js"
|
|
19
|
+
},
|
|
20
|
+
"./src/*": "./src/*",
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
"dsh": {
|
|
24
|
+
"bundle": {
|
|
25
|
+
"patch": "./cordis.patch.yml"
|
|
26
|
+
},
|
|
27
|
+
"client": {
|
|
28
|
+
"inject": [
|
|
29
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
30
|
+
"@deepseek-ai/dsh-client-connection",
|
|
31
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
32
|
+
],
|
|
33
|
+
"platform": "web"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"fflate": "^0.8.2",
|
|
38
|
+
"schemastery": "^3.18.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.0-rc.5",
|
|
42
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.5",
|
|
43
|
+
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.5",
|
|
44
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.5",
|
|
45
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.5",
|
|
46
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.5",
|
|
47
|
+
"@deepseek-ai/dsh-llm": "^0.1.0-rc.5",
|
|
48
|
+
"@deepseek-ai/dsh-settings": "^0.1.0-rc.5",
|
|
49
|
+
"@deepseek-ai/dsh-skill": "^0.1.0-rc.5",
|
|
50
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.5",
|
|
51
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.5",
|
|
52
|
+
"react": "^18.2.0",
|
|
53
|
+
"react-dom": "^18.2.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
57
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.0-rc.5",
|
|
58
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.5",
|
|
59
|
+
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.5",
|
|
60
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.5",
|
|
61
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.5",
|
|
62
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.5",
|
|
63
|
+
"@deepseek-ai/dsh-llm": "^0.1.0-rc.5",
|
|
64
|
+
"@deepseek-ai/dsh-settings": "^0.1.0-rc.5",
|
|
65
|
+
"@deepseek-ai/dsh-skill": "^0.1.0-rc.5",
|
|
66
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.5",
|
|
67
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.5",
|
|
68
|
+
"@types/node": "^22.20.0",
|
|
69
|
+
"@types/react": "~18.3.1",
|
|
70
|
+
"@types/react-dom": "^18.3.5",
|
|
71
|
+
"lightningcss": "1.32.0",
|
|
72
|
+
"react": "^18.3.1",
|
|
73
|
+
"react-dom": "^18.3.1",
|
|
74
|
+
"tsdown": "0.22.2",
|
|
75
|
+
"typescript": "~5.7.2",
|
|
76
|
+
"vitest": "^3.0.0"
|
|
77
|
+
},
|
|
78
|
+
"files": [
|
|
79
|
+
"lib/**/*.js",
|
|
80
|
+
"lib/**/*.js.map",
|
|
81
|
+
"lib/**/*.d.ts",
|
|
82
|
+
"lib/**/*.d.ts.map",
|
|
83
|
+
"src",
|
|
84
|
+
"scripts/patch-schemastery.mjs",
|
|
85
|
+
"cordis.patch.yml",
|
|
86
|
+
"README.md"
|
|
87
|
+
],
|
|
88
|
+
"license": "Apache-2.0",
|
|
89
|
+
"scripts": {
|
|
90
|
+
"postinstall": "node scripts/patch-schemastery.mjs",
|
|
91
|
+
"build": "tsc -p tsconfig.build.json && tsdown",
|
|
92
|
+
"bundle": "tsdown",
|
|
93
|
+
"watch": "tsdown --watch",
|
|
94
|
+
"typecheck": "tsc --noEmit",
|
|
95
|
+
"test": "vitest run"
|
|
96
|
+
}
|
|
97
|
+
}
|
package/src/bookshelf.ts
CHANGED
|
@@ -114,6 +114,22 @@ export function seedBookshelfFromOutputDir(outputDir: string): boolean {
|
|
|
114
114
|
return true
|
|
115
115
|
}
|
|
116
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
|
+
|
|
117
133
|
/** 激活一本书。 */
|
|
118
134
|
export function activateBook(id: string): BookEntry | undefined {
|
|
119
135
|
const store = loadBookshelf()
|
|
@@ -144,8 +160,8 @@ export function activeBookOutputDir(): string | undefined {
|
|
|
144
160
|
return book?.outputDir
|
|
145
161
|
}
|
|
146
162
|
|
|
147
|
-
/**
|
|
163
|
+
/** 默认输出目录推断:~/.dsh/novels/书名。 */
|
|
148
164
|
export function defaultOutputDirFor(bookName: string): string {
|
|
149
165
|
const clean = bookName.replace(/[\\/:*?"<>|]/g, '').trim().slice(0, 40) || '未命名小说'
|
|
150
|
-
return join('
|
|
166
|
+
return join(homedir(), '.dsh', 'novels', clean)
|
|
151
167
|
}
|