dsh-novel-generator 0.1.26 → 0.1.27
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 +9 -0
- package/index.js +31 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -81,6 +81,15 @@ dsh plugin --profile web add dsh-novel-generator
|
|
|
81
81
|
- 正文为空时按钮不可点,接口也会拒绝(400);修改意见为空同样拒绝。
|
|
82
82
|
- **重写结果只放进编辑区、不自动保存**,状态变成「未保存」,你确认后再点「保存」——避免 AI 的改动直接覆盖原稿。
|
|
83
83
|
|
|
84
|
+
## 附属子插件:小说工坊 · 作者预设
|
|
85
|
+
|
|
86
|
+
另有一个**独立包** `dsh-novel-author-preset`,只负责往 DSH 注册一个 Agent 预设「小说工坊 · 作者」:
|
|
87
|
+
|
|
88
|
+
- 装上它(`dsh plugin --profile web add dsh-novel-author-preset`),作品列表的「预设」与「设置 → 预设」里就多出这一项,**新建作品默认用它**;
|
|
89
|
+
- 卸掉它,预设立刻消失;已绑定的作品不会因此损坏——重建会话时检测到预设已不在,会自动退回 profile 的默认预设。
|
|
90
|
+
|
|
91
|
+
预设内容刻意做得很薄:三句人设(你是小说写作者/只输出正文/文风视角篇幅以用户要求为准)+ 关闭运行时上下文 + **不挂任何工具** + 只保留上下文压缩。所有文学倾向都交给作品级「前置提示词」。
|
|
92
|
+
|
|
84
93
|
## 迁移、导入与会话
|
|
85
94
|
|
|
86
95
|
- **改预设**:作品列表每行的「预设」改的是「下次建会话时用哪个预设」。会话在创建时就固定了预设,所以保存后会提示「重建会话后生效」——要立刻换,点同一行的「重建会话」。
|
package/index.js
CHANGED
|
@@ -922,6 +922,20 @@ function normalizeSnapshot(raw) {
|
|
|
922
922
|
|
|
923
923
|
/* ------------------------------------------------------------ agent work */
|
|
924
924
|
|
|
925
|
+
/** The preset a work records, but only when the deployment still offers it. */
|
|
926
|
+
async function usablePreset(ctx, presetId) {
|
|
927
|
+
if (!presetId) return false;
|
|
928
|
+
const presets = ctx.get('agentPresets');
|
|
929
|
+
if (!presets || typeof presets.list !== 'function') return true;
|
|
930
|
+
try {
|
|
931
|
+
const list = await presets.list();
|
|
932
|
+
if (!Array.isArray(list) || list.length === 0) return true;
|
|
933
|
+
return list.some((entry) => entry.id === presetId);
|
|
934
|
+
} catch {
|
|
935
|
+
return true;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
925
939
|
/**
|
|
926
940
|
* Bind a fresh session to a work whose old one disappeared (deleted in the
|
|
927
941
|
* sidebar, or gone from the session store). The work's memory — snapshots,
|
|
@@ -931,7 +945,12 @@ function normalizeSnapshot(raw) {
|
|
|
931
945
|
async function rebindSession(ctx, root, project) {
|
|
932
946
|
const controller = ctx.get('sessionController');
|
|
933
947
|
if (controller === undefined) throw httpError(503, '当前部署缺少 sessionController 服务,无法为作品重建会话');
|
|
934
|
-
|
|
948
|
+
// A preset can disappear when its plugin is uninstalled; falling back to the
|
|
949
|
+
// profile default keeps the work usable instead of failing every rebuild.
|
|
950
|
+
const presetOk = await usablePreset(ctx, project.agentPreset);
|
|
951
|
+
const created = await controller.create(presetOk && project.agentPreset
|
|
952
|
+
? { cwd: project.cwd, agentPreset: project.agentPreset }
|
|
953
|
+
: { cwd: project.cwd });
|
|
935
954
|
const sessionId = created && created.sessionId ? created.sessionId : null;
|
|
936
955
|
if (!sessionId) throw httpError(502, '没能为作品重建会话');
|
|
937
956
|
if (project.model) {
|
|
@@ -1477,7 +1496,7 @@ async function bootstrap(ctx, root) {
|
|
|
1477
1496
|
}
|
|
1478
1497
|
}
|
|
1479
1498
|
return {
|
|
1480
|
-
revision: '2026-10-27.
|
|
1499
|
+
revision: '2026-10-27.11',
|
|
1481
1500
|
projects,
|
|
1482
1501
|
models: {
|
|
1483
1502
|
default: modelCatalog.default || null,
|
|
@@ -1511,6 +1530,11 @@ async function createProject(ctx, root, body) {
|
|
|
1511
1530
|
const cwd = asText(body.cwd);
|
|
1512
1531
|
if (cwd === '') throw httpError(400, '请先选择作品的工作目录');
|
|
1513
1532
|
const agentPreset = asText(body.agentPreset) || undefined;
|
|
1533
|
+
// New works prefer the bundled author preset when its plugin is installed, and
|
|
1534
|
+
// otherwise fall back to the profile default instead of failing.
|
|
1535
|
+
const chosenPreset = agentPreset !== undefined && await usablePreset(ctx, agentPreset)
|
|
1536
|
+
? agentPreset
|
|
1537
|
+
: (await usablePreset(ctx, AUTHOR_PRESET_ID) ? AUTHOR_PRESET_ID : undefined);
|
|
1514
1538
|
const model = body.model && asText(body.model.provider) && asText(body.model.model)
|
|
1515
1539
|
? {
|
|
1516
1540
|
provider: asText(body.model.provider),
|
|
@@ -1529,7 +1553,7 @@ async function createProject(ctx, root, body) {
|
|
|
1529
1553
|
throw httpError(400, `无法在工作目录下创建作品文件夹:${error instanceof Error ? error.message : String(error)}`);
|
|
1530
1554
|
}
|
|
1531
1555
|
|
|
1532
|
-
const created = await controller.create(
|
|
1556
|
+
const created = await controller.create(chosenPreset === undefined ? { cwd } : { cwd, agentPreset: chosenPreset });
|
|
1533
1557
|
const sessionId = created && created.sessionId ? created.sessionId : null;
|
|
1534
1558
|
let warning = null;
|
|
1535
1559
|
if (sessionId && model) {
|
|
@@ -1546,7 +1570,7 @@ async function createProject(ctx, root, body) {
|
|
|
1546
1570
|
projectId,
|
|
1547
1571
|
title,
|
|
1548
1572
|
cwd,
|
|
1549
|
-
agentPreset:
|
|
1573
|
+
agentPreset: chosenPreset || created.agentPreset || null,
|
|
1550
1574
|
model,
|
|
1551
1575
|
// Every new work starts with the default narrative preface; the author can
|
|
1552
1576
|
// edit or clear it from the work list.
|
|
@@ -1914,6 +1938,9 @@ const PRELUDE_PRESETS = [
|
|
|
1914
1938
|
/** The preface a fresh work starts with. */
|
|
1915
1939
|
const DEFAULT_PRELUDE_MODE = 'thirdOmniscient';
|
|
1916
1940
|
|
|
1941
|
+
/** Preset id contributed by the optional `dsh-novel-author-preset` sub-plugin. */
|
|
1942
|
+
const AUTHOR_PRESET_ID = 'novel-studio-author';
|
|
1943
|
+
|
|
1917
1944
|
function defaultPrelude() {
|
|
1918
1945
|
const preset = PRELUDE_PRESETS.find((entry) => entry.id === DEFAULT_PRELUDE_MODE);
|
|
1919
1946
|
return preset ? { mode: preset.id, text: preset.text, updatedAt: Date.now() } : null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-novel-generator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.27",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Novel studio for DeepSeek Harness: a draggable story timeline, world snapshots, chapter outlines, and chapters written by the work's own agent.",
|
|
6
6
|
"license": "MIT",
|