dsh-novel-generator 0.1.36 → 0.1.38

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 CHANGED
@@ -98,12 +98,16 @@ dsh plugin --profile web add dsh-novel-generator
98
98
 
99
99
  ## 章节故事页
100
100
 
101
- - 正文可以直接编辑、保存;工具条上还有两个按钮:
101
+ - 正文可以直接编辑、保存;工具条上还有三个按钮:
102
102
  - **「同步章节大纲」**:确认后把当前正文交给模型,**按这一章的实际内容重算整份大纲**——故事梗概、故事时间长度(天)、章节最低字数、章节最多字数、梗概最低字数,然后直接保存覆盖旧大纲(正文不动)。
103
103
  - 字数范围一定会把正文实际字数包在里面;梗概下限不会超过新梗概本身的长度。
104
104
  - 时间长度只有在不破坏时间线时才会改:末章可以直接改;后面还有章节时,只有「下一章起始日 = 本章起始日 + 新时长」才采纳,否则保留原时长并在提示里说明模型建议值。
105
+ - **「提取行文风格」**:模型读这一章,提炼视角与人称、句式、用词、节奏、描写比例,输出条目式说明(≤600 字)。
106
+ - 分析期间整个工坊被锁定,无法点别的按钮;正文不足 300 字时按钮不可点,接口也返回 400。
107
+ - 完成后弹面板:只读文本 + 「复制」(贴到作品列表的「前置」里)+ 「写入前置」。
108
+ - 「写入前置」会先弹确认,**明确告知要用 AI 整理**:模型把这段风格与你现有前置合并成一段统一的写作约束(≤2000 字)后保存为本书前置,覆盖旧的那份。
105
109
  - **「AI 修改」**:填入修改意见后,模型按意见重写整章,结果只放进编辑区、不自动保存。
106
- - 正文为空时两个按钮都不可点,接口也会拒绝(400);修改意见为空同样拒绝。
110
+ - 正文为空时按钮不可点,接口也会拒绝(400);修改意见为空同样拒绝。
107
111
 
108
112
  ## 章节大纲页
109
113
 
package/client.js CHANGED
@@ -166,6 +166,7 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
166
166
  border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}
167
167
  .dsn-note{margin:0;padding:8px 12px;border-radius:10px;font-size:12px;
168
168
  border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1)}
169
+ .dsn-note-row{display:flex;align-items:center;gap:10px;justify-content:space-between}
169
170
  .dsn-empty{padding:32px;text-align:center;color:var(--dsw-alias-label-secondary);font-size:13px}
170
171
  .dsn-toast{position:absolute;top:58px;left:50%;transform:translateX(-50%);z-index:30;
171
172
  padding:8px 16px;border-radius:999px;font-size:12px;border-left:3px solid var(--dsw-alias-state-success-primary);
@@ -1576,7 +1577,18 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
1576
1577
  ? h('div', { className: 'dsn-empty' }, t('还没有章节。点右上角「+ 新建章节」开始第一章。', "No chapters yet. Use \"+ New chapter\" at the top right to start the first one."))
1577
1578
  : h(React.Fragment, null,
1578
1579
  h('div', { className: 'dsn-editor' },
1579
- !chapter.outline ? h('div', { className: 'dsn-note' }, t('这一章还没有保存过章节大纲,可以先回章节大纲里填写并生成。', "This chapter has no saved outline yet; fill one in under \"Outline\" and generate from there.")) : null,
1580
+ !chapter.outline
1581
+ ? (String(text || '').trim() === ''
1582
+ ? h('div', { className: 'dsn-note' }, t('这一章还没有章节大纲:先去「章节大纲」填写,再回来生成正文。', 'This chapter has no outline yet — fill one in under "Outline", then generate from there.'))
1583
+ : h('div', { className: 'dsn-note dsn-note-row' },
1584
+ h('span', null, t('这一章是导入的,没有章节大纲记录:点「同步章节大纲」会根据正文生成梗概与字数范围。', 'This chapter came from an import and has no outline recorded — “Sync outline” builds one from the text.')),
1585
+ h('button', {
1586
+ className: 'dsn-btn ghost',
1587
+ type: 'button',
1588
+ disabled: saving || Boolean(summarizing),
1589
+ onClick: onSummarize,
1590
+ }, t('现在同步', 'Sync now'))))
1591
+ : null,
1580
1592
  h('textarea', {
1581
1593
  className: 'dsn-textarea dsn-story',
1582
1594
  value: text,
package/index.js CHANGED
@@ -1499,7 +1499,7 @@ async function bootstrap(ctx, root) {
1499
1499
  }
1500
1500
  }
1501
1501
  return {
1502
- revision: '2026-10-28.10',
1502
+ revision: '2026-10-29.1',
1503
1503
  projects,
1504
1504
  models: {
1505
1505
  default: modelCatalog.default || null,
@@ -2017,7 +2017,6 @@ async function updatePreset(ctx, root, body) {
2017
2017
  * the four numbers the outline records, all measured from this one chapter.
2018
2018
  */
2019
2019
  function syncOutlinePrompt(project, chapter, prose) {
2020
- const span = chapterWindow(project, chapter);
2021
2020
  const chars = wordCount(prose);
2022
2021
  const lines = [];
2023
2022
  lines.push('你是这部小说的编辑。作者已经写完了下面这一章,请据此同步它的章节大纲。');
@@ -2026,13 +2025,17 @@ function syncOutlinePrompt(project, chapter, prose) {
2026
2025
  lines.push('');
2027
2026
  lines.push('各项含义:');
2028
2027
  lines.push('- synopsis:这一章的故事梗概,写清起因、经过、转折、结果,供后续章节与世界观使用;300 字以内,纯文本。');
2029
- lines.push(`- durationDays:这段剧情在故事里覆盖的天数,整数 1–365。当前记为第 ${span.start}→${span.end} 天(共 ${span.end - span.start} 天),按正文实际推进判断是否需要改。`);
2028
+ lines.push('- durationDays:这段剧情在故事内部推进了几天,整数 1–365。');
2029
+ lines.push(' 只看正文里的时间线索(清晨到入夜、翌日、过了三日、雨下到第几天……)来数;');
2030
+ lines.push(' 正文没有时间线索时按事件密度估计:一场连续场景通常算 1 天,跨几次昼夜就往上加;');
2031
+ lines.push(' 大多数章节在 1–7 天之间,只有正文明确跨越更久时才写更大的数。');
2032
+ lines.push(' 不要参考任何已有设定或历史记录,完全按这段正文判断,不要沿用「原来记了多少天」。');
2030
2033
  lines.push(`- minWords / maxWords:这一章应有的字数下限与上限,整数;本章正文实际 ${chars} 字,范围应当把 ${chars} 包在里面。`);
2031
2034
  lines.push('- synopsisMinChars:上面这段梗概算「合格」的最低字数,整数 20–400,取梗概长度的八成左右。');
2032
2035
  lines.push('');
2033
- const prelude = preludeBlock(project);
2034
- if (prelude !== '') lines.push(prelude);
2035
- lines.push(`【本章】第 ${chapter.index + 1} 章 ${chapter.title || ''}(第 ${span.start}→${span.end} 天)`);
2036
+ // No time span and no preface here: this is a measurement of the text, and
2037
+ // either would hand the model the answer it is supposed to derive.
2038
+ lines.push(`【本章】第 ${chapter.index + 1} 章 ${chapter.title || ''}`);
2036
2039
  lines.push(`【正文】(共 ${chars} 字,不含空白)`);
2037
2040
  lines.push(prose);
2038
2041
  return lines.join('\n');
@@ -2454,7 +2457,6 @@ const STYLE_MIN_CHARS = 300;
2454
2457
  const STYLE_MAX_CHARS = 600;
2455
2458
 
2456
2459
  function styleExtractPrompt(project, chapter, prose) {
2457
- const span = chapterWindow(project, chapter);
2458
2460
  const lines = [];
2459
2461
  lines.push('你是这部小说的文字编辑。请从下面这段正文里提取这篇小说的行文风格,写成可以直接当作「写作约束」使用的条目。');
2460
2462
  lines.push('');
@@ -2471,7 +2473,7 @@ function styleExtractPrompt(project, chapter, prose) {
2471
2473
  lines.push('- 不要出现「这段文字」「作者」之类的话,也不要评价好坏;');
2472
2474
  lines.push(`- 全文不超过 ${STYLE_MAX_CHARS} 字,宁可少写几条也要写得可执行。`);
2473
2475
  lines.push('');
2474
- lines.push(`【本章】第 ${chapter.index + 1} 章 ${chapter.title || ''}(第 ${span.start}→${span.end} 天)`);
2476
+ lines.push(`【本章】第 ${chapter.index + 1} 章 ${chapter.title || ''}`);
2475
2477
  lines.push('【正文】');
2476
2478
  lines.push(prose);
2477
2479
  return lines.join('\n');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-novel-generator",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
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",